diff --git a/build.gradle b/build.gradle index 845c6a0..e919e31 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,25 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - buildscript { repositories { + google() + maven { + url 'https://maven.google.com/' + name 'Google' + } jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.2' + classpath 'com.android.tools.build:gradle:3.6.3' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files } } allprojects { repositories { + maven { + url 'https://maven.google.com/' + name 'Google' + } jcenter() maven { url "https://nexus.eastbanctech.ru/content/repositories/releases/" diff --git a/gradle.properties b/gradle.properties index 1d3591c..c5a1e55 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,8 @@ # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# org.gradle.parallel=true +android.enableJetifier=true +android.useAndroidX=true + +android.enableUnitTestBinaryResources=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e410a0e..ac9fa5a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat May 27 22:05:03 KRAT 2017 +#Thu Mar 19 13:28:18 NOVT 2020 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 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip diff --git a/reamplib/build.gradle b/reamplib/build.gradle index 3444944..bb71da4 100644 --- a/reamplib/build.gradle +++ b/reamplib/build.gradle @@ -3,12 +3,14 @@ apply plugin: 'maven' apply plugin: 'signing' android { - compileSdkVersion 25 - buildToolsVersion '25.0.3' + compileSdkVersion 29 + buildToolsVersion '29.0.3' + + testOptions.unitTests.includeAndroidResources = true defaultConfig { - minSdkVersion 15 - targetSdkVersion 25 + minSdkVersion 19 + targetSdkVersion 29 versionCode 1 versionName "1.0" } @@ -24,65 +26,65 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - testCompile "org.robolectric:robolectric:3.3.2" - testCompile "org.robolectric:shadows-support-v4:3.3.2" - compile 'com.android.support:appcompat-v7:25.3.1' -} - -def isReleaseBuild() { - return VERSION_NAME.contains("SNAPSHOT") == false -} - -def getReleaseRepositoryUrl() { - return hasProperty("RELEASE_REPOSITORY_URL") ? RELEASE_REPOSITORY_URL : "" + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.12' + testImplementation "org.robolectric:robolectric:4.3.1" + testImplementation 'org.mockito:mockito-core:2.25.1' + implementation 'androidx.appcompat:appcompat:1.1.0' } -def getSnapshotRepositoryUrl() { - return ghasProperty("SNAPSHOT_REPOSITORY_URL") ? SNAPSHOT_REPOSITORY_URL : "" -} - -def getRepositoryUsername() { - return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" -} - -def getRepositoryPassword() { - return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" -} +//def isReleaseBuild() { +// return VERSION_NAME.contains("SNAPSHOT") == false +//} +// +//def getReleaseRepositoryUrl() { +// return hasProperty("RELEASE_REPOSITORY_URL") ? RELEASE_REPOSITORY_URL : "" +//} +// +//def getSnapshotRepositoryUrl() { +// return ghasProperty("SNAPSHOT_REPOSITORY_URL") ? SNAPSHOT_REPOSITORY_URL : "" +//} +// +//def getRepositoryUsername() { +// return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" +//} +// +//def getRepositoryPassword() { +// return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" +//} tasks.withType(Javadoc) { failOnError false } -ext { - bintrayRepo = 'Reamp' - bintrayName = 'Reamp' - bintrayOrg = 'eastbanctechru' - - publishedGroupId = 'etr.android.reamp' - libraryName = 'Reamp' - artifact = 'reamp' - - libraryDescription = 'Reamp' - - siteUrl = 'https://github.com/eastbanctechru/Reamp' - gitUrl = 'https://github.com/eastbanctechru/Reamp.git' - - libraryVersion = '1.0.2' - - developerId = 'eastbanctechru' - developerName = 'EastBanc Technologies' - developerEmail = 'info@eastbanctech.ru' - - licenseName = 'The MIT License' - licenseUrl = 'https://opensource.org/licenses/MIT' - allLicenses = ["MIT"] -} - +//ext { +// bintrayRepo = 'Reamp' +// bintrayName = 'Reamp' +// bintrayOrg = 'eastbanctechru' +// +// publishedGroupId = 'etr.android.reamp' +// libraryName = 'Reamp' +// artifact = 'reamp' +// +// libraryDescription = 'Reamp' +// +// siteUrl = 'https://github.com/eastbanctechru/Reamp' +// gitUrl = 'https://github.com/eastbanctechru/Reamp.git' +// +// libraryVersion = '1.0.2' +// +// developerId = 'eastbanctechru' +// developerName = 'EastBanc Technologies' +// developerEmail = 'info@eastbanctech.ru' +// +// licenseName = 'The MIT License' +// licenseUrl = 'https://opensource.org/licenses/MIT' +// allLicenses = ["MIT"] +//} +// apply from: '../jacoco.gradle' - -if (project.rootProject.file('local.properties').exists()) { - apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' - apply from: './bintray.gradle' -} +// +//if (project.rootProject.file('local.properties').exists()) { +// apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' +// apply from: './bintray.gradle' +//} diff --git a/reamplib/src/main/java/etr/android/reamp/functional/ConsumerNonNull.java b/reamplib/src/main/java/etr/android/reamp/functional/ConsumerNonNull.java new file mode 100644 index 0000000..2c1131f --- /dev/null +++ b/reamplib/src/main/java/etr/android/reamp/functional/ConsumerNonNull.java @@ -0,0 +1,7 @@ +package etr.android.reamp.functional; + +import androidx.annotation.NonNull; + +public interface ConsumerNonNull { + void consume(@NonNull T t); +} diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/Action.java b/reamplib/src/main/java/etr/android/reamp/mvp/Action.java index 828a29e..2a7cf16 100644 --- a/reamplib/src/main/java/etr/android/reamp/mvp/Action.java +++ b/reamplib/src/main/java/etr/android/reamp/mvp/Action.java @@ -1,7 +1,11 @@ package etr.android.reamp.mvp; +import androidx.annotation.NonNull; + import java.io.Serializable; +import etr.android.reamp.functional.ConsumerNonNull; + /** * A handy container-class which can be used to store "one-shot" data into {@link ReampStateModel} *
@@ -16,11 +20,16 @@ public class Action implements Serializable { private T value; private boolean hasAction; - public void set(T value) { + public void set(@NonNull T value) { this.value = value; hasAction = true; } + /** + * @deprecated use {@link Action#consume(ConsumerNonNull)}. + */ + @Deprecated + @NonNull public T get() { if (!hasAction) { throw new IllegalStateException("No action yet"); @@ -31,7 +40,17 @@ public T get() { return result; } + /** + * @deprecated use {@link Action#consume(ConsumerNonNull)}. + */ + @Deprecated public boolean hasAction() { return hasAction; } + + public void consume(@NonNull ConsumerNonNull consumer) { + if (hasAction()) { + consumer.consume(get()); + } + } } diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/Consumable.java b/reamplib/src/main/java/etr/android/reamp/mvp/Consumable.java deleted file mode 100644 index 7a61eb8..0000000 --- a/reamplib/src/main/java/etr/android/reamp/mvp/Consumable.java +++ /dev/null @@ -1,28 +0,0 @@ -package etr.android.reamp.mvp; - -import java.io.Serializable; - -/** - * @deprecated Use {@link Action} - */ -@Deprecated -public class Consumable implements Serializable { - - private final T defaultValue; - private T value; - - public Consumable(T value) { - this.value = value; - this.defaultValue = value; - } - - public void set(T value) { - this.value = value; - } - - public T get() { - T result = value; - value = defaultValue; - return result; - } -} diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/EmptyAction.java b/reamplib/src/main/java/etr/android/reamp/mvp/EmptyAction.java new file mode 100644 index 0000000..a3f49c9 --- /dev/null +++ b/reamplib/src/main/java/etr/android/reamp/mvp/EmptyAction.java @@ -0,0 +1,21 @@ +package etr.android.reamp.mvp; + +import androidx.annotation.NonNull; + +import java.io.Serializable; + +public class EmptyAction implements Serializable { + + private boolean hasAction; + + public void set() { + hasAction = true; + } + + public void consume(@NonNull Runnable consumer) { + if (hasAction) { + hasAction = false; + consumer.run(); + } + } +} diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/MvpDelegate.java b/reamplib/src/main/java/etr/android/reamp/mvp/MvpDelegate.java index bc29bc1..6924975 100644 --- a/reamplib/src/main/java/etr/android/reamp/mvp/MvpDelegate.java +++ b/reamplib/src/main/java/etr/android/reamp/mvp/MvpDelegate.java @@ -3,10 +3,15 @@ import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; +import android.util.Log; import java.util.List; import java.util.UUID; +import etr.android.reamp.navigation.ResultProvider; + /** * A proxy class between {@link ReampView} and {@link ReampPresenter} which should be used * while implementing a custom {@link ReampView}. @@ -21,12 +26,16 @@ public class MvpDelegate { private String mvpId; private ReampPresenter presenter; private StateChanges stateChanges; + private boolean isDestroyed = false; public MvpDelegate(ReampView view) { this.view = view; } public

, SM extends ReampStateModel> P getPresenter() { + if (isDestroyed) { + Log.e(TAG, "MvpDelegate#getPresenter was called after onDestroy.", new IllegalStateException()); + } return (P) presenter; } @@ -107,7 +116,8 @@ public void onSaveInstanceState(Bundle outState) { public void onDestroy() { ReampPresenter presenter = view.getPresenter(); presenter.removeView(view); - this.presenter = null; + isDestroyed = true; + // Don't set presenter to null, because there are a lot of crashes, when view calls getPresenter() after onDestroy. } /** @@ -119,11 +129,19 @@ public void onResult(int requestCode, int resultCode, Intent data) { } } + @RestrictTo(RestrictTo.Scope.TESTS) + public void onResult(@NonNull ResultProvider resultProvider) { + view.getPresenter().onResult(resultProvider); + } + private void dispatchResult(int requestCode, int resultCode, Intent data) { List views = PresenterManager.getInstance().getViewsOf(view.getContext()); for (ReampView reampView : views) { ReampPresenter presenter = reampView.getPresenter(); if (presenter != null) { + presenter.onResult(new ResultProvider.Android(view.getPresenter().getNavigation(), requestCode, resultCode, data)); + + // Call it for backward compatibility. presenter.onResult(requestCode, resultCode, data); } } diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/ReampAppCompatActivity.java b/reamplib/src/main/java/etr/android/reamp/mvp/ReampAppCompatActivity.java index 18a9d27..c190936 100644 --- a/reamplib/src/main/java/etr/android/reamp/mvp/ReampAppCompatActivity.java +++ b/reamplib/src/main/java/etr/android/reamp/mvp/ReampAppCompatActivity.java @@ -3,8 +3,8 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import etr.android.reamp.R; diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/ReampFragment.java b/reamplib/src/main/java/etr/android/reamp/mvp/ReampFragment.java index 35a38ec..bcf7e4d 100644 --- a/reamplib/src/main/java/etr/android/reamp/mvp/ReampFragment.java +++ b/reamplib/src/main/java/etr/android/reamp/mvp/ReampFragment.java @@ -2,9 +2,9 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.app.AlertDialog; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.appcompat.app.AlertDialog; import android.util.Log; import etr.android.reamp.R; diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/ReampPresenter.java b/reamplib/src/main/java/etr/android/reamp/mvp/ReampPresenter.java index 3511e0a..8f4c896 100644 --- a/reamplib/src/main/java/etr/android/reamp/mvp/ReampPresenter.java +++ b/reamplib/src/main/java/etr/android/reamp/mvp/ReampPresenter.java @@ -2,9 +2,8 @@ import android.content.Intent; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; import android.util.Log; import java.io.ByteArrayInputStream; @@ -19,17 +18,19 @@ import java.util.List; import etr.android.reamp.BuildConfig; +import etr.android.reamp.functional.ConsumerNonNull; import etr.android.reamp.navigation.Navigation; +import etr.android.reamp.navigation.ResultProvider; public class ReampPresenter { private static final String TAG = "ReampPresenter"; private static final String EXTRA_INSTANCE_STATE = "EXTRA_INSTANCE_STATE"; - private final Handler uiHandler = new Handler(Looper.getMainLooper()); private SM stateModel; private List views = new ArrayList<>(); private List stateChanges = new ArrayList<>(); + private final SendStateModelExecutor sendStateModelExecutor = createSendStateModelExecutor(); private boolean throwOnSerializationError = BuildConfig.DEBUG; public void attachStateModel(SM stateModel) { @@ -43,6 +44,10 @@ public SM getStateModel() { return stateModel; } + protected SendStateModelExecutor createSendStateModelExecutor() { + return SendStateModelExecutor.createDefault(); + } + /** * Send a state model to a view and save it as a current. * If the view is attached, {@link ReampView#onStateChanged(ReampStateModel)} is called. @@ -50,22 +55,19 @@ public SM getStateModel() { */ public final void sendStateModel(final SM stateModel) { this.stateModel = stateModel; - if (Looper.myLooper() != Looper.getMainLooper()) { - uiHandler.post(new Runnable() { - @Override - public void run() { - sendStateModel(stateModel); - } - }); - } else { - for (StateChanges stateChange : stateChanges) { - try { - stateChange.onNewState(stateModel); - } catch (Throwable e) { - stateChange.onError(e); + + sendStateModelExecutor.execute(new Runnable() { + @Override + public void run() { + for (StateChanges stateChange : stateChanges) { + try { + stateChange.onNewState(stateModel); + } catch (Throwable e) { + stateChange.onError(e); + } } } - } + }); } /** @@ -94,6 +96,11 @@ public void onPresenterCreated() { } + /** + * @deprecated if you need Context in Presenter, + * move Context related logic to long-living object in data-layer and use only application's context. + */ + @Deprecated public ReampView getView() { if (views.isEmpty()) { return null; @@ -101,6 +108,7 @@ public ReampView getView() { return views.get(0); } + @Deprecated public List getViews() { return new ArrayList<>(views); } @@ -169,9 +177,20 @@ private Serializable fromByteArray(byte[] bytes) throws IOException, ClassNotFou /** * Callback from an activity or a fragment when they receive a result intent * Do not use this callback in a fragment's presenters if the host activity is not an ReampView + * @deprecated use {@link ReampPresenter#onResult(ResultProvider)}. */ + @Deprecated + @CallSuper public void onResult(int requestCode, int resultCode, Intent data) { + } + /** + * Convenient receiving result: + * - Useful in Unit-tests without Android dependencies. + * - Useful in application code - no extra params like "requestCode, resultCode, data" + */ + public void onResult(@NonNull ResultProvider resultProvider) { + // nothing by default. } /** @@ -183,6 +202,7 @@ public void onDestroyPresenter() { /** * Called when the first view has been connected + * * @see ReampPresenter#onConnect(ReampView) * @see ReampPresenter#onDisconnect(ReampView) () * @see ReampPresenter#onDisconnect() @@ -206,6 +226,7 @@ public void onConnect(ReampView view) { /** * Called when the last view has been disconnected + * * @see ReampPresenter#onConnect(ReampView) * @see ReampPresenter#onDisconnect(ReampView) () * @see ReampPresenter#onDisconnect() @@ -227,8 +248,16 @@ public void onDisconnect(ReampView view) { } + public boolean isNavigationAvailable() { + return !views.isEmpty(); + } + public Navigation getNavigation() { - return new Navigation(getView()); + if (views.isEmpty()) { + Log.e(TAG, "ReampPresenter#getNavigation was called when no views were added.", new IllegalStateException()); + return null; + } + return new Navigation(views.get(0)); } public void connect(StateChanges stateChanges, ReampView reampView) { @@ -263,6 +292,11 @@ public void setThrowOnSerializationError(boolean throwOnSerializationError) { public void releaseAllViews() { views.clear(); stateChanges.clear(); - uiHandler.removeCallbacks(null); + sendStateModelExecutor.cancelAll(); + } + + protected final void updateStateModel(@NonNull ConsumerNonNull updater) { + updater.consume(getStateModel()); + sendStateModel(); } } diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/ReampProvider.java b/reamplib/src/main/java/etr/android/reamp/mvp/ReampProvider.java index 9a70830..9f7a933 100644 --- a/reamplib/src/main/java/etr/android/reamp/mvp/ReampProvider.java +++ b/reamplib/src/main/java/etr/android/reamp/mvp/ReampProvider.java @@ -5,8 +5,8 @@ import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public class ReampProvider extends ContentProvider { diff --git a/reamplib/src/main/java/etr/android/reamp/mvp/SendStateModelExecutor.java b/reamplib/src/main/java/etr/android/reamp/mvp/SendStateModelExecutor.java new file mode 100644 index 0000000..32a292b --- /dev/null +++ b/reamplib/src/main/java/etr/android/reamp/mvp/SendStateModelExecutor.java @@ -0,0 +1,50 @@ +package etr.android.reamp.mvp; + +import android.annotation.SuppressLint; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import androidx.annotation.NonNull; + +public abstract class SendStateModelExecutor { + public abstract void execute(@NonNull Runnable sendStateModel); + + public abstract void cancelAll(); + + @SuppressLint("ObsoleteSdkInt") + public static SendStateModelExecutor createDefault() { + return Build.VERSION.SDK_INT > 0 // SDK_INT == 0 in unit tests. + ? new UiThread() + : new Unconfined(); + } + + public static final class UiThread extends SendStateModelExecutor { + private final Handler uiHandler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(@NonNull Runnable sendStateModel) { + if (Looper.myLooper() != Looper.getMainLooper()) { + uiHandler.post(sendStateModel); + } else { + sendStateModel.run(); + } + } + + @Override + public void cancelAll() { + uiHandler.removeCallbacks(null); + } + } + + public static final class Unconfined extends SendStateModelExecutor { + @Override + public void execute(@NonNull Runnable sendStateModel) { + sendStateModel.run(); + } + + @Override + public void cancelAll() { + // nothing. + } + } +} \ No newline at end of file diff --git a/reamplib/src/main/java/etr/android/reamp/navigation/ResultProvider.java b/reamplib/src/main/java/etr/android/reamp/navigation/ResultProvider.java new file mode 100644 index 0000000..2d3a0f6 --- /dev/null +++ b/reamplib/src/main/java/etr/android/reamp/navigation/ResultProvider.java @@ -0,0 +1,43 @@ +package etr.android.reamp.navigation; + +import android.content.Intent; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import etr.android.reamp.functional.ConsumerNonNull; + +public abstract class ResultProvider { + @Nullable + abstract public R getResult(@NonNull ComplexNavigationUnit navigationUnit); + + public void consumeResult( + @NonNull ComplexNavigationUnit navigationUnit, + @NonNull ConsumerNonNull consumer + ) { + final R result = getResult(navigationUnit); + if (result != null) { + consumer.consume(result); + } + } + + public static final class Android extends ResultProvider { + @NonNull + private final Navigation navigation; + private final int requestCode; + private final int resultCode; + private final Intent data; + + public Android(@NonNull Navigation navigation, int requestCode, int resultCode, Intent data) { + this.navigation = navigation; + this.requestCode = requestCode; + this.resultCode = resultCode; + this.data = data; + } + + @Override + @Nullable + public R getResult(@NonNull ComplexNavigationUnit navigationUnit) { + return navigation.getResult(navigationUnit, requestCode, resultCode, data); + } + } +} \ No newline at end of file diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/ActionTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/ActionTest.java index bca31c1..4a42cec 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/ActionTest.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/ActionTest.java @@ -1,8 +1,12 @@ package etr.android.reamp.mvp; +import androidx.annotation.NonNull; + import org.junit.Assert; import org.junit.Test; +import etr.android.reamp.functional.ConsumerNonNull; + public class ActionTest extends BaseTest { @Test @@ -25,6 +29,30 @@ public void illegalState() throws Exception { } } + public void consume() { + Action action = new Action<>(); + + final String[] strings = new String[]{null}; + + action.set("test"); + action.consume(new ConsumerNonNull() { + @Override + public void consume(@NonNull String s) { + strings[0] = s; + } + }); + Assert.assertEquals("test", strings[0]); + + strings[0] = null; + action.consume(new ConsumerNonNull() { + @Override + public void consume(@NonNull String s) { + strings[0] = s; + } + }); + Assert.assertNull(strings[0]); + } + @Test public void serialization() throws Exception { Action action = new Action<>(); diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/BaseTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/BaseTest.java index 88034ba..683d47c 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/BaseTest.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/BaseTest.java @@ -1,13 +1,13 @@ package etr.android.reamp.mvp; +import android.os.Build; + import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import etr.android.reamp.BuildConfig; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class) +@Config(sdk = Build.VERSION_CODES.P) public abstract class BaseTest { } diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/ConsumableTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/ConsumableTest.java deleted file mode 100644 index d02d5ca..0000000 --- a/reamplib/src/test/java/etr/android/reamp/mvp/ConsumableTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package etr.android.reamp.mvp; - -import org.junit.Assert; -import org.junit.Test; - -public class ConsumableTest extends BaseTest { - - @Test - public void basics() throws Exception { - Consumable consumable = new Consumable<>(null); - Assert.assertEquals(consumable.get(), null); - consumable.set("test"); - Assert.assertEquals(consumable.get(), "test"); - Assert.assertEquals(consumable.get(), null); - } -} \ No newline at end of file diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/EmptyActionTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/EmptyActionTest.java new file mode 100644 index 0000000..86391e6 --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/EmptyActionTest.java @@ -0,0 +1,38 @@ +package etr.android.reamp.mvp; + +import org.junit.Assert; +import org.junit.Test; + +public class EmptyActionTest { + @Test + public void test() { + EmptyAction emptyAction = new EmptyAction(); + + final boolean[] b = {false}; + emptyAction.consume(new Runnable() { + @Override + public void run() { + b[0] = true; + } + }); + Assert.assertFalse(b[0]); + + emptyAction.set(); + emptyAction.consume(new Runnable() { + @Override + public void run() { + b[0] = true; + } + }); + Assert.assertTrue(b[0]); + + b[0] = false; + emptyAction.consume(new Runnable() { + @Override + public void run() { + b[0] = true; + } + }); + Assert.assertFalse(b[0]); + } +} diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/ActivityTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/ActivityTest.java index f9b1192..4b56100 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/ActivityTest.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/ActivityTest.java @@ -135,7 +135,6 @@ public void activityLeak() throws Exception { controller.create().start().resume().visible(); TesteePresenter presenter = testMvpActivity.getPresenter(); controller.pause().stop().destroy(); - Assert.assertNull(testMvpActivity.getPresenter()); Assert.assertNull(presenter.getView()); List reampViews = PresenterManager.getInstance().getViewsOf(testMvpActivity); Assert.assertTrue(reampViews.isEmpty()); diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/NavigationTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/NavigationTest.java index 7614dce..d4e732a 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/NavigationTest.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/NavigationTest.java @@ -2,7 +2,7 @@ import android.app.Activity; import android.content.Intent; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.junit.Assert; import org.junit.Test; @@ -13,7 +13,6 @@ import etr.android.reamp.R; import etr.android.reamp.mvp.BaseTest; -import etr.android.reamp.mvp.internal.RegularFragment; import etr.android.reamp.mvp.internal.SimpleView; import etr.android.reamp.mvp.internal.navigation.FirstActivity; import etr.android.reamp.mvp.internal.navigation.NavFragment; diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/PresenterLeaksTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/PresenterLeaksTest.java index cc92b39..439dc7d 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/PresenterLeaksTest.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/PresenterLeaksTest.java @@ -39,10 +39,20 @@ public void checkPhantoms() throws Exception { EmptyAppCompatActivity activity = controller.setup().get(); for (int i = 0; i < 3; i++) { + /* + todo + Раньше, когда targetSdkVersion был 25, фрагменты добавлялись в бек-стек, + и тест проходил проверку "only the last fragment has attached". + После миграции на AndroidX и поднятия targetSdkVersion до 29 тест стал падать в этом месте. + В результате убрали добавление фрагментов в бек-стек и все заработало. + Почему оно работало раньше -- не понятно. Так как: + - в MvpDelegate.onCreate вызывается presenterManager.registerView(view, view.getContext()); + - и если положить фрагменты в бек стек, то после поворота активити у фрагментов будет вызван onCreate и все 3 фрагмента вызовут registerView. + - у фрагментов в бек-стеке точно вызываются onCreate после поворота активити. + */ activity.getSupportFragmentManager() .beginTransaction() .replace(R.id.root, new TestReampFragment()) - .addToBackStack("bs") .commit(); } diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/StandAloneViewTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/StandAloneViewTest.java index 38bca00..8a450ef 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/StandAloneViewTest.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/StandAloneViewTest.java @@ -88,7 +88,6 @@ public void viewLeak() throws Exception { TestReampCustomView view = activity.getCustomView(); TesteePresenter presenter = view.getPresenter(); activity.removeView(); - Assert.assertNull(view.getPresenter()); Assert.assertNull(presenter.getView()); } } diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/SupportFragmentTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/SupportFragmentTest.java index 91265e4..6da2b7e 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/SupportFragmentTest.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/integrationtests/SupportFragmentTest.java @@ -109,7 +109,6 @@ public void fragmentLeak() throws Exception { TestReampFragment fragment = activity.getEmbeddedFragment(); TesteePresenter presenter = fragment.getPresenter(); controller.pause().stop().destroy(); - Assert.assertNull(fragment.getPresenter()); Assert.assertNull(presenter.getView()); } diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/internal/EmptyAppCompatActivity.java b/reamplib/src/test/java/etr/android/reamp/mvp/internal/EmptyAppCompatActivity.java index 448c04c..e555d96 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/internal/EmptyAppCompatActivity.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/internal/EmptyAppCompatActivity.java @@ -1,8 +1,8 @@ package etr.android.reamp.mvp.internal; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import etr.android.reamp.R; diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularAppCompatActivity.java b/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularAppCompatActivity.java index 0123522..f3b0441 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularAppCompatActivity.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularAppCompatActivity.java @@ -1,8 +1,8 @@ package etr.android.reamp.mvp.internal; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import android.view.ViewGroup; import etr.android.reamp.R; diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularFragment.java b/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularFragment.java index b39e0e1..f08dff7 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularFragment.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/internal/RegularFragment.java @@ -1,8 +1,8 @@ package etr.android.reamp.mvp.internal; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampCustomView.java b/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampCustomView.java index 143fdc9..1efcc0d 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampCustomView.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampCustomView.java @@ -4,7 +4,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.view.View; diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampFragment.java b/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampFragment.java index c37f654..6a07cf7 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampFragment.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/internal/TestReampFragment.java @@ -1,7 +1,7 @@ package etr.android.reamp.mvp.internal; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/internal/navigation/NavFragment.java b/reamplib/src/test/java/etr/android/reamp/mvp/internal/navigation/NavFragment.java index 95f0fce..0fc9012 100644 --- a/reamplib/src/test/java/etr/android/reamp/mvp/internal/navigation/NavFragment.java +++ b/reamplib/src/test/java/etr/android/reamp/mvp/internal/navigation/NavFragment.java @@ -1,7 +1,7 @@ package etr.android.reamp.mvp.internal.navigation; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OneModel.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OneModel.java new file mode 100644 index 0000000..5fd34c0 --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OneModel.java @@ -0,0 +1,13 @@ +package etr.android.reamp.mvp.screen_one; + +import etr.android.reamp.mvp.Action; +import etr.android.reamp.mvp.EmptyAction; +import etr.android.reamp.mvp.SerializableStateModel; + +class OneModel extends SerializableStateModel { + int counter = 0; + + final Action action = new Action<>(); + + final EmptyAction emptyAction = new EmptyAction(); +} diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OneNavigationUnit.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OneNavigationUnit.java new file mode 100644 index 0000000..e8d2d27 --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OneNavigationUnit.java @@ -0,0 +1,36 @@ +package etr.android.reamp.mvp.screen_one; + +import java.util.Objects; + +import etr.android.reamp.navigation.ComplexNavigationUnit; +import etr.android.reamp.navigation.Navigation; + +public class OneNavigationUnit extends ComplexNavigationUnit { + private final Integer i; + + public OneNavigationUnit() { + this.i = null; + } + + public OneNavigationUnit(int i) { + this.i = i; + } + + @Override + protected void navigate(Navigation navigation) { + + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OneNavigationUnit that = (OneNavigationUnit) o; + return Objects.equals(i, that.i); + } + + @Override + public int hashCode() { + return Objects.hash(i); + } +} diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OnePresenter.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OnePresenter.java new file mode 100644 index 0000000..8409b24 --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OnePresenter.java @@ -0,0 +1,58 @@ +package etr.android.reamp.mvp.screen_one; + +import androidx.annotation.NonNull; + +import etr.android.reamp.functional.ConsumerNonNull; +import etr.android.reamp.mvp.ReampPresenter; +import etr.android.reamp.mvp.screen_two.TwoNavigationUnit; +import etr.android.reamp.navigation.ResultProvider; + +class OnePresenter extends ReampPresenter { + + @Override + public void onPresenterCreated() { + super.onPresenterCreated(); + + getStateModel().counter = getNavigation().getData(new OneNavigationUnit()); + sendStateModel(); + } + + void onIncrement() { + updateStateModel(new ConsumerNonNull() { + @Override + public void consume(@NonNull OneModel oneModel) { + oneModel.counter++; + } + }); + } + + void onDecrement() { + getStateModel().counter--; + sendStateModel(); + } + + void onOpenScreenTwo() { + getNavigation().open(new TwoNavigationUnit(getStateModel().counter)); + } + + void onShow() { + getStateModel().action.set(getStateModel().counter); + sendStateModel(); + } + + void onShowEmpty() { + getStateModel().emptyAction.set(); + sendStateModel(); + } + + @Override + public void onResult(@NonNull ResultProvider resultProvider) { + resultProvider.consumeResult(new TwoNavigationUnit(), new ConsumerNonNull() { + @Override + public void consume(@NonNull Integer result) { + getStateModel().counter = result; + sendStateModel(); + } + }); + } +} diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OnePresenterTest.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OnePresenterTest.java new file mode 100644 index 0000000..578b2c7 --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/OnePresenterTest.java @@ -0,0 +1,60 @@ +package etr.android.reamp.mvp.screen_one; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import etr.android.reamp.mvp.MvpDelegate; +import etr.android.reamp.mvp.screen_two.TwoNavigationUnit; +import etr.android.reamp.navigation.Navigation; + +public class OnePresenterTest { + @Test + public void test() { + final Navigation navigation = Mockito.mock(Navigation.class); + Mockito.when(navigation.getData(new OneNavigationUnit())).thenReturn(10); + + OnePresenter onePresenter = new OnePresenter() { + @Override + public Navigation getNavigation() { + return navigation; + } + }; + + TestReampView view = new TestReampView<>(onePresenter, new OneModel()); + MvpDelegate mvpDelegate = new MvpDelegate(view); + mvpDelegate.onCreate(null); + mvpDelegate.connect(); + + Mockito.verify(navigation).getData(new OneNavigationUnit()); + Assert.assertEquals(10, view.sm.counter); + Util.assertNoValue(view.sm.action); + Util.assertAndConsume(view.sm.emptyAction, false); + + onePresenter.onIncrement(); + Assert.assertEquals(11, onePresenter.getStateModel().counter); + + onePresenter.onShow(); + Util.assertHasValue(view.sm.action, 11); + + onePresenter.onShowEmpty(); + Util.assertAndConsume(view.sm.emptyAction, true); + + onePresenter.onIncrement(); + Assert.assertEquals(12, onePresenter.getStateModel().counter); + + onePresenter.onDecrement(); + Assert.assertEquals(11, onePresenter.getStateModel().counter); + + onePresenter.onOpenScreenTwo(); + Mockito.verify(navigation).open(new TwoNavigationUnit(11)); + + mvpDelegate.onResult(new TestResultProvider<>(TwoNavigationUnit.class, 14)); + Assert.assertEquals(14, onePresenter.getStateModel().counter); + + onePresenter.onShow(); + Util.assertHasValue(view.sm.action, 14); + + Mockito.verifyNoMoreInteractions(navigation); + } +} diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/TestReampView.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/TestReampView.java new file mode 100644 index 0000000..b1213b6 --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/TestReampView.java @@ -0,0 +1,57 @@ +package etr.android.reamp.mvp.screen_one; + +import android.content.Context; +import androidx.annotation.NonNull; + +import etr.android.reamp.mvp.ReampPresenter; +import etr.android.reamp.mvp.ReampStateModel; +import etr.android.reamp.mvp.ReampView; + +public class TestReampView

, SM extends ReampStateModel> implements ReampView { + + private final P presenter; + private final SM stateModel; + + public SM sm; + public Throwable error; + + public TestReampView(@NonNull P presenter, @NonNull SM stateModel) { + this.presenter = presenter; + this.stateModel = stateModel; + } + + @Override + public Context getContext() { + return null; + } + + @Override + public void onStateChanged(SM stateModel) { + sm = stateModel; + } + + @Override + public void onError(Throwable throwable) { + error = throwable; + } + + @Override + public String getMvpId() { + return null; + } + + @Override + public SM onCreateStateModel() { + return stateModel; + } + + @Override + public P onCreatePresenter() { + return presenter; + } + + @Override + public P getPresenter() { + return presenter; + } +} diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/TestResultProvider.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/TestResultProvider.java new file mode 100644 index 0000000..93ca01e --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/TestResultProvider.java @@ -0,0 +1,27 @@ +package etr.android.reamp.mvp.screen_one; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import etr.android.reamp.navigation.ComplexNavigationUnit; +import etr.android.reamp.navigation.ResultProvider; + +public final class TestResultProvider extends ResultProvider { + private final Class> nClass; + private final R result; + + public TestResultProvider(Class> nClass, R result) { + this.nClass = nClass; + this.result = result; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public R2 getResult(@NonNull ComplexNavigationUnit navigationUnit) { + if (navigationUnit.getClass() == nClass) { + return (R2) result; + } + return null; + } +} \ No newline at end of file diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/Util.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/Util.java new file mode 100644 index 0000000..bae93cc --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_one/Util.java @@ -0,0 +1,47 @@ +package etr.android.reamp.mvp.screen_one; + +import androidx.annotation.NonNull; + +import junit.framework.Assert; + +import java.io.Serializable; + +import etr.android.reamp.functional.ConsumerNonNull; +import etr.android.reamp.mvp.Action; +import etr.android.reamp.mvp.EmptyAction; + +class Util { + static void assertAndConsume(@NonNull EmptyAction emptyAction, boolean expectedHasAction) { + final boolean[] actualHasAction = {false}; + emptyAction.consume(new Runnable() { + @Override + public void run() { + actualHasAction[0] = true; + } + }); + Assert.assertEquals(expectedHasAction, actualHasAction[0]); + } + + static void assertHasValue(@NonNull final Action action, @NonNull T expected) { + final Serializable[] actual = new Serializable[]{null}; + action.consume(new ConsumerNonNull() { + @Override + public void consume(@NonNull T t) { + Assert.assertNotNull(t); + actual[0] = t; + } + }); + Assert.assertEquals(expected, actual[0]); + } + + static void assertNoValue(@NonNull final Action action) { + final boolean[] hasValue = new boolean[]{false}; + action.consume(new ConsumerNonNull() { + @Override + public void consume(@NonNull T t) { + hasValue[0] = true; + } + }); + Assert.assertFalse(hasValue[0]); + } +} diff --git a/reamplib/src/test/java/etr/android/reamp/mvp/screen_two/TwoNavigationUnit.java b/reamplib/src/test/java/etr/android/reamp/mvp/screen_two/TwoNavigationUnit.java new file mode 100644 index 0000000..70502f2 --- /dev/null +++ b/reamplib/src/test/java/etr/android/reamp/mvp/screen_two/TwoNavigationUnit.java @@ -0,0 +1,37 @@ +package etr.android.reamp.mvp.screen_two; + +import java.util.Objects; + +import etr.android.reamp.navigation.Navigation; +import etr.android.reamp.navigation.NavigationUnit; + +public class TwoNavigationUnit extends NavigationUnit { + + private final Integer i; + + public TwoNavigationUnit() { + this.i = null; + } + + public TwoNavigationUnit(int i) { + this.i = i; + } + + @Override + protected void navigate(Navigation navigation) { + + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TwoNavigationUnit that = (TwoNavigationUnit) o; + return Objects.equals(i, that.i); + } + + @Override + public int hashCode() { + return Objects.hash(i); + } +} diff --git a/rxstatemodel/build.gradle b/rxstatemodel/build.gradle index 5166145..9219b20 100644 --- a/rxstatemodel/build.gradle +++ b/rxstatemodel/build.gradle @@ -7,16 +7,16 @@ repositories { } android { - compileSdkVersion 25 - buildToolsVersion "25.0.3" + compileSdkVersion 29 + buildToolsVersion '29.0.3' defaultConfig { - minSdkVersion 15 - targetSdkVersion 25 + minSdkVersion 19 + targetSdkVersion 29 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -28,9 +28,9 @@ android { } dependencies { - compile project(':reamp') - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - compile 'io.reactivex:rxandroid:1.1.0' - compile 'io.reactivex:rxjava:1.1.0' + implementation project(':reamp') + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.12' + implementation 'io.reactivex:rxandroid:1.2.1' + implementation 'io.reactivex:rxjava:1.3.0' } diff --git a/sample/build.gradle b/sample/build.gradle index 5caa295..3c3cc8e 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion '25.0.3' + compileSdkVersion 29 + buildToolsVersion '29.0.3' defaultConfig { applicationId "example.reamp" - minSdkVersion 15 - targetSdkVersion 25 + minSdkVersion 19 + targetSdkVersion 29 versionCode 1 versionName "1.0" } @@ -23,14 +23,12 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - testCompile "org.robolectric:robolectric:3.3.2" - testCompile "org.robolectric:shadows-support-v4:3.3.2" - compile project(':reamp') - compile project(':rxstatemodel') - compile 'com.android.support:appcompat-v7:25.3.1' - compile 'com.android.support:support-v4:25.3.1' - compile 'io.reactivex:rxandroid:1.1.0' - compile 'io.reactivex:rxjava:1.1.0' + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.12' + testImplementation "org.robolectric:robolectric:4.3.1" + implementation project(':reamp') + implementation project(':rxstatemodel') + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'io.reactivex:rxandroid:1.2.1' + implementation 'io.reactivex:rxjava:1.3.0' } diff --git a/sample/src/main/java/example/reamp/WelcomeActivity.java b/sample/src/main/java/example/reamp/WelcomeActivity.java index 2929bbf..c09a51e 100644 --- a/sample/src/main/java/example/reamp/WelcomeActivity.java +++ b/sample/src/main/java/example/reamp/WelcomeActivity.java @@ -2,8 +2,8 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import example.reamp.basic.BasicActivity; diff --git a/sample/src/main/java/example/reamp/basic/BasicFragment.java b/sample/src/main/java/example/reamp/basic/BasicFragment.java index d33a2ea..912f784 100644 --- a/sample/src/main/java/example/reamp/basic/BasicFragment.java +++ b/sample/src/main/java/example/reamp/basic/BasicFragment.java @@ -1,7 +1,7 @@ package example.reamp.basic; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/sample/src/main/java/example/reamp/basic/BasicFragmentActivity.java b/sample/src/main/java/example/reamp/basic/BasicFragmentActivity.java index 0158c3e..3e5ca98 100644 --- a/sample/src/main/java/example/reamp/basic/BasicFragmentActivity.java +++ b/sample/src/main/java/example/reamp/basic/BasicFragmentActivity.java @@ -1,8 +1,8 @@ package example.reamp.basic; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; import example.reamp.R; diff --git a/sample/src/main/java/example/reamp/lifecycle/LongRunningFragment.java b/sample/src/main/java/example/reamp/lifecycle/LongRunningFragment.java index c5041fe..3b9b788 100644 --- a/sample/src/main/java/example/reamp/lifecycle/LongRunningFragment.java +++ b/sample/src/main/java/example/reamp/lifecycle/LongRunningFragment.java @@ -2,7 +2,7 @@ import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/sample/src/main/java/example/reamp/login/LoginActivity.java b/sample/src/main/java/example/reamp/login/LoginActivity.java index 2f3b148..4760a8f 100644 --- a/sample/src/main/java/example/reamp/login/LoginActivity.java +++ b/sample/src/main/java/example/reamp/login/LoginActivity.java @@ -1,12 +1,14 @@ package example.reamp.login; import android.os.Bundle; -import android.support.v7.app.AlertDialog; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import android.text.Editable; import android.text.TextWatcher; import android.view.View; import android.widget.EditText; +import etr.android.reamp.functional.ConsumerNonNull; import etr.android.reamp.mvp.ReampAppCompatActivity; import etr.android.reamp.mvp.ReampPresenter; import example.reamp.R; @@ -70,9 +72,13 @@ public void onStateChanged(LoginState stateModel) { loginActionView.setEnabled(stateModel.isLoginActionEnabled()); successView.setVisibility(stateModel.showSuccessLogin() ? View.VISIBLE : View.GONE); errorView.setVisibility(stateModel.showFailedLogin() ? View.VISIBLE : View.GONE); - if (stateModel.errorAction().hasAction()) { - showError(stateModel.errorAction().get()); - } + + stateModel.errorAction().consume(new ConsumerNonNull() { + @Override + public void consume(@NonNull String s) { + showError(s); + } + }); } private void showError(String message) { diff --git a/sample/src/main/java/example/reamp/navigation/NavigationFragmentPresenter.java b/sample/src/main/java/example/reamp/navigation/NavigationFragmentPresenter.java index dd24023..a52edff 100644 --- a/sample/src/main/java/example/reamp/navigation/NavigationFragmentPresenter.java +++ b/sample/src/main/java/example/reamp/navigation/NavigationFragmentPresenter.java @@ -1,8 +1,10 @@ package example.reamp.navigation; -import android.content.Intent; +import androidx.annotation.NonNull; +import etr.android.reamp.functional.ConsumerNonNull; import etr.android.reamp.mvp.ReampPresenter; +import etr.android.reamp.navigation.ResultProvider; import example.reamp.navigation.details.DetailsWithData; import example.reamp.navigation.details.DetailsWithResultUnit; @@ -19,10 +21,16 @@ public void openForResult() { } @Override - public void onResult(int requestCode, int resultCode, Intent data) { - super.onResult(requestCode, resultCode, data); - getStateModel().resultText = getNavigation().getResult(new DetailsWithResultUnit(), requestCode, resultCode, data); - sendStateModel(); + public void onResult(@NonNull ResultProvider resultProvider) { + super.onResult(resultProvider); + + resultProvider.consumeResult(new DetailsWithResultUnit(), new ConsumerNonNull() { + @Override + public void consume(@NonNull String s) { + getStateModel().resultText = s; + sendStateModel(); + } + }); } public void openWithData() { diff --git a/sample/src/main/java/example/reamp/navigation/details/DetailsFragment.java b/sample/src/main/java/example/reamp/navigation/details/DetailsFragment.java index 5b117f4..0d8d3df 100644 --- a/sample/src/main/java/example/reamp/navigation/details/DetailsFragment.java +++ b/sample/src/main/java/example/reamp/navigation/details/DetailsFragment.java @@ -2,7 +2,8 @@ import android.os.Bundle; -import android.support.v7.app.AlertDialog; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; @@ -10,6 +11,7 @@ import android.view.ViewGroup; import android.widget.EditText; +import etr.android.reamp.functional.ConsumerNonNull; import etr.android.reamp.mvp.ReampFragment; import example.reamp.R; @@ -64,9 +66,12 @@ public DetailsFragmentPresenter onCreatePresenter() { @Override public void onStateChanged(DetailsFragmentStateModel stateModel) { editText.setText(stateModel.text); - if (stateModel.showDataAction.hasAction()) { - showAlert(stateModel.showDataAction.get()); - } + stateModel.showDataAction.consume(new ConsumerNonNull() { + @Override + public void consume(@NonNull String s) { + showAlert(s); + } + }); } private void showAlert(String msg) { diff --git a/sample/src/main/java/example/reamp/view/CustomViewActivity.java b/sample/src/main/java/example/reamp/view/CustomViewActivity.java index 1f238e7..225a03e 100644 --- a/sample/src/main/java/example/reamp/view/CustomViewActivity.java +++ b/sample/src/main/java/example/reamp/view/CustomViewActivity.java @@ -1,9 +1,8 @@ package example.reamp.view; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.view.View; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import example.reamp.R; diff --git a/sample/src/main/java/example/reamp/view/MyView.java b/sample/src/main/java/example/reamp/view/MyView.java index aaf7334..5fe1261 100644 --- a/sample/src/main/java/example/reamp/view/MyView.java +++ b/sample/src/main/java/example/reamp/view/MyView.java @@ -7,7 +7,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.View;