Browse Source

Merge child options when child appears

Guy Carmeli 6 years ago
parent
commit
5114fdfe4c

+ 7
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java View File

@@ -54,11 +54,17 @@ public class Options implements DEFAULT_VALUES {
54 54
         topTabOptions.tabIndex = i;
55 55
     }
56 56
 
57
+    @CheckResult
58
+    public Options copy() {
59
+        return new Options().mergeWith(this);
60
+    }
61
+
57 62
     @CheckResult
58 63
 	public Options mergeWith(final Options other) {
59 64
         Options result = new Options();
60 65
         result.topBarOptions.mergeWith(other.topBarOptions);
61 66
         result.topTabsOptions.mergeWith(other.topTabsOptions);
67
+        result.topTabOptions.mergeWith(other.topTabOptions);
62 68
         result.bottomTabOptions.mergeWith(other.bottomTabOptions);
63 69
         result.bottomTabsOptions.mergeWith(other.bottomTabsOptions);
64 70
         return result;
@@ -66,6 +72,7 @@ public class Options implements DEFAULT_VALUES {
66 72
 
67 73
     Options withDefaultOptions(final Options other) {
68 74
         topBarOptions.mergeWithDefault(other.topBarOptions);
75
+        topTabOptions.mergeWithDefault(other.topTabOptions);
69 76
         topTabsOptions.mergeWithDefault(other.topTabsOptions);
70 77
         bottomTabOptions.mergeWithDefault(other.bottomTabOptions);
71 78
         bottomTabsOptions.mergeWithDefault(other.bottomTabsOptions);

+ 6
- 4
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopTabOptions.java View File

@@ -21,11 +21,13 @@ public class TopTabOptions implements DEFAULT_VALUES {
21 21
         return result;
22 22
     }
23 23
 
24
-    void mergeWith(TopTabOptions topTabsOptions) {
25
-
24
+    void mergeWith(TopTabOptions other) {
25
+        if (other.title.hasValue()) title = other.title;
26
+        if (other.fontFamily != null) fontFamily = other.fontFamily;
27
+        if (other.tabIndex >= 0) tabIndex = other.tabIndex;
26 28
     }
27 29
 
28
-    void mergeWithDefault(TopTabOptions topTabsOptions) {
29
-
30
+    void mergeWithDefault(TopTabOptions other) {
31
+        if (fontFamily == null) fontFamily = other.fontFamily;
30 32
     }
31 33
 }

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

@@ -58,6 +58,11 @@ public abstract class ParentController<T extends ViewGroup> extends ViewControll
58 58
 
59 59
     @CallSuper
60 60
     public void applyOptions(Options options, ReactComponent childComponent) {
61
+        mergeChildOptions(options);
62
+        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(this.options, childComponent));
63
+    }
64
+
65
+    private void mergeChildOptions(Options options) {
61 66
         this.options = this.options.mergeWith(options);
62 67
     }
63 68
 

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

@@ -38,7 +38,6 @@ public class StackController extends ParentController <StackLayout> {
38 38
     public void applyOptions(Options options, ReactComponent component) {
39 39
         super.applyOptions(options, component);
40 40
         stackLayout.applyOptions(this.options, component);
41
-        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(this.options, component));
42 41
     }
43 42
 
44 43
     @Override

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

@@ -30,6 +30,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
30 30
         boolean onViewDisappear(View view);
31 31
     }
32 32
 
33
+    Options initialOptions;
33 34
     public Options options;
34 35
 
35 36
     private final Activity activity;
@@ -43,7 +44,8 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
43 44
     public ViewController(Activity activity, String id, Options initialOptions) {
44 45
         this.activity = activity;
45 46
         this.id = id;
46
-        options = initialOptions;
47
+        this.initialOptions = initialOptions;
48
+        options = initialOptions.copy();
47 49
     }
48 50
 
49 51
     protected abstract T createView();

+ 0
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java View File

@@ -70,7 +70,6 @@ public class TopTabsController extends ParentController<TopTabsViewPager> implem
70 70
     @Override
71 71
     public void applyOptions(Options options, ReactComponent childComponent) {
72 72
         super.applyOptions(options, childComponent);
73
-        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(this.options, childComponent));
74 73
     }
75 74
 
76 75
     @Override

+ 6
- 8
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java View File

@@ -59,8 +59,7 @@ public class OptionsApplyingTest extends BaseTest {
59 59
 
60 60
     @Test
61 61
     public void initialOptionsAppliedOnAppear() throws Exception {
62
-        assertThat(uut.options).isSameAs(initialNavigationOptions);
63
-        initialNavigationOptions.topBarOptions.title = new Text("the title");
62
+        uut.options.topBarOptions.title = new Text("the title");
64 63
         StackController stackController = new StackController(activity, "stackId", new Options());
65 64
         stackController.animatePush(uut, new MockPromise() {});
66 65
         assertThat(stackController.getTopBar().getTitle()).isEmpty();
@@ -106,7 +105,7 @@ public class OptionsApplyingTest extends BaseTest {
106 105
 
107 106
     @Test
108 107
     public void appliesTopBarTextColor() throws Exception {
109
-        assertThat(uut.options).isSameAs(initialNavigationOptions);
108
+        assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
110 109
         stackController.animatePush(uut, new MockPromise() {
111 110
             @Override
112 111
             public void resolve(@Nullable Object value) {
@@ -123,7 +122,7 @@ public class OptionsApplyingTest extends BaseTest {
123 122
 
124 123
     @Test
125 124
     public void appliesTopBarTextSize() throws Exception {
126
-        assertThat(uut.options).isSameAs(initialNavigationOptions);
125
+        assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
127 126
         initialNavigationOptions.topBarOptions.title = new Text("the title");
128 127
         uut.ensureViewIsCreated();
129 128
         uut.onViewAppeared();
@@ -139,7 +138,7 @@ public class OptionsApplyingTest extends BaseTest {
139 138
 
140 139
     @Test
141 140
     public void appliesTopBarHidden() throws Exception {
142
-        assertThat(uut.options).isSameAs(initialNavigationOptions);
141
+        assertThat(uut.initialOptions).isSameAs(initialNavigationOptions);
143 142
         initialNavigationOptions.topBarOptions.title = new Text("the title");
144 143
         uut.ensureViewIsCreated();
145 144
         uut.onViewAppeared();
@@ -154,9 +153,8 @@ public class OptionsApplyingTest extends BaseTest {
154 153
 
155 154
     @Test
156 155
     public void appliesDrawUnder() throws Exception {
157
-        assertThat(uut.options).isSameAs(initialNavigationOptions);
158
-        initialNavigationOptions.topBarOptions.title = new Text("the title");
159
-        initialNavigationOptions.topBarOptions.drawBehind = Options.BooleanOptions.False;
156
+        uut.options.topBarOptions.title = new Text("the title");
157
+        uut.options.topBarOptions.drawBehind = Options.BooleanOptions.False;
160 158
         uut.ensureViewIsCreated();
161 159
         uut.onViewAppeared();
162 160
         stackController.animatePush(uut, new MockPromise() {

+ 61
- 14
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/ParentControllerTest.java View File

@@ -1,23 +1,32 @@
1 1
 package com.reactnativenavigation.viewcontrollers;
2 2
 
3
-import android.app.*;
4
-import android.support.annotation.*;
5
-import android.view.*;
6
-import android.widget.*;
7
-
8
-import com.reactnativenavigation.*;
9
-import com.reactnativenavigation.mocks.*;
3
+import android.app.Activity;
4
+import android.support.annotation.NonNull;
5
+import android.view.ViewGroup;
6
+import android.widget.FrameLayout;
7
+
8
+import com.reactnativenavigation.BaseTest;
9
+import com.reactnativenavigation.mocks.MockPromise;
10
+import com.reactnativenavigation.mocks.SimpleViewController;
10 11
 import com.reactnativenavigation.parse.Options;
12
+import com.reactnativenavigation.parse.Text;
13
+import com.reactnativenavigation.views.ReactComponent;
11 14
 
12
-import org.junit.*;
15
+import org.junit.Test;
16
+import org.mockito.ArgumentCaptor;
13 17
 
14
-import java.util.*;
18
+import java.util.ArrayList;
19
+import java.util.Collection;
20
+import java.util.List;
15 21
 
16
-import static org.assertj.core.api.Java6Assertions.*;
17
-import static org.mockito.Mockito.*;
22
+import static org.assertj.core.api.Java6Assertions.assertThat;
23
+import static org.mockito.Mockito.spy;
24
+import static org.mockito.Mockito.times;
25
+import static org.mockito.Mockito.verify;
18 26
 
19 27
 public class ParentControllerTest extends BaseTest {
20 28
 
29
+    public static final String INITIAL_TITLE = "initial title";
21 30
     private Activity activity;
22 31
     private List<ViewController> children;
23 32
     private ParentController uut;
@@ -27,12 +36,19 @@ public class ParentControllerTest extends BaseTest {
27 36
         super.beforeEach();
28 37
         activity = newActivity();
29 38
         children = new ArrayList<>();
30
-        uut = new ParentController(activity, "uut", new Options()) {
39
+        Options initialOptions = new Options();
40
+        initialOptions.topBarOptions.title = new Text(INITIAL_TITLE);
41
+        uut = spy(new ParentController(activity, "uut", initialOptions) {
31 42
 
32 43
             @NonNull
33 44
             @Override
34 45
             protected ViewGroup createView() {
35
-                return new FrameLayout(activity);
46
+                FrameLayout layout = new FrameLayout(activity);
47
+                for (ViewController child : children) {
48
+                    child.setParentController(this);
49
+                    layout.addView(child.getView());
50
+                }
51
+                return layout;
36 52
             }
37 53
 
38 54
             @NonNull
@@ -40,7 +56,7 @@ public class ParentControllerTest extends BaseTest {
40 56
             public Collection<ViewController> getChildControllers() {
41 57
                 return children;
42 58
             }
43
-        };
59
+        });
44 60
     }
45 61
 
46 62
     @Test
@@ -95,4 +111,35 @@ public class ParentControllerTest extends BaseTest {
95 111
         child1.onViewAppeared();
96 112
         verify(stackController, times(1)).clearOptions();
97 113
     }
114
+
115
+    @Test
116
+    public void mergeOptions_optionsAreMergedWhenChildAppears() throws Exception {
117
+        Options options = new Options();
118
+        options.topBarOptions.title = new Text("new title");
119
+        ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
120
+        children.add(child1);
121
+        uut.ensureViewIsCreated();
122
+
123
+        child1.ensureViewIsCreated();
124
+        child1.onViewAppeared();
125
+        ArgumentCaptor<Options> optionsCaptor = ArgumentCaptor.forClass(Options.class);
126
+        ArgumentCaptor<ReactComponent> viewCaptor = ArgumentCaptor.forClass(ReactComponent.class);
127
+        verify(uut, times(1)).applyOptions(optionsCaptor.capture(), viewCaptor.capture());
128
+        assertThat(optionsCaptor.getValue().topBarOptions.title.get()).isEqualTo("new title");
129
+        assertThat(viewCaptor.getValue()).isEqualTo(child1.getView());
130
+    }
131
+
132
+    @Test
133
+    public void mergeOptions_initialParentOptionsAreNotMutatedWhenChildAppears() throws Exception {
134
+        Options options = new Options();
135
+        options.topBarOptions.title = new Text("new title");
136
+        ViewController child1 = spy(new SimpleViewController(activity, "child1", options));
137
+        children.add(child1);
138
+
139
+        uut.ensureViewIsCreated();
140
+
141
+        child1.ensureViewIsCreated();
142
+        child1.onViewAppeared();
143
+        assertThat(uut.initialOptions.topBarOptions.title.get()).isEqualTo(INITIAL_TITLE);
144
+    }
98 145
 }

+ 17
- 4
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java View File

@@ -15,6 +15,7 @@ import com.reactnativenavigation.views.ReactComponent;
15 15
 import com.reactnativenavigation.views.TopTabsLayoutCreator;
16 16
 import com.reactnativenavigation.views.TopTabsViewPager;
17 17
 
18
+import org.assertj.core.api.Assertions;
18 19
 import org.junit.Test;
19 20
 import org.mockito.Mockito;
20 21
 
@@ -62,7 +63,7 @@ public class TopTabsViewControllerTest extends BaseTest {
62 63
         for (int i = 0; i < SIZE; i++) {
63 64
             final Options options = new Options();
64 65
             options.topTabOptions.title = new Text("Tab " + i);
65
-            options.topBarOptions.title = new Text("Title " + i);
66
+            options.topBarOptions.title = new Text(createTabTopBarTitle(i));
66 67
             result.add(options);
67 68
         }
68 69
         return result;
@@ -162,11 +163,19 @@ public class TopTabsViewControllerTest extends BaseTest {
162 163
         tabControllers.get(1).ensureViewIsCreated();
163 164
 
164 165
         uut.onViewAppeared();
165
-        verify(uut, times(1)).applyOptions(tabOptions.get(0), tabView(0));
166
+        ReactComponent currentTab = tabView(0);
167
+        verify(uut, times(1)).applyOptions(any(Options.class), eq(currentTab));
168
+        Assertions.assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(0));
169
+
166 170
         uut.switchToTab(1);
167
-        verify(uut, times(1)).applyOptions(tabOptions.get(1), tabView(1));
171
+        currentTab = tabView(1);
172
+        verify(uut, times(1)).applyOptions(any(Options.class), eq(currentTab));
173
+        Assertions.assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(1));
174
+
168 175
         uut.switchToTab(0);
169
-        verify(uut, times(2)).applyOptions(tabOptions.get(0), tabView(0));
176
+        currentTab = tabView(0);
177
+        verify(uut, times(2)).applyOptions(any(Options.class), eq(currentTab));
178
+        Assertions.assertThat(uut.options.topBarOptions.title.get()).isEqualTo(createTabTopBarTitle(0));
170 179
     }
171 180
 
172 181
     private TestReactView getActualTabView(int index) {
@@ -187,4 +196,8 @@ public class TopTabsViewControllerTest extends BaseTest {
187 196
     private IReactView tab(TopTabsViewPager topTabs, final int index) {
188 197
         return (IReactView) ((ViewGroup) topTabs.getChildAt(index)).getChildAt(0);
189 198
     }
199
+
200
+    private String createTabTopBarTitle(int i) {
201
+        return "Title " + i;
202
+    }
190 203
 }