[Android] Refactor multi-selection in browsers

Geoffrey Métais git at videolan.org
Thu Sep 6 16:45:42 CEST 2018


vlc-android | branch: master | Geoffrey Métais <geoffrey.metais at gmail.com> | Thu Sep  6 16:45:11 2018 +0200| [c271b062e702f536eb54f7c843f60dae0df45306] | committer: Geoffrey Métais

Refactor multi-selection in browsers

> https://code.videolan.org/videolan/vlc-android/commit/c271b062e702f536eb54f7c843f60dae0df45306
---

 .../vlc/gui/browser/BaseBrowserAdapter.java        | 49 +++++++---------------
 .../vlc/gui/browser/BaseBrowserFragment.kt         | 26 ++++--------
 2 files changed, 23 insertions(+), 52 deletions(-)

diff --git a/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserAdapter.java b/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserAdapter.java
index 2ab011170..d529396d2 100644
--- a/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserAdapter.java
+++ b/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserAdapter.java
@@ -37,6 +37,8 @@ import org.videolan.libvlc.util.AndroidUtil;
 import org.videolan.medialibrary.media.MediaLibraryItem;
 import org.videolan.medialibrary.media.MediaWrapper;
 import org.videolan.medialibrary.media.Storage;
+import org.videolan.tools.MultiSelectAdapter;
+import org.videolan.tools.MultiSelectHelper;
 import org.videolan.vlc.R;
 import org.videolan.vlc.VLCApplication;
 import org.videolan.vlc.databinding.BrowserItemBinding;
@@ -44,6 +46,7 @@ import org.videolan.vlc.databinding.BrowserItemSeparatorBinding;
 import org.videolan.vlc.gui.DiffUtilAdapter;
 import org.videolan.vlc.gui.helpers.SelectorViewHolder;
 import org.videolan.vlc.util.AndroidDevices;
+import org.videolan.vlc.util.Constants;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -52,11 +55,13 @@ import static org.videolan.medialibrary.media.MediaLibraryItem.FLAG_SELECTED;
 import static org.videolan.medialibrary.media.MediaLibraryItem.TYPE_MEDIA;
 import static org.videolan.medialibrary.media.MediaLibraryItem.TYPE_STORAGE;
 
-public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBrowserAdapter.ViewHolder> {
+public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBrowserAdapter.ViewHolder> implements MultiSelectAdapter<MediaLibraryItem> {
     protected static final String TAG = "VLC/BaseBrowserAdapter";
 
     private static int FOLDER_RES_ID = R.drawable.ic_menu_folder;
 
+    private MultiSelectHelper<MediaLibraryItem> multiSelectHelper;
+
     private static class Images {
         private static final BitmapDrawable IMAGE_FOLDER = new BitmapDrawable(VLCApplication.getAppResources(), BitmapFactory.decodeResource(VLCApplication.getAppResources(), FOLDER_RES_ID));
         private static final BitmapDrawable IMAGE_AUDIO = new BitmapDrawable(VLCApplication.getAppResources(), BitmapFactory.decodeResource(VLCApplication.getAppResources(), R.drawable.ic_browser_audio_normal));
@@ -69,11 +74,12 @@ public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBr
         private static final BitmapDrawable IMAGE_QA_DOWNLOAD = new BitmapDrawable(VLCApplication.getAppResources(), BitmapFactory.decodeResource(VLCApplication.getAppResources(), R.drawable.ic_browser_download_normal));
     }
     protected final BaseBrowserFragment fragment;
-    private int mMediaCount = 0, mSelectionCount = 0;
+    private int mMediaCount = 0;
     private final boolean mNetworkRoot, mSpecialIcons;
 
     BaseBrowserAdapter(BaseBrowserFragment fragment) {
         this.fragment = fragment;
+        multiSelectHelper = new MultiSelectHelper<>(this, Constants.UPDATE_SELECTION);
         final boolean root = fragment.isRootDirectory();
         final boolean fileBrowser = fragment instanceof FileBrowserFragment;
         final boolean filesRoot = root && fileBrowser;
@@ -108,8 +114,10 @@ public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBr
         else if (payloads.get(0) instanceof CharSequence){
             ((MediaViewHolder) holder).binding.text.setVisibility(View.VISIBLE);
             ((MediaViewHolder) holder).binding.text.setText((CharSequence) payloads.get(0));
-        } else if (payloads.get(0) instanceof MediaWrapper)
-            holder.selectView(((MediaWrapper)payloads.get(0)).hasStateFlags(FLAG_SELECTED));
+        } else if (payloads.get(0) instanceof Integer) {
+            final int value = (Integer) payloads.get(0);
+            if (value == Constants.UPDATE_SELECTION) holder.selectView(multiSelectHelper.isSelected(position));
+        }
     }
 
     private void onBindMediaViewHolder(final MediaViewHolder vh, int position) {
@@ -121,7 +129,7 @@ public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBr
                 && !"otg".equals(media.getUri().getScheme()));
         if (mNetworkRoot) vh.binding.setProtocol(getProtocol(media));
         vh.binding.setCover(getIcon(media, mSpecialIcons));
-        vh.selectView(media.hasStateFlags(FLAG_SELECTED));
+        vh.selectView(multiSelectHelper.isSelected(position));
     }
 
     @Override
@@ -129,8 +137,8 @@ public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBr
         return getDataset().size();
     }
 
-    public MediaLibraryItem get(int position) {
-        return getDataset().get(position);
+    public MultiSelectHelper<MediaLibraryItem> getMultiSelectHelper() {
+        return multiSelectHelper;
     }
 
     public abstract class ViewHolder<T extends ViewDataBinding> extends SelectorViewHolder<T> {
@@ -207,8 +215,7 @@ public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBr
 
         @Override
         protected boolean isSelected() {
-            final MediaLibraryItem item = getItem(getLayoutPosition());
-            return item != null && item.hasStateFlags(FLAG_SELECTED);
+            return multiSelectHelper.isSelected(getLayoutPosition());
         }
     }
 
@@ -281,30 +288,6 @@ public class BaseBrowserAdapter extends DiffUtilAdapter<MediaLibraryItem, BaseBr
 
     protected void checkBoxAction(View v, String mrl){}
 
-    List<MediaWrapper> getSelection() {
-        List<MediaWrapper> selection = new ArrayList<>();
-        for (MediaLibraryItem item : getDataset()) {
-            if (item.hasStateFlags(FLAG_SELECTED))
-                selection.add((MediaWrapper) item);
-        }
-        return selection;
-    }
-
-    @MainThread
-    int getSelectionCount() {
-        return mSelectionCount;
-    }
-
-    @MainThread
-    void resetSelectionCount() {
-        mSelectionCount = 0;
-    }
-
-    @MainThread
-    void updateSelectionCount(boolean selected) {
-        mSelectionCount += selected ? 1 : -1;
-    }
-
     @SuppressWarnings("unchecked")
     @Override
     protected List<MediaLibraryItem> prepareList(List<? extends MediaLibraryItem> list) {
diff --git a/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt b/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
index 035b77752..486279c90 100644
--- a/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
+++ b/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
@@ -318,21 +318,21 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
     }
 
     override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
-        val count = adapter.selectionCount
+        val count = adapter.multiSelectHelper.getSelectionCount()
         if (count == 0) {
             stopActionMode()
             return false
         }
         val single = this is FileBrowserFragment && count == 1
-        val selection = if (single) adapter.selection else null
-        val type = if (!Util.isListEmpty(selection)) selection!![0].type else -1
+        val selection = if (single) adapter.multiSelectHelper.getSelection() else null
+        val type = if (!Util.isListEmpty(selection)) (selection!![0] as MediaWrapper).type else -1
         menu.findItem(R.id.action_mode_file_info).isVisible = single && (type == MediaWrapper.TYPE_AUDIO || type == MediaWrapper.TYPE_VIDEO)
         menu.findItem(R.id.action_mode_file_append).isVisible = PlaylistManager.hasMedia()
         return true
     }
 
     override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
-        val list = adapter.selection
+        val list = adapter.multiSelectHelper.getSelection() as? List<MediaWrapper> ?: return false
         if (!list.isEmpty()) {
             when (item.itemId) {
                 R.id.action_mode_file_play -> MediaUtils.openList(activity, list, 0)
@@ -351,15 +351,7 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
 
     override fun onDestroyActionMode(mode: ActionMode?) {
         mActionMode = null
-        var index = -1
-        for (media in adapter.all) {
-            ++index
-            if (media.hasStateFlags(MediaLibraryItem.FLAG_SELECTED)) {
-                media.removeStateFlags(MediaLibraryItem.FLAG_SELECTED)
-                adapter.notifyItemChanged(index, media)
-            }
-        }
-        adapter.resetSelectionCount()
+        adapter.multiSelectHelper.clearSelection()
     }
 
     override fun onOptionsItemSelected(item: MenuItem?): Boolean {
@@ -391,9 +383,7 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
             if (mediaWrapper.type == MediaWrapper.TYPE_AUDIO ||
                     mediaWrapper.type == MediaWrapper.TYPE_VIDEO ||
                     mediaWrapper.type == MediaWrapper.TYPE_DIR) {
-                item.toggleStateFlag(MediaLibraryItem.FLAG_SELECTED)
-                adapter.updateSelectionCount(mediaWrapper.hasStateFlags(MediaLibraryItem.FLAG_SELECTED))
-                adapter.notifyItemChanged(position, item)
+                adapter.multiSelectHelper.toggleSelection(position)
                 invalidateActionMode()
             }
         } else {
@@ -410,9 +400,7 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
                 mediaWrapper.type == MediaWrapper.TYPE_VIDEO ||
                 mediaWrapper.type == MediaWrapper.TYPE_DIR) {
             if (mActionMode != null) return false
-            item.addStateFlags(MediaLibraryItem.FLAG_SELECTED)
-            adapter.updateSelectionCount(mediaWrapper.hasStateFlags(MediaLibraryItem.FLAG_SELECTED))
-            adapter.notifyItemChanged(position, item)
+            adapter.multiSelectHelper.toggleSelection(position)
             startActionMode()
         } else onCtxClick(v, position, item)
         return true



More information about the Android mailing list