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
deleted file mode 100644
index f8b5f7919..000000000
--- a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/ViewAdapterAnnotationProcessor.kt
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * 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.annotations.inflater
-
-import com.google.auto.service.AutoService
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.CodeBlock
-import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.JavaFile
-import com.squareup.javapoet.MethodSpec
-import com.squareup.javapoet.ParameterizedTypeName
-import com.squareup.javapoet.TypeName
-import com.squareup.javapoet.TypeSpec
-import java.io.File
-import javax.annotation.processing.AbstractProcessor
-import javax.annotation.processing.Processor
-import javax.annotation.processing.RoundEnvironment
-import javax.lang.model.SourceVersion
-import javax.lang.model.element.Element
-import javax.lang.model.element.ElementKind.CLASS
-import javax.lang.model.element.ElementKind.PACKAGE
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.Modifier.FINAL
-import javax.lang.model.element.Modifier.PRIVATE
-import javax.lang.model.element.Modifier.PUBLIC
-import javax.lang.model.element.Modifier.STATIC
-import javax.lang.model.element.TypeElement
-import javax.lang.model.type.MirroredTypeException
-import javax.tools.Diagnostic.Kind.ERROR
-
-@Suppress("unused")
-@AutoService(Processor::class)
-class ViewAdapterAnnotationProcessor : AbstractProcessor() {
-
- private val adapterElement by lazy {
- 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 =
- TypeSpec.classBuilder(INDEX_CLASS_NAME).addModifiers(PUBLIC, FINAL)
- private val indexAddStatements = CodeBlock.builder()
-
- private val listOfString: TypeName =
- ParameterizedTypeName.get(java.util.ArrayList::class.java, String::class.java)
-
- init {
- addIndexClassMembers()
- }
-
- companion object {
- const val ADAPTER_BASE_CLASS_PCK = "com.itsaky.androidide.inflater"
- const val ADAPTER_BASE_CLASS_NAME = "IViewAdapter"
- const val ADAPTER_BASE_CLASS = "$ADAPTER_BASE_CLASS_PCK.$ADAPTER_BASE_CLASS_NAME"
-
- const val INDEX_PACKAGE_NAME = "com.itsaky.androidide.inflater.internal"
- const val INDEX_CLASS_NAME = "ViewAdapterIndex"
- const val INDEX_MAP_FIELD = "adapterMap"
-
- const val METHOD_SET_SUPERCLASS_HIERARCHY = "setSuperclassHierarchy"
- const val METHOD_SET_MODULE = "setModuleNamespace"
- }
-
- override fun getSupportedAnnotationTypes(): MutableSet {
- return mutableSetOf(ViewAdapter::class.java.name)
- }
-
- override fun getSupportedSourceVersion(): SourceVersion {
- return SourceVersion.latestSupported()
- }
-
- override fun process(
- annotations: MutableSet?,
- roundEnv: RoundEnvironment
- ): Boolean {
- if (roundEnv.processingOver()) {
- return true
- }
- roundEnv.getElementsAnnotatedWith(ViewAdapter::class.java).forEach {
- if (it.kind != CLASS) {
- processingEnv.messager.printMessage(
- ERROR,
- "@ViewAdapter can only be used with classes. Used on $it"
- )
- return true
- }
- process(it)
- }
-
- indexClassBuilder.addStaticBlock(indexAddStatements.build())
- val file = JavaFile.builder(INDEX_PACKAGE_NAME, indexClassBuilder.build())
- val generatedDir =
- File(
- processingEnv.options[KAPT_KOTLIN_GENERATED]
- ?: throw IllegalStateException("Cannot find kapt output directory path")
- )
- file.build().writeTo(generatedDir)
- return false
- }
-
- private fun process(element: Element) {
- if (element.enclosingElement?.kind != PACKAGE || element !is TypeElement) {
- processingEnv.messager.printMessage(
- ERROR,
- "@ViewAdapter can only be used on top-level classes. Used on $element"
- )
- return
- }
-
- val block = CodeBlock.builder()
-
- val constructors =
- processingEnv.elementUtils.getAllMembers(element).filter {
- "".contentEquals(it.simpleName)
- }
- if (constructors.size != 1) {
- processingEnv.messager.printMessage(
- ERROR,
- "A view adapter must have only default constructor"
- )
- return
- }
-
- if ((constructors.first() as ExecutableElement).parameters.isNotEmpty()) {
- processingEnv.messager.printMessage(
- ERROR,
- "View adapter constructor should not have any parameters"
- )
- return
- }
-
- if (
- !processingEnv.typeUtils.isAssignable(
- processingEnv.typeUtils.erasure(element.asType()),
- adapterElement
- )
- ) {
- processingEnv.messager.printMessage(ERROR, "Class must be a subtype of $ADAPTER_BASE_CLASS $element $adapterElement")
- 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)
-
- val superclasses = getViewSuperclasses(annotation)
-
- block.addStatement("final var superclasses = new \$T()", listOfString)
- 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()", 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)
-
- indexAddStatements.add("{\n")
- indexAddStatements.indent()
- indexAddStatements.add(block.build())
- indexAddStatements.unindent()
- indexAddStatements.add("}\n")
- }
-
- private fun addIndexClassMembers() {
- val adpaterType = ClassName.get(ADAPTER_BASE_CLASS_PCK, ADAPTER_BASE_CLASS_NAME)
- val type =
- ParameterizedTypeName.get(
- ClassName.get(Map::class.java),
- ClassName.get(String::class.java),
- adpaterType
- )
- indexClassBuilder.addField(
- FieldSpec.builder(type, INDEX_MAP_FIELD, PRIVATE, STATIC, FINAL)
- .initializer("new \$T<>()", HashMap::class.java)
- .build()
- )
-
- addUninstantiableConstructor(indexClassBuilder)
-
- indexClassBuilder.addMethod(
- MethodSpec.methodBuilder("getAdapter")
- .addAnnotation(ClassName.get("androidx.annotation", "Nullable"))
- .addModifiers(PUBLIC, STATIC)
- .addParameter(String::class.java, "view", FINAL)
- .returns(adpaterType)
- .addStatement("return \$L.get(\$L)", INDEX_MAP_FIELD, "view")
- .build()
- )
- }
-
- private fun addUninstantiableConstructor(builder: TypeSpec.Builder) {
- builder.addMethod(
- MethodSpec.constructorBuilder()
- .addModifiers(PRIVATE)
- .addStatement(
- "throw new \$T(\$S)",
- UnsupportedOperationException::class.java,
- "This class cannot be instantiated."
- )
- .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 {
- annotation.forView.qualifiedName
- ?: throw IllegalStateException("Cannot find type of $annotation")
- } catch (err: MirroredTypeException) {
- (processingEnv.typeUtils.asElement(err.typeMirror) as TypeElement).qualifiedName.toString()
- }
- }
-
- private fun getViewSuperclasses(annotation: ViewAdapter): List {
- val result = mutableListOf()
- try {
- val view = annotation.forView
- var superclass = view.java.superclass
- while (superclass != null) {
- result.add(superclass.name)
- superclass = superclass.superclass
- }
- } 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?
- superType ?: break
- result.add(superType.qualifiedName.toString())
- superclass = superType.superclass
- }
- }
-
- return result
- }
-}
diff --git a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/ViewAdapterAnnotationProcessor.kt b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/ViewAdapterAnnotationProcessor.kt
new file mode 100644
index 000000000..62f7056a2
--- /dev/null
+++ b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/ViewAdapterAnnotationProcessor.kt
@@ -0,0 +1,139 @@
+/*
+ * 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.annotations.processor
+
+import com.google.auto.service.AutoService
+import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.Processor
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.Element
+import javax.lang.model.element.ElementKind.CLASS
+import javax.lang.model.element.ElementKind.PACKAGE
+import javax.lang.model.element.ExecutableElement
+import javax.lang.model.element.TypeElement
+import javax.tools.Diagnostic.Kind.ERROR
+
+@Suppress("unused")
+@AutoService(Processor::class)
+class ViewAdapterAnnotationProcessor : AbstractProcessor() {
+
+ private val adapterElement by lazy { processingEnv.erasure(processingEnv.adapterElement()) }
+ private val viewElement by lazy { processingEnv.erasure(processingEnv.viewElement()) }
+
+ private val generator = ViewAdapterIndexGenerator()
+
+ override fun getSupportedAnnotationTypes(): MutableSet {
+ return mutableSetOf(ViewAdapter::class.java.name, IncludeInDesigner::class.java.name)
+ }
+
+ override fun getSupportedSourceVersion(): SourceVersion {
+ return SourceVersion.latestSupported()
+ }
+
+ override fun process(
+ annotations: MutableSet?,
+ roundEnv: RoundEnvironment
+ ): Boolean {
+ if (roundEnv.processingOver()) {
+ return true
+ }
+
+ generator.init(processingEnv)
+
+ roundEnv.getElementsAnnotatedWith(ViewAdapter::class.java).forEach {
+ if (it.kind != CLASS) {
+ processingEnv.messager.printMessage(
+ ERROR,
+ "@ViewAdapter can only be used with classes. Used on $it"
+ )
+ return true
+ }
+ process(it)
+ }
+
+ generator.generate(
+ processingEnv.options[KAPT_KOTLIN_GENERATED]
+ ?: throw IllegalStateException("Cannot find kapt output directory path")
+ )
+
+ return false
+ }
+
+ private fun process(element: Element) {
+ if (element.enclosingElement?.kind != PACKAGE || element !is TypeElement) {
+ processingEnv.messager.printMessage(
+ ERROR,
+ "@ViewAdapter can only be used on top-level classes. Used on $element"
+ )
+ return
+ }
+
+ val constructors =
+ processingEnv.elementUtils.getAllMembers(element).filter {
+ "".contentEquals(it.simpleName)
+ }
+ if (constructors.size != 1) {
+ processingEnv.messager.printMessage(
+ ERROR,
+ "A view adapter must have only default constructor"
+ )
+ return
+ }
+
+ if ((constructors.first() as ExecutableElement).parameters.isNotEmpty()) {
+ processingEnv.messager.printMessage(
+ ERROR,
+ "View adapter constructor should not have any parameters"
+ )
+ return
+ }
+
+ if (
+ !processingEnv.typeUtils.isAssignable(
+ processingEnv.typeUtils.erasure(element.asType()),
+ adapterElement
+ )
+ ) {
+ processingEnv.messager.printMessage(
+ ERROR,
+ "Class must be a subtype of $ADAPTER_BASE_CLASS $element $adapterElement"
+ )
+ 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"
+ )
+ }
+
+ generator.addViewAdapter(processingEnv, element)
+ }
+}
diff --git a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/ViewAdapterIndexGenerator.kt b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/ViewAdapterIndexGenerator.kt
new file mode 100644
index 000000000..89a6632f4
--- /dev/null
+++ b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/ViewAdapterIndexGenerator.kt
@@ -0,0 +1,274 @@
+/*
+ * 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.annotations.processor
+
+import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
+import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.JavaFile
+import com.squareup.javapoet.MethodSpec
+import com.squareup.javapoet.ParameterSpec
+import com.squareup.javapoet.ParameterizedTypeName
+import com.squareup.javapoet.TypeName
+import com.squareup.javapoet.TypeSpec
+import com.squareup.javapoet.WildcardTypeName
+import java.io.File
+import java.util.Collections
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.element.ExecutableElement
+import javax.lang.model.element.Modifier.FINAL
+import javax.lang.model.element.Modifier.PRIVATE
+import javax.lang.model.element.Modifier.PUBLIC
+import javax.lang.model.element.Modifier.STATIC
+import javax.lang.model.element.TypeElement
+import javax.lang.model.type.MirroredTypeException
+import javax.tools.Diagnostic.Kind.ERROR
+
+/**
+ * Generates the ViewAdapterIndex class.
+ *
+ * @author Akash Yadav
+ */
+class ViewAdapterIndexGenerator {
+
+ private val indexClassBuilder =
+ TypeSpec.classBuilder(INDEX_CLASS_NAME).addModifiers(PUBLIC, FINAL)
+ private val indexAddStatements = CodeBlock.builder()
+
+ fun init(env: ProcessingEnvironment) {
+ val adapterType =
+ ParameterizedTypeName.get(
+ ClassName.get(ADAPTER_BASE_CLASS_PCK, ADAPTER_BASE_CLASS_NAME),
+ WildcardTypeName.subtypeOf(ClassName.get(env.viewElement()))
+ )
+ val mapOfStringToViewAdapter =
+ ParameterizedTypeName.get(
+ ClassName.get(Map::class.java),
+ ClassName.get(String::class.java),
+ adapterType
+ )
+ indexClassBuilder.addField(
+ FieldSpec.builder(mapOfStringToViewAdapter, INDEX_MAP_FIELD, PRIVATE, STATIC, FINAL).build()
+ )
+
+ indexAddStatements.addStatement(
+ "final var adapters = new \$T()",
+ ParameterizedTypeName.get(
+ ClassName.get(HashMap::class.java),
+ ClassName.get(String::class.java),
+ adapterType
+ )
+ )
+
+ addUninstantiableConstructor(indexClassBuilder)
+
+ indexClassBuilder.addMethod(
+ MethodSpec.methodBuilder("getAdapter")
+ .addAnnotation(ClassName.get("androidx.annotation", "Nullable"))
+ .addModifiers(PUBLIC, STATIC)
+ .addParameter(String::class.java, "view", FINAL)
+ .returns(adapterType)
+ .addStatement("return \$L.get(\$L)", INDEX_MAP_FIELD, "view")
+ .build()
+ )
+
+ val listOfViewAdapters =
+ ParameterizedTypeName.get(ClassName.get(java.util.List::class.java), adapterType)
+ val mapOfGroupToListOfViewAdapter =
+ ParameterizedTypeName.get(
+ ClassName.get(Map::class.java),
+ ClassName.get(IncludeInDesigner.Group::class.java),
+ listOfViewAdapters
+ )
+
+ indexClassBuilder.addField(
+ FieldSpec.builder(
+ mapOfGroupToListOfViewAdapter,
+ INDEX_PROVIDER_MAP_FIELD,
+ PRIVATE,
+ STATIC,
+ FINAL
+ )
+ .build()
+ )
+
+ indexAddStatements.addStatement(
+ "final var providers = new \$T()",
+ ParameterizedTypeName.get(
+ ClassName.get(HashMap::class.java),
+ ClassName.get(IncludeInDesigner.Group::class.java),
+ listOfViewAdapters
+ )
+ )
+
+ val nonNull = ClassName.get("androidx.annotation", "NonNull")
+ val groupParam =
+ ParameterSpec.builder(IncludeInDesigner.Group::class.java, "group", FINAL).build()
+
+ indexClassBuilder.addMethod(
+ MethodSpec.methodBuilder("getWidgetProviders")
+ .addAnnotation(nonNull)
+ .addModifiers(PUBLIC, STATIC)
+ .returns(listOfViewAdapters)
+ .addParameter(groupParam)
+ .addStatement("return \$L.get(group)", INDEX_PROVIDER_MAP_FIELD)
+ .build()
+ )
+ }
+
+ private val listOfString: TypeName =
+ ParameterizedTypeName.get(java.util.ArrayList::class.java, String::class.java)
+
+ fun addViewAdapter(processingEnv: ProcessingEnvironment, element: TypeElement) {
+ val block = CodeBlock.builder()
+
+ val viewAdapter =
+ element.getAnnotation(ViewAdapter::class.java) ?: throw IllegalStateException()
+ val includeInDesigner = element.getAnnotation(IncludeInDesigner::class.java)
+
+ val viewName = getViewName(processingEnv, viewAdapter)
+ val superclasses = getViewSuperclasses(processingEnv, viewAdapter)
+
+ block.addStatement("final var superclasses = new \$T()", listOfString)
+ for (superclass in superclasses) {
+ block.addStatement("superclasses.add(\$S)", superclass)
+ }
+
+ val adapterType = ClassName.get(element)
+ val paramType = getViewTypeName(processingEnv, viewAdapter)
+
+ block.add("\n")
+ 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, viewAdapter.moduleNamespace)
+ block.addStatement("adapters.put(\$S, adapter)", viewName)
+
+ if (includeInDesigner != null) {
+ assertOverridesCreateWidget(processingEnv, element)
+ block.addStatement(
+ "providers.computeIfAbsent(\$T.\$L, g -> new ArrayList<>()).add(adapter)",
+ ClassName.get(IncludeInDesigner.Group::class.java),
+ includeInDesigner.group
+ )
+ }
+
+ indexAddStatements.add("{\n")
+ indexAddStatements.indent()
+ indexAddStatements.add(block.build())
+ indexAddStatements.unindent()
+ indexAddStatements.add("}\n")
+ }
+
+ private fun assertOverridesCreateWidget(env: ProcessingEnvironment, element: TypeElement) {
+ element.enclosedElements.filterIsInstance().find {
+ ADAPTER_FUNC_CREATE_WIDGET == it.simpleName.toString()
+ }
+ ?: env.messager.printMessage(
+ ERROR,
+ "${element.qualifiedName} annotated with ${IncludeInDesigner::class.java.simpleName} must override $ADAPTER_FUNC_CREATE_WIDGET"
+ )
+ }
+
+ fun generate(outDir: String) {
+ val javaCollections = ClassName.get(Collections::class.java)
+
+ indexAddStatements.addStatement(
+ "\$L = \$T.unmodifiableMap(adapters)",
+ INDEX_MAP_FIELD,
+ javaCollections
+ )
+
+ indexAddStatements.addStatement(
+ "\$L = \$T.unmodifiableMap(providers)",
+ INDEX_PROVIDER_MAP_FIELD,
+ javaCollections
+ )
+
+ indexClassBuilder.addStaticBlock(indexAddStatements.build())
+ val file = JavaFile.builder(INDEX_PACKAGE_NAME, indexClassBuilder.build())
+ val generatedDir = File(outDir)
+ file.build().writeTo(generatedDir)
+ }
+
+ private fun addUninstantiableConstructor(builder: TypeSpec.Builder) {
+ builder.addMethod(
+ MethodSpec.constructorBuilder()
+ .addModifiers(PRIVATE)
+ .addStatement(
+ "throw new \$T(\$S)",
+ UnsupportedOperationException::class.java,
+ "This class cannot be instantiated."
+ )
+ .build()
+ )
+ }
+
+ private fun getViewTypeName(
+ processingEnv: ProcessingEnvironment,
+ 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(processingEnv: ProcessingEnvironment, annotation: ViewAdapter): String {
+ return try {
+ annotation.forView.qualifiedName
+ ?: throw IllegalStateException("Cannot find type of $annotation")
+ } catch (err: MirroredTypeException) {
+ (processingEnv.typeUtils.asElement(err.typeMirror) as TypeElement).qualifiedName.toString()
+ }
+ }
+
+ private fun getViewSuperclasses(
+ processingEnv: ProcessingEnvironment,
+ annotation: ViewAdapter
+ ): List {
+ val result = mutableListOf()
+ try {
+ val view = annotation.forView
+ var superclass = view.java.superclass
+ while (superclass != null) {
+ result.add(superclass.name)
+ superclass = superclass.superclass
+ }
+ } 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?
+ superType ?: break
+ result.add(superType.qualifiedName.toString())
+ superclass = superType.superclass
+ }
+ }
+
+ return result
+ }
+}
diff --git a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/utils.kt b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/utils.kt
new file mode 100644
index 000000000..b373d9ddf
--- /dev/null
+++ b/annotation-processors/src/main/java/com/itsaky/androidide/annotations/processor/utils.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.annotations.processor
+
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.element.TypeElement
+import javax.lang.model.type.TypeMirror
+
+const val KAPT_KOTLIN_GENERATED = "kapt.kotlin.generated"
+
+const val VIEW_CLASS = "android.view.View"
+
+const val ADAPTER_BASE_CLASS_PCK = "com.itsaky.androidide.inflater"
+const val ADAPTER_BASE_CLASS_NAME = "IViewAdapter"
+const val ADAPTER_BASE_CLASS = "$ADAPTER_BASE_CLASS_PCK.$ADAPTER_BASE_CLASS_NAME"
+const val ADAPTER_FUNC_CREATE_WIDGET = "createUiWidgets"
+
+const val INDEX_PACKAGE_NAME = "com.itsaky.androidide.inflater.internal"
+const val INDEX_CLASS_NAME = "ViewAdapterIndex"
+const val INDEX_MAP_FIELD = "adapterMap"
+const val INDEX_PROVIDER_MAP_FIELD = "widgetProviders"
+
+const val METHOD_SET_SUPERCLASS_HIERARCHY = "setSuperclassHierarchy"
+const val METHOD_SET_MODULE = "setModuleNamespace"
+
+private var adapterElement: TypeElement? = null
+private var viewElement: TypeElement? = null
+
+fun ProcessingEnvironment.adapterElement(): TypeElement {
+ return adapterElement
+ ?: elementUtils.getTypeElement(ADAPTER_BASE_CLASS)!!.also { adapterElement = it }
+}
+
+fun ProcessingEnvironment.viewElement(): TypeElement {
+ return viewElement ?: elementUtils.getTypeElement(VIEW_CLASS)!!.also { viewElement = it }
+}
+
+fun ProcessingEnvironment.erasure(typeElement: TypeElement): TypeMirror? {
+ return typeUtils.erasure(typeElement.asType())
+}
diff --git a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/contants.kt b/annotations/src/main/java/com/itsaky/androidide/annotations/uidesigner/IncludeInDesigner.kt
similarity index 56%
rename from annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/contants.kt
rename to annotations/src/main/java/com/itsaky/androidide/annotations/uidesigner/IncludeInDesigner.kt
index 715d24ee2..e5299e3b2 100644
--- a/annotation-processors/src/main/java/com/itsaky/androidide/annotations/inflater/contants.kt
+++ b/annotations/src/main/java/com/itsaky/androidide/annotations/uidesigner/IncludeInDesigner.kt
@@ -15,10 +15,23 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.annotations.inflater
+package com.itsaky.androidide.annotations.uidesigner
/**
+ * Indicates that the view (whose view adapter is annotated with [ViewAdapter]
+ * [com.itsaky.androidide.annotations.inflater.ViewAdapter] and [IncludeInDesigner]) should be
+ * included in the UI Designer and made accessible to the user.
+ *
* @author Akash Yadav
*/
+annotation class IncludeInDesigner(val group: Group) {
-const val KAPT_KOTLIN_GENERATED = "kapt.kotlin.generated"
\ No newline at end of file
+ /** The widget groups that are available in the UI Designer. */
+ enum class Group {
+ /** Includes the Android platform widgets. */
+ WIDGETS,
+
+ /** Includes the Android platform layouts. */
+ LAYOUTS
+ }
+}
diff --git a/editor/src/main/res/layout/layout_completion_item.xml b/editor/src/main/res/layout/layout_completion_item.xml
index 824088194..b9abfe5fc 100755
--- a/editor/src/main/res/layout/layout_completion_item.xml
+++ b/editor/src/main/res/layout/layout_completion_item.xml
@@ -1,4 +1,21 @@
+
+
= mutableListOf(), var isExpanded: Boolean = false)
\ No newline at end of file
+data class UiWidgetCategory(@StringRes val label: Int, var widgets: List = emptyList(), var isExpanded: Boolean = false)
\ No newline at end of file
diff --git a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/utils/Widgets.kt b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/utils/Widgets.kt
index dfdc4e6bc..9a4f8de49 100644
--- a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/utils/Widgets.kt
+++ b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/utils/Widgets.kt
@@ -17,36 +17,11 @@
package com.itsaky.androidide.uidesigner.utils
-import android.content.Context
-import android.view.SurfaceView
-import android.view.TextureView
-import android.view.ViewGroup
-import android.webkit.WebView
-import android.widget.AutoCompleteTextView
-import android.widget.Button
-import android.widget.CheckBox
-import android.widget.CheckedTextView
-import android.widget.EditText
-import android.widget.FrameLayout
-import android.widget.GridLayout
-import android.widget.ImageButton
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.ListView
-import android.widget.ProgressBar
-import android.widget.RadioButton
-import android.widget.RelativeLayout
-import android.widget.SeekBar
-import android.widget.Switch
-import android.widget.ToggleButton
-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.LayoutFile
-import com.itsaky.androidide.uidesigner.R.drawable
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.LAYOUTS
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.internal.ViewAdapterIndex
+import com.itsaky.androidide.inflater.internal.utils.simpleName
import com.itsaky.androidide.uidesigner.R.string
-import com.itsaky.androidide.uidesigner.models.UiAttribute
-import com.itsaky.androidide.uidesigner.models.UiWidget
import com.itsaky.androidide.uidesigner.models.UiWidgetCategory
internal object Widgets {
@@ -69,72 +44,10 @@ internal object Widgets {
if (widgets.isNotEmpty()) {
return@apply
}
- widgets.apply {
- add(
- UiWidget(
- AutoCompleteTextView::class.java,
- string.widget_auto_complete_textview,
- drawable.ic_widget_auto_complete_textview
- )
- )
- add(UiWidget(Button::class.java, string.widget_button, drawable.ic_widget_button))
- add(UiWidget(CheckBox::class.java, string.widget_checkbox, drawable.ic_widget_checkbox))
- add(
- UiWidget(
- CheckedTextView::class.java,
- string.widget_checked_textview,
- drawable.ic_widget_checked_textview
- )
- )
- add(UiWidget(EditText::class.java, string.widget_edittext, drawable.ic_widget_edittext))
- add(
- UiWidget(
- ImageButton::class.java,
- string.widget_image_button,
- drawable.ic_widget_imagebutton
- )
- )
- add(UiWidget(ImageView::class.java, string.widget_image_view, drawable.ic_widget_imageview))
- add(UiWidget(ListView::class.java, string.widget_listview, drawable.ic_widget_list_view))
- add(
- UiWidget(
- ProgressBar::class.java,
- string.widget_progressbar,
- drawable.ic_widget_progress_bar
- )
- )
- add(
- UiWidget(
- RadioButton::class.java,
- string.widget_radio_button,
- drawable.ic_widget_radio_button
- )
- )
- add(UiWidget(SeekBar::class.java, string.widget_seekbar, drawable.ic_widget_seek_bar))
- add(
- UiWidget(
- SurfaceView::class.java,
- string.widget_surfaceview,
- drawable.ic_widget_surface_view
- )
- )
- add(UiWidget(Switch::class.java, string.widget_switch, drawable.ic_widget_switch))
- add(
- UiWidget(
- TextureView::class.java,
- string.widget_textureview,
- drawable.ic_widget_textureview
- )
- )
- add(
- UiWidget(
- ToggleButton::class.java,
- string.widget_togglebutton,
- drawable.ic_widget_toggle_button
- )
- )
- add(UiWidget(WebView::class.java, string.widget_webview, drawable.ic_widget_webview))
- }
+ this.widgets =
+ ViewAdapterIndex.getWidgetProviders(WIDGETS)
+ .flatMap { it.getUiWidgets() }
+ .sortedBy { it.name.simpleName() }
}
}
@@ -144,57 +57,10 @@ internal object Widgets {
return@apply
}
- widgets.apply {
- add(
- UiWidget(
- FrameLayout::class.java,
- string.widget_frame_layout,
- drawable.ic_widget_frame_layout
- )
- )
- add(
- UiWidget(
- GridLayout::class.java,
- string.widget_grid_layout,
- drawable.ic_widget_grid_layout
- )
- )
- add(
- object :
- UiWidget(
- LinearLayout::class.java,
- string.widget_linear_layout_horz,
- drawable.ic_widget_linear_layout_horz
- ) {
- override fun createView(context: Context, parent: ViewGroup, layoutFile: LayoutFile): IView {
- return super.createView(context, parent, layoutFile).apply {
- addAttribute(UiAttribute(name = "orientation", value = "horizontal"))
- }
- }
- }
- )
- add(
- object :
- UiWidget(
- LinearLayout::class.java,
- string.widget_linear_layout_vert,
- drawable.ic_widget_linear_layout_vert
- ) {
- override fun createView(context: Context, parent: ViewGroup, layoutFile: LayoutFile): IView {
- return super.createView(context, parent, layoutFile).apply {
- addAttribute(UiAttribute(name = "orientation", value = "vertical"))
- }
- }
- }
- )
- add(
- UiWidget(
- RelativeLayout::class.java,
- string.widget_relative_layout,
- drawable.ic_widget_relative_layout
- )
- )
- }
+ this.widgets =
+ ViewAdapterIndex.getWidgetProviders(LAYOUTS)
+ .flatMap { it.getUiWidgets() }
+ .sortedBy { it.name.simpleName() }
}
}
}
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 d62b66494..4b6aedf28 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
@@ -21,6 +21,7 @@ import android.view.View
import com.android.SdkConstants
import com.itsaky.androidide.inflater.internal.AttributeImpl
import com.itsaky.androidide.inflater.internal.ViewImpl
+import com.itsaky.androidide.inflater.models.UiWidget
/**
* Handles logic for applying attributes to a view.
@@ -67,6 +68,23 @@ abstract class IViewAdapter : AbstractParser() {
return@lazy handlers
}
+ private val widget by lazy { createUiWidgets() }
+
+ /**
+ * Get the [UiWidget] model that can be used to list this adapter's view in the UI designer.
+ *
+ * @throws UnsupportedOperationException If this view adapter does not adapt a UI designer widget.
+ */
+ fun getUiWidgets(): List {
+ return widget
+ }
+
+ protected open fun createUiWidgets(): List {
+ throw UnsupportedOperationException(
+ "${javaClass.simpleName} is not a UI Designer widget adapter"
+ )
+ }
+
/**
* Apply the given attribute to the given view.
*
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAdapter.kt
index 563c63290..eb1d7e7d4 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsListViewAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.widget.AbsListView
import com.itsaky.androidide.inflater.AttributeHandlerScope
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAdapter.kt
index 8d763dbe8..2fa337b8e 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSeekBarAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.widget.AbsSeekBar
import com.itsaky.androidide.inflater.AttributeHandlerScope
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAdapter.kt
index 9da0e8d60..13fddf69f 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsSpinnerAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.R.layout
import android.widget.AbsSpinner
import com.itsaky.androidide.inflater.AttributeHandlerScope
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAdapter.kt
index cf30e4ebb..106b9bda6 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AbsoluteLayoutAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.widget.AbsoluteLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAdapter.kt
index 863c339be..776d7f967 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AdapterViewAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.R.layout
import android.content.Context
import android.widget.AdapterView
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAdapter.kt
index 475f2680d..a8a8dd7a7 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/AutoCompleteTextViewAdapter.kt
@@ -17,9 +17,14 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.widget.AutoCompleteTextView
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
/**
* Attribute adapter for [AutoCompleteTextView].
@@ -27,6 +32,7 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(AutoCompleteTextView::class)
+@IncludeInDesigner(group = WIDGETS)
open class AutoCompleteTextViewAdapter : EditTextAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
@@ -37,4 +43,12 @@ open class AutoCompleteTextViewAdapter : EditTextAdapt
create("dropDownWidth") { view.dropDownWidth = parseDimension(context, value) }
create("dropDownHeight") { view.dropDownHeight = parseDimension(context, value) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(UiWidget(
+ AutoCompleteTextView::class.java,
+ string.widget_auto_complete_textview,
+ drawable.ic_widget_auto_complete_textview
+ ))
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAdapter.kt
index 7a317d866..26d3e40b1 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ButtonAdapter.kt
@@ -19,10 +19,21 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.Button
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [Button].
*
* @author Akash Yadav
*/
-@ViewAdapter(Button::class) open class ButtonAdapter : TextViewAdapter()
+@ViewAdapter(Button::class)
+@IncludeInDesigner(group = WIDGETS)
+open class ButtonAdapter : TextViewAdapter() {
+ override fun createUiWidgets(): List {
+ return listOf(UiWidget(Button::class.java, string.widget_button, drawable.ic_widget_button))
+ }
+}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAdapter.kt
index 3b0a0be92..f5c58275a 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckBoxAdapter.kt
@@ -19,10 +19,23 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.CheckBox
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [CheckBox].
*
* @author Akash Yadav
*/
-@ViewAdapter(CheckBox::class) open class CheckBoxAdapter : CompoundButtonAdapter()
\ No newline at end of file
+@ViewAdapter(CheckBox::class)
+@IncludeInDesigner(group = WIDGETS)
+open class CheckBoxAdapter : CompoundButtonAdapter() {
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(CheckBox::class.java, string.widget_checkbox, drawable.ic_widget_checkbox)
+ )
+ }
+}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAdapter.kt
index b24e79643..02faabbd2 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CheckedTextViewAdapter.kt
@@ -19,7 +19,12 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.CheckedTextView
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [CheckedTextView].
@@ -27,6 +32,7 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(CheckedTextView::class)
+@IncludeInDesigner(group = WIDGETS)
open class CheckedTextViewAdapter : TextViewAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
@@ -34,4 +40,14 @@ open class CheckedTextViewAdapter : TextViewAdapter() {
create("checkMarkTintMode") { view.checkMarkTintMode = parsePorterDuffMode(value) }
create("checkMarkTint") { view.checkMarkTintList = parseColorStateList(context, value) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(
+ CheckedTextView::class.java,
+ string.widget_checked_textview,
+ drawable.ic_widget_checked_textview
+ )
+ )
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAdapter.kt
index eca985a7f..545988b0e 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/CompoundButtonAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.widget.CompoundButton
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IView
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAdapter.kt
index 1e9c6d5d5..ff5b4c47f 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/EditTextAdapter.kt
@@ -19,6 +19,11 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.EditText
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [EditText].
@@ -26,4 +31,11 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* @author Akash Yadav
*/
@ViewAdapter(EditText::class)
-open class EditTextAdapter : TextViewAdapter()
+@IncludeInDesigner(group = WIDGETS)
+open class EditTextAdapter : TextViewAdapter() {
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(EditText::class.java, string.widget_edittext, drawable.ic_widget_edittext)
+ )
+ }
+}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAdapter.kt
index 8c132f355..b5665c23d 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/FrameLayoutAdapter.kt
@@ -19,7 +19,12 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.FrameLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.LAYOUTS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [FrameLayout].
@@ -27,11 +32,18 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(FrameLayout::class)
+@IncludeInDesigner(group = LAYOUTS)
open class FrameLayoutAdapter : ViewGroupAdapter() {
-
+
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
create("foregroundGravity") { view.foregroundGravity = parseGravity(value) }
create("measureAllChildren") { view.measureAllChildren = parseBoolean(value) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(FrameLayout::class.java, string.widget_frame_layout, drawable.ic_widget_frame_layout)
+ )
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAdapter.kt
index 5e677b4bc..029799463 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GestureOverlayViewAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.gesture.GestureOverlayView
import com.blankj.utilcode.util.ReflectUtils
import com.itsaky.androidide.annotations.inflater.ViewAdapter
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAdapter.kt
index 5c911c3b6..e41e3486d 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/GridLayoutAdapter.kt
@@ -19,7 +19,12 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.GridLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.LAYOUTS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [GridLayout].
@@ -27,6 +32,7 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(GridLayout::class)
+@IncludeInDesigner(group = LAYOUTS)
open class GridLayoutAdapter : ViewGroupAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
@@ -39,6 +45,12 @@ open class GridLayoutAdapter : ViewGroupAdapter() {
create("useDefaultMargins") { view.useDefaultMargins = parseBoolean(value) }
}
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(GridLayout::class.java, string.widget_grid_layout, drawable.ic_widget_grid_layout)
+ )
+ }
+
protected open fun parseOrientation(value: String): Int {
return if ("vertical" == value) {
GridLayout.VERTICAL
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAdapter.kt
index 57f2447ac..e7670383a 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageButtonAdapter.kt
@@ -19,6 +19,11 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.ImageButton
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [ImageButton].
@@ -26,4 +31,11 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* @author Akash Yadav
*/
@ViewAdapter(ImageButton::class)
-open class ImageButtonAdapter : ImageViewAdapter()
+@IncludeInDesigner(group = WIDGETS)
+open class ImageButtonAdapter : ImageViewAdapter() {
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(ImageButton::class.java, string.widget_image_button, drawable.ic_widget_imagebutton)
+ )
+ }
+}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAdapter.kt
index 246ea1717..4a042a240 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ImageViewAdapter.kt
@@ -27,9 +27,14 @@ import android.widget.ImageView.ScaleType.FIT_END
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.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
import com.itsaky.androidide.inflater.AttributeHandlerScope
import com.itsaky.androidide.inflater.IView
import com.itsaky.androidide.inflater.R
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adpater [ImageView]s.
@@ -37,6 +42,7 @@ import com.itsaky.androidide.inflater.R
* @author Akash Yadav
*/
@com.itsaky.androidide.annotations.inflater.ViewAdapter(ImageView::class)
+@IncludeInDesigner(group = WIDGETS)
open class ImageViewAdapter : ViewAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
@@ -53,6 +59,12 @@ open class ImageViewAdapter : ViewAdapter() {
create("tintMode") { view.imageTintMode = parsePorterDuffMode(value) }
}
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(ImageView::class.java, string.widget_image_view, drawable.ic_widget_imageview)
+ )
+ }
+
override fun applyBasic(view: IView) {
super.applyBasic(view)
(view.view as ImageView).setImageResource(R.drawable.ic_android)
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAdapter.kt
index 22a535f3c..5c93e13fa 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/LinearLayoutAdapter.kt
@@ -17,14 +17,26 @@
package com.itsaky.androidide.inflater.internal.adapters
+import android.content.Context
+import android.view.ViewGroup
import android.widget.LinearLayout
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.LAYOUTS
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
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.inflater.utils.newAttribute
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [LinearLayout].
@@ -32,6 +44,7 @@ import com.itsaky.androidide.inflater.LayoutBehavior.VERTICAL
* @author Akash Yadav
*/
@ViewAdapter(LinearLayout::class)
+@IncludeInDesigner(group = LAYOUTS)
open class LinearLayoutAdapter : ViewGroupAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
@@ -49,6 +62,22 @@ open class LinearLayoutAdapter : ViewGroupAdapter() {
create("weightSum") { view.weightSum = parseFloat(value) }
}
+ override fun createUiWidgets(): List {
+ val horizontal =
+ LinearLayoutWidget(
+ title = string.widget_linear_layout_horz,
+ icon = drawable.ic_widget_linear_layout_horz,
+ isVertical = false
+ )
+ val vertical =
+ LinearLayoutWidget(
+ title = string.widget_linear_layout_vert,
+ icon = drawable.ic_widget_linear_layout_vert,
+ isVertical = true
+ )
+ return listOf(horizontal, vertical)
+ }
+
override fun getLayoutBehavior(group: IViewGroup): LayoutBehavior {
val orientation = group.findAttribute(INamespace.ANDROID.uri, "orientation")
return if (orientation?.value == "vertical") VERTICAL else HORIZONTAL
@@ -61,4 +90,24 @@ open class LinearLayoutAdapter : ViewGroupAdapter() {
else -> LinearLayout.HORIZONTAL
}
}
+
+ private class LinearLayoutWidget(
+ @StringRes title: Int,
+ @DrawableRes icon: Int,
+ private val isVertical: Boolean
+ ) : UiWidget(LinearLayout::class.java, title, icon) {
+
+ companion object {
+ private const val HORIZONTAL = "horizontal"
+ private const val VERTICAL = "vertical"
+ }
+
+ override fun createView(context: Context, parent: ViewGroup, layoutFile: LayoutFile): IView {
+ return super.createView(context, parent, layoutFile).apply {
+ addAttribute(
+ newAttribute(this, name = "orientation", value = if (isVertical) VERTICAL else HORIZONTAL)
+ )
+ }
+ }
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAdapter.kt
index 2baca964a..7885c5219 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ListViewAdapter.kt
@@ -22,7 +22,12 @@ 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.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [ListView].
@@ -30,6 +35,7 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(ListView::class)
+@IncludeInDesigner(group = WIDGETS)
open class ListViewAdapter : AbsListViewAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
@@ -45,4 +51,10 @@ open class ListViewAdapter : AbsListViewAdapter() {
create("footerDividersEnabled") { view.setFooterDividersEnabled(parseBoolean(value)) }
create("headerDividersEnabled") { view.setHeaderDividersEnabled(parseBoolean(value)) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(ListView::class.java, string.widget_listview, drawable.ic_widget_list_view)
+ )
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAdapter.kt
index 86253aa15..96451b766 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ProgressBarAdapter.kt
@@ -19,6 +19,9 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.ProgressBar
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [ProgressBar].
@@ -74,4 +77,10 @@ open class ProgressBarAdapter : ViewAdapter() {
view.secondaryProgressTintMode = parsePorterDuffMode(value)
}
}
+
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(ProgressBar::class.java, string.widget_progressbar, drawable.ic_widget_progress_bar)
+ )
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAdapter.kt
index e60c244c8..522bf7b60 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RadioButtonAdapter.kt
@@ -19,6 +19,11 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.RadioButton
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [RadioButton].
@@ -26,4 +31,12 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* @author Akash Yadav
*/
@ViewAdapter(RadioButton::class)
-open class RadioButtonAdapter : CompoundButtonAdapter()
+@IncludeInDesigner(group = WIDGETS)
+open class RadioButtonAdapter : CompoundButtonAdapter() {
+
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(RadioButton::class.java, string.widget_radio_button, drawable.ic_widget_radio_button)
+ )
+ }
+}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAdapter.kt
index 7c9a28dd6..09102d71c 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/RelativeLayoutAdapter.kt
@@ -19,7 +19,12 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.RelativeLayout
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.LAYOUTS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [RelativeLayout].
@@ -27,6 +32,7 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(RelativeLayout::class)
+@IncludeInDesigner(group = LAYOUTS)
open class RelativeLayoutAdapter : ViewGroupAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
@@ -34,4 +40,14 @@ open class RelativeLayoutAdapter : ViewGroupAdapter() {
create("gravity") { view.gravity = parseGravity(value) }
create("ignoreGravity") { view.ignoreGravity = parseId(file.resName, value) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(
+ RelativeLayout::class.java,
+ string.widget_relative_layout,
+ drawable.ic_widget_relative_layout
+ )
+ )
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAdapter.kt
index 04335fee9..1c867ca9a 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SeekBarAdapter.kt
@@ -19,7 +19,12 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.widget.SeekBar
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [SeekBar].
@@ -27,6 +32,7 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(SeekBar::class)
+@IncludeInDesigner(group = WIDGETS)
open class SeekBarAdapter : AbsSeekBarAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
@@ -34,4 +40,8 @@ open class SeekBarAdapter : AbsSeekBarAdapter() {
create("thumb") { view.thumb = parseDrawable(context, value) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(UiWidget(SeekBar::class.java, string.widget_seekbar, drawable.ic_widget_seek_bar))
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAdapter.kt
index 969dabfaf..cb7c13d37 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SpinnerAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.widget.Spinner
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.AttributeHandlerScope
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAdapter.kt
index b1274946b..f7d21b3bd 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SurfaceViewAdapter.kt
@@ -18,10 +18,22 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.view.SurfaceView
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [SurfaceView].
* @author Akash Yadav
*/
@com.itsaky.androidide.annotations.inflater.ViewAdapter(SurfaceView::class)
-open class SurfaceViewAdapter : ViewAdapter()
+@IncludeInDesigner(group = WIDGETS)
+open class SurfaceViewAdapter : ViewAdapter() {
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(SurfaceView::class.java, string.widget_surfaceview, drawable.ic_widget_surface_view)
+ )
+ }
+}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAdapter.kt
index 5853db029..2b3c85269 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/SwitchAdapter.kt
@@ -20,7 +20,12 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.graphics.Typeface.DEFAULT
import android.widget.Switch
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [Switch].
@@ -28,6 +33,7 @@ import com.itsaky.androidide.inflater.AttributeHandlerScope
* @author Akash Yadav
*/
@ViewAdapter(Switch::class)
+@IncludeInDesigner(group = WIDGETS)
open class SwitchAdapter : CompoundButtonAdapter() {
override fun createAttrHandlers(create: (String, AttributeHandlerScope.() -> Unit) -> Unit) {
super.createAttrHandlers(create)
@@ -47,4 +53,8 @@ open class SwitchAdapter : CompoundButtonAdapter() {
create("trackTintMode") { view.trackTintMode = parsePorterDuffMode(value) }
create("typeface") { view.setSwitchTypeface(parseTypeface(value)) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(UiWidget(Switch::class.java, string.widget_switch, drawable.ic_widget_switch))
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAdapter.kt
index 30db68b4c..43b7eeab6 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextViewAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.graphics.Typeface
import android.text.TextUtils
import android.text.util.Linkify
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAdapter.kt
index fe44c95ae..366ea0164 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/TextureViewAdapter.kt
@@ -18,6 +18,11 @@
package com.itsaky.androidide.inflater.internal.adapters
import android.view.TextureView
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [TextureView].
@@ -25,4 +30,11 @@ import android.view.TextureView
* @author Akash Yadav
*/
@com.itsaky.androidide.annotations.inflater.ViewAdapter(TextureView::class)
-open class TextureViewAdapter : ViewAdapter()
\ No newline at end of file
+@IncludeInDesigner(group = WIDGETS)
+open class TextureViewAdapter : ViewAdapter() {
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(TextureView::class.java, string.widget_textureview, drawable.ic_widget_textureview)
+ )
+ }
+}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAdapter.kt
index e112ec00d..7bd60affb 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ToggleButtonAdapter.kt
@@ -21,6 +21,9 @@ import android.widget.ToggleButton
import com.blankj.utilcode.util.ReflectUtils.reflect
import com.itsaky.androidide.annotations.inflater.ViewAdapter
import com.itsaky.androidide.inflater.AttributeHandlerScope
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [ToggleButton].
@@ -36,4 +39,14 @@ open class ToggleButtonAdapter : CompoundButtonAdapter() {
create("textOff") { view.textOff = parseString(value) }
create("textOn") { view.textOn = parseString(value) }
}
+
+ override fun createUiWidgets(): List {
+ return listOf(
+ UiWidget(
+ ToggleButton::class.java,
+ string.widget_togglebutton,
+ drawable.ic_widget_toggle_button
+ )
+ )
+ }
}
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAdapter.kt
index 7fdc6dcab..79c4231f2 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.content.Context
import android.graphics.PorterDuff
import android.os.Build
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAdapter.kt
index 3317e5939..999bf10bc 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/ViewGroupAdapter.kt
@@ -17,6 +17,8 @@
package com.itsaky.androidide.inflater.internal.adapters
+import com.itsaky.androidide.resources.R.string
+import com.itsaky.androidide.resources.R.drawable
import android.animation.LayoutTransition
import android.view.ViewGroup
import com.itsaky.androidide.inflater.AttributeHandlerScope
diff --git a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAdapter.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAdapter.kt
index 9fa4d326a..a3ad62a21 100644
--- a/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAdapter.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/internal/adapters/WebViewAdapter.kt
@@ -19,6 +19,11 @@ package com.itsaky.androidide.inflater.internal.adapters
import android.webkit.WebView
import com.itsaky.androidide.annotations.inflater.ViewAdapter
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner
+import com.itsaky.androidide.annotations.uidesigner.IncludeInDesigner.Group.WIDGETS
+import com.itsaky.androidide.inflater.models.UiWidget
+import com.itsaky.androidide.resources.R.drawable
+import com.itsaky.androidide.resources.R.string
/**
* Attribute adapter for [WebView].
@@ -26,4 +31,9 @@ import com.itsaky.androidide.annotations.inflater.ViewAdapter
* @author Akash Yadav
*/
@ViewAdapter(WebView::class)
-open class WebViewAdapter : AbsoluteLayoutAdapter()
\ No newline at end of file
+@IncludeInDesigner(group = WIDGETS)
+open class WebViewAdapter : AbsoluteLayoutAdapter() {
+ override fun createUiWidgets(): List {
+ return listOf(UiWidget(WebView::class.java, string.widget_webview, drawable.ic_widget_webview))
+ }
+}
diff --git a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiWidget.kt b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/models/UiWidget.kt
similarity index 78%
rename from uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiWidget.kt
rename to xml-inflater/src/main/java/com/itsaky/androidide/inflater/models/UiWidget.kt
index 4dac7fd78..21b1bce18 100644
--- a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/models/UiWidget.kt
+++ b/xml-inflater/src/main/java/com/itsaky/androidide/inflater/models/UiWidget.kt
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.uidesigner.models
+package com.itsaky.androidide.inflater.models
import android.content.Context
import android.view.View
@@ -25,10 +25,14 @@ import androidx.annotation.StringRes
import androidx.core.view.updatePaddingRelative
import com.blankj.utilcode.util.SizeUtils
import com.itsaky.androidide.inflater.IView
+import com.itsaky.androidide.inflater.IViewGroup
import com.itsaky.androidide.inflater.internal.LayoutFile
import com.itsaky.androidide.inflater.internal.ViewAdapterIndex.getAdapter
+import com.itsaky.androidide.inflater.internal.ViewGroupImpl
+import com.itsaky.androidide.inflater.internal.ViewImpl
import com.itsaky.androidide.inflater.internal.utils.ViewFactory
import com.itsaky.androidide.inflater.internal.utils.ViewFactory.generateLayoutParams
+import com.itsaky.androidide.inflater.utils.lookupComponentFactory
open class UiWidget(val name: String, @StringRes val label: Int, @DrawableRes val icon: Int) {
@@ -46,13 +50,14 @@ open class UiWidget(val name: String, @StringRes val label: Int, @DrawableRes va
*/
open fun createView(context: Context, parent: ViewGroup, layoutFile: LayoutFile): IView {
val v = ViewFactory.createViewInstance(name, context)
- val view: IView =
- if (v is ViewGroup) {
- UiViewGroup(layoutFile, name, v).apply {
- val dp8 = SizeUtils.dp2px(8f)
- view.updatePaddingRelative(start = dp8, top = dp8, end = dp8, bottom = dp8)
- }
- } else UiView(layoutFile, name, v)
+
+ val view: IView = createView(layoutFile, v)
+
+ (view as? IViewGroup)?.apply {
+ val dp8 = SizeUtils.dp2px(8f)
+ this.view.updatePaddingRelative(start = dp8, top = dp8, end = dp8, bottom = dp8)
+ }
+
view.view.layoutParams = generateLayoutParams(parent)
val adapter =
getAdapter(view.name)
@@ -61,6 +66,12 @@ open class UiWidget(val name: String, @StringRes val label: Int, @DrawableRes va
return view
}
+ private fun createView(layoutFile: LayoutFile, v: View) =
+ (lookupComponentFactory()?.createView(layoutFile, name, v)
+ ?: if (v is ViewGroup) {
+ ViewGroupImpl(layoutFile, name, v)
+ } else ViewImpl(layoutFile, name, v))
+
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is UiWidget) return false