diff --git a/scoop-basics/build.gradle b/scoop-basics/build.gradle
index 06416fc..e840738 100644
--- a/scoop-basics/build.gradle
+++ b/scoop-basics/build.gradle
@@ -49,6 +49,7 @@ dependencies {
compile 'com.android.support:multidex:1.0.0'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.jakewharton.timber:timber:3.1.0'
+ compile 'com.jakewharton.rxrelay:rxrelay:1.0.0'
compile 'com.google.android.gms:play-services-location:8.1.0'
compile project(':scoop')
compile project(':scoop-dagger')
diff --git a/scoop-basics/src/main/AndroidManifest.xml b/scoop-basics/src/main/AndroidManifest.xml
index cd07e0a..acb6aa6 100644
--- a/scoop-basics/src/main/AndroidManifest.xml
+++ b/scoop-basics/src/main/AndroidManifest.xml
@@ -1,14 +1,16 @@
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
-
+
+ android:required="true"
+ />
+ android:value="@integer/google_play_services_version"
+ />
+ android:value="AIzaSyAgTvwvsXZpBZrEGSKEUSDS_v1b5dtGEfg"
+ />
+
+
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/App.java b/scoop-basics/src/main/java/com/example/scoop/basics/App.java
index cf708e1..7530192 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/App.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/App.java
@@ -18,6 +18,8 @@ public void onCreate() {
Stetho.initializeWithDefaults(this);
Timber.plant(new Timber.DebugTree());
+ Timber.d("onCreate");
+
Scoop.setViewBinder(new ButterKnifeViewBinder());
applicationGraph = ObjectGraph.create(new AppModule(this));
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/AppModule.java b/scoop-basics/src/main/java/com/example/scoop/basics/AppModule.java
index ad2cc28..e6d86cd 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/AppModule.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/AppModule.java
@@ -1,9 +1,14 @@
package com.example.scoop.basics;
import android.app.Application;
+import android.app.NotificationManager;
+import android.content.Context;
+import com.example.scoop.basics.androidservices.SampleIntentService;
import com.example.scoop.basics.scoop.AppRouter;
import com.example.scoop.basics.scoop.DialogRouter;
-import com.lyft.scoop.dagger.DaggerScreenScooper;
+import com.lyft.scoop.ScreenScoopFactory;
+import com.lyft.scoop.ScreenScooper;
+import com.lyft.scoop.dagger.DaggerScreenScoopFactory;
import dagger.Module;
import dagger.Provides;
import javax.inject.Singleton;
@@ -11,6 +16,7 @@
@Module(
injects = {
App.class,
+ SampleIntentService.class
},
includes = {
},
@@ -24,22 +30,26 @@ public AppModule(App app) {
this.app = app;
}
- @Singleton
@Provides
- DaggerScreenScooper provideDaggerScreenScooper() {
- return new DaggerScreenScooper();
+ ScreenScoopFactory provideDaggerScreenScooper() {
+ return new DaggerScreenScoopFactory();
+ }
+
+ @Provides
+ ScreenScooper provideScreenFactory(ScreenScoopFactory screenScoopFactory) {
+ return new ScreenScooper(screenScoopFactory);
}
@Singleton
@Provides
- AppRouter provideAppRouter(DaggerScreenScooper daggerScreenScooper) {
- return new AppRouter(daggerScreenScooper, false);
+ AppRouter provideAppRouter() {
+ return new AppRouter(false);
}
@Singleton
@Provides
- DialogRouter provideDialogRouter(DaggerScreenScooper daggerScreenScooper) {
- return new DialogRouter(new AppRouter(daggerScreenScooper, true));
+ DialogRouter provideDialogRouter() {
+ return new DialogRouter(new AppRouter(true));
}
@Singleton
@@ -48,4 +58,9 @@ Application provideApplication() {
return app;
}
+ @Singleton
+ @Provides
+ NotificationManager provideNotificationManager() {
+ return (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/MainActivity.java b/scoop-basics/src/main/java/com/example/scoop/basics/MainActivity.java
index 6bbec85..bde203d 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/MainActivity.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/MainActivity.java
@@ -32,34 +32,35 @@ public class MainActivity extends AppCompatActivity {
DialogRouter dialogRouter;
private CompositeSubscription subscriptions = new CompositeSubscription();
- private Scoop rootScoop;
+ private Scoop activityScoop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Timber.d("onCreate");
setContentView(R.layout.activity_main);
- getRootScoop().inflate(R.layout.root, (ViewGroup) findViewById(R.id.root), true);
+ getActivityScoop().inflate(R.layout.root, (ViewGroup) findViewById(R.id.root), true);
ButterKnife.bind(this);
- DaggerInjector.fromScoop(getRootScoop()).inject(this);
-
- appRouter.onCreate(rootScoop);
- dialogRouter.onCreate(rootScoop);
- appRouter.goTo(new DemoScreen());
-
- Timber.d("onCreate");
+ DaggerInjector.fromScoop(getActivityScoop()).inject(this);
}
@Override
protected void onResume() {
super.onResume();
+ Timber.d("onResume");
+
+ if (!appRouter.hasActiveScreen()) {
+ appRouter.goTo(new DemoScreen());
+ }
}
@Override
protected void onPause() {
super.onPause();
+ Timber.d("onPause");
}
@Override
@@ -70,10 +71,9 @@ protected void onSaveInstanceState(Bundle outState) {
@Override
protected void onDestroy() {
-
Timber.d("onDestroy");
subscriptions.clear();
-
+ getActivityScoop().destroy();
super.onDestroy();
}
@@ -104,18 +104,19 @@ public void onBackPressed() {
super.onBackPressed();
}
- private Scoop getRootScoop() {
- if (rootScoop == null) {
+ private Scoop getActivityScoop() {
+ if (activityScoop == null) {
+ Timber.d("getActivityScoop");
ObjectGraph activityGraph = getApp().getApplicationGraph().plus(new MainActivityModule(this));
DaggerInjector activityInjector = new DaggerInjector(activityGraph);
- rootScoop = new Scoop.Builder("root")
+ activityScoop = new Scoop.Builder("activity_scoop")
.service(DaggerInjector.SERVICE_NAME, activityInjector)
.build();
}
- return rootScoop;
+ return activityScoop;
}
private App getApp() {
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/MainActivityModule.java b/scoop-basics/src/main/java/com/example/scoop/basics/MainActivityModule.java
index a9aa1e8..5c2a6f5 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/MainActivityModule.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/MainActivityModule.java
@@ -1,6 +1,5 @@
package com.example.scoop.basics;
-import android.app.Activity;
import com.example.scoop.basics.scoop.DialogUiContainer;
import com.example.scoop.basics.scoop.MainUiContainer;
import dagger.Provides;
@@ -25,7 +24,7 @@ public MainActivityModule(MainActivity mainActivity) {
}
@Provides
- Activity provideActivity() {
+ MainActivity provideActivity() {
return mainActivity;
}
}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/androidservices/SampleIntentService.java b/scoop-basics/src/main/java/com/example/scoop/basics/androidservices/SampleIntentService.java
new file mode 100644
index 0000000..575c927
--- /dev/null
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/androidservices/SampleIntentService.java
@@ -0,0 +1,39 @@
+package com.example.scoop.basics.androidservices;
+
+import android.app.IntentService;
+import android.content.Intent;
+import com.example.scoop.basics.App;
+import com.example.scoop.basics.MainActivity;
+import com.example.scoop.basics.scoop.AppRouter;
+import com.example.scoop.basics.ui.DemoScreen;
+import com.example.scoop.basics.ui.navigationsample.screen.AScreen;
+import javax.inject.Inject;
+import timber.log.Timber;
+
+public class SampleIntentService extends IntentService {
+
+ @Inject
+ AppRouter appRouter;
+
+ public SampleIntentService() {
+ super(SampleIntentService.class.getSimpleName());
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Timber.d("onCreate");
+ getApp().getApplicationGraph().inject(this);
+ }
+
+ private App getApp() {return (App) this.getApplicationContext();}
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ appRouter.replaceAllWith(new DemoScreen(), new AScreen());
+ Intent mainActivityIntent = new Intent(this, MainActivity.class);
+ mainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(mainActivityIntent);
+ }
+}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/AppRouter.java b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/AppRouter.java
index 60edf4d..f2248e9 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/AppRouter.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/AppRouter.java
@@ -1,25 +1,24 @@
package com.example.scoop.basics.scoop;
-import com.lyft.scoop.Router;
+import com.jakewharton.rxrelay.BehaviorRelay;
import com.lyft.scoop.RouteChange;
-import com.lyft.scoop.ScreenScooper;
+import com.lyft.scoop.Router;
import rx.Observable;
-import rx.subjects.BehaviorSubject;
public class AppRouter extends Router {
- private final BehaviorSubject screenChangeSubject = BehaviorSubject.create();
+ private final BehaviorRelay routeChangeRelay = BehaviorRelay.create();
- public AppRouter(ScreenScooper screenScooper, boolean hasEmptyStack) {
- super(screenScooper, hasEmptyStack);
+ public AppRouter(boolean hasEmptyStack) {
+ super(hasEmptyStack);
}
- public Observable observeScreenChange() {
- return screenChangeSubject.asObservable();
+ @Override
+ protected void onRouteChanged(RouteChange routeChange) {
+ routeChangeRelay.call(routeChange);
}
- @Override
- protected void onScoopChanged(RouteChange change) {
- screenChangeSubject.onNext(change);
+ public Observable observeRouteChange() {
+ return routeChangeRelay.asObservable();
}
}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogRouter.java b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogRouter.java
index ec4f7d9..3b6e66c 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogRouter.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogRouter.java
@@ -1,7 +1,6 @@
package com.example.scoop.basics.scoop;
import com.lyft.scoop.RouteChange;
-import com.lyft.scoop.Scoop;
import com.lyft.scoop.Screen;
import rx.Observable;
@@ -21,11 +20,7 @@ public void show(Screen screen) {
dialogRouter.replaceAllWith(screen);
}
- public void onCreate(Scoop rootScoop) {
- dialogRouter.onCreate(rootScoop);
- }
-
public Observable observeDialogChange() {
- return dialogRouter.observeScreenChange();
+ return dialogRouter.observeRouteChange();
}
}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogUiContainer.java b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogUiContainer.java
index f1b00f0..d53805b 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogUiContainer.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/DialogUiContainer.java
@@ -6,6 +6,8 @@
import com.example.scoop.basics.ui.Keyboard;
import com.lyft.scoop.LayoutInflater;
import com.lyft.scoop.RouteChange;
+import com.lyft.scoop.Scoop;
+import com.lyft.scoop.ScreenScooper;
import com.lyft.scoop.UiContainer;
import com.lyft.scoop.ViewControllerInflater;
import com.lyft.scoop.dagger.DaggerInjector;
@@ -13,13 +15,15 @@
import com.lyft.scoop.dagger.DaggerViewControllerInflater;
import javax.inject.Inject;
import rx.functions.Action1;
-import timber.log.Timber;
public class DialogUiContainer extends UiContainer {
@Inject
DialogRouter dialogRouter;
+ @Inject
+ ScreenScooper screenScooper;
+
private ViewSubscriptions subscriptions = new ViewSubscriptions();
public DialogUiContainer(Context context, AttributeSet attrs) {
@@ -62,12 +66,17 @@ protected void onDetachedFromWindow() {
private Action1 onDialogChanged = new Action1() {
@Override
- public void call(RouteChange screenChange) {
- if (screenChange.next != null) {
- Timber.d("Scoop changed:" + screenChange.next.getClass().getSimpleName());
- }
- DialogUiContainer.this.goTo(screenChange);
+ public void call(RouteChange routeChange) {
+
+ Scoop rootScoop = Scoop.fromView(DialogUiContainer.this);
+
+ Scoop currentScreenScoop = Scoop.fromView(getActiveView());
+
+ Scoop scoop = screenScooper.create(rootScoop, currentScreenScoop, routeChange.fromPath, routeChange.toPath);
+
+ goTo(routeChange.toScreenSwap(scoop));
+
Keyboard.hideKeyboard(DialogUiContainer.this);
}
};
-}
\ No newline at end of file
+}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/MainUiContainer.java b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/MainUiContainer.java
index 90fc454..8921278 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/scoop/MainUiContainer.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/scoop/MainUiContainer.java
@@ -6,6 +6,8 @@
import com.example.scoop.basics.ui.Keyboard;
import com.lyft.scoop.LayoutInflater;
import com.lyft.scoop.RouteChange;
+import com.lyft.scoop.Scoop;
+import com.lyft.scoop.ScreenScooper;
import com.lyft.scoop.UiContainer;
import com.lyft.scoop.ViewControllerInflater;
import com.lyft.scoop.dagger.DaggerInjector;
@@ -13,13 +15,15 @@
import com.lyft.scoop.dagger.DaggerViewControllerInflater;
import javax.inject.Inject;
import rx.functions.Action1;
-import timber.log.Timber;
public class MainUiContainer extends UiContainer {
@Inject
AppRouter appRouter;
+ @Inject
+ ScreenScooper screenScooper;
+
private ViewSubscriptions subscriptions = new ViewSubscriptions();
public MainUiContainer(Context context, AttributeSet attrs) {
@@ -50,7 +54,7 @@ protected void onAttachedToWindow() {
return;
}
- subscriptions.add(appRouter.observeScreenChange(), onScreenChanged);
+ subscriptions.add(appRouter.observeRouteChange(), onRouteChange);
}
@Override
@@ -60,14 +64,21 @@ protected void onDetachedFromWindow() {
subscriptions.unsubscribe();
}
- private Action1 onScreenChanged = new Action1() {
+ private Action1 onRouteChange = new Action1() {
@Override
- public void call(RouteChange screenChange) {
- if (screenChange.next != null) {
- Timber.d("Scoop changed:" + screenChange.next.getClass().getSimpleName());
+ public void call(RouteChange routeChange) {
+
+ Scoop rootScoop = Scoop.fromView(MainUiContainer.this);
+
+ Scoop currentScreenScoop = Scoop.fromView(getActiveView());
+
+ Scoop scoop = screenScooper.create(rootScoop, currentScreenScoop, routeChange.fromPath, routeChange.toPath);
+
+ // To prevent showing empty screen when activity is closed with "Back" button
+ if (!routeChange.toPath.isEmpty()) {
+ goTo(routeChange.toScreenSwap(scoop));
+ Keyboard.hideKeyboard(MainUiContainer.this);
}
- MainUiContainer.this.goTo(screenChange);
- Keyboard.hideKeyboard(MainUiContainer.this);
}
};
}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/ui/DemosController.java b/scoop-basics/src/main/java/com/example/scoop/basics/ui/DemosController.java
index b4fa8f1..8555a75 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/ui/DemosController.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/ui/DemosController.java
@@ -1,10 +1,15 @@
package com.example.scoop.basics.ui;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
import butterknife.OnClick;
import com.example.scoop.basics.R;
+import com.example.scoop.basics.androidservices.SampleIntentService;
import com.example.scoop.basics.rx.ViewSubscriptions;
import com.example.scoop.basics.scoop.AppRouter;
-import com.example.scoop.basics.scoop.DialogRouter;
import com.example.scoop.basics.ui.layoutsample.screen.LayoutScreen;
import com.example.scoop.basics.ui.layoutsample.screen.NestedLayoutScreen;
import com.example.scoop.basics.ui.navigationsample.screen.AScreen;
@@ -17,14 +22,14 @@
public class DemosController extends ViewController {
private AppRouter appRouter;
- private DialogRouter dialogRouter;
+ private NotificationManager notificationManager;
ViewSubscriptions viewSubscriptions = new ViewSubscriptions();
@Inject
- public DemosController(AppRouter appRouter, DialogRouter dialogRouter) {
+ public DemosController(AppRouter appRouter, NotificationManager notificationManager) {
this.appRouter = appRouter;
- this.dialogRouter = dialogRouter;
+ this.notificationManager = notificationManager;
}
@Override
@@ -73,4 +78,23 @@ public void goToNestedLayoutSample() {
public void goToTransitions() {
appRouter.goTo(new TransitionsScreen());
}
+
+ @OnClick(R.id.notification_button)
+ public void openNotification() {
+ Context context = getView().getContext();
+
+ Intent serviceIntent = new Intent(context, SampleIntentService.class);
+
+ PendingIntent contentIntent = PendingIntent.getService(context, 0,
+ serviceIntent, 0);
+
+ Notification notification = new Notification.Builder(context)
+ .setContentTitle("This is a push notification.")
+ .setContentText("Scoop!")
+ .setSmallIcon(R.drawable.ic_launcher)
+ .setContentIntent(contentIntent)
+ .build();
+
+ notificationManager.notify(100, notification);
+ }
}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/SlideDownTransition.java b/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/SlideDownTransition.java
index f9b6cda..f2c2222 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/SlideDownTransition.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/SlideDownTransition.java
@@ -13,28 +13,23 @@ public class SlideDownTransition implements ScreenTransition {
@Override
public void transition(final ViewGroup root, final View from, final View to, final TransitionListener transitionListener) {
- if (to == null) {
- root.removeView(from);
- return;
- }
-
- Animator animator = createAnimator(to);
+ Animator animator = createAnimator(from);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- root.removeView(from);
+ ((ViewGroup) from.getParent()).removeView(from);
transitionListener.onTransitionCompleted();
}
});
animator.start();
}
- private Animator createAnimator(View to) {
- int fromTranslation = to.getHeight();
+ private Animator createAnimator(View from) {
+ int fromTranslation = from.getHeight();
AnimatorSet set = new AnimatorSet();
- set.play(ObjectAnimator.ofFloat(to, View.TRANSLATION_Y, fromTranslation));
+ set.play(ObjectAnimator.ofFloat(from, View.TRANSLATION_Y, fromTranslation));
return set;
}
diff --git a/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/screen/Dialog.java b/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/screen/Dialog.java
index b813afd..e691988 100644
--- a/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/screen/Dialog.java
+++ b/scoop-basics/src/main/java/com/example/scoop/basics/ui/transitions/dialogtransitions/screen/Dialog.java
@@ -12,7 +12,7 @@
@Controller(DialogController.class)
@DaggerModule(DialogModule.class)
-@EnterTransition(SlideDownTransition.class)
-@ExitTransition(SlideUpTransition.class)
+@EnterTransition(SlideUpTransition.class)
+@ExitTransition(SlideDownTransition.class)
public class Dialog extends Screen {
}
diff --git a/scoop-basics/src/main/res/layout/demos.xml b/scoop-basics/src/main/res/layout/demos.xml
index 08e87cf..c4a483e 100644
--- a/scoop-basics/src/main/res/layout/demos.xml
+++ b/scoop-basics/src/main/res/layout/demos.xml
@@ -47,4 +47,11 @@
android:text="Nested layout sample"
/>
-
\ No newline at end of file
+
+
+
diff --git a/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerInjector.java b/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerInjector.java
index a553747..38b9ac8 100644
--- a/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerInjector.java
+++ b/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerInjector.java
@@ -1,5 +1,6 @@
package com.lyft.scoop.dagger;
+import android.content.Context;
import android.view.View;
import com.lyft.scoop.Scoop;
import com.lyft.scoop.Screen;
@@ -35,6 +36,10 @@ public static DaggerInjector fromView(View view) {
return Scoop.fromView(view).findService(SERVICE_NAME);
}
+ public static DaggerInjector fromContext(Context context) {
+ return Scoop.fromContext(context).findService(SERVICE_NAME);
+ }
+
public static Scoop extend(final Scoop parentScoop, final Object... modules) {
final Screen parentScreen = Screen.fromScoop(parentScoop);
final Scoop.Builder scoopBuilder = new Scoop.Builder(parentScreen.getClass().getSimpleName(), parentScoop)
diff --git a/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerScreenScooper.java b/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerScreenScoopFactory.java
similarity index 89%
rename from scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerScreenScooper.java
rename to scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerScreenScoopFactory.java
index 620a90b..3ab5c27 100644
--- a/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerScreenScooper.java
+++ b/scoop-dagger/src/main/java/com/lyft/scoop/dagger/DaggerScreenScoopFactory.java
@@ -2,9 +2,9 @@
import com.lyft.scoop.Scoop;
import com.lyft.scoop.Screen;
-import com.lyft.scoop.ScreenScooper;
+import com.lyft.scoop.ScreenScoopFactory;
-public class DaggerScreenScooper extends ScreenScooper {
+public class DaggerScreenScoopFactory extends ScreenScoopFactory {
@Override
protected Scoop addServices(Scoop.Builder scoopBuilder, Screen screen, Scoop parentScoop) {
diff --git a/scoop-dagger/src/test/java/com/lyft/scoop/dagger/DaggerScreenScooperTest.java b/scoop-dagger/src/test/java/com/lyft/scoop/dagger/DaggerScreenScoopFactoryTest.java
similarity index 88%
rename from scoop-dagger/src/test/java/com/lyft/scoop/dagger/DaggerScreenScooperTest.java
rename to scoop-dagger/src/test/java/com/lyft/scoop/dagger/DaggerScreenScoopFactoryTest.java
index d3fdfc4..e23b3f3 100644
--- a/scoop-dagger/src/test/java/com/lyft/scoop/dagger/DaggerScreenScooperTest.java
+++ b/scoop-dagger/src/test/java/com/lyft/scoop/dagger/DaggerScreenScoopFactoryTest.java
@@ -11,19 +11,19 @@
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
-public class DaggerScreenScooperTest {
+public class DaggerScreenScoopFactoryTest {
@Mock
DaggerInjector mockDaggerInjector;
- private DaggerScreenScooper daggerScreenScooper;
+ private DaggerScreenScoopFactory daggerScreenScooper;
private Scoop.Builder scoopBuilder;
private Scoop scoop;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- daggerScreenScooper = new DaggerScreenScooper();
+ daggerScreenScooper = new DaggerScreenScoopFactory();
scoop = new Scoop.Builder("root").service(DaggerInjector.SERVICE_NAME, mockDaggerInjector).build();
scoopBuilder = new Scoop.Builder("child");
}
diff --git a/scoop/src/main/java/com/lyft/scoop/RouteChange.java b/scoop/src/main/java/com/lyft/scoop/RouteChange.java
index 6897fe9..2907e4f 100644
--- a/scoop/src/main/java/com/lyft/scoop/RouteChange.java
+++ b/scoop/src/main/java/com/lyft/scoop/RouteChange.java
@@ -1,17 +1,41 @@
package com.lyft.scoop;
+import java.util.List;
+
public class RouteChange {
- public final Scoop scoop;
- public final Screen previous;
- public final Screen next;
+ public final List fromPath;
+ public final List toPath;
public final TransitionDirection direction;
- public RouteChange(Scoop scoop, Screen previous, Screen next, TransitionDirection direction) {
- this.scoop = scoop;
- this.previous = previous;
- this.next = next;
-
+ public RouteChange(List fromPath, List toPath, TransitionDirection direction) {
+ this.fromPath = fromPath;
+ this.toPath = toPath;
this.direction = direction;
}
+
+ public ScreenSwap toScreenSwap(Scoop scoop) {
+ return new ScreenSwap(scoop,
+ this.previousScreen(),
+ this.nextScreen(),
+ this.direction);
+ }
+
+ private Screen previousScreen() {
+ return getScreenFromPath(fromPath);
+ }
+
+ private Screen nextScreen() {
+ return getScreenFromPath(toPath);
+ }
+
+ private Screen getScreenFromPath(List path) {
+ Screen screen = null;
+
+ if (!path.isEmpty()) {
+ screen = path.get(path.size() - 1);
+ }
+
+ return screen;
+ }
}
diff --git a/scoop/src/main/java/com/lyft/scoop/Router.java b/scoop/src/main/java/com/lyft/scoop/Router.java
index f43b356..100d131 100644
--- a/scoop/src/main/java/com/lyft/scoop/Router.java
+++ b/scoop/src/main/java/com/lyft/scoop/Router.java
@@ -1,46 +1,31 @@
package com.lyft.scoop;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
public abstract class Router {
- private ScoopBackstack backStack = new ScoopBackstack();
- private ScreenScooper screenScooper;
- private Scoop root;
+ private ScreenBackstack backStack = new ScreenBackstack();
private boolean allowEmptyStack;
- public Router(ScreenScooper screenScooper) {
- this.screenScooper = screenScooper;
+ public Router() {
this.allowEmptyStack = false;
}
- public Router(ScreenScooper screenScooper, boolean allowEmptyStack) {
+ public Router(boolean allowEmptyStack) {
- this.screenScooper = screenScooper;
this.allowEmptyStack = allowEmptyStack;
}
- public void onCreate(Scoop root) {
- this.root = root;
- }
-
- protected abstract void onScoopChanged(RouteChange routeChange);
-
public boolean goBack() {
if (!backStack.isEmpty()) {
- Scoop previousScoop = backStack.peek();
- Screen previousScreen = Screen.fromScoop(previousScoop);
+ List fromPath = backStack.asList();
backStack.pop();
- if (!backStack.isEmpty()) {
- Scoop nextScoop = backStack.peek();
- Screen nextScreen = Screen.fromScoop(nextScoop);
- performScoopChange(nextScoop, previousScreen, nextScreen, TransitionDirection.EXIT);
- return true;
- } else if (allowEmptyStack) {
- performScoopChange(previousScoop, previousScreen, null, TransitionDirection.EXIT);
+ performRouteChange(fromPath, backStack.asList(), TransitionDirection.EXIT);
+ if (!backStack.isEmpty() || allowEmptyStack) {
return true;
}
}
@@ -48,47 +33,40 @@ public boolean goBack() {
return false;
}
- public void goTo(Screen screen) {
- if (tryHandleEmptyBackstack(screen)) {
+ public void goTo(Screen nextScreen) {
+ if (tryHandleEmptyBackstack(nextScreen)) {
return;
}
- Scoop previousScoop = backStack.peek();
- Screen previousScreen = Screen.fromScoop(previousScoop);
- if (sameScreen(Screen.fromScoop(previousScoop), screen)) {
+ List fromPath = backStack.asList();
+
+ if (Screen.equals(backStack.peek(), nextScreen)) {
return;
}
- Scoop nextScoop = screenScooper.createScreenScoop(screen, previousScoop);
- backStack.push(nextScoop);
- performScoopChange(nextScoop, previousScreen, screen, TransitionDirection.ENTER);
+ backStack.push(nextScreen);
+
+ performRouteChange(fromPath, backStack.asList(), TransitionDirection.ENTER);
}
- public void replaceWith(Screen screen) {
- if (tryHandleEmptyBackstack(screen)) {
+ public void replaceWith(Screen nextScreen) {
+ if (tryHandleEmptyBackstack(nextScreen)) {
return;
}
- Scoop previousScoop = backStack.peek();
- Screen previousScreen = Screen.fromScoop(previousScoop);
+ List fromPath = backStack.asList();
- if (sameScreen(Screen.fromScoop(previousScoop), screen)) {
+ Screen previousScreen = backStack.peek();
+
+ if (Screen.equals(previousScreen, nextScreen)) {
return;
}
- Scoop nextScoop;
-
if (!backStack.isEmpty()) {
- Scoop previousParent = previousScoop.getParent();
-
backStack.pop();
-
- nextScoop = screenScooper.createScreenScoop(screen, previousParent);
- } else {
- nextScoop = screenScooper.createScreenScoop(screen, root);
}
- backStack.push(nextScoop);
- performScoopChange(nextScoop, previousScreen, screen, TransitionDirection.ENTER);
+ backStack.push(nextScreen);
+ performRouteChange(fromPath, backStack.asList(), TransitionDirection.ENTER);
}
public void replaceAllWith(Screen... screens) {
@@ -96,22 +74,15 @@ public void replaceAllWith(Screen... screens) {
}
public void replaceAllWith(List screens) {
- Screen previousScreen = Screen.fromScoop(backStack.peek());
+ List fromPath = backStack.asList();
backStack.clear();
- Scoop scoop = root;
for (final Screen screen : screens) {
- final Scoop newScoop = screenScooper.createScreenScoop(screen, scoop);
- backStack.push(newScoop);
- scoop = newScoop;
+ backStack.push(screen);
}
- Screen currentScreen = null;
- if (!screens.isEmpty()) {
- currentScreen = screens.get(screens.size() - 1);
- }
- performScoopChange(backStack.peek(), previousScreen, currentScreen, TransitionDirection.ENTER);
+ performRouteChange(fromPath, backStack.asList(), TransitionDirection.ENTER);
}
public void resetTo(Screen screen) {
@@ -121,24 +92,27 @@ public void resetTo(Screen screen) {
resetTo(screen, TransitionDirection.EXIT);
}
- public void resetTo(Screen screen, TransitionDirection direction) {
- Scoop previousScoop = backStack.peek();
- Screen previousScreen = Screen.fromScoop(previousScoop);
+ public void resetTo(Screen nextScreen, TransitionDirection direction) {
+ List fromPath = backStack.asList();
+
+ // do nothing if screen already top of reset
+ if (!backStack.isEmpty() && Screen.equals(nextScreen, backStack.peek())) {
+ return;
+ }
while (!backStack.isEmpty()) {
- Scoop topScoop = backStack.peek();
+ Screen topScreen = backStack.peek();
- if (sameScreen(screen, Screen.fromScoop(topScoop))) {
- performScoopChange(topScoop, previousScreen, screen, direction);
+ if (Screen.equals(nextScreen, topScreen)) {
+ performRouteChange(fromPath, backStack.asList(), direction);
return;
}
backStack.pop();
}
- Scoop nextScoop = screenScooper.createScreenScoop(screen, root);
- backStack.push(nextScoop);
- performScoopChange(nextScoop, previousScreen, screen, direction);
+ backStack.push(nextScreen);
+ performRouteChange(fromPath, backStack.asList(), direction);
}
public boolean hasActiveScreen() {
@@ -147,23 +121,16 @@ public boolean hasActiveScreen() {
private boolean tryHandleEmptyBackstack(final Screen screen) {
if (backStack.isEmpty()) {
- final Scoop newScoop = screenScooper.createScreenScoop(screen, root);
- backStack.push(newScoop);
- performScoopChange(backStack.peek(), null, screen, TransitionDirection.ENTER);
+ backStack.push(screen);
+ performRouteChange(Collections.emptyList(), backStack.asList(), TransitionDirection.ENTER);
return true;
}
return false;
}
- private void performScoopChange(Scoop scoop, Screen previous, Screen next, TransitionDirection direction) {
- onScoopChanged(new RouteChange(scoop, previous, next, direction));
+ private void performRouteChange(List fromPath, List toPath, TransitionDirection direction) {
+ onRouteChanged(new RouteChange(fromPath, toPath, direction));
}
- static boolean sameScreen(Screen previous, Screen next) {
-
- if (previous == null || next == null) {
- return false;
- }
- return previous.equals(next);
- }
+ protected abstract void onRouteChanged(RouteChange routeChange);
}
diff --git a/scoop/src/main/java/com/lyft/scoop/Scoop.java b/scoop/src/main/java/com/lyft/scoop/Scoop.java
index 6cb5881..57bb78e 100644
--- a/scoop/src/main/java/com/lyft/scoop/Scoop.java
+++ b/scoop/src/main/java/com/lyft/scoop/Scoop.java
@@ -108,7 +108,21 @@ public static void setViewBinder(ViewBinder binder) {
}
public static Scoop fromView(View view) {
- return ((IHaveScoop) view.getContext()).getScoop();
+ if (view == null) {
+ return null;
+ }
+ return fromContext(view.getContext());
+ }
+
+ public static Scoop fromContext(Context context) {
+
+ if (!(context instanceof HaveScoop)) {
+ throw new RuntimeException("View does not implement interface: HaveScoop");
+ }
+
+ HaveScoop haveScoop = (HaveScoop) context;
+
+ return haveScoop.getScoop();
}
public LayoutInflater inflater(Context context) {
@@ -123,12 +137,12 @@ public View inflate(int layoutId, ViewGroup viewGroup, boolean attachToRoot) {
return inflater(viewGroup.getContext()).inflate(layoutId, viewGroup, attachToRoot);
}
- private interface IHaveScoop {
+ protected interface HaveScoop {
Scoop getScoop();
}
- private static class ScoopContextWrapper extends ContextWrapper implements IHaveScoop {
+ private static class ScoopContextWrapper extends ContextWrapper implements HaveScoop {
private final Scoop scoop;
@@ -141,4 +155,4 @@ public Scoop getScoop() {
return this.scoop;
}
}
-}
\ No newline at end of file
+}
diff --git a/scoop/src/main/java/com/lyft/scoop/ScoopBackstack.java b/scoop/src/main/java/com/lyft/scoop/ScoopBackstack.java
deleted file mode 100644
index 2420cb1..0000000
--- a/scoop/src/main/java/com/lyft/scoop/ScoopBackstack.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.lyft.scoop;
-
-import java.util.ArrayDeque;
-
-class ScoopBackstack {
-
- ArrayDeque backStack = new ArrayDeque<>();
-
- public void pop() {
- Scoop poppedScoop = backStack.pop();
- poppedScoop.destroy();
- }
-
- public boolean isEmpty() {
- return backStack.isEmpty();
- }
-
- public Scoop peek() {
- return backStack.peek();
- }
-
- public void push(Scoop scoop) {
- backStack.push(scoop);
- }
-
- public void clear() {
- while(!backStack.isEmpty()) {
- pop();
- }
- }
-}
diff --git a/scoop/src/main/java/com/lyft/scoop/Screen.java b/scoop/src/main/java/com/lyft/scoop/Screen.java
index c56a1c3..33e1cb7 100644
--- a/scoop/src/main/java/com/lyft/scoop/Screen.java
+++ b/scoop/src/main/java/com/lyft/scoop/Screen.java
@@ -14,6 +14,14 @@ public Screen() {
viewState = new SparseArray();
}
+ public static boolean equals(Screen previous, Screen next) {
+
+ if (previous == null || next == null) {
+ return false;
+ }
+ return previous.equals(next);
+ }
+
public void saveViewState(View view) {
SparseArray viewState = new SparseArray();
view.saveHierarchyState(viewState);
diff --git a/scoop/src/main/java/com/lyft/scoop/ScreenBackstack.java b/scoop/src/main/java/com/lyft/scoop/ScreenBackstack.java
new file mode 100644
index 0000000..d8af64f
--- /dev/null
+++ b/scoop/src/main/java/com/lyft/scoop/ScreenBackstack.java
@@ -0,0 +1,42 @@
+package com.lyft.scoop;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+class ScreenBackstack {
+
+ ArrayDeque backStack = new ArrayDeque<>();
+
+ public void pop() {
+ Screen poppedScreen = backStack.pop();
+ }
+
+ public boolean isEmpty() {
+ return backStack.isEmpty();
+ }
+
+ public Screen peek() {
+ return backStack.peek();
+ }
+
+ public void push(Screen screen) {
+ backStack.push(screen);
+ }
+
+ public void clear() {
+ while (!backStack.isEmpty()) {
+ pop();
+ }
+ }
+
+ public List asList() {
+ Screen[] array = backStack.toArray(new Screen[backStack.size()]);
+
+ List list = Arrays.asList(array);
+ Collections.reverse(list);
+
+ return list;
+ }
+}
diff --git a/scoop/src/main/java/com/lyft/scoop/ScreenScoopFactory.java b/scoop/src/main/java/com/lyft/scoop/ScreenScoopFactory.java
new file mode 100644
index 0000000..594839b
--- /dev/null
+++ b/scoop/src/main/java/com/lyft/scoop/ScreenScoopFactory.java
@@ -0,0 +1,16 @@
+package com.lyft.scoop;
+
+public class ScreenScoopFactory {
+
+ public final Scoop createScreenScoop(Screen screen, Scoop parentScoop) {
+
+ Scoop.Builder scoopBuilder = new Scoop.Builder(screen.getClass().getSimpleName(), parentScoop)
+ .service(Screen.SERVICE_NAME, screen);
+
+ return addServices(scoopBuilder, screen, parentScoop);
+ }
+
+ protected Scoop addServices(Scoop.Builder scoopBuilder, Screen screen, Scoop parentScoop) {
+ return scoopBuilder.build();
+ }
+}
diff --git a/scoop/src/main/java/com/lyft/scoop/ScreenScooper.java b/scoop/src/main/java/com/lyft/scoop/ScreenScooper.java
index 711ffa9..318a1cb 100644
--- a/scoop/src/main/java/com/lyft/scoop/ScreenScooper.java
+++ b/scoop/src/main/java/com/lyft/scoop/ScreenScooper.java
@@ -1,16 +1,74 @@
package com.lyft.scoop;
+import java.util.ArrayList;
+import java.util.List;
+
public class ScreenScooper {
- public final Scoop createScreenScoop(Screen screen, Scoop parentScoop) {
+ private ScreenScoopFactory screenScoopFactory;
+
+ public ScreenScooper(ScreenScoopFactory screenScoopFactory) {
+ this.screenScoopFactory = screenScoopFactory;
+ }
+
+ public Scoop create(Scoop rootScoop, Scoop currentScreenScoop, List fromPath, List toPath) {
+ Scoop finalScoop = null;
+
+ List scoops = getCurrentScoops(fromPath, currentScreenScoop);
+
+ int index = 0;
+
+ while (index < fromPath.size() && currentScreenScoop != null) {
+ Screen fromScreen = safeElementGet(fromPath, index);
+ Screen toScreen = safeElementGet(toPath, index);
+
+ Scoop scoop = scoops.get(index);
+
+ if (Screen.equals(fromScreen, toScreen)) {
+ finalScoop = scoop;
+ } else {
+ scoop.destroy();
+ break;
+ }
+
+ index++;
+ }
+
+ while (index < toPath.size()) {
+ Screen toScreen = safeElementGet(toPath, index);
+
+ if (finalScoop == null) {
+ finalScoop = rootScoop;
+ }
+
+ finalScoop = screenScoopFactory.createScreenScoop(toScreen, finalScoop);
+
+ index++;
+ }
+
+ return finalScoop;
+ }
+
+ private ArrayList getCurrentScoops(List fromPath, Scoop currentScreenScoop) {
+
+ ArrayList scoops = new ArrayList<>();
+
+ Scoop startScoop = currentScreenScoop;
- Scoop.Builder scoopBuilder = new Scoop.Builder(screen.getClass().getSimpleName(), parentScoop)
- .service(Screen.SERVICE_NAME, screen);
+ if (startScoop != null) {
+ for (int i = 0; i < fromPath.size(); i++) {
+ scoops.add(0, startScoop);
+ startScoop = startScoop.getParent();
+ }
+ }
- return addServices(scoopBuilder, screen, parentScoop);
+ return scoops;
}
- protected Scoop addServices(Scoop.Builder scoopBuilder, Screen screen, Scoop parentScoop) {
- return scoopBuilder.build();
+ private T safeElementGet(List fromPath, int i) {
+ if (i < fromPath.size()) {
+ return fromPath.get(i);
+ }
+ return null;
}
}
diff --git a/scoop/src/main/java/com/lyft/scoop/ScreenSwap.java b/scoop/src/main/java/com/lyft/scoop/ScreenSwap.java
new file mode 100644
index 0000000..be42ff6
--- /dev/null
+++ b/scoop/src/main/java/com/lyft/scoop/ScreenSwap.java
@@ -0,0 +1,17 @@
+package com.lyft.scoop;
+
+public class ScreenSwap {
+
+ public final Scoop scoop;
+ public final Screen previous;
+ public final Screen next;
+ public final TransitionDirection direction;
+
+ public ScreenSwap(Scoop scoop, Screen previous, Screen next, TransitionDirection direction) {
+ this.scoop = scoop;
+ this.previous = previous;
+ this.next = next;
+
+ this.direction = direction;
+ }
+}
diff --git a/scoop/src/main/java/com/lyft/scoop/UiContainer.java b/scoop/src/main/java/com/lyft/scoop/UiContainer.java
index 43f9ed1..9b255bc 100644
--- a/scoop/src/main/java/com/lyft/scoop/UiContainer.java
+++ b/scoop/src/main/java/com/lyft/scoop/UiContainer.java
@@ -12,7 +12,7 @@
public abstract class UiContainer extends FrameLayout implements HandleBack, TransitionListener {
- private ArrayDeque routeChangeQueue = new ArrayDeque<>();
+ private ArrayDeque screenSwapQueue = new ArrayDeque<>();
private boolean isTransitioning;
private View active;
@@ -44,13 +44,17 @@ public boolean onBack() {
return childCanGoBack();
}
- public void goTo(RouteChange routeChange) {
- if (routeChangeQueue.isEmpty()) {
- routeChangeQueue.add(routeChange);
+ public View getActiveView() {
+ return active;
+ }
+
+ public void goTo(ScreenSwap screenSwap) {
+ if (screenSwapQueue.isEmpty()) {
+ screenSwapQueue.add(screenSwap);
- swap(routeChange);
+ swap(screenSwap);
} else {
- routeChangeQueue.add(routeChange);
+ screenSwapQueue.add(screenSwap);
}
}
@@ -60,11 +64,11 @@ public void onTransitionCompleted() {
transitionListener.onTransitionCompleted();
isTransitioning = false;
- if (!routeChangeQueue.isEmpty()) {
- routeChangeQueue.pop();
+ if (!screenSwapQueue.isEmpty()) {
+ screenSwapQueue.pop();
- if (!routeChangeQueue.isEmpty()) {
- swap(routeChangeQueue.peek());
+ if (!screenSwapQueue.isEmpty()) {
+ swap(screenSwapQueue.peek());
}
}
}
@@ -79,7 +83,7 @@ public boolean dispatchTouchEvent(MotionEvent event) {
}
@Override
- public boolean dispatchDragEvent(DragEvent event){
+ public boolean dispatchDragEvent(DragEvent event) {
if (isTransitioning) {
return true;
} else {
@@ -88,7 +92,7 @@ public boolean dispatchDragEvent(DragEvent event){
}
@Override
- public boolean dispatchKeyEvent(KeyEvent event){
+ public boolean dispatchKeyEvent(KeyEvent event) {
if (isTransitioning) {
return true;
} else {
@@ -97,7 +101,7 @@ public boolean dispatchKeyEvent(KeyEvent event){
}
@Override
- public boolean dispatchKeyEventPreIme(KeyEvent event){
+ public boolean dispatchKeyEventPreIme(KeyEvent event) {
if (isTransitioning) {
return true;
} else {
@@ -106,7 +110,7 @@ public boolean dispatchKeyEventPreIme(KeyEvent event){
}
@Override
- public boolean dispatchKeyShortcutEvent(KeyEvent event){
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) {
if (isTransitioning) {
return true;
} else {
@@ -115,7 +119,7 @@ public boolean dispatchKeyShortcutEvent(KeyEvent event){
}
@Override
- public boolean dispatchTrackballEvent(MotionEvent event){
+ public boolean dispatchTrackballEvent(MotionEvent event) {
if (isTransitioning) {
return true;
} else {
@@ -123,39 +127,38 @@ public boolean dispatchTrackballEvent(MotionEvent event){
}
}
- private void swap(RouteChange routeChange) {
- Screen nextScreen = routeChange.next;
-
+ private void swap(ScreenSwap screenSwap) {
+ Screen nextScreen = screenSwap.next;
final View prevView = active;
- if (active != null && routeChange.previous != null) {
- routeChange.previous.saveViewState(active);
+ if (active != null && screenSwap.previous != null) {
+ screenSwap.previous.saveViewState(active);
}
if (nextScreen == null) {
active = null;
} else if (nextScreen.getController() != null) {
- active = inflateControllerView(routeChange, nextScreen);
+ active = inflateControllerView(screenSwap, nextScreen);
nextScreen.restoreViewState(active);
} else {
- active = inflateLayout(routeChange, nextScreen);
+ active = inflateLayout(screenSwap, nextScreen);
nextScreen.restoreViewState(active);
}
isTransitioning = true;
- final ScreenTransition transition = getTransition(routeChange);
+ final ScreenTransition transition = getTransition(screenSwap);
transition.transition(this, prevView, active, this);
}
- private View inflateControllerView(RouteChange screenChange, Screen nextScreen) {
+ private View inflateControllerView(ScreenSwap screenChange, Screen nextScreen) {
return getViewControllerInflater().inflateViewController(screenChange.scoop, nextScreen.getController(), this);
}
- private View inflateLayout(RouteChange screenChange, Screen nextScreen) {
+ private View inflateLayout(ScreenSwap screenChange, Screen nextScreen) {
return getLayoutInflater().inflateView(screenChange.scoop, nextScreen, this);
}
- private ScreenTransition getTransition(RouteChange screenChange) {
+ private ScreenTransition getTransition(ScreenSwap screenChange) {
if (screenChange.direction == TransitionDirection.ENTER) {
return getEnterTransition(screenChange);
} else {
@@ -196,7 +199,7 @@ private TransitionListener getTransitionListener() {
return transitionListener;
}
- static ScreenTransition getEnterTransition(RouteChange screenChange) {
+ static ScreenTransition getEnterTransition(ScreenSwap screenChange) {
if (screenChange.next == null) {
return new InstantTransition();
}
@@ -214,7 +217,7 @@ static ScreenTransition getEnterTransition(RouteChange screenChange) {
return new InstantTransition();
}
- static ScreenTransition getExitTransition(RouteChange screenChange) {
+ static ScreenTransition getExitTransition(ScreenSwap screenChange) {
if (screenChange.previous == null) {
return new InstantTransition();
}
diff --git a/scoop/src/main/java/com/lyft/scoop/transitions/FadeTransition.java b/scoop/src/main/java/com/lyft/scoop/transitions/FadeTransition.java
index f1e3fbd..078fe0e 100644
--- a/scoop/src/main/java/com/lyft/scoop/transitions/FadeTransition.java
+++ b/scoop/src/main/java/com/lyft/scoop/transitions/FadeTransition.java
@@ -33,6 +33,7 @@ public FadeTransition(final long fadeTime, final Interpolator interpolator) {
@Override
public void performTranslate(final ViewGroup root, final View from, View to, final TransitionListener transitionListener) {
Animator animator = createAnimator(from, to);
+
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -40,20 +41,23 @@ public void onAnimationEnd(Animator animation) {
transitionListener.onTransitionCompleted();
}
});
+
animator.start();
}
private Animator createAnimator(View from, View to) {
AnimatorSet set = new AnimatorSet();
- ObjectAnimator fadeOut = ObjectAnimator.ofFloat(from, View.ALPHA, 1f, 0f).setDuration(fadeTime);
- ObjectAnimator fadeIn = ObjectAnimator.ofFloat(to, View.ALPHA, 0f, 1f).setDuration(fadeTime);
-
- fadeOut.setInterpolator(interpolator);
- fadeIn.setInterpolator(interpolator);
-
- set.play(fadeOut);
- set.play(fadeIn);
-
+ if (from != null) {
+ ObjectAnimator fadeOut = ObjectAnimator.ofFloat(from, View.ALPHA, 1f, 0f).setDuration(fadeTime);
+ fadeOut.setInterpolator(interpolator);
+ set.play(fadeOut);
+ }
+
+ if (to != null) {
+ ObjectAnimator fadeIn = ObjectAnimator.ofFloat(to, View.ALPHA, 0f, 1f).setDuration(fadeTime);
+ fadeIn.setInterpolator(interpolator);
+ set.play(fadeIn);
+ }
return set;
}
}
diff --git a/scoop/src/main/java/com/lyft/scoop/transitions/ObjectAnimatorTransition.java b/scoop/src/main/java/com/lyft/scoop/transitions/ObjectAnimatorTransition.java
index 3ac911f..976eb1c 100644
--- a/scoop/src/main/java/com/lyft/scoop/transitions/ObjectAnimatorTransition.java
+++ b/scoop/src/main/java/com/lyft/scoop/transitions/ObjectAnimatorTransition.java
@@ -10,13 +10,17 @@ public abstract class ObjectAnimatorTransition implements ScreenTransition {
@Override
public void transition(final ViewGroup root, final View from, final View to, final TransitionListener transitionListener) {
- root.addView(to);
- waitForMeasure(to, new OnMeasuredCallback() {
- @Override
- public void onMeasured(View view, int width, int height) {
- performTranslate(root, from, to, transitionListener);
- }
- });
+ if (to == null) {
+ performTranslate(root, from, to, transitionListener);
+ } else {
+ root.addView(to);
+ waitForMeasure(to, new OnMeasuredCallback() {
+ @Override
+ public void onMeasured(View view, int width, int height) {
+ performTranslate(root, from, to, transitionListener);
+ }
+ });
+ }
}
protected abstract void performTranslate(ViewGroup root, View from, View to, TransitionListener transitionListener);
diff --git a/scoop/src/test/java/com/lyft/scoop/RouteChangeTest.java b/scoop/src/test/java/com/lyft/scoop/RouteChangeTest.java
new file mode 100644
index 0000000..c9a6335
--- /dev/null
+++ b/scoop/src/test/java/com/lyft/scoop/RouteChangeTest.java
@@ -0,0 +1,63 @@
+package com.lyft.scoop;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+public class RouteChangeTest {
+ private static final TransitionDirection ENTER_TRANSITION = TransitionDirection.ENTER;
+ private static final Scoop TEST_SCOOP = new Scoop.Builder(null, null).build();
+
+ @Test
+ public void screenEmptyPath() {
+ List fromPath = Arrays.asList();
+ List toPath = Arrays.asList();
+
+ RouteChange routeChange = new RouteChange(fromPath, toPath, ENTER_TRANSITION);
+ ScreenSwap screenSwap = routeChange.toScreenSwap(TEST_SCOOP);
+
+ assertNull(screenSwap.next);
+ assertNull(screenSwap.previous);
+ assertEquals(TEST_SCOOP, screenSwap.scoop);
+ assertEquals(ENTER_TRANSITION, screenSwap.direction);
+ }
+
+ @Test
+ public void screenOneElementPath() {
+
+ List fromPath = Arrays.asList(new ScreenA());
+ List toPath = Arrays.asList(new ScreenA());
+
+ RouteChange routeChange = new RouteChange(fromPath, toPath, ENTER_TRANSITION);
+ ScreenSwap screenSwap = routeChange.toScreenSwap(TEST_SCOOP);
+
+ assertEquals(new ScreenA(), screenSwap.next);
+ assertEquals(new ScreenA(), screenSwap.previous);
+ assertEquals(TEST_SCOOP, screenSwap.scoop);
+ assertEquals(ENTER_TRANSITION, screenSwap.direction);
+ }
+
+ @Test
+ public void screenMultipleElementPath() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB());
+
+ RouteChange routeChange = new RouteChange(fromPath, toPath, ENTER_TRANSITION);
+ ScreenSwap screenSwap = routeChange.toScreenSwap(TEST_SCOOP);
+
+ assertEquals(new ScreenB(), screenSwap.next);
+ assertEquals(new ScreenB(), screenSwap.previous);
+ assertEquals(TEST_SCOOP, screenSwap.scoop);
+ assertEquals(ENTER_TRANSITION, screenSwap.direction);
+ }
+
+ static class ScreenA extends Screen {
+ }
+
+ static class ScreenB extends Screen {
+ }
+}
diff --git a/scoop/src/test/java/com/lyft/scoop/RouterTest.java b/scoop/src/test/java/com/lyft/scoop/RouterTest.java
index 85a6a8d..cd8b886 100644
--- a/scoop/src/test/java/com/lyft/scoop/RouterTest.java
+++ b/scoop/src/test/java/com/lyft/scoop/RouterTest.java
@@ -1,14 +1,13 @@
package com.lyft.scoop;
import java.util.Collections;
-import org.junit.Assert;
+import java.util.List;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
public class RouterTest {
private TestRouter router;
@@ -16,47 +15,51 @@ public class RouterTest {
@Test
public void defaultRouter() {
- TestDefaultRouter defaultRouter = new TestDefaultRouter();
+ TestRouter defaultRouter = new TestRouter();
+
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenB();
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen2();
+ defaultRouter.goTo(screenA);
+ defaultRouter.goTo(screenB);
+ assertTrue(defaultRouter.goBack());
- defaultRouter.goTo(screen1);
- defaultRouter.goTo(screen2);
- Assert.assertTrue(defaultRouter.goBack());
+ assertEquals(screenA, defaultRouter.fromPath.get(0));
+ assertEquals(screenB, defaultRouter.fromPath.get(1));
- Assert.assertEquals(screen1, defaultRouter.lastScreenChange.next);
- Assert.assertEquals(screen2, defaultRouter.lastScreenChange.previous);
- Assert.assertEquals(TransitionDirection.EXIT, defaultRouter.lastScreenChange.direction);
+ assertEquals(screenA, defaultRouter.toPath.get(0));
+ assertEquals(TransitionDirection.EXIT, defaultRouter.direction);
}
@Test
public void goTo() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
+ Screen screenA = new ScreenA();
- router.goTo(screen1);
+ router.goTo(screenA);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
- Assert.assertEquals(null, router.lastScreenChange.previous);
- Assert.assertEquals(TransitionDirection.ENTER, router.lastScreenChange.direction);
+ assertTrue(router.fromPath.isEmpty());
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(TransitionDirection.ENTER, router.direction);
+ assertEquals(1, router.routeChangeCount);
}
@Test
- public void goToSameController() {
+ public void goToSameScreen() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen1();
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenA();
- router.goTo(screen1);
+ router.goTo(screenA);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
+ assertEquals(screenA, router.toPath.get(0));
- router.goTo(screen2);
+ router.goTo(screenB);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(1, router.routeChangeCount);
}
@Test
@@ -64,16 +67,19 @@ public void goBack() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen2();
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenB();
- router.goTo(screen1);
- router.goTo(screen2);
- Assert.assertTrue(router.goBack());
+ router.goTo(screenA);
+ router.goTo(screenB);
+ assertTrue(router.goBack());
- Assert.assertEquals(screen1, router.lastScreenChange.next);
- Assert.assertEquals(screen2, router.lastScreenChange.previous);
- Assert.assertEquals(TransitionDirection.EXIT, router.lastScreenChange.direction);
+ assertEquals(screenA, router.fromPath.get(0));
+ assertEquals(screenB, router.fromPath.get(1));
+
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(TransitionDirection.EXIT, router.direction);
+ assertEquals(3, router.routeChangeCount);
}
@Test
@@ -81,150 +87,161 @@ public void goBackAllowEmptyStack() {
router = new TestRouter(true);
- Screen screen1 = new Screen1();
+ Screen screenA = new ScreenA();
+
+ router.goTo(screenA);
- router.goTo(screen1);
- Assert.assertTrue(router.goBack());
+ assertTrue(router.goBack());
- Assert.assertNull(router.lastScreenChange.next);
- Assert.assertEquals(screen1, router.lastScreenChange.previous);
- Assert.assertEquals(TransitionDirection.EXIT, router.lastScreenChange.direction);
+ assertEquals(screenA, router.fromPath.get(0));
+ assertTrue(router.toPath.isEmpty());
+ assertEquals(TransitionDirection.EXIT, router.direction);
+ assertEquals(2, router.routeChangeCount);
}
@Test
public void goBackNoScreens() {
router = new TestRouter(true);
- Assert.assertFalse(router.goBack());
+ assertFalse(router.goBack());
+ assertEquals(0, router.routeChangeCount);
}
@Test
public void resetToExisting() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen2();
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenB();
- router.goTo(screen1);
- router.goTo(screen2);
- router.resetTo(screen1);
+ router.goTo(screenA);
+ router.goTo(screenB);
+ router.resetTo(screenA);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
- Assert.assertEquals(screen2, router.lastScreenChange.previous);
- Assert.assertEquals(TransitionDirection.EXIT, router.lastScreenChange.direction);
+ assertEquals(screenA, router.fromPath.get(0));
+ assertEquals(screenB, router.fromPath.get(1));
+ assertEquals(screenA, router.toPath.get(0));
+
+ assertEquals(TransitionDirection.EXIT, router.direction);
checkIfRouterBackstackIsEmpty();
+ assertEquals(4, router.routeChangeCount);
}
@Test
public void resetToNew() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen2();
-
- router.goTo(screen2);
- router.resetTo(screen1);
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenB();
- Assert.assertEquals(screen1, router.lastScreenChange.next);
- Assert.assertEquals(screen2, router.lastScreenChange.previous);
- Assert.assertEquals(TransitionDirection.EXIT, router.lastScreenChange.direction);
+ router.goTo(screenB);
+ router.resetTo(screenA);
+ assertEquals(screenB, router.fromPath.get(0));
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(TransitionDirection.EXIT, router.direction);
checkIfRouterBackstackIsEmpty();
+ assertEquals(3, router.routeChangeCount);
}
@Test
public void replaceWith() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen2();
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenB();
- router.goTo(screen1);
- router.replaceWith(screen2);
+ router.goTo(screenA);
+ router.replaceWith(screenB);
- Assert.assertEquals(screen2, router.lastScreenChange.next);
- Assert.assertEquals(screen1, router.lastScreenChange.previous);
- Assert.assertEquals(TransitionDirection.ENTER, router.lastScreenChange.direction);
+ assertEquals(screenA, router.fromPath.get(0));
+ assertEquals(screenB, router.toPath.get(0));
+ assertEquals(TransitionDirection.ENTER, router.direction);
checkIfRouterBackstackIsEmpty();
+ assertEquals(3, router.routeChangeCount);
}
@Test
public void replaceAllWith() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen2();
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenB();
+
+ router.goTo(screenA);
+ router.replaceAllWith(screenA, screenB);
- router.goTo(screen1);
- router.replaceAllWith(screen1, screen2);
- Assert.assertEquals(screen2, router.lastScreenChange.next);
+ assertEquals(screenA, router.fromPath.get(0));
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(screenB, router.toPath.get(1));
+ assertEquals(2, router.routeChangeCount);
}
@Test
public void emptyBackstackGoTo() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
+ Screen screenA = new ScreenA();
- router.goTo(screen1);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
+ router.goTo(screenA);
- router.goBack();
+ assertTrue(router.fromPath.isEmpty());
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(1, router.routeChangeCount);
}
@Test
public void emptyBackstackReplaceWith() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
-
- router.replaceWith(screen1);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
+ Screen screenA = new ScreenA();
- router.goBack();
+ router.replaceWith(screenA);
+ assertTrue(router.fromPath.isEmpty());
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(1, router.routeChangeCount);
}
@Test
public void emptyBackstackResetTo() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
-
- router.resetTo(screen1);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
+ Screen screenA = new ScreenA();
- router.goBack();
+ router.resetTo(screenA);
+ assertTrue(router.fromPath.isEmpty());
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(1, router.routeChangeCount);
}
@Test
- public void replaceToSameController() {
+ public void replaceToSameScreen() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
- Screen screen2 = new Screen1();
-
- router.replaceWith(screen1);
-
- Assert.assertEquals(screen1, router.lastScreenChange.next);
+ Screen screenA = new ScreenA();
+ Screen screenB = new ScreenA();
- router.replaceWith(screen2);
+ router.replaceWith(screenA);
+ router.replaceWith(screenB);
- Assert.assertEquals(screen1, router.lastScreenChange.next);
+ assertTrue(router.fromPath.isEmpty());
+ assertEquals(screenA, router.toPath.get(0));
+ assertEquals(1, router.routeChangeCount);
}
@Test
public void hasActiveScreen() {
router = new TestRouter(false);
- Screen screen1 = new Screen1();
+ Screen screenA = new ScreenA();
- router.goTo(screen1);
- Assert.assertTrue(router.hasActiveScreen());
+ router.goTo(screenA);
+ assertTrue(router.hasActiveScreen());
router.goBack();
- Assert.assertFalse(router.hasActiveScreen());
+ assertFalse(router.hasActiveScreen());
}
@Test
@@ -233,60 +250,41 @@ public void replaceAllWithEmptyListOnDisallowedEmptyStack() {
router = new TestRouter(true);
router.replaceAllWith(Collections.emptyList());
- Assert.assertFalse(router.hasActiveScreen());
+ assertFalse(router.hasActiveScreen());
+ assertEquals(1, router.routeChangeCount);
}
- private void checkIfRouterBackstackIsEmpty() {Assert.assertEquals(false, router.goBack());}
-
- @Test
- public void sameController() {
-
- Screen previous = new Screen1();
- Screen next = new Screen1();
- Assert.assertTrue(Router.sameScreen(previous, next));
- }
-
- @Test
- public void differentController() {
-
- Screen previous = new Screen1();
- Screen next = new Screen2();
- Assert.assertFalse(Router.sameScreen(previous, next));
+ private void checkIfRouterBackstackIsEmpty() {
+ assertEquals(false, router.goBack());
}
- @Layout(0)
- static class Screen1 extends Screen {
+ static class ScreenA extends Screen {
}
- @Layout(0)
- static class Screen2 extends Screen {
+ static class ScreenB extends Screen {
}
static class TestRouter extends Router {
- private RouteChange lastScreenChange;
+ List fromPath;
+ List toPath;
+ TransitionDirection direction;
+ int routeChangeCount;
public TestRouter(boolean allowEmptyStack) {
- super(new ScreenScooper(), allowEmptyStack);
+ super(allowEmptyStack);
}
- @Override
- protected void onScoopChanged(RouteChange routeChange) {
- lastScreenChange = routeChange;
- }
- }
-
- static class TestDefaultRouter extends Router {
-
- private RouteChange lastScreenChange;
-
- public TestDefaultRouter() {
- super(new ScreenScooper());
+ public TestRouter() {
+ super();
}
@Override
- protected void onScoopChanged(RouteChange routeChange) {
- lastScreenChange = routeChange;
+ protected void onRouteChanged(RouteChange routeChange) {
+ routeChangeCount++;
+ fromPath = routeChange.fromPath;
+ toPath = routeChange.toPath;
+ direction = routeChange.direction;
}
}
}
diff --git a/scoop/src/test/java/com/lyft/scoop/ScoopBackstackTest.java b/scoop/src/test/java/com/lyft/scoop/ScoopBackstackTest.java
deleted file mode 100644
index 41d3c0a..0000000
--- a/scoop/src/test/java/com/lyft/scoop/ScoopBackstackTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.lyft.scoop;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-public class ScoopBackstackTest {
-
- private ScoopBackstack backStack;
-
- @Before
- public void setUp() {
- backStack = new ScoopBackstack();
- }
-
- @Test
- public void pushSingleScoop() {
- Scoop scoop = new Scoop.Builder("foo").build();
- backStack.push(scoop);
- Assert.assertFalse(backStack.isEmpty());
- Assert.assertEquals(scoop, backStack.peek());
- }
-
- @Test
- public void popDestroyScoop() {
- Scoop scoop = new Scoop.Builder("foo").build();
- backStack.push(scoop);
- backStack.pop();
- Assert.assertTrue(scoop.isDestroyed());
- }
-}
diff --git a/scoop/src/test/java/com/lyft/scoop/ScoopTest.java b/scoop/src/test/java/com/lyft/scoop/ScoopTest.java
index fd0d503..bd41ce1 100644
--- a/scoop/src/test/java/com/lyft/scoop/ScoopTest.java
+++ b/scoop/src/test/java/com/lyft/scoop/ScoopTest.java
@@ -1,9 +1,21 @@
package com.lyft.scoop;
+import android.content.Context;
+import android.view.View;
import org.junit.Assert;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
public class ScoopTest {
+ private static final Scoop TEST_SCOOP = new Scoop.Builder("root").build();
@Test
public void createRootScoop() {
@@ -13,7 +25,7 @@ public void createRootScoop() {
.build();
Assert.assertEquals("root", scoop.getName());
- Assert.assertNull(scoop.getParent());
+ assertNull(scoop.getParent());
Assert.assertEquals(service, scoop.findService("foo_service"));
}
@@ -77,12 +89,12 @@ public void destroyRootScoop() {
childScoop.destroy();
Assert.assertFalse(rootScoop.isDestroyed());
- Assert.assertNull(rootScoop.findChild("child"));
+ assertNull(rootScoop.findChild("child"));
Assert.assertNotNull(rootScoop.findService("foo_service_1"));
Assert.assertTrue(childScoop.isDestroyed());
Assert.assertNotNull(childScoop.getParent());
- Assert.assertNull(childScoop.findChild("grand_child"));
+ assertNull(childScoop.findChild("grand_child"));
Assert.assertNotNull(childScoop.findService("foo_service_1"));
Assert.assertNotNull(childScoop.findService("foo_service_2"));
@@ -93,7 +105,30 @@ public void destroyRootScoop() {
Assert.assertNotNull(grandChildScoop.findService("foo_service_3"));
}
+ @Test
+ public void fromNullView() {
+ assertNull(Scoop.fromView(null));
+ }
+
+ @Test
+ public void fromViewNoScoop() {
+ try {
+ Scoop.fromView(new TestView(RuntimeEnvironment.application));
+ fail("Should have thrown a RuntimeException if there is no scoop in the view's context.");
+ } catch (RuntimeException e) {
+ //Expected result
+ }
+
+ }
+
static class FooService {
}
+
+ static class TestView extends View {
+
+ public TestView(Context context) {
+ super(context);
+ }
+ }
}
diff --git a/scoop/src/test/java/com/lyft/scoop/ScreenBackstackTest.java b/scoop/src/test/java/com/lyft/scoop/ScreenBackstackTest.java
new file mode 100644
index 0000000..4b5172e
--- /dev/null
+++ b/scoop/src/test/java/com/lyft/scoop/ScreenBackstackTest.java
@@ -0,0 +1,46 @@
+package com.lyft.scoop;
+
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ScreenBackstackTest {
+
+ private ScreenBackstack backStack;
+
+ @Before
+ public void setUp() {
+ backStack = new ScreenBackstack();
+ }
+
+ @Test
+ public void asList() {
+ Screen1 screen1 = new Screen1();
+ Screen2 screen2 = new Screen2();
+ backStack.push(screen1);
+ backStack.push(screen2);
+
+ List list = backStack.asList();
+
+ assertEquals(screen1, list.get(0));
+ assertEquals(screen2, list.get(1));
+ }
+
+ @Test
+ public void asListWithEmptyBackstack() {
+ List list = backStack.asList();
+
+ assertTrue(list.isEmpty());
+ }
+
+ static class Screen1 extends Screen {
+
+ }
+
+ static class Screen2 extends Screen {
+
+ }
+}
diff --git a/scoop/src/test/java/com/lyft/scoop/ScreenScoopFactoryTest.java b/scoop/src/test/java/com/lyft/scoop/ScreenScoopFactoryTest.java
new file mode 100644
index 0000000..41468d4
--- /dev/null
+++ b/scoop/src/test/java/com/lyft/scoop/ScreenScoopFactoryTest.java
@@ -0,0 +1,29 @@
+package com.lyft.scoop;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ScreenScoopFactoryTest {
+
+ @Test
+ public void screenAddedToScoop() {
+ ScreenScoopFactory screenScoopFactory = new ScreenScoopFactory();
+
+ Scoop parentScoop = new Scoop.Builder("root").build();
+
+ Screen screen = new TestScreen();
+
+ Scoop childScoop = screenScoopFactory.createScreenScoop(screen, parentScoop);
+
+ Assert.assertEquals(screen, Screen.fromScoop(childScoop));
+ }
+
+ @Layout(0)
+ static class TestScreen extends Screen {
+ }
+}
diff --git a/scoop/src/test/java/com/lyft/scoop/ScreenScooperTest.java b/scoop/src/test/java/com/lyft/scoop/ScreenScooperTest.java
index 84487d4..2af91d6 100644
--- a/scoop/src/test/java/com/lyft/scoop/ScreenScooperTest.java
+++ b/scoop/src/test/java/com/lyft/scoop/ScreenScooperTest.java
@@ -1,29 +1,417 @@
package com.lyft.scoop;
-import org.junit.Assert;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
public class ScreenScooperTest {
+ private ScreenScooper screenScooper;
+ private Scoop rootScoop;
+ private ScreenScoopFactory screenScoopFactory;
+
+ @Before
+ public void setUp() {
+ screenScoopFactory = new ScreenScoopFactory();
+ screenScooper = new ScreenScooper(screenScoopFactory);
+ rootScoop = new Scoop.Builder("root").build();
+ }
+
+ // [ ] - > [ ]
+ @Test
+ public void createScoopFromEmptyPathToEmptyPath() {
+
+ Scoop scoop = screenScooper.create(rootScoop, null, Collections.emptyList(), Collections.emptyList());
+
+ assertFalse(rootScoop.isDestroyed());
+ assertNull(scoop);
+ }
+
+ // [ ] - > [ A ]
+ @Test
+ public void createScoopFromEmptyPathToAPath() {
+
+ List toPath = Arrays.asList(new ScreenA());
+
+ Scoop aScoop = screenScooper.create(rootScoop, null, Collections.emptyList(), toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertEquals(rootScoop, aScoop.getParent());
+ }
+
+ // [ ] - > [ A, B ]
+ @Test
+ public void createScoopFromEmptyPathToABPath() {
+
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB());
+
+ Scoop bScoop = screenScooper.create(rootScoop, null, Collections.emptyList(), toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(bScoop.getParent().isDestroyed());
+ assertFalse(bScoop.isDestroyed());
+ assertEquals(rootScoop, bScoop.getParent().getParent());
+ }
+
+ // [ A ] - > [ A, B]
+ @Test
+ public void createScoopFromAPathToABPath() {
+
+ List fromPath = Arrays.asList(new ScreenA());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+
+ Scoop bScoop = screenScooper.create(rootScoop, aScoop, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertFalse(bScoop.isDestroyed());
+ assertEquals(aScoop, bScoop.getParent());
+ }
+
+ // [ A ] - > [ A, B]
+ @Test
+ public void createScoopFromAPathToABPathWithNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB());
+
+ Scoop bScoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(bScoop.isDestroyed());
+ assertEquals(rootScoop, bScoop.getParent().getParent());
+ }
+
+ // [ A, B ] - > [ A ]
+ @Test
+ public void createScoopFromABPathToAPath() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenA());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+ Scoop bScoop = screenScoopFactory.createScreenScoop(new ScreenB(), aScoop);
+
+ Scoop scoop = screenScooper.create(rootScoop, bScoop, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertTrue(bScoop.isDestroyed());
+ assertEquals(aScoop, scoop);
+ }
+
+ // [ A, B ] - > [ A ]
+ @Test
+ public void createScoopFromABPathToAPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenA());
+
+ Scoop scoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertEquals(rootScoop, scoop.getParent());
+ }
+
+ // [ A, B ] - > [ ]
+ @Test
+ public void createScoopFromABPathToEmptyPath() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList();
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+ Scoop bScoop = screenScoopFactory.createScreenScoop(new ScreenB(), aScoop);
+
+ Scoop scoop = screenScooper.create(rootScoop, bScoop, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertTrue(aScoop.isDestroyed());
+ assertTrue(bScoop.isDestroyed());
+
+ assertNull(scoop);
+ }
+
+ // [ A, B ] - > [ ]
+ @Test
+ public void createScoopFromABPathToEmptyPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList();
+
+ Scoop scoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+
+ assertNull(scoop);
+ }
+
+ // [ A, B, C ] - > [ A ]
+ @Test
+ public void createScoopFromABCPathToAPath() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
+ List toPath = Arrays.asList(new ScreenA());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+ Scoop bScoop = screenScoopFactory.createScreenScoop(new ScreenB(), aScoop);
+ Scoop cScoop = screenScoopFactory.createScreenScoop(new ScreenC(), bScoop);
+
+ Scoop scoop = screenScooper.create(rootScoop, cScoop, fromPath, toPath);
+
+ assertTrue(bScoop.isDestroyed());
+ assertTrue(cScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertFalse(rootScoop.isDestroyed());
+ assertEquals(aScoop, scoop);
+ }
+
+ // [ A, B, C ] - > [ A ]
+ @Test
+ public void createScoopFromABCPathToAPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
+ List toPath = Arrays.asList(new ScreenA());
+
+ Scoop scoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(scoop.isDestroyed());
+ assertFalse(rootScoop.isDestroyed());
+ assertEquals(rootScoop, scoop.getParent());
+ }
+
+ // [ A ] - > [ A, B, C ]
+ @Test
+ public void createScoopFromAPathToABCPath() {
+
+ List fromPath = Arrays.asList(new ScreenA());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+
+ Scoop cScoop = screenScooper.create(rootScoop, aScoop, fromPath, toPath);
+
+ assertFalse(cScoop.getParent().isDestroyed());
+ assertFalse(cScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertFalse(rootScoop.isDestroyed());
+ assertEquals(aScoop, cScoop.getParent().getParent());
+ }
+
+ // [ A ] - > [ A, B, C ]
+ @Test
+ public void createScoopFromAPathToABCPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
+
+ Scoop cScoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ //A
+ assertFalse(cScoop.getParent().getParent().isDestroyed());
+ //B
+ assertFalse(cScoop.getParent().isDestroyed());
+ assertFalse(cScoop.isDestroyed());
+ assertFalse(rootScoop.isDestroyed());
+ assertEquals(rootScoop, cScoop.getParent().getParent().getParent());
+ }
+
+ // [ A ] - > [ B ]
+ @Test
+ public void createScoopFromAPathToBPath() {
+
+ List fromPath = Arrays.asList(new ScreenA());
+ List toPath = Arrays.asList(new ScreenB());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+
+ Scoop bScoop = screenScooper.create(rootScoop, aScoop, fromPath, toPath);
+
+ assertTrue(aScoop.isDestroyed());
+ assertFalse(bScoop.isDestroyed());
+ assertFalse(rootScoop.isDestroyed());
+ assertEquals(rootScoop, bScoop.getParent());
+ }
+
+ // [ A ] - > [ B ]
+ @Test
+ public void createScoopFromAPathToBPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA());
+ List toPath = Arrays.asList(new ScreenB());
+
+ Scoop bScoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(bScoop.isDestroyed());
+ assertFalse(rootScoop.isDestroyed());
+ assertEquals(rootScoop, bScoop.getParent());
+ }
+
+ // [ A, B ] - > [ A, C ]
+ @Test
+ public void createScoopFromABPathToACPath() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenC());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+ Scoop bScoop = screenScoopFactory.createScreenScoop(new ScreenB(), aScoop);
+
+ Scoop cScoop = screenScooper.create(rootScoop, bScoop, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertTrue(bScoop.isDestroyed());
+ assertFalse(cScoop.isDestroyed());
+ assertEquals(aScoop, cScoop.getParent());
+ }
+
+ // [ A, B ] - > [ A, C ]
+ @Test
+ public void createScoopFromABPathToACPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenC());
+
+ Scoop cScoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ //A
+ assertFalse(cScoop.getParent().isDestroyed());
+ assertFalse(cScoop.isDestroyed());
+ assertEquals(rootScoop, cScoop.getParent().getParent());
+ }
+
+ // [ A, B ] - > [ C, D ]
+ @Test
+ public void createScoopFromABPathToCDPath() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenC(), new ScreenD());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+ Scoop bScoop = screenScoopFactory.createScreenScoop(new ScreenB(), aScoop);
+
+ Scoop dScoop = screenScooper.create(rootScoop, bScoop, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertTrue(aScoop.isDestroyed());
+ assertTrue(bScoop.isDestroyed());
+ assertFalse(dScoop.getParent().isDestroyed());
+ assertFalse(dScoop.isDestroyed());
+ assertEquals(rootScoop, dScoop.getParent().getParent());
+ }
+
+ // [ A, B ] - > [ C, D ]
+ @Test
+ public void createScoopFromABPathToCDPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenC(), new ScreenD());
+
+ Scoop dScoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(dScoop.getParent().isDestroyed());
+ assertFalse(dScoop.isDestroyed());
+ assertEquals(rootScoop, dScoop.getParent().getParent());
+ }
+
+ // [ A, B ] - > [ A, B, C ]
@Test
- public void screenAddedToScoop() {
- ScreenScooper screenScooper = new ScreenScooper();
+ public void createScoopFromABPathToABCPath() {
- Scoop parentScoop = new Scoop.Builder("root").build();
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
- Screen screen = new TestScreen();
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+ Scoop bScoop = screenScoopFactory.createScreenScoop(new ScreenB(), aScoop);
- Scoop childScoop = screenScooper.createScreenScoop(screen, parentScoop);
+ Scoop cScoop = screenScooper.create(rootScoop, bScoop, fromPath, toPath);
- Assert.assertEquals(screen, Screen.fromScoop(childScoop));
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertFalse(bScoop.isDestroyed());
+ assertFalse(cScoop.isDestroyed());
+ assertEquals(rootScoop, cScoop.getParent().getParent().getParent());
}
- @Layout(0)
- static class TestScreen extends Screen {
+ // [ A, B ] - > [ A, B, C ]
+ @Test
+ public void createScoopFromABPathToABCPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
+
+ Scoop cScoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(cScoop.getParent().getParent().isDestroyed());
+ assertFalse(cScoop.getParent().isDestroyed());
+ assertFalse(cScoop.isDestroyed());
+ assertEquals(rootScoop, cScoop.getParent().getParent().getParent());
+ }
+
+ // [ A, B, C ] - > [ A, B, D ]
+ @Test
+ public void createScoopFromABCPathToABDPath() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenD());
+
+ Scoop aScoop = screenScoopFactory.createScreenScoop(new ScreenA(), rootScoop);
+ Scoop bScoop = screenScoopFactory.createScreenScoop(new ScreenB(), aScoop);
+ Scoop cScoop = screenScoopFactory.createScreenScoop(new ScreenC(), bScoop);
+
+ Scoop dScoop = screenScooper.create(rootScoop, cScoop, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(aScoop.isDestroyed());
+ assertFalse(bScoop.isDestroyed());
+ assertFalse(dScoop.isDestroyed());
+ assertTrue(cScoop.isDestroyed());
+ assertEquals(rootScoop, dScoop.getParent().getParent().getParent());
+ }
+
+ // [ A, B, C ] - > [ A, B, D ]
+ @Test
+ public void createScoopFromABCPathToABDPathNullCurrentScoop() {
+
+ List fromPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenC());
+ List toPath = Arrays.asList(new ScreenA(), new ScreenB(), new ScreenD());
+
+ Scoop dScoop = screenScooper.create(rootScoop, null, fromPath, toPath);
+
+ assertFalse(rootScoop.isDestroyed());
+ assertFalse(dScoop.getParent().getParent().isDestroyed());
+ assertFalse(dScoop.getParent().isDestroyed());
+ assertFalse(dScoop.isDestroyed());
+ assertEquals(rootScoop, dScoop.getParent().getParent().getParent());
+ }
+
+ static class ScreenA extends Screen {
+
+ }
+
+ static class ScreenB extends Screen {
+
+ }
+
+ static class ScreenC extends Screen {
+
+ }
+
+ static class ScreenD extends Screen {
+
}
}
diff --git a/scoop/src/test/java/com/lyft/scoop/ScreenTest.java b/scoop/src/test/java/com/lyft/scoop/ScreenTest.java
new file mode 100644
index 0000000..312da44
--- /dev/null
+++ b/scoop/src/test/java/com/lyft/scoop/ScreenTest.java
@@ -0,0 +1,31 @@
+package com.lyft.scoop;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ScreenTest {
+
+ @Test
+ public void sameScreen() {
+
+ Screen previous = new ScreenA();
+ Screen next = new ScreenA();
+ assertTrue(Screen.equals(previous, next));
+ }
+
+ @Test
+ public void differentScreen() {
+
+ Screen previous = new ScreenA();
+ Screen next = new ScreenB();
+ assertFalse(Screen.equals(previous, next));
+ }
+
+ static class ScreenA extends Screen {
+ }
+
+ static class ScreenB extends Screen {
+ }
+}
diff --git a/scoop/src/test/java/com/lyft/scoop/UiContainerTest.java b/scoop/src/test/java/com/lyft/scoop/UiContainerTest.java
index 27af815..f6307f7 100644
--- a/scoop/src/test/java/com/lyft/scoop/UiContainerTest.java
+++ b/scoop/src/test/java/com/lyft/scoop/UiContainerTest.java
@@ -21,36 +21,36 @@ public class UiContainerTest {
@Test
public void getTransitions() {
- final RouteChange routeChange = createRouteChange(new ViewControllerWithTransitions(), new ViewControllerWithTransitions());
- Assert.assertNotNull(UiContainer.getEnterTransition(routeChange));
- Assert.assertNotNull(UiContainer.getExitTransition(routeChange));
+ final ScreenSwap screenSwap = createRouteChange(new ViewControllerWithTransitions(), new ViewControllerWithTransitions());
+ Assert.assertNotNull(UiContainer.getEnterTransition(screenSwap));
+ Assert.assertNotNull(UiContainer.getExitTransition(screenSwap));
}
@Test
public void enterTransitionWithoutDefaultConstructor() {
exception.expect(RuntimeException.class);
- final RouteChange routeChange = createRouteChange(new ViewControllerWithTransitionWithoutDefaultConstructor(), new ViewControllerWithTransitionWithoutDefaultConstructor());
- UiContainer.getEnterTransition(routeChange);
+ final ScreenSwap screenSwap = createRouteChange(new ViewControllerWithTransitionWithoutDefaultConstructor(), new ViewControllerWithTransitionWithoutDefaultConstructor());
+ UiContainer.getEnterTransition(screenSwap);
}
@Test
public void exitTransitionWithoutDefaultConstructor() {
exception.expect(RuntimeException.class);
- final RouteChange routeChange = createRouteChange(new ViewControllerWithTransitionWithoutDefaultConstructor(), new ViewControllerWithTransitionWithoutDefaultConstructor());
- UiContainer.getExitTransition(routeChange);
+ final ScreenSwap screenSwap = createRouteChange(new ViewControllerWithTransitionWithoutDefaultConstructor(), new ViewControllerWithTransitionWithoutDefaultConstructor());
+ UiContainer.getExitTransition(screenSwap);
}
@Test
public void useInstantTransitionIfControllerHasNoTransitions() {
- final RouteChange routeChange = createRouteChange(new ViewControllerWithoutTransitions(), new ViewControllerWithoutTransitions());
+ final ScreenSwap screenSwap = createRouteChange(new ViewControllerWithoutTransitions(), new ViewControllerWithoutTransitions());
Assert.assertEquals(InstantTransition.class,
- UiContainer.getEnterTransition(routeChange).getClass());
+ UiContainer.getEnterTransition(screenSwap).getClass());
Assert.assertEquals(InstantTransition.class,
- UiContainer.getExitTransition(routeChange).getClass());
+ UiContainer.getExitTransition(screenSwap).getClass());
}
- private RouteChange createRouteChange(final Screen previous, final Screen next) {
- return new RouteChange(null, previous, next, null);
+ private ScreenSwap createRouteChange(final Screen previous, final Screen next) {
+ return new ScreenSwap(null, previous, next, null);
}
@EnterTransition(ForwardSlideTransition.class)