diff --git a/android-mvvm/.gitignore b/android-mvvm-conductor/.gitignore
similarity index 100%
rename from android-mvvm/.gitignore
rename to android-mvvm-conductor/.gitignore
diff --git a/android-mvvm-conductor/build.gradle b/android-mvvm-conductor/build.gradle
new file mode 100644
index 0000000..1b12a2b
--- /dev/null
+++ b/android-mvvm-conductor/build.gradle
@@ -0,0 +1,54 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+buildscript {
+ ext.kotlin_version = '1.1.2-2'
+ ext.moduleArtifact = 'conductor'
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.3"
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+
+ dataBinding {
+ enabled = true
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ provided project(path: ':android-mvvm-core')
+ provided project(path: ':android-mvvm-kotlin')
+
+ testCompile 'junit:junit:4.12'
+
+ compile 'com.bluelinelabs:conductor:2.1.2'
+ compile 'com.bluelinelabs:conductor-rxlifecycle2:2.1.2'
+ compile 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.0.1'
+ compile "com.android.support:support-v4:$support_library_version"
+ provided "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+
+}
+
+apply from: rootProject.file('gradle/bintray-push.gradle')
\ No newline at end of file
diff --git a/android-mvvm-conductor/proguard-rules.pro b/android-mvvm-conductor/proguard-rules.pro
new file mode 100644
index 0000000..5f245cb
--- /dev/null
+++ b/android-mvvm-conductor/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/gabor/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/android-mvvm-conductor/src/main/AndroidManifest.xml b/android-mvvm-conductor/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3b5d76a
--- /dev/null
+++ b/android-mvvm-conductor/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/android-mvvm-conductor/src/main/java/com/manaschaudhari/android_mvvm/conductor/ConductorExtensions.kt b/android-mvvm-conductor/src/main/java/com/manaschaudhari/android_mvvm/conductor/ConductorExtensions.kt
new file mode 100644
index 0000000..94cef58
--- /dev/null
+++ b/android-mvvm-conductor/src/main/java/com/manaschaudhari/android_mvvm/conductor/ConductorExtensions.kt
@@ -0,0 +1,43 @@
+package com.manaschaudhari.android_mvvm.conductor
+
+import com.bluelinelabs.conductor.rxlifecycle2.ControllerEvent
+import com.trello.rxlifecycle2.LifecycleProvider
+import com.trello.rxlifecycle2.kotlin.bindUntilEvent
+import io.reactivex.BackpressureStrategy
+import io.reactivex.Completable
+import io.reactivex.Flowable
+import io.reactivex.Observable
+
+/**
+ * Created by gabor on 2017. 05. 01..
+ */
+
+typealias ControllerLifecycleProvider = LifecycleProvider
+
+/**
+ * Convenience function for [Observable]s to bind to a controller's lifecycle. This makes it possible
+ * to terminate a stream when the specified [end] controller event occurs. Also, this function takes care
+ * of resubscribing to the Observable when the specified [start] lifecycle event occurs.
+ *
+ * @param lp The lifecycle provider instance, usually the Controller itself (in case of an [RxController]).
+ */
+fun Observable.attachToLifecycle(lp: ControllerLifecycleProvider, start: ControllerEvent = ControllerEvent.ATTACH, end: ControllerEvent = ControllerEvent.DETACH): Observable = lp.lifecycle()
+ .filter { it == start }
+ .switchMap { this.bindUntilEvent(lp, end) }
+ .bindUntilEvent(lp, ControllerEvent.DESTROY)
+
+/*fun Single.attachToLifecycle(lp: ControllerLifecycleProvider, start: ControllerEvent = ControllerEvent.ATTACH, end: ControllerEvent = ControllerEvent.DETACH): Single = lp.lifecycle()
+ .filter { it == start }
+ .flatMapSingle { this.bindUntilEvent(lp, end) }
+ .bindUntilEvent(lp, ControllerEvent.DESTROY)*/
+
+fun Flowable.attachToLifecycle(lp: ControllerLifecycleProvider, start: ControllerEvent = ControllerEvent.ATTACH, end: ControllerEvent = ControllerEvent.DETACH): Flowable = lp.lifecycle()
+ .toFlowable(BackpressureStrategy.LATEST)
+ .filter { it == start }
+ .switchMap { this.bindUntilEvent(lp, end) }
+ .bindUntilEvent(lp, ControllerEvent.DESTROY)
+
+fun Completable.attachToLifecycle(lp: ControllerLifecycleProvider, start: ControllerEvent = ControllerEvent.ATTACH, end: ControllerEvent = ControllerEvent.DETACH): Completable = lp.lifecycle()
+ .filter { it == start }
+ .flatMapCompletable { this.bindUntilEvent(lp, end) }
+ .bindUntilEvent(lp, ControllerEvent.DESTROY)
diff --git a/android-mvvm-conductor/src/main/java/com/manaschaudhari/android_mvvm/conductor/MvvmController.kt b/android-mvvm-conductor/src/main/java/com/manaschaudhari/android_mvvm/conductor/MvvmController.kt
new file mode 100644
index 0000000..014069f
--- /dev/null
+++ b/android-mvvm-conductor/src/main/java/com/manaschaudhari/android_mvvm/conductor/MvvmController.kt
@@ -0,0 +1,100 @@
+package com.manaschaudhari.android_mvvm.conductor
+
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.bluelinelabs.conductor.Controller
+import com.bluelinelabs.conductor.rxlifecycle2.RxController
+import com.manaschaudhari.android_mvvm.adapters.ViewModelBinder
+import com.manaschaudhari.android_mvvm.utils.BindingUtils
+import com.trello.rxlifecycle2.internal.Preconditions
+
+/**
+ * A [Controller] that uses DataBinding to inflate a layout, and asks implementations
+ * to create a [ViewModel] instance when necessary. This class is designed to integrate
+ * with Conductor, and to take care of retaining the ViewModel across orientation changes.
+ *
+ * With that, it is possible for ViewModels to hold a reference to the [Controller] (either
+ * directly, or indirectly), and not cause any memory leaks. This is possible
+ * because the Controller will be retained across orientation changes as well.
+ *
+ * Created by Gabor Szanto on 2017. 04. 29..
+ */
+abstract class MvvmController : RxController {
+ constructor() : super()
+ constructor(args: Bundle?) : super(args)
+
+ /**
+ * The [ViewModel] instance that will be held by implementations. This instance will be
+ * constructed once, and persisted across orientation changes.
+ */
+ abstract var viewModel: ViewModel
+
+ /**
+ * The generic [Binding] instance. This will be recreated whenever the Controller decides
+ * to recreate its View.
+ */
+ lateinit var binding: Binding
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
+ val vm = this::class.java.getDeclaredField("viewModel")
+ vm.isAccessible = true
+ if (vm.get(this) == null)
+ createViewModel()
+
+ binding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false)
+ return binding.root
+ }
+
+ override fun onDestroyView(view: View) {
+ val binding = this::class.java.getField("binding")
+ binding.isAccessible = true
+ binding.set(this, null)
+ super.onDestroyView(view)
+ }
+
+ private val defaultBinder: com.manaschaudhari.android_mvvm.adapters.ViewModelBinder
+ get() {
+ val defaultBinder = BindingUtils.getDefaultBinder()
+ Preconditions.checkNotNull(defaultBinder, "Default Binder")
+ return defaultBinder!!
+ }
+
+ override fun onAttach(view: View) {
+ super.onAttach(view)
+ defaultBinder.bind(binding, viewModel)
+ }
+
+ override fun onDetach(view: View) {
+ defaultBinder.bind(binding, null)
+ binding.executePendingBindings()
+ super.onDetach(view)
+ }
+
+ /**
+ * The [Controller] instance is about to be destroyed, so we need to clear out the
+ * reference to the [ViewModel].
+ *
+ * Note: we need to use reflection here to keep Kotlin happy about the nullability. :)
+ */
+ override fun onDestroy() {
+ val viewModel = this::class.java.getField("viewModel")
+ viewModel.isAccessible = true
+ viewModel.set(this, null)
+ super.onDestroy()
+ }
+
+ /**
+ * Implementations should return the ID of the layout to be inflated.
+ */
+ abstract fun getLayoutId(): Int
+
+ /**
+ * Implementations should create the ViewModel in this method, either manually, or
+ * by using dependency injection (e.g. Dagger 2)
+ */
+ abstract fun createViewModel()
+}
\ No newline at end of file
diff --git a/android-mvvm-core/.gitignore b/android-mvvm-core/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/android-mvvm-core/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/android-mvvm/build.gradle b/android-mvvm-core/build.gradle
similarity index 69%
rename from android-mvvm/build.gradle
rename to android-mvvm-core/build.gradle
index 9ca6f69..b772e80 100644
--- a/android-mvvm/build.gradle
+++ b/android-mvvm-core/build.gradle
@@ -1,16 +1,20 @@
apply plugin: 'com.android.library'
-def isCi() {
+buildscript {
+ ext.moduleArtifact = 'core'
+}
+
+static def isCi() {
return "true".equals(System.getenv('CI'))
}
android {
- compileSdkVersion 24
- buildToolsVersion "24.0.0"
+ compileSdkVersion 25
+ buildToolsVersion "25.0.3"
defaultConfig {
- minSdkVersion 9
- targetSdkVersion 24
+ minSdkVersion 16
+ targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -60,13 +64,19 @@ if (isCi()) {
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
+ compile "io.reactivex.rxjava2:rxjava:$rx_version"
+
+ compile "com.android.support:recyclerview-v7:$support_library_version"
+ compile "com.android.support:support-v4:$support_library_version"
+
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
- compile 'io.reactivex:rxjava:1.1.7'
- compile 'com.android.support:recyclerview-v7:24.2.1'
- compile 'com.android.support:appcompat-v7:24.2.1'
+ androidTestCompile "com.android.support:recyclerview-v7:$support_library_version"
}
-apply from: rootProject.file('gradle/bintray-push.gradle')
\ No newline at end of file
+apply from: rootProject.file('gradle/bintray-push.gradle')
+repositories {
+ mavenCentral()
+ jcenter()
+}
diff --git a/android-mvvm-core/gradle/wrapper/gradle-wrapper.jar b/android-mvvm-core/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/android-mvvm-core/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android-mvvm-core/gradle/wrapper/gradle-wrapper.properties b/android-mvvm-core/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..9a778d6
--- /dev/null
+++ b/android-mvvm-core/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Dec 28 10:00:20 PST 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/android-mvvm-core/gradlew b/android-mvvm-core/gradlew
new file mode 100644
index 0000000..9d82f78
--- /dev/null
+++ b/android-mvvm-core/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/android-mvvm-core/pom.xml b/android-mvvm-core/pom.xml
new file mode 100644
index 0000000..3368922
--- /dev/null
+++ b/android-mvvm-core/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+ com.apptive
+ android-mvvm
+ 0.3.0
+ aar
+ Android MVVM
+ Tools for implementing MVVM on Android
+ https://github.com/manas-chaudhari/android-mvvm
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+
+
+
+
+ manas-chaudhari
+ Manas Chaudhari
+ chaudhari.manas@gmail.com
+
+
+
+ https://github.com/manas-chaudhari/android-mvvm.git
+ https://github.com/manas-chaudhari/android-mvvm.git
+ https://github.com/manas-chaudhari/android-mvvm
+
+
+
+ com.android.support
+ recyclerview-v7
+ 25.3.0
+ compile
+
+
+ com.android.support
+ appcompat-v7
+ 25.3.0
+ compile
+
+
+ com.trello
+ navi
+ 1.0
+ compile
+
+
+
diff --git a/android-mvvm/proguard-rules.pro b/android-mvvm-core/proguard-rules.pro
similarity index 100%
rename from android-mvvm/proguard-rules.pro
rename to android-mvvm-core/proguard-rules.pro
diff --git a/android-mvvm-core/settings.gradle b/android-mvvm-core/settings.gradle
new file mode 100644
index 0000000..6a12b63
--- /dev/null
+++ b/android-mvvm-core/settings.gradle
@@ -0,0 +1 @@
+include ':android-mvvm-core'
diff --git a/android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/ApplicationTest.java b/android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/ApplicationTest.java
similarity index 100%
rename from android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/ApplicationTest.java
rename to android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/ApplicationTest.java
diff --git a/android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/BindingTestViewModel.java b/android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/BindingTestViewModel.java
similarity index 97%
rename from android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/BindingTestViewModel.java
rename to android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/BindingTestViewModel.java
index 892f9c0..2fc42a9 100644
--- a/android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/BindingTestViewModel.java
+++ b/android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/BindingTestViewModel.java
@@ -21,7 +21,7 @@
import java.util.List;
-import rx.Observable;
+import io.reactivex.Observable;
public class BindingTestViewModel implements ViewModel {
public List subclassList;
diff --git a/android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapterTest.java b/android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapterTest.java
similarity index 100%
rename from android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapterTest.java
rename to android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapterTest.java
diff --git a/android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModel.java b/android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModel.java
similarity index 100%
rename from android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModel.java
rename to android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModel.java
diff --git a/android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModelBinder.java b/android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModelBinder.java
similarity index 100%
rename from android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModelBinder.java
rename to android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/TestViewModelBinder.java
diff --git a/android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapterTest.java b/android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapterTest.java
similarity index 100%
rename from android-mvvm/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapterTest.java
rename to android-mvvm-core/src/androidTest/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapterTest.java
diff --git a/android-mvvm/src/androidTest/res/layout/layout_binding_tests.xml b/android-mvvm-core/src/androidTest/res/layout/layout_binding_tests.xml
similarity index 100%
rename from android-mvvm/src/androidTest/res/layout/layout_binding_tests.xml
rename to android-mvvm-core/src/androidTest/res/layout/layout_binding_tests.xml
diff --git a/android-mvvm/src/androidTest/res/layout/layout_test.xml b/android-mvvm-core/src/androidTest/res/layout/layout_test.xml
similarity index 100%
rename from android-mvvm/src/androidTest/res/layout/layout_test.xml
rename to android-mvvm-core/src/androidTest/res/layout/layout_test.xml
diff --git a/android-mvvm-core/src/main/AndroidManifest.xml b/android-mvvm-core/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..448d0aa
--- /dev/null
+++ b/android-mvvm-core/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/FieldUtils.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/FieldUtils.java
new file mode 100644
index 0000000..1ad2863
--- /dev/null
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/FieldUtils.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2016 Manas Chaudhari
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.manaschaudhari.android_mvvm;
+
+import android.databinding.Observable.OnPropertyChangedCallback;
+import android.databinding.ObservableBoolean;
+import android.databinding.ObservableDouble;
+import android.databinding.ObservableField;
+import android.databinding.ObservableFloat;
+import android.databinding.ObservableInt;
+import android.databinding.ObservableList;
+import android.databinding.ObservableLong;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import java.util.List;
+
+import io.reactivex.Observable;
+import io.reactivex.ObservableEmitter;
+import io.reactivex.ObservableOnSubscribe;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Cancellable;
+import io.reactivex.functions.Consumer;
+
+public class FieldUtils {
+ @NonNull
+ public static Observable toObservable(@NonNull final ObservableField field) {
+ return Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(final ObservableEmitter subscriber) {
+ if (field.get() != null)
+ subscriber.onNext(field.get());
+
+ final OnPropertyChangedCallback callback = new OnPropertyChangedCallback() {
+ @Override
+ public void onPropertyChanged(android.databinding.Observable observable, int i) {
+ if (field.get() == null) {
+ Log.w("FieldUtils", "Null value received in ObservableField. Since Observables cannot emit null, ignoring this value.");
+ return;
+ }
+
+ subscriber.onNext(field.get());
+ }
+ };
+ field.addOnPropertyChangedCallback(callback);
+
+ subscriber.setCancellable(new Cancellable() {
+ @Override
+ public void cancel() throws Exception {
+ field.removeOnPropertyChangedCallback(callback);
+ }
+ });
+ }
+ });
+ }
+
+ @NonNull
+ public static Observable toObservable(@NonNull final ObservableInt field) {
+ return Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(final ObservableEmitter subscriber) {
+ subscriber.onNext(field.get());
+ final OnPropertyChangedCallback callback = new OnPropertyChangedCallback() {
+ @Override
+ public void onPropertyChanged(android.databinding.Observable observable, int i) {
+ subscriber.onNext(field.get());
+ }
+ };
+ field.addOnPropertyChangedCallback(callback);
+
+ subscriber.setCancellable(new Cancellable() {
+ @Override
+ public void cancel() throws Exception {
+ field.removeOnPropertyChangedCallback(callback);
+ }
+ });
+ }
+ });
+ }
+
+ @NonNull
+ public static Observable toObservable(@NonNull final ObservableBoolean field) {
+ return Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(final ObservableEmitter subscriber) {
+ subscriber.onNext(field.get());
+ final OnPropertyChangedCallback callback = new OnPropertyChangedCallback() {
+ @Override
+ public void onPropertyChanged(android.databinding.Observable observable, int i) {
+ subscriber.onNext(field.get());
+ }
+ };
+ field.addOnPropertyChangedCallback(callback);
+ subscriber.setCancellable(new Cancellable() {
+ @Override
+ public void cancel() throws Exception {
+ field.removeOnPropertyChangedCallback(callback);
+ }
+ });
+ }
+ });
+ }
+
+ @NonNull
+ public static Observable toObservable(@NonNull final ObservableFloat field) {
+ return Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(final ObservableEmitter subscriber) {
+ subscriber.onNext(field.get());
+ final OnPropertyChangedCallback callback = new OnPropertyChangedCallback() {
+ @Override
+ public void onPropertyChanged(android.databinding.Observable observable, int i) {
+ subscriber.onNext(field.get());
+ }
+ };
+ field.addOnPropertyChangedCallback(callback);
+ subscriber.setCancellable(new Cancellable() {
+ @Override
+ public void cancel() throws Exception {
+ field.removeOnPropertyChangedCallback(callback);
+ }
+ });
+ }
+ });
+ }
+
+ @NonNull
+ public static Observable toObservable(@NonNull final ObservableDouble field) {
+ return Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(final ObservableEmitter subscriber) {
+ subscriber.onNext(field.get());
+ final OnPropertyChangedCallback callback = new OnPropertyChangedCallback() {
+ @Override
+ public void onPropertyChanged(android.databinding.Observable observable, int i) {
+ subscriber.onNext(field.get());
+ }
+ };
+ field.addOnPropertyChangedCallback(callback);
+ subscriber.setCancellable(new Cancellable() {
+ @Override
+ public void cancel() throws Exception {
+ field.removeOnPropertyChangedCallback(callback);
+ }
+ });
+ }
+ });
+ }
+
+ @NonNull
+ public static Observable toObservable(@NonNull final ObservableLong field) {
+ return Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(final ObservableEmitter subscriber) {
+ subscriber.onNext(field.get());
+ final OnPropertyChangedCallback callback = new OnPropertyChangedCallback() {
+ @Override
+ public void onPropertyChanged(android.databinding.Observable observable, int i) {
+ subscriber.onNext(field.get());
+ }
+ };
+ field.addOnPropertyChangedCallback(callback);
+ subscriber.setCancellable(new Cancellable() {
+ @Override
+ public void cancel() throws Exception {
+ field.removeOnPropertyChangedCallback(callback);
+ }
+ });
+ }
+ });
+ }
+
+ @NonNull
+ public static Observable> toObservable(@NonNull final ObservableList field) {
+ return Observable.create(new ObservableOnSubscribe>() {
+ @Override
+ public void subscribe(final ObservableEmitter> subscriber) {
+ subscriber.onNext(field);
+ final ObservableList.OnListChangedCallback> callback = new ObservableList.OnListChangedCallback>() {
+ @Override
+ public void onChanged(ObservableList observableList) {
+ subscriber.onNext(field);
+ }
+
+ @Override
+ public void onItemRangeChanged(ObservableList observableList, int i, int i1) {
+ onChanged(observableList);
+ }
+
+ @Override
+ public void onItemRangeInserted(ObservableList observableList, int i, int i1) {
+ onChanged(observableList);
+ }
+
+ @Override
+ public void onItemRangeMoved(ObservableList observableList, int i, int i1, int i2) {
+ onChanged(observableList);
+ }
+
+ @Override
+ public void onItemRangeRemoved(ObservableList observableList, int i, int i1) {
+ onChanged(observableList);
+ }
+ };
+ field.addOnListChangedCallback(callback);
+ subscriber.setCancellable(new Cancellable() {
+ @Override
+ public void cancel() throws Exception {
+ field.removeOnListChangedCallback(callback);
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * A convenient wrapper for {@code ReadOnlyField#create(Observable)}
+ *
+ * @return DataBinding field created from the specified Observable
+ */
+ @NonNull
+ public static ReadOnlyField toField(@NonNull final Observable observable) {
+ return ReadOnlyField.create(observable);
+ }
+
+ @NonNull
+ public static Disposable bindTo(@NonNull final Observable observable, @NonNull final ObservableField field) {
+ return observable.subscribe(new Consumer() {
+ @Override
+ public void accept(@io.reactivex.annotations.NonNull T t) throws Exception {
+ field.set(t);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
+ Log.e("FieldUtils", "onError in source observable", throwable);
+ }
+ });
+ }
+
+/* @NonNull
+ public static Disposable bindTo(@NonNull final ObservableSource observable, @NonNull final Observer observer) {
+ observable.subscribe(observer);
+ return observable.subscribe(new Consumer() {
+ @Override
+ public void accept(@io.reactivex.annotations.NonNull T t) throws Exception {
+ field.onNext(t);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
+ Log.e("FieldUtils", "onError in source observable", throwable);
+ }
+ });
+ }*/
+
+ @NonNull
+ public static , U> ReadOnlyList toList(@NonNull final Observable observable) {
+ return ReadOnlyList.create(observable);
+ }
+}
\ No newline at end of file
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyField.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyField.java
similarity index 79%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyField.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyField.java
index cbd07e3..4e609d1 100644
--- a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyField.java
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyField.java
@@ -22,13 +22,13 @@
import java.util.HashMap;
-import rx.Observable;
-import rx.Subscription;
-import rx.functions.Action1;
+import io.reactivex.Observable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
public class ReadOnlyField extends ObservableField {
final Observable source;
- final HashMap subscriptions = new HashMap<>();
+ final HashMap subscriptions = new HashMap<>();
public static ReadOnlyField create(@NonNull Observable source) {
return new ReadOnlyField<>(source);
@@ -37,15 +37,15 @@ public static ReadOnlyField create(@NonNull Observable source) {
protected ReadOnlyField(@NonNull Observable source) {
super();
this.source = source
- .doOnNext(new Action1() {
+ .doOnNext(new Consumer() {
@Override
- public void call(T t) {
+ public void accept(T t) {
ReadOnlyField.super.set(t);
}
})
- .doOnError(new Action1() {
+ .doOnError(new Consumer() {
@Override
- public void call(Throwable throwable) {
+ public void accept(Throwable throwable) {
Log.e("ReadOnlyField", "onError in source observable", throwable);
}
})
@@ -70,9 +70,9 @@ public synchronized void addOnPropertyChangedCallback(OnPropertyChangedCallback
@Override
public synchronized void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
super.removeOnPropertyChangedCallback(callback);
- Subscription subscription = subscriptions.remove(callback);
- if (subscription != null && !subscription.isUnsubscribed()) {
- subscription.unsubscribe();
+ Disposable subscription = subscriptions.remove(callback);
+ if (subscription != null && !subscription.isDisposed()) {
+ subscription.dispose();
}
}
}
diff --git a/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyList.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyList.java
new file mode 100644
index 0000000..00689ec
--- /dev/null
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ReadOnlyList.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 Manas Chaudhari
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.manaschaudhari.android_mvvm;
+
+import android.databinding.ObservableArrayList;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.List;
+
+import io.reactivex.Observable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
+
+public class ReadOnlyList, U> extends ObservableArrayList {
+ final Observable source;
+ private Disposable subscription;
+ private int listenerCount = 0;
+
+ public static , X> ReadOnlyList create(@NonNull Observable source) {
+ return new ReadOnlyList<>(source);
+ }
+
+ protected ReadOnlyList(@NonNull Observable source) {
+ super();
+ this.source = source;
+ subscribe();
+ }
+
+ /**
+ * @deprecated Setter of ReadOnlyList does nothing. Merge with the source Observable instead.
+ * See Documentation/ObservablesAndSetters.md
+ */
+ @Override
+ public boolean add(U object) {
+ return false;
+ }
+
+ @Override
+ public void clear() {
+ }
+
+ @Override
+ public boolean addAll(Collection extends U> collection) {
+ return false;
+ }
+
+ @Override
+ public void addOnListChangedCallback(OnListChangedCallback listener) {
+ super.addOnListChangedCallback(listener);
+ listenerCount++;
+ if (subscription == null || subscription.isDisposed()) {
+ subscribe();
+ }
+ }
+
+ private void subscribe() {
+ subscription = this.source.subscribe(new Consumer() {
+ @Override
+ public void accept(T us) {
+ ReadOnlyList.super.clear();
+ ReadOnlyList.super.addAll(us);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(Throwable throwable) {
+ Log.e("ReadOnlyList", "onError in source observable", throwable);
+ }
+ });
+ }
+
+ @Override
+ public void removeOnListChangedCallback(OnListChangedCallback listener) {
+ super.removeOnListChangedCallback(listener);
+ if (--listenerCount == 0 && subscription != null && !subscription.isDisposed()) {
+ subscription.dispose();
+ subscription = null;
+ }
+ }
+}
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/ViewModel.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ViewModel.java
similarity index 99%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/ViewModel.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ViewModel.java
index e041ba8..af44815 100644
--- a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/ViewModel.java
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/ViewModel.java
@@ -17,4 +17,4 @@
package com.manaschaudhari.android_mvvm;
public interface ViewModel {
-}
+}
\ No newline at end of file
diff --git a/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/Connectable.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/Connectable.java
new file mode 100644
index 0000000..e0202a6
--- /dev/null
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/Connectable.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Manas Chaudhari
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.manaschaudhari.android_mvvm.adapters;
+
+import io.reactivex.disposables.Disposable;
+
+/**
+ * A {@link com.manaschaudhari.android_mvvm.ViewModel} can implement this
+ * interface to return a Subscription which will eventually be
+ * unsubscribed from when the ViewModel's View is detached from the
+ * view hierarchy.
+ */
+public interface Connectable {
+ Disposable connect();
+}
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapter.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapter.java
similarity index 86%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapter.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapter.java
index fa0f769..6baf1e0 100644
--- a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapter.java
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/RecyclerViewAdapter.java
@@ -31,16 +31,17 @@
import java.util.HashMap;
import java.util.List;
-import rx.Observable;
-import rx.Subscription;
-import rx.functions.Action1;
+import io.reactivex.Observable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
+
public class RecyclerViewAdapter extends RecyclerView.Adapter {
private @NonNull List latestViewModels = new ArrayList<>();
private final @NonNull ViewProvider viewProvider;
private final @NonNull ViewModelBinder binder;
private final @NonNull Observable> source;
- private final @NonNull HashMap subscriptions = new HashMap<>();
+ private final @NonNull HashMap subscriptions = new HashMap<>();
public RecyclerViewAdapter(@NonNull Observable> viewModels,
@NonNull ViewProvider viewProvider,
@@ -48,16 +49,16 @@ public RecyclerViewAdapter(@NonNull Observable> viewModels,
this.viewProvider = viewProvider;
this.binder = viewModelBinder;
source = viewModels
- .doOnNext(new Action1>() {
+ .doOnNext(new Consumer>() {
@Override
- public void call(@Nullable List viewModels) {
+ public void accept(@Nullable List viewModels) {
latestViewModels = viewModels != null ? viewModels : new ArrayList();
notifyDataSetChanged();
}
})
- .doOnError(new Action1() {
+ .doOnError(new Consumer() {
@Override
- public void call(Throwable throwable) {
+ public void accept(Throwable throwable) {
Log.e("RecyclerViewAdapter", "onError in source observable", throwable);
}
})
@@ -101,9 +102,9 @@ public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observe
@Override
public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
super.unregisterAdapterDataObserver(observer);
- Subscription subscription = subscriptions.remove(observer);
- if (subscription != null && !subscription.isUnsubscribed()) {
- subscription.unsubscribe();
+ Disposable subscription = subscriptions.remove(observer);
+ if (subscription != null && !subscription.isDisposed()) {
+ subscription.dispose();
}
}
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewModelBinder.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewModelBinder.java
similarity index 100%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewModelBinder.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewModelBinder.java
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapter.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapter.java
similarity index 79%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapter.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapter.java
index 1074920..538352e 100644
--- a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapter.java
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerAdapter.java
@@ -31,9 +31,9 @@
import java.util.ArrayList;
import java.util.List;
-import rx.Observable;
-import rx.Subscription;
-import rx.functions.Action1;
+import io.reactivex.Observable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Consumer;
public class ViewPagerAdapter extends PagerAdapter implements Connectable {
@@ -44,23 +44,23 @@ public class ViewPagerAdapter extends PagerAdapter implements Connectable {
private final Observable> source;
@NonNull
- private final ViewProvider viewProvider;
+ private final ViewPagerViewProvider viewProvider;
@NonNull
private final ViewModelBinder binder;
- public ViewPagerAdapter(@NonNull Observable> viewModels, @NonNull ViewProvider viewProvider, @NonNull ViewModelBinder binder) {
+ public ViewPagerAdapter(@NonNull Observable> viewModels, @NonNull ViewPagerViewProvider viewProvider, @NonNull ViewModelBinder binder) {
source = viewModels
- .doOnNext(new Action1>() {
+ .doOnNext(new Consumer>() {
@Override
- public void call(@Nullable List viewModels) {
+ public void accept(@Nullable List viewModels) {
latestViewModels = (viewModels != null) ? viewModels : new ArrayList();
notifyDataSetChanged();
}
})
- .doOnError(new Action1() {
+ .doOnError(new Consumer() {
@Override
- public void call(Throwable throwable) {
+ public void accept(Throwable throwable) {
Log.e("ViewPagerAdapter", "Error in source observable", throwable);
}
})
@@ -103,11 +103,17 @@ public int getCount() {
@Override
public boolean isViewFromObject(View view, Object object) {
- return ((ViewDataBinding)object).getRoot() == view;
+ return ((ViewDataBinding) object).getRoot() == view;
}
@Override
- public Subscription connect() {
+ public CharSequence getPageTitle(int position) {
+ ViewModel vm = latestViewModels.get(position);
+ return viewProvider.getTitle(vm);
+ }
+
+ @Override
+ public Disposable connect() {
return source.subscribe();
}
}
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/Connectable.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerViewProvider.java
similarity index 81%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/Connectable.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerViewProvider.java
index b99cc3e..146f43e 100644
--- a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/Connectable.java
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewPagerViewProvider.java
@@ -16,8 +16,8 @@
package com.manaschaudhari.android_mvvm.adapters;
-import rx.Subscription;
+import com.manaschaudhari.android_mvvm.ViewModel;
-public interface Connectable {
- Subscription connect();
+public interface ViewPagerViewProvider extends ViewProvider {
+ String getTitle(ViewModel vm);
}
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewProvider.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewProvider.java
similarity index 100%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewProvider.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/adapters/ViewProvider.java
diff --git a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/utils/BindingUtils.java b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/utils/BindingUtils.java
similarity index 58%
rename from android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/utils/BindingUtils.java
rename to android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/utils/BindingUtils.java
index 110188d..bf4284e 100644
--- a/android-mvvm/src/main/java/com/manaschaudhari/android_mvvm/utils/BindingUtils.java
+++ b/android-mvvm-core/src/main/java/com/manaschaudhari/android_mvvm/utils/BindingUtils.java
@@ -18,13 +18,18 @@
import android.databinding.BindingAdapter;
import android.databinding.BindingConversion;
+import android.databinding.adapters.ListenerUtil;
+import android.os.Build;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.view.View;
import com.manaschaudhari.android_mvvm.R;
import com.manaschaudhari.android_mvvm.ViewModel;
@@ -32,14 +37,17 @@
import com.manaschaudhari.android_mvvm.adapters.RecyclerViewAdapter;
import com.manaschaudhari.android_mvvm.adapters.ViewModelBinder;
import com.manaschaudhari.android_mvvm.adapters.ViewPagerAdapter;
+import com.manaschaudhari.android_mvvm.adapters.ViewPagerViewProvider;
import com.manaschaudhari.android_mvvm.adapters.ViewProvider;
import java.util.ArrayList;
import java.util.List;
-import rx.Observable;
-import rx.Subscription;
-import rx.functions.Func1;
+import io.reactivex.Observable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Function;
+import io.reactivex.processors.PublishProcessor;
+import io.reactivex.subjects.PublishSubject;
@SuppressWarnings("unused")
public class BindingUtils {
@@ -62,9 +70,9 @@ public static void bindAdapter(@NonNull ViewPager viewPager, @Nullable PagerAdap
// Disconnect previous adapter if its Connectable
if (oldAdapter != null && oldAdapter instanceof Connectable) {
- Subscription subscription = (Subscription) viewPager.getTag(R.integer.tag_subscription);
- if (subscription != null && !subscription.isUnsubscribed()) {
- subscription.unsubscribe();
+ Disposable subscription = (Disposable) viewPager.getTag(R.integer.tag_subscription);
+ if (subscription != null && !subscription.isDisposed()) {
+ subscription.dispose();
}
viewPager.setTag(R.integer.tag_subscription, null);
}
@@ -92,7 +100,7 @@ public static void bindAdapterWithDefaultBinder(@NonNull RecyclerView recyclerVi
}
@BindingAdapter({"items", "view_provider"})
- public static void bindAdapterWithDefaultBinder(@NonNull ViewPager viewPager, @Nullable Observable> items, @Nullable ViewProvider viewProvider) {
+ public static void bindAdapterWithDefaultBinder(@NonNull ViewPager viewPager, @Nullable Observable> items, @Nullable ViewPagerViewProvider viewProvider) {
ViewPagerAdapter adapter = null;
if (items != null && viewProvider != null) {
Preconditions.checkNotNull(defaultBinder, "Default Binder");
@@ -115,9 +123,9 @@ public int getView(ViewModel vm) {
@BindingConversion
@Nullable
public static Observable> toGenericList(@Nullable Observable> specificList) {
- return specificList == null ? null : specificList.map(new Func1, List>() {
+ return specificList == null ? null : specificList.map(new Function, List>() {
@Override
- public List call(List ts) {
+ public List apply(List ts) {
return new ArrayList(ts);
}
});
@@ -127,7 +135,7 @@ public List call(List ts) {
@Nullable
public static Observable> toListObservable(@Nullable List specificList) {
return specificList == null ? null :
- Observable.just((List)new ArrayList(specificList));
+ Observable.just((List) new ArrayList(specificList));
}
// Extra Utilities
@@ -137,4 +145,85 @@ public static void bindLayoutManager(@NonNull RecyclerView recyclerView, boolean
int orientation = vertical ? RecyclerView.VERTICAL : RecyclerView.HORIZONTAL;
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext(), orientation, false));
}
-}
+
+ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
+ @BindingAdapter("lifecycle")
+ public static void bindLifecycle(View view, final Connectable connectable) {
+ View.OnAttachStateChangeListener newListener = null;
+
+ if (connectable != null) {
+ newListener = new View.OnAttachStateChangeListener() {
+ private Disposable subscription;
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ subscription = connectable.connect();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ subscription.dispose();
+ }
+ };
+
+ View.OnAttachStateChangeListener oldValue = ListenerUtil.trackListener(view, newListener, R.id.onAttachStateChangeListener);
+ if (oldValue != null) {
+ view.removeOnAttachStateChangeListener(oldValue);
+ }
+ }
+
+ if (newListener != null) {
+ if (ViewCompat.isAttachedToWindow(view)) {
+ newListener.onViewAttachedToWindow(view);
+ }
+
+ view.addOnAttachStateChangeListener(newListener);
+ }
+ }
+
+ private static final Object CLICK_OBJECT = new Object();
+
+ @BindingConversion
+ public static View.OnClickListener toOnClickListener(final PublishSubject