feat: use attribute handlers to apply attributes in IViewAdapter

This commit is contained in:
Akash Yadav
2022-12-18 18:10:21 +05:30
parent 341931c902
commit 97193ca11d
40 changed files with 627 additions and 820 deletions
@@ -48,7 +48,15 @@ import javax.tools.Diagnostic.Kind.ERROR
class ViewAdapterAnnotationProcessor : AbstractProcessor() {
private val adapterElement by lazy {
processingEnv.elementUtils.getTypeElement(ADAPTER_BASE_CLASS)
processingEnv.typeUtils.erasure(
processingEnv.elementUtils.getTypeElement(ADAPTER_BASE_CLASS).asType()
)
}
private val viewElement by lazy {
processingEnv.typeUtils.erasure(
processingEnv.elementUtils.getTypeElement("android.view.View").asType()
)
}
private val indexClassBuilder =
@@ -143,11 +151,31 @@ class ViewAdapterAnnotationProcessor : AbstractProcessor() {
return
}
if (!processingEnv.typeUtils.isSubtype(element.asType(), adapterElement.asType())) {
if (
!processingEnv.typeUtils.isAssignable(
processingEnv.typeUtils.erasure(element.asType()),
adapterElement
)
) {
processingEnv.messager.printMessage(ERROR, "Class must be a subtype of $ADAPTER_BASE_CLASS")
return
}
if (element.typeParameters.size != 1) {
processingEnv.messager.printMessage(
ERROR,
"A view adapter must have exactly one type parameter"
)
}
val typeParam = element.typeParameters[0]
if (!processingEnv.typeUtils.isAssignable(typeParam.asType(), viewElement)) {
processingEnv.messager.printMessage(
ERROR,
"The type parameter of view adapter must be assignable from android.view.View"
)
}
val annotation = element.getAnnotation(ViewAdapter::class.java) ?: throw IllegalStateException()
val viewName = getViewName(annotation)
@@ -157,9 +185,13 @@ class ViewAdapterAnnotationProcessor : AbstractProcessor() {
for (superclass in superclasses) {
block.addStatement("superclasses.add(\$S)", superclass)
}
val adapterType = ClassName.get(element)
val paramType = getViewTypeName(annotation)
block.add("\n")
block.addStatement("final var adapter = new \$T()", TypeName.get(element.asType()))
block.addStatement("final var adapter = new \$T()", ParameterizedTypeName.get(adapterType, paramType))
block.addStatement("adapter.\$L(superclasses)", METHOD_SET_SUPERCLASS_HIERARCHY)
block.addStatement("adapter.\$L(\$S)", METHOD_SET_MODULE, annotation.moduleNamespace)
block.addStatement("\$L.put(\$S, adapter)", INDEX_MAP_FIELD, viewName)
@@ -181,7 +213,7 @@ class ViewAdapterAnnotationProcessor : AbstractProcessor() {
)
indexClassBuilder.addField(
FieldSpec.builder(type, INDEX_MAP_FIELD, PRIVATE, STATIC, FINAL)
.initializer("new \$T<>();", HashMap::class.java)
.initializer("new \$T<>()", HashMap::class.java)
.build()
)
@@ -210,6 +242,15 @@ class ViewAdapterAnnotationProcessor : AbstractProcessor() {
.build()
)
}
private fun getViewTypeName(annotation: ViewAdapter) : TypeName {
return try {
ClassName.get(annotation.forView.java)
?: throw IllegalStateException("Cannot find type of $annotation")
} catch (err: MirroredTypeException) {
(processingEnv.typeUtils.asElement(err.typeMirror) as TypeElement).let { ClassName.get(it) }
}
}
private fun getViewName(annotation: ViewAdapter): String {
return try {
@@ -232,7 +273,7 @@ class ViewAdapterAnnotationProcessor : AbstractProcessor() {
} catch (err: MirroredTypeException) {
val typeElement = processingEnv.typeUtils.asElement(err.typeMirror) as TypeElement
result.add(typeElement.qualifiedName.toString())
var superclass = typeElement.superclass
while (superclass != null) {
val superType = processingEnv.typeUtils.asElement(superclass) as? TypeElement?
Binary file not shown.
@@ -376,8 +376,25 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
* @param pck The package to look for.
*/
fun findResourceTableForPackage(pck: String, hasGroup: AaptResourceType? = null): ResourceTable? {
return findAllResourceTableForPackage(pck, hasGroup).let {
if (it.isNotEmpty()) {
return it.first()
} else null
}
}
/**
* Checks all the resource tables from this module and returns if any of the tables contain
* resources for the the given package.
*
* @param pck The package to look for.
*/
fun findAllResourceTableForPackage(
pck: String,
hasGroup: AaptResourceType? = null
): List<ResourceTable> {
if (pck == SdkConstants.ANDROID_PKG) {
return getFrameworkResourceTable()
return getFrameworkResourceTable()?.let { listOf(it) } ?: emptyList()
}
val tables: List<ResourceTable> =
@@ -387,17 +404,20 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
addAll(getDependencyResourceTables())
}
val result = mutableListOf<ResourceTable>()
for (table in tables) {
val resPck = table.findPackage(pck) ?: continue
if (hasGroup == null) {
return table
result.add(table)
continue
}
if (resPck.findGroup(hasGroup) != null) {
return table
result.add(table)
continue
}
}
return null
return emptyList()
}
/**
Binary file not shown.
@@ -23,7 +23,15 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.android.aaptcompiler.AaptResourceType.STYLEABLE
import com.android.aaptcompiler.AttributeResource
import com.android.aaptcompiler.ConfigDescription
import com.android.aaptcompiler.Styleable
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.itsaky.androidide.inflater.internal.ViewAdapterIndex
import com.itsaky.androidide.inflater.internal.ViewImpl
import com.itsaky.androidide.projects.ProjectManager
import com.itsaky.androidide.projects.api.AndroidModule
import com.itsaky.androidide.uidesigner.adapters.ViewAttrListAdapter
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoBinding
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoHeaderBinding
@@ -31,6 +39,8 @@ import com.itsaky.androidide.uidesigner.models.UiAttribute
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_VALUE_EDITOR
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_VIEW_INFO
import com.itsaky.androidide.utils.ILogger
import java.util.TreeSet
/**
* A [BottomSheetDialogFragment] which shows information about a clicked view.
@@ -53,6 +63,7 @@ class ViewInfoFragment : Fragment() {
}
private var header: LayoutViewInfoHeaderBinding? = null
private val log = ILogger.newInstance("ViewInfoFragment")
companion object {
const val TAG = "ide.uidesigner.viewinfo"
@@ -86,7 +97,8 @@ class ViewInfoFragment : Fragment() {
private fun showViewInfo() {
val binding = this.binding ?: return
val header = this.header ?: return
val view = this.viewModel.view ?: return
val view = this.viewModel.view as? ViewImpl ?: return
val adapter = ViewAdapterIndex.getAdapter(view.name) ?: return
header.name.text = view.simpleName
header.desc.text = view.name
@@ -21,6 +21,7 @@ import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.AttributeImpl
import com.itsaky.androidide.inflater.internal.ViewAdapterIndex
/**
* UI Designer specific implementation of [IAttribute].
@@ -36,7 +37,7 @@ constructor(
) : AttributeImpl(namespace, name, value) {
constructor(src: IAttribute) : this(namespace = src.namespace, name = src.name, value = src.value)
/**
* Whether this attribute is required or not. Required attributes cannot be removed from a view
* once applied.
@@ -25,6 +25,7 @@ import com.itsaky.androidide.inflater.LayoutBehavior.HORIZONTAL
import com.itsaky.androidide.inflater.LayoutBehavior.TOP_LEFT
import com.itsaky.androidide.inflater.LayoutBehavior.VERTICAL
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.internal.ViewAdapterIndex
import com.itsaky.androidide.inflater.internal.ViewGroupImpl
/**
@@ -0,0 +1,36 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.inflater
import android.content.Context
import android.view.View
import android.view.ViewGroup
import com.itsaky.androidide.inflater.internal.LayoutFile
/**
* @author Akash Yadav
*/
data class AttributeHandlerScope<T : View>(
val view: T,
val file: LayoutFile,
val context: Context,
val layoutParams: ViewGroup.LayoutParams,
val namespace: INamespace,
val name: String,
val value: String
)
@@ -17,12 +17,17 @@
package com.itsaky.androidide.inflater
import android.view.View
import com.android.SdkConstants
import com.itsaky.androidide.inflater.internal.AttributeImpl
import com.itsaky.androidide.inflater.internal.ViewImpl
/**
* Handles logic for applying attributes to a view.
*
* @author Akash Yadav
*/
abstract class IViewAdapter : AbstractParser() {
abstract class IViewAdapter<T : View> : AbstractParser() {
/** Superclasses of the view that this adpater handles. */
var superclassHierarchy: List<String> = emptyList()
@@ -34,9 +39,9 @@ abstract class IViewAdapter : AbstractParser() {
}
/**
* The package name or namespace of the module/artifact in which the view that this adapter handles is defined.
* The value is set to "android" by default unless explicitly specified in the [ViewAdapter]
* [com.itsaky.androidide.annotations.inflater.ViewAdapter] annotation.
* The package name or namespace of the module/artifact in which the view that this adapter
* handles is defined. The value is set to "android" by default unless explicitly specified in the
* [ViewAdapter][com.itsaky.androidide.annotations.inflater.ViewAdapter] annotation.
*
* This is used by the UI designer to quickly look for attributes of an inflated view from the
* resource tables.
@@ -49,6 +54,19 @@ abstract class IViewAdapter : AbstractParser() {
field = value
}
/** The attributes that are supported by the adapter. The attributes in the list are immutable. */
val supportedAttributes by lazy {
attributeHandlers.map {
AttributeImpl(namespace = defaultNamespace(), name = it.key, value = "").immutable()
}
}
private val attributeHandlers by lazy {
val handlers = mutableMapOf<String, AttributeHandlerScope<T>.() -> Unit>()
createAttrHandlers(handlers::put)
return@lazy handlers
}
/**
* Apply the given attribute to the given view.
*
@@ -56,7 +74,9 @@ abstract class IViewAdapter : AbstractParser() {
* @param attribute The attribute to apply.
* @return Whether the attribute was applied or not.
*/
abstract fun apply(view: IView, attribute: IAttribute): Boolean
open fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply(view, attribute) { applyInternal() }
}
/**
* Apply the basic attributes to a view so that it could be rendered.
@@ -73,4 +93,70 @@ abstract class IViewAdapter : AbstractParser() {
* @return `true` if the attribute is required, `false` otherwise.
*/
abstract fun isRequiredAttribute(attribute: IAttribute): Boolean
/**
* The default namespace that will be used by the UI designer to create and apply new attributes.
*/
protected open fun defaultNamespace(): INamespace {
return INamespace.ANDROID
}
protected open fun canHandleNamespace(namespace: INamespace): Boolean {
return this.canHandleNamespace(namespace.uri)
}
protected open fun canHandleNamespace(nsUri: String): Boolean {
return SdkConstants.ANDROID_URI == nsUri
}
protected open fun AttributeHandlerScope<T>.applyInternal(): Boolean {
val handler = attributeHandlers[name]
if (handler != null) {
handler()
}
return handler != null || applyLayoutParams()
}
protected open fun AttributeHandlerScope<T>.applyLayoutParams(): Boolean {
return false
}
/**
* Provides easy access to various properties related to the view and attribute when applying an
* attributes.
*/
private fun doApply(
view: IView,
attribute: IAttribute,
apply: AttributeHandlerScope<T>.() -> Boolean,
): Boolean {
if (!canHandleNamespace(attribute.namespace)) {
return false
}
@Suppress("UNCHECKED_CAST")
return (view.view as T).let {
val file = (view as ViewImpl).file
return@let AttributeHandlerScope(
it,
file,
it.context,
it.layoutParams,
attribute.namespace,
attribute.name,
attribute.value
)
.let(apply)
}
}
/**
* Creates the attribute handlers. Subclasses are expected to use the [create] function to create
* new handlers.
*
* A subclass should call the `super` method and add only the view specific attribute handlers.
*/
protected open fun createAttrHandlers(
create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit
) {}
}
@@ -18,6 +18,7 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.widget.AbsListView
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.IView
@@ -26,30 +27,19 @@ import com.itsaky.androidide.inflater.IView
*
* @author Akash Yadav
*/
abstract class AbsListViewAttrAdapter : AdapterViewAttrAdapter() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<AbsListView>(view, attribute) { _, context, _, _, name, value ->
var applied = true
when (name) {
"cacheColorHint" -> cacheColorHint = parseColor(context, value)
"choiceMode" -> choiceMode = parseChoiceMode(value)
"drawSelectorOnTop" -> isDrawSelectorOnTop = parseBoolean(value)
"fastScrollEnabled" -> isFastScrollEnabled = parseBoolean(value)
"listSelector" -> selector = parseDrawable(context, value)
"smoothScrollbar" -> isSmoothScrollbarEnabled = parseBoolean(value)
"stackFromBottom" -> isStackFromBottom = parseBoolean(value)
"textFilterEnabled" -> isTextFilterEnabled = parseBoolean(value)
"transcriptMode" -> transcriptMode = parseTranscriptMode(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
abstract class AbsListViewAttrAdapter<T : AbsListView> : AdapterViewAttrAdapter<T>() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("cacheColorHint") { view.cacheColorHint = parseColor(context, value) }
create("choiceMode") { view.choiceMode = parseChoiceMode(value) }
create("drawSelectorOnTop") { view.isDrawSelectorOnTop = parseBoolean(value) }
create("fastScrollEnabled") { view.isFastScrollEnabled = parseBoolean(value) }
create("listSelector") { view.selector = parseDrawable(context, value) }
create("smoothScrollbar") { view.isSmoothScrollbarEnabled = parseBoolean(value) }
create("stackFromBottom") { view.isStackFromBottom = parseBoolean(value) }
create("textFilterEnabled") { view.isTextFilterEnabled = parseBoolean(value) }
create("transcriptMode") { view.transcriptMode = parseTranscriptMode(value) }
}
protected open fun parseTranscriptMode(value: String): Int {
@@ -18,39 +18,20 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.widget.AbsSeekBar
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [AbsSeekBar].
*
* @author Akash Yadav
*/
abstract class AbsSeekBarAttrAdapter : ProgressBarAttrAdapter() {
abstract class AbsSeekBarAttrAdapter<T : AbsSeekBar> : ProgressBarAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<AbsSeekBar>(view, attribute) {
_,
context,
_,
_,
name,
value ->
var applied = true
when (name) {
"thumbTint" -> thumbTintList = parseColorStateList(context, value)
"thumbTintMode" -> thumbTintMode = parsePorterDuffMode(value)
"tickMarkTint" -> tickMarkTintList = parseColorStateList(context, value)
"tickMarkTintMode" -> tickMarkTintMode = parsePorterDuffMode(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("thumbTint") { view.thumbTintList = parseColorStateList(context, value) }
create("thumbTintMode") { view.thumbTintMode = parsePorterDuffMode(value) }
create("tickMarkTint") { view.tickMarkTintList = parseColorStateList(context, value) }
create("tickMarkTintMode") { view.tickMarkTintMode = parsePorterDuffMode(value) }
}
}
@@ -18,44 +18,22 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.R.layout
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.AbsSpinner
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [AbsSpinner].
*
* @author Akash Yadav
*/
abstract class AbsSpinnerAttrAdapter : AdapterViewAttrAdapter() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<AbsSpinner>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"entries" -> {
val array = parseStringArray(value)
val adapter = newSimpleAdapter(context, array)
adapter.setDropDownViewResource(layout.simple_spinner_dropdown_item)
setAdapter(adapter)
}
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
abstract class AbsSpinnerAttrAdapter<T : AbsSpinner> : AdapterViewAttrAdapter<T>() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("entries") {
val array = parseStringArray(value)
val adapter = newSimpleAdapter(context, array)
adapter.setDropDownViewResource(layout.simple_spinner_dropdown_item)
view.adapter = adapter
}
}
}
@@ -27,4 +27,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
*/
@Suppress("DEPRECATION")
@ViewAdapter(AbsoluteLayout::class)
open class AbsoluteLayoutAttrAdapter : ViewGroupAttrAdapter()
open class AbsoluteLayoutAttrAdapter<T : AbsoluteLayout> : ViewGroupAttrAdapter<T>()
@@ -29,7 +29,7 @@ import com.itsaky.androidide.inflater.internal.ViewGroupImpl
*
* @author Akash Yadav
*/
abstract class AdapterViewAttrAdapter : ViewGroupAttrAdapter() {
abstract class AdapterViewAttrAdapter<T: AdapterView<*>> : ViewGroupAttrAdapter<T>() {
companion object {
const val ADAPTER_DEFAULT_ITEM_COUNT = 3
@@ -17,14 +17,9 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.AutoCompleteTextView
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [AutoCompleteTextView].
@@ -32,30 +27,14 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(AutoCompleteTextView::class)
class AutoCompleteTextViewAttrAdapter : EditTextAttrAdapter() {
open class AutoCompleteTextViewAttrAdapter<T : AutoCompleteTextView> : EditTextAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<AutoCompleteTextView>(view, attribute) {
file: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"completionHint" -> completionHint = parseString(value)
"completionThreshold" -> threshold = parseInteger(value, 1)
"dropDownAnchor" -> dropDownAnchor = parseId(file.resName, value)
"dropDownWidth" -> dropDownWidth = parseDimension(context, value)
"dropDownHeight" -> dropDownHeight = parseDimension(context, value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("completionHint") { view.completionHint = parseString(value) }
create("completionThreshold") { view.threshold = parseInteger(value, 1) }
create("dropDownAnchor") { view.dropDownAnchor = parseId(file.resName, value) }
create("dropDownWidth") { view.dropDownWidth = parseDimension(context, value) }
create("dropDownHeight") { view.dropDownHeight = parseDimension(context, value) }
}
}
@@ -25,4 +25,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
*
* @author Akash Yadav
*/
@ViewAdapter(Button::class) open class ButtonAttrAdapter : TextViewAttrAdapter()
@ViewAdapter(Button::class) open class ButtonAttrAdapter<T : Button> : TextViewAttrAdapter<T>()
@@ -25,4 +25,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
*
* @author Akash Yadav
*/
@ViewAdapter(CheckBox::class) class CheckBoxAttrAdapter : CompoundButtonAttrAdapter()
@ViewAdapter(CheckBox::class) open class CheckBoxAttrAdapter<T : CheckBox> : CompoundButtonAttrAdapter<T>()
@@ -19,8 +19,7 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.CheckedTextView
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [CheckedTextView].
@@ -28,24 +27,11 @@ import com.itsaky.androidide.inflater.IView
* @author Akash Yadav
*/
@ViewAdapter(CheckedTextView::class)
class CheckedTextViewAttrAdapter : TextViewAttrAdapter() {
open class CheckedTextViewAttrAdapter<T : CheckedTextView> : TextViewAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<CheckedTextView>(view, attribute) { _, context, _, _, name, value ->
var applied = true
when (name) {
"checkMarkTintMode" -> checkMarkTintMode = parsePorterDuffMode(value)
"checkMarkTint" -> checkMarkTintList = parseColorStateList(context, value)
"checkMark" -> {} // ignored
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("checkMarkTintMode") { view.checkMarkTintMode = parsePorterDuffMode(value) }
create("checkMarkTint") { view.checkMarkTintList = parseColorStateList(context, value) }
}
}
@@ -17,45 +17,23 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.CompoundButton
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
/**
* Attribute adapter for [CompoundButton].
*
* @author Akash Yadav
*/
abstract class CompoundButtonAttrAdapter : ButtonAttrAdapter() {
abstract class CompoundButtonAttrAdapter<T : CompoundButton> : ButtonAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<CompoundButton>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"buttonTint" -> buttonTintList = parseColorStateList(context, value)
"button" -> buttonDrawable = parseDrawable(context, value)
"buttonTintMode" -> buttonTintMode = parsePorterDuffMode(value)
"checked" -> isChecked = parseBoolean(value = value, def = true)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("buttonTint") { view.buttonTintList = parseColorStateList(context, value) }
create("button") { view.buttonDrawable = parseDrawable(context, value) }
create("buttonTintMode") { view.buttonTintMode = parsePorterDuffMode(value) }
create("checked") { view.isChecked = parseBoolean(value = value, def = true) }
}
override fun applyBasic(view: IView) {
@@ -26,4 +26,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* @author Akash Yadav
*/
@ViewAdapter(EditText::class)
open class EditTextAttrAdapter : TextViewAttrAdapter()
open class EditTextAttrAdapter<T : EditText> : TextViewAttrAdapter<T>()
@@ -21,6 +21,7 @@ import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.FrameLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
@@ -32,29 +33,11 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(FrameLayout::class)
open class FrameLayoutAttrAdapter : ViewGroupAttrAdapter() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<FrameLayout>(view, attribute) {
_: LayoutFile,
_: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"foregroundGravity" -> foregroundGravity = parseGravity(value)
"measureAllChildren" -> measureAllChildren = parseBoolean(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
open class FrameLayoutAttrAdapter<T : FrameLayout> : ViewGroupAttrAdapter<T>() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("foregroundGravity") { view.foregroundGravity = parseGravity(value) }
create("measureAllChildren") { view.measureAllChildren = parseBoolean(value) }
}
}
@@ -22,6 +22,7 @@ import android.gesture.GestureOverlayView
import android.view.ViewGroup.LayoutParams
import com.blankj.utilcode.util.ReflectUtils
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
@@ -33,42 +34,24 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(GestureOverlayView::class)
open class GestureOverlayViewAttrAdapter : FrameLayoutAttrAdapter() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<GestureOverlayView>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"eventsInterceptionEnabled" -> isEventsInterceptionEnabled = parseBoolean(value)
"fadeDuration" ->
ReflectUtils.reflect(gesture).field("mFadeDuration", parseLong(value, 150))
"fadeEnabled" -> isFadeEnabled = parseBoolean(value)
"fadeOffset" -> fadeOffset = parseLong(value, 420)
"gestureColor" -> gestureColor = parseColor(context, value)
"gestureStrokeAngleThreshold" -> gestureStrokeAngleThreshold = parseFloat(value)
"gestureStrokeLengthThreshold" -> gestureStrokeLengthThreshold = parseFloat(value)
"gestureStrokeSquarenessThreshold" -> gestureStrokeSquarenessTreshold = parseFloat(value)
"gestureStrokeType" -> gestureStrokeType = parseGestureStrokeType(value)
"gestureStrokeWidth" -> gestureStrokeWidth = parseFloat(value)
"orientation" -> orientation = parseOrientation(value)
"uncertainGestureColor" -> uncertainGestureColor = parseColor(context, value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
open class GestureOverlayViewAttrAdapter<T : GestureOverlayView> : FrameLayoutAttrAdapter<T>() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("eventsInterceptionEnabled") { view.isEventsInterceptionEnabled = parseBoolean(value) }
create("fadeDuration") { ReflectUtils.reflect(view).field("mFadeDuration", parseLong(value, 150)) }
create("fadeEnabled") { view.isFadeEnabled = parseBoolean(value) }
create("fadeOffset") { view.fadeOffset = parseLong(value, 420) }
create("gestureColor") { view.gestureColor = parseColor(context, value) }
create("gestureStrokeAngleThreshold") { view.gestureStrokeAngleThreshold = parseFloat(value) }
create("gestureStrokeLengthThreshold") { view.gestureStrokeLengthThreshold = parseFloat(value) }
create("gestureStrokeSquarenessThreshold") { view.gestureStrokeSquarenessTreshold = parseFloat(value) }
create("gestureStrokeType") { view.gestureStrokeType = parseGestureStrokeType(value) }
create("gestureStrokeWidth") { view.gestureStrokeWidth = parseFloat(value) }
create("orientation") { view.orientation = parseOrientation(value) }
create("uncertainGestureColor") { view.uncertainGestureColor = parseColor(context, value) }
}
protected open fun parseOrientation(value: String): Int {
return if ("horizontal" == value) {
GestureOverlayView.ORIENTATION_HORIZONTAL
@@ -17,14 +17,9 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.GridLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [GridLayout].
@@ -32,33 +27,16 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(GridLayout::class)
open class GridLayoutAttrAdapter : ViewGroupAttrAdapter() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<GridLayout>(view, attribute) {
_: LayoutFile,
_: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"alignmentMode" -> alignmentMode = parseAlignmentMode(value)
"columnCount" -> columnCount = parseInteger(value, Int.MIN_VALUE)
"columnOrderPreserved" -> isColumnOrderPreserved = parseBoolean(value)
"orientation" -> orientation = parseOrientation(value)
"rowCount" -> rowCount = parseInteger(value, Int.MIN_VALUE)
"rowOrderPreserved" -> isRowOrderPreserved = parseBoolean(value)
"useDefaultMargins" -> useDefaultMargins = parseBoolean(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
open class GridLayoutAttrAdapter<T : GridLayout> : ViewGroupAttrAdapter<T>() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("alignmentMode") { view.alignmentMode = parseAlignmentMode(value) }
create("columnCount") { view.columnCount = parseInteger(value, Int.MIN_VALUE) }
create("columnOrderPreserved") { view.isColumnOrderPreserved = parseBoolean(value) }
create("orientation") { view.orientation = parseOrientation(value) }
create("rowCount") { view.rowCount = parseInteger(value, Int.MIN_VALUE) }
create("rowOrderPreserved") { view.isRowOrderPreserved = parseBoolean(value) }
create("useDefaultMargins") { view.useDefaultMargins = parseBoolean(value) }
}
protected open fun parseOrientation(value: String): Int {
@@ -25,4 +25,5 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
*
* @author Akash Yadav
*/
@ViewAdapter(ImageButton::class) class ImageButtonAttrAdapter : ImageViewAttrAdapter()
@ViewAdapter(ImageButton::class)
open class ImageButtonAttrAdapter<T : ImageButton> : ImageViewAttrAdapter<T>()
@@ -17,8 +17,6 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.ImageView
import android.widget.ImageView.ScaleType
import android.widget.ImageView.ScaleType.CENTER
@@ -30,11 +28,9 @@ import android.widget.ImageView.ScaleType.FIT_START
import android.widget.ImageView.ScaleType.FIT_XY
import android.widget.ImageView.ScaleType.MATRIX
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.R
import com.itsaky.androidide.inflater.internal.LayoutFile
/**
* Attribute adpater [ImageView]s.
@@ -42,38 +38,20 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(ImageView::class)
open class ImageViewAttrAdapter : ViewAttrAdapter() {
open class ImageViewAttrAdapter<T : ImageView> : ViewAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<ImageView>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"adjustViewBounds" -> adjustViewBounds = parseBoolean(value)
"baseline" -> baseline = parseDimension(context, value, 0)
"baselineAlignBottom" -> baselineAlignBottom = parseBoolean(value)
"cropToPadding" -> cropToPadding = parseBoolean(value)
"maxHeight" -> maxHeight = parseDimension(context, value, 0)
"maxWidth" -> maxWidth = parseDimension(context, value, 0)
"scaleType" -> scaleType = parseScaleType(value)
"src" -> setImageDrawable(parseDrawable(context, value))
"tint" -> imageTintList = parseColorStateList(context, value)
"tintMode" -> imageTintMode = parsePorterDuffMode(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("adjustViewBounds") { view.adjustViewBounds = parseBoolean(value) }
create("baseline") { view.baseline = parseDimension(context, value, 0) }
create("baselineAlignBottom") { view.baselineAlignBottom = parseBoolean(value) }
create("cropToPadding") { view.cropToPadding = parseBoolean(value) }
create("maxHeight") { view.maxHeight = parseDimension(context, value, 0) }
create("maxWidth") { view.maxWidth = parseDimension(context, value, 0) }
create("scaleType") { view.scaleType = parseScaleType(value) }
create("src") { view.setImageDrawable(parseDrawable(context, value)) }
create("tint") { view.imageTintList = parseColorStateList(context, value) }
create("tintMode") { view.imageTintMode = parsePorterDuffMode(value) }
}
override fun applyBasic(view: IView) {
@@ -17,18 +17,14 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.LinearLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.IViewGroup
import com.itsaky.androidide.inflater.LayoutBehavior
import com.itsaky.androidide.inflater.LayoutBehavior.HORIZONTAL
import com.itsaky.androidide.inflater.LayoutBehavior.VERTICAL
import com.itsaky.androidide.inflater.internal.LayoutFile
/**
* Attribute adapter for [LinearLayout].
@@ -36,34 +32,21 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(LinearLayout::class)
open class LinearLayoutAttrAdapter : ViewGroupAttrAdapter() {
open class LinearLayoutAttrAdapter<T : LinearLayout> : ViewGroupAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<LinearLayout>(view, attribute) {
_: LayoutFile,
_: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
when (name) {
"baselineAligned" -> isBaselineAligned = parseBoolean(value)
"baselineAlignedChildIndex" -> baselineAlignedChildIndex = parseInteger(value, childCount)
"gravity" -> gravity = parseGravity(value)
"measureWithLargestChild" -> isMeasureWithLargestChildEnabled = parseBoolean(value)
"orientation" -> orientation = parseOrientation(value)
"weightSum" -> weightSum = parseFloat(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
create("baselineAligned") { view.isBaselineAligned = parseBoolean(value) }
create("baselineAlignedChildIndex") {
view.baselineAlignedChildIndex = parseInteger(value, view.childCount)
}
create("gravity") { view.gravity = parseGravity(value) }
create("measureWithLargestChild") {
view.isMeasureWithLargestChildEnabled = parseBoolean(value)
}
create("orientation") { view.orientation = parseOrientation(value) }
create("weightSum") { view.weightSum = parseFloat(value) }
}
override fun getLayoutBehavior(group: IViewGroup): LayoutBehavior {
@@ -18,16 +18,11 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.R.layout
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.ArrayAdapter
import android.widget.ListView
import com.blankj.utilcode.util.SizeUtils
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [ListView].
@@ -35,34 +30,19 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(ListView::class)
class ListViewAttrAdapter : AbsListViewAttrAdapter() {
open class ListViewAttrAdapter<T : ListView> : AbsListViewAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<ListView>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"divider" -> divider = parseDrawable(context, value)
"dividerHeight" -> dividerHeight = parseDimension(context, value, SizeUtils.dp2px(1f))
"entries" -> {
val entries = parseStringArray(value)
adapter = ArrayAdapter(context, layout.simple_list_item_1, entries)
}
"footerDividersEnabled" -> setFooterDividersEnabled(parseBoolean(value))
"headerDividersEnabled" -> setHeaderDividersEnabled(parseBoolean(value))
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("divider") { view.divider = parseDrawable(context, value) }
create("dividerHeight") {
view.dividerHeight = parseDimension(context, value, SizeUtils.dp2px(1f))
}
create("entries") {
val entries = parseStringArray(value)
view.adapter = ArrayAdapter(context, layout.simple_list_item_1, entries)
}
create("footerDividersEnabled") { view.setFooterDividersEnabled(parseBoolean(value)) }
create("headerDividersEnabled") { view.setHeaderDividersEnabled(parseBoolean(value)) }
}
}
@@ -21,6 +21,7 @@ import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.ProgressBar
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
@@ -32,58 +33,52 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(ProgressBar::class)
open class ProgressBarAttrAdapter : ViewAttrAdapter() {
open class ProgressBarAttrAdapter<T : ProgressBar> : ViewAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<ProgressBar>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"indeterminate" -> isIndeterminate = parseBoolean(value)
"indeterminateDrawable" -> indeterminateDrawable = parseDrawable(context, value)
"indeterminateTint" -> indeterminateTintList = parseColorStateList(context, value)
"indeterminateTintMode" -> indeterminateTintMode = parsePorterDuffMode(value)
"max" -> max = parseInteger(value, 100)
"maxHeight" ->
if (isApi29()) {
maxHeight = parseDimension(context, value, Int.MAX_VALUE)
}
"maxWidth" ->
if (isApi29()) {
maxWidth = parseDimension(context, value, Int.MAX_VALUE)
}
"min" -> min = parseInteger(value, 0)
"minHeight" ->
if (isApi29()) {
minHeight = parseDimension(context, value, 0)
}
"minWidth" ->
if (isApi29()) {
minWidth = parseDimension(context, value, 0)
}
"progress" -> progress = parseInteger(value, 50)
"progressBackgroundTint" -> progressBackgroundTintList = parseColorStateList(context, value)
"progressBackgroundTintMode" -> progressBackgroundTintMode = parsePorterDuffMode(value)
"progressDrawable" -> progressDrawable = parseDrawable(context, value)
"progressTint" -> progressTintList = parseColorStateList(context, value)
"progressTintMode" -> progressTintMode = parsePorterDuffMode(value)
"secondaryProgress" -> secondaryProgress = parseInteger(value, 0)
"secondaryProgressTint" -> secondaryProgressTintList = parseColorStateList(context, value)
"secondaryProgressTintMode" -> secondaryProgressTintMode = parsePorterDuffMode(value)
else -> applied = false
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("indeterminate") { view.isIndeterminate = parseBoolean(value) }
create("indeterminateDrawable") { view.indeterminateDrawable = parseDrawable(context, value) }
create("indeterminateTint") { view.indeterminateTintList = parseColorStateList(context, value) }
create("indeterminateTintMode") { view.indeterminateTintMode = parsePorterDuffMode(value) }
create("max") { view.max = parseInteger(value, 100) }
create("maxHeight") {
if (isApi29()) {
view.maxHeight = parseDimension(context, value, Int.MAX_VALUE)
}
if (!applied) {
applied = super.apply(view, attribute)
}
create("maxWidth") {
if (isApi29()) {
view.maxWidth = parseDimension(context, value, Int.MAX_VALUE)
}
return@doApply applied
}
create("min") { view.min = parseInteger(value, 0) }
create("minHeight") {
if (isApi29()) {
view.minHeight = parseDimension(context, value, 0)
}
}
create("minWidth") {
if (isApi29()) {
view.minWidth = parseDimension(context, value, 0)
}
}
create("progress") { view.progress = parseInteger(value, 50) }
create("progressBackgroundTint") {
view.progressBackgroundTintList = parseColorStateList(context, value)
}
create("progressBackgroundTintMode") {
view.progressBackgroundTintMode = parsePorterDuffMode(value)
}
create("progressDrawable") { view.progressDrawable = parseDrawable(context, value) }
create("progressTint") { view.progressTintList = parseColorStateList(context, value) }
create("progressTintMode") { view.progressTintMode = parsePorterDuffMode(value) }
create("secondaryProgress") { view.secondaryProgress = parseInteger(value, 0) }
create("secondaryProgressTint") {
view.secondaryProgressTintList = parseColorStateList(context, value)
}
create("secondaryProgressTintMode") {
view.secondaryProgressTintMode = parsePorterDuffMode(value)
}
}
}
@@ -25,4 +25,5 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
*
* @author Akash Yadav
*/
@ViewAdapter(RadioButton::class) class RadioButtonAttrAdapter : CompoundButtonAttrAdapter()
@ViewAdapter(RadioButton::class)
open class RadioButtonAttrAdapter<T : RadioButton> : CompoundButtonAttrAdapter<T>()
@@ -17,14 +17,9 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.RelativeLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [RelativeLayout].
@@ -32,29 +27,11 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(RelativeLayout::class)
class RelativeLayoutAttrAdapter : ViewGroupAttrAdapter() {
open class RelativeLayoutAttrAdapter<T : RelativeLayout> : ViewGroupAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<RelativeLayout>(view, attribute) {
file: LayoutFile,
_: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"gravity" -> gravity = parseGravity(value)
"ignoreGravity" -> ignoreGravity = parseId(file.resName, value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("gravity") { view.gravity = parseGravity(value) }
create("ignoreGravity") { view.ignoreGravity = parseId(file.resName, value) }
}
}
@@ -19,8 +19,7 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.SeekBar
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [SeekBar].
@@ -28,22 +27,11 @@ import com.itsaky.androidide.inflater.IView
* @author Akash Yadav
*/
@ViewAdapter(SeekBar::class)
class SeekBarAttrAdapter : AbsSeekBarAttrAdapter() {
open class SeekBarAttrAdapter<T : SeekBar> : AbsSeekBarAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<SeekBar>(view, attribute) { _, context, _, _, name, value ->
var applied = true
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
when (name) {
"thumb" -> thumb = parseDrawable(context, value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
create("thumb") { view.thumb = parseDrawable(context, value) }
}
}
@@ -17,14 +17,9 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.Spinner
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [Spinner].
@@ -32,31 +27,17 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(Spinner::class)
class SpinnerAttrAdapter : AbsSpinnerAttrAdapter() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<Spinner>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"dropDownHorizontalOffset" -> dropDownHorizontalOffset = parseDimension(context, value, 0)
"dropDownVerticalOffset" -> dropDownVerticalOffset = parseDimension(context, value, 0)
"dropDownWidth" -> dropDownWidth = parseDimension(context, value, 0)
"gravity" -> gravity = parseGravity(value)
"popupBackground" -> setPopupBackgroundDrawable(parseDrawable(context, value))
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
open class SpinnerAttrAdapter<T : Spinner> : AbsSpinnerAttrAdapter<T>() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("dropDownHorizontalOffset") {
view.dropDownHorizontalOffset = parseDimension(context, value, 0)
}
create("dropDownVerticalOffset") {
view.dropDownVerticalOffset = parseDimension(context, value, 0)
}
create("dropDownWidth") { view.dropDownWidth = parseDimension(context, value, 0) }
create("gravity") { view.gravity = parseGravity(value) }
create("popupBackground") { view.setPopupBackgroundDrawable(parseDrawable(context, value)) }
}
}
@@ -24,4 +24,5 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* Attribute adapter for [SurfaceView].
* @author Akash Yadav
*/
@ViewAdapter(SurfaceView::class) class SurfaceViewAttrAdapter : ViewAttrAdapter()
@ViewAdapter(SurfaceView::class)
open class SurfaceViewAttrAdapter<T : SurfaceView> : ViewAttrAdapter<T>()
@@ -17,15 +17,10 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.graphics.Typeface.DEFAULT
import android.view.ViewGroup.LayoutParams
import android.widget.Switch
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [Switch].
@@ -33,40 +28,23 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(Switch::class)
class SwitchAttrAdapter : CompoundButtonAttrAdapter() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<Switch>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"showText" -> showText = parseBoolean(value)
"splitTrack" -> splitTrack = parseBoolean(value)
"switchMinWidth" -> switchMinWidth = parseDimension(context, value, 0)
"switchPadding" -> switchPadding = parseDimension(context, value, 0)
"textOff" -> textOff = parseString(value)
"textOn" -> textOn = parseString(value)
"textStyle" -> setSwitchTypeface(DEFAULT, parseTextStyle(value))
"thumb" -> thumbDrawable = parseDrawable(context, value)
"thumbTextPadding" -> thumbTextPadding = parseDimension(context, value, 0)
"thumbTint" -> thumbTintList = parseColorStateList(context, value)
"thumbTintMode" -> thumbTintMode = parsePorterDuffMode(value)
"track" -> trackDrawable = parseDrawable(context, value)
"trackTint" -> trackTintList = parseColorStateList(context, value)
"trackTintMode" -> trackTintMode = parsePorterDuffMode(value)
"typeface" -> setSwitchTypeface(parseTypeface(value))
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
open class SwitchAttrAdapter<T : Switch> : CompoundButtonAttrAdapter<T>() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("showText") { view.showText = parseBoolean(value) }
create("splitTrack") { view.splitTrack = parseBoolean(value) }
create("switchMinWidth") { view.switchMinWidth = parseDimension(context, value, 0) }
create("switchPadding") { view.switchPadding = parseDimension(context, value, 0) }
create("textOff") { view.textOff = parseString(value) }
create("textOn") { view.textOn = parseString(value) }
create("textStyle") { view.setSwitchTypeface(DEFAULT, parseTextStyle(value)) }
create("thumb") { view.thumbDrawable = parseDrawable(context, value) }
create("thumbTextPadding") { view.thumbTextPadding = parseDimension(context, value, 0) }
create("thumbTint") { view.thumbTintList = parseColorStateList(context, value) }
create("thumbTintMode") { view.thumbTintMode = parsePorterDuffMode(value) }
create("track") { view.trackDrawable = parseDrawable(context, value) }
create("trackTint") { view.trackTintList = parseColorStateList(context, value) }
create("trackTintMode") { view.trackTintMode = parsePorterDuffMode(value) }
create("typeface") { view.setSwitchTypeface(parseTypeface(value)) }
}
}
@@ -17,19 +17,15 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.content.Context
import android.graphics.Typeface
import android.text.TextUtils
import android.text.util.Linkify
import android.util.TypedValue
import android.view.ViewGroup.LayoutParams
import android.widget.TextView
import com.blankj.utilcode.util.SizeUtils
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.utils.newAttribute
import java.util.regex.Pattern
@@ -39,93 +35,88 @@ import java.util.regex.Pattern
* @author Akash Yadav
*/
@ViewAdapter(TextView::class)
open class TextViewAttrAdapter : ViewAttrAdapter() {
open class TextViewAttrAdapter<T : TextView> : ViewAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<TextView>(view, attribute) {
_: LayoutFile,
context: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
val drawables = compoundDrawables
val drawablesRelative = compoundDrawablesRelative
var applied = true
when (name) {
"autoLink" -> autoLinkMask = parseAutoLinkMask(value)
"drawableLeft" ->
setCompoundDrawables(
parseDrawable(context, value),
drawables[1],
drawables[2],
drawables[3]
)
"drawableTop" ->
setCompoundDrawables(
drawables[0],
parseDrawable(context, value),
drawables[2],
drawables[3]
)
"drawableRight" ->
setCompoundDrawables(
drawables[0],
drawables[1],
parseDrawable(context, value),
drawables[3]
)
"drawableBottom" ->
setCompoundDrawables(
drawables[0],
drawables[1],
drawables[2],
parseDrawable(context, value)
)
"drawableStart" ->
setCompoundDrawables(
parseDrawable(context, value),
drawablesRelative[1],
drawablesRelative[2],
drawablesRelative[3]
)
"drawableEnd" ->
setCompoundDrawables(
drawablesRelative[0],
drawablesRelative[1],
parseDrawable(context, value),
drawablesRelative[3]
)
"drawablePadding" -> compoundDrawablePadding = parseDimension(context, value, 0)
"ellipsize" -> ellipsize = parseEllipsize(value)
"gravity" -> gravity = parseGravity(value)
"hint" -> hint = parseString(value)
"letterSpacing" -> letterSpacing = parseFloat(value)
"lineHeight" -> setLines(parseInteger(value, Int.MAX_VALUE))
"linksClickable" -> linksClickable = parseBoolean(value)
"marqueeRepeatLimit" -> marqueeRepeatLimit = parseInteger(value, Int.MAX_VALUE)
"maxLines" -> maxLines = parseInteger(value, Int.MAX_VALUE)
"minLines" -> minLines = parseInteger(value, 1)
"singleLine" -> isSingleLine = parseBoolean(value)
"text" -> text = parseString(value)
"textAllCaps" -> isAllCaps = parseBoolean(value)
"textColor" -> setTextColor(parseColor(context, value))
"textColorHint" -> setHintTextColor(parseColor(context, value))
"textSize" ->
setTextSize(
TypedValue.COMPLEX_UNIT_PX,
parseDimensionF(context, value, SizeUtils.sp2px(14f).toFloat())
)
"textStyle" -> setTypeface(typeface, parseTextStyle(value))
"typeface" -> typeface = parseTypeface(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("autoLink") { view.autoLinkMask = parseAutoLinkMask(value) }
create("drawableLeft") {
val drawables = view.compoundDrawables
view.setCompoundDrawables(
parseDrawable(context, value),
drawables[1],
drawables[2],
drawables[3]
)
}
create("drawableTop") {
val drawables = view.compoundDrawables
view.setCompoundDrawables(
drawables[0],
parseDrawable(context, value),
drawables[2],
drawables[3]
)
}
create("drawableRight") {
val drawables = view.compoundDrawables
view.setCompoundDrawables(
drawables[0],
drawables[1],
parseDrawable(context, value),
drawables[3]
)
}
create("drawableBottom") {
val drawables = view.compoundDrawables
view.setCompoundDrawables(
drawables[0],
drawables[1],
drawables[2],
parseDrawable(context, value)
)
}
create("drawableStart") {
val drawablesRelative = view.compoundDrawablesRelative
view.setCompoundDrawables(
parseDrawable(context, value),
drawablesRelative[1],
drawablesRelative[2],
drawablesRelative[3]
)
}
create("drawableEnd") {
val drawablesRelative = view.compoundDrawablesRelative
view.setCompoundDrawables(
drawablesRelative[0],
drawablesRelative[1],
parseDrawable(context, value),
drawablesRelative[3]
)
}
create("drawablePadding") { view.compoundDrawablePadding = parseDimension(context, value, 0) }
create("ellipsize") { view.ellipsize = parseEllipsize(value) }
create("gravity") { view.gravity = parseGravity(value) }
create("hint") { view.hint = parseString(value) }
create("letterSpacing") { view.letterSpacing = parseFloat(value) }
create("lineHeight") { view.setLines(parseInteger(value, Int.MAX_VALUE)) }
create("linksClickable") { view.linksClickable = parseBoolean(value) }
create("marqueeRepeatLimit") { view.marqueeRepeatLimit = parseInteger(value, Int.MAX_VALUE) }
create("maxLines") { view.maxLines = parseInteger(value, Int.MAX_VALUE) }
create("minLines") { view.minLines = parseInteger(value, 1) }
create("singleLine") { view.isSingleLine = parseBoolean(value) }
create("text") { view.text = parseString(value) }
create("textAllCaps") { view.isAllCaps = parseBoolean(value) }
create("textColor") { view.setTextColor(parseColor(context, value)) }
create("textColorHint") { view.setHintTextColor(parseColor(context, value)) }
create("textSize") {
view.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
parseDimensionF(context, value, SizeUtils.sp2px(14f).toFloat())
)
}
create("textStyle") { view.setTypeface(view.typeface, parseTextStyle(value)) }
create("typeface") { view.typeface = parseTypeface(value) }
}
override fun applyBasic(view: IView) {
@@ -26,4 +26,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* @author Akash Yadav
*/
@ViewAdapter(TextureView::class)
class TextureViewAttrAdapter : ViewAttrAdapter()
open class TextureViewAttrAdapter<T : TextureView> : ViewAttrAdapter<T>()
@@ -17,16 +17,10 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.R.attr.button
import android.content.Context
import android.view.ViewGroup.LayoutParams
import android.widget.ToggleButton
import com.blankj.utilcode.util.ReflectUtils.reflect
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.AttributeHandlerScope
/**
* Attribute adapter for [ToggleButton].
@@ -34,29 +28,12 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
* @author Akash Yadav
*/
@ViewAdapter(ToggleButton::class)
class ToggleButtonAttrAdapter : CompoundButtonAttrAdapter() {
open class ToggleButtonAttrAdapter<T : ToggleButton> : CompoundButtonAttrAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<ToggleButton>(view, attribute) {
_: LayoutFile,
_: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"disabledAlpha" -> reflect(button).field("mDisabledAlpha", parseFloat(value, 0.5f))
"textOff" -> textOff = parseString(value)
"textOn" -> textOn = parseString(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("disabledAlpha") { reflect(view).field("mDisabledAlpha", parseFloat(value, 0.5f)) }
create("textOff") { view.textOff = parseString(value) }
create("textOn") { view.textOn = parseString(value) }
}
}
@@ -30,14 +30,12 @@ import android.widget.RelativeLayout.*
import androidx.annotation.ChecksSdkIntAtLeast
import androidx.core.view.updatePadding
import androidx.core.view.updatePaddingRelative
import com.android.SdkConstants
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.IViewAdapter
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.internal.ViewImpl
import com.itsaky.androidide.inflater.utils.newAttribute
/**
@@ -46,89 +44,93 @@ import com.itsaky.androidide.inflater.utils.newAttribute
* @author Akash Yadav
*/
@ViewAdapter(forView = View::class)
open class ViewAttrAdapter : IViewAdapter() {
open class ViewAttrAdapter<T : View> : IViewAdapter<T>() {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<View>(view, attribute) { file, context, layoutParams, _, name, value ->
var applied = true
@Suppress("DEPRECATION")
when (name) {
"alpha" -> alpha = parseFloat(value)
"background" -> background = parseDrawable(context, value)
"backgroundTint" -> backgroundTintList = parseColorStateList(context, value)
"backgroundTintMode" -> backgroundTintMode = parsePorterDuffMode(value)
"clipToOutline" -> clipToOutline = parseBoolean(value)
"contentDescription" -> contentDescription = parseString(value)
"contextClickable" -> isContextClickable = parseBoolean(value)
"defaultFocusHighlightEnabled" -> defaultFocusHighlightEnabled = parseBoolean(value)
"drawingCacheQuality" -> drawingCacheQuality = parseDrawingCacheQuality(value)
"duplicateParentState" -> isDuplicateParentStateEnabled = parseBoolean(value)
"elevation" -> elevation = parseDimensionF(context, value)
"fadeScrollbars" -> isScrollbarFadingEnabled = parseBoolean(value)
"fadingEdgeLength" -> setFadingEdgeLength(parseDimension(context, value))
"filterTouchesWhenObscured" -> filterTouchesWhenObscured = parseBoolean(value)
"foreground" -> foreground = parseDrawable(context, value)
"foregroundGravity" -> foregroundGravity = parseGravity(value)
"foregroundTint" -> foregroundTintList = parseColorStateList(context, value)
"foregroundTintMode" -> foregroundTintMode = parsePorterDuffMode(value)
"id" -> id = parseId(file.resName, value)
"minHeight" -> minimumWidth = parseDimension(context, value)
"minWidth" -> minimumHeight = parseDimension(context, value)
"padding" ->
parseDimension(context, value).also {
updatePadding(left = it, top = it, right = it, bottom = it)
}
"paddingLeft" -> updatePadding(left = parseDimension(context, value))
"paddingTop" -> updatePadding(top = parseDimension(context, value))
"paddingRight" -> updatePadding(right = parseDimension(context, value))
"paddingBottom" -> updatePadding(bottom = parseDimension(context, value))
"paddingStart" -> updatePaddingRelative(start = parseDimension(context, value))
"paddingEnd" -> updatePaddingRelative(end = parseDimension(context, value))
"rotation" -> rotation = parseFloat(value)
"rotationX" -> rotationX = parseFloat(value)
"rotationY" -> rotationY = parseFloat(value)
"scaleX" -> scaleX = parseFloat(value)
"scaleY" -> scaleY = parseFloat(value)
"scrollX" -> scrollX = parseInteger(value)
"scrollY" -> scrollY = parseInteger(value)
"textAlignment" -> textAlignment = parseTextAlignment(value)
"textDirection" -> textDirection = parseTextDirection(value)
"tooltipText" -> tooltipText = parseString(value)
"transformPivotX" -> pivotX = parseFloat(value)
"transformPivotY" -> pivotY = parseFloat(value)
"translationX" -> translationX = parseFloat(value)
"translationY" -> translationY = parseFloat(value)
"translationZ" -> translationZ = parseFloat(value)
"visibility" -> visibility = parseVisibility(value)
else -> applied = false
}
if (!applied && layoutParams is LinearLayout.LayoutParams) {
applied = applyLinearLayoutParams(layoutParams, name, value)
}
if (!applied && layoutParams is RelativeLayout.LayoutParams) {
applied = applyRelativeLayoutParams(layoutParams, file.resName, name, value)
}
if (!applied && layoutParams is FrameLayout.LayoutParams) {
applied = applyFrameLayoutParams(layoutParams, name, value)
}
if (!applied && layoutParams is MarginLayoutParams) {
applied = applyMarginParams(context, layoutParams, name, value)
}
if (!applied) {
applied = applyLayoutParams(context, layoutParams, name, value)
}
if (applied) {
this.layoutParams = layoutParams
}
return@doApply applied
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
create("alpha") { view.alpha = parseFloat(value) }
create("background") { view.background = parseDrawable(context, value) }
create("backgroundTint") { view.backgroundTintList = parseColorStateList(context, value) }
create("backgroundTintMode") { view.backgroundTintMode = parsePorterDuffMode(value) }
create("clipToOutline") { view.clipToOutline = parseBoolean(value) }
create("contentDescription") { view.contentDescription = parseString(value) }
create("contextClickable") { view.isContextClickable = parseBoolean(value) }
create("defaultFocusHighlightEnabled") {
view.defaultFocusHighlightEnabled = parseBoolean(value)
}
create("drawingCacheQuality") {
@Suppress("DEPRECATION")
view.drawingCacheQuality = parseDrawingCacheQuality(value)
}
create("duplicateParentState") { view.isDuplicateParentStateEnabled = parseBoolean(value) }
create("elevation") { view.elevation = parseDimensionF(context, value) }
create("fadeScrollbars") { view.isScrollbarFadingEnabled = parseBoolean(value) }
create("fadingEdgeLength") { view.setFadingEdgeLength(parseDimension(context, value)) }
create("filterTouchesWhenObscured") { view.filterTouchesWhenObscured = parseBoolean(value) }
create("foreground") { view.foreground = parseDrawable(context, value) }
create("foregroundGravity") { view.foregroundGravity = parseGravity(value) }
create("foregroundTint") { view.foregroundTintList = parseColorStateList(context, value) }
create("foregroundTintMode") { view.foregroundTintMode = parsePorterDuffMode(value) }
create("id") { view.id = parseId(file.resName, value) }
create("minHeight") { view.minimumWidth = parseDimension(context, value) }
create("minWidth") { view.minimumHeight = parseDimension(context, value) }
create("padding") {
parseDimension(context, value).also {
view.updatePadding(left = it, top = it, right = it, bottom = it)
}
}
create("paddingLeft") { view.updatePadding(left = parseDimension(context, value)) }
create("paddingTop") { view.updatePadding(top = parseDimension(context, value)) }
create("paddingRight") { view.updatePadding(right = parseDimension(context, value)) }
create("paddingBottom") { view.updatePadding(bottom = parseDimension(context, value)) }
create("paddingStart") { view.updatePaddingRelative(start = parseDimension(context, value)) }
create("paddingEnd") { view.updatePaddingRelative(end = parseDimension(context, value)) }
create("rotation") { view.rotation = parseFloat(value) }
create("rotationX") { view.rotationX = parseFloat(value) }
create("rotationY") { view.rotationY = parseFloat(value) }
create("scaleX") { view.scaleX = parseFloat(value) }
create("scaleY") { view.scaleY = parseFloat(value) }
create("scrollX") { view.scrollX = parseInteger(value) }
create("scrollY") { view.scrollY = parseInteger(value) }
create("textAlignment") { view.textAlignment = parseTextAlignment(value) }
create("textDirection") { view.textDirection = parseTextDirection(value) }
create("tooltipText") { view.tooltipText = parseString(value) }
create("transformPivotX") { view.pivotX = parseFloat(value) }
create("transformPivotY") { view.pivotY = parseFloat(value) }
create("translationX") { view.translationX = parseFloat(value) }
create("translationY") { view.translationY = parseFloat(value) }
create("translationZ") { view.translationZ = parseFloat(value) }
create("visibility") { view.visibility = parseVisibility(value) }
}
override fun AttributeHandlerScope<T>.applyLayoutParams() : Boolean {
var applied = false
if (layoutParams is LinearLayout.LayoutParams) {
applied = applyLinearLayoutParams(layoutParams, name, value)
}
if (!applied && layoutParams is RelativeLayout.LayoutParams) {
applied = applyRelativeLayoutParams(layoutParams, file.resName, name, value)
}
if (!applied && layoutParams is FrameLayout.LayoutParams) {
applied = applyFrameLayoutParams(layoutParams, name, value)
}
if (!applied && layoutParams is MarginLayoutParams) {
applied = applyMarginParams(context, layoutParams, name, value)
}
if (!applied) {
applied = applyLayoutParams(context, layoutParams, name, value)
}
if (applied) {
view.layoutParams = layoutParams
}
return applied
}
override fun applyBasic(view: IView) {
@@ -250,49 +252,6 @@ open class ViewAttrAdapter : IViewAdapter() {
return applied
}
protected open fun canHandleNamespace(namespace: INamespace): Boolean {
return this.canHandleNamespace(namespace.uri)
}
protected open fun canHandleNamespace(nsUri: String): Boolean {
return SdkConstants.ANDROID_URI == nsUri
}
/**
* Provides easy access to various properties related to the view and attribute when applying an
* attributes.
*/
protected open fun <T : View> doApply(
view: IView,
attribute: IAttribute,
block:
T.(
file: LayoutFile,
context: Context,
layoutParams: LayoutParams,
namespace: INamespace,
name: String,
value: String,
) -> Boolean,
): Boolean {
if (!canHandleNamespace(attribute.namespace)) {
return false
}
@Suppress("UNCHECKED_CAST")
return (view.view as T).let {
val file = (view as ViewImpl).file
val applied =
it.block(
file,
it.context,
it.layoutParams,
attribute.namespace,
attribute.name,
attribute.value
)
return@let applied
}
}
protected open fun parseDrawingCacheQuality(value: String): Int {
return com.itsaky.androidide.inflater.internal.utils.parseDrawingCacheQuality(value)
}
@@ -21,6 +21,7 @@ import android.animation.LayoutTransition
import android.content.Context
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.INamespace
import com.itsaky.androidide.inflater.IView
@@ -35,34 +36,17 @@ import com.itsaky.androidide.inflater.internal.LayoutFile
*
* @author Akash Yadav
*/
abstract class ViewGroupAttrAdapter : ViewAttrAdapter(), IViewGroupAdapter {
override fun apply(view: IView, attribute: IAttribute): Boolean {
return doApply<ViewGroup>(view, attribute) {
_: LayoutFile,
_: Context,
_: LayoutParams,
_: INamespace,
name: String,
value: String ->
var applied = true
when (name) {
"animateLayoutChanges" -> layoutTransition = LayoutTransition()
"clipChildren" -> clipChildren = parseBoolean(value)
"clipToPadding" -> clipToPadding = parseBoolean(value)
"descendantFocusability" -> descendantFocusability = parseDescendantsFocusability(value)
"layoutMode" -> layoutMode = parseLayoutMode(value)
else -> applied = false
}
if (!applied) {
applied = super.apply(view, attribute)
}
return@doApply applied
}
abstract class ViewGroupAttrAdapter<T : ViewGroup> : ViewAttrAdapter<T>(), IViewGroupAdapter {
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("animateLayoutChanges") { view.layoutTransition = LayoutTransition() }
create("clipChildren") { view.clipChildren = parseBoolean(value) }
create("clipToPadding") { view.clipToPadding = parseBoolean(value) }
create("descendantFocusability") { view.descendantFocusability = parseDescendantsFocusability(value) }
create("layoutMode") { view.layoutMode = parseLayoutMode(value) }
}
override fun getLayoutBehavior(group: IViewGroup): LayoutBehavior {
return TOP_LEFT
}
@@ -26,4 +26,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* @author Akash Yadav
*/
@ViewAdapter(WebView::class)
class WebViewAttrAdapter : AbsoluteLayoutAttrAdapter()
open class WebViewAttrAdapter<T : WebView> : AbsoluteLayoutAttrAdapter<T>()