diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
new file mode 100644
index 0000000..ed13fbf
Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..97626ba
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/annotation/.gitignore b/annotation/.gitignore
new file mode 100644
index 0000000..ed53c05
--- /dev/null
+++ b/annotation/.gitignore
@@ -0,0 +1,29 @@
+/build
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+.gradle/
+build/
+
+# Intellij
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/dictionaries
+.idea/libraries
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+.idea/misc.xml
+.idea/runConfigurations.xml
+.idea/vcs.xml
+.idea/modules.xml
\ No newline at end of file
diff --git a/annotation/build.gradle b/annotation/build.gradle
new file mode 100644
index 0000000..3e82836
--- /dev/null
+++ b/annotation/build.gradle
@@ -0,0 +1,10 @@
+apply plugin: 'java-library'
+apply plugin: 'kotlin'
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+}
+
+sourceCompatibility = "7"
+targetCompatibility = "7"
diff --git a/annotation/src/main/java/com/umairjavid/kombind/anontation/SimpleKombindAdapter.kt b/annotation/src/main/java/com/umairjavid/kombind/anontation/SimpleKombindAdapter.kt
new file mode 100644
index 0000000..5cfd3eb
--- /dev/null
+++ b/annotation/src/main/java/com/umairjavid/kombind/anontation/SimpleKombindAdapter.kt
@@ -0,0 +1,5 @@
+package com.umairjavid.kombind.anontation
+
+@Retention(AnnotationRetention.SOURCE)
+@Target(AnnotationTarget.FIELD)
+annotation class SimpleKombindAdapter(val layoutRes: Int = 0)
diff --git a/app/build.gradle b/app/build.gradle
index abfed1a..2a9aaee 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -36,6 +36,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ kapt {
+ generateStubs = true
+ }
dataBinding {
enabled = true
}
@@ -44,6 +47,9 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':kombind')
+ compileOnly project(':annotation')
+ kapt project(':processor')
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.legacy:legacy-support-v4:$androidx_legacy_support_library_version"
implementation "androidx.appcompat:appcompat:$androidx_appcompat"
diff --git a/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainActivity.kt b/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainActivity.kt
index a35ad05..c8999bb 100644
--- a/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainActivity.kt
+++ b/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainActivity.kt
@@ -4,8 +4,10 @@ import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.umairjavid.kombind.ui.KombindActivity
import com.umairjavid.kombindsample.R
+import com.umairjavid.kombindsample.model.SimpleHeader
import com.umairjavid.kombindsample.repo.SimpleItemRepository
-import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.android.synthetic.main.activity_main.simple_item_list
+import main.KombindAdapter_MainState_Items
class MainActivity : KombindActivity() {
override val viewModelClass = MainViewModel::class.java
@@ -21,8 +23,12 @@ class MainActivity : KombindActivity() {
private fun setupSimpleItemList() {
simple_item_list.apply {
layoutManager = LinearLayoutManager(this@MainActivity)
- adapter = SimpleItemAdapter(viewModel.state.items, viewModel)
- .registerObserver(this@MainActivity)
+ adapter = object :KombindAdapter_MainState_Items(viewModel.state.items, viewModel) {
+ override fun getLayout(position: Int) = when(items[position]) {
+ is SimpleHeader -> R.layout.item_simpleheader
+ else -> R.layout.item_simpleitem
+ }
+ } .registerObserver(this@MainActivity)
}
}
}
diff --git a/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainState.kt b/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainState.kt
index 1c90a48..d65a6a3 100644
--- a/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainState.kt
+++ b/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainState.kt
@@ -1,10 +1,12 @@
package com.umairjavid.kombindsample.ui.main
+import com.umairjavid.kombind.anontation.SimpleKombindAdapter
import com.umairjavid.kombind.model.MutableLiveArrayList
import com.umairjavid.kombind.model.MutableLiveField
class MainState {
val title = MutableLiveField("Items Loaded!")
+ @SimpleKombindAdapter
val items = MutableLiveArrayList()
operator fun invoke(func: MainState.() -> Unit) = func()
diff --git a/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainViewModel.kt b/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainViewModel.kt
index 9b92ea8..ecd33b8 100644
--- a/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainViewModel.kt
+++ b/app/src/main/java/com/umairjavid/kombindsample/ui/main/MainViewModel.kt
@@ -11,8 +11,7 @@ import com.umairjavid.kombindsample.repo.SimpleItemRepository
class MainViewModel(application: Application, private val simpleItemRepository: SimpleItemRepository) : KombindViewModel(application),
SimpleItemAdapter.HeaderActionHandler,
SimpleItemAdapter.ItemActionHandler {
- val state = MainState()
-
+ val state = MainState()
init {
loadItems()
}
diff --git a/build.gradle b/build.gradle
index c6004e0..98f7055 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,8 +1,8 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.android_plugin_version = '3.2.1'
- ext.kotlin_version = '1.3.0'
+ ext.android_plugin_version = '3.4.0'
+ ext.kotlin_version = '1.3.30'
repositories {
google()
jcenter()
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 5e54eca..277ee54 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sat Nov 10 09:57:43 EST 2018
+#Thu Apr 18 00:03:04 EDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/kombind/build.gradle b/kombind/build.gradle
index afd9684..1c8e559 100644
--- a/kombind/build.gradle
+++ b/kombind/build.gradle
@@ -8,7 +8,6 @@ group = 'com.github.ujavid'
project.ext {
compileSdkVersion = 28
- buildToolsVersion = '28.0.3'
minSdkVersion = 14
targetSdkVersion = 28
versionCode = 1
@@ -16,7 +15,7 @@ project.ext {
support_library_version = '27.1.1'
androidx_appcompat = '1.0.2'
- android_material = '1.1.0-alpha01'
+ android_material = '1.1.0-alpha05'
lifecycle_version = '2.0.0'
junit_version = '4.12'
test_runner_version = '1.1.0'
@@ -25,7 +24,6 @@ project.ext {
android {
compileSdkVersion project.ext.compileSdkVersion
- buildToolsVersion project.ext.buildToolsVersion
defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
@@ -54,7 +52,7 @@ dependencies {
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
- classifier 'sources'
+ archiveClassifier.set("sources")
}
artifacts {
diff --git a/kombind/src/main/java/com/umairjavid/kombind/ui/DialogFragmentBuilder.kt b/kombind/src/main/java/com/umairjavid/kombind/ui/DialogFragmentBuilder.kt
index a6dc133..a67ac2a 100644
--- a/kombind/src/main/java/com/umairjavid/kombind/ui/DialogFragmentBuilder.kt
+++ b/kombind/src/main/java/com/umairjavid/kombind/ui/DialogFragmentBuilder.kt
@@ -10,7 +10,7 @@ open class DialogFragmentBuilder(private val clazz: Class
val fragment = clazz.newInstance()
fragment.arguments = arguments
return fragment
- } catch (e: java.lang.InstantiationException) {
+ } catch (e: InstantiationException) {
throw RuntimeException(e)
} catch (e: IllegalAccessException) {
throw RuntimeException(e)
@@ -27,7 +27,7 @@ open class DialogFragmentBuilder(private val clazz: Class
val fragment = fragmentManager.findFragmentByTag(fragmentTag)
return if (fragment != null) {
- clazz.cast(fragment)
+ clazz.cast(fragment)!!
} else {
forceShow(fragmentManager)
}
diff --git a/kombind/src/main/java/com/umairjavid/kombind/ui/KombindDialogFragment.kt b/kombind/src/main/java/com/umairjavid/kombind/ui/KombindDialogFragment.kt
index 811bb90..41d6957 100644
--- a/kombind/src/main/java/com/umairjavid/kombind/ui/KombindDialogFragment.kt
+++ b/kombind/src/main/java/com/umairjavid/kombind/ui/KombindDialogFragment.kt
@@ -1,17 +1,17 @@
package com.umairjavid.kombind.ui
import android.app.Dialog
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.ViewModelProviders
-import androidx.databinding.DataBindingUtil
-import androidx.databinding.ViewDataBinding
import android.os.Bundle
-import androidx.fragment.app.DialogFragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
import androidx.databinding.library.baseAdapters.BR
+import androidx.fragment.app.DialogFragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.ViewModelProviders
import com.umairjavid.kombind.ext.registerViewActionObserver
abstract class KombindDialogFragment : DialogFragment() {
@@ -28,7 +28,7 @@ abstract class KombindDialogFragment : DialogFragment() {
viewModel.activityViewModel = (activity as KombindActivity<*>).viewModel
viewBinding = DataBindingUtil.inflate(inflater, layoutResId, container, false)
viewBinding.setVariable(BR.viewModel, viewModel)
- viewBinding.setLifecycleOwner(this)
+ viewBinding.lifecycleOwner = this
registerViewActionObserver(viewModel.viewAction)
return viewBinding.root
}
@@ -43,7 +43,7 @@ abstract class KombindDialogFragment : DialogFragment() {
super.onViewStateRestored(savedInstanceState)
val width = resources.displayMetrics.widthPixels
- dialog.window?.setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT)
+ dialog!!.window?.setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
diff --git a/processor/.gitignore b/processor/.gitignore
new file mode 100644
index 0000000..8cdebca
--- /dev/null
+++ b/processor/.gitignore
@@ -0,0 +1,29 @@
+/build
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+.gradle/
+build/
+
+# Intellij
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/dictionaries
+.idea/libraries
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+.idea/misc.xml
+.idea/runConfigurations.xml
+.idea/vcs.xml
+.idea/modules.xml
diff --git a/processor/build.gradle b/processor/build.gradle
new file mode 100644
index 0000000..b888386
--- /dev/null
+++ b/processor/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'java-library'
+apply plugin: 'kotlin'
+apply plugin: 'kotlin-kapt'
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ kapt 'com.google.auto.service:auto-service:1.0-rc2'
+ implementation 'com.google.auto.service:auto-service:1.0-rc2'
+ implementation project(':annotation')
+ implementation 'com.squareup:kotlinpoet:1.2.0'
+}
+
+sourceCompatibility = "7"
+targetCompatibility = "7"
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+
+}
+repositories {
+ mavenCentral()
+}
+compileKotlin {
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+compileTestKotlin {
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
diff --git a/processor/src/main/java/com/umairjavid/kombind/processor/AdapterProcessor.kt b/processor/src/main/java/com/umairjavid/kombind/processor/AdapterProcessor.kt
new file mode 100644
index 0000000..34b4b44
--- /dev/null
+++ b/processor/src/main/java/com/umairjavid/kombind/processor/AdapterProcessor.kt
@@ -0,0 +1,129 @@
+package com.umairjavid.kombind.processor
+
+import com.google.auto.service.AutoService
+import com.squareup.kotlinpoet.ClassName
+import com.squareup.kotlinpoet.FileSpec
+import com.squareup.kotlinpoet.FunSpec
+import com.squareup.kotlinpoet.KModifier
+import com.squareup.kotlinpoet.ParameterSpec
+import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
+import com.squareup.kotlinpoet.PropertySpec
+import com.squareup.kotlinpoet.TypeName
+import com.squareup.kotlinpoet.TypeSpec
+import com.squareup.kotlinpoet.asTypeName
+import com.umairjavid.kombind.anontation.SimpleKombindAdapter
+import java.io.File
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.Messager
+import javax.annotation.processing.ProcessingEnvironment
+import javax.annotation.processing.Processor
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.TypeElement
+import javax.lang.model.element.VariableElement
+import javax.tools.Diagnostic
+import kotlin.reflect.KClass
+
+@AutoService(Processor::class)
+class AdapterProcessor : AbstractProcessor() {
+ lateinit var messenger: Messager
+ val genaratedClassSet = mutableSetOf()
+
+ override fun init(env: ProcessingEnvironment?) {
+ super.init(env)
+ messenger = env!!.messager
+ }
+ override fun getSupportedAnnotationTypes() = mutableSetOf(SimpleKombindAdapter::class.java.name)
+
+ override fun getSupportedSourceVersion() = SourceVersion.latestSupported()
+
+ override fun process(typeElemnts: MutableSet?, roundEnv: RoundEnvironment?): Boolean {
+ val env = roundEnv!!.getElementsAnnotatedWith(SimpleKombindAdapter::class.java)
+ env.forEach {
+ val layoutRes = it.getAnnotation(SimpleKombindAdapter::class.java).layoutRes
+ if (it is VariableElement)
+ generateAdapterClass(it, layoutRes)
+ }
+ return false
+ }
+
+ fun generateAdapterClass(element: VariableElement, layoutRes: Int) {
+ if (!element.asType().asTypeName().isMutableLiveArraylist()) {
+ messenger.printMessage(Diagnostic.Kind.ERROR, "Needs to be of type MutableArrayList")
+ return
+ }
+
+ val kombindPackage = "com.umairjavid.kombind.ui"
+ val appPackageName = processingEnv.elementUtils.getPackageOf(element).simpleName.toString()
+ val kombindAdapterName = "KombindAdapter"
+ val viewHolder = "KombindAdapter.ViewHolder"
+ val elementName = element.simpleName
+ val enclosingClassName = element.enclosingElement.simpleName
+ val className = "KombindAdapter_${enclosingClassName.toString().capitalize()}_${elementName.toString().capitalize()}"
+
+ if (genaratedClassSet.contains(className)) {
+ messenger.printMessage(Diagnostic.Kind.ERROR, "Properties with sig not allowed,consider combinding both types into one adapter")
+ return
+ }
+ genaratedClassSet.add(className)
+
+ val file = FileSpec.builder(appPackageName, className)
+ .addType(TypeSpec.classBuilder(className)
+ .makeAbstractIfTrue(layoutRes == 0)
+ .primaryConstructor(FunSpec.constructorBuilder()
+ .addParameter("items", element.asType().asTypeName().checkForAnyType())
+ .addParameter("handler", Any::class).build())
+ .addProperty(generateConstructorProperty("handler", Any::class))
+ .addSuperclassConstructorParameter("items")
+ .addFunction(generateGetHandlerMethod())
+ .addFunction(if (layoutRes == 0) generateAbstractGetLayoutMethod() else generateGetLayoutMethod(layoutRes))
+ .superclass(ClassName(kombindPackage, kombindAdapterName).parameterizedBy(ClassName(kombindPackage, viewHolder))
+ ).build())
+ .build()
+ val kaptKotlnGenDir = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME]
+ file.writeTo(File(kaptKotlnGenDir, "Gen$className"))
+ }
+
+ private fun generateConstructorProperty(propertyName: String, propertyType: KClass<*>) = PropertySpec.builder(propertyName, propertyType)
+ .initializer(propertyName)
+ .addModifiers(KModifier.PRIVATE)
+ .build()
+
+ private fun generateGetHandlerMethod() = FunSpec.builder("getHandler")
+ .addModifiers(KModifier.OVERRIDE)
+ .addParameter(ParameterSpec.builder("position", Int::class).build())
+ .addStatement("return handler")
+ .build()
+
+ private fun generateGetLayoutMethod(layoutRes: Int): FunSpec {
+ return FunSpec.builder("getLayout")
+ .addModifiers(KModifier.OVERRIDE)
+ .addParameter(ParameterSpec.builder("position", Int::class).build())
+ .addStatement("return $layoutRes")
+ .returns(Int::class)
+ .build()
+ }
+
+ private fun generateAbstractGetLayoutMethod() =
+ FunSpec.builder("getLayout")
+ .addModifiers(KModifier.OVERRIDE, KModifier.ABSTRACT)
+ .addParameter(ParameterSpec.builder("position", Int::class).build())
+ .returns(Int::class)
+ .build()
+
+ private fun String.capitalize() = this.substring(0..0).toUpperCase() + this.substring(1)
+
+
+ private fun TypeName.checkForAnyType() = if (this.toString().equals("com.umairjavid.kombind.model.MutableLiveArrayList")) {
+ ClassName("com.umairjavid.kombind.model", "MutableLiveArrayList").parameterizedBy(ClassName("kotlin", "Any"))
+ } else this
+
+ private fun TypeSpec.Builder.makeAbstractIfTrue(isAbstract: Boolean) = if (isAbstract) {
+
+ this.addModifiers(KModifier.ABSTRACT)
+ } else this
+
+ private fun TypeName.isMutableLiveArraylist() = this.toString().startsWith("com.umairjavid.kombind.model.MutableLiveArrayList")
+
+ companion object { const val KAPT_KOTLIN_GENERATED_OPTION_NAME = "kapt.kotlin.generated" }
+}
diff --git a/settings.gradle b/settings.gradle
index d0f092e..5379f76 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':kombind'
+include ':app', ':kombind', ':processor', ':annotation'