Browse Source

navigationOptions

Daniel Zlotin 7 years ago
parent
commit
30d0111f16

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/layout/LayoutFactory.java View File

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 
4
 
5
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
6
-import com.reactnativenavigation.viewcontrollers.SideMenuController;
7
 import com.reactnativenavigation.viewcontrollers.BottomTabsController;
6
 import com.reactnativenavigation.viewcontrollers.BottomTabsController;
7
+import com.reactnativenavigation.viewcontrollers.SideMenuController;
8
 import com.reactnativenavigation.viewcontrollers.StackController;
8
 import com.reactnativenavigation.viewcontrollers.StackController;
9
 import com.reactnativenavigation.viewcontrollers.ViewController;
9
 import com.reactnativenavigation.viewcontrollers.ViewController;
10
 
10
 
76
 	}
76
 	}
77
 
77
 
78
 	private ViewController createContainer(LayoutNode node) {
78
 	private ViewController createContainer(LayoutNode node) {
79
-		return new ReactRootViewController(activity, node.id, node.data.optString("name"), reactInstanceManager);
79
+		return new ReactRootViewController(activity, node.id, node.data.optString("name"), node.data.optJSONObject("navigationOptions").optString("title"), reactInstanceManager);
80
 	}
80
 	}
81
 
81
 
82
 	private ViewController createContainerStack(LayoutNode node) {
82
 	private ViewController createContainerStack(LayoutNode node) {

+ 4
- 1
lib/android/app/src/main/java/com/reactnativenavigation/layout/ReactRootViewController.java View File

13
 public class ReactRootViewController extends ViewController {
13
 public class ReactRootViewController extends ViewController {
14
 
14
 
15
 	private final String name;
15
 	private final String name;
16
+	private final String title;
16
 	private final ReactInstanceManager reactInstanceManager;
17
 	private final ReactInstanceManager reactInstanceManager;
17
 	private boolean attachedToReactInstance = false;
18
 	private boolean attachedToReactInstance = false;
18
 	private ReactRootView reactRootView;
19
 	private ReactRootView reactRootView;
19
 
20
 
20
-	public ReactRootViewController(final Activity activity, final String id, final String name, final ReactInstanceManager reactInstanceManager) {
21
+	public ReactRootViewController(final Activity activity, final String id, final String name, String title, final ReactInstanceManager reactInstanceManager) {
21
 		super(activity, id);
22
 		super(activity, id);
22
 		this.name = name;
23
 		this.name = name;
24
+		this.title = title;
23
 		this.reactInstanceManager = reactInstanceManager;
25
 		this.reactInstanceManager = reactInstanceManager;
24
 	}
26
 	}
25
 
27
 
33
 	@Override
35
 	@Override
34
 	public void onViewAppeared() {
36
 	public void onViewAppeared() {
35
 		super.onViewAppeared();
37
 		super.onViewAppeared();
38
+		if (getParentStackController() != null) getParentStackController().setTitle(title);
36
 		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).containerStart(getId());
39
 		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).containerStart(getId());
37
 	}
40
 	}
38
 
41
 

+ 29
- 12
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java View File

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
+import android.view.View;
5
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
6
-import android.widget.FrameLayout;
7
+import android.widget.LinearLayout;
7
 
8
 
8
 import com.reactnativenavigation.anim.StackAnimator;
9
 import com.reactnativenavigation.anim.StackAnimator;
10
+import com.reactnativenavigation.utils.CompatUtils;
11
+import com.reactnativenavigation.views.TopBar;
9
 
12
 
10
 import java.util.Collection;
13
 import java.util.Collection;
11
 
14
 
12
 public class StackController extends ParentController {
15
 public class StackController extends ParentController {
13
 	private final IdStack<ViewController> stack = new IdStack<>();
16
 	private final IdStack<ViewController> stack = new IdStack<>();
14
-	private StackAnimator animator;
17
+	private final StackAnimator animator;
18
+	private TopBar topBar;
15
 
19
 
16
 	public StackController(final Activity activity, String id) {
20
 	public StackController(final Activity activity, String id) {
17
 		this(activity, id, new StackAnimator(activity));
21
 		this(activity, id, new StackAnimator(activity));
29
 		stack.push(child.getId(), child);
33
 		stack.push(child.getId(), child);
30
 
34
 
31
 		getView().addView(child.getView());
35
 		getView().addView(child.getView());
32
-
36
+//TODO animate only when needed
33
 		if (previousTop != null) {
37
 		if (previousTop != null) {
34
 			animator.animatePush(child.getView(), previousTop.getView(), new Runnable() {
38
 			animator.animatePush(child.getView(), previousTop.getView(), new Runnable() {
35
 				@Override
39
 				@Override
50
 		final ViewController poppedTop = stack.pop();
54
 		final ViewController poppedTop = stack.pop();
51
 		ViewController newTop = peek();
55
 		ViewController newTop = peek();
52
 
56
 
53
-		getView().addView(newTop.getView());
57
+		final View enteringView = newTop.getView();
58
+		final View exitingView = poppedTop.getView();
59
+
60
+		getView().addView(enteringView);
54
 
61
 
55
-		animator.animatePop(newTop.getView(), poppedTop.getView(), new Runnable() {
56
-			@Override
57
-			public void run() {
58
-				getView().removeView(poppedTop.getView());
59
-				poppedTop.destroy();
60
-			}
61
-		});
62
+		//TODO animate only when needed
63
+//		animator.animatePop(enteringView, exitingView, new Runnable() {
64
+//			@Override
65
+//			public void run() {
66
+		getView().removeView(exitingView);
67
+		poppedTop.destroy();
68
+//			}
69
+//		});
62
 	}
70
 	}
63
 
71
 
64
 	public void popSpecific(final ViewController childController) {
72
 	public void popSpecific(final ViewController childController) {
110
 	@NonNull
118
 	@NonNull
111
 	@Override
119
 	@Override
112
 	protected ViewGroup createView() {
120
 	protected ViewGroup createView() {
113
-		return new FrameLayout(getActivity());
121
+		LinearLayout root = new LinearLayout(getActivity());
122
+		root.setOrientation(LinearLayout.VERTICAL);
123
+		topBar = new TopBar(getActivity());
124
+		topBar.setId(CompatUtils.generateViewId());
125
+		root.addView(topBar);
126
+		return root;
114
 	}
127
 	}
115
 
128
 
116
 	@NonNull
129
 	@NonNull
118
 	public Collection<ViewController> getChildControllers() {
131
 	public Collection<ViewController> getChildControllers() {
119
 		return stack.values();
132
 		return stack.values();
120
 	}
133
 	}
134
+
135
+	public void setTitle(final String title) {
136
+		topBar.setTitle(title);
137
+	}
121
 }
138
 }

+ 2
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java View File

7
 import android.view.ViewGroup;
7
 import android.view.ViewGroup;
8
 import android.view.ViewTreeObserver;
8
 import android.view.ViewTreeObserver;
9
 
9
 
10
+import com.reactnativenavigation.utils.CompatUtils;
10
 import com.reactnativenavigation.utils.StringUtils;
11
 import com.reactnativenavigation.utils.StringUtils;
11
 
12
 
12
 public abstract class ViewController implements ViewTreeObserver.OnGlobalLayoutListener {
13
 public abstract class ViewController implements ViewTreeObserver.OnGlobalLayoutListener {
46
 	public View getView() {
47
 	public View getView() {
47
 		if (view == null) {
48
 		if (view == null) {
48
 			view = createView();
49
 			view = createView();
50
+			view.setId(CompatUtils.generateViewId());
49
 			view.getViewTreeObserver().addOnGlobalLayoutListener(this);
51
 			view.getViewTreeObserver().addOnGlobalLayoutListener(this);
50
 		}
52
 		}
51
 		return view;
53
 		return view;

+ 18
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java View File

1
+package com.reactnativenavigation.views;
2
+
3
+import android.app.Activity;
4
+import android.support.design.widget.AppBarLayout;
5
+import android.support.v7.widget.Toolbar;
6
+
7
+public class TopBar extends AppBarLayout {
8
+	private final Toolbar titleBar;
9
+
10
+	public TopBar(final Activity context) {
11
+		super(context);
12
+		titleBar = new Toolbar(context);
13
+	}
14
+
15
+	public void setTitle(String title) {
16
+		titleBar.setTitle(title);
17
+	}
18
+}

+ 18
- 0
lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.java View File

1
 package com.reactnativenavigation;
1
 package com.reactnativenavigation;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
+import android.view.View;
5
+import android.view.ViewGroup;
4
 
6
 
5
 import org.junit.After;
7
 import org.junit.After;
6
 import org.junit.Before;
8
 import org.junit.Before;
9
 import org.robolectric.RobolectricTestRunner;
11
 import org.robolectric.RobolectricTestRunner;
10
 import org.robolectric.annotation.Config;
12
 import org.robolectric.annotation.Config;
11
 
13
 
14
+import static org.assertj.core.api.Java6Assertions.assertThat;
15
+
12
 @RunWith(RobolectricTestRunner.class)
16
 @RunWith(RobolectricTestRunner.class)
13
 @Config(sdk = 25, constants = BuildConfig.class, manifest = "/../../../../../src/test/AndroidManifest.xml")
17
 @Config(sdk = 25, constants = BuildConfig.class, manifest = "/../../../../../src/test/AndroidManifest.xml")
14
 public abstract class BaseTest {
18
 public abstract class BaseTest {
25
 	public Activity newActivity() {
29
 	public Activity newActivity() {
26
 		return Robolectric.setupActivity(Activity.class);
30
 		return Robolectric.setupActivity(Activity.class);
27
 	}
31
 	}
32
+
33
+	public void assertIsChildById(ViewGroup parent, View child) {
34
+		assertThat(parent).isNotNull();
35
+		assertThat(child).isNotNull();
36
+		assertThat(child.getId()).isNotZero().isPositive();
37
+		assertThat(parent.findViewById(child.getId())).isNotNull().isEqualTo(child);
38
+	}
39
+
40
+	public void assertNotChildOf(ViewGroup parent, View child) {
41
+		assertThat(parent).isNotNull();
42
+		assertThat(child).isNotNull();
43
+		assertThat(child.getId()).isNotZero().isPositive();
44
+		assertThat(parent.findViewById(child.getId())).isNull();
45
+	}
28
 }
46
 }

+ 7
- 13
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java View File

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
-import android.view.ViewGroup;
6
 
5
 
7
 import com.reactnativenavigation.BaseTest;
6
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.mocks.SimpleViewController;
7
 import com.reactnativenavigation.mocks.SimpleViewController;
44
 	public void setRoot_AddsChildControllerView() throws Exception {
43
 	public void setRoot_AddsChildControllerView() throws Exception {
45
 		assertThat(uut.getView().getChildCount()).isZero();
44
 		assertThat(uut.getView().getChildCount()).isZero();
46
 		uut.setRoot(child1);
45
 		uut.setRoot(child1);
47
-		assertHasSingleChildViewOf(uut, child1);
46
+		assertIsChildById(uut.getView(), child1.getView());
48
 	}
47
 	}
49
 
48
 
50
 	@Test
49
 	@Test
51
 	public void setRoot_ReplacesExistingChildControllerViews() throws Exception {
50
 	public void setRoot_ReplacesExistingChildControllerViews() throws Exception {
52
 		uut.setRoot(child1);
51
 		uut.setRoot(child1);
53
 		uut.setRoot(child2);
52
 		uut.setRoot(child2);
54
-		assertHasSingleChildViewOf(uut, child2);
53
+		assertIsChildById(uut.getView(), child2.getView());
55
 	}
54
 	}
56
 
55
 
57
 	@Test
56
 	@Test
66
 		stackController.push(child1);
65
 		stackController.push(child1);
67
 		uut.setRoot(stackController);
66
 		uut.setRoot(stackController);
68
 
67
 
69
-		assertHasSingleChildViewOf(uut, stackController);
70
-		assertHasSingleChildViewOf(stackController, child1);
68
+		assertIsChildById(uut.getView(), stackController.getView());
69
+		assertIsChildById(stackController.getView(), child1.getView());
71
 
70
 
72
 		uut.push(child1.getId(), child2);
71
 		uut.push(child1.getId(), child2);
73
 
72
 
74
-		assertHasSingleChildViewOf(uut, stackController);
75
-		assertHasSingleChildViewOf(stackController, child2);
73
+		assertIsChildById(uut.getView(), stackController.getView());
74
+		assertIsChildById(stackController.getView(), child2.getView());
76
 	}
75
 	}
77
 
76
 
78
 	@Test
77
 	@Test
79
 	public void push_InvalidPushWithoutAStack_DoesNothing() throws Exception {
78
 	public void push_InvalidPushWithoutAStack_DoesNothing() throws Exception {
80
 		uut.setRoot(child1);
79
 		uut.setRoot(child1);
81
 		uut.push(child1.getId(), child2);
80
 		uut.push(child1.getId(), child2);
82
-		assertHasSingleChildViewOf(uut, child1);
81
+		assertIsChildById(uut.getView(), child1.getView());
83
 	}
82
 	}
84
 
83
 
85
 	@Test
84
 	@Test
193
 		return new BottomTabsController(activity, "tabsController");
192
 		return new BottomTabsController(activity, "tabsController");
194
 	}
193
 	}
195
 
194
 
196
-	private void assertHasSingleChildViewOf(ViewController parent, ViewController child) {
197
-		assertThat(((ViewGroup) parent.getView()).getChildCount()).isEqualTo(1);
198
-		assertThat(((ViewGroup) parent.getView()).getChildAt(0)).isEqualTo(child.getView()).isNotNull();
199
-	}
200
-
201
 	@NonNull
195
 	@NonNull
202
 	private StackController newStack() {
196
 	private StackController newStack() {
203
 		return new StackController(activity, "stack" + CompatUtils.generateViewId(), new TestStackAnimator());
197
 		return new StackController(activity, "stack" + CompatUtils.generateViewId(), new TestStackAnimator());

+ 13
- 26
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.view.ViewGroup;
5
-import android.widget.FrameLayout;
6
 
4
 
7
 import com.reactnativenavigation.BaseTest;
5
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.mocks.SimpleViewController;
6
 import com.reactnativenavigation.mocks.SimpleViewController;
126
 		assertThat(uut.canPop()).isTrue();
124
 		assertThat(uut.canPop()).isTrue();
127
 	}
125
 	}
128
 
126
 
129
-	@Test
130
-	public void constructsSelfWithFrameLayout() throws Exception {
131
-		assertThat(uut.getView())
132
-				.isNotNull()
133
-				.isInstanceOf(ViewGroup.class)
134
-				.isInstanceOf(FrameLayout.class);
135
-	}
136
-
137
 	@Test
127
 	@Test
138
 	public void pushAddsToViewTree() throws Exception {
128
 	public void pushAddsToViewTree() throws Exception {
139
-		assertThat(uut.getView().getChildCount()).isZero();
129
+		assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
140
 		uut.push(child1);
130
 		uut.push(child1);
141
-		assertHasSingleChildViewOfController(child1);
131
+		assertThat(uut.getView().findViewById(child1.getView().getId())).isNotNull();
142
 	}
132
 	}
143
 
133
 
144
 	@Test
134
 	@Test
145
 	public void pushRemovesPreviousFromTree() throws Exception {
135
 	public void pushRemovesPreviousFromTree() throws Exception {
146
-		assertThat(uut.getView().getChildCount()).isZero();
136
+		assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
147
 		uut.push(child1);
137
 		uut.push(child1);
148
-		assertHasSingleChildViewOfController(child1);
138
+		assertThat(uut.getView().findViewById(child1.getView().getId())).isNotNull();
149
 		uut.push(child2);
139
 		uut.push(child2);
150
-		assertHasSingleChildViewOfController(child2);
140
+		assertThat(uut.getView().findViewById(child1.getView().getId())).isNull();
141
+		assertThat(uut.getView().findViewById(child2.getView().getId())).isNotNull();
151
 	}
142
 	}
152
 
143
 
153
 	@Test
144
 	@Test
154
 	public void popReplacesViewWithPrevious() throws Exception {
145
 	public void popReplacesViewWithPrevious() throws Exception {
155
 		uut.push(child1);
146
 		uut.push(child1);
156
 		uut.push(child2);
147
 		uut.push(child2);
157
-		assertHasSingleChildViewOfController(child2);
148
+		assertIsChildById(uut.getView(), child2.getView());
149
+		assertNotChildOf(uut.getView(), child1.getView());
158
 		uut.pop();
150
 		uut.pop();
159
-		assertHasSingleChildViewOfController(child1);
151
+		assertNotChildOf(uut.getView(), child2.getView());
152
+		assertIsChildById(uut.getView(), child1.getView());
160
 	}
153
 	}
161
 
154
 
162
 	@Test
155
 	@Test
165
 		uut.push(child2);
158
 		uut.push(child2);
166
 		uut.popSpecific(child2);
159
 		uut.popSpecific(child2);
167
 		assertContainsOnlyId(child1.getId());
160
 		assertContainsOnlyId(child1.getId());
168
-		assertHasSingleChildViewOfController(child1);
161
+		assertIsChildById(uut.getView(), child1.getView());
169
 	}
162
 	}
170
 
163
 
171
 	@Test
164
 	@Test
172
 	public void popSpecificDeepInStack() throws Exception {
165
 	public void popSpecificDeepInStack() throws Exception {
173
 		uut.push(child1);
166
 		uut.push(child1);
174
 		uut.push(child2);
167
 		uut.push(child2);
175
-		assertHasSingleChildViewOfController(child2);
176
-
168
+		assertIsChildById(uut.getView(), child2.getView());
177
 		uut.popSpecific(child1);
169
 		uut.popSpecific(child1);
178
 		assertContainsOnlyId(child2.getId());
170
 		assertContainsOnlyId(child2.getId());
179
-		assertHasSingleChildViewOfController(child2);
171
+		assertIsChildById(uut.getView(), child2.getView());
180
 	}
172
 	}
181
 
173
 
182
 	@Test
174
 	@Test
285
 		verify(child3, times(1)).destroy();
277
 		verify(child3, times(1)).destroy();
286
 	}
278
 	}
287
 
279
 
288
-	private void assertHasSingleChildViewOfController(ViewController childController) {
289
-		assertThat(uut.getView().getChildCount()).isEqualTo(1);
290
-		assertThat(uut.getView().getChildAt(0)).isEqualTo(childController.getView());
291
-	}
292
-
293
 	private void assertContainsOnlyId(String... ids) {
280
 	private void assertContainsOnlyId(String... ids) {
294
 		assertThat(uut.size()).isEqualTo(ids.length);
281
 		assertThat(uut.size()).isEqualTo(ids.length);
295
 		assertThat(uut.getChildControllers()).extracting(new Extractor<ViewController, String>() {
282
 		assertThat(uut.getChildControllers()).extracting(new Extractor<ViewController, String>() {

+ 5
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ViewControllerTest.java View File

172
 		verify(spy, times(1)).onViewDisappear();
172
 		verify(spy, times(1)).onViewDisappear();
173
 	}
173
 	}
174
 
174
 
175
+	@Test
176
+	public void assignsIdToCreatedView() throws Exception {
177
+		assertThat(uut.getView().getId()).isPositive();
178
+	}
179
+
175
 	@Test
180
 	@Test
176
 	public void onDestroy_RemovesSelfFromParentIfExists() throws Exception {
181
 	public void onDestroy_RemovesSelfFromParentIfExists() throws Exception {
177
 		LinearLayout parent = new LinearLayout(activity);
182
 		LinearLayout parent = new LinearLayout(activity);

+ 1
- 1
playground/src/containers/OptionsScreen.js View File

22
   render() {
22
   render() {
23
     return (
23
     return (
24
       <View style={styles.root}>
24
       <View style={styles.root}>
25
-        <Text style={styles.h1}>{`Style Screen`}</Text>
25
+        <Text style={styles.h1}>{`Options Screen`}</Text>
26
         <Button title="Dynamic Options" onPress={this.onClickDynamicOptions} />
26
         <Button title="Dynamic Options" onPress={this.onClickDynamicOptions} />
27
         <Text style={styles.footer}>{`this.props.id = ${this.props.id}`}</Text>
27
         <Text style={styles.footer}>{`this.props.id = ${this.props.id}`}</Text>
28
       </View>
28
       </View>