Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 55e8aebb87 | |||
| 272c507f91 | |||
| 8e945cde52 | |||
| c17287db67 | |||
| 625a3fcfd6 | |||
| dd2ecf2f83 | |||
| 0efc2b3daf | |||
| 4b4c3a82b8 | |||
| 7d0599fc5d | |||
| 0adea89d34 | |||
| 044363517c | |||
| a2f11d5d51 | |||
| bcd8ddbfb5 | |||
| 479e3f0474 | |||
| c298ca905c | |||
| aebb19effa | |||
| e64fe1c610 | |||
| 2357297531 | |||
| 926f7da6ce | |||
| d260dfcf12 | |||
| a84b2fb4c4 | |||
| 6aca3f578a | |||
| 45ab54b5d7 | |||
| ca84419e0c | |||
| a04dec7ec1 | |||
| 81a499d121 | |||
| ff8ab621bc | |||
| cdb5e5a978 | |||
| effa410eae | |||
| df27bfaa3d | |||
| a865c210b6 | |||
| 7820748cce | |||
| 2147b2aa5e | |||
| 19418617dd | |||
| e1924bf8a7 | |||
| 6d3faaebe3 | |||
| 17639129b9 | |||
| 1c809095ec | |||
| 3bc563de38 | |||
| 7beb94f8cc |
Executable → Regular
+1
-1
@@ -3,7 +3,7 @@ language: android
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- build-tools-25.0.0
|
||||
- build-tools-25.0.3
|
||||
- android-25
|
||||
- extra-android-m2repository
|
||||
licenses:
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
A small, yet full-featured framework that allows building View-based Android applications. Conductor provides a light-weight wrapper around standard Android Views that does just about everything you'd want:
|
||||
|
||||
| Conductor
|
||||
------|------------------------------
|
||||
| | Conductor |
|
||||
|-----------|-------------|
|
||||
:tada: | Easy integration
|
||||
:point_up: | Single Activity apps without using Fragments
|
||||
:recycle: | Simple but powerful lifecycle management
|
||||
@@ -20,29 +20,28 @@ Conductor is architecture-agnostic and does not try to force any design decision
|
||||
## Installation
|
||||
|
||||
```gradle
|
||||
compile 'com.bluelinelabs:conductor:2.1.1'
|
||||
compile 'com.bluelinelabs:conductor:2.1.4'
|
||||
|
||||
// If you want the components that go along with
|
||||
// Android's support libraries (currently just a PagerAdapter):
|
||||
compile 'com.bluelinelabs:conductor-support:2.1.1'
|
||||
compile 'com.bluelinelabs:conductor-support:2.1.4'
|
||||
|
||||
// If you want RxJava lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.1.1'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.1.4'
|
||||
|
||||
// If you want RxJava2 lifecycle support:
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle2:2.1.1'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle2:2.1.4'
|
||||
|
||||
// If you want RxJava2 Autodispose support:
|
||||
compile 'com.bluelinelabs:conductor-autodispose:2.1.4'
|
||||
|
||||
// If you want Controllers that are Lifecycle-aware (architecture components):
|
||||
compile 'com.bluelinelabs:conductor-arch-components-lifecycle:0.1.1'
|
||||
```
|
||||
|
||||
SNAPSHOT:
|
||||
|
||||
```gradle
|
||||
compile 'com.bluelinelabs:conductor:2.1.2-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-support:2.1.2-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle:2.1.2-SNAPSHOT'
|
||||
compile 'com.bluelinelabs:conductor-rxlifecycle2:2.1.2-SNAPSHOT'
|
||||
```
|
||||
|
||||
You also have to add the url to the snapshot repository:
|
||||
Just use `2.1.5-SNAPSHOT` as your version number in any of the above dependencies and add the url to the snapshot repository:
|
||||
|
||||
```gradle
|
||||
allprojects {
|
||||
@@ -55,7 +54,7 @@ allprojects {
|
||||
|
||||
## Components to Know
|
||||
|
||||
| Conductor Components
|
||||
| | Conductor Components |
|
||||
------|------------------------------
|
||||
__Controller__ | The Controller is the View wrapper that will give you all of your lifecycle management features. Think of it as a lighter-weight and more predictable Fragment alternative with an easier to manage lifecycle.
|
||||
__Router__ | A Router implements navigation and backstack handling for Controllers. Router objects are attached to Activity/containing ViewGroup pairs. Routers do not directly render or push Views to the container ViewGroup, but instead defer this responsibility to the ControllerChangeHandler specified in a given transaction.
|
||||
@@ -118,7 +117,7 @@ public class HomeController extends Controller {
|
||||
|
||||
The lifecycle of a Controller is significantly simpler to understand than that of a Fragment. A lifecycle diagram is shown below:
|
||||
|
||||

|
||||

|
||||
|
||||
## Advanced Topics
|
||||
|
||||
|
||||
Executable → Regular
+2
-1
@@ -3,7 +3,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
classpath 'com.android.tools.build:gradle:2.3.2'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'https://maven.google.com' }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -66,4 +66,4 @@ public final class ControllerChangeHandlerIssueDetector extends Detector impleme
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -79,4 +79,4 @@ public final class ControllerIssueDetector extends Detector implements Detector.
|
||||
context.report(ISSUE, declaration, context.getLocation(declaration), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ public final class IssueRegistry extends com.android.tools.lint.client.api.Issue
|
||||
ControllerIssueDetector.ISSUE,
|
||||
ControllerChangeHandlerIssueDetector.ISSUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
apply from: rootProject.file('gradle-mvn-push.gradle')
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile rootProject.ext.archComopnentsLifecycle
|
||||
|
||||
compile project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-arch-components-lifecycle'
|
||||
@@ -0,0 +1,4 @@
|
||||
POM_NAME=Conductor Architecture Components Lifecycle Extensions
|
||||
POM_ARTIFACT_ID=conductor-archlifecycle
|
||||
POM_PACKAGING=aar
|
||||
VERSION_NAME=0.1.2-SNAPSHOT
|
||||
@@ -0,0 +1,3 @@
|
||||
<manifest package="com.bluelinelabs.conductor.archlifecycle">
|
||||
<application />
|
||||
</manifest>
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package com.bluelinelabs.conductor.archlifecycle;
|
||||
|
||||
import android.arch.lifecycle.Lifecycle.Event;
|
||||
import android.arch.lifecycle.Lifecycle.State;
|
||||
import android.arch.lifecycle.LifecycleRegistry;
|
||||
import android.arch.lifecycle.LifecycleRegistryOwner;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
|
||||
public class ControllerLifecycleRegistryOwner extends LifecycleListener implements LifecycleRegistryOwner {
|
||||
|
||||
private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
|
||||
|
||||
public ControllerLifecycleRegistryOwner(Controller controller) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_CREATE);
|
||||
lifecycleRegistry.markState(State.CREATED);
|
||||
|
||||
controller.addLifecycleListener(new LifecycleListener() {
|
||||
@Override
|
||||
public void preCreateView(@NonNull Controller controller) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_START);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCreateView(@NonNull Controller controller, @NonNull View view) {
|
||||
lifecycleRegistry.markState(State.STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_RESUME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
lifecycleRegistry.markState(State.RESUMED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_PAUSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
lifecycleRegistry.markState(State.STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroyView(@NonNull Controller controller, @NonNull View view) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_STOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroyView(@NonNull Controller controller) {
|
||||
lifecycleRegistry.markState(State.CREATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
lifecycleRegistry.handleLifecycleEvent(Event.ON_DESTROY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDestroy(@NonNull Controller controller) {
|
||||
lifecycleRegistry.markState(State.DESTROYED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifecycleRegistry getLifecycle() {
|
||||
return lifecycleRegistry;
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.bluelinelabs.conductor.archlifecycle;
|
||||
|
||||
import android.arch.lifecycle.LifecycleRegistry;
|
||||
import android.arch.lifecycle.LifecycleRegistryOwner;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
|
||||
public abstract class LifecycleController extends Controller implements LifecycleRegistryOwner {
|
||||
|
||||
private final ControllerLifecycleRegistryOwner lifecycleRegistryOwner = new ControllerLifecycleRegistryOwner(this);
|
||||
|
||||
@Override
|
||||
public LifecycleRegistry getLifecycle() {
|
||||
return lifecycleRegistryOwner.getLifecycle();
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.bluelinelabs.conductor.archlifecycle;
|
||||
|
||||
import android.arch.lifecycle.LifecycleRegistry;
|
||||
import android.arch.lifecycle.LifecycleRegistryOwner;
|
||||
|
||||
import com.bluelinelabs.conductor.RestoreViewOnCreateController;
|
||||
|
||||
public abstract class LifecycleRestoreViewOnCreateController extends RestoreViewOnCreateController implements LifecycleRegistryOwner {
|
||||
|
||||
private final ControllerLifecycleRegistryOwner lifecycleRegistryOwner = new ControllerLifecycleRegistryOwner(this);
|
||||
|
||||
@Override
|
||||
public LifecycleRegistry getLifecycle() {
|
||||
return lifecycleRegistryOwner.getLifecycle();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
apply from: rootProject.file('gradle-mvn-push.gradle')
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode Integer.parseInt(project.VERSION_CODE)
|
||||
versionName project.VERSION_NAME
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile rootProject.ext.rxJava2
|
||||
compile rootProject.ext.autodispose
|
||||
|
||||
compile project(':conductor')
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-autodispose'
|
||||
@@ -0,0 +1,3 @@
|
||||
POM_NAME=Conductor AutoDispose Extensions
|
||||
POM_ARTIFACT_ID=conductor-autodispose
|
||||
POM_PACKAGING=aar
|
||||
@@ -0,0 +1,3 @@
|
||||
<manifest package="com.bluelinelabs.conductor.autodispose">
|
||||
<application />
|
||||
</manifest>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.bluelinelabs.conductor.autodispose;
|
||||
|
||||
public enum ControllerEvent {
|
||||
|
||||
CREATE,
|
||||
CONTEXT_AVAILABLE,
|
||||
CREATE_VIEW,
|
||||
ATTACH,
|
||||
DETACH,
|
||||
DESTROY_VIEW,
|
||||
CONTEXT_UNAVAILABLE,
|
||||
DESTROY
|
||||
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.bluelinelabs.conductor.autodispose;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.uber.autodispose.OutsideLifecycleException;
|
||||
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
||||
public class ControllerLifecycleSubjectHelper {
|
||||
private ControllerLifecycleSubjectHelper() { }
|
||||
|
||||
@NonNull
|
||||
public static BehaviorSubject<ControllerEvent> create(Controller controller) {
|
||||
ControllerEvent initialState;
|
||||
if (controller.isBeingDestroyed() || controller.isDestroyed()) {
|
||||
throw new OutsideLifecycleException("Cannot bind to Controller lifecycle when outside of it.");
|
||||
} else if (controller.isAttached()) {
|
||||
initialState = ControllerEvent.ATTACH;
|
||||
} else if (controller.getView() != null) {
|
||||
initialState = ControllerEvent.CREATE_VIEW;
|
||||
} else if (controller.getActivity() != null) {
|
||||
initialState = ControllerEvent.CONTEXT_AVAILABLE;
|
||||
} else {
|
||||
initialState = ControllerEvent.CREATE;
|
||||
}
|
||||
|
||||
final BehaviorSubject<ControllerEvent> subject = BehaviorSubject.createDefault(initialState);
|
||||
|
||||
controller.addLifecycleListener(new Controller.LifecycleListener() {
|
||||
@Override
|
||||
public void preContextAvailable(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_AVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCreateView(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CREATE_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preAttach(@NonNull Controller controller, @NonNull View view) {
|
||||
subject.onNext(ControllerEvent.ATTACH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDetach(@NonNull Controller controller, @NonNull View view) {
|
||||
subject.onNext(ControllerEvent.DETACH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroyView(@NonNull Controller controller, @NonNull View view) {
|
||||
subject.onNext(ControllerEvent.DESTROY_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preContextUnavailable(@NonNull Controller controller, @NonNull Context context) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.DESTROY);
|
||||
}
|
||||
});
|
||||
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.bluelinelabs.conductor.autodispose;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.uber.autodispose.LifecycleScopeProvider;
|
||||
import com.uber.autodispose.OutsideLifecycleException;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.functions.Function;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
||||
public class ControllerScopeProvider implements LifecycleScopeProvider<ControllerEvent> {
|
||||
private static final Function<ControllerEvent, ControllerEvent> CORRESPONDING_EVENTS =
|
||||
new Function<ControllerEvent, ControllerEvent>() {
|
||||
@Override
|
||||
public ControllerEvent apply(ControllerEvent lastEvent) throws Exception {
|
||||
switch (lastEvent) {
|
||||
case CREATE:
|
||||
return ControllerEvent.DESTROY;
|
||||
case CONTEXT_AVAILABLE:
|
||||
return ControllerEvent.CONTEXT_UNAVAILABLE;
|
||||
case CREATE_VIEW:
|
||||
return ControllerEvent.DESTROY_VIEW;
|
||||
case ATTACH:
|
||||
return ControllerEvent.DETACH;
|
||||
case DETACH:
|
||||
return ControllerEvent.DESTROY;
|
||||
default:
|
||||
throw new OutsideLifecycleException("Cannot bind to Controller lifecycle when outside of it.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull private final BehaviorSubject<ControllerEvent> lifecycleSubject;
|
||||
|
||||
public static ControllerScopeProvider from(@NonNull Controller controller) {
|
||||
return new ControllerScopeProvider(controller);
|
||||
}
|
||||
|
||||
private ControllerScopeProvider(@NonNull Controller controller) {
|
||||
lifecycleSubject = ControllerLifecycleSubjectHelper.create(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<ControllerEvent> lifecycle() {
|
||||
return lifecycleSubject.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<ControllerEvent, ControllerEvent> correspondingEvents() {
|
||||
return CORRESPONDING_EVENTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerEvent peekLifecycle() {
|
||||
return lifecycleSubject.getValue();
|
||||
}
|
||||
}
|
||||
Executable → Regular
-1
@@ -29,4 +29,3 @@ dependencies {
|
||||
}
|
||||
|
||||
ext.artifactId = 'conductor-rxlifecycle'
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
<manifest package="com.bluelinelabs.conductor.rxlifecycle">
|
||||
<application />
|
||||
</manifest>
|
||||
</manifest>
|
||||
+2
@@ -3,10 +3,12 @@ package com.bluelinelabs.conductor.rxlifecycle;
|
||||
public enum ControllerEvent {
|
||||
|
||||
CREATE,
|
||||
CONTEXT_AVAILABLE,
|
||||
CREATE_VIEW,
|
||||
ATTACH,
|
||||
DETACH,
|
||||
DESTROY_VIEW,
|
||||
CONTEXT_UNAVAILABLE,
|
||||
DESTROY
|
||||
|
||||
}
|
||||
+26
-1
@@ -1,10 +1,12 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
import com.trello.rxlifecycle.OutsideLifecycleException;
|
||||
|
||||
import rx.subjects.BehaviorSubject;
|
||||
|
||||
@@ -17,9 +19,27 @@ public class ControllerLifecycleSubjectHelper {
|
||||
private ControllerLifecycleSubjectHelper() { }
|
||||
|
||||
public static BehaviorSubject<ControllerEvent> create(Controller controller) {
|
||||
final BehaviorSubject<ControllerEvent> subject = BehaviorSubject.create(ControllerEvent.CREATE);
|
||||
ControllerEvent initialState;
|
||||
if (controller.isBeingDestroyed() || controller.isDestroyed()) {
|
||||
throw new OutsideLifecycleException("Cannot bind to Controller lifecycle when outside of it.");
|
||||
} else if (controller.isAttached()) {
|
||||
initialState = ControllerEvent.ATTACH;
|
||||
} else if (controller.getView() != null) {
|
||||
initialState = ControllerEvent.CREATE_VIEW;
|
||||
} else if (controller.getActivity() != null) {
|
||||
initialState = ControllerEvent.CONTEXT_AVAILABLE;
|
||||
} else {
|
||||
initialState = ControllerEvent.CREATE;
|
||||
}
|
||||
|
||||
final BehaviorSubject<ControllerEvent> subject = BehaviorSubject.create(initialState);
|
||||
|
||||
controller.addLifecycleListener(new LifecycleListener() {
|
||||
@Override
|
||||
public void preContextAvailable(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_AVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCreateView(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CREATE_VIEW);
|
||||
@@ -40,6 +60,11 @@ public class ControllerLifecycleSubjectHelper {
|
||||
subject.onNext(ControllerEvent.DESTROY_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preContextUnavailable(@NonNull Controller controller, @NonNull Context context) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.DESTROY);
|
||||
+1
-1
@@ -49,4 +49,4 @@ public abstract class RxController extends Controller implements LifecycleProvid
|
||||
return RxControllerLifecycle.bindController(lifecycleSubject);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -17,7 +17,7 @@ public class RxControllerLifecycle {
|
||||
* {@link com.trello.rxlifecycle.android.RxLifecycleAndroid#bindFragment(Observable)}.
|
||||
*
|
||||
* @param lifecycle the lifecycle sequence of a Controller
|
||||
* @return a reusable {@link Observable.Transformer} that unsubscribes the source during the Controller lifecycle
|
||||
* @return a reusable {@link rx.Observable.Transformer} that unsubscribes the source during the Controller lifecycle
|
||||
*/
|
||||
@NonNull
|
||||
@CheckResult
|
||||
@@ -32,6 +32,8 @@ public class RxControllerLifecycle {
|
||||
switch (lastEvent) {
|
||||
case CREATE:
|
||||
return ControllerEvent.DESTROY;
|
||||
case CONTEXT_AVAILABLE:
|
||||
return ControllerEvent.CONTEXT_UNAVAILABLE;
|
||||
case ATTACH:
|
||||
return ControllerEvent.DETACH;
|
||||
case CREATE_VIEW:
|
||||
+1
-1
@@ -49,4 +49,4 @@ public abstract class RxRestoreViewOnCreateController extends RestoreViewOnCreat
|
||||
return RxControllerLifecycle.bindController(lifecycleSubject);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
<manifest package="com.bluelinelabs.conductor.rxlifecycle2">
|
||||
<application />
|
||||
</manifest>
|
||||
|
||||
+2
@@ -3,10 +3,12 @@ package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
public enum ControllerEvent {
|
||||
|
||||
CREATE,
|
||||
CONTEXT_AVAILABLE,
|
||||
CREATE_VIEW,
|
||||
ATTACH,
|
||||
DETACH,
|
||||
DESTROY_VIEW,
|
||||
CONTEXT_UNAVAILABLE,
|
||||
DESTROY
|
||||
|
||||
}
|
||||
+29
-2
@@ -1,18 +1,40 @@
|
||||
package com.bluelinelabs.conductor.rxlifecycle2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.trello.rxlifecycle2.OutsideLifecycleException;
|
||||
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
|
||||
public class ControllerLifecycleSubjectHelper {
|
||||
private ControllerLifecycleSubjectHelper() {
|
||||
}
|
||||
|
||||
public static BehaviorSubject<ControllerEvent> create(Controller controller){
|
||||
final BehaviorSubject<ControllerEvent> subject = BehaviorSubject.createDefault(ControllerEvent.CREATE);
|
||||
public static BehaviorSubject<ControllerEvent> create(Controller controller) {
|
||||
ControllerEvent initialState;
|
||||
if (controller.isBeingDestroyed() || controller.isDestroyed()) {
|
||||
throw new OutsideLifecycleException("Cannot bind to Controller lifecycle when outside of it.");
|
||||
} else if (controller.isAttached()) {
|
||||
initialState = ControllerEvent.ATTACH;
|
||||
} else if (controller.getView() != null) {
|
||||
initialState = ControllerEvent.CREATE_VIEW;
|
||||
} else if (controller.getActivity() != null) {
|
||||
initialState = ControllerEvent.CONTEXT_AVAILABLE;
|
||||
} else {
|
||||
initialState = ControllerEvent.CREATE;
|
||||
}
|
||||
|
||||
final BehaviorSubject<ControllerEvent> subject = BehaviorSubject.createDefault(initialState);
|
||||
|
||||
controller.addLifecycleListener(new Controller.LifecycleListener() {
|
||||
@Override
|
||||
public void preContextAvailable(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_AVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCreateView(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.CREATE_VIEW);
|
||||
@@ -33,6 +55,11 @@ public class ControllerLifecycleSubjectHelper {
|
||||
subject.onNext(ControllerEvent.DESTROY_VIEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preContextUnavailable(@NonNull Controller controller, @NonNull Context context) {
|
||||
subject.onNext(ControllerEvent.CONTEXT_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preDestroy(@NonNull Controller controller) {
|
||||
subject.onNext(ControllerEvent.DESTROY);
|
||||
+2
@@ -27,6 +27,8 @@ public class RxControllerLifecycle {
|
||||
switch (lastEvent) {
|
||||
case CREATE:
|
||||
return ControllerEvent.DESTROY;
|
||||
case CONTEXT_AVAILABLE:
|
||||
return ControllerEvent.CONTEXT_UNAVAILABLE;
|
||||
case ATTACH:
|
||||
return ControllerEvent.DETACH;
|
||||
case CREATE_VIEW:
|
||||
Executable → Regular
+3
-4
@@ -3,7 +3,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'de.mobilej.unmock:UnMockPlugin:0.3.6'
|
||||
classpath 'de.mobilej.unmock:UnMockPlugin:0.6.0'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ dependencies {
|
||||
|
||||
compile rootProject.ext.supportAppCompat
|
||||
compile project(':conductor')
|
||||
|
||||
unmock 'org.robolectric:android-all:4.3_r2-robolectric-0'
|
||||
}
|
||||
|
||||
unMock {
|
||||
downloadFrom 'https://oss.sonatype.org/content/groups/public/org/robolectric/android-all/4.3_r2-robolectric-0/android-all-4.3_r2-robolectric-0.jar'
|
||||
|
||||
keep "android.os.Bundle"
|
||||
keep "android.os.BaseBundle"
|
||||
}
|
||||
@@ -46,4 +46,3 @@ ext.artifactId = 'conductor-support'
|
||||
|
||||
apply from: rootProject.file('dependencies.gradle')
|
||||
apply from: rootProject.file('gradle-mvn-push.gradle')
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
<manifest package="com.bluelinelabs.conductor.support">
|
||||
<application />
|
||||
</manifest>
|
||||
</manifest>
|
||||
+1
-1
@@ -158,4 +158,4 @@ public abstract class RouterPagerAdapter extends PagerAdapter {
|
||||
return viewId + ":" + id;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Executable → Regular
+3
-3
@@ -3,7 +3,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'de.mobilej.unmock:UnMockPlugin:0.3.6'
|
||||
classpath 'de.mobilej.unmock:UnMockPlugin:0.6.0'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,11 @@ dependencies {
|
||||
compile rootProject.ext.supportAnnotations
|
||||
|
||||
lintChecks project(path: ':conductor-lint', configuration: 'lintChecks')
|
||||
|
||||
unmock 'org.robolectric:android-all:4.3_r2-robolectric-0'
|
||||
}
|
||||
|
||||
unMock {
|
||||
downloadFrom 'https://oss.sonatype.org/content/groups/public/org/robolectric/android-all/4.3_r2-robolectric-0/android-all-4.3_r2-robolectric-0.jar'
|
||||
|
||||
keep "android.os.Bundle"
|
||||
keep "android.os.BaseBundle"
|
||||
keep "android.text.TextUtils"
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
-keepclassmembers public class * extends com.bluelinelabs.conductor.Controller {
|
||||
public <init>();
|
||||
public <init>(android.os.Bundle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<manifest package="com.bluelinelabs.conductor">
|
||||
<application />
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -32,6 +32,8 @@ public class ActivityHostedRouter extends Router {
|
||||
|
||||
this.lifecycleHandler = lifecycleHandler;
|
||||
this.container = container;
|
||||
|
||||
watchContainerAttach();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,4 +129,10 @@ public class ActivityHostedRouter extends Router {
|
||||
TransactionIndexer getTransactionIndexer() {
|
||||
return transactionIndexer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContextAvailable() {
|
||||
super.onContextAvailable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Executable → Regular
@@ -8,14 +8,15 @@ import android.support.annotation.UiThread;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.internal.LifecycleHandler;
|
||||
import com.bluelinelabs.conductor.internal.ThreadUtils;
|
||||
|
||||
/**
|
||||
* Point of initial interaction with Conductor. Used to attach a {@link Router} to your Activity.
|
||||
*/
|
||||
public final class Conductor {
|
||||
|
||||
|
||||
private Conductor() {}
|
||||
|
||||
|
||||
/**
|
||||
* Conductor will create a {@link Router} that has been initialized for your Activity and containing ViewGroup.
|
||||
* If an existing {@link Router} is already associated with this Activity/ViewGroup pair, either in memory
|
||||
@@ -30,6 +31,8 @@ public final class Conductor {
|
||||
*/
|
||||
@NonNull @UiThread
|
||||
public static Router attachRouter(@NonNull Activity activity, @NonNull ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
LifecycleHandler lifecycleHandler = LifecycleHandler.install(activity);
|
||||
|
||||
Router router = lifecycleHandler.getRouter(container, savedInstanceState);
|
||||
|
||||
Executable → Regular
+111
-15
@@ -55,7 +55,7 @@ public abstract class Controller {
|
||||
private static final String KEY_OVERRIDDEN_PUSH_HANDLER = "Controller.overriddenPushHandler";
|
||||
private static final String KEY_OVERRIDDEN_POP_HANDLER = "Controller.overriddenPopHandler";
|
||||
private static final String KEY_VIEW_STATE_HIERARCHY = "Controller.viewState.hierarchy";
|
||||
private static final String KEY_VIEW_STATE_BUNDLE = "Controller.viewState.bundle";
|
||||
static final String KEY_VIEW_STATE_BUNDLE = "Controller.viewState.bundle";
|
||||
private static final String KEY_RETAIN_VIEW_MODE = "Controller.retainViewMode";
|
||||
|
||||
private final Bundle args;
|
||||
@@ -87,21 +87,34 @@ public abstract class Controller {
|
||||
private final ArrayList<String> requestedPermissions = new ArrayList<>();
|
||||
private final ArrayList<RouterRequiringFunc> onRouterSetListeners = new ArrayList<>();
|
||||
private WeakReference<View> destroyedView;
|
||||
private boolean isPerformingExitTransition;
|
||||
private boolean isContextAvailable;
|
||||
|
||||
@NonNull
|
||||
static Controller newInstance(@NonNull Bundle bundle) {
|
||||
final String className = bundle.getString(KEY_CLASS_NAME);
|
||||
//noinspection ConstantConditions
|
||||
Constructor[] constructors = ClassUtils.classForName(className, false).getConstructors();
|
||||
Class cls = ClassUtils.classForName(className, false);
|
||||
Constructor[] constructors = cls.getConstructors();
|
||||
Constructor bundleConstructor = getBundleConstructor(constructors);
|
||||
|
||||
Bundle args = bundle.getBundle(KEY_ARGS);
|
||||
if (args != null) {
|
||||
args.setClassLoader(cls.getClassLoader());
|
||||
}
|
||||
|
||||
Controller controller;
|
||||
try {
|
||||
if (bundleConstructor != null) {
|
||||
controller = (Controller)bundleConstructor.newInstance(bundle.getBundle(KEY_ARGS));
|
||||
controller = (Controller)bundleConstructor.newInstance(args);
|
||||
} else {
|
||||
//noinspection ConstantConditions
|
||||
controller = (Controller)getDefaultConstructor(constructors).newInstance();
|
||||
|
||||
// Restore the args that existed before the last process death
|
||||
if (args != null) {
|
||||
controller.args.putAll(args);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("An exception occurred while creating a new instance of " + className + ". " + e.getMessage(), e);
|
||||
@@ -124,7 +137,7 @@ public abstract class Controller {
|
||||
* @param args Any arguments that need to be retained.
|
||||
*/
|
||||
protected Controller(@Nullable Bundle args) {
|
||||
this.args = args != null ? args : new Bundle();
|
||||
this.args = args != null ? args : new Bundle(getClass().getClassLoader());
|
||||
instanceId = UUID.randomUUID().toString();
|
||||
ensureRequiredConstructor();
|
||||
}
|
||||
@@ -211,6 +224,10 @@ public abstract class Controller {
|
||||
childRouter = new ControllerHostedRouter(container.getId(), tag);
|
||||
childRouter.setHost(this, container);
|
||||
childRouters.add(childRouter);
|
||||
|
||||
if (isPerformingExitTransition) {
|
||||
childRouter.setDetachFrozen(true);
|
||||
}
|
||||
}
|
||||
} else if (!childRouter.hasHost()) {
|
||||
childRouter.setHost(this, container);
|
||||
@@ -395,6 +412,19 @@ public abstract class Controller {
|
||||
*/
|
||||
protected void onChangeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) { }
|
||||
|
||||
/**
|
||||
* Called when this Controller has a Context available to it. This will happen very early on in the lifecycle
|
||||
* (before a view is created). If the host activity is re-created (ex: for orientation change), this will be
|
||||
* called again when the new context is available.
|
||||
*/
|
||||
protected void onContextAvailable(@NonNull Context context) { }
|
||||
|
||||
/**
|
||||
* Called when this Controller's Context is no longer available. This can happen when the Controller is
|
||||
* destroyed or when the host Activity is destroyed.
|
||||
*/
|
||||
protected void onContextUnavailable() { }
|
||||
|
||||
/**
|
||||
* Called when this Controller is attached to its host ViewGroup
|
||||
*
|
||||
@@ -546,7 +576,7 @@ public abstract class Controller {
|
||||
* @param permission A permission this Controller has requested
|
||||
*/
|
||||
public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
|
||||
return false;
|
||||
return Build.VERSION.SDK_INT >= 23 && getActivity().shouldShowRequestPermissionRationale(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -593,7 +623,7 @@ public abstract class Controller {
|
||||
*
|
||||
* @param lifecycleListener The listener
|
||||
*/
|
||||
public void addLifecycleListener(@NonNull LifecycleListener lifecycleListener) {
|
||||
public final void addLifecycleListener(@NonNull LifecycleListener lifecycleListener) {
|
||||
if (!lifecycleListeners.contains(lifecycleListener)) {
|
||||
lifecycleListeners.add(lifecycleListener);
|
||||
}
|
||||
@@ -604,7 +634,7 @@ public abstract class Controller {
|
||||
*
|
||||
* @param lifecycleListener The listener to be removed
|
||||
*/
|
||||
public void removeLifecycleListener(@NonNull LifecycleListener lifecycleListener) {
|
||||
public final void removeLifecycleListener(@NonNull LifecycleListener lifecycleListener) {
|
||||
lifecycleListeners.remove(lifecycleListener);
|
||||
}
|
||||
|
||||
@@ -721,8 +751,8 @@ public abstract class Controller {
|
||||
return false;
|
||||
}
|
||||
|
||||
final void setNeedsAttach() {
|
||||
needsAttach = true;
|
||||
final void setNeedsAttach(boolean needsAttach) {
|
||||
this.needsAttach = needsAttach;
|
||||
}
|
||||
|
||||
final void prepareForHostDetach() {
|
||||
@@ -761,6 +791,29 @@ public abstract class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
final void onContextAvailable() {
|
||||
final Context context = router.getActivity();
|
||||
|
||||
if (context != null && !isContextAvailable) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.preContextAvailable(this);
|
||||
}
|
||||
|
||||
isContextAvailable = true;
|
||||
onContextAvailable(context);
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postContextAvailable(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
for (Router childRouter : childRouters) {
|
||||
childRouter.onContextAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
final void executeWithRouter(@NonNull RouterRequiringFunc listener) {
|
||||
if (router != null) {
|
||||
listener.execute();
|
||||
@@ -799,12 +852,27 @@ public abstract class Controller {
|
||||
onActivityStopped(activity);
|
||||
}
|
||||
|
||||
final void activityDestroyed(boolean isChangingConfigurations) {
|
||||
if (isChangingConfigurations) {
|
||||
final void activityDestroyed(@NonNull Activity activity) {
|
||||
if (activity.isChangingConfigurations()) {
|
||||
detach(view, true, false);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void attach(@NonNull View view) {
|
||||
@@ -831,7 +899,7 @@ public abstract class Controller {
|
||||
|
||||
listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
lifecycleListener.postAttach(this, view);
|
||||
lifecycleListener.postAttach(Controller.this, view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,6 +1044,21 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
private void performDestroy() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (!destroyed) {
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
for (LifecycleListener lifecycleListener : listeners) {
|
||||
@@ -1026,7 +1109,7 @@ public abstract class Controller {
|
||||
view.saveHierarchyState(hierarchyState);
|
||||
viewState.putSparseParcelableArray(KEY_VIEW_STATE_HIERARCHY, hierarchyState);
|
||||
|
||||
Bundle stateBundle = new Bundle();
|
||||
Bundle stateBundle = new Bundle(getClass().getClassLoader());
|
||||
onSaveViewState(view, stateBundle);
|
||||
viewState.putBundle(KEY_VIEW_STATE_BUNDLE, stateBundle);
|
||||
|
||||
@@ -1039,7 +1122,9 @@ public abstract class Controller {
|
||||
private void restoreViewState(@NonNull View view) {
|
||||
if (viewState != null) {
|
||||
view.restoreHierarchyState(viewState.getSparseParcelableArray(KEY_VIEW_STATE_HIERARCHY));
|
||||
onRestoreViewState(view, viewState.getBundle(KEY_VIEW_STATE_BUNDLE));
|
||||
Bundle savedViewState = viewState.getBundle(KEY_VIEW_STATE_BUNDLE);
|
||||
savedViewState.setClassLoader(getClass().getClassLoader());
|
||||
onRestoreViewState(view, savedViewState);
|
||||
|
||||
restoreChildControllerHosts();
|
||||
|
||||
@@ -1080,7 +1165,7 @@ public abstract class Controller {
|
||||
}
|
||||
outState.putParcelableArrayList(KEY_CHILD_ROUTERS, childBundles);
|
||||
|
||||
Bundle savedState = new Bundle();
|
||||
Bundle savedState = new Bundle(getClass().getClassLoader());
|
||||
onSaveInstanceState(savedState);
|
||||
|
||||
List<LifecycleListener> listeners = new ArrayList<>(lifecycleListeners);
|
||||
@@ -1115,6 +1200,9 @@ public abstract class Controller {
|
||||
}
|
||||
|
||||
this.savedInstanceState = savedInstanceState.getBundle(KEY_SAVED_STATE);
|
||||
if (this.savedInstanceState != null) {
|
||||
this.savedInstanceState.setClassLoader(getClass().getClassLoader());
|
||||
}
|
||||
performOnRestoreInstanceState();
|
||||
}
|
||||
|
||||
@@ -1133,6 +1221,7 @@ public abstract class Controller {
|
||||
|
||||
final void changeStarted(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
if (!changeType.isEnter) {
|
||||
isPerformingExitTransition = true;
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.setDetachFrozen(true);
|
||||
}
|
||||
@@ -1148,6 +1237,7 @@ public abstract class Controller {
|
||||
|
||||
final void changeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
if (!changeType.isEnter) {
|
||||
isPerformingExitTransition = false;
|
||||
for (ControllerHostedRouter router : childRouters) {
|
||||
router.setDetachFrozen(false);
|
||||
}
|
||||
@@ -1259,6 +1349,12 @@ public abstract class Controller {
|
||||
public void preDestroy(@NonNull Controller controller) { }
|
||||
public void postDestroy(@NonNull Controller controller) { }
|
||||
|
||||
public void preContextAvailable(@NonNull Controller controller) { }
|
||||
public void postContextAvailable(@NonNull Controller controller, @NonNull Context context) { }
|
||||
|
||||
public void preContextUnavailable(@NonNull Controller controller, @NonNull Context context) { }
|
||||
public void postContextUnavailable(@NonNull Controller controller) { }
|
||||
|
||||
public void onSaveInstanceState(@NonNull Controller controller, @NonNull Bundle outState) { }
|
||||
public void onRestoreInstanceState(@NonNull Controller controller, @NonNull Bundle savedInstanceState) { }
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public abstract class ControllerChangeHandler {
|
||||
private static final String KEY_CLASS_NAME = "ControllerChangeHandler.className";
|
||||
private static final String KEY_SAVED_STATE = "ControllerChangeHandler.savedState";
|
||||
|
||||
private static final Map<String, ControllerChangeHandler> inProgressPushHandlers = new HashMap<>();
|
||||
private static final Map<String, ChangeHandlerData> inProgressChangeHandlers = new HashMap<>();
|
||||
|
||||
private boolean forceRemoveViewOnPush;
|
||||
private boolean hasBeenUsed;
|
||||
@@ -127,29 +127,34 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
static boolean completePushImmediately(@NonNull String controllerInstanceId) {
|
||||
ControllerChangeHandler changeHandler = inProgressPushHandlers.get(controllerInstanceId);
|
||||
if (changeHandler != null) {
|
||||
changeHandler.completeImmediately();
|
||||
inProgressPushHandlers.remove(controllerInstanceId);
|
||||
static boolean completeHandlerImmediately(@NonNull String controllerInstanceId) {
|
||||
ChangeHandlerData changeHandlerData = inProgressChangeHandlers.get(controllerInstanceId);
|
||||
if (changeHandlerData != null) {
|
||||
changeHandlerData.changeHandler.completeImmediately();
|
||||
inProgressChangeHandlers.remove(controllerInstanceId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void abortPush(@NonNull Controller toAbort, @Nullable Controller newController, @NonNull ControllerChangeHandler newChangeHandler) {
|
||||
ControllerChangeHandler handlerForPush = inProgressPushHandlers.get(toAbort.getInstanceId());
|
||||
if (handlerForPush != null) {
|
||||
handlerForPush.onAbortPush(newChangeHandler, newController);
|
||||
inProgressPushHandlers.remove(toAbort.getInstanceId());
|
||||
static void abortOrComplete(@NonNull Controller toAbort, @Nullable Controller newController, @NonNull ControllerChangeHandler newChangeHandler) {
|
||||
ChangeHandlerData changeHandlerData = inProgressChangeHandlers.get(toAbort.getInstanceId());
|
||||
if (changeHandlerData != null) {
|
||||
if (changeHandlerData.isPush) {
|
||||
changeHandlerData.changeHandler.onAbortPush(newChangeHandler, newController);
|
||||
} else {
|
||||
changeHandlerData.changeHandler.completeImmediately();
|
||||
}
|
||||
|
||||
inProgressChangeHandlers.remove(toAbort.getInstanceId());
|
||||
}
|
||||
}
|
||||
|
||||
static void executeChange(@Nullable final Controller to, @Nullable final Controller from, final boolean isPush, @Nullable final ViewGroup container, @Nullable final ControllerChangeHandler inHandler, @NonNull final List<ControllerChangeListener> listeners) {
|
||||
if (isPush && to != null && to.isDestroyed()) {
|
||||
throw new IllegalStateException("Trying to push a controller that has already been destroyed. (" + to.getClass().getSimpleName() + ")");
|
||||
}
|
||||
static void executeChange(@NonNull final ChangeTransaction transaction) {
|
||||
executeChange(transaction.to, transaction.from, transaction.isPush, transaction.container, transaction.changeHandler, transaction.listeners);
|
||||
}
|
||||
|
||||
private static void executeChange(@Nullable final Controller to, @Nullable final Controller from, final boolean isPush, @Nullable final ViewGroup container, @Nullable final ControllerChangeHandler inHandler, @NonNull final List<ControllerChangeListener> listeners) {
|
||||
if (container != null) {
|
||||
final ControllerChangeHandler handler;
|
||||
if (inHandler == null) {
|
||||
@@ -161,14 +166,16 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
handler.hasBeenUsed = true;
|
||||
|
||||
if (isPush && to != null) {
|
||||
inProgressPushHandlers.put(to.getInstanceId(), handler);
|
||||
|
||||
if (from != null) {
|
||||
completePushImmediately(from.getInstanceId());
|
||||
if (from != null) {
|
||||
if (isPush) {
|
||||
completeHandlerImmediately(from.getInstanceId());
|
||||
} else {
|
||||
abortOrComplete(from, to, handler);
|
||||
}
|
||||
} else if (!isPush && from != null) {
|
||||
abortPush(from, to, handler);
|
||||
}
|
||||
|
||||
if (to != null) {
|
||||
inProgressChangeHandlers.put(to.getInstanceId(), new ChangeHandlerData(handler, isPush));
|
||||
}
|
||||
|
||||
for (ControllerChangeListener listener : listeners) {
|
||||
@@ -202,7 +209,7 @@ public abstract class ControllerChangeHandler {
|
||||
}
|
||||
|
||||
if (to != null) {
|
||||
inProgressPushHandlers.remove(to.getInstanceId());
|
||||
inProgressChangeHandlers.remove(to.getInstanceId());
|
||||
to.changeEnded(handler, toChangeType);
|
||||
}
|
||||
|
||||
@@ -216,6 +223,10 @@ public abstract class ControllerChangeHandler {
|
||||
((ViewGroup)fromParent).removeView(fromView);
|
||||
}
|
||||
}
|
||||
|
||||
if (handler.removesFromViewOnPush() && from != null) {
|
||||
from.setNeedsAttach(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -229,6 +240,24 @@ public abstract class ControllerChangeHandler {
|
||||
forceRemoveViewOnPush = force;
|
||||
}
|
||||
|
||||
static class ChangeTransaction {
|
||||
@Nullable final Controller to;
|
||||
@Nullable final Controller from;
|
||||
final boolean isPush;
|
||||
@Nullable final ViewGroup container;
|
||||
@Nullable final ControllerChangeHandler changeHandler;
|
||||
@NonNull final List<ControllerChangeListener> listeners;
|
||||
|
||||
public ChangeTransaction(@Nullable Controller to, @Nullable Controller from, boolean isPush, @Nullable ViewGroup container, @Nullable ControllerChangeHandler changeHandler, @NonNull List<ControllerChangeListener> listeners) {
|
||||
this.to = to;
|
||||
this.from = from;
|
||||
this.isPush = isPush;
|
||||
this.container = container;
|
||||
this.changeHandler = changeHandler;
|
||||
this.listeners = listeners;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener interface useful for allowing external classes to be notified of change events.
|
||||
*/
|
||||
@@ -267,4 +296,14 @@ public abstract class ControllerChangeHandler {
|
||||
void onChangeCompleted();
|
||||
}
|
||||
|
||||
private static class ChangeHandlerData {
|
||||
public final ControllerChangeHandler changeHandler;
|
||||
public final boolean isPush;
|
||||
|
||||
public ChangeHandlerData(ControllerChangeHandler changeHandler, boolean isPush) {
|
||||
this.changeHandler = changeHandler;
|
||||
this.isPush = isPush;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ class ControllerHostedRouter extends Router {
|
||||
|
||||
@IdRes private int hostId;
|
||||
private String tag;
|
||||
private boolean isDetachFrozen;
|
||||
|
||||
ControllerHostedRouter() { }
|
||||
|
||||
@@ -43,6 +44,12 @@ class ControllerHostedRouter extends Router {
|
||||
|
||||
hostController = controller;
|
||||
this.container = container;
|
||||
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.setParentController(controller);
|
||||
}
|
||||
|
||||
watchContainerAttach();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +76,7 @@ class ControllerHostedRouter extends Router {
|
||||
}
|
||||
|
||||
final void setDetachFrozen(boolean frozen) {
|
||||
isDetachFrozen = frozen;
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.setDetachFrozen(frozen);
|
||||
}
|
||||
@@ -80,6 +88,24 @@ class ControllerHostedRouter extends Router {
|
||||
super.destroy(popViews);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void pushToBackstack(@NonNull RouterTransaction entry) {
|
||||
if (isDetachFrozen) {
|
||||
entry.controller.setDetachFrozen(true);
|
||||
}
|
||||
super.pushToBackstack(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackstack(@NonNull List<RouterTransaction> newBackstack, @Nullable ControllerChangeHandler changeHandler) {
|
||||
if (isDetachFrozen) {
|
||||
for (RouterTransaction transaction : newBackstack) {
|
||||
transaction.controller.setDetachFrozen(true);
|
||||
}
|
||||
}
|
||||
super.setBackstack(newBackstack, changeHandler);
|
||||
}
|
||||
|
||||
@Override @Nullable
|
||||
public Activity getActivity() {
|
||||
return hostController != null ? hostController.getActivity() : null;
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ abstract public class RestoreViewOnCreateController extends Controller {
|
||||
|
||||
@Override @NonNull
|
||||
protected final View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return onCreateView(inflater, container, viewState);
|
||||
return onCreateView(inflater, container, viewState == null ? null : viewState.getBundle(KEY_VIEW_STATE_BUNDLE));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Executable → Regular
+125
-19
@@ -14,9 +14,11 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller.LifecycleListener;
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler.ChangeTransaction;
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener;
|
||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
|
||||
import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.internal.ThreadUtils;
|
||||
import com.bluelinelabs.conductor.internal.TransactionIndexer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -34,11 +36,13 @@ public abstract class Router {
|
||||
private static final String KEY_BACKSTACK = "Router.backstack";
|
||||
private static final String KEY_POPS_LAST_VIEW = "Router.popsLastView";
|
||||
|
||||
protected final Backstack backstack = new Backstack();
|
||||
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;
|
||||
boolean containerFullyAttached = false;
|
||||
|
||||
ViewGroup container;
|
||||
|
||||
@@ -83,6 +87,8 @@ public abstract class Router {
|
||||
*/
|
||||
@UiThread
|
||||
public boolean handleBack() {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
if (!backstack.isEmpty()) {
|
||||
//noinspection ConstantConditions
|
||||
if (backstack.peek().controller.handleBack()) {
|
||||
@@ -103,6 +109,8 @@ public abstract class Router {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@UiThread
|
||||
public boolean popCurrentController() {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
RouterTransaction transaction = backstack.peek();
|
||||
if (transaction == null) {
|
||||
throw new IllegalStateException("Trying to pop the current controller when there are none on the backstack.");
|
||||
@@ -118,26 +126,39 @@ public abstract class Router {
|
||||
*/
|
||||
@UiThread
|
||||
public boolean popController(@NonNull Controller controller) {
|
||||
RouterTransaction topController = backstack.peek();
|
||||
boolean poppingTopController = topController != null && topController.controller == controller;
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
RouterTransaction topTransaction = backstack.peek();
|
||||
boolean poppingTopController = topTransaction != null && topTransaction.controller == controller;
|
||||
|
||||
if (poppingTopController) {
|
||||
trackDestroyingController(backstack.pop());
|
||||
performControllerChange(backstack.peek(), topTransaction, false);
|
||||
} else {
|
||||
RouterTransaction removedTransaction = null;
|
||||
RouterTransaction nextTransaction = null;
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (transaction.controller == controller) {
|
||||
if (controller.isAttached()) {
|
||||
trackDestroyingController(transaction);
|
||||
}
|
||||
backstack.remove(transaction);
|
||||
removedTransaction = transaction;
|
||||
} else if (removedTransaction != null) {
|
||||
if (!transaction.controller.isAttached()) {
|
||||
nextTransaction = transaction;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (poppingTopController) {
|
||||
performControllerChange(backstack.peek(), topController, false);
|
||||
if (removedTransaction != null) {
|
||||
performControllerChange(nextTransaction, removedTransaction, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (popsLastView) {
|
||||
return topController != null;
|
||||
return topTransaction != null;
|
||||
} else {
|
||||
return !backstack.isEmpty();
|
||||
}
|
||||
@@ -151,6 +172,8 @@ public abstract class Router {
|
||||
*/
|
||||
@UiThread
|
||||
public void pushController(@NonNull RouterTransaction transaction) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
RouterTransaction from = backstack.peek();
|
||||
pushToBackstack(transaction);
|
||||
performControllerChange(transaction, from, true);
|
||||
@@ -165,6 +188,8 @@ public abstract class Router {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@UiThread
|
||||
public void replaceTopController(@NonNull RouterTransaction transaction) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
RouterTransaction topTransaction = backstack.peek();
|
||||
if (!backstack.isEmpty()) {
|
||||
trackDestroyingController(backstack.pop());
|
||||
@@ -235,6 +260,8 @@ public abstract class Router {
|
||||
*/
|
||||
@UiThread
|
||||
public boolean popToRoot() {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
return popToRoot(null);
|
||||
}
|
||||
|
||||
@@ -247,6 +274,8 @@ public abstract class Router {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@UiThread
|
||||
public boolean popToRoot(@Nullable ControllerChangeHandler changeHandler) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
if (backstack.size() > 1) {
|
||||
//noinspection ConstantConditions
|
||||
popToTransaction(backstack.root(), changeHandler);
|
||||
@@ -264,6 +293,8 @@ public abstract class Router {
|
||||
*/
|
||||
@UiThread
|
||||
public boolean popToTag(@NonNull String tag) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
return popToTag(tag, null);
|
||||
}
|
||||
|
||||
@@ -277,6 +308,8 @@ public abstract class Router {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@UiThread
|
||||
public boolean popToTag(@NonNull String tag, @Nullable ControllerChangeHandler changeHandler) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (tag.equals(transaction.tag())) {
|
||||
popToTransaction(transaction, changeHandler);
|
||||
@@ -294,6 +327,8 @@ public abstract class Router {
|
||||
*/
|
||||
@UiThread
|
||||
public void setRoot(@NonNull RouterTransaction transaction) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
List<RouterTransaction> transactions = Collections.singletonList(transaction);
|
||||
setBackstack(transactions, transaction.pushChangeHandler());
|
||||
}
|
||||
@@ -362,6 +397,8 @@ public abstract class Router {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@UiThread
|
||||
public void setBackstack(@NonNull List<RouterTransaction> newBackstack, @Nullable ControllerChangeHandler changeHandler) {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
List<RouterTransaction> oldVisibleTransactions = getVisibleTransactions(backstack.iterator());
|
||||
|
||||
boolean newRootRequiresPush = !(newBackstack.size() > 0 && backstack.contains(newBackstack.get(0)));
|
||||
@@ -381,10 +418,16 @@ public abstract class Router {
|
||||
|
||||
boolean visibleTransactionsChanged = !backstacksAreEqual(newVisibleTransactions, oldVisibleTransactions);
|
||||
if (visibleTransactionsChanged) {
|
||||
RouterTransaction rootTransaction = oldVisibleTransactions.size() > 0 ? oldVisibleTransactions.get(0) : null;
|
||||
RouterTransaction oldRootTransaction = oldVisibleTransactions.size() > 0 ? oldVisibleTransactions.get(0) : null;
|
||||
RouterTransaction newRootTransaction = newVisibleTransactions.get(0);
|
||||
|
||||
// Replace the old root with the new one
|
||||
if (rootTransaction == null || rootTransaction.controller != newVisibleTransactions.get(0).controller) {
|
||||
performControllerChange(newVisibleTransactions.get(0), rootTransaction, newRootRequiresPush, changeHandler);
|
||||
if (oldRootTransaction == null || oldRootTransaction.controller != newRootTransaction.controller) {
|
||||
// Ensure the existing root controller is fully pushed to the view hierarchy
|
||||
if (oldRootTransaction != null) {
|
||||
ControllerChangeHandler.completeHandlerImmediately(oldRootTransaction.controller.getInstanceId());
|
||||
}
|
||||
performControllerChange(newRootTransaction, oldRootTransaction, newRootRequiresPush, changeHandler);
|
||||
}
|
||||
|
||||
// Remove all visible controllers that were previously on the backstack
|
||||
@@ -393,6 +436,7 @@ public abstract class Router {
|
||||
if (!newVisibleTransactions.contains(transaction)) {
|
||||
ControllerChangeHandler localHandler = changeHandler != null ? changeHandler.copy() : new SimpleSwapChangeHandler();
|
||||
localHandler.setForceRemoveViewOnPush(true);
|
||||
ControllerChangeHandler.completeHandlerImmediately(transaction.controller.getInstanceId());
|
||||
performControllerChange(null, transaction, newRootRequiresPush, localHandler);
|
||||
}
|
||||
}
|
||||
@@ -447,6 +491,8 @@ public abstract class Router {
|
||||
*/
|
||||
@UiThread
|
||||
public void rebindIfNeeded() {
|
||||
ThreadUtils.ensureMainThread();
|
||||
|
||||
Iterator<RouterTransaction> backstackIterator = backstack.reverseIterator();
|
||||
while (backstackIterator.hasNext()) {
|
||||
RouterTransaction transaction = backstackIterator.next();
|
||||
@@ -509,7 +555,7 @@ public abstract class Router {
|
||||
changeListeners.clear();
|
||||
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.activityDestroyed(activity.isChangingConfigurations());
|
||||
transaction.controller.activityDestroyed(activity);
|
||||
|
||||
for (Router childRouter : transaction.controller.getChildRouters()) {
|
||||
childRouter.onActivityDestroyed(activity);
|
||||
@@ -518,7 +564,7 @@ public abstract class Router {
|
||||
|
||||
for (int index = destroyingControllers.size() - 1; index >= 0; index--) {
|
||||
Controller controller = destroyingControllers.get(index);
|
||||
controller.activityDestroyed(activity.isChangingConfigurations());
|
||||
controller.activityDestroyed(activity);
|
||||
|
||||
for (Router childRouter : controller.getChildRouters()) {
|
||||
childRouter.onActivityDestroyed(activity);
|
||||
@@ -530,8 +576,8 @@ public abstract class Router {
|
||||
|
||||
void prepareForHostDetach() {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
if (ControllerChangeHandler.completePushImmediately(transaction.controller.getInstanceId())) {
|
||||
transaction.controller.setNeedsAttach();
|
||||
if (ControllerChangeHandler.completeHandlerImmediately(transaction.controller.getInstanceId())) {
|
||||
transaction.controller.setNeedsAttach(true);
|
||||
}
|
||||
transaction.controller.prepareForHostDetach();
|
||||
}
|
||||
@@ -617,12 +663,29 @@ public abstract class Router {
|
||||
}
|
||||
}
|
||||
|
||||
void watchContainerAttach() {
|
||||
container.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
containerFullyAttached = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void prepareForContainerRemoval() {
|
||||
containerFullyAttached = false;
|
||||
|
||||
if (container != null) {
|
||||
container.setOnHierarchyChangeListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
void onContextAvailable() {
|
||||
for (RouterTransaction transaction : backstack) {
|
||||
transaction.controller.onContextAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
final List<Controller> getControllers() {
|
||||
List<Controller> controllers = new ArrayList<>();
|
||||
@@ -663,23 +726,65 @@ public abstract class Router {
|
||||
performControllerChange(to, from, isPush, changeHandler);
|
||||
}
|
||||
|
||||
private void performControllerChange(@Nullable final RouterTransaction to, @Nullable final RouterTransaction from, boolean isPush, @Nullable ControllerChangeHandler changeHandler) {
|
||||
private void performControllerChange(@Nullable RouterTransaction to, @Nullable RouterTransaction from, boolean isPush, @Nullable ControllerChangeHandler changeHandler) {
|
||||
Controller toController = to != null ? to.controller : null;
|
||||
Controller fromController = from != null ? from.controller : null;
|
||||
boolean forceDetachDestroy = false;
|
||||
|
||||
if (to != null) {
|
||||
to.ensureValidIndex(getTransactionIndexer());
|
||||
setControllerRouter(toController);
|
||||
} else if (backstack.size() == 0 && !popsLastView) {
|
||||
// We're emptying out the backstack. Views get weird if you transition them out, so just no-op it. The hosting
|
||||
// Activity should be handling this by finishing or at least hiding this 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();
|
||||
forceDetachDestroy = true;
|
||||
}
|
||||
|
||||
ControllerChangeHandler.executeChange(toController, fromController, isPush, container, changeHandler, changeListeners);
|
||||
performControllerChange(toController, fromController, isPush, changeHandler);
|
||||
|
||||
if (forceDetachDestroy && fromController != null && fromController.getView() != null) {
|
||||
fromController.detach(fromController.getView(), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void pushToBackstack(@NonNull RouterTransaction entry) {
|
||||
private void performControllerChange(@Nullable final Controller to, @Nullable final Controller from, final boolean isPush, @Nullable final ControllerChangeHandler changeHandler) {
|
||||
if (isPush && to != null && to.isDestroyed()) {
|
||||
throw new IllegalStateException("Trying to push a controller that has already been destroyed. (" + to.getClass().getSimpleName() + ")");
|
||||
}
|
||||
|
||||
final ChangeTransaction transaction = new ChangeTransaction(to, from, isPush, container, changeHandler, changeListeners);
|
||||
|
||||
if (pendingControllerChanges.size() > 0) {
|
||||
// If we already have changes queued up (awaiting full container attach), queue this one up as well so they don't happen
|
||||
// out of order.
|
||||
pendingControllerChanges.add(transaction);
|
||||
} else if (from != null && (changeHandler == null || changeHandler.removesFromViewOnPush()) && !containerFullyAttached) {
|
||||
// If the change handler will remove the from view, we have to make sure the container is fully attached first so we avoid NPEs
|
||||
// within ViewGroup (details on issue #287). Post this to the container to ensure the attach is complete before we try to remove
|
||||
// anything.
|
||||
pendingControllerChanges.add(transaction);
|
||||
container.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
performPendingControllerChanges();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ControllerChangeHandler.executeChange(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
void performPendingControllerChanges() {
|
||||
// We're intentionally using dynamic size checking (list.size()) here so we can account for changes
|
||||
// that occur during this loop (ex: if a controller is popped from within onAttach)
|
||||
for (int i = 0; i < pendingControllerChanges.size(); i++) {
|
||||
ControllerChangeHandler.executeChange(pendingControllerChanges.get(i));
|
||||
}
|
||||
pendingControllerChanges.clear();
|
||||
}
|
||||
|
||||
protected void pushToBackstack(@NonNull RouterTransaction entry) {
|
||||
backstack.push(entry);
|
||||
}
|
||||
|
||||
@@ -786,6 +891,7 @@ public abstract class Router {
|
||||
|
||||
void setControllerRouter(@NonNull Controller controller) {
|
||||
controller.setRouter(this);
|
||||
controller.onContextAvailable();
|
||||
}
|
||||
|
||||
abstract void invalidateOptionsMenu();
|
||||
|
||||
@@ -140,4 +140,4 @@ public class RouterTransaction {
|
||||
return bundle;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+65
-11
@@ -21,6 +21,7 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
private static final String KEY_DURATION = "AnimatorChangeHandler.duration";
|
||||
private static final String KEY_REMOVES_FROM_ON_PUSH = "AnimatorChangeHandler.removesFromViewOnPush";
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static final long DEFAULT_ANIMATION_DURATION = -1;
|
||||
|
||||
private long animationDuration;
|
||||
@@ -29,15 +30,19 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
private boolean needsImmediateCompletion;
|
||||
private boolean completed;
|
||||
private Animator animator;
|
||||
private OnAnimationReadyOrAbortedListener onAnimationReadyOrAbortedListener;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public AnimatorChangeHandler() {
|
||||
this(DEFAULT_ANIMATION_DURATION, true);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public AnimatorChangeHandler(boolean removesFromViewOnPush) {
|
||||
this(DEFAULT_ANIMATION_DURATION, removesFromViewOnPush);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public AnimatorChangeHandler(long duration) {
|
||||
this(duration, true);
|
||||
}
|
||||
@@ -68,6 +73,8 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
canceled = true;
|
||||
if (animator != null) {
|
||||
animator.cancel();
|
||||
} else if (onAnimationReadyOrAbortedListener != null) {
|
||||
onAnimationReadyOrAbortedListener.onReadyOrAborted();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +85,8 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
needsImmediateCompletion = true;
|
||||
if (animator != null) {
|
||||
animator.end();
|
||||
} else if (onAnimationReadyOrAbortedListener != null) {
|
||||
onAnimationReadyOrAbortedListener.onReadyOrAborted();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,17 +130,8 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
if (to.getWidth() <= 0 && to.getHeight() <= 0) {
|
||||
readyToAnimate = false;
|
||||
to.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
final ViewTreeObserver observer = to.getViewTreeObserver();
|
||||
if (observer.isAlive()) {
|
||||
observer.removeOnPreDrawListener(this);
|
||||
}
|
||||
performAnimation(container, from, to, isPush, addingToView, changeListener);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
onAnimationReadyOrAbortedListener = new OnAnimationReadyOrAbortedListener(container, from, to, isPush, true, changeListener);
|
||||
to.getViewTreeObserver().addOnPreDrawListener(onAnimationReadyOrAbortedListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +153,8 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
animator.cancel();
|
||||
animator = null;
|
||||
}
|
||||
|
||||
onAnimationReadyOrAbortedListener = null;
|
||||
}
|
||||
|
||||
private void performAnimation(@NonNull final ViewGroup container, @Nullable final View from, @Nullable final View to, final boolean isPush, final boolean toAddedToContainer, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
@@ -160,6 +162,16 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
complete(changeListener, null);
|
||||
return;
|
||||
}
|
||||
if (needsImmediateCompletion) {
|
||||
if (from != null && (!isPush || removesFromViewOnPush)) {
|
||||
container.removeView(from);
|
||||
}
|
||||
complete(changeListener, null);
|
||||
if (isPush && from != null) {
|
||||
resetFromView(from);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
animator = getAnimator(container, from, to, isPush, toAddedToContainer);
|
||||
|
||||
@@ -196,4 +208,46 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private class OnAnimationReadyOrAbortedListener implements ViewTreeObserver.OnPreDrawListener {
|
||||
@NonNull final ViewGroup container;
|
||||
@Nullable final View from;
|
||||
@Nullable final View to;
|
||||
final boolean isPush;
|
||||
final boolean addingToView;
|
||||
@NonNull final ControllerChangeCompletedListener changeListener;
|
||||
private boolean hasRun;
|
||||
|
||||
OnAnimationReadyOrAbortedListener(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, boolean addingToView, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
this.container = container;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.isPush = isPush;
|
||||
this.addingToView = addingToView;
|
||||
this.changeListener = changeListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
onReadyOrAborted();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onReadyOrAborted() {
|
||||
if (!hasRun) {
|
||||
hasRun = true;
|
||||
|
||||
if (to != null) {
|
||||
final ViewTreeObserver observer = to.getViewTreeObserver();
|
||||
if (observer.isAlive()) {
|
||||
observer.removeOnPreDrawListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
performAnimation(container, from, to, isPush, addingToView, changeListener);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Executable → Regular
Executable → Regular
+1
-1
@@ -37,7 +37,7 @@ public class FadeChangeHandler extends AnimatorChangeHandler {
|
||||
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, start, 1));
|
||||
}
|
||||
|
||||
if (from != null && removesFromViewOnPush()) {
|
||||
if (from != null && (!isPush || removesFromViewOnPush())) {
|
||||
animator.play(ObjectAnimator.ofFloat(from, View.ALPHA, 0));
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
+1
-1
@@ -46,7 +46,7 @@ public class HorizontalChangeHandler extends AnimatorChangeHandler {
|
||||
}
|
||||
if (to != null) {
|
||||
// Allow this to have a nice transition when coming off an aborted push animation
|
||||
float fromLeft = from != null ? from.getX() : 0;
|
||||
float fromLeft = from != null ? from.getTranslationX() : 0;
|
||||
animatorSet.play(ObjectAnimator.ofFloat(to, View.TRANSLATION_X, fromLeft - to.getWidth(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+16
-3
@@ -20,10 +20,11 @@ import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
public abstract class TransitionChangeHandler extends ControllerChangeHandler {
|
||||
|
||||
public interface OnTransitionPreparedListener {
|
||||
public void onPrepared();
|
||||
void onPrepared();
|
||||
}
|
||||
|
||||
private boolean canceled;
|
||||
private boolean needsImmediateCompletion;
|
||||
|
||||
/**
|
||||
* Should be overridden to return the Transition to use while replacing Views.
|
||||
@@ -43,12 +44,24 @@ public abstract class TransitionChangeHandler extends ControllerChangeHandler {
|
||||
canceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeImmediately() {
|
||||
super.completeImmediately();
|
||||
|
||||
needsImmediateCompletion = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performChange(@NonNull final ViewGroup container, @Nullable final View from, @Nullable final View to, final boolean isPush, @NonNull final ControllerChangeCompletedListener changeListener) {
|
||||
if (canceled) {
|
||||
changeListener.onChangeCompleted();
|
||||
return;
|
||||
}
|
||||
if (needsImmediateCompletion) {
|
||||
executePropertyChanges(container, from, to, null, isPush);
|
||||
changeListener.onChangeCompleted();
|
||||
return;
|
||||
}
|
||||
|
||||
final Transition transition = getTransition(container, from, to, isPush);
|
||||
transition.addListener(new TransitionListener() {
|
||||
@@ -109,10 +122,10 @@ public abstract class TransitionChangeHandler extends ControllerChangeHandler {
|
||||
* @param container The container these Views are hosted in
|
||||
* @param from The previous View in the container or {@code null} if there was no Controller before this transition
|
||||
* @param to The next View that should be put in the container or {@code null} if no Controller is being transitioned to
|
||||
* @param transition The transition with which {@code TransitionManager.beginDelayedTransition} has been called
|
||||
* @param transition The transition with which {@code TransitionManager.beginDelayedTransition} has been called. This will be null only if another ControllerChangeHandler immediately overrides this one.
|
||||
* @param isPush True if this is a push transaction, false if it's a pop
|
||||
*/
|
||||
public void executePropertyChanges(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, @NonNull Transition transition, boolean isPush) {
|
||||
public void executePropertyChanges(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, @Nullable Transition transition, boolean isPush) {
|
||||
if (from != null && (removesFromViewOnPush() || !isPush) && from.getParent() == container) {
|
||||
container.removeView(from);
|
||||
}
|
||||
|
||||
+16
@@ -7,6 +7,7 @@ import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.internal.ClassUtils;
|
||||
|
||||
@@ -78,4 +79,19 @@ public class TransitionChangeHandlerCompat extends ControllerChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAbortPush(@NonNull ControllerChangeHandler newHandler, @Nullable Controller newTop) {
|
||||
changeHandler.onAbortPush(newHandler, newTop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeImmediately() {
|
||||
changeHandler.completeImmediately();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForceRemoveViewOnPush(boolean force) {
|
||||
changeHandler.setForceRemoveViewOnPush(force);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Executable → Regular
@@ -41,6 +41,7 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
private boolean destroyed;
|
||||
private boolean attached;
|
||||
|
||||
private static final Map<Activity, LifecycleHandler> activeLifecycleHandlers = new HashMap<>();
|
||||
private SparseArray<String> permissionRequestMap = new SparseArray<>();
|
||||
private SparseArray<String> activityRequestMap = new SparseArray<>();
|
||||
private ArrayList<PendingPermissionRequest> pendingPermissionRequests = new ArrayList<>();
|
||||
@@ -54,7 +55,10 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
|
||||
@Nullable
|
||||
private static LifecycleHandler findInActivity(@NonNull Activity activity) {
|
||||
LifecycleHandler lifecycleHandler = (LifecycleHandler)activity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||
LifecycleHandler lifecycleHandler = activeLifecycleHandlers.get(activity);
|
||||
if (lifecycleHandler == null) {
|
||||
lifecycleHandler = (LifecycleHandler)activity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||
}
|
||||
if (lifecycleHandler != null) {
|
||||
lifecycleHandler.registerActivityListener(activity);
|
||||
}
|
||||
@@ -113,6 +117,11 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
if (!hasRegisteredCallbacks) {
|
||||
hasRegisteredCallbacks = true;
|
||||
activity.getApplication().registerActivityLifecycleCallbacks(this);
|
||||
|
||||
// Since Fragment transactions are async, we have to keep an <Activity, LifecycleHandler> map in addition
|
||||
// to trying to find the LifecycleHandler fragment in the Activity to handle the case of the developer
|
||||
// trying to immediately get > 1 router in the same Activity. See issue #299.
|
||||
activeLifecycleHandlers.put(activity, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +156,7 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
|
||||
if (activity != null) {
|
||||
activity.getApplication().unregisterActivityLifecycleCallbacks(this);
|
||||
activeLifecycleHandlers.remove(activity);
|
||||
destroyRouters();
|
||||
activity = null;
|
||||
}
|
||||
@@ -184,6 +194,10 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
requestPermissions(request.instanceId, request.permissions, request.requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
for (ActivityHostedRouter router : routerMap.values()) {
|
||||
router.onContextAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyRouters() {
|
||||
@@ -306,6 +320,10 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
if (this.activity == null && findInActivity(activity) == LifecycleHandler.this) {
|
||||
this.activity = activity;
|
||||
|
||||
for (ActivityHostedRouter router : routerMap.values()) {
|
||||
router.onContextAvailable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +375,9 @@ public class LifecycleHandler extends Fragment implements ActivityLifecycleCallb
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) { }
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
activeLifecycleHandlers.remove(activity);
|
||||
}
|
||||
|
||||
private static class PendingPermissionRequest implements Parcelable {
|
||||
final String instanceId;
|
||||
|
||||
+1
-1
@@ -24,4 +24,4 @@ public class NoOpControllerChangeHandler extends ControllerChangeHandler {
|
||||
public boolean isReusable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.bluelinelabs.conductor.internal;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.util.AndroidRuntimeException;
|
||||
|
||||
public class ThreadUtils {
|
||||
|
||||
public static void ensureMainThread() {
|
||||
if (Looper.getMainLooper().getThread() != Thread.currentThread()) {
|
||||
throw new CalledFromWrongThreadException("Methods that affect the view hierarchy can can only be called from the main thread.");
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CalledFromWrongThreadException extends AndroidRuntimeException {
|
||||
CalledFromWrongThreadException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,7 +23,7 @@ public class ViewAttachHandler implements OnAttachStateChangeListener {
|
||||
}
|
||||
|
||||
private boolean rootAttached = false;
|
||||
boolean childrenAttached = false;
|
||||
private boolean childrenAttached = false;
|
||||
private boolean activityStopped = false;
|
||||
private ReportedState reportedState = ReportedState.VIEW_DETACHED;
|
||||
private ViewAttachListener attachListener;
|
||||
@@ -55,7 +55,7 @@ public class ViewAttachHandler implements OnAttachStateChangeListener {
|
||||
rootAttached = false;
|
||||
if (childrenAttached) {
|
||||
childrenAttached = false;
|
||||
reportDetached();
|
||||
reportDetached(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,34 +78,33 @@ public class ViewAttachHandler implements OnAttachStateChangeListener {
|
||||
|
||||
public void onActivityStopped() {
|
||||
activityStopped = true;
|
||||
reportDetached();
|
||||
reportDetached(true);
|
||||
}
|
||||
|
||||
void reportAttached() {
|
||||
private void reportAttached() {
|
||||
if (rootAttached && childrenAttached && !activityStopped && reportedState != ReportedState.ATTACHED) {
|
||||
reportedState = ReportedState.ATTACHED;
|
||||
attachListener.onAttached();
|
||||
}
|
||||
}
|
||||
|
||||
void reportDetached() {
|
||||
private void reportDetached(boolean detachedForActivity) {
|
||||
boolean wasDetachedForActivity = reportedState == ReportedState.ACTIVITY_STOPPED;
|
||||
boolean isDetachedForActivity = rootAttached;
|
||||
|
||||
if (isDetachedForActivity) {
|
||||
if (detachedForActivity) {
|
||||
reportedState = ReportedState.ACTIVITY_STOPPED;
|
||||
} else {
|
||||
reportedState = ReportedState.VIEW_DETACHED;
|
||||
}
|
||||
|
||||
if (wasDetachedForActivity && !isDetachedForActivity) {
|
||||
if (wasDetachedForActivity && !detachedForActivity) {
|
||||
attachListener.onViewDetachAfterStop();
|
||||
} else {
|
||||
attachListener.onDetached(isDetachedForActivity);
|
||||
attachListener.onDetached(detachedForActivity);
|
||||
}
|
||||
}
|
||||
|
||||
void listenForDeepestChildAttach(final View view, final ChildAttachListener attachListener) {
|
||||
private void listenForDeepestChildAttach(final View view, final ChildAttachListener attachListener) {
|
||||
if (!(view instanceof ViewGroup)) {
|
||||
attachListener.onAttached();
|
||||
return;
|
||||
|
||||
+29
-9
@@ -1,5 +1,6 @@
|
||||
package com.bluelinelabs.conductor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
@@ -49,7 +50,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
public void setup() {
|
||||
createActivityController(null, true);
|
||||
|
||||
currentCallState = new CallState();
|
||||
currentCallState = new CallState(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -57,7 +58,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
@@ -78,7 +79,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
@@ -109,7 +110,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
@@ -131,6 +132,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
|
||||
activityProxy.destroy();
|
||||
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
@@ -140,7 +142,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
@@ -167,11 +169,13 @@ public class ControllerLifecycleCallbacksTests {
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.destroy();
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
createActivityController(bundle, false);
|
||||
controller = (TestController)router.getControllerWithTag("root");
|
||||
|
||||
expectedCallState.contextAvailableCalls++;
|
||||
expectedCallState.restoreInstanceStateCalls++;
|
||||
expectedCallState.restoreViewStateCalls++;
|
||||
expectedCallState.changeStartCalls++;
|
||||
@@ -184,6 +188,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
currentCallState.changeEndCalls = controller.currentCallState.changeEndCalls;
|
||||
currentCallState.createViewCalls = controller.currentCallState.createViewCalls;
|
||||
currentCallState.attachCalls = controller.currentCallState.attachCalls;
|
||||
currentCallState.contextAvailableCalls = controller.currentCallState.contextAvailableCalls;
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
@@ -204,7 +209,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
TestController controller = new TestController();
|
||||
attachLifecycleListener(controller);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
router.pushController(RouterTransaction.with(controller)
|
||||
@@ -222,12 +227,14 @@ public class ControllerLifecycleCallbacksTests {
|
||||
assertCalls(expectedCallState, controller);
|
||||
|
||||
activityProxy.resume();
|
||||
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleCallOrder() {
|
||||
final TestController testController = new TestController();
|
||||
final CallState callState = new CallState();
|
||||
final CallState callState = new CallState(false);
|
||||
|
||||
testController.addLifecycleListener(new LifecycleListener() {
|
||||
@Override
|
||||
@@ -443,7 +450,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
TestController child = new TestController();
|
||||
attachLifecycleListener(child);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
@@ -470,7 +477,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
TestController child = new TestController();
|
||||
attachLifecycleListener(child);
|
||||
|
||||
CallState expectedCallState = new CallState();
|
||||
CallState expectedCallState = new CallState(false);
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
|
||||
@@ -486,6 +493,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.destroyViewCalls++;
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
|
||||
assertCalls(expectedCallState, child);
|
||||
@@ -495,6 +503,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
return MockChangeHandler.listeningChangeHandler(new ChangeHandlerListener() {
|
||||
@Override
|
||||
public void willStartChange() {
|
||||
expectedCallState.contextAvailableCalls++;
|
||||
expectedCallState.changeStartCalls++;
|
||||
expectedCallState.createViewCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
@@ -526,6 +535,7 @@ public class ControllerLifecycleCallbacksTests {
|
||||
public void didAttachOrDetach() {
|
||||
expectedCallState.destroyViewCalls++;
|
||||
expectedCallState.detachCalls++;
|
||||
expectedCallState.contextUnavailableCalls++;
|
||||
expectedCallState.destroyCalls++;
|
||||
assertCalls(expectedCallState, controller);
|
||||
}
|
||||
@@ -555,6 +565,16 @@ public class ControllerLifecycleCallbacksTests {
|
||||
currentCallState.changeEndCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postContextAvailable(@NonNull Controller controller, @NonNull Context context) {
|
||||
currentCallState.contextAvailableCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postContextUnavailable(@NonNull Controller controller) {
|
||||
currentCallState.contextUnavailableCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCreateView(@NonNull Controller controller, @NonNull View view) {
|
||||
currentCallState.createViewCalls++;
|
||||
|
||||
@@ -86,18 +86,6 @@ public class ViewLeakTests {
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityStopWhenPushNeverAdded() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller).pushChangeHandler(new NeverAddChangeHandler()));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
activityProxy.stop(true);
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityStopWhenPushNeverCompleted() {
|
||||
Controller controller = new TestController();
|
||||
@@ -110,9 +98,21 @@ public class ViewLeakTests {
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityDestroyWhenPushNeverAdded() {
|
||||
Controller controller = new TestController();
|
||||
router.pushController(RouterTransaction.with(controller).pushChangeHandler(new NeverAddChangeHandler()));
|
||||
|
||||
assertNotNull(controller.getView());
|
||||
|
||||
activityProxy.stop(true).destroy();
|
||||
|
||||
assertNull(controller.getView());
|
||||
}
|
||||
|
||||
public static class NeverAddChangeHandler extends ControllerChangeHandler {
|
||||
@Override
|
||||
public void performChange(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
public void performChange(@NonNull final ViewGroup container, @Nullable View from, @Nullable final View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) {
|
||||
if (from != null) {
|
||||
container.removeView(from);
|
||||
}
|
||||
|
||||
@@ -19,10 +19,8 @@ public class CallState implements Parcelable {
|
||||
public int onActivityResultCalls;
|
||||
public int onRequestPermissionsResultCalls;
|
||||
public int createOptionsMenuCalls;
|
||||
|
||||
public CallState() {
|
||||
this(false);
|
||||
}
|
||||
public int contextAvailableCalls;
|
||||
public int contextUnavailableCalls;
|
||||
|
||||
public CallState(boolean setupForAddedController) {
|
||||
if (setupForAddedController) {
|
||||
@@ -30,6 +28,7 @@ public class CallState implements Parcelable {
|
||||
changeEndCalls++;
|
||||
createViewCalls++;
|
||||
attachCalls++;
|
||||
contextAvailableCalls++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +41,14 @@ public class CallState implements Parcelable {
|
||||
return false;
|
||||
}
|
||||
|
||||
CallState callState = (CallState)o;
|
||||
CallState callState = (CallState) o;
|
||||
|
||||
if (contextAvailableCalls != callState.contextAvailableCalls) {
|
||||
return false;
|
||||
}
|
||||
if (contextUnavailableCalls != callState.contextUnavailableCalls) {
|
||||
return false;
|
||||
}
|
||||
if (changeStartCalls != callState.changeStartCalls) {
|
||||
return false;
|
||||
}
|
||||
@@ -102,6 +107,8 @@ public class CallState implements Parcelable {
|
||||
result = 31 * result + onActivityResultCalls;
|
||||
result = 31 * result + onRequestPermissionsResultCalls;
|
||||
result = 31 * result + createOptionsMenuCalls;
|
||||
result = 31 * result + contextAvailableCalls;
|
||||
result = 31 * result + contextUnavailableCalls;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -122,6 +129,8 @@ public class CallState implements Parcelable {
|
||||
"\n onActivityResultCalls=" + onActivityResultCalls +
|
||||
"\n onRequestPermissionsResultCalls=" + onRequestPermissionsResultCalls +
|
||||
"\n createOptionsMenuCalls=" + createOptionsMenuCalls +
|
||||
"\n contextAvailableCalls=" + contextAvailableCalls +
|
||||
"\n contextUnavailableCalls=" + contextUnavailableCalls +
|
||||
"}\n";
|
||||
}
|
||||
|
||||
@@ -144,11 +153,13 @@ public class CallState implements Parcelable {
|
||||
out.writeInt(onActivityResultCalls);
|
||||
out.writeInt(onRequestPermissionsResultCalls);
|
||||
out.writeInt(createOptionsMenuCalls);
|
||||
out.writeInt(contextAvailableCalls);
|
||||
out.writeInt(contextUnavailableCalls);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<CallState> CREATOR = new Parcelable.Creator<CallState>() {
|
||||
public static final Parcelable.Creator<CallState> CREATOR = new Parcelable.Creator<CallState>() {
|
||||
public CallState createFromParcel(Parcel in) {
|
||||
CallState state = new CallState();
|
||||
CallState state = new CallState(false);
|
||||
|
||||
state.changeStartCalls = in.readInt();
|
||||
state.changeEndCalls = in.readInt();
|
||||
@@ -164,6 +175,8 @@ public class CallState implements Parcelable {
|
||||
state.onActivityResultCalls = in.readInt();
|
||||
state.onRequestPermissionsResultCalls = in.readInt();
|
||||
state.createOptionsMenuCalls = in.readInt();
|
||||
state.contextAvailableCalls = in.readInt();
|
||||
state.contextUnavailableCalls = in.readInt();
|
||||
|
||||
return state;
|
||||
}
|
||||
@@ -172,4 +185,4 @@ public class CallState implements Parcelable {
|
||||
return new CallState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bluelinelabs.conductor.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
@@ -23,7 +24,7 @@ public class TestController extends Controller {
|
||||
|
||||
private static final String KEY_CALL_STATE = "TestController.currentCallState";
|
||||
|
||||
public CallState currentCallState = new CallState();
|
||||
public CallState currentCallState = new CallState(false);
|
||||
public ChangeHandlerHistory changeHandlerHistory = new ChangeHandlerHistory();
|
||||
|
||||
@NonNull
|
||||
@@ -63,6 +64,18 @@ public class TestController extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onContextAvailable(@NonNull Context context) {
|
||||
super.onContextAvailable(context);
|
||||
currentCallState.contextAvailableCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onContextUnavailable() {
|
||||
super.onContextUnavailable();
|
||||
currentCallState.contextUnavailableCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(@NonNull View view) {
|
||||
super.onAttach(view);
|
||||
|
||||
Executable → Regular
+6
-19
@@ -1,24 +1,9 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.neenbedankt.android-apt'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
lintOptions {
|
||||
abortOnError true
|
||||
ignore 'UnusedResources'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
@@ -49,13 +34,15 @@ dependencies {
|
||||
compile rootProject.ext.supportV4
|
||||
compile rootProject.ext.supportDesign
|
||||
|
||||
apt rootProject.ext.butterknifeCompiler
|
||||
annotationProcessor rootProject.ext.butterknifeCompiler
|
||||
compile rootProject.ext.butterknife
|
||||
compile rootProject.ext.picasso
|
||||
|
||||
compile project(':conductor-support')
|
||||
compile project(':conductor-rxlifecycle')
|
||||
compile project(':conductor-rxlifecycle2')
|
||||
compile project(':conductor-modules:support')
|
||||
compile project(':conductor-modules:rxlifecycle')
|
||||
compile project(':conductor-modules:rxlifecycle2')
|
||||
compile project(':conductor-modules:autodispose')
|
||||
compile project(':conductor-modules:arch-components-lifecycle')
|
||||
|
||||
debugCompile rootProject.ext.leakCanary
|
||||
releaseCompile rootProject.ext.leakCanaryNoOp
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
+15
-6
@@ -15,7 +15,6 @@ import com.bluelinelabs.conductor.changehandler.TransitionChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.changehandler.transitions.FabTransform;
|
||||
import com.bluelinelabs.conductor.demo.util.AnimUtils;
|
||||
import com.bluelinelabs.conductor.demo.util.AnimUtils.TransitionEndListener;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public class FabToDialogTransitionChangeHandler extends TransitionChangeHandler {
|
||||
@@ -64,7 +63,7 @@ public class FabToDialogTransitionChangeHandler extends TransitionChangeHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePropertyChanges(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, @NonNull Transition transition, boolean isPush) {
|
||||
public void executePropertyChanges(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, @Nullable Transition transition, boolean isPush) {
|
||||
if (isPush) {
|
||||
fabParent.removeView(fab);
|
||||
container.addView(to);
|
||||
@@ -74,7 +73,7 @@ public class FabToDialogTransitionChangeHandler extends TransitionChangeHandler
|
||||
* Because otherwise we will be lost when trying to transition back.
|
||||
* Set it to invisible because we don't want it to jump back after the transition
|
||||
*/
|
||||
transition.addListener(new AnimUtils.TransitionEndListener() {
|
||||
AnimUtils.TransitionEndListener endListener = new AnimUtils.TransitionEndListener() {
|
||||
@Override
|
||||
public void onTransitionCompleted(Transition transition) {
|
||||
fab.setVisibility(View.GONE);
|
||||
@@ -82,19 +81,29 @@ public class FabToDialogTransitionChangeHandler extends TransitionChangeHandler
|
||||
fab = null;
|
||||
fabParent = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
if (transition != null) {
|
||||
transition.addListener(endListener);
|
||||
} else {
|
||||
endListener.onTransitionCompleted(null);
|
||||
}
|
||||
} else {
|
||||
dialogBackground.setVisibility(View.INVISIBLE);
|
||||
fabParent.addView(fab);
|
||||
container.removeView(from);
|
||||
|
||||
transition.addListener(new TransitionEndListener() {
|
||||
AnimUtils.TransitionEndListener endListener = new AnimUtils.TransitionEndListener() {
|
||||
@Override
|
||||
public void onTransitionCompleted(Transition transition) {
|
||||
fabParent.removeView(dialogBackground);
|
||||
dialogBackground = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
if (transition != null) {
|
||||
transition.addListener(endListener);
|
||||
} else {
|
||||
endListener.onTransitionCompleted(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
+2
-1
@@ -70,6 +70,7 @@ public class SharedElementDelayingChangeHandler extends ArcFadeMoveChangeHandler
|
||||
|
||||
if (waitForTransitionNames.size() == 0) {
|
||||
to.getViewTreeObserver().removeOnPreDrawListener(onPreDrawListener);
|
||||
onPreDrawListener = null;
|
||||
|
||||
to.setVisibility(View.INVISIBLE);
|
||||
|
||||
@@ -95,7 +96,7 @@ public class SharedElementDelayingChangeHandler extends ArcFadeMoveChangeHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePropertyChanges(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, @NonNull Transition transition, boolean isPush) {
|
||||
public void executePropertyChanges(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, @Nullable Transition transition, boolean isPush) {
|
||||
if (to != null) {
|
||||
to.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
+1
-1
@@ -292,4 +292,4 @@ public class FabTransform extends Transition {
|
||||
transitionValues.values.put(PROP_BOUNDS, new Rect(view.getLeft(), view.getTop(),
|
||||
view.getRight(), view.getBottom()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -214,4 +214,4 @@ public class GravityArcMotion extends ArcMotion {
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers;
|
||||
|
||||
import android.arch.lifecycle.Lifecycle.Event;
|
||||
import android.arch.lifecycle.LifecycleObserver;
|
||||
import android.arch.lifecycle.OnLifecycleEvent;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.archlifecycle.LifecycleController;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.ActionBarProvider;
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class ArchLifecycleController extends LifecycleController {
|
||||
|
||||
private static final String TAG = "ArchLifecycleController";
|
||||
|
||||
@BindView(R.id.tv_title) TextView tvTitle;
|
||||
|
||||
private Unbinder unbinder;
|
||||
private boolean hasExited;
|
||||
|
||||
public ArchLifecycleController() {
|
||||
LifecycleObserver lifecycleObserver = new LifecycleObserver() {
|
||||
@OnLifecycleEvent(Event.ON_CREATE)
|
||||
void onCreate() {
|
||||
Log.d(TAG, "LifecycleObserver onCreate() called");
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Event.ON_START)
|
||||
void onStart() {
|
||||
Log.d(TAG, "LifecycleObserver onStart() called");
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Event.ON_RESUME)
|
||||
void onResume() {
|
||||
Log.d(TAG, "LifecycleObserver onResume() called");
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Event.ON_PAUSE)
|
||||
void onPause() {
|
||||
Log.d(TAG, "LifecycleObserver onPause() called");
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Event.ON_STOP)
|
||||
void onStop() {
|
||||
Log.d(TAG, "LifecycleObserver onStop() called");
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Event.ON_DESTROY)
|
||||
void onDestroy() {
|
||||
Log.d(TAG, "LifecycleObserver onDestroy() called");
|
||||
}
|
||||
};
|
||||
|
||||
Log.i(TAG, "constructor called");
|
||||
|
||||
getLifecycle().addObserver(lifecycleObserver);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
Log.i(TAG, "onCreateView() called");
|
||||
|
||||
View view = inflater.inflate(R.layout.controller_lifecycle, container, false);
|
||||
view.setBackgroundColor(ContextCompat.getColor(container.getContext(), R.color.orange_300));
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
tvTitle.setText(getResources().getString(R.string.rxlifecycle_title, TAG));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(@NonNull View view) {
|
||||
super.onAttach(view);
|
||||
|
||||
Log.i(TAG, "onAttach() called");
|
||||
|
||||
(((ActionBarProvider) getActivity()).getSupportActionBar()).setTitle("Arch Components Lifecycle Demo");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
|
||||
Log.i(TAG, "onDestroyView() called");
|
||||
|
||||
unbinder.unbind();
|
||||
unbinder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach(@NonNull View view) {
|
||||
super.onDetach(view);
|
||||
|
||||
Log.i(TAG, "onDetach() called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
Log.i(TAG, "onDestroy() called");
|
||||
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
super.onChangeEnded(changeHandler, changeType);
|
||||
|
||||
hasExited = !changeType.isEnter;
|
||||
if (isDestroyed()) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next_release_view) void onNextWithReleaseClicked() {
|
||||
setRetainViewMode(RetainViewMode.RELEASE_DETACH);
|
||||
|
||||
getRouter().pushController(RouterTransaction.with(new TextController("Logcat should now report that the Controller's onDetach() and LifecycleObserver's onPause() methods were called, followed by the Controller's onDestroyView() and LifecycleObserver's onStop()."))
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next_retain_view) void onNextWithRetainClicked() {
|
||||
setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
|
||||
getRouter().pushController(RouterTransaction.with(new TextController("Logcat should now report that the Controller's onDetach() and LifecycleObserver's onPause() methods were called."))
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bluelinelabs.conductor.Controller;
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.ActionBarProvider;
|
||||
import com.bluelinelabs.conductor.demo.DemoApplication;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.uber.autodispose.LifecycleScopeProvider;
|
||||
import com.uber.autodispose.ObservableScoper;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
|
||||
// Shamelessly borrowed from the official RxLifecycle demo by Trello and adapted for Conductor Controllers
|
||||
// instead of Activities or Fragments.
|
||||
public class AutodisposeController extends Controller {
|
||||
|
||||
private static final String TAG = "AutodisposeController";
|
||||
|
||||
@BindView(R.id.tv_title) TextView tvTitle;
|
||||
|
||||
private Unbinder unbinder;
|
||||
private boolean hasExited;
|
||||
private final LifecycleScopeProvider scopeProvider = ControllerScopeProvider.from(this);
|
||||
|
||||
public AutodisposeController() {
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose(new Action() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Disposing from constructor");
|
||||
}
|
||||
})
|
||||
.to(new ObservableScoper<Long>(scopeProvider))
|
||||
.subscribe(new Consumer<Long>() {
|
||||
@Override
|
||||
public void accept(Long num) {
|
||||
Log.i(TAG, "Started in constructor, running until onDestroy(): " + num);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
Log.i(TAG, "onCreateView() called");
|
||||
|
||||
View view = inflater.inflate(R.layout.controller_lifecycle, container, false);
|
||||
view.setBackgroundColor(ContextCompat.getColor(container.getContext(), R.color.purple_300));
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
tvTitle.setText(getResources().getString(R.string.rxlifecycle_title, TAG));
|
||||
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose(new Action() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Disposing from onCreateView()");
|
||||
}
|
||||
})
|
||||
.to(new ObservableScoper<Long>(scopeProvider))
|
||||
.subscribe(new Consumer<Long>() {
|
||||
@Override
|
||||
public void accept(Long num) {
|
||||
Log.i(TAG, "Started in onCreateView(), running until onDestroyView(): " + num);
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(@NonNull View view) {
|
||||
super.onAttach(view);
|
||||
|
||||
Log.i(TAG, "onAttach() called");
|
||||
|
||||
(((ActionBarProvider) getActivity()).getSupportActionBar()).setTitle("Autodispose Demo");
|
||||
|
||||
Observable.interval(1, TimeUnit.SECONDS)
|
||||
.doOnDispose(new Action() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Disposing from onAttach()");
|
||||
}
|
||||
})
|
||||
.to(new ObservableScoper<Long>(scopeProvider))
|
||||
.subscribe(new Consumer<Long>() {
|
||||
@Override
|
||||
public void accept(Long num) {
|
||||
Log.i(TAG, "Started in onAttach(), running until onDetach(): " + num);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
super.onDestroyView(view);
|
||||
|
||||
Log.i(TAG, "onDestroyView() called");
|
||||
|
||||
unbinder.unbind();
|
||||
unbinder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach(@NonNull View view) {
|
||||
super.onDetach(view);
|
||||
|
||||
Log.i(TAG, "onDetach() called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
Log.i(TAG, "onDestroy() called");
|
||||
|
||||
if (hasExited) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangeEnded(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
super.onChangeEnded(changeHandler, changeType);
|
||||
|
||||
hasExited = !changeType.isEnter;
|
||||
if (isDestroyed()) {
|
||||
DemoApplication.refWatcher.watch(this);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next_release_view)
|
||||
void onNextWithReleaseClicked() {
|
||||
setRetainViewMode(RetainViewMode.RELEASE_DETACH);
|
||||
|
||||
getRouter().pushController(RouterTransaction.with(new TextController("Logcat should now report that the observables from onAttach() and onViewBound() have been disposed of, while the constructor observable is still running."))
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_next_retain_view)
|
||||
void onNextWithRetainClicked() {
|
||||
setRetainViewMode(RetainViewMode.RETAIN_DETACH);
|
||||
|
||||
getRouter().pushController(RouterTransaction.with(new TextController("Logcat should now report that the observables from onAttach() has been disposed of, while the constructor and onViewBound() observables are still running."))
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -84,7 +84,7 @@ public class CityDetailController extends BaseController {
|
||||
private final String textViewTransitionName;
|
||||
private final String[] details;
|
||||
|
||||
public CityDetailAdapter(LayoutInflater inflater, @DrawableRes String title, int imageDrawableRes, String[] details, String transitionNameBase) {
|
||||
public CityDetailAdapter(LayoutInflater inflater, String title, @DrawableRes int imageDrawableRes, String[] details, String transitionNameBase) {
|
||||
this.inflater = inflater;
|
||||
this.title = title;
|
||||
this.imageDrawableRes = imageDrawableRes;
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package com.bluelinelabs.conductor.demo.controllers;
|
||||
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.controllers.base.BaseController;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
public class ExternalModulesController extends BaseController {
|
||||
|
||||
private enum DemoModel {
|
||||
RX_LIFECYCLE("Rx Lifecycle", R.color.red_300),
|
||||
RX_LIFECYCLE_2("Rx Lifecycle 2", R.color.blue_grey_300),
|
||||
AUTODISPOSE("Autodispose", R.color.purple_300),
|
||||
ARCH_LIFECYCLE("Arch Components Lifecycle", R.color.orange_300);
|
||||
|
||||
String title;
|
||||
@ColorRes int color;
|
||||
|
||||
DemoModel(String title, @ColorRes int color) {
|
||||
this.title = title;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
@BindView(R.id.recycler_view) RecyclerView recyclerView;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return inflater.inflate(R.layout.controller_additional_modules, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewBound(@NonNull View view) {
|
||||
super.onViewBound(view);
|
||||
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
|
||||
recyclerView.setAdapter(new AdditionalModulesAdapter(LayoutInflater.from(view.getContext()), DemoModel.values()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangeStarted(@NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
|
||||
if (changeType.isEnter) {
|
||||
setTitle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTitle() {
|
||||
return "External Module Demos";
|
||||
}
|
||||
|
||||
void onModelRowClick(DemoModel model) {
|
||||
switch (model) {
|
||||
case RX_LIFECYCLE:
|
||||
getRouter().pushController(RouterTransaction.with(new RxLifecycleController())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case RX_LIFECYCLE_2:
|
||||
getRouter().pushController(RouterTransaction.with(new RxLifecycle2Controller())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case AUTODISPOSE:
|
||||
getRouter().pushController(RouterTransaction.with(new AutodisposeController())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case ARCH_LIFECYCLE:
|
||||
getRouter().pushController(RouterTransaction.with(new ArchLifecycleController())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class AdditionalModulesAdapter extends RecyclerView.Adapter<AdditionalModulesAdapter.ViewHolder> {
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
private final DemoModel[] items;
|
||||
|
||||
public AdditionalModulesAdapter(LayoutInflater inflater, DemoModel[] items) {
|
||||
this.inflater = inflater;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(inflater.inflate(R.layout.row_home, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
holder.bind(items[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.tv_title) TextView tvTitle;
|
||||
@BindView(R.id.img_dot) ImageView imgDot;
|
||||
private DemoModel model;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
||||
void bind(DemoModel item) {
|
||||
model = item;
|
||||
tvTitle.setText(item.title);
|
||||
imgDot.getDrawable().setColorFilter(ContextCompat.getColor(getActivity(), item.color), Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
@OnClick(R.id.row_root)
|
||||
void onRowClick() {
|
||||
onModelRowClick(model);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+14
-19
@@ -28,6 +28,7 @@ import com.bluelinelabs.conductor.ControllerChangeHandler;
|
||||
import com.bluelinelabs.conductor.ControllerChangeType;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.conductor.changehandler.TransitionChangeHandlerCompat;
|
||||
import com.bluelinelabs.conductor.demo.R;
|
||||
import com.bluelinelabs.conductor.demo.changehandler.ArcFadeMoveChangeHandler;
|
||||
@@ -41,7 +42,7 @@ import butterknife.OnClick;
|
||||
|
||||
public class HomeController extends BaseController {
|
||||
|
||||
private enum HomeDemoModel {
|
||||
private enum DemoModel {
|
||||
NAVIGATION("Navigation Demos", R.color.red_300),
|
||||
TRANSITIONS("Transition Demos", R.color.blue_grey_300),
|
||||
SHARED_ELEMENT_TRANSITIONS("Shared Element Demos", R.color.purple_300),
|
||||
@@ -51,13 +52,12 @@ public class HomeController extends BaseController {
|
||||
MULTIPLE_CHILD_ROUTERS("Multiple Child Routers", R.color.deep_orange_300),
|
||||
MASTER_DETAIL("Master Detail", R.color.grey_300),
|
||||
DRAG_DISMISS("Drag Dismiss", R.color.lime_300),
|
||||
RX_LIFECYCLE("Rx Lifecycle", R.color.teal_300),
|
||||
RX_LIFECYCLE_2("Rx Lifecycle 2", R.color.brown_300);
|
||||
EXTERNAL_MODULES("Bonus Modules", R.color.teal_300);
|
||||
|
||||
String title;
|
||||
@ColorRes int color;
|
||||
|
||||
HomeDemoModel(String title, @ColorRes int color) {
|
||||
DemoModel(String title, @ColorRes int color) {
|
||||
this.title = title;
|
||||
this.color = color;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public class HomeController extends BaseController {
|
||||
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
|
||||
recyclerView.setAdapter(new HomeAdapter(LayoutInflater.from(view.getContext()), HomeDemoModel.values()));
|
||||
recyclerView.setAdapter(new HomeAdapter(LayoutInflater.from(view.getContext()), DemoModel.values()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,7 +163,7 @@ public class HomeController extends BaseController {
|
||||
|
||||
}
|
||||
|
||||
void onModelRowClick(HomeDemoModel model, int position) {
|
||||
void onModelRowClick(DemoModel model, int position) {
|
||||
switch (model) {
|
||||
case NAVIGATION:
|
||||
getRouter().pushController(RouterTransaction.with(new NavigationDemoController(0, DisplayUpMode.SHOW_FOR_CHILDREN_ONLY))
|
||||
@@ -201,15 +201,10 @@ public class HomeController extends BaseController {
|
||||
.pushChangeHandler(new FadeChangeHandler(false))
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case RX_LIFECYCLE:
|
||||
getRouter().pushController(RouterTransaction.with(new RxLifecycleController())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
break;
|
||||
case RX_LIFECYCLE_2:
|
||||
getRouter().pushController(RouterTransaction.with(new RxLifecycle2Controller())
|
||||
.pushChangeHandler(new FadeChangeHandler())
|
||||
.popChangeHandler(new FadeChangeHandler()));
|
||||
case EXTERNAL_MODULES:
|
||||
getRouter().pushController(RouterTransaction.with(new ExternalModulesController())
|
||||
.pushChangeHandler(new HorizontalChangeHandler())
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
break;
|
||||
case MULTIPLE_CHILD_ROUTERS:
|
||||
getRouter().pushController(RouterTransaction.with(new MultipleChildRouterController())
|
||||
@@ -227,9 +222,9 @@ public class HomeController extends BaseController {
|
||||
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> {
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
private final HomeDemoModel[] items;
|
||||
private final DemoModel[] items;
|
||||
|
||||
public HomeAdapter(LayoutInflater inflater, HomeDemoModel[] items) {
|
||||
public HomeAdapter(LayoutInflater inflater, DemoModel[] items) {
|
||||
this.inflater = inflater;
|
||||
this.items = items;
|
||||
}
|
||||
@@ -253,7 +248,7 @@ public class HomeController extends BaseController {
|
||||
|
||||
@BindView(R.id.tv_title) TextView tvTitle;
|
||||
@BindView(R.id.img_dot) ImageView imgDot;
|
||||
private HomeDemoModel model;
|
||||
private DemoModel model;
|
||||
private int position;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
@@ -261,7 +256,7 @@ public class HomeController extends BaseController {
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
||||
void bind(int position, HomeDemoModel item) {
|
||||
void bind(int position, DemoModel item) {
|
||||
model = item;
|
||||
tvTitle.setText(item.title);
|
||||
imgDot.getDrawable().setColorFilter(ContextCompat.getColor(getActivity(), item.color), Mode.SRC_ATOP);
|
||||
|
||||
+10
-7
@@ -49,6 +49,12 @@ public class PagerController extends BaseController {
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return inflater.inflate(R.layout.controller_pager, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewBound(@NonNull View view) {
|
||||
super.onViewBound(view);
|
||||
@@ -58,16 +64,13 @@ public class PagerController extends BaseController {
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(@NonNull View view) {
|
||||
viewPager.setAdapter(null);
|
||||
if (!getActivity().isChangingConfigurations()) {
|
||||
viewPager.setAdapter(null);
|
||||
}
|
||||
tabLayout.setupWithViewPager(null);
|
||||
super.onDestroyView(view);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return inflater.inflate(R.layout.controller_pager, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTitle() {
|
||||
return "ViewPager Demo";
|
||||
|
||||
Executable → Regular
+3
-3
@@ -61,8 +61,8 @@ public class RxLifecycle2Controller extends RxController {
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
Log.i(TAG, "onCreateView() called");
|
||||
|
||||
View view = inflater.inflate(R.layout.controller_rxlifecycle, container, false);
|
||||
view.setBackgroundColor(ContextCompat.getColor(container.getContext(), R.color.brown_300));
|
||||
View view = inflater.inflate(R.layout.controller_lifecycle, container, false);
|
||||
view.setBackgroundColor(ContextCompat.getColor(container.getContext(), R.color.blue_grey_300));
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
tvTitle.setText(getResources().getString(R.string.rxlifecycle_title, TAG));
|
||||
@@ -71,7 +71,7 @@ public class RxLifecycle2Controller extends RxController {
|
||||
.doOnDispose(new Action() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Disposing from onCreateView)");
|
||||
Log.i(TAG, "Disposing from onCreateView()");
|
||||
}
|
||||
})
|
||||
.compose(this.<Long>bindUntilEvent(ControllerEvent.DESTROY_VIEW))
|
||||
|
||||
Executable → Regular
+2
-2
@@ -61,8 +61,8 @@ public class RxLifecycleController extends RxController {
|
||||
protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
Log.i(TAG, "onCreateView() called");
|
||||
|
||||
View view = inflater.inflate(R.layout.controller_rxlifecycle, container, false);
|
||||
view.setBackgroundColor(ContextCompat.getColor(container.getContext(), R.color.teal_300));
|
||||
View view = inflater.inflate(R.layout.controller_lifecycle, container, false);
|
||||
view.setBackgroundColor(ContextCompat.getColor(container.getContext(), R.color.red_300));
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
|
||||
tvTitle.setText(getResources().getString(R.string.rxlifecycle_title, TAG));
|
||||
|
||||
Executable → Regular
@@ -169,4 +169,4 @@ public class BundleBuilder {
|
||||
return bundle;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -239,4 +239,4 @@ public class ElasticDragDismissFrameLayout extends FrameLayout implements Nested
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
android:propertyName="translationZ"
|
||||
android:valueTo="0dp" />
|
||||
</item>
|
||||
</selector>
|
||||
</selector>
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
/>
|
||||
/>
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/dialog_corners" />
|
||||
<solid android:color="@color/dialog_background" />
|
||||
</shape>
|
||||
</shape>
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
<path
|
||||
android:fillColor="@color/white"
|
||||
android:pathData="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z"/>
|
||||
</vector>
|
||||
</vector>
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
android:fillColor="@color/dark_icon"
|
||||
android:pathData="M20.38,8.53C20.54,8.13 21.06,6.54 20.21,4.39C20.21,4.39 18.9,4 15.91,6C14.66,5.67 13.33,5.62 12,5.62C10.68,5.62 9.34,5.67 8.09,6C5.1,3.97 3.79,4.39 3.79,4.39C2.94,6.54 3.46,8.13 3.63,8.53C2.61,9.62 2,11 2,12.72C2,19.16 6.16,20.61 12,20.61C17.79,20.61 22,19.16 22,12.72C22,11 21.39,9.62 20.38,8.53M12,19.38C7.88,19.38 4.53,19.19 4.53,15.19C4.53,14.24 5,13.34 5.8,12.61C7.14,11.38 9.43,12.03 12,12.03C14.59,12.03 16.85,11.38 18.2,12.61C19,13.34 19.5,14.23 19.5,15.19C19.5,19.18 16.13,19.38 12,19.38M8.86,13.12C8.04,13.12 7.36,14.12 7.36,15.34C7.36,16.57 8.04,17.58 8.86,17.58C9.69,17.58 10.36,16.58 10.36,15.34C10.36,14.11 9.69,13.12 8.86,13.12M15.14,13.12C14.31,13.12 13.64,14.11 13.64,15.34C13.64,16.58 14.31,17.58 15.14,17.58C15.96,17.58 16.64,16.58 16.64,15.34C16.64,14.11 16,13.12 15.14,13.12Z"
|
||||
/>
|
||||
</vector>
|
||||
</vector>
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user