Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8488242a26 | |||
| 1fe0187439 | |||
| f78726b916 | |||
| 1f918f10c5 | |||
| bd584727be | |||
| 91db7fe65f | |||
| 2abe2b33f9 | |||
| ac4e09cf67 | |||
| 055532bb21 | |||
| 15037c2217 | |||
| 728f1fb4e9 | |||
| 55c8d64d8a | |||
| 88e0eb882b | |||
| 63a92db540 | |||
| ba98e3b165 | |||
| 966bc1645d | |||
| c8ac58ad6a | |||
| 5f04d9de89 | |||
| d32fc813d0 | |||
| c2bc72c5ce | |||
| 924e4bebfa | |||
| 4ea4aa5c56 | |||
| 3b275d31c2 | |||
| 0e21c8c9c1 | |||
| 8297e0273d | |||
| 46519c2c2c |
+3
-1
@@ -8,7 +8,9 @@
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
*.idea/dictionaries
|
||||
/.idea/*
|
||||
!/.idea/codeStyles/
|
||||
!/.idea/scopes/
|
||||
classes
|
||||
gen-external-apklibs
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[](https://travis-ci.com/bluelinelabs/Conductor) [](http://android-arsenal.com/details/1/3361) [](http://javadoc.io/doc/com.bluelinelabs/conductor)
|
||||
[](https://github.com/bluelinelabs/conductor/actions/workflows/main.yml) [](http://android-arsenal.com/details/1/3361) [](http://javadoc.io/doc/com.bluelinelabs/conductor)
|
||||
|
||||
# Conductor
|
||||
|
||||
@@ -20,27 +20,29 @@ Conductor is architecture-agnostic and does not try to force any design decision
|
||||
## Installation
|
||||
|
||||
```gradle
|
||||
implementation 'com.bluelinelabs:conductor:3.1.1'
|
||||
def conductorVersion = '3.1.9'
|
||||
|
||||
implementation "com.bluelinelabs:conductor:$conductorVersion"
|
||||
|
||||
// AndroidX Transition change handlers:
|
||||
implementation 'com.bluelinelabs:conductor-androidx-transition:3.1.1'
|
||||
implementation "com.bluelinelabs:conductor-androidx-transition:$conductorVersion"
|
||||
|
||||
// ViewPager PagerAdapter:
|
||||
implementation 'com.bluelinelabs:conductor-viewpager:3.1.1'
|
||||
implementation "com.bluelinelabs:conductor-viewpager:$conductorVersion"
|
||||
|
||||
// ViewPager2 Adapter:
|
||||
implementation 'com.bluelinelabs:conductor-viewpager2:3.1.1'
|
||||
implementation "com.bluelinelabs:conductor-viewpager2:$conductorVersion"
|
||||
|
||||
// RxJava2 Autodispose support:
|
||||
implementation 'com.bluelinelabs:conductor-autodispose:3.1.1'
|
||||
implementation "com.bluelinelabs:conductor-autodispose:$conductorVersion"
|
||||
|
||||
// Lifecycle-aware Controllers (architecture components):
|
||||
implementation 'com.bluelinelabs:conductor-archlifecycle:3.1.1'
|
||||
implementation "com.bluelinelabs:conductor-archlifecycle:$conductorVersion"
|
||||
```
|
||||
|
||||
**SNAPSHOT**
|
||||
|
||||
Just use `3.1.2-SNAPSHOT` as your version number in any of the dependencies above and add the url to the snapshot repository:
|
||||
Just use `3.2.0-SNAPSHOT` as your version number in any of the dependencies above and add the url to the snapshot repository:
|
||||
|
||||
```gradle
|
||||
allprojects {
|
||||
@@ -76,7 +78,8 @@ public class MainActivity extends Activity {
|
||||
|
||||
ViewGroup container = (ViewGroup) findViewById(R.id.controller_container);
|
||||
|
||||
router = Conductor.attachRouter(this, container, savedInstanceState);
|
||||
router = Conductor.attachRouter(this, container, savedInstanceState)
|
||||
.setPopRootControllerMode(PopRootControllerMode.NEVER);
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(RouterTransaction.with(new HomeController()));
|
||||
}
|
||||
|
||||
+4
-8
@@ -1,15 +1,13 @@
|
||||
buildscript {
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:$agpVersion"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
classpath "com.vanniktech:gradle-maven-publish-plugin:$mvnPublishVersion"
|
||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion"
|
||||
classpath libs.agp
|
||||
classpath libs.kotlin.plugin
|
||||
classpath libs.mvnpublish
|
||||
classpath libs.dokka
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,5 +17,3 @@ allprojects {
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
configurations {
|
||||
lintChecks
|
||||
libs.lint.checks
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly rootProject.ext.lintapi
|
||||
compileOnly rootProject.ext.lintchecks
|
||||
compileOnly rootProject.ext.kotlinStd
|
||||
compileOnly libs.lint.api
|
||||
compileOnly libs.lint.checks
|
||||
compileOnly libs.kotlin.stdlib
|
||||
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.lint
|
||||
testImplementation rootProject.ext.lintTests
|
||||
testImplementation libs.junit
|
||||
testImplementation libs.lint
|
||||
testImplementation libs.lint.tests
|
||||
}
|
||||
|
||||
jar {
|
||||
@@ -19,5 +19,3 @@ jar {
|
||||
attributes('Lint-Registry-v2': 'com.bluelinelabs.conductor.lint.IssueRegistry')
|
||||
}
|
||||
}
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion libs.versions.compilesdk.get() as Integer
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
minSdkVersion libs.versions.minsdk.get()
|
||||
targetSdkVersion libs.versions.targetsdk.get()
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation rootProject.ext.androidxAppCompat
|
||||
implementation rootProject.ext.androidxCollection
|
||||
api rootProject.ext.androidxTransition
|
||||
implementation libs.androidx.appcompat
|
||||
implementation libs.androidx.collection
|
||||
api libs.androidx.transition
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-androidx-transition'
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion libs.versions.compilesdk.get() as Integer
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
minSdkVersion libs.versions.minsdk.get()
|
||||
targetSdkVersion libs.versions.targetsdk.get()
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api rootProject.ext.archComponentsLifecycle
|
||||
api libs.androidx.lifecycle.runtime
|
||||
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-arch-components-lifecycle'
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
+4
-1
@@ -51,7 +51,10 @@ public class ControllerLifecycleOwner implements LifecycleOwner {
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_DESTROY); // --> State.DESTROYED;
|
||||
// Only act on Controllers that have had at least the onContextAvailable call made on them.
|
||||
if (lifecycleRegistry.getCurrentState() != Lifecycle.State.INITIALIZED) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_DESTROY); // --> State.DESTROYED;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion libs.versions.compilesdk.get() as Integer
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
minSdkVersion libs.versions.minsdk.get()
|
||||
targetSdkVersion libs.versions.targetsdk.get()
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api rootProject.ext.rxJava2
|
||||
api rootProject.ext.autodispose
|
||||
api rootProject.ext.autodisposeLifecycle
|
||||
api libs.rxjava2
|
||||
api libs.autodispose
|
||||
api libs.autodispose.lifecycle
|
||||
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
@@ -2,25 +2,23 @@ apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion libs.versions.compilesdk.get() as Integer
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
minSdkVersion libs.versions.minsdk.get()
|
||||
targetSdkVersion libs.versions.targetsdk.get()
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.robolectric
|
||||
testImplementation libs.junit
|
||||
testImplementation libs.robolectric
|
||||
|
||||
implementation rootProject.ext.androidxAppCompat
|
||||
implementation libs.androidx.appcompat
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
ext.artifactId = 'conductor-viewpager'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
@@ -3,11 +3,11 @@ apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion libs.versions.compilesdk.get() as Integer
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
minSdkVersion libs.versions.minsdk.get()
|
||||
targetSdkVersion libs.versions.targetsdk.get()
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
@@ -20,15 +20,13 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.robolectric
|
||||
testImplementation libs.junit
|
||||
testImplementation libs.robolectric
|
||||
|
||||
implementation rootProject.ext.androidxAppCompat
|
||||
implementation rootProject.ext.androidxViewPager2
|
||||
implementation libs.androidx.appcompat
|
||||
implementation libs.androidx.viewpager2
|
||||
implementation project(':conductor')
|
||||
}
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
ext.artifactId = 'conductor-viewpager2'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ abstract class RouterStateAdapter(private val host: Controller) :
|
||||
|
||||
private fun attachRouter(holder: RouterViewHolder, position: Int) {
|
||||
val itemId = getItemId(position)
|
||||
val router = host.getChildRouter(holder.container, "$itemId")
|
||||
val router = host.getChildRouter(holder.container, "$itemId", true, false)!!
|
||||
|
||||
// This should have already been handled by onViewRecycled, but it seems like this wasn't
|
||||
// always reliably called
|
||||
|
||||
+10
-12
@@ -2,11 +2,11 @@ apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion libs.versions.compilesdk.get() as Integer
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
minSdkVersion libs.versions.minsdk.get()
|
||||
targetSdkVersion libs.versions.targetsdk.get()
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
consumerProguardFiles 'proguard-rules.txt'
|
||||
@@ -14,20 +14,18 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation savedState
|
||||
testImplementation rootProject.ext.junit
|
||||
testImplementation rootProject.ext.robolectric
|
||||
testImplementation kotestAssertions
|
||||
implementation libs.androidx.savedstate.ktx
|
||||
testImplementation libs.junit
|
||||
testImplementation libs.robolectric
|
||||
testImplementation libs.kotest
|
||||
|
||||
implementation archComponentsLifecycle
|
||||
implementation libs.androidx.lifecycle.runtime
|
||||
|
||||
api rootProject.ext.androidxAnnotations
|
||||
api kotlinStd
|
||||
api libs.androidx.annotation
|
||||
api libs.kotlin.stdlib
|
||||
|
||||
lintPublish project(':conductor-lint')
|
||||
}
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
|
||||
ext.artifactId = 'conductor'
|
||||
apply plugin: "com.vanniktech.maven.publish"
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -215,6 +214,23 @@ public abstract class Controller {
|
||||
*/
|
||||
@Nullable
|
||||
public final Router getChildRouter(@NonNull ViewGroup container, @Nullable String tag, boolean createIfNeeded) {
|
||||
return getChildRouter(container, tag, createIfNeeded, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child {@link Router} for the given container/tag combination. Note that multiple
|
||||
* routers should not exist in the same container unless a lot of care is taken to maintain order
|
||||
* between them. Avoid using the same container unless you have a great reason to do so (ex: ViewPagers).
|
||||
* The only time this method will return {@code null} is when the child router does not exist prior
|
||||
* to calling this method and the createIfNeeded parameter is set to false.
|
||||
*
|
||||
* @param container The ViewGroup that hosts the child Router
|
||||
* @param tag The router's tag or {@code null} if none is needed
|
||||
* @param createIfNeeded If true, a router will be created if one does not yet exist. Else {@code null} will be returned in this case.
|
||||
* @param boundToHostContainerId If true, a router will only ever rebind with a container with the same view id on state restoration. Note that this must be set to true if the tag is null.
|
||||
*/
|
||||
@Nullable
|
||||
public final Router getChildRouter(@NonNull ViewGroup container, @Nullable String tag, boolean createIfNeeded, boolean boundToHostContainerId) {
|
||||
@IdRes final int containerId = container.getId();
|
||||
if (containerId == View.NO_ID) {
|
||||
throw new IllegalStateException("You must set an id on your container.");
|
||||
@@ -222,7 +238,7 @@ public abstract class Controller {
|
||||
|
||||
ControllerHostedRouter childRouter = null;
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
if (router.getHostId() == containerId && TextUtils.equals(tag, router.getTag())) {
|
||||
if (router.matches(containerId, tag)) {
|
||||
childRouter = router;
|
||||
break;
|
||||
}
|
||||
@@ -230,7 +246,7 @@ public abstract class Controller {
|
||||
|
||||
if (childRouter == null) {
|
||||
if (createIfNeeded) {
|
||||
childRouter = new ControllerHostedRouter(container.getId(), tag);
|
||||
childRouter = new ControllerHostedRouter(container.getId(), tag, boundToHostContainerId);
|
||||
childRouter.setHostContainer(this, container);
|
||||
childRouters.add(childRouter);
|
||||
|
||||
@@ -693,7 +709,7 @@ public abstract class Controller {
|
||||
public void setRetainViewMode(@NonNull RetainViewMode retainViewMode) {
|
||||
this.retainViewMode = retainViewMode != null ? retainViewMode : RetainViewMode.RELEASE_DETACH;
|
||||
if (this.retainViewMode == RetainViewMode.RELEASE_DETACH && !attached) {
|
||||
removeViewReference();
|
||||
removeViewReference(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,6 +872,27 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
final void onContextUnavailable(@NonNull Context context) {
|
||||
for (Router childRouter : childRouters) {
|
||||
childRouter.onContextUnavailable(context);
|
||||
}
|
||||
|
||||
if (isContextAvailable) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preContextUnavailable(this, context);
|
||||
}
|
||||
|
||||
isContextAvailable = false;
|
||||
onContextUnavailable();
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postContextUnavailable(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void executeWithRouter(@NonNull RouterRequiringFunc listener) {
|
||||
if (router != null) {
|
||||
listener.execute();
|
||||
@@ -908,20 +945,7 @@ public abstract class Controller {
|
||||
destroy(true);
|
||||
}
|
||||
|
||||
if (isContextAvailable) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preContextUnavailable(this, activity);
|
||||
}
|
||||
|
||||
isContextAvailable = false;
|
||||
onContextUnavailable();
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postContextUnavailable(this);
|
||||
}
|
||||
}
|
||||
onContextUnavailable(activity);
|
||||
}
|
||||
|
||||
void attach(@NonNull View view) {
|
||||
@@ -971,7 +995,7 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
void detach(@NonNull View view, boolean forceViewRefRemoval, boolean blockViewRefRemoval) {
|
||||
void detach(View view, boolean forceViewRefRemoval, boolean blockViewRefRemoval) {
|
||||
if (!attachedToUnownedParent) {
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.prepareForHostDetach();
|
||||
@@ -981,34 +1005,41 @@ public abstract class Controller {
|
||||
final boolean removeViewRef = !blockViewRefRemoval && (forceViewRefRemoval || retainViewMode == RetainViewMode.RELEASE_DETACH || isBeingDestroyed);
|
||||
|
||||
if (attached) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preDetach(this, view);
|
||||
}
|
||||
|
||||
attached = false;
|
||||
|
||||
if (!awaitingParentAttach) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preDetach(this, view);
|
||||
}
|
||||
|
||||
attached = false;
|
||||
onDetach(view);
|
||||
}
|
||||
|
||||
if (hasOptionsMenu && !optionsMenuHidden) {
|
||||
router.invalidateOptionsMenu();
|
||||
}
|
||||
if (hasOptionsMenu && !optionsMenuHidden) {
|
||||
router.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDetach(this, view);
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postDetach(this, view);
|
||||
}
|
||||
} else {
|
||||
attached = false;
|
||||
}
|
||||
}
|
||||
|
||||
awaitingParentAttach = false;
|
||||
|
||||
if (removeViewRef) {
|
||||
removeViewReference();
|
||||
removeViewReference(view != null ? view.getContext() : null);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeViewReference() {
|
||||
private void removeViewReference(@Nullable Context context) {
|
||||
if (view != null) {
|
||||
if (context == null) {
|
||||
context = view.getContext();
|
||||
}
|
||||
|
||||
if (!isBeingDestroyed && !hasSavedViewState) {
|
||||
saveViewState(view);
|
||||
}
|
||||
@@ -1044,14 +1075,15 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
if (isBeingDestroyed) {
|
||||
performDestroy();
|
||||
performDestroy(context);
|
||||
}
|
||||
}
|
||||
|
||||
final View inflate(@NonNull ViewGroup parent) {
|
||||
if (view != null && view.getParent() != null && view.getParent() != parent) {
|
||||
View viewRef = view;
|
||||
detach(view, true, false);
|
||||
removeViewReference();
|
||||
removeViewReference(viewRef.getContext());
|
||||
}
|
||||
|
||||
if (view == null) {
|
||||
@@ -1121,20 +1153,13 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
private void performDestroy() {
|
||||
private void performDestroy(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
context = getActivity();
|
||||
}
|
||||
|
||||
if (isContextAvailable) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preContextUnavailable(this, getActivity());
|
||||
}
|
||||
|
||||
isContextAvailable = false;
|
||||
onContextUnavailable();
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postContextUnavailable(this);
|
||||
}
|
||||
onContextUnavailable(context);
|
||||
}
|
||||
|
||||
if (!destroyed) {
|
||||
@@ -1172,7 +1197,7 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
if (!attached) {
|
||||
removeViewReference();
|
||||
removeViewReference(null);
|
||||
} else if (removeViews) {
|
||||
detach(view, true, false);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.IntentSender.SendIntentException;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
@@ -22,18 +23,24 @@ class ControllerHostedRouter extends Router {
|
||||
|
||||
private final String KEY_HOST_ID = "ControllerHostedRouter.hostId";
|
||||
private final String KEY_TAG = "ControllerHostedRouter.tag";
|
||||
private final String KEY_BOUND_TO_CONTAINER = "ControllerHostedRouter.boundToContainer";
|
||||
|
||||
private Controller hostController;
|
||||
|
||||
@IdRes private int hostId;
|
||||
private String tag;
|
||||
private boolean isDetachFrozen;
|
||||
private boolean boundToContainer;
|
||||
|
||||
ControllerHostedRouter() { }
|
||||
|
||||
ControllerHostedRouter(int hostId, @Nullable String tag) {
|
||||
ControllerHostedRouter(int hostId, @Nullable String tag, boolean boundToContainer) {
|
||||
if (!boundToContainer && tag == null) {
|
||||
throw new IllegalStateException("ControllerHostedRouter can't be created without a tag if not bounded to its container");
|
||||
}
|
||||
this.hostId = hostId;
|
||||
this.tag = tag;
|
||||
this.boundToContainer = boundToContainer;
|
||||
}
|
||||
|
||||
final void setHostController(@NonNull Controller controller) {
|
||||
@@ -213,6 +220,7 @@ class ControllerHostedRouter extends Router {
|
||||
super.saveInstanceState(outState);
|
||||
|
||||
outState.putInt(KEY_HOST_ID, hostId);
|
||||
outState.putBoolean(KEY_BOUND_TO_CONTAINER, boundToContainer);
|
||||
outState.putString(KEY_TAG, tag);
|
||||
}
|
||||
|
||||
@@ -221,6 +229,7 @@ class ControllerHostedRouter extends Router {
|
||||
super.restoreInstanceState(savedInstanceState);
|
||||
|
||||
hostId = savedInstanceState.getInt(KEY_HOST_ID);
|
||||
boundToContainer = savedInstanceState.getBoolean(KEY_BOUND_TO_CONTAINER);
|
||||
tag = savedInstanceState.getString(KEY_TAG);
|
||||
}
|
||||
|
||||
@@ -234,9 +243,18 @@ class ControllerHostedRouter extends Router {
|
||||
return hostId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getTag() {
|
||||
return tag;
|
||||
boolean matches(int hostId, @Nullable String tag) {
|
||||
if (!boundToContainer && container == null) {
|
||||
if (this.tag == null) {
|
||||
throw new IllegalStateException("Host ID can't be variable with a null tag");
|
||||
}
|
||||
if (this.tag.equals(tag)) {
|
||||
this.hostId = hostId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return this.hostId == hostId && TextUtils.equals(tag, this.tag);
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
@@ -34,14 +35,14 @@ import java.util.List;
|
||||
public abstract class Router {
|
||||
|
||||
private static final String KEY_BACKSTACK = "Router.backstack";
|
||||
private static final String KEY_POPS_LAST_VIEW = "Router.popsLastView";
|
||||
private static final String KEY_POP_ROOT_CONTROLLER_MODE = "Router.popRootControllerMode";
|
||||
|
||||
final Backstack backstack = new Backstack();
|
||||
private final List<ControllerChangeListener> changeListeners = new ArrayList<>();
|
||||
private final List<ChangeTransaction> pendingControllerChanges = new ArrayList<>();
|
||||
final List<Controller> destroyingControllers = new ArrayList<>();
|
||||
|
||||
private boolean popsLastView = false;
|
||||
private PopRootControllerMode popRootControllerMode = PopRootControllerMode.POP_ROOT_CONTROLLER_BUT_NOT_VIEW;
|
||||
boolean containerFullyAttached = false;
|
||||
boolean isActivityStopped = false;
|
||||
|
||||
@@ -94,7 +95,7 @@ public abstract class Router {
|
||||
//noinspection ConstantConditions
|
||||
if (backstack.peek().controller().handleBack()) {
|
||||
return true;
|
||||
} else if (popCurrentController()) {
|
||||
} else if ((backstack.getSize() > 1 || popRootControllerMode != PopRootControllerMode.NEVER) && popCurrentController()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -161,7 +162,7 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
if (popsLastView) {
|
||||
if (popRootControllerMode == PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW) {
|
||||
return topTransaction != null;
|
||||
} else {
|
||||
return !backstack.isEmpty();
|
||||
@@ -220,7 +221,7 @@ public abstract class Router {
|
||||
}
|
||||
|
||||
void destroy(boolean popViews) {
|
||||
popsLastView = true;
|
||||
popRootControllerMode = PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW;
|
||||
final List<RouterTransaction> poppedControllers = backstack.popAll();
|
||||
trackDestroyingControllers(poppedControllers);
|
||||
|
||||
@@ -250,10 +251,24 @@ public abstract class Router {
|
||||
* If set to true, this router will handle back presses by performing a change handler on the last controller and view
|
||||
* in the stack. This defaults to false so that the developer can either finish its containing Activity or otherwise
|
||||
* hide its parent view without any strange artifacting.
|
||||
*
|
||||
* Note: This method has been deprecated and should be replaced with setPopRootControllerMode.
|
||||
*/
|
||||
@NonNull
|
||||
@Deprecated
|
||||
public Router setPopsLastView(boolean popsLastView) {
|
||||
this.popsLastView = popsLastView;
|
||||
this.popRootControllerMode = popsLastView ? PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW : PopRootControllerMode.POP_ROOT_CONTROLLER_BUT_NOT_VIEW;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the method this router will use to handle back presses when there is only one controller left in the backstack.
|
||||
* Defaults to POP_ROOT_CONTROLLER_LEAVING_VIEW so that the developer can either finish its containing Activity or
|
||||
* otherwise hide its parent view without any strange artifacting.
|
||||
*/
|
||||
@NonNull
|
||||
public Router setPopRootControllerMode(@NonNull PopRootControllerMode popRootControllerMode) {
|
||||
this.popRootControllerMode = popRootControllerMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -545,10 +560,9 @@ public abstract class Router {
|
||||
public void rebindIfNeeded() {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
while (backstackIterator.hasNext()) {
|
||||
RouterTransaction transaction = backstackIterator.next();
|
||||
|
||||
// Not directly using the iterator in order to prevent ConcurrentModificationExceptions if controllers pop
|
||||
// themselves on re-attach.
|
||||
for (RouterTransaction transaction : getTransactions()) {
|
||||
if (transaction.controller().getNeedsAttach()) {
|
||||
performControllerChange(transaction, null, true, new SimpleSwapChangeHandler(false));
|
||||
} else {
|
||||
@@ -649,14 +663,14 @@ public abstract class Router {
|
||||
backstack.saveInstanceState(backstackState);
|
||||
|
||||
outState.putParcelable(KEY_BACKSTACK, backstackState);
|
||||
outState.putBoolean(KEY_POPS_LAST_VIEW, popsLastView);
|
||||
outState.putInt(KEY_POP_ROOT_CONTROLLER_MODE, popRootControllerMode.ordinal());
|
||||
}
|
||||
|
||||
public void restoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
Bundle backstackBundle = savedInstanceState.getParcelable(KEY_BACKSTACK);
|
||||
//noinspection ConstantConditions
|
||||
backstack.restoreInstanceState(backstackBundle);
|
||||
popsLastView = savedInstanceState.getBoolean(KEY_POPS_LAST_VIEW);
|
||||
popRootControllerMode = PopRootControllerMode.values()[savedInstanceState.getInt(KEY_POP_ROOT_CONTROLLER_MODE)];
|
||||
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
while (backstackIterator.hasNext()) {
|
||||
@@ -727,6 +741,7 @@ public abstract class Router {
|
||||
@Override
|
||||
public void run() {
|
||||
containerFullyAttached = true;
|
||||
performPendingControllerChanges();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -745,6 +760,15 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
void onContextUnavailable(@NonNull Context context) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller().onContextUnavailable(context);
|
||||
}
|
||||
for (Controller controller : destroyingControllers) {
|
||||
controller.onContextUnavailable(context);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
final List<Controller> getControllers() {
|
||||
List<Controller> controllers = new ArrayList<>(backstack.getSize());
|
||||
@@ -757,6 +781,18 @@ public abstract class Router {
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
final List<RouterTransaction> getTransactions() {
|
||||
List<RouterTransaction> transactions = new ArrayList<>(backstack.getSize());
|
||||
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
while (backstackIterator.hasNext()) {
|
||||
transactions.add(backstackIterator.next());
|
||||
}
|
||||
|
||||
return transactions;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public final Boolean handleRequestedPermission(@NonNull String permission) {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
@@ -793,7 +829,7 @@ public abstract class Router {
|
||||
if (to != null) {
|
||||
to.ensureValidIndex(getTransactionIndexer());
|
||||
setRouterOnController(toController);
|
||||
} else if (backstack.getSize() == 0 && !popsLastView) {
|
||||
} else if (backstack.getSize() == 0 && popRootControllerMode == PopRootControllerMode.POP_ROOT_CONTROLLER_BUT_NOT_VIEW) {
|
||||
// We're emptying out the backstack. Views get weird if you transition them out, so just no-op it. The host
|
||||
// Activity or controller should be handling this by finishing or at least hiding this view.
|
||||
changeHandler = new NoOpControllerChangeHandler();
|
||||
@@ -837,12 +873,14 @@ public abstract class Router {
|
||||
to.setNeedsAttach(true);
|
||||
}
|
||||
pendingControllerChanges.add(transaction);
|
||||
container.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
performPendingControllerChanges();
|
||||
}
|
||||
});
|
||||
if (container != null) {
|
||||
container.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
performPendingControllerChanges();
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
ControllerChangeHandler.executeChange(transaction);
|
||||
}
|
||||
@@ -1001,4 +1039,25 @@ public abstract class Router {
|
||||
@NonNull abstract Router getRootRouter();
|
||||
@NonNull abstract TransactionIndexer getTransactionIndexer();
|
||||
|
||||
/**
|
||||
* Defines the way a Router will handle back button or pop events when there is only one controller
|
||||
* left in the backstack.
|
||||
*/
|
||||
public enum PopRootControllerMode {
|
||||
/**
|
||||
* The Router will not pop the final controller left on the backstack when the back button is pressed
|
||||
* or when pop events are called. This mode should generally be used for Activity-hosted routers.
|
||||
*/
|
||||
NEVER,
|
||||
/**
|
||||
* The Router will pop the final controller, but will leave its view in the hierarchy. This is useful
|
||||
* when the developer wishes to allow its containing Activity to finish or otherwise hide its parent
|
||||
* view without any strange artifacting.
|
||||
*/
|
||||
POP_ROOT_CONTROLLER_BUT_NOT_VIEW,
|
||||
/**
|
||||
* The Router will pop both the final controller as well as its view.
|
||||
*/
|
||||
POP_ROOT_CONTROLLER_AND_VIEW
|
||||
}
|
||||
}
|
||||
|
||||
+109
-22
@@ -1,5 +1,6 @@
|
||||
package com.bluelinelabs.conductor.internal
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@@ -84,29 +85,19 @@ internal class OwnViewTreeLifecycleAndRegistry private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
// AbstractComposeView adds its own OnAttachStateChangeListener by default. Since it
|
||||
// does this on init, its detach callbacks get called before ours, which prevents us
|
||||
// from saving state in onDetach. The if statement in here should detect upcoming
|
||||
// detachment.
|
||||
override fun onChangeStart(
|
||||
changeController: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
changeType: ControllerChangeType,
|
||||
) {
|
||||
if (
|
||||
controller === changeController &&
|
||||
!changeType.isEnter &&
|
||||
changeHandler.removesFromViewOnPush() &&
|
||||
changeController.view != null &&
|
||||
lifecycleRegistry.currentState == Lifecycle.State.RESUMED
|
||||
) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
pauseOnChangeStart(
|
||||
targetController = controller,
|
||||
changeController = changeController,
|
||||
changeHandler = changeHandler,
|
||||
changeType = changeType,
|
||||
)
|
||||
|
||||
savedRegistryState = Bundle()
|
||||
savedStateRegistryController.performSave(savedRegistryState)
|
||||
|
||||
hasSavedState = true
|
||||
}
|
||||
GlobalChangeStartListener.onChangeStart(changeController, changeHandler, changeType)
|
||||
}
|
||||
|
||||
override fun preDetach(controller: Controller, view: View) {
|
||||
@@ -135,8 +126,7 @@ internal class OwnViewTreeLifecycleAndRegistry private constructor(
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
if (controller.isBeingDestroyed && controller.router.backstackSize == 0) {
|
||||
val parent = view.parent as? View
|
||||
parent?.addOnAttachStateChangeListener(object :
|
||||
View.OnAttachStateChangeListener {
|
||||
parent?.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View?) = Unit
|
||||
override fun onViewDetachedFromWindow(v: View?) {
|
||||
parent.removeOnAttachStateChangeListener(this)
|
||||
@@ -147,6 +137,14 @@ internal class OwnViewTreeLifecycleAndRegistry private constructor(
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
}
|
||||
}
|
||||
|
||||
override fun postContextAvailable(controller: Controller, context: Context) {
|
||||
listenForAncestorChangeStart(controller)
|
||||
}
|
||||
|
||||
override fun preContextUnavailable(controller: Controller, context: Context) {
|
||||
stopListeningForAncestorChangeStart(controller)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -154,11 +152,100 @@ internal class OwnViewTreeLifecycleAndRegistry private constructor(
|
||||
|
||||
override fun getSavedStateRegistry() = savedStateRegistryController.savedStateRegistry
|
||||
|
||||
private fun listenForAncestorChangeStart(controller: Controller) {
|
||||
GlobalChangeStartListener.subscribe(controller, controller.ancestors()) { ancestor, changeHandler, changeType ->
|
||||
// No-op on the case where we (the child controller) hasn't yet created a View as our parent is being
|
||||
// changed out.
|
||||
if (::lifecycleRegistry.isInitialized) {
|
||||
pauseOnChangeStart(
|
||||
targetController = ancestor,
|
||||
changeController = ancestor,
|
||||
changeHandler = changeHandler,
|
||||
changeType = changeType,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopListeningForAncestorChangeStart(controller: Controller) {
|
||||
GlobalChangeStartListener.unsubscribe(controller)
|
||||
}
|
||||
|
||||
// AbstractComposeView adds its own OnAttachStateChangeListener by default. Since it
|
||||
// does this on init, its detach callbacks get called before ours, which prevents us
|
||||
// from saving state in onDetach. The if statement in here should detect upcoming
|
||||
// detachment.
|
||||
private fun pauseOnChangeStart(
|
||||
targetController: Controller,
|
||||
changeController: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType,
|
||||
) {
|
||||
if (
|
||||
targetController === changeController &&
|
||||
!changeType.isEnter &&
|
||||
changeHandler.removesFromViewOnPush() &&
|
||||
changeController.view != null &&
|
||||
lifecycleRegistry.currentState == Lifecycle.State.RESUMED
|
||||
) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
|
||||
savedRegistryState = Bundle()
|
||||
savedStateRegistryController.performSave(savedRegistryState)
|
||||
|
||||
hasSavedState = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun Controller.ancestors(): Collection<String> {
|
||||
return buildList {
|
||||
var ancestor = parentController
|
||||
while (ancestor != null) {
|
||||
add(ancestor.instanceId)
|
||||
ancestor = ancestor.parentController
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_SAVED_STATE = "Registry.savedState"
|
||||
|
||||
fun own(target: Controller) {
|
||||
OwnViewTreeLifecycleAndRegistry(target)
|
||||
fun own(target: Controller): OwnViewTreeLifecycleAndRegistry {
|
||||
return OwnViewTreeLifecycleAndRegistry(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In order to prevent child controllers from having strong references to all of their ancestors, some of which may
|
||||
// break their connection before the child is made aware, this shared listener is used to call all interested parties
|
||||
// when a controller begins transitioning.
|
||||
private object GlobalChangeStartListener {
|
||||
private val listeners = mutableMapOf<String, Listener>()
|
||||
|
||||
fun subscribe(
|
||||
controller: Controller,
|
||||
targetControllers: Collection<String>,
|
||||
listener: (Controller, ControllerChangeHandler, ControllerChangeType) -> Unit,
|
||||
) {
|
||||
listeners[controller.instanceId] = Listener(targetControllers, listener)
|
||||
}
|
||||
|
||||
fun unsubscribe(controller: Controller) {
|
||||
listeners.remove(controller.instanceId)
|
||||
}
|
||||
|
||||
fun onChangeStart(controller: Controller, changeHandler: ControllerChangeHandler, changeType: ControllerChangeType) {
|
||||
listeners.values.forEach { it.call(controller, changeHandler, changeType) }
|
||||
}
|
||||
|
||||
private class Listener(
|
||||
private val targetControllers: Collection<String>,
|
||||
private val listener: (Controller, ControllerChangeHandler, ControllerChangeType) -> Unit,
|
||||
) {
|
||||
fun call(controller: Controller, changeHandler: ControllerChangeHandler, changeType: ControllerChangeType) {
|
||||
if (targetControllers.contains(controller.instanceId)) {
|
||||
listener(controller, changeHandler, changeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -112,7 +112,7 @@ class ControllerLifecycleActivityReferenceTests {
|
||||
child.addLifecycleListener(listener)
|
||||
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setPopRootControllerMode(Router.PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
childRouter.pushController(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
@@ -146,7 +146,7 @@ class ControllerLifecycleActivityReferenceTests {
|
||||
child.addLifecycleListener(listener)
|
||||
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setPopRootControllerMode(Router.PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
childRouter.pushController(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
@@ -199,7 +199,7 @@ class ControllerLifecycleActivityReferenceTests {
|
||||
val listener = ActivityReferencingLifecycleListener()
|
||||
child.addLifecycleListener(listener)
|
||||
val childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setPopRootControllerMode(Router.PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
childRouter.pushController(
|
||||
child.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
|
||||
@@ -276,7 +276,7 @@ class ControllerTests {
|
||||
Assert.assertNull(child2.parentController)
|
||||
|
||||
var childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setPopRootControllerMode(Router.PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
childRouter.setRoot(child1.asTransaction())
|
||||
Assert.assertEquals(1, parent.childRouters.size)
|
||||
Assert.assertEquals(childRouter, parent.childRouters[0])
|
||||
@@ -362,7 +362,7 @@ class ControllerTests {
|
||||
val childTransaction1 = TestController().asTransaction()
|
||||
val childTransaction2 = TestController().asTransaction()
|
||||
var childRouter = parent.getChildRouter(parent.view!!.findViewById(TestController.CHILD_VIEW_ID_1))
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setPopRootControllerMode(Router.PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
childRouter.setRoot(childTransaction1)
|
||||
childRouter.pushController(childTransaction2)
|
||||
val savedState = Bundle()
|
||||
|
||||
@@ -124,7 +124,7 @@ class ReattachCaseTests {
|
||||
val childRouter = controllerB.getChildRouter(
|
||||
controllerB.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setPopRootControllerMode(Router.PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
childRouter.pushController(
|
||||
childController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
@@ -179,7 +179,7 @@ class ReattachCaseTests {
|
||||
val childRouter = controllerB.getChildRouter(
|
||||
controllerB.view!!.findViewById(TestController.VIEW_ID)
|
||||
)
|
||||
childRouter.setPopsLastView(true)
|
||||
childRouter.setPopRootControllerMode(Router.PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
childRouter.pushController(
|
||||
childController.asTransaction(
|
||||
pushChangeHandler = MockChangeHandler.defaultHandler(),
|
||||
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
package com.bluelinelabs.conductor.internal
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.TestController
|
||||
import com.bluelinelabs.conductor.asTransaction
|
||||
import com.bluelinelabs.conductor.util.TestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class OwnViewTreeLifecycleAndRegistryTest {
|
||||
|
||||
private val router = Robolectric.buildActivity(TestActivity::class.java)
|
||||
.setup()
|
||||
.get()
|
||||
.router
|
||||
|
||||
@Test
|
||||
fun `onCreate lifecycle event before create view`() {
|
||||
assertControllerState(
|
||||
preCreateViewAssertedState = Lifecycle.State.CREATED,
|
||||
setup = { router.setRoot(it.asTransaction()) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onStart lifecycle event after create view`() {
|
||||
assertControllerState(
|
||||
postCreateViewAssertedState = Lifecycle.State.STARTED,
|
||||
setup = { router.setRoot(it.asTransaction()) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onResume lifecycle event on attach`() {
|
||||
assertControllerState(
|
||||
postAttachAssertedState = Lifecycle.State.RESUMED,
|
||||
setup = { router.setRoot(it.asTransaction()) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onPause lifecycle event on exit change start`() {
|
||||
assertControllerState(
|
||||
onChangeStartAssertedState = Lifecycle.State.STARTED,
|
||||
setup = {
|
||||
router.setRoot(it.asTransaction())
|
||||
router.pushController(TestController().asTransaction())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onPause lifecycle event on parent exit change start`() {
|
||||
val parent = TestController()
|
||||
val controller = TestController()
|
||||
var hasAsserted = false
|
||||
val ownViewTreeLifecycleAndRegistry = OwnViewTreeLifecycleAndRegistry.own(controller)
|
||||
|
||||
// Ensure our listener gets added after OwnViewTreeLifecycleAndRegistry's by waiting until
|
||||
// postContextAvailable to add the lifecycle listener on the parent controller
|
||||
controller.addLifecycleListener(object : Controller.LifecycleListener() {
|
||||
override fun postContextAvailable(controller: Controller, context: Context) {
|
||||
parent.addLifecycleListener(object : Controller.LifecycleListener() {
|
||||
override fun onChangeStart(
|
||||
controller: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
Assert.assertEquals(Lifecycle.State.STARTED, ownViewTreeLifecycleAndRegistry.lifecycle.currentState)
|
||||
hasAsserted = true
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
router.setRoot(parent.asTransaction())
|
||||
parent.getChildRouter(parent.view!!.findViewById(TestController.VIEW_ID)).setRoot(controller.asTransaction())
|
||||
router.pushController(TestController().asTransaction())
|
||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||
|
||||
Assert.assertTrue(hasAsserted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onStop lifecycle event on detach`() {
|
||||
assertControllerState(
|
||||
preDetachAssertedState = Lifecycle.State.CREATED,
|
||||
setup = {
|
||||
router.setRoot(it.asTransaction())
|
||||
router.pushController(TestController().asTransaction())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onDestroy lifecycle event on destroy view`() {
|
||||
assertControllerState(
|
||||
preDestroyViewAssertedState = Lifecycle.State.DESTROYED,
|
||||
setup = {
|
||||
router.setRoot(it.asTransaction())
|
||||
router.pushController(TestController().asTransaction())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun assertControllerState(
|
||||
preCreateViewAssertedState: Lifecycle.State? = null,
|
||||
postCreateViewAssertedState: Lifecycle.State? = null,
|
||||
postAttachAssertedState: Lifecycle.State? = null,
|
||||
preDetachAssertedState: Lifecycle.State? = null,
|
||||
preDestroyViewAssertedState: Lifecycle.State? = null,
|
||||
onChangeStartAssertedState: Lifecycle.State? = null,
|
||||
setup: (Controller) -> Unit = { },
|
||||
) {
|
||||
val controller = TestController()
|
||||
val ownViewTreeLifecycleAndRegistry = OwnViewTreeLifecycleAndRegistry.own(controller)
|
||||
var hasAsserted = false
|
||||
|
||||
val assertState: (Lifecycle.State) -> Unit = {
|
||||
Assert.assertEquals(it, ownViewTreeLifecycleAndRegistry.lifecycle.currentState)
|
||||
}
|
||||
|
||||
controller.addLifecycleListener(object : Controller.LifecycleListener() {
|
||||
override fun preCreateView(controller: Controller) {
|
||||
preCreateViewAssertedState?.let {
|
||||
assertState(it)
|
||||
hasAsserted = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
postCreateViewAssertedState?.let {
|
||||
assertState(it)
|
||||
hasAsserted = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun postAttach(controller: Controller, view: View) {
|
||||
postAttachAssertedState?.let {
|
||||
assertState(it)
|
||||
hasAsserted = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun preDetach(controller: Controller, view: View) {
|
||||
preDetachAssertedState?.let {
|
||||
assertState(it)
|
||||
hasAsserted = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
preDestroyViewAssertedState?.let {
|
||||
assertState(it)
|
||||
hasAsserted = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChangeStart(
|
||||
controller: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
changeType: ControllerChangeType
|
||||
) {
|
||||
if (!changeType.isEnter) {
|
||||
onChangeStartAssertedState?.let {
|
||||
assertState(it)
|
||||
hasAsserted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
setup(controller)
|
||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertTrue(hasAsserted)
|
||||
}
|
||||
}
|
||||
+15
-20
@@ -5,7 +5,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId "com.bluelinelabs.conductor.demo"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
targetSdkVersion libs.versions.targetsdk.get()
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
vectorDrawables.useSupportLibrary true
|
||||
@@ -27,7 +27,7 @@ android {
|
||||
compose = true
|
||||
}
|
||||
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion 31
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
@@ -39,21 +39,19 @@ android {
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion composeVersion
|
||||
kotlinCompilerExtensionVersion libs.versions.compose.get()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation rootProject.ext.androidxAppCompat
|
||||
implementation rootProject.ext.androidxViewPager2
|
||||
implementation rootProject.ext.material
|
||||
implementation rootProject.ext.androidxCoreKtx
|
||||
implementation libs.androidx.appcompat
|
||||
implementation libs.androidx.viewpager2
|
||||
implementation libs.material
|
||||
implementation libs.androidx.core.ktx
|
||||
|
||||
implementation rootProject.ext.archComponentsLiveDataCore // Fix duplicate classes
|
||||
implementation libs.picasso
|
||||
|
||||
implementation rootProject.ext.picasso
|
||||
|
||||
implementation rootProject.ext.autodisposeKtx
|
||||
implementation libs.autodispose.ktx
|
||||
|
||||
implementation project(':conductor')
|
||||
implementation project(':conductor-modules:viewpager')
|
||||
@@ -62,14 +60,11 @@ dependencies {
|
||||
implementation project(':conductor-modules:arch-components-lifecycle')
|
||||
implementation project(':conductor-modules:androidx-transition')
|
||||
|
||||
implementation "androidx.compose.ui:ui:$composeVersion"
|
||||
implementation "androidx.compose.ui:ui-tooling:$composeVersion"
|
||||
implementation "androidx.compose.foundation:foundation:$composeVersion"
|
||||
implementation "androidx.compose.material:material:$composeVersion"
|
||||
implementation "androidx.compose.material:material-icons-core:$composeVersion"
|
||||
implementation "androidx.compose.material:material-icons-extended:$composeVersion"
|
||||
implementation "androidx.activity:activity-compose:1.3.0-beta02"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07"
|
||||
implementation libs.compose.ui
|
||||
implementation libs.compose.ui.tooling
|
||||
implementation libs.compose.foundation
|
||||
implementation libs.compose.material
|
||||
implementation libs.activity.compose
|
||||
|
||||
implementation rootProject.ext.leakCanary
|
||||
implementation libs.leakCanary
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import com.bluelinelabs.conductor.Conductor.attachRouter
|
||||
import com.bluelinelabs.conductor.Router
|
||||
import com.bluelinelabs.conductor.Router.PopRootControllerMode
|
||||
import com.bluelinelabs.conductor.RouterTransaction.Companion.with
|
||||
import com.bluelinelabs.conductor.demo.controllers.HomeController
|
||||
import com.bluelinelabs.conductor.demo.databinding.ActivityMainBinding
|
||||
@@ -23,6 +24,8 @@ class MainActivity : AppCompatActivity(), ToolbarProvider {
|
||||
setContentView(binding.root)
|
||||
|
||||
router = attachRouter(this, binding.controllerContainer, savedInstanceState)
|
||||
.setPopRootControllerMode(PopRootControllerMode.NEVER)
|
||||
|
||||
if (!router.hasRootController()) {
|
||||
router.setRoot(with(HomeController()))
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers
|
||||
|
||||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Router.PopRootControllerMode
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.demo.R
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController
|
||||
@@ -18,7 +19,7 @@ class MultipleChildRouterController : BaseController(R.layout.controller_multipl
|
||||
val childContainers = listOf(binding.container0, binding.container1, binding.container2)
|
||||
|
||||
childContainers.forEach { container ->
|
||||
val childRouter = getChildRouter(container).setPopsLastView(false)
|
||||
val childRouter = getChildRouter(container).setPopRootControllerMode(PopRootControllerMode.POP_ROOT_CONTROLLER_BUT_NOT_VIEW)
|
||||
if (!childRouter.hasRootController()) {
|
||||
childRouter.setRoot(RouterTransaction.with(NavigationDemoController(0, NavigationDemoController.DisplayUpMode.HIDE)))
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.bluelinelabs.conductor.demo.controllers
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.Router.PopRootControllerMode
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||
import com.bluelinelabs.conductor.demo.R
|
||||
@@ -11,7 +12,6 @@ import com.bluelinelabs.conductor.demo.databinding.ControllerParentBinding
|
||||
import com.bluelinelabs.conductor.demo.util.getMaterialColor
|
||||
import com.bluelinelabs.conductor.demo.util.viewBinding
|
||||
|
||||
|
||||
class ParentController : BaseController(R.layout.controller_parent) {
|
||||
private val binding: ControllerParentBinding by viewBinding(ControllerParentBinding::bind)
|
||||
|
||||
@@ -50,7 +50,7 @@ class ParentController : BaseController(R.layout.controller_parent) {
|
||||
else -> throw IllegalStateException("Invalid child index $index")
|
||||
}
|
||||
|
||||
val childRouter = getChildRouter(container).setPopsLastView(true)
|
||||
val childRouter = getChildRouter(container).setPopRootControllerMode(PopRootControllerMode.POP_ROOT_CONTROLLER_AND_VIEW)
|
||||
if (!childRouter.hasRootController()) {
|
||||
val child = ChildController(
|
||||
title = "Child Controller #$index",
|
||||
|
||||
+8
@@ -1,5 +1,6 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers.base
|
||||
|
||||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
@@ -15,6 +16,13 @@ private class RefWatchingControllerLifecycleListener : Controller.LifecycleListe
|
||||
}
|
||||
}
|
||||
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
AppWatcher.objectWatcher.expectWeaklyReachable(
|
||||
view,
|
||||
"A destroyed controller view should have only weak references."
|
||||
)
|
||||
}
|
||||
|
||||
override fun onChangeEnd(
|
||||
controller: Controller,
|
||||
changeHandler: ControllerChangeHandler,
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
ext {
|
||||
minSdkVersion = 16
|
||||
compileSdkVersion = 28
|
||||
targetSdkVersion = 28
|
||||
|
||||
picassoVersion = '2.5.2'
|
||||
rxJava2Version = '2.1.14'
|
||||
autodisposeVersion = '1.0.0'
|
||||
archComponentsVersion = '2.3.1'
|
||||
junitVersion = '4.12'
|
||||
mvnPublishVersion = '0.13.0'
|
||||
dokkaVersion = '1.4.32'
|
||||
composeVersion = "1.0.0-beta09"
|
||||
|
||||
agpVersion = "7.0.0-beta05"
|
||||
lintVersion = agpVersion.replaceFirst(~/\d*/) { version ->
|
||||
// the major version of lint is always 23 version higher than the major version of agp
|
||||
version.toInteger() + 23
|
||||
}
|
||||
|
||||
kotlinVersion = '1.5.10'
|
||||
kotlinStd = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
||||
|
||||
material = "com.google.android.material:material:1.1.0"
|
||||
androidxAnnotations = "androidx.annotation:annotation:1.1.0"
|
||||
androidxAppCompat = "androidx.appcompat:appcompat:1.3.0"
|
||||
androidxTransition = "androidx.transition:transition:1.3.1"
|
||||
androidxCollection = "androidx.collection:collection:1.1.0"
|
||||
androidxViewPager2 = "androidx.viewpager2:viewpager2:1.0.0"
|
||||
androidxCoreKtx = "androidx.core:core-ktx:1.3.2"
|
||||
|
||||
picasso = "com.squareup.picasso:picasso:$picassoVersion"
|
||||
|
||||
leakCanary = "com.squareup.leakcanary:leakcanary-android:2.7"
|
||||
|
||||
rxJava2 = "io.reactivex.rxjava2:rxjava:$rxJava2Version"
|
||||
|
||||
autodispose = "com.uber.autodispose:autodispose:$autodisposeVersion"
|
||||
autodisposeLifecycle = "com.uber.autodispose:autodispose-lifecycle:$autodisposeVersion"
|
||||
autodisposeKtx = "com.uber.autodispose:autodispose-ktx:$autodisposeVersion"
|
||||
|
||||
archComponentsLifecycle = "androidx.lifecycle:lifecycle-runtime:$archComponentsVersion"
|
||||
archComponentsLiveDataCore = "androidx.lifecycle:lifecycle-livedata-core:$archComponentsVersion"
|
||||
|
||||
savedState = "androidx.savedstate:savedstate-ktx:1.1.0"
|
||||
|
||||
junit = "junit:junit:$junitVersion"
|
||||
robolectric = "org.robolectric:robolectric:4.5.1"
|
||||
kotestAssertions = "io.kotest:kotest-assertions-core:4.6.0"
|
||||
|
||||
lintapi = "com.android.tools.lint:lint-api:$lintVersion"
|
||||
lintchecks = "com.android.tools.lint:lint-checks:$lintVersion"
|
||||
lint = "com.android.tools.lint:lint:$lintVersion"
|
||||
lintTests = "com.android.tools.lint:lint-tests:$lintVersion"
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
VERSION_CODE=3
|
||||
VERSION_NAME=3.1.2-SNAPSHOT
|
||||
VERSION_NAME=3.2.0-SNAPSHOT
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
[versions]
|
||||
minsdk = "16"
|
||||
compilesdk = "28"
|
||||
targetsdk = "28"
|
||||
|
||||
activity-compose = "1.3.0"
|
||||
agp = "7.2.1" # Note: update lint version whenever this is updated
|
||||
androidx-annotation = "1.1.0"
|
||||
androidx-appcompat = "1.3.0"
|
||||
androidx-collection = "1.1.0"
|
||||
androidx-core = "1.3.2"
|
||||
androidx-lifecycle = "2.3.1"
|
||||
androidx-savedstate = "1.1.0"
|
||||
androidx-transition = "1.3.1"
|
||||
androidx-viewpager2 = "1.0.0"
|
||||
autodispose = "1.0.0"
|
||||
compose = "1.1.0"
|
||||
dokka = "1.4.32"
|
||||
junit = "4.13"
|
||||
kotest = "4.6.0"
|
||||
kotlin = "1.6.10"
|
||||
leakCanary = "2.7"
|
||||
lint = "30.2.1" # Should always be agp + 23
|
||||
material = "1.2.1"
|
||||
mvnpublish = "0.13.0"
|
||||
picasso = "2.5.2"
|
||||
robolectric = "4.5.1"
|
||||
rxjava2 = "2.1.14"
|
||||
|
||||
[libraries]
|
||||
activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" }
|
||||
agp = { module = "com.android.tools.build:gradle", version.ref = "agp" }
|
||||
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
|
||||
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
|
||||
androidx-collection = { module = "androidx.collection:collection", version.ref = "androidx-collection" }
|
||||
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
|
||||
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "androidx-lifecycle" }
|
||||
androidx-lifecycle-livedata-core = { module = "androidx.lifecycle:lifecycle-livedata-core", version.ref = "androidx-lifecycle" }
|
||||
androidx-savedstate-ktx = { module = "androidx.savedstate:savedstate-ktx", version.ref = "androidx-savedstate" }
|
||||
androidx-transition = { module = "androidx.transition:transition", version.ref = "androidx-transition" }
|
||||
androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "androidx-viewpager2" }
|
||||
autodispose = { module = "com.uber.autodispose:autodispose", version.ref = "autodispose" }
|
||||
autodispose-lifecycle = { module = "com.uber.autodispose:autodispose-lifecycle", version.ref = "autodispose" }
|
||||
autodispose-ktx = { module = "com.uber.autodispose:autodispose-ktx", version.ref = "autodispose" }
|
||||
compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose" }
|
||||
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
|
||||
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
|
||||
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
|
||||
compose-material = { module = "androidx.compose.material:material", version.ref = "compose" }
|
||||
dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
|
||||
junit = { module = "junit:junit", version.ref = "junit" }
|
||||
kotest = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
|
||||
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
|
||||
leakCanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakCanary" }
|
||||
lint = { module = "com.android.tools.lint:lint", version.ref = "lint" }
|
||||
lint-api = { module = "com.android.tools.lint:lint-api", version.ref = "lint" }
|
||||
lint-checks = { module = "com.android.tools.lint:lint-checks", version.ref = "lint" }
|
||||
lint-tests = { module = "com.android.tools.lint:lint-tests", version.ref = "lint" }
|
||||
material = { module = "com.google.android.material:material", version.ref = "material" }
|
||||
mvnpublish = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "mvnpublish" }
|
||||
picasso = { module = "com.squareup.picasso:picasso", version.ref = "picasso" }
|
||||
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
|
||||
rxjava2 = { module = "io.reactivex.rxjava2:rxjava", version.ref = "rxjava2" }
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
Reference in New Issue
Block a user