feat(templates): add ability to dynamically change start and end icons for text inputs and spinners

This commit is contained in:
Akash Yadav
2023-05-25 10:11:15 +05:30
parent e696af34f6
commit 5d2adc7cb1
3 changed files with 49 additions and 34 deletions
@@ -83,7 +83,7 @@ fun baseProject(sdkFilter: ((Sdk) -> Boolean)? = null,
val saveLocation = stringParameter {
name = R.string.wizard_save_location
default = Environment.PROJECTS_DIR.absolutePath
endIcon = R.drawable.ic_folder
endIcon = { R.drawable.ic_folder }
constraints = listOf(NONEMPTY, DIRECTORY, EXISTS)
}
@@ -162,7 +162,7 @@ fun baseAndroidModule(isLibrary: Boolean = false,
val type = enumParameter<ModuleType> {
name = R.string.wizard_module_type
default = AndroidLibrary
startIcon = R.drawable.ic_android
startIcon = { R.drawable.ic_android }
displayName = ModuleType::typeName
}
@@ -19,6 +19,7 @@ package com.itsaky.androidide.templates
import androidx.annotation.StringRes
import com.itsaky.androidide.templates.Language.Java
import com.itsaky.androidide.templates.Language.Kotlin
import com.itsaky.androidide.templates.ParameterConstraint.NONEMPTY
import com.itsaky.androidide.templates.ParameterConstraint.PACKAGE
import com.itsaky.androidide.templates.R.string
@@ -217,20 +218,24 @@ class BooleanParameterBuilder : ParameterBuilder<Boolean>() {
*/
abstract class TextFieldParameter<T>(@StringRes name: Int,
@StringRes description: Int?, default: T,
val startIcon: Int?, val endIcon: Int?,
val startIcon: ((TextFieldParameter<T>) -> Int)?,
val endIcon: ((TextFieldParameter<T>) -> Int)?,
val onStartIconClick: (() -> Unit)?,
val onEndIconClick: (() -> Unit)?,
constraints: List<ParameterConstraint>
) : Parameter<T>(name, description, default, constraints)
abstract class TextFieldParameterBuilder<T>(var startIcon: Int? = null,
var endIcon: Int? = null,
var onStartIconClick: (() -> Unit)? = null,
var onEndIconClick: (() -> Unit)? = null
abstract class TextFieldParameterBuilder<T>(
var startIcon: ((TextFieldParameter<T>) -> Int)? = null,
var endIcon: ((TextFieldParameter<T>) -> Int)? = null,
var onStartIconClick: (() -> Unit)? = null,
var onEndIconClick: (() -> Unit)? = null
) : ParameterBuilder<T>()
class StringParameter(@StringRes name: Int, @StringRes description: Int?,
default: String, startIcon: Int?, endIcon: Int?,
default: String,
startIcon: ((TextFieldParameter<String>) -> Int)?,
endIcon: ((TextFieldParameter<String>) -> Int)?,
onStartIconClick: (() -> Unit)?,
onEndIconClick: (() -> Unit)?,
constraints: List<ParameterConstraint>
@@ -249,7 +254,8 @@ class StringParameterBuilder : TextFieldParameterBuilder<String>() {
class EnumParameter<T : Enum<*>>(@StringRes name: Int,
@StringRes description: Int?, default: T,
startIcon: Int?, endIcon: Int?,
startIcon: ((TextFieldParameter<T>) -> Int)?,
endIcon: ((TextFieldParameter<T>) -> Int)?,
onStartIconClick: (() -> Unit)?,
onEndIconClick: (() -> Unit)?,
constraints: List<ParameterConstraint>,
@@ -290,7 +296,7 @@ fun projectNameParameter(configure: StringParameterBuilder.() -> Unit = {}) =
stringParameter {
name = string.project_app_name
default = "My Application"
startIcon = R.drawable.ic_android
startIcon = { R.drawable.ic_android }
constraints = listOf(NONEMPTY)
configure()
@@ -300,7 +306,7 @@ fun packageNameParameter(configure: StringParameterBuilder.() -> Unit = {}) =
stringParameter {
name = string.package_name
default = "com.example.myapplication"
startIcon = R.drawable.ic_package
startIcon = { R.drawable.ic_package }
constraints = listOf(NONEMPTY, PACKAGE)
configure()
@@ -312,7 +318,10 @@ fun projectLanguageParameter(
name = string.wizard_language
default = Java
displayName = Language::lang
startIcon = R.drawable.ic_language_java
startIcon = {
if (it.value == Kotlin) R.drawable.ic_language_kotlin
else R.drawable.ic_language_java
}
configure()
}
@@ -322,7 +331,7 @@ fun minSdkParameter(configure: EnumParameterBuilder<Sdk>.() -> Unit = {}) =
name = string.minimum_sdk
default = Sdk.Lollipop
displayName = Sdk::displayName
startIcon = R.drawable.ic_min_sdk
startIcon = { R.drawable.ic_min_sdk }
configure()
}
@@ -113,6 +113,7 @@ class TemplateWidgetViewProviderImpl : ITemplateWidgetViewProvider {
param.configureTextField(context, root) { value ->
observer.disableAndRun {
param.setValue(value)
param.resetStartAndEndIcons(root.context, root)
}
val err =
@@ -174,12 +175,6 @@ class TemplateWidgetViewProviderImpl : ITemplateWidgetViewProvider {
}
}
param.configureTextField(context, root) {
observer.disableAndRun {
param.setValue(nameToEnum[it] ?: param.default)
}
}
if (param.default != nameToEnum[defaultName]) {
// the default value may have been filtered
// reset the value to the first item
@@ -188,6 +183,13 @@ class TemplateWidgetViewProviderImpl : ITemplateWidgetViewProvider {
param.setValue(first)
}
param.configureTextField(context, root) {
observer.disableAndRun {
param.setValue(nameToEnum[it] ?: param.default)
param.resetStartAndEndIcons(root.context, root)
}
}
param.observe(observer)
}.root
}
@@ -197,21 +199,7 @@ class TemplateWidgetViewProviderImpl : ITemplateWidgetViewProvider {
onTextChanged: (String) -> Unit = {}
) {
root.setHint(name)
startIcon?.let {
root.startIconDrawable = ContextCompat.getDrawable(context, it)
onStartIconClick?.let { onClick ->
root.setStartIconOnClickListener { onClick() }
}
}
endIcon?.let {
root.endIconDrawable = ContextCompat.getDrawable(context, it)
onEndIconClick?.let { onClick ->
root.setEndIconOnClickListener { onClick() }
}
}
resetStartAndEndIcons(context, root)
root.editText!!.addTextChangedListener(object : SingleTextWatcher() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int,
count: Int
@@ -220,4 +208,22 @@ class TemplateWidgetViewProviderImpl : ITemplateWidgetViewProvider {
}
})
}
private fun <T> TextFieldParameter<T>.resetStartAndEndIcons(context: Context,
root: TextInputLayout
) {
startIcon?.let {
root.startIconDrawable = ContextCompat.getDrawable(context, it(this))
onStartIconClick?.let { onClick ->
root.setStartIconOnClickListener { onClick() }
}
}
endIcon?.let {
root.endIconDrawable = ContextCompat.getDrawable(context, it(this))
onEndIconClick?.let { onClick ->
root.setEndIconOnClickListener { onClick() }
}
}
}
}