Browse Source

Implement images loader (#3152)

* Implementation of passing multiple arguments to ImageLoader in order to avoid asynchronous issues and for performance as BottomBar re-creates all views every time an item is added

* removed redundant checks for testId

* Implementation of passing multiple arguments to ImageLoader in order to avoid asynchronous issues and for performance as BottomBar re-creates all views every time an item is added

* removed redundant checks for testId
andresesfm 6 years ago
parent
commit
9bef6f1822

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

@@ -18,21 +18,28 @@ import java.io.FileNotFoundException;
18 18
 import java.io.IOException;
19 19
 import java.io.InputStream;
20 20
 import java.net.URL;
21
+import java.util.ArrayList;
22
+import java.util.List;
21 23
 
22 24
 public class ImageLoader {
23 25
 
24
-    public interface ImageLoadingListener {
25
-        void onComplete(@NonNull Drawable drawable);
26
+    public interface ImagesLoadingListener {
27
+        void onComplete(@NonNull List<Drawable> drawable);
26 28
 
27 29
         void onError(Throwable error);
28 30
     }
29 31
 
30 32
     private static final String FILE_SCHEME = "file";
31 33
 
32
-    public void loadIcon(final Context context, final String uri, final ImageLoadingListener listener) {
34
+
35
+    public void loadIcons(final Context context, List<String> uris, ImagesLoadingListener listener) {
33 36
         try {
34
-            Drawable drawable = getDrawable(context, uri);
35
-            listener.onComplete(drawable);
37
+            List<Drawable> drawables = new ArrayList<>();
38
+            for (String uri : uris) {
39
+                Drawable drawable = getDrawable(context, uri);
40
+                drawables.add(drawable);
41
+            }
42
+            listener.onComplete(drawables);
36 43
         } catch (IOException e) {
37 44
             listener.onError(e);
38 45
         }

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

@@ -3,9 +3,11 @@ package com.reactnativenavigation.utils;
3 3
 import android.graphics.drawable.Drawable;
4 4
 import android.support.annotation.NonNull;
5 5
 
6
-public class ImageLoadingListenerAdapter implements ImageLoader.ImageLoadingListener {
6
+import java.util.List;
7
+
8
+public class ImageLoadingListenerAdapter implements ImageLoader.ImagesLoadingListener {
7 9
     @Override
8
-    public void onComplete(@NonNull Drawable drawable) {
10
+    public void onComplete(@NonNull List<Drawable> drawables) {
9 11
 
10 12
     }
11 13
 

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

@@ -25,6 +25,7 @@ public class NoOpPromise implements Promise {
25 25
 
26 26
     }
27 27
 
28
+    @Deprecated
28 29
     @Override
29 30
     public void reject(String message) {
30 31
 

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

@@ -22,6 +22,7 @@ import com.reactnativenavigation.utils.UiUtils;
22 22
 import com.reactnativenavigation.utils.ViewUtils;
23 23
 import com.reactnativenavigation.views.titlebar.TitleBarReactButtonView;
24 24
 
25
+import java.util.Collections;
25 26
 import java.util.List;
26 27
 
27 28
 public class TopBarButtonController extends ViewController<TitleBarReactButtonView> implements MenuItem.OnMenuItemClickListener {
@@ -79,11 +80,11 @@ public class TopBarButtonController extends ViewController<TitleBarReactButtonVi
79 80
             return;
80 81
         }
81 82
 
82
-        imageLoader.loadIcon(toolbar.getContext(), button.icon.get(), new ImageLoader.ImageLoadingListener() {
83
+        imageLoader.loadIcons(toolbar.getContext(), Collections.singletonList(button.icon.get()), new ImageLoader.ImagesLoadingListener() {
83 84
             @Override
84
-            public void onComplete(@NonNull Drawable drawable) {
85
-                icon = drawable;
86
-                setIconColor(drawable);
85
+            public void onComplete(@NonNull List<Drawable> drawables) {
86
+                icon = drawables.get(0);
87
+                setIconColor(icon);
87 88
                 toolbar.setNavigationOnClickListener(view -> onPressListener.onPress(button.id));
88 89
                 toolbar.setNavigationIcon(icon);
89 90
                 setLeftButtonTestId(toolbar);
@@ -117,7 +118,8 @@ public class TopBarButtonController extends ViewController<TitleBarReactButtonVi
117 118
             if (button.hasIcon()) {
118 119
                 loadIcon(new ImageLoadingListenerAdapter() {
119 120
                     @Override
120
-                    public void onComplete(@NonNull Drawable icon) {
121
+                    public void onComplete(@NonNull List<Drawable> icons) {
122
+                        Drawable icon = icons.get(0);
121 123
                         TopBarButtonController.this.icon = icon;
122 124
                         setIconColor(icon);
123 125
                         menuItem.setIcon(icon);
@@ -132,8 +134,8 @@ public class TopBarButtonController extends ViewController<TitleBarReactButtonVi
132 134
         setTestId(toolbar, button.testId);
133 135
     }
134 136
 
135
-    private void loadIcon(ImageLoader.ImageLoadingListener callbacks) {
136
-        imageLoader.loadIcon(getActivity(), button.icon.get(), callbacks);
137
+    private void loadIcon(ImageLoader.ImagesLoadingListener callback) {
138
+        imageLoader.loadIcons(getActivity(), Collections.singletonList(button.icon.get()), callback);
137 139
     }
138 140
 
139 141
     private void setIconColor(Drawable icon) {

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

@@ -111,23 +111,33 @@ public class BottomTabsController extends ParentController implements AHBottomNa
111 111
 		this.tabs = tabs;
112 112
         bottomTabFinder.setTabs(tabs);
113 113
         getView();
114
-		for (int i = 0; i < tabs.size(); i++) {
115
-		    tabs.get(i).setParentController(this);
116
-			createTab(i, tabs.get(i).options.bottomTabOptions);
117
-		}
118
-		selectTab(0);
119
-	}
120
-
121
-	private void createTab(int index, final BottomTabOptions tabOptions) {
122
-	    if (!tabOptions.icon.hasValue()) {
123
-            throw new RuntimeException("BottomTab must have an icon");
114
+        List<String> icons = new ArrayList<>();
115
+        List<BottomTabOptions> bottomTabOptionsList = new ArrayList<>();
116
+        for (int i = 0; i < tabs.size(); i++) {
117
+            tabs.get(i).setParentController(this);
118
+            BottomTabOptions tabOptions = tabs.get(i).options.bottomTabOptions;
119
+            if (!tabOptions.icon.hasValue()) {
120
+                throw new RuntimeException("BottomTab must have an icon");
121
+            }
122
+            bottomTabOptionsList.add(tabOptions);
123
+            icons.add(tabOptions.icon.get());
124 124
         }
125
-        imageLoader.loadIcon(getActivity(), tabOptions.icon.get(), new ImageLoader.ImageLoadingListener() {
125
+
126
+        imageLoader.loadIcons(getActivity(), icons, new ImageLoader.ImagesLoadingListener() {
127
+
126 128
             @Override
127
-            public void onComplete(@NonNull Drawable drawable) {
128
-                AHBottomNavigationItem item = new AHBottomNavigationItem(tabOptions.title.get(""), drawable);
129
-                bottomTabs.addItem(item);
130
-                bottomTabs.post(() -> bottomTabs.setTabTag(index, tabOptions.testId));
129
+            public void onComplete(@NonNull List<Drawable> drawables) {
130
+                List<AHBottomNavigationItem> tabs = new ArrayList<>();
131
+                for (int i = 0; i < drawables.size(); i++) {
132
+                    AHBottomNavigationItem tab = createTab(bottomTabOptionsList.get(i), drawables.get(i));
133
+                    tabs.add(tab);
134
+
135
+                }
136
+                bottomTabs.addItems(tabs);
137
+                for (int i = 0; i < bottomTabOptionsList.size(); i++) {
138
+                    bottomTabs.setTabTag(i, bottomTabOptionsList.get(i).testId);
139
+                }
140
+                selectTab(0);
131 141
             }
132 142
 
133 143
             @Override
@@ -135,6 +145,12 @@ public class BottomTabsController extends ParentController implements AHBottomNa
135 145
                 error.printStackTrace();
136 146
             }
137 147
         });
148
+
149
+	}
150
+
151
+	private AHBottomNavigationItem createTab(final BottomTabOptions tabOptions, Drawable drawable) {
152
+        return  new AHBottomNavigationItem(tabOptions.title.get(""), drawable);
153
+
138 154
 	}
139 155
 
140 156
     public int getSelectedIndex() {

+ 5
- 3
lib/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java View File

@@ -3,6 +3,7 @@ package com.reactnativenavigation.views;
3 3
 import android.annotation.SuppressLint;
4 4
 import android.content.Context;
5 5
 import android.support.annotation.IntRange;
6
+import android.view.View;
6 7
 
7 8
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
8 9
 import com.reactnativenavigation.parse.params.Text;
@@ -17,9 +18,10 @@ public class BottomTabs extends AHBottomNavigation {
17 18
     }
18 19
 
19 20
     public void setTabTag(int index, Text testId) {
20
-        if (!testId.hasValue()) return;
21
-        if (testId.hasValue()) getViewAtPosition(index).setTag(testId.get());
22
-        if (testId.hasValue()) getViewAtPosition(index).setContentDescription(testId.get());
21
+        View view = getViewAtPosition(index);
22
+        if (!testId.hasValue() || view == null) return;
23
+        view.setTag(testId.get());
24
+        view.setContentDescription(testId.get());
23 25
     }
24 26
 
25 27
     public void setBadge(int bottomTabIndex, Text badge) {

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

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

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

@@ -9,8 +9,10 @@ import com.reactnativenavigation.utils.ImageLoader;
9 9
 
10 10
 import org.mockito.Mockito;
11 11
 
12
+import java.util.Collections;
13
+import java.util.List;
14
+
12 15
 import static org.mockito.ArgumentMatchers.any;
13
-import static org.mockito.ArgumentMatchers.anyString;
14 16
 import static org.mockito.Mockito.doAnswer;
15 17
 
16 18
 public class ImageLoaderMock {
@@ -40,10 +42,12 @@ public class ImageLoaderMock {
40 42
         ImageLoader imageLoader = Mockito.mock(ImageLoader.class);
41 43
         doAnswer(
42 44
                 invocation -> {
43
-                    ((ImageLoader.ImageLoadingListener) invocation.getArguments()[2]).onComplete(mockDrawable);
45
+                    int urlCount = ((List) invocation.getArguments()[1]).size();
46
+                    List<Drawable> drawables = Collections.nCopies(urlCount, mockDrawable);
47
+                    ((ImageLoader.ImagesLoadingListener) invocation.getArguments()[2]).onComplete(drawables);
44 48
                     return null;
45 49
                 }
46
-        ).when(imageLoader).loadIcon(any(), anyString(), any());
50
+        ).when(imageLoader).loadIcons(any(), any(), any());
47 51
         return imageLoader;
48 52
     }
49 53
 }