Daniel Zlotin преди 7 години
родител
ревизия
5e74cc72c6

+ 2
- 0
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/ApplicationLifecycleTest.java Целия файл

@@ -3,10 +3,12 @@ package com.reactnativenavigation.e2e.androide2e;
3 3
 import android.support.test.uiautomator.By;
4 4
 
5 5
 import org.junit.FixMethodOrder;
6
+import org.junit.Ignore;
6 7
 import org.junit.Test;
7 8
 import org.junit.runners.MethodSorters;
8 9
 
9 10
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
11
+@Ignore
10 12
 public class ApplicationLifecycleTest extends BaseTest {
11 13
 
12 14
 	@Test

+ 8
- 7
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/TopLevelApiTest.java Целия файл

@@ -31,10 +31,9 @@ public class TopLevelApiTest extends BaseTest {
31 31
 		launchTheApp();
32 32
 		assertMainShown();
33 33
 		elementByText("PUSH LIFECYCLE SCREEN").click();
34
-		elementByText("onStart!");
34
+		assertExists(By.text("onStart"));
35 35
 		elementByText("PUSH TO TEST ONSTOP").click();
36
-		elementByText("Alert");
37
-		elementByText("onStop").click();
36
+		assertExists(By.text("onStop"));
38 37
 	}
39 38
 
40 39
 	@Test
@@ -42,9 +41,11 @@ public class TopLevelApiTest extends BaseTest {
42 41
 	public void unmountIsCalledOnPop() throws Exception {
43 42
 		launchTheApp();
44 43
 		assertMainShown();
45
-		elementByText("Push lifecycle screen").click();
46
-		elementByText("onStart!");
47
-		elementByText("BACK").click();
48
-		elementByText("componentWillUnmount");
44
+		elementByText("PUSH LIFECYCLE SCREEN").click();
45
+		elementByText("onStart");
46
+		device().pressBack();
47
+		assertMainShown();
48
+		assertExists(By.text("onStop"));
49
+		assertExists(By.text("componentWillUnmount"));
49 50
 	}
50 51
 }

+ 2
- 2
e2e/app.test.js Целия файл

@@ -21,7 +21,7 @@ describe('top level api', () => {
21 21
 
22 22
   it('screen lifecycle', async () => {
23 23
     await elementByLabel('Push lifecycle screen').tap();
24
-    await expect(elementByLabel('onStart!')).toBeVisible();
24
+    await expect(elementByLabel('onStart')).toBeVisible();
25 25
     await elementByLabel('Push to test onStop').tap();
26 26
     await expect(elementByLabel('Alert')).toBeVisible();
27 27
     await expect(elementByLabel('onStop')).toBeVisible();
@@ -29,7 +29,7 @@ describe('top level api', () => {
29 29
 
30 30
   it('unmount is called on pop', async () => {
31 31
     await elementByLabel('Push lifecycle screen').tap();
32
-    await expect(elementByLabel('onStart!')).toBeVisible();
32
+    await expect(elementByLabel('onStart')).toBeVisible();
33 33
     await element(by.traits(['button']).and(by.label('Back'))).tap();
34 34
     await expect(elementByLabel('onStop')).toBeVisible();
35 35
     await expect(elementByLabel('componentWillUnmount')).toBeVisible();

+ 8
- 0
lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java Целия файл

@@ -6,6 +6,7 @@ import android.support.v7.app.AppCompatActivity;
6 6
 import android.view.View;
7 7
 
8 8
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
9
+import com.reactnativenavigation.layout.StackLayout;
9 10
 
10 11
 public class NavigationActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
11 12
 	private View contentView;
@@ -50,6 +51,13 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard
50 51
 		onBackPressed();
51 52
 	}
52 53
 
54
+	@Override
55
+	public void onBackPressed() {
56
+		if (!(contentView instanceof StackLayout) || !((StackLayout) contentView).onBackPressed()) {
57
+			super.onBackPressed();
58
+		}
59
+	}
60
+
53 61
 	private NavigationApplication app() {
54 62
 		return ((NavigationApplication) getApplication());
55 63
 	}

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/controllers/CommandsHandler.java Целия файл

@@ -7,6 +7,7 @@ import com.reactnativenavigation.NavigationApplication;
7 7
 import com.reactnativenavigation.layout.LayoutFactory;
8 8
 import com.reactnativenavigation.layout.LayoutNode;
9 9
 import com.reactnativenavigation.layout.StackLayout;
10
+import com.reactnativenavigation.layout.containers.Container;
10 11
 
11 12
 import org.json.JSONObject;
12 13
 
@@ -29,7 +30,7 @@ public class CommandsHandler {
29 30
 		final LayoutNode layoutNode = LayoutNode.parse(layoutTree);
30 31
 		LayoutFactory factory = new LayoutFactory(activity, application.getReactNativeHost());
31 32
 		final View rootView = factory.create(layoutNode);
32
-		((StackLayout) activity.getContentView()).push(rootView);
33
+		((StackLayout) activity.getContentView()).push((Container) rootView);
33 34
 	}
34 35
 
35 36
 	public void pop(final NavigationActivity activity, String onContainerId) {

+ 4
- 2
lib/android/app/src/main/java/com/reactnativenavigation/layout/StackLayout.java Целия файл

@@ -1,9 +1,11 @@
1 1
 package com.reactnativenavigation.layout;
2 2
 
3
-import android.view.View;
3
+import com.reactnativenavigation.layout.containers.Container;
4 4
 
5 5
 public interface StackLayout {
6
-	void push(View view);
6
+	void push(Container view);
7 7
 
8 8
 	void pop();
9
+
10
+	boolean onBackPressed();
9 11
 }

+ 12
- 7
lib/android/app/src/main/java/com/reactnativenavigation/layout/containers/Container.java Целия файл

@@ -15,6 +15,7 @@ public class Container extends FrameLayout {
15 15
 	private final ReactNativeHost reactNativeHost;
16 16
 	private final String id;
17 17
 	private final String name;
18
+	private ReactRootView rootView;
18 19
 
19 20
 	public Container(Activity activity, ReactNativeHost reactNativeHost, String id, String name) {
20 21
 		super(activity);
@@ -24,8 +25,18 @@ public class Container extends FrameLayout {
24 25
 		addView(createReactRootView());
25 26
 	}
26 27
 
28
+	@Override
29
+	protected void onDetachedFromWindow() {
30
+		super.onDetachedFromWindow();
31
+		onStop();
32
+	}
33
+
34
+	public void destroy() {
35
+		rootView.unmountReactApplication();
36
+	}
37
+
27 38
 	private View createReactRootView() {
28
-		final ReactRootView rootView = new ReactRootView(getContext());
39
+		rootView = new ReactRootView(getContext());
29 40
 		Bundle opts = new Bundle();
30 41
 		opts.putString("id", id);
31 42
 		rootView.startReactApplication(reactNativeHost.getReactInstanceManager(), name, opts);
@@ -39,12 +50,6 @@ public class Container extends FrameLayout {
39 50
 		return rootView;
40 51
 	}
41 52
 
42
-	@Override
43
-	protected void onDetachedFromWindow() {
44
-		super.onDetachedFromWindow();
45
-		onStop();
46
-	}
47
-
48 53
 	private void onStart() {
49 54
 		new NavigationEventEmitter(reactContext()).containerStart(id);
50 55
 	}

+ 29
- 7
lib/android/app/src/main/java/com/reactnativenavigation/layout/containers/ContainerStack.java Целия файл

@@ -1,7 +1,6 @@
1 1
 package com.reactnativenavigation.layout.containers;
2 2
 
3 3
 import android.content.Context;
4
-import android.view.View;
5 4
 import android.widget.FrameLayout;
6 5
 
7 6
 import com.reactnativenavigation.layout.StackLayout;
@@ -10,22 +9,45 @@ import java.util.Stack;
10 9
 
11 10
 public class ContainerStack extends FrameLayout implements StackLayout {
12 11
 
13
-	private Stack<View> stack = new Stack<>();
12
+	private Stack<Container> stack = new Stack<>();
14 13
 
15 14
 	public ContainerStack(Context context) {
16 15
 		super(context);
17 16
 	}
18 17
 
18
+
19 19
 	@Override
20
-	public void push(View view) {
20
+	public void push(Container view) {
21
+		stack.push(view);
21 22
 		addView(view);
22
-		stack.push(getChildAt(0));
23
-		removeView(getChildAt(0));
23
+		if (stack.size() > 1) {
24
+			Container previousTop = stack.elementAt(stack.size() - 2);
25
+			removeView(previousTop);
26
+		}
24 27
 	}
25 28
 
26 29
 	@Override
27 30
 	public void pop() {
28
-		addView(stack.pop());
29
-		removeView(getChildAt(0));
31
+		Container top = stack.pop();
32
+		removeView(top);
33
+		top.destroy();
34
+		if (!stack.isEmpty()) {
35
+			Container previousTop = stack.peek();
36
+			addView(previousTop);
37
+		}
38
+	}
39
+
40
+	@Override
41
+	public boolean onBackPressed() {
42
+		if (stack.isEmpty()) {
43
+			return false;
44
+		} else {
45
+			pop();
46
+			return true;
47
+		}
48
+	}
49
+
50
+	public boolean isEmpty() {
51
+		return stack.isEmpty();
30 52
 	}
31 53
 }

+ 41
- 0
lib/android/app/src/test/java/com/reactnativenavigation/layout/ContainerStackTest.java Целия файл

@@ -0,0 +1,41 @@
1
+package com.reactnativenavigation.layout;
2
+
3
+import android.support.annotation.NonNull;
4
+
5
+import com.facebook.react.ReactInstanceManager;
6
+import com.facebook.react.ReactNativeHost;
7
+import com.reactnativenavigation.BaseTest;
8
+import com.reactnativenavigation.NavigationActivity;
9
+import com.reactnativenavigation.layout.containers.Container;
10
+import com.reactnativenavigation.layout.containers.ContainerStack;
11
+
12
+import org.junit.Test;
13
+import org.robolectric.Robolectric;
14
+
15
+import static org.assertj.core.api.Java6Assertions.assertThat;
16
+import static org.mockito.Mockito.mock;
17
+import static org.mockito.Mockito.when;
18
+
19
+public class ContainerStackTest extends BaseTest {
20
+	@Test
21
+	public void push() throws Exception {
22
+		NavigationActivity context = Robolectric.setupActivity(NavigationActivity.class);
23
+		ContainerStack uut = new ContainerStack(context);
24
+		assertThat(uut.isEmpty()).isTrue();
25
+		assertThat(uut.getChildCount()).isZero();
26
+
27
+		Container container = createContainer(context);
28
+		uut.push(container);
29
+		assertThat(uut.isEmpty()).isFalse();
30
+
31
+		assertThat(uut.getChildCount()).isEqualTo(1);
32
+
33
+	}
34
+
35
+	@NonNull
36
+	private Container createContainer(final NavigationActivity context) {
37
+		ReactNativeHost reactNativeHost = mock(ReactNativeHost.class);
38
+		when(reactNativeHost.getReactInstanceManager()).thenReturn(mock(ReactInstanceManager.class));
39
+		return new Container(context, reactNativeHost, "id", "name");
40
+	}
41
+}

+ 1
- 1
playground/src/containers/LifecycleScreen.js Целия файл

@@ -13,7 +13,7 @@ class LifecycleScreen extends Component {
13 13
   }
14 14
 
15 15
   onStart() {
16
-    this.setState({ text: 'onStart!' });
16
+    this.setState({ text: 'onStart' });
17 17
   }
18 18
 
19 19
   onStop() {