瀏覽代碼

Fix title component not being replaced via mergeOptions (#6066)

This commit fixes a bug related to setting a new react component as title via mergeOptions. When a title component was set, and the user tried to replace the existing title with a new title via mergeOptions, the new title was not created and instead the current title was reapplied.
Fixes #5377
Guy Carmeli 4 年之前
父節點
當前提交
b0e8a824f5
No account linked to committer's email address

+ 21
- 12
lib/android/app/src/main/java/com/reactnativenavigation/presentation/StackPresenter.java 查看文件

@@ -177,14 +177,13 @@ public class StackPresenter {
177 177
 
178 178
         if (topBarOptions.title.component.hasValue()) {
179 179
             if (titleControllers.containsKey(component)) {
180
-                topBar.setTitleComponent(titleControllers.get(component).getView());
180
+                topBarController.setTitleComponent(titleControllers.get(component));
181 181
             } else {
182
-                TitleBarReactViewController controller = new TitleBarReactViewController(activity, titleViewCreator);
182
+                TitleBarReactViewController controller = new TitleBarReactViewController(activity, titleViewCreator, topBarOptions.title.component);
183 183
                 controller.setWaitForRender(topBarOptions.title.component.waitForRender);
184 184
                 titleControllers.put(component, controller);
185
-                controller.setComponent(topBarOptions.title.component);
186 185
                 controller.getView().setLayoutParams(getComponentLayoutParams(topBarOptions.title.component));
187
-                topBar.setTitleComponent(controller.getView());
186
+                topBarController.setTitleComponent(controller);
188 187
             }
189 188
         }
190 189
 
@@ -415,19 +414,19 @@ public class StackPresenter {
415 414
         }
416 415
 
417 416
         if (topBarOptions.title.height.hasValue()) topBar.setTitleHeight(topBarOptions.title.height.get());
418
-        if (topBarOptions.title.text.hasValue()) topBar.setTitle(topBarOptions.title.text.get());
419 417
         if (topBarOptions.title.topMargin.hasValue()) topBar.setTitleTopMargin(topBarOptions.title.topMargin.get());
420 418
 
421 419
         if (topBarOptions.title.component.hasValue()) {
422
-            if (titleControllers.containsKey(component)) {
423
-                topBar.setTitleComponent(titleControllers.get(component).getView());
424
-            } else {
425
-                TitleBarReactViewController controller = new TitleBarReactViewController(activity, titleViewCreator);
426
-                titleControllers.put(component, controller);
427
-                controller.setComponent(topBarOptions.title.component);
420
+            TitleBarReactViewController controller = findTitleComponent(topBarOptions.title.component);
421
+            if (controller == null) {
422
+                controller = new TitleBarReactViewController(activity, titleViewCreator, topBarOptions.title.component);
423
+                perform(titleControllers.put(component, controller), ViewController::destroy);
428 424
                 controller.getView().setLayoutParams(getComponentLayoutParams(topBarOptions.title.component));
429
-                topBar.setTitleComponent(controller.getView());
430 425
             }
426
+            topBarController.setTitleComponent(controller);
427
+        } else if (topBarOptions.title.text.hasValue()) {
428
+            perform(titleControllers.remove(component), ViewController::destroy);
429
+            topBar.setTitle(topBarOptions.title.text.get());
431 430
         }
432 431
 
433 432
         if (topBarOptions.title.color.hasValue()) topBar.setTitleTextColor(topBarOptions.title.color.get());
@@ -478,6 +477,16 @@ public class StackPresenter {
478 477
         }
479 478
     }
480 479
 
480
+    private TitleBarReactViewController findTitleComponent(com.reactnativenavigation.parse.Component component) {
481
+        for (TitleBarReactViewController controller : titleControllers.values()) {
482
+            if (ObjectUtils.equalsNotNull(controller.getComponent().name.get(null), component.name.get(null)) &&
483
+                ObjectUtils.equalsNotNull(controller.getComponent().componentId.get(null), component.componentId.get(null))) {
484
+                return controller;
485
+            }
486
+        }
487
+        return null;
488
+    }
489
+
481 490
     private void mergeTopTabsOptions(TopTabsOptions options) {
482 491
         if (options.selectedTabColor.hasValue() && options.unselectedTabColor.hasValue()) topBar.applyTopTabsColors(options.selectedTabColor, options.unselectedTabColor);
483 492
         if (options.fontSize.hasValue()) topBar.applyTopTabsFontSize(options.fontSize);

+ 7
- 6
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewController.java 查看文件

@@ -13,11 +13,16 @@ import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
13 13
 public class TitleBarReactViewController extends ViewController<TitleBarReactView> {
14 14
 
15 15
     private final TitleBarReactViewCreator reactViewCreator;
16
-    private Component component;
16
+    private final Component component;
17 17
 
18
-    public TitleBarReactViewController(Activity activity, TitleBarReactViewCreator reactViewCreator) {
18
+    public Component getComponent() {
19
+        return component;
20
+    }
21
+
22
+    public TitleBarReactViewController(Activity activity, TitleBarReactViewCreator reactViewCreator, Component component) {
19 23
         super(activity, CompatUtils.generateViewId() + "", new YellowBoxDelegate(), new Options(), new ViewControllerOverlay(activity));
20 24
         this.reactViewCreator = reactViewCreator;
25
+        this.component = component;
21 26
     }
22 27
 
23 28
     @Override
@@ -49,8 +54,4 @@ public class TitleBarReactViewController extends ViewController<TitleBarReactVie
49 54
     public String getCurrentComponentName() {
50 55
         return null;
51 56
     }
52
-
53
-    public void setComponent(Component component) {
54
-        this.component = component;
55
-    }
56 57
 }

+ 5
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/topbar/TopBarController.java 查看文件

@@ -6,6 +6,7 @@ import android.view.View;
6 6
 import com.reactnativenavigation.anim.TopBarAnimator;
7 7
 import com.reactnativenavigation.parse.AnimationOptions;
8 8
 import com.reactnativenavigation.utils.CompatUtils;
9
+import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
9 10
 import com.reactnativenavigation.views.StackLayout;
10 11
 import com.reactnativenavigation.views.topbar.TopBar;
11 12
 
@@ -93,4 +94,8 @@ public class TopBarController {
93 94
         topBar.setRotationY(0);
94 95
         topBar.setRotation(0);
95 96
     }
97
+
98
+    public void setTitleComponent(TitleBarReactViewController component) {
99
+        topBar.setTitleComponent(component.getView());
100
+    }
96 101
 }

+ 3
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java 查看文件

@@ -29,6 +29,7 @@ import static com.reactnativenavigation.utils.ObjectUtils.perform;
29 29
 import static com.reactnativenavigation.utils.UiUtils.runOnPreDrawOnce;
30 30
 import static com.reactnativenavigation.utils.ViewUtils.findChildByClass;
31 31
 import static com.reactnativenavigation.utils.ViewUtils.findChildrenByClass;
32
+import static com.reactnativenavigation.utils.ViewUtils.removeFromParent;
32 33
 
33 34
 @SuppressLint("ViewConstructor")
34 35
 public class TitleBar extends Toolbar {
@@ -70,6 +71,7 @@ public class TitleBar extends Toolbar {
70 71
     }
71 72
 
72 73
     public void setComponent(View component) {
74
+        if (this.component == component) return;
73 75
         clearTitle();
74 76
         clearSubtitle();
75 77
         this.component = component;
@@ -175,7 +177,7 @@ public class TitleBar extends Toolbar {
175 177
 
176 178
     private void clearComponent() {
177 179
         if (component != null) {
178
-            removeView(component);
180
+            removeFromParent(component);
179 181
             component = null;
180 182
         }
181 183
     }

+ 7
- 0
lib/android/app/src/test/java/com/reactnativenavigation/utils/TitleBarHelper.java 查看文件

@@ -35,6 +35,13 @@ public class TitleBarHelper {
35 35
         return button;
36 36
     }
37 37
 
38
+    public static Component titleComponent(String componentId) {
39
+        Component component = new Component();
40
+        component.componentId = new Text(componentId);
41
+        component.name = new Text(componentId);
42
+        return component;
43
+    }
44
+
38 45
     public static Button iconButton(String id, String icon) {
39 46
         Button button = new Button();
40 47
         button.id = "someButton";

+ 56
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackPresenterTest.java 查看文件

@@ -84,9 +84,10 @@ public class StackPresenterTest extends BaseTest {
84 84
     private Button textBtn2 = TitleBarHelper.textualButton("btn2");
85 85
     private Button componentBtn1 = TitleBarHelper.reactViewButton("btn1_");
86 86
     private Button componentBtn2 = TitleBarHelper.reactViewButton("btn2_");
87
+    private Component titleComponent1 = TitleBarHelper.titleComponent("component1");
88
+    private Component titleComponent2 = TitleBarHelper.titleComponent("component2");
87 89
     private TopBarController topBarController;
88 90
     private ChildControllersRegistry childRegistry;
89
-    private IconResolver iconResolver;
90 91
 
91 92
     @Override
92 93
     public void beforeEach() {
@@ -98,7 +99,7 @@ public class StackPresenterTest extends BaseTest {
98 99
             }
99 100
         };
100 101
         renderChecker = spy(new RenderChecker());
101
-        iconResolver = new IconResolver(activity, ImageLoaderMock.mock());
102
+        IconResolver iconResolver = new IconResolver(activity, ImageLoaderMock.mock());
102 103
         uut = spy(new StackPresenter(activity, titleViewCreator, new TopBarBackgroundViewCreatorMock(), new TopBarButtonCreatorMock(), iconResolver, renderChecker, new Options()));
103 104
         createTopBarController();
104 105
 
@@ -309,6 +310,59 @@ public class StackPresenterTest extends BaseTest {
309 310
         uut.mergeChildOptions(options, EMPTY_OPTIONS, parent, child);
310 311
     }
311 312
 
313
+    @Test
314
+    public void applyTopBarOptions_setTitleComponent() {
315
+        Options applyComponent = new Options();
316
+        applyComponent.topBar.title.component.name = new Text("Component1");
317
+        applyComponent.topBar.title.component.componentId = new Text("Component1id");
318
+        uut.applyChildOptions(applyComponent, parent, child);
319
+        verify(topBarController).setTitleComponent(any());
320
+    }
321
+
322
+    @Test
323
+    public void mergeTopBarOptions_settingTitleDestroysComponent() {
324
+        Options componentOptions = new Options();
325
+        componentOptions.topBar.title.component = titleComponent1;
326
+        uut.applyChildOptions(componentOptions, parent, child);
327
+        ArgumentCaptor<TitleBarReactViewController> applyCaptor = ArgumentCaptor.forClass(TitleBarReactViewController.class);
328
+        verify(topBarController).setTitleComponent(applyCaptor.capture());
329
+
330
+        Options titleOptions = new Options();
331
+        titleOptions.topBar.title.text = new Text("Some title");
332
+        uut.mergeChildOptions(titleOptions, Options.EMPTY, parent, child);
333
+        assertThat(applyCaptor.getValue().isDestroyed()).isTrue();
334
+    }
335
+
336
+    @Test
337
+    public void mergeTopBarOptions_doesNotRecreateTitleComponentIfEquals() {
338
+        Options options = new Options();
339
+        options.topBar.title.component = titleComponent1;
340
+        uut.applyChildOptions(options, parent, child);
341
+        ArgumentCaptor<TitleBarReactViewController> applyCaptor = ArgumentCaptor.forClass(TitleBarReactViewController.class);
342
+        verify(topBarController).setTitleComponent(applyCaptor.capture());
343
+
344
+        uut.mergeChildOptions(options, Options.EMPTY, parent, child);
345
+        verify(topBarController, times(2)).setTitleComponent(applyCaptor.getValue());
346
+    }
347
+
348
+    @Test
349
+    public void mergeTopBarOptions_previousTitleComponentIsDestroyed() {
350
+        Options options = new Options();
351
+        options.topBar.title.component = titleComponent1;
352
+        uut.applyChildOptions(options, parent, child);
353
+        ArgumentCaptor<TitleBarReactViewController> applyCaptor = ArgumentCaptor.forClass(TitleBarReactViewController.class);
354
+        verify(topBarController).setTitleComponent(applyCaptor.capture());
355
+
356
+        Options toMerge = new Options();
357
+        toMerge.topBar.title.component = titleComponent2;
358
+        uut.mergeChildOptions(toMerge, Options.EMPTY, parent, child);
359
+        ArgumentCaptor<TitleBarReactViewController> mergeCaptor = ArgumentCaptor.forClass(TitleBarReactViewController.class);
360
+        verify(topBarController, times(2)).setTitleComponent(mergeCaptor.capture());
361
+
362
+        assertThat(applyCaptor.getValue()).isNotEqualTo(mergeCaptor.getValue());
363
+        assertThat(applyCaptor.getValue().isDestroyed()).isTrue();
364
+    }
365
+
312 366
     @Test
313 367
     public void mergeTopTabsOptions() {
314 368
         Options options = new Options();

+ 5
- 5
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarReactViewControllerTest.java 查看文件

@@ -23,9 +23,8 @@ public class TitleBarReactViewControllerTest extends BaseTest {
23 23
     public void beforeEach() {
24 24
         viewCreator = spy(new TitleBarReactViewCreatorMock());
25 25
         activity = newActivity();
26
-        uut = new TitleBarReactViewController(activity, viewCreator);
27
-        createComponent();
28
-        uut.setComponent(component);
26
+        component = createComponent();
27
+        uut = new TitleBarReactViewController(activity, viewCreator, component);
29 28
     }
30 29
 
31 30
     @Test
@@ -34,9 +33,10 @@ public class TitleBarReactViewControllerTest extends BaseTest {
34 33
         verify(viewCreator).create(activity, component.componentId.get(), component.name.get());
35 34
     }
36 35
 
37
-    private void createComponent() {
38
-        component = new Component();
36
+    private Component createComponent() {
37
+        Component component = new Component();
39 38
         component.componentId = new Text("compId");
40 39
         component.name = new Text("compName");
40
+        return component;
41 41
     }
42 42
 }

+ 10
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java 查看文件

@@ -124,6 +124,15 @@ public class TitleBarTest extends BaseTest {
124 124
         verify(uut).addView(component);
125 125
     }
126 126
 
127
+    @Test
128
+    public void setComponent_doesNothingIfComponentIsAlreadyAdded() {
129
+        View component = new View(activity);
130
+        uut.setComponent(component);
131
+
132
+        uut.setComponent(component);
133
+        verify(uut).addView(component);
134
+    }
135
+
127 136
     @Test
128 137
     public void addView_overflowIsEnabledForButtonsContainer() {
129 138
         ActionMenuView buttonsContainer = mock(ActionMenuView.class);
@@ -141,7 +150,7 @@ public class TitleBarTest extends BaseTest {
141 150
         assertThat(uut.getTitle()).isNullOrEmpty();
142 151
         assertThat(uut.getMenu().size()).isZero();
143 152
         assertThat(uut.getNavigationIcon()).isNull();
144
-        verify(uut).removeView(title);
153
+        assertThat(title.getParent()).isNull();
145 154
     }
146 155
 
147 156
     @Test

+ 0
- 1
playground/src/commons/Options.js 查看文件

@@ -3,7 +3,6 @@ const Colors = require('./Colors');
3 3
 const { Dimensions } = require('react-native');
4 4
 const height = Math.round(Dimensions.get('window').height);
5 5
 const width = Math.round(Dimensions.get('window').width);
6
-console.log('guyca', `height: ${height} width: ${width}`);
7 6
 const {
8 7
   useCustomAnimations,
9 8
   useSlowOpenScreenAnimations,