Browse Source

Add back button to pushed screens

Guy Carmeli 6 years ago
parent
commit
3c1933b76b
17 changed files with 278 additions and 43 deletions
  1. 5
    0
      lib/android/app/src/main/java/com/reactnativenavigation/react/Constants.java
  2. 9
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/CollectionUtils.java
  3. 9
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoader.java
  4. 5
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoadingListenerAdapter.java
  5. 34
    5
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  6. 12
    21
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TopBarButtonController.java
  7. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java
  8. 44
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/button/NavigationIconResolver.java
  9. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/Fab.java
  10. 10
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java
  11. 9
    0
      lib/android/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml
  12. 8
    1
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/ImageLoaderMock.java
  13. 3
    0
      lib/android/app/src/test/java/com/reactnativenavigation/utils/OptionHelper.java
  14. 47
    9
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  15. 2
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java
  16. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopBarButtonControllerTest.java
  17. 75
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/button/NavigationIconResolverTest.java

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

@@ -0,0 +1,5 @@
1
+package com.reactnativenavigation.react;
2
+
3
+public class Constants {
4
+    public static final String BACK_BUTTON_ID = "RNN.back";
5
+}

+ 9
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/CollectionUtils.java View File

@@ -0,0 +1,9 @@
1
+package com.reactnativenavigation.utils;
2
+
3
+import java.util.Collection;
4
+
5
+public class CollectionUtils {
6
+    public static boolean isNullOrEmpty(Collection collection) {
7
+        return collection == null || collection.isEmpty();
8
+    }
9
+}

+ 9
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoader.java View File

@@ -26,11 +26,20 @@ public class ImageLoader {
26 26
     public interface ImagesLoadingListener {
27 27
         void onComplete(@NonNull List<Drawable> drawable);
28 28
 
29
+        void onComplete(@NonNull Drawable drawable);
30
+
29 31
         void onError(Throwable error);
30 32
     }
31 33
 
32 34
     private static final String FILE_SCHEME = "file";
33 35
 
36
+    public void loadIcon(Context context, String uri, ImagesLoadingListener listener) {
37
+        try {
38
+            listener.onComplete(getDrawable(context, uri));
39
+        } catch (IOException e) {
40
+            listener.onError(e);
41
+        }
42
+    }
34 43
 
35 44
     public void loadIcons(final Context context, List<String> uris, ImagesLoadingListener listener) {
36 45
         try {

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

@@ -11,6 +11,11 @@ public class ImageLoadingListenerAdapter implements ImageLoader.ImagesLoadingLis
11 11
 
12 12
     }
13 13
 
14
+    @Override
15
+    public void onComplete(@NonNull Drawable drawable) {
16
+
17
+    }
18
+
14 19
     @Override
15 20
     public void onError(Throwable error) {
16 21
         error.printStackTrace();

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

@@ -7,6 +7,8 @@ import android.support.v4.view.ViewPager;
7 7
 
8 8
 import com.reactnativenavigation.anim.NavigationAnimator;
9 9
 import com.reactnativenavigation.parse.Options;
10
+import com.reactnativenavigation.parse.params.Button;
11
+import com.reactnativenavigation.react.Constants;
10 12
 import com.reactnativenavigation.utils.CommandListener;
11 13
 import com.reactnativenavigation.utils.CommandListenerAdapter;
12 14
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarBackgroundViewController;
@@ -17,7 +19,9 @@ import com.reactnativenavigation.views.StackLayout;
17 19
 import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
18 20
 import com.reactnativenavigation.views.topbar.TopBar;
19 21
 
22
+import java.util.ArrayList;
20 23
 import java.util.Collection;
24
+import java.util.Collections;
21 25
 import java.util.Iterator;
22 26
 
23 27
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -88,6 +92,7 @@ public class StackController extends ParentController<StackLayout> {
88 92
         final ViewController toRemove = stack.peek();
89 93
         child.setParentController(this);
90 94
         stack.push(child.getId(), child);
95
+        addBackButton(child);
91 96
         getView().addView(child.getView(), MATCH_PARENT, MATCH_PARENT);
92 97
 
93 98
         if (toRemove != null) {
@@ -105,6 +110,15 @@ public class StackController extends ParentController<StackLayout> {
105 110
         }
106 111
     }
107 112
 
113
+    private void addBackButton(ViewController child) {
114
+        if (size() <= 1 || child.options.topBar.leftButtons != null) return;
115
+        Options options = new Options();
116
+        Button back = new Button();
117
+        back.id = Constants.BACK_BUTTON_ID;
118
+        options.topBar.leftButtons = new ArrayList<>(Collections.singleton(back));
119
+        child.mergeOptions(options);
120
+    }
121
+
108 122
     public void setRoot(ViewController child, CommandListener listener) {
109 123
         push(child, new CommandListenerAdapter() {
110 124
             @Override
@@ -227,15 +241,30 @@ public class StackController extends ParentController<StackLayout> {
227 241
         return stack.size() > 1;
228 242
     }
229 243
 
244
+    @NonNull
230 245
     @Override
231
-    public void sendOnNavigationButtonPressed(String buttonId) {
232
-        peek().sendOnNavigationButtonPressed(buttonId);
246
+    protected StackLayout createView() {
247
+        return new StackLayout(getActivity(),
248
+                topBarButtonCreator,
249
+                titleBarReactViewCreator,
250
+                topBarBackgroundViewController,
251
+                topBarController,
252
+                this::onNavigationButtonPressed,
253
+                getId()
254
+        );
255
+    }
256
+
257
+    private void onNavigationButtonPressed(String buttonId) {
258
+        if (Constants.BACK_BUTTON_ID.equals(buttonId)) {
259
+            pop(new CommandListenerAdapter());
260
+        } else {
261
+            sendOnNavigationButtonPressed(buttonId);
262
+        }
233 263
     }
234 264
 
235
-    @NonNull
236 265
     @Override
237
-    protected StackLayout createView() {
238
-        return new StackLayout(getActivity(), topBarButtonCreator, titleBarReactViewCreator, topBarBackgroundViewController, topBarController, this::sendOnNavigationButtonPressed, getId());
266
+    public void sendOnNavigationButtonPressed(String buttonId) {
267
+        peek().sendOnNavigationButtonPressed(buttonId);
239 268
     }
240 269
 
241 270
     @NonNull

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

@@ -1,12 +1,12 @@
1 1
 package com.reactnativenavigation.viewcontrollers;
2 2
 
3
+import android.annotation.SuppressLint;
3 4
 import android.app.Activity;
4 5
 import android.graphics.Color;
5 6
 import android.graphics.drawable.Drawable;
6 7
 import android.support.annotation.NonNull;
7 8
 import android.support.v7.widget.ActionMenuView;
8 9
 import android.support.v7.widget.Toolbar;
9
-import android.util.Log;
10 10
 import android.view.MenuItem;
11 11
 import android.widget.ImageButton;
12 12
 import android.widget.TextView;
@@ -20,6 +20,7 @@ import com.reactnativenavigation.utils.ImageLoader;
20 20
 import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;
21 21
 import com.reactnativenavigation.utils.UiUtils;
22 22
 import com.reactnativenavigation.utils.ViewUtils;
23
+import com.reactnativenavigation.viewcontrollers.button.NavigationIconResolver;
23 24
 import com.reactnativenavigation.views.titlebar.TitleBarReactButtonView;
24 25
 
25 26
 import java.util.Collections;
@@ -30,6 +31,7 @@ public class TopBarButtonController extends ViewController<TitleBarReactButtonVi
30 31
         void onPress(String buttonId);
31 32
     }
32 33
 
34
+    private final NavigationIconResolver navigationIconResolver;
33 35
     private final ImageLoader imageLoader;
34 36
     private ButtonOptionsPresenter optionsPresenter;
35 37
     private final Button button;
@@ -37,8 +39,9 @@ public class TopBarButtonController extends ViewController<TitleBarReactButtonVi
37 39
     private TopBarButtonController.OnClickListener onPressListener;
38 40
     private Drawable icon;
39 41
 
40
-    public TopBarButtonController(Activity activity, ImageLoader imageLoader, ButtonOptionsPresenter optionsPresenter, Button button, ReactViewCreator viewCreator, OnClickListener onClickListener) {
42
+    public TopBarButtonController(Activity activity, NavigationIconResolver navigationIconResolver, ImageLoader imageLoader, ButtonOptionsPresenter optionsPresenter, Button button, ReactViewCreator viewCreator, OnClickListener onClickListener) {
41 43
         super(activity, button.id, new Options());
44
+        this.navigationIconResolver = navigationIconResolver;
42 45
         this.imageLoader = imageLoader;
43 46
         this.optionsPresenter = optionsPresenter;
44 47
         this.button = button;
@@ -46,11 +49,13 @@ public class TopBarButtonController extends ViewController<TitleBarReactButtonVi
46 49
         this.onPressListener = onClickListener;
47 50
     }
48 51
 
52
+    @SuppressLint("MissingSuperCall")
49 53
     @Override
50 54
     public void onViewAppeared() {
51 55
         view.sendComponentStart();
52 56
     }
53 57
 
58
+    @SuppressLint("MissingSuperCall")
54 59
     @Override
55 60
     public void onViewDisappear() {
56 61
         view.sendComponentStop();
@@ -75,25 +80,11 @@ public class TopBarButtonController extends ViewController<TitleBarReactButtonVi
75 80
     }
76 81
 
77 82
     public void applyNavigationIcon(Toolbar toolbar) {
78
-        if (!button.hasIcon()) {
79
-            Log.w("RNN", "Left button needs to have an icon");
80
-            return;
81
-        }
82
-
83
-        imageLoader.loadIcons(toolbar.getContext(), Collections.singletonList(button.icon.get()), new ImageLoader.ImagesLoadingListener() {
84
-            @Override
85
-            public void onComplete(@NonNull List<Drawable> drawables) {
86
-                icon = drawables.get(0);
87
-                setIconColor(icon);
88
-                toolbar.setNavigationOnClickListener(view -> onPressListener.onPress(button.id));
89
-                toolbar.setNavigationIcon(icon);
90
-                setLeftButtonTestId(toolbar);
91
-            }
92
-
93
-            @Override
94
-            public void onError(Throwable error) {
95
-                error.printStackTrace();
96
-            }
83
+        navigationIconResolver.resolve(button, icon -> {
84
+            setIconColor(icon);
85
+            toolbar.setNavigationOnClickListener(view -> onPressListener.onPress(button.id));
86
+            toolbar.setNavigationIcon(icon);
87
+            setLeftButtonTestId(toolbar);
97 88
         });
98 89
     }
99 90
 

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java View File

@@ -15,6 +15,7 @@ import com.reactnativenavigation.presentation.BottomTabsOptionsPresenter;
15 15
 import com.reactnativenavigation.react.EventEmitter;
16 16
 import com.reactnativenavigation.utils.CommandListener;
17 17
 import com.reactnativenavigation.utils.ImageLoader;
18
+import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;
18 19
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
19 20
 import com.reactnativenavigation.viewcontrollers.ParentController;
20 21
 import com.reactnativenavigation.viewcontrollers.ViewController;
@@ -124,7 +125,7 @@ public class BottomTabsController extends ParentController implements AHBottomNa
124 125
             icons.add(tabOptions.icon.get());
125 126
         }
126 127
 
127
-        imageLoader.loadIcons(getActivity(), icons, new ImageLoader.ImagesLoadingListener() {
128
+        imageLoader.loadIcons(getActivity(), icons, new ImageLoadingListenerAdapter() {
128 129
 
129 130
             @Override
130 131
             public void onComplete(@NonNull List<Drawable> drawables) {

+ 44
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/button/NavigationIconResolver.java View File

@@ -0,0 +1,44 @@
1
+package com.reactnativenavigation.viewcontrollers.button;
2
+
3
+import android.content.Context;
4
+import android.graphics.drawable.Drawable;
5
+import android.support.annotation.NonNull;
6
+import android.support.v4.content.ContextCompat;
7
+
8
+import com.reactnativenavigation.R;
9
+import com.reactnativenavigation.parse.params.Button;
10
+import com.reactnativenavigation.react.Constants;
11
+import com.reactnativenavigation.utils.ImageLoader;
12
+import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;
13
+import com.reactnativenavigation.utils.Task;
14
+
15
+public class NavigationIconResolver {
16
+
17
+    private Context context;
18
+    private ImageLoader imageLoader;
19
+
20
+    public NavigationIconResolver(Context context, ImageLoader imageLoader) {
21
+        this.context = context;
22
+        this.imageLoader = imageLoader;
23
+    }
24
+
25
+    public void resolve(Button button, Task<Drawable> onSuccess) {
26
+        if (button.icon.hasValue()) {
27
+            imageLoader.loadIcon(context, button.icon.get(), new ImageLoadingListenerAdapter() {
28
+                @Override
29
+                public void onComplete(@NonNull Drawable icon) {
30
+                    onSuccess.run(icon);
31
+                }
32
+
33
+                @Override
34
+                public void onError(Throwable error) {
35
+                    throw new RuntimeException(error);
36
+                }
37
+            });
38
+        } else if (Constants.BACK_BUTTON_ID.equals(button.id)) {
39
+            onSuccess.run(ContextCompat.getDrawable(context, R.drawable.ic_arrow_back_black_24dp));
40
+        } else {
41
+            throw new RuntimeException("Left button needs to have an icon");
42
+        }
43
+    }
44
+}

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/Fab.java View File

@@ -9,6 +9,7 @@ import com.reactnativenavigation.anim.FabAnimator;
9 9
 import com.reactnativenavigation.anim.FabCollapseBehaviour;
10 10
 import com.reactnativenavigation.interfaces.ScrollEventListener;
11 11
 import com.reactnativenavigation.utils.ImageLoader;
12
+import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;
12 13
 
13 14
 import java.util.Collections;
14 15
 import java.util.List;
@@ -26,7 +27,7 @@ public class Fab extends FloatingActionButton implements FabAnimator {
26 27
     }
27 28
 
28 29
     public void applyIcon(String icon) {
29
-        new ImageLoader().loadIcons(getContext(), Collections.singletonList(icon), new ImageLoader.ImagesLoadingListener() {
30
+        new ImageLoader().loadIcons(getContext(), Collections.singletonList(icon), new ImageLoadingListenerAdapter() {
30 31
             @Override
31 32
             public void onComplete(@NonNull List<Drawable> drawables) {
32 33
                 setImageDrawable(drawables.get(0));

+ 10
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/titlebar/TitleBar.java View File

@@ -20,6 +20,7 @@ import com.reactnativenavigation.utils.ViewUtils;
20 20
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
21 21
 import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
22 22
 import com.reactnativenavigation.viewcontrollers.TopBarButtonController;
23
+import com.reactnativenavigation.viewcontrollers.button.NavigationIconResolver;
23 24
 
24 25
 import java.util.ArrayList;
25 26
 import java.util.List;
@@ -194,7 +195,15 @@ public class TitleBar extends Toolbar {
194 195
     }
195 196
 
196 197
     public TopBarButtonController createButtonController(Button button) {
197
-        return new TopBarButtonController((Activity) getContext(), new ImageLoader(), new ButtonOptionsPresenter(this, button), button, buttonCreator, onClickListener);
198
+        ImageLoader imageLoader = new ImageLoader();
199
+        return new TopBarButtonController((Activity) getContext(),
200
+                new NavigationIconResolver(getContext(), imageLoader),
201
+                imageLoader,
202
+                new ButtonOptionsPresenter(this, button),
203
+                button,
204
+                buttonCreator,
205
+                onClickListener
206
+        );
198 207
     }
199 208
 
200 209
     public Toolbar.LayoutParams getComponentLayoutParams(Component component) {

+ 9
- 0
lib/android/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml View File

@@ -0,0 +1,9 @@
1
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+        android:width="24dp"
3
+        android:height="24dp"
4
+        android:viewportWidth="24.0"
5
+        android:viewportHeight="24.0">
6
+    <path
7
+        android:fillColor="#FF000000"
8
+        android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
9
+</vector>

+ 8
- 1
lib/android/app/src/test/java/com/reactnativenavigation/mocks/ImageLoaderMock.java View File

@@ -9,6 +9,7 @@ import com.reactnativenavigation.utils.ImageLoader;
9 9
 
10 10
 import org.mockito.Mockito;
11 11
 
12
+import java.util.Collection;
12 13
 import java.util.Collections;
13 14
 import java.util.List;
14 15
 
@@ -42,12 +43,18 @@ public class ImageLoaderMock {
42 43
         ImageLoader imageLoader = Mockito.mock(ImageLoader.class);
43 44
         doAnswer(
44 45
                 invocation -> {
45
-                    int urlCount = ((List) invocation.getArguments()[1]).size();
46
+                    int urlCount = ((Collection) invocation.getArguments()[1]).size();
46 47
                     List<Drawable> drawables = Collections.nCopies(urlCount, mockDrawable);
47 48
                     ((ImageLoader.ImagesLoadingListener) invocation.getArguments()[2]).onComplete(drawables);
48 49
                     return null;
49 50
                 }
50 51
         ).when(imageLoader).loadIcons(any(), any(), any());
52
+        doAnswer(
53
+                invocation -> {
54
+                    ((ImageLoader.ImagesLoadingListener) invocation.getArguments()[2]).onComplete(mockDrawable);
55
+                    return null;
56
+                }
57
+        ).when(imageLoader).loadIcon(any(), any(), any());
51 58
         return imageLoader;
52 59
     }
53 60
 }

+ 3
- 0
lib/android/app/src/test/java/com/reactnativenavigation/utils/OptionHelper.java View File

@@ -3,9 +3,12 @@ package com.reactnativenavigation.utils;
3 3
 import com.reactnativenavigation.parse.Options;
4 4
 import com.reactnativenavigation.parse.params.Text;
5 5
 
6
+import java.util.ArrayList;
7
+
6 8
 public class OptionHelper {
7 9
     public static Options createBottomTabOptions() {
8 10
         Options options = new Options();
11
+        options.topBar.leftButtons = new ArrayList<>();
9 12
         options.bottomTabOptions.title = new Text("Tab");
10 13
         options.bottomTabOptions.icon = new Text("http://127.0.0.1/icon.png");
11 14
         return options;

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

@@ -13,6 +13,7 @@ import com.reactnativenavigation.mocks.TopBarButtonCreatorMock;
13 13
 import com.reactnativenavigation.parse.NestedAnimationsOptions;
14 14
 import com.reactnativenavigation.parse.Options;
15 15
 import com.reactnativenavigation.parse.params.Bool;
16
+import com.reactnativenavigation.parse.params.Button;
16 17
 import com.reactnativenavigation.parse.params.Text;
17 18
 import com.reactnativenavigation.utils.CommandListenerAdapter;
18 19
 import com.reactnativenavigation.utils.ViewHelper;
@@ -30,6 +31,9 @@ import org.junit.Test;
30 31
 import org.mockito.ArgumentCaptor;
31 32
 import org.mockito.Mockito;
32 33
 
34
+import java.util.ArrayList;
35
+import java.util.Collections;
36
+
33 37
 import static org.assertj.core.api.Java6Assertions.assertThat;
34 38
 import static org.mockito.ArgumentMatchers.any;
35 39
 import static org.mockito.ArgumentMatchers.eq;
@@ -87,6 +91,36 @@ public class StackControllerTest extends BaseTest {
87 91
         verify(listener, times(1)).onSuccess(child1.getId());
88 92
     }
89 93
 
94
+    @Test
95
+    public void push_backButtonIsAddedIfStackContainsMoreThenOneScreen() {
96
+        uut.push(child1, new CommandListenerAdapter());
97
+        verify(child1, times(0)).mergeOptions(any());
98
+
99
+        uut.push(child2, new CommandListenerAdapter());
100
+        ArgumentCaptor<Options> captor = ArgumentCaptor.forClass(Options.class);
101
+        verify(child2, times(1)).mergeOptions(captor.capture());
102
+        assertThat(captor.getValue().topBar.leftButtons).isNotNull();
103
+        assertThat(captor.getValue().topBar.leftButtons.get(0).id).isEqualTo("RNN.back");
104
+    }
105
+
106
+    @Test
107
+    public void push_backButtonIsNotAddedIfScreenContainsLeftButtons() {
108
+        uut.push(child1, new CommandListenerAdapter());
109
+
110
+        Button leftButton = new Button();
111
+        leftButton.id = "someButton";
112
+        child2.options.topBar.leftButtons = new ArrayList<>(Collections.singleton(leftButton));
113
+        uut.push(child2, new CommandListenerAdapter());
114
+        verify(child2, times(0)).mergeOptions(any());
115
+    }
116
+
117
+    @Test
118
+    public void push_backButtonIsNotAddedIfScreenClearsLeftButton() {
119
+        child1.options.topBar.leftButtons = new ArrayList<>();
120
+        uut.push(child1, new CommandListenerAdapter());
121
+        verify(child1, times(0)).mergeOptions(any());
122
+    }
123
+
90 124
     @Test
91 125
     public void animateSetRoot() {
92 126
         assertThat(uut.isEmpty()).isTrue();
@@ -105,10 +139,12 @@ public class StackControllerTest extends BaseTest {
105 139
         assertThat(uut.isEmpty()).isTrue();
106 140
         uut.push(child1, new CommandListenerAdapter());
107 141
         uut.push(child2, new CommandListenerAdapter());
142
+        assertThat(uut.getTopBar().getTitleBar().getNavigationIcon()).isNotNull();
108 143
         uut.setRoot(child3, new CommandListenerAdapter() {
109 144
             @Override
110 145
             public void onSuccess(String childId) {
111 146
                 assertContainsOnlyId(child3.getId());
147
+                assertThat(uut.getTopBar().getTitleBar().getNavigationIcon()).isNull();
112 148
             }
113 149
         });
114 150
     }
@@ -141,8 +177,7 @@ public class StackControllerTest extends BaseTest {
141 177
     @Test
142 178
     public void pop_layoutHandlesChildWillDisappear() {
143 179
         final StackLayout[] stackLayout = new StackLayout[1];
144
-        uut =
145
-                new StackControllerBuilder(activity)
180
+        uut = new StackControllerBuilder(activity)
146 181
                         .setTopBarButtonCreator(new TopBarButtonCreatorMock())
147 182
                         .setTitleBarReactViewCreator(new TitleBarReactViewCreatorMock())
148 183
                         .setTopBarBackgroundViewController(new TopBarBackgroundViewController(activity, new TopBarBackgroundViewCreatorMock()))
@@ -722,13 +757,7 @@ public class StackControllerTest extends BaseTest {
722 757
     }
723 758
 
724 759
     private StackController createStackController(String id) {
725
-        topBarController = spy(new TopBarController() {
726
-            @Override
727
-            protected TopBar createTopBar(Context context, ReactViewCreator buttonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarBackgroundViewController topBarBackgroundViewController, TopBarButtonController.OnClickListener topBarButtonClickListener, StackLayout stackLayout) {
728
-                TopBar topBar = spy(super.createTopBar(context, buttonCreator, titleBarReactViewCreator, topBarBackgroundViewController, topBarButtonClickListener, stackLayout));
729
-                return topBar;
730
-            }
731
-        });
760
+        createTopBarController();
732 761
         return new StackControllerBuilder(activity)
733 762
                 .setChildRegistry(childRegistry)
734 763
                 .setTopBarButtonCreator(new TopBarButtonCreatorMock())
@@ -740,4 +769,13 @@ public class StackControllerTest extends BaseTest {
740 769
                 .setInitialOptions(new Options())
741 770
                 .createStackController();
742 771
     }
772
+
773
+    private void createTopBarController() {
774
+        topBarController = spy(new TopBarController() {
775
+            @Override
776
+            protected TopBar createTopBar(Context context, ReactViewCreator buttonCreator, TitleBarReactViewCreator titleBarReactViewCreator, TopBarBackgroundViewController topBarBackgroundViewController, TopBarButtonController.OnClickListener topBarButtonClickListener, StackLayout stackLayout) {
777
+                return spy(super.createTopBar(context, buttonCreator, titleBarReactViewCreator, topBarBackgroundViewController, topBarButtonClickListener, stackLayout));
778
+            }
779
+        });
780
+    }
743 781
 }

+ 2
- 3
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TitleBarTest.java View File

@@ -12,6 +12,7 @@ import com.reactnativenavigation.parse.Alignment;
12 12
 import com.reactnativenavigation.parse.Component;
13 13
 import com.reactnativenavigation.parse.params.Button;
14 14
 import com.reactnativenavigation.parse.params.Text;
15
+import com.reactnativenavigation.react.Constants;
15 16
 import com.reactnativenavigation.react.ReactView;
16 17
 import com.reactnativenavigation.utils.ViewUtils;
17 18
 import com.reactnativenavigation.views.titlebar.TitleBar;
@@ -60,8 +61,7 @@ public class TitleBarTest extends BaseTest {
60 61
 
61 62
     private void createButtons() {
62 63
         leftButton = new Button();
63
-        leftButton.id = "back";
64
-        leftButton.title = new Text("abc");
64
+        leftButton.id = Constants.BACK_BUTTON_ID;
65 65
 
66 66
         textButton = new Button();
67 67
         textButton.id = "textButton";
@@ -100,7 +100,6 @@ public class TitleBarTest extends BaseTest {
100 100
 
101 101
     @Test
102 102
     public void setRightButtons_destroysRightButtons() {
103
-        uut.setLeftButtons(leftButton(leftButton));
104 103
         uut.setRightButtons(rightButtons(customButton));
105 104
         uut.setLeftButtons(leftButton(leftButton));
106 105
         uut.setRightButtons(rightButtons(textButton));

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopBarButtonControllerTest.java View File

@@ -18,6 +18,7 @@ import com.reactnativenavigation.parse.params.NullText;
18 18
 import com.reactnativenavigation.parse.params.Number;
19 19
 import com.reactnativenavigation.parse.params.Text;
20 20
 import com.reactnativenavigation.utils.ButtonOptionsPresenter;
21
+import com.reactnativenavigation.viewcontrollers.button.NavigationIconResolver;
21 22
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarBackgroundViewController;
22 23
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
23 24
 
@@ -58,7 +59,7 @@ public class TopBarButtonControllerTest extends BaseTest {
58 59
         getTitleBar().layout(0, 0, 1080, 200);
59 60
 
60 61
         optionsPresenter = spy(new ButtonOptionsPresenter(getTitleBar(), button));
61
-        uut = new TopBarButtonController(activity, ImageLoaderMock.mock(), optionsPresenter, button, buttonCreatorMock, (buttonId) -> {});
62
+        uut = new TopBarButtonController(activity, new NavigationIconResolver(activity, ImageLoaderMock.mock()), ImageLoaderMock.mock(), optionsPresenter, button, buttonCreatorMock, (buttonId) -> {});
62 63
 
63 64
         stackController.ensureViewIsCreated();
64 65
     }

+ 75
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/button/NavigationIconResolverTest.java View File

@@ -0,0 +1,75 @@
1
+package com.reactnativenavigation.viewcontrollers.button;
2
+
3
+import android.content.Context;
4
+import android.graphics.drawable.Drawable;
5
+
6
+import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.mocks.ImageLoaderMock;
8
+import com.reactnativenavigation.parse.params.Button;
9
+import com.reactnativenavigation.parse.params.Color;
10
+import com.reactnativenavigation.parse.params.Text;
11
+import com.reactnativenavigation.react.Constants;
12
+import com.reactnativenavigation.utils.ImageLoader;
13
+import com.reactnativenavigation.utils.Task;
14
+
15
+import org.junit.Test;
16
+
17
+import static org.mockito.ArgumentMatchers.any;
18
+import static org.mockito.ArgumentMatchers.eq;
19
+import static org.mockito.Mockito.spy;
20
+import static org.mockito.Mockito.verify;
21
+import static org.mockito.Mockito.verifyZeroInteractions;
22
+
23
+public class NavigationIconResolverTest extends BaseTest {
24
+    private static final String ICON_URI = "someIconUri";
25
+    private NavigationIconResolver uut;
26
+    private ImageLoader imageLoader;
27
+    private Context context;
28
+
29
+    @Override
30
+    public void beforeEach() {
31
+        imageLoader = ImageLoaderMock.mock();
32
+        context = newActivity();
33
+        uut = new NavigationIconResolver(context, imageLoader);
34
+    }
35
+
36
+    @Test
37
+    public void create_iconButton() {
38
+        @SuppressWarnings("Convert2Lambda") Task<Drawable> onSuccess = spy(new Task<Drawable>() {
39
+            @Override
40
+            public void run(Drawable icon) {
41
+
42
+            }
43
+        });
44
+        uut.resolve(iconButton(), onSuccess);
45
+        verify(imageLoader).loadIcon(eq(context), eq(ICON_URI), any());
46
+        verify(onSuccess).run(any(Drawable.class));
47
+    }
48
+
49
+    @Test
50
+    public void create_backButton() {
51
+        @SuppressWarnings("Convert2Lambda") Task<Drawable> onSuccess = spy(new Task<Drawable>() {
52
+            @Override
53
+            public void run(Drawable param) {
54
+
55
+            }
56
+        });
57
+        uut.resolve(backButton(), onSuccess);
58
+        verifyZeroInteractions(imageLoader);
59
+        verify(onSuccess).run(any());
60
+    }
61
+
62
+    private Button iconButton() {
63
+        Button button = new Button();
64
+        button.id = "iconBtnId";
65
+        button.icon = new Text(ICON_URI);
66
+        button.color = new Color(android.graphics.Color.RED);
67
+        return button;
68
+    }
69
+
70
+    private Button backButton() {
71
+        Button button = new Button();
72
+        button.id = Constants.BACK_BUTTON_ID;
73
+        return button;
74
+    }
75
+}