Parcourir la 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 il y a 6 ans
Parent
révision
9bef6f1822

+ 12
- 5
lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoader.java Voir le fichier

18
 import java.io.IOException;
18
 import java.io.IOException;
19
 import java.io.InputStream;
19
 import java.io.InputStream;
20
 import java.net.URL;
20
 import java.net.URL;
21
+import java.util.ArrayList;
22
+import java.util.List;
21
 
23
 
22
 public class ImageLoader {
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
         void onError(Throwable error);
29
         void onError(Throwable error);
28
     }
30
     }
29
 
31
 
30
     private static final String FILE_SCHEME = "file";
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
         try {
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
         } catch (IOException e) {
43
         } catch (IOException e) {
37
             listener.onError(e);
44
             listener.onError(e);
38
         }
45
         }

+ 4
- 2
lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoadingListenerAdapter.java Voir le fichier

3
 import android.graphics.drawable.Drawable;
3
 import android.graphics.drawable.Drawable;
4
 import android.support.annotation.NonNull;
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
     @Override
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 Voir le fichier

25
 
25
 
26
     }
26
     }
27
 
27
 
28
+    @Deprecated
28
     @Override
29
     @Override
29
     public void reject(String message) {
30
     public void reject(String message) {
30
 
31
 

+ 9
- 7
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TopBarButtonController.java Voir le fichier

22
 import com.reactnativenavigation.utils.ViewUtils;
22
 import com.reactnativenavigation.utils.ViewUtils;
23
 import com.reactnativenavigation.views.titlebar.TitleBarReactButtonView;
23
 import com.reactnativenavigation.views.titlebar.TitleBarReactButtonView;
24
 
24
 
25
+import java.util.Collections;
25
 import java.util.List;
26
 import java.util.List;
26
 
27
 
27
 public class TopBarButtonController extends ViewController<TitleBarReactButtonView> implements MenuItem.OnMenuItemClickListener {
28
 public class TopBarButtonController extends ViewController<TitleBarReactButtonView> implements MenuItem.OnMenuItemClickListener {
79
             return;
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
             @Override
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
                 toolbar.setNavigationOnClickListener(view -> onPressListener.onPress(button.id));
88
                 toolbar.setNavigationOnClickListener(view -> onPressListener.onPress(button.id));
88
                 toolbar.setNavigationIcon(icon);
89
                 toolbar.setNavigationIcon(icon);
89
                 setLeftButtonTestId(toolbar);
90
                 setLeftButtonTestId(toolbar);
117
             if (button.hasIcon()) {
118
             if (button.hasIcon()) {
118
                 loadIcon(new ImageLoadingListenerAdapter() {
119
                 loadIcon(new ImageLoadingListenerAdapter() {
119
                     @Override
120
                     @Override
120
-                    public void onComplete(@NonNull Drawable icon) {
121
+                    public void onComplete(@NonNull List<Drawable> icons) {
122
+                        Drawable icon = icons.get(0);
121
                         TopBarButtonController.this.icon = icon;
123
                         TopBarButtonController.this.icon = icon;
122
                         setIconColor(icon);
124
                         setIconColor(icon);
123
                         menuItem.setIcon(icon);
125
                         menuItem.setIcon(icon);
132
         setTestId(toolbar, button.testId);
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
     private void setIconColor(Drawable icon) {
141
     private void setIconColor(Drawable icon) {

+ 31
- 15
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java Voir le fichier

111
 		this.tabs = tabs;
111
 		this.tabs = tabs;
112
         bottomTabFinder.setTabs(tabs);
112
         bottomTabFinder.setTabs(tabs);
113
         getView();
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
             @Override
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
             @Override
143
             @Override
135
                 error.printStackTrace();
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
     public int getSelectedIndex() {
156
     public int getSelectedIndex() {

+ 5
- 3
lib/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java Voir le fichier

3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
 import android.support.annotation.IntRange;
5
 import android.support.annotation.IntRange;
6
+import android.view.View;
6
 
7
 
7
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
8
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
8
 import com.reactnativenavigation.parse.params.Text;
9
 import com.reactnativenavigation.parse.params.Text;
17
     }
18
     }
18
 
19
 
19
     public void setTabTag(int index, Text testId) {
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
     public void setBadge(int bottomTabIndex, Text badge) {
27
     public void setBadge(int bottomTabIndex, Text badge) {

+ 6
- 3
lib/android/app/src/main/java/com/reactnativenavigation/views/Fab.java Voir le fichier

10
 import com.reactnativenavigation.interfaces.ScrollEventListener;
10
 import com.reactnativenavigation.interfaces.ScrollEventListener;
11
 import com.reactnativenavigation.utils.ImageLoader;
11
 import com.reactnativenavigation.utils.ImageLoader;
12
 
12
 
13
+import java.util.Collections;
14
+import java.util.List;
15
+
13
 
16
 
14
 public class Fab extends FloatingActionButton implements FabAnimator {
17
 public class Fab extends FloatingActionButton implements FabAnimator {
15
 
18
 
23
     }
26
     }
24
 
27
 
25
     public void applyIcon(String icon) {
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
             @Override
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
             @Override
35
             @Override

+ 7
- 3
lib/android/app/src/test/java/com/reactnativenavigation/mocks/ImageLoaderMock.java Voir le fichier

9
 
9
 
10
 import org.mockito.Mockito;
10
 import org.mockito.Mockito;
11
 
11
 
12
+import java.util.Collections;
13
+import java.util.List;
14
+
12
 import static org.mockito.ArgumentMatchers.any;
15
 import static org.mockito.ArgumentMatchers.any;
13
-import static org.mockito.ArgumentMatchers.anyString;
14
 import static org.mockito.Mockito.doAnswer;
16
 import static org.mockito.Mockito.doAnswer;
15
 
17
 
16
 public class ImageLoaderMock {
18
 public class ImageLoaderMock {
40
         ImageLoader imageLoader = Mockito.mock(ImageLoader.class);
42
         ImageLoader imageLoader = Mockito.mock(ImageLoader.class);
41
         doAnswer(
43
         doAnswer(
42
                 invocation -> {
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
                     return null;
48
                     return null;
45
                 }
49
                 }
46
-        ).when(imageLoader).loadIcon(any(), anyString(), any());
50
+        ).when(imageLoader).loadIcons(any(), any(), any());
47
         return imageLoader;
51
         return imageLoader;
48
     }
52
     }
49
 }
53
 }