diff --git a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/ViewAdapterAnnotationProcessor.kt b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/ViewAdapterAnnotationProcessor.kt index 5769f376e..c77bdf356 100644 --- a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/ViewAdapterAnnotationProcessor.kt +++ b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/ViewAdapterAnnotationProcessor.kt @@ -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? diff --git a/app/src/main/assets/data/common/tooling-api-all.jar b/app/src/main/assets/data/common/tooling-api-all.jar index 47e24cb5d..dfdbb9d5b 100644 Binary files a/app/src/main/assets/data/common/tooling-api-all.jar and b/app/src/main/assets/data/common/tooling-api-all.jar differ diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt index 753c5c067..81f4c279f 100644 --- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt +++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt @@ -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 { if (pck == SdkConstants.ANDROID_PKG) { - return getFrameworkResourceTable() + return getFrameworkResourceTable()?.let { listOf(it) } ?: emptyList() } val tables: List = @@ -387,17 +404,20 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this.. addAll(getDependencyResourceTables()) } + val result = mutableListOf() 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() } /** diff --git a/tests/test-home/.androidide/init/model.jar b/tests/test-home/.androidide/init/model.jar index 5d2ff9602..46009ac5d 100644 Binary files a/tests/test-home/.androidide/init/model.jar and b/tests/test-home/.androidide/init/model.jar differ diff --git a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/ViewInfoFragment.kt b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/ViewInfoFragment.kt index 8bae04e06..dd1980434 100644 --- a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/ViewInfoFragment.kt +++ b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/ViewInfoFragment.kt @@ -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 diff --git a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiAttribute.kt b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiAttribute.kt index 838aa0b27..a9930fa73 100644 --- a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiAttribute.kt +++ b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiAttribute.kt @@ -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. diff --git a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiViewGroup.kt b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiViewGroup.kt index 0eabbeeda..05511ddb9 100644 --- a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiViewGroup.kt +++ b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiViewGroup.kt @@ -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 /** diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/AttributeHandlerScope.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/AttributeHandlerScope.kt new file mode 100644 index 000000000..a632cc452 --- /dev/null +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/AttributeHandlerScope.kt @@ -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 . + */ + +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( + val view: T, + val file: LayoutFile, + val context: Context, + val layoutParams: ViewGroup.LayoutParams, + val namespace: INamespace, + val name: String, + val value: String +) \ No newline at end of file diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/IViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/IViewAdapter.kt index a4f357663..d62b66494 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/IViewAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/IViewAdapter.kt @@ -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 : AbstractParser() { /** Superclasses of the view that this adpater handles. */ var superclassHierarchy: List = 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.() -> 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.applyInternal(): Boolean { + val handler = attributeHandlers[name] + if (handler != null) { + handler() + } + return handler != null || applyLayoutParams() + } + + protected open fun AttributeHandlerScope.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.() -> 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.() -> Unit) -> Unit + ) {} } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAttrAdapter.kt index f3b3c96a9..3f754605d 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAttrAdapter.kt @@ -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(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 : AdapterViewAttrAdapter() { + + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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 { diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAttrAdapter.kt index 3ed7c23a9..127eb649a 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAttrAdapter.kt @@ -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 : ProgressBarAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAttrAdapter.kt index aed199b6e..580ff399d 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAttrAdapter.kt @@ -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(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 : AdapterViewAttrAdapter() { + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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 } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAttrAdapter.kt index fcb5b084e..54626d62a 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAttrAdapter.kt @@ -27,4 +27,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter */ @Suppress("DEPRECATION") @ViewAdapter(AbsoluteLayout::class) -open class AbsoluteLayoutAttrAdapter : ViewGroupAttrAdapter() +open class AbsoluteLayoutAttrAdapter : ViewGroupAttrAdapter() diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAttrAdapter.kt index 545b9fe36..ae10a2728 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAttrAdapter.kt @@ -29,7 +29,7 @@ import com.itsaky.androidide.inflater.internal.ViewGroupImpl * * @author Akash Yadav */ -abstract class AdapterViewAttrAdapter : ViewGroupAttrAdapter() { +abstract class AdapterViewAttrAdapter> : ViewGroupAttrAdapter() { companion object { const val ADAPTER_DEFAULT_ITEM_COUNT = 3 diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAttrAdapter.kt index b7c3c23aa..22525b437 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAttrAdapter.kt @@ -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 : EditTextAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAttrAdapter.kt index 73d3f3315..bd227e9dd 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAttrAdapter.kt @@ -25,4 +25,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter * * @author Akash Yadav */ -@ViewAdapter(Button::class) open class ButtonAttrAdapter : TextViewAttrAdapter() \ No newline at end of file +@ViewAdapter(Button::class) open class ButtonAttrAdapter : TextViewAttrAdapter() diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAttrAdapter.kt index 16ff2b8ce..774363884 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAttrAdapter.kt @@ -25,4 +25,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter * * @author Akash Yadav */ -@ViewAdapter(CheckBox::class) class CheckBoxAttrAdapter : CompoundButtonAttrAdapter() \ No newline at end of file +@ViewAdapter(CheckBox::class) open class CheckBoxAttrAdapter : CompoundButtonAttrAdapter() \ No newline at end of file diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAttrAdapter.kt index bd4919861..04571a83c 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAttrAdapter.kt @@ -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 : TextViewAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> Unit) -> Unit) { + super.createAttrHandlers(create) + create("checkMarkTintMode") { view.checkMarkTintMode = parsePorterDuffMode(value) } + create("checkMarkTint") { view.checkMarkTintList = parseColorStateList(context, value) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAttrAdapter.kt index 30428b769..5bfa68dd5 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAttrAdapter.kt @@ -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 : ButtonAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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) { diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAttrAdapter.kt index 780affed8..8b1f5f5d7 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAttrAdapter.kt @@ -26,4 +26,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter * @author Akash Yadav */ @ViewAdapter(EditText::class) -open class EditTextAttrAdapter : TextViewAttrAdapter() +open class EditTextAttrAdapter : TextViewAttrAdapter() diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAttrAdapter.kt index 0582899f8..6c0911872 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAttrAdapter.kt @@ -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(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 : ViewGroupAttrAdapter() { + + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) { + super.createAttrHandlers(create) + create("foregroundGravity") { view.foregroundGravity = parseGravity(value) } + create("measureAllChildren") { view.measureAllChildren = parseBoolean(value) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAttrAdapter.kt index cdab903c6..fef728754 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAttrAdapter.kt @@ -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(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 : FrameLayoutAttrAdapter() { + + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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 diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAttrAdapter.kt index 0c92b7752..39d27774e 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAttrAdapter.kt @@ -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(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 : ViewGroupAttrAdapter() { + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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 { diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAttrAdapter.kt index acf101834..489607927 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAttrAdapter.kt @@ -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 : ImageViewAttrAdapter() diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAttrAdapter.kt index cc92fd765..c7dd79165 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAttrAdapter.kt @@ -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 : ViewAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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) { diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAttrAdapter.kt index 908d336c7..48615fdd7 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAttrAdapter.kt @@ -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 : ViewGroupAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(view, attribute) { - _: LayoutFile, - _: Context, - _: LayoutParams, - _: INamespace, - name: String, - value: String -> - var applied = true + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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 { diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAttrAdapter.kt index fbef65971..e6dc0c8c8 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAttrAdapter.kt @@ -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 : AbsListViewAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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)) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAttrAdapter.kt index ce22f16f3..1495c62ec 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAttrAdapter.kt @@ -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 : ViewAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAttrAdapter.kt index d71cb15ba..4a648105a 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAttrAdapter.kt @@ -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 : CompoundButtonAttrAdapter() diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAttrAdapter.kt index 8ae58470b..574b27799 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAttrAdapter.kt @@ -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 : ViewGroupAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> Unit) -> Unit) { + super.createAttrHandlers(create) + create("gravity") { view.gravity = parseGravity(value) } + create("ignoreGravity") { view.ignoreGravity = parseId(file.resName, value) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAttrAdapter.kt index 887ba4420..f8a18b342 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAttrAdapter.kt @@ -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 : AbsSeekBarAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(view, attribute) { _, context, _, _, name, value -> - var applied = true + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAttrAdapter.kt index 46a506df9..7bb4fc136 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAttrAdapter.kt @@ -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(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 : AbsSpinnerAttrAdapter() { + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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)) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAttrAdapter.kt index fa006df2f..72547dfad 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAttrAdapter.kt @@ -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 : ViewAttrAdapter() diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAttrAdapter.kt index c6229af7e..32e74ba71 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAttrAdapter.kt @@ -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(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 : CompoundButtonAttrAdapter() { + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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)) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAttrAdapter.kt index 22b0b9aaf..6dc58957f 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAttrAdapter.kt @@ -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 : ViewAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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) { diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAttrAdapter.kt index 6bfba3a0a..9d9cc9f26 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAttrAdapter.kt @@ -26,4 +26,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter * @author Akash Yadav */ @ViewAdapter(TextureView::class) -class TextureViewAttrAdapter : ViewAttrAdapter() \ No newline at end of file +open class TextureViewAttrAdapter : ViewAttrAdapter() \ No newline at end of file diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAttrAdapter.kt index 5184afac3..f4af20f67 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAttrAdapter.kt @@ -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 : CompoundButtonAttrAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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) } } } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAttrAdapter.kt index 5c27bdded..9f8a83c2b 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAttrAdapter.kt @@ -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 : IViewAdapter() { - override fun apply(view: IView, attribute: IAttribute): Boolean { - return doApply(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.() -> 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.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 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) } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAttrAdapter.kt index 65b711a27..96a066c32 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAttrAdapter.kt @@ -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(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 : ViewAttrAdapter(), IViewGroupAdapter { + + override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> 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 } diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAttrAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAttrAdapter.kt index fda8eb5ba..9898ff34c 100644 --- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAttrAdapter.kt +++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAttrAdapter.kt @@ -26,4 +26,4 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter * @author Akash Yadav */ @ViewAdapter(WebView::class) -class WebViewAttrAdapter : AbsoluteLayoutAttrAdapter() \ No newline at end of file +open class WebViewAttrAdapter : AbsoluteLayoutAttrAdapter() \ No newline at end of file