|
@@ -5,134 +5,123 @@
|
|
|
* SPDX-FileCopyrightText: 2016 Nextcloud
|
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
|
|
|
*/
|
|
|
-package com.owncloud.android.ui.adapter;
|
|
|
-
|
|
|
-import android.content.Context;
|
|
|
-import android.view.LayoutInflater;
|
|
|
-import android.view.MenuItem;
|
|
|
-import android.view.View;
|
|
|
-import android.view.ViewGroup;
|
|
|
-import android.widget.ImageButton;
|
|
|
-import android.widget.PopupMenu;
|
|
|
-
|
|
|
-import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter;
|
|
|
-import com.afollestad.sectionedrecyclerview.SectionedViewHolder;
|
|
|
-import com.nextcloud.client.core.Clock;
|
|
|
-import com.owncloud.android.R;
|
|
|
-import com.owncloud.android.databinding.GridSyncItemBinding;
|
|
|
-import com.owncloud.android.databinding.SyncedFoldersEmptyBinding;
|
|
|
-import com.owncloud.android.databinding.SyncedFoldersFooterBinding;
|
|
|
-import com.owncloud.android.databinding.SyncedFoldersItemHeaderBinding;
|
|
|
-import com.owncloud.android.datamodel.MediaFolderType;
|
|
|
-import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
|
|
|
-import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
|
|
-import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
|
-
|
|
|
-import java.io.File;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Locale;
|
|
|
-import java.util.concurrent.Executor;
|
|
|
-import java.util.concurrent.Executors;
|
|
|
-
|
|
|
-import androidx.annotation.NonNull;
|
|
|
-import androidx.annotation.VisibleForTesting;
|
|
|
+package com.owncloud.android.ui.adapter
|
|
|
+
|
|
|
+import android.annotation.SuppressLint
|
|
|
+import android.content.Context
|
|
|
+import android.view.LayoutInflater
|
|
|
+import android.view.MenuItem
|
|
|
+import android.view.View
|
|
|
+import android.view.ViewGroup
|
|
|
+import android.widget.ImageButton
|
|
|
+import android.widget.PopupMenu
|
|
|
+import androidx.annotation.VisibleForTesting
|
|
|
+import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter
|
|
|
+import com.afollestad.sectionedrecyclerview.SectionedViewHolder
|
|
|
+import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
|
|
+import com.nextcloud.client.core.Clock
|
|
|
+import com.owncloud.android.R
|
|
|
+import com.owncloud.android.databinding.GridSyncItemBinding
|
|
|
+import com.owncloud.android.databinding.SyncedFoldersEmptyBinding
|
|
|
+import com.owncloud.android.databinding.SyncedFoldersFooterBinding
|
|
|
+import com.owncloud.android.databinding.SyncedFoldersItemHeaderBinding
|
|
|
+import com.owncloud.android.datamodel.MediaFolderType
|
|
|
+import com.owncloud.android.datamodel.SyncedFolderDisplayItem
|
|
|
+import com.owncloud.android.datamodel.ThumbnailsCacheManager
|
|
|
+import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncMediaThumbnailDrawable
|
|
|
+import com.owncloud.android.datamodel.ThumbnailsCacheManager.MediaThumbnailGenerationTask
|
|
|
+import com.owncloud.android.utils.theme.ViewThemeUtils
|
|
|
+import java.io.File
|
|
|
+import java.util.Locale
|
|
|
+import java.util.concurrent.Executor
|
|
|
+import java.util.concurrent.Executors
|
|
|
|
|
|
/**
|
|
|
* Adapter to display all auto-synced folders and/or instant upload media folders.
|
|
|
*/
|
|
|
-public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedViewHolder> {
|
|
|
-
|
|
|
- private final Context context;
|
|
|
- private final Clock clock;
|
|
|
- private final int gridWidth;
|
|
|
- private final int gridTotal;
|
|
|
- private final ClickListener clickListener;
|
|
|
- private final List<SyncedFolderDisplayItem> syncFolderItems;
|
|
|
- private final List<SyncedFolderDisplayItem> filteredSyncFolderItems;
|
|
|
- private final boolean light;
|
|
|
- private static final int VIEW_TYPE_EMPTY = Integer.MAX_VALUE;
|
|
|
- private static final int VIEW_TYPE_ITEM = 1;
|
|
|
- private static final int VIEW_TYPE_HEADER = 2;
|
|
|
- private static final int VIEW_TYPE_FOOTER = 3;
|
|
|
- private boolean hideItems;
|
|
|
- private final ViewThemeUtils viewThemeUtils;
|
|
|
- private final Executor thumbnailThreadPool;
|
|
|
-
|
|
|
- public SyncedFolderAdapter(Context context,
|
|
|
- Clock clock,
|
|
|
- int gridWidth,
|
|
|
- ClickListener listener,
|
|
|
- boolean light,
|
|
|
- ViewThemeUtils viewThemeUtils) {
|
|
|
- this.context = context;
|
|
|
- this.clock = clock;
|
|
|
- this.gridWidth = gridWidth;
|
|
|
- gridTotal = gridWidth * 2;
|
|
|
- clickListener = listener;
|
|
|
- syncFolderItems = new ArrayList<>();
|
|
|
- filteredSyncFolderItems = new ArrayList<>();
|
|
|
- this.light = light;
|
|
|
- this.hideItems = true;
|
|
|
- this.viewThemeUtils = viewThemeUtils;
|
|
|
- this.thumbnailThreadPool = Executors.newCachedThreadPool();
|
|
|
-
|
|
|
- shouldShowHeadersForEmptySections(true);
|
|
|
- shouldShowFooters(true);
|
|
|
+@Suppress("LongParameterList")
|
|
|
+class SyncedFolderAdapter(
|
|
|
+ private val context: Context,
|
|
|
+ private val clock: Clock,
|
|
|
+ private val gridWidth: Int,
|
|
|
+ private val clickListener: ClickListener,
|
|
|
+ private val light: Boolean,
|
|
|
+ private val viewThemeUtils: ViewThemeUtils
|
|
|
+) : SectionedRecyclerViewAdapter<SectionedViewHolder>() {
|
|
|
+
|
|
|
+ private val gridTotal = gridWidth * 2
|
|
|
+ private val syncFolderItems: MutableList<SyncedFolderDisplayItem> = ArrayList()
|
|
|
+ private val filteredSyncFolderItems: MutableList<SyncedFolderDisplayItem> = ArrayList()
|
|
|
+ private var hideItems = true
|
|
|
+ private val thumbnailThreadPool: Executor = Executors.newCachedThreadPool()
|
|
|
+
|
|
|
+ init {
|
|
|
+ shouldShowHeadersForEmptySections(true)
|
|
|
+ shouldShowFooters(true)
|
|
|
}
|
|
|
|
|
|
- public void toggleHiddenItemsVisibility() {
|
|
|
- hideItems = !hideItems;
|
|
|
- filteredSyncFolderItems.clear();
|
|
|
- filteredSyncFolderItems.addAll(filterHiddenItems(syncFolderItems, hideItems));
|
|
|
- notifyDataSetChanged();
|
|
|
+ @SuppressLint("NotifyDataSetChanged")
|
|
|
+ fun toggleHiddenItemsVisibility() {
|
|
|
+ hideItems = !hideItems
|
|
|
+
|
|
|
+ filterHiddenItems(syncFolderItems, hideItems)?.let {
|
|
|
+ filteredSyncFolderItems.clear()
|
|
|
+ filteredSyncFolderItems.addAll(it)
|
|
|
+ notifyDataSetChanged()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public void setSyncFolderItems(List<SyncedFolderDisplayItem> syncFolderItems) {
|
|
|
- this.syncFolderItems.clear();
|
|
|
- this.syncFolderItems.addAll(syncFolderItems);
|
|
|
+ fun setSyncFolderItems(syncFolderItems: List<SyncedFolderDisplayItem>) {
|
|
|
+ this.syncFolderItems.clear()
|
|
|
+ this.syncFolderItems.addAll(syncFolderItems)
|
|
|
|
|
|
- this.filteredSyncFolderItems.clear();
|
|
|
- this.filteredSyncFolderItems.addAll(filterHiddenItems(this.syncFolderItems, hideItems));
|
|
|
+ filterHiddenItems(this.syncFolderItems, hideItems)?.let {
|
|
|
+ filteredSyncFolderItems.clear()
|
|
|
+ filteredSyncFolderItems.addAll(it)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public void setSyncFolderItem(int location, SyncedFolderDisplayItem syncFolderItem) {
|
|
|
- if (hideItems && syncFolderItem.isHidden() && filteredSyncFolderItems.contains(syncFolderItem)) {
|
|
|
- filteredSyncFolderItems.remove(location);
|
|
|
+ @SuppressLint("NotifyDataSetChanged")
|
|
|
+ fun setSyncFolderItem(location: Int, syncFolderItem: SyncedFolderDisplayItem) {
|
|
|
+ if (hideItems && syncFolderItem.isHidden && filteredSyncFolderItems.contains(syncFolderItem)) {
|
|
|
+ filteredSyncFolderItems.removeAt(location)
|
|
|
} else {
|
|
|
if (filteredSyncFolderItems.contains(syncFolderItem)) {
|
|
|
- filteredSyncFolderItems.set(filteredSyncFolderItems.indexOf(syncFolderItem), syncFolderItem);
|
|
|
+ filteredSyncFolderItems[filteredSyncFolderItems.indexOf(syncFolderItem)] = syncFolderItem
|
|
|
} else {
|
|
|
- filteredSyncFolderItems.add(syncFolderItem);
|
|
|
+ filteredSyncFolderItems.add(syncFolderItem)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (syncFolderItems.contains(syncFolderItem)) {
|
|
|
- syncFolderItems.set(syncFolderItems.indexOf(syncFolderItem), syncFolderItem);
|
|
|
+ syncFolderItems[syncFolderItems.indexOf(syncFolderItem)] = syncFolderItem
|
|
|
} else {
|
|
|
- syncFolderItems.add(syncFolderItem);
|
|
|
+ syncFolderItems.add(syncFolderItem)
|
|
|
}
|
|
|
|
|
|
- notifyDataSetChanged();
|
|
|
+ notifyDataSetChanged()
|
|
|
}
|
|
|
|
|
|
- public void addSyncFolderItem(SyncedFolderDisplayItem syncFolderItem) {
|
|
|
- syncFolderItems.add(syncFolderItem);
|
|
|
+ @SuppressLint("NotifyDataSetChanged")
|
|
|
+ fun addSyncFolderItem(syncFolderItem: SyncedFolderDisplayItem) {
|
|
|
+ syncFolderItems.add(syncFolderItem)
|
|
|
|
|
|
// add item for display when either all items should be shown (!hideItems)
|
|
|
// or if item should be shown (!.isHidden())
|
|
|
- if (!hideItems || !syncFolderItem.isHidden()) {
|
|
|
- filteredSyncFolderItems.add(syncFolderItem);
|
|
|
- notifyDataSetChanged();
|
|
|
+ if (!hideItems || !syncFolderItem.isHidden) {
|
|
|
+ filteredSyncFolderItems.add(syncFolderItem)
|
|
|
+ notifyDataSetChanged()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public void removeItem(int section) {
|
|
|
- if (filteredSyncFolderItems.contains(syncFolderItems.get(section))) {
|
|
|
- filteredSyncFolderItems.remove(syncFolderItems.get(section));
|
|
|
- notifyDataSetChanged();
|
|
|
+ @SuppressLint("NotifyDataSetChanged")
|
|
|
+ fun removeItem(section: Int) {
|
|
|
+ if (filteredSyncFolderItems.contains(syncFolderItems[section])) {
|
|
|
+ filteredSyncFolderItems.remove(syncFolderItems[section])
|
|
|
+ notifyDataSetChanged()
|
|
|
}
|
|
|
- syncFolderItems.remove(section);
|
|
|
+
|
|
|
+ syncFolderItems.removeAt(section)
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -141,94 +130,95 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
|
|
|
* @param items Collection of items to filter
|
|
|
* @return Non-hidden items
|
|
|
*/
|
|
|
- private List<SyncedFolderDisplayItem> filterHiddenItems(List<SyncedFolderDisplayItem> items, boolean hide) {
|
|
|
+ private fun filterHiddenItems(
|
|
|
+ items: List<SyncedFolderDisplayItem>?,
|
|
|
+ hide: Boolean
|
|
|
+ ): List<SyncedFolderDisplayItem>? {
|
|
|
if (!hide) {
|
|
|
- return items;
|
|
|
+ return items
|
|
|
} else {
|
|
|
- List<SyncedFolderDisplayItem> result = new ArrayList<>();
|
|
|
+ val result: MutableList<SyncedFolderDisplayItem> = ArrayList()
|
|
|
|
|
|
- for (SyncedFolderDisplayItem item : items) {
|
|
|
- if (!item.isHidden() && !result.contains(item)) {
|
|
|
- result.add(item);
|
|
|
+ for (item in items!!) {
|
|
|
+ if (!item.isHidden && !result.contains(item)) {
|
|
|
+ result.add(item)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return result;
|
|
|
+ return result
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public int getSectionCount() {
|
|
|
- if (filteredSyncFolderItems.size() > 0) {
|
|
|
- return filteredSyncFolderItems.size() + 1;
|
|
|
+ override fun getSectionCount(): Int {
|
|
|
+ return if (filteredSyncFolderItems.size > 0) {
|
|
|
+ filteredSyncFolderItems.size + 1
|
|
|
} else {
|
|
|
- return 0;
|
|
|
+ 0
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@VisibleForTesting
|
|
|
- public void clear() {
|
|
|
- filteredSyncFolderItems.clear();
|
|
|
- syncFolderItems.clear();
|
|
|
+ fun clear() {
|
|
|
+ filteredSyncFolderItems.clear()
|
|
|
+ syncFolderItems.clear()
|
|
|
}
|
|
|
|
|
|
- public int getUnfilteredSectionCount() {
|
|
|
- if (syncFolderItems.size() > 0) {
|
|
|
- return syncFolderItems.size() + 1;
|
|
|
+ val unfilteredSectionCount: Int
|
|
|
+ get() = if (syncFolderItems.size > 0) {
|
|
|
+ syncFolderItems.size + 1
|
|
|
} else {
|
|
|
- return 0;
|
|
|
+ 0
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- @Override
|
|
|
- public int getItemCount(int section) {
|
|
|
- if (section < filteredSyncFolderItems.size()) {
|
|
|
- List<String> filePaths = filteredSyncFolderItems.get(section).getFilePaths();
|
|
|
+ override fun getItemCount(section: Int): Int {
|
|
|
+ if (section < filteredSyncFolderItems.size) {
|
|
|
+ val filePaths = filteredSyncFolderItems[section].filePaths
|
|
|
|
|
|
- if (filePaths != null) {
|
|
|
- return filteredSyncFolderItems.get(section).getFilePaths().size();
|
|
|
+ return if (filePaths != null) {
|
|
|
+ filteredSyncFolderItems[section].filePaths.size
|
|
|
} else {
|
|
|
- return 1;
|
|
|
+ 1
|
|
|
}
|
|
|
} else {
|
|
|
- return 1;
|
|
|
+ return 1
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public SyncedFolderDisplayItem get(int section) {
|
|
|
- return filteredSyncFolderItems.get(section);
|
|
|
+ fun get(section: Int): SyncedFolderDisplayItem? {
|
|
|
+ return if (section in filteredSyncFolderItems.indices) {
|
|
|
+ filteredSyncFolderItems[section]
|
|
|
+ } else {
|
|
|
+ null
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public int getItemViewType(int section, int relativePosition, int absolutePosition) {
|
|
|
- if (isLastSection(section)) {
|
|
|
- return VIEW_TYPE_EMPTY;
|
|
|
+ override fun getItemViewType(section: Int, relativePosition: Int, absolutePosition: Int): Int {
|
|
|
+ return if (isLastSection(section)) {
|
|
|
+ VIEW_TYPE_EMPTY
|
|
|
} else {
|
|
|
- return VIEW_TYPE_ITEM;
|
|
|
+ VIEW_TYPE_ITEM
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public int getHeaderViewType(int section) {
|
|
|
- if (isLastSection(section)) {
|
|
|
- return VIEW_TYPE_EMPTY;
|
|
|
+ override fun getHeaderViewType(section: Int): Int {
|
|
|
+ return if (isLastSection(section)) {
|
|
|
+ VIEW_TYPE_EMPTY
|
|
|
} else {
|
|
|
- return VIEW_TYPE_HEADER;
|
|
|
+ VIEW_TYPE_HEADER
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public int getFooterViewType(int section) {
|
|
|
- if (isLastSection(section) && showFooter()) {
|
|
|
- return VIEW_TYPE_FOOTER;
|
|
|
+ override fun getFooterViewType(section: Int): Int {
|
|
|
+ return if (isLastSection(section) && showFooter()) {
|
|
|
+ VIEW_TYPE_FOOTER
|
|
|
} else {
|
|
|
// only show footer after last item and only if folders have been hidden
|
|
|
- return VIEW_TYPE_EMPTY;
|
|
|
+ VIEW_TYPE_EMPTY
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private boolean showFooter() {
|
|
|
- return syncFolderItems.size() > filteredSyncFolderItems.size();
|
|
|
+ private fun showFooter(): Boolean {
|
|
|
+ return syncFolderItems.size > filteredSyncFolderItems.size
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -236,219 +226,231 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
|
|
|
*
|
|
|
* @param localPath the local path of the synced folder
|
|
|
* @param type the of the synced folder
|
|
|
- * @return the section index of the looked up synced folder, <code>-1</code> if not present
|
|
|
+ * @return the section index of the looked up synced folder, `-1` if not present
|
|
|
*/
|
|
|
- public int getSectionByLocalPathAndType(String localPath, int type) {
|
|
|
- for (int i = 0; i < filteredSyncFolderItems.size(); i++) {
|
|
|
- if (filteredSyncFolderItems.get(i).getLocalPath().equalsIgnoreCase(localPath) &&
|
|
|
- filteredSyncFolderItems.get(i).getType().id == type) {
|
|
|
- return i;
|
|
|
+ fun getSectionByLocalPathAndType(localPath: String?, type: Int): Int {
|
|
|
+ for (i in filteredSyncFolderItems.indices) {
|
|
|
+ if (filteredSyncFolderItems[i].localPath.equals(localPath, ignoreCase = true) &&
|
|
|
+ filteredSyncFolderItems[i].type.id == type
|
|
|
+ ) {
|
|
|
+ return i
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return -1;
|
|
|
+ return -1
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void onBindHeaderViewHolder(SectionedViewHolder commonHolder, final int section, boolean expanded) {
|
|
|
- if (section < filteredSyncFolderItems.size()) {
|
|
|
- HeaderViewHolder holder = (HeaderViewHolder) commonHolder;
|
|
|
- holder.binding.headerContainer.setVisibility(View.VISIBLE);
|
|
|
+ override fun onBindHeaderViewHolder(commonHolder: SectionedViewHolder, section: Int, expanded: Boolean) {
|
|
|
+ if (section < filteredSyncFolderItems.size) {
|
|
|
+ val holder = commonHolder as HeaderViewHolder
|
|
|
+ holder.binding.headerContainer.visibility = View.VISIBLE
|
|
|
|
|
|
- holder.binding.title.setText(filteredSyncFolderItems.get(section).getFolderName());
|
|
|
+ holder.binding.title.text = filteredSyncFolderItems[section].folderName
|
|
|
|
|
|
- if (MediaFolderType.VIDEO == filteredSyncFolderItems.get(section).getType()) {
|
|
|
- holder.binding.type.setImageResource(R.drawable.video_32dp);
|
|
|
- } else if (MediaFolderType.IMAGE == filteredSyncFolderItems.get(section).getType()) {
|
|
|
- holder.binding.type.setImageResource(R.drawable.image_32dp);
|
|
|
+ if (MediaFolderType.VIDEO == filteredSyncFolderItems[section].type) {
|
|
|
+ holder.binding.type.setImageResource(R.drawable.video_32dp)
|
|
|
+ } else if (MediaFolderType.IMAGE == filteredSyncFolderItems[section].type) {
|
|
|
+ holder.binding.type.setImageResource(R.drawable.image_32dp)
|
|
|
} else {
|
|
|
- holder.binding.type.setImageResource(R.drawable.folder_star_32dp);
|
|
|
+ holder.binding.type.setImageResource(R.drawable.folder_star_32dp)
|
|
|
}
|
|
|
|
|
|
- holder.binding.syncStatusButton.setVisibility(View.VISIBLE);
|
|
|
- holder.binding.syncStatusButton.setTag(section);
|
|
|
- holder.binding.syncStatusButton.setOnClickListener(v -> {
|
|
|
- filteredSyncFolderItems.get(section).setEnabled(
|
|
|
- !filteredSyncFolderItems.get(section).isEnabled(),
|
|
|
- clock.getCurrentTime()
|
|
|
- );
|
|
|
+ holder.binding.syncStatusButton.visibility = View.VISIBLE
|
|
|
+ holder.binding.syncStatusButton.tag = section
|
|
|
+ holder.binding.syncStatusButton.setOnClickListener {
|
|
|
+ filteredSyncFolderItems[section].setEnabled(
|
|
|
+ !filteredSyncFolderItems[section].isEnabled,
|
|
|
+ clock.currentTime
|
|
|
+ )
|
|
|
setSyncButtonActiveIcon(
|
|
|
holder.binding.syncStatusButton,
|
|
|
- filteredSyncFolderItems.get(section).isEnabled());
|
|
|
- clickListener.onSyncStatusToggleClick(section, filteredSyncFolderItems.get(section));
|
|
|
- });
|
|
|
- setSyncButtonActiveIcon(holder.binding.syncStatusButton, filteredSyncFolderItems.get(section).isEnabled());
|
|
|
+ filteredSyncFolderItems[section].isEnabled
|
|
|
+ )
|
|
|
+ clickListener.onSyncStatusToggleClick(section, filteredSyncFolderItems[section])
|
|
|
+ }
|
|
|
+ setSyncButtonActiveIcon(holder.binding.syncStatusButton, filteredSyncFolderItems[section].isEnabled)
|
|
|
|
|
|
if (light) {
|
|
|
- holder.binding.settingsButton.setVisibility(View.GONE);
|
|
|
+ holder.binding.settingsButton.visibility = View.GONE
|
|
|
} else {
|
|
|
- holder.binding.settingsButton.setVisibility(View.VISIBLE);
|
|
|
- holder.binding.settingsButton.setTag(section);
|
|
|
- holder.binding.settingsButton.setOnClickListener(
|
|
|
- v -> onOverflowIconClicked(section, filteredSyncFolderItems.get(section), v));
|
|
|
+ holder.binding.settingsButton.visibility = View.VISIBLE
|
|
|
+ holder.binding.settingsButton.tag = section
|
|
|
+ holder.binding.settingsButton.setOnClickListener { v: View ->
|
|
|
+ onOverflowIconClicked(
|
|
|
+ section,
|
|
|
+ filteredSyncFolderItems[section],
|
|
|
+ v
|
|
|
+ )
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void onOverflowIconClicked(int section, SyncedFolderDisplayItem item, View view) {
|
|
|
- PopupMenu popup = new PopupMenu(context, view);
|
|
|
- popup.inflate(R.menu.synced_folders_adapter);
|
|
|
- popup.setOnMenuItemClickListener(i -> optionsItemSelected(i, section, item));
|
|
|
- popup.getMenu()
|
|
|
- .findItem(R.id.action_auto_upload_folder_toggle_visibility)
|
|
|
- .setChecked(item.isHidden());
|
|
|
+ private fun onOverflowIconClicked(section: Int, item: SyncedFolderDisplayItem, view: View) {
|
|
|
+ val popup = PopupMenu(context, view).apply {
|
|
|
+ inflate(R.menu.synced_folders_adapter)
|
|
|
+ setOnMenuItemClickListener { i: MenuItem -> optionsItemSelected(i, section, item) }
|
|
|
+ menu
|
|
|
+ .findItem(R.id.action_auto_upload_folder_toggle_visibility)
|
|
|
+ .setChecked(item.isHidden)
|
|
|
+ }
|
|
|
|
|
|
- popup.show();
|
|
|
+ popup.show()
|
|
|
}
|
|
|
|
|
|
- private boolean optionsItemSelected(MenuItem menuItem, int section, SyncedFolderDisplayItem item) {
|
|
|
- if (menuItem.getItemId() == R.id.action_auto_upload_folder_toggle_visibility) {
|
|
|
- clickListener.onVisibilityToggleClick(section, item);
|
|
|
+ private fun optionsItemSelected(menuItem: MenuItem, section: Int, item: SyncedFolderDisplayItem): Boolean {
|
|
|
+ if (menuItem.itemId == R.id.action_auto_upload_folder_toggle_visibility) {
|
|
|
+ clickListener.onVisibilityToggleClick(section, item)
|
|
|
} else {
|
|
|
// default: R.id.action_create_custom_folder
|
|
|
- clickListener.onSyncFolderSettingsClick(section, item);
|
|
|
+ clickListener.onSyncFolderSettingsClick(section, item)
|
|
|
}
|
|
|
- return true;
|
|
|
+ return true
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void onBindFooterViewHolder(SectionedViewHolder holder, int section) {
|
|
|
+ override fun onBindFooterViewHolder(holder: SectionedViewHolder, section: Int) {
|
|
|
if (isLastSection(section) && showFooter()) {
|
|
|
- FooterViewHolder footerHolder = (FooterViewHolder) holder;
|
|
|
- footerHolder.binding.footerText.setOnClickListener(v -> toggleHiddenItemsVisibility());
|
|
|
- footerHolder.binding.footerText.setText(
|
|
|
- context.getResources().getQuantityString(
|
|
|
- R.plurals.synced_folders_show_hidden_folders,
|
|
|
- getHiddenFolderCount(),
|
|
|
- getHiddenFolderCount()
|
|
|
- )
|
|
|
- );
|
|
|
+ val footerHolder = holder as FooterViewHolder
|
|
|
+ footerHolder.binding.footerText.setOnClickListener { toggleHiddenItemsVisibility() }
|
|
|
+ footerHolder.binding.footerText.text = context.resources.getQuantityString(
|
|
|
+ R.plurals.synced_folders_show_hidden_folders,
|
|
|
+ hiddenFolderCount,
|
|
|
+ hiddenFolderCount
|
|
|
+ )
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void onBindViewHolder(SectionedViewHolder commonHolder, int section, int relativePosition,
|
|
|
- int absolutePosition) {
|
|
|
- if (section < filteredSyncFolderItems.size() && filteredSyncFolderItems.get(section).getFilePaths() != null) {
|
|
|
- MainViewHolder holder = (MainViewHolder) commonHolder;
|
|
|
+ override fun onBindViewHolder(
|
|
|
+ commonHolder: SectionedViewHolder,
|
|
|
+ section: Int,
|
|
|
+ relativePosition: Int,
|
|
|
+ absolutePosition: Int
|
|
|
+ ) {
|
|
|
+ if (section < filteredSyncFolderItems.size && filteredSyncFolderItems[section].filePaths != null) {
|
|
|
+ val holder = commonHolder as MainViewHolder
|
|
|
+
|
|
|
+ val file = File(filteredSyncFolderItems[section].filePaths[relativePosition])
|
|
|
+
|
|
|
+ val task =
|
|
|
+ MediaThumbnailGenerationTask(
|
|
|
+ holder.binding.thumbnail,
|
|
|
+ context,
|
|
|
+ viewThemeUtils
|
|
|
+ )
|
|
|
|
|
|
- File file = new File(filteredSyncFolderItems.get(section).getFilePaths().get(relativePosition));
|
|
|
+ val asyncDrawable =
|
|
|
+ AsyncMediaThumbnailDrawable(
|
|
|
+ context.resources,
|
|
|
+ ThumbnailsCacheManager.mDefaultImg
|
|
|
+ )
|
|
|
+ holder.binding.thumbnail.setImageDrawable(asyncDrawable)
|
|
|
|
|
|
- ThumbnailsCacheManager.MediaThumbnailGenerationTask task =
|
|
|
- new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.binding.thumbnail,
|
|
|
- context,
|
|
|
- viewThemeUtils);
|
|
|
+ task.executeOnExecutor(thumbnailThreadPool, file)
|
|
|
|
|
|
- ThumbnailsCacheManager.AsyncMediaThumbnailDrawable asyncDrawable =
|
|
|
- new ThumbnailsCacheManager.AsyncMediaThumbnailDrawable(
|
|
|
- context.getResources(),
|
|
|
- ThumbnailsCacheManager.mDefaultImg
|
|
|
- );
|
|
|
- holder.binding.thumbnail.setImageDrawable(asyncDrawable);
|
|
|
+ // set proper tag
|
|
|
+ holder.binding.thumbnail.tag = file.hashCode()
|
|
|
|
|
|
- task.executeOnExecutor(thumbnailThreadPool, file);
|
|
|
+ holder.itemView.tag = relativePosition % gridWidth
|
|
|
|
|
|
- // set proper tag
|
|
|
- holder.binding.thumbnail.setTag(file.hashCode());
|
|
|
-
|
|
|
- holder.itemView.setTag(relativePosition % gridWidth);
|
|
|
-
|
|
|
- if (filteredSyncFolderItems.get(section).getNumberOfFiles() > gridTotal &&
|
|
|
- relativePosition >= gridTotal - 1) {
|
|
|
- holder.binding.counter.setText(
|
|
|
- String.format(
|
|
|
- Locale.US,
|
|
|
- "%d",
|
|
|
- filteredSyncFolderItems.get(section).getNumberOfFiles() - gridTotal));
|
|
|
- holder.binding.counterLayout.setVisibility(View.VISIBLE);
|
|
|
- holder.binding.thumbnailDarkener.setVisibility(View.VISIBLE);
|
|
|
+ if (filteredSyncFolderItems[section].numberOfFiles > gridTotal &&
|
|
|
+ relativePosition >= gridTotal - 1
|
|
|
+ ) {
|
|
|
+ holder.binding.counter.text = String.format(
|
|
|
+ Locale.US,
|
|
|
+ "%d",
|
|
|
+ filteredSyncFolderItems[section].numberOfFiles - gridTotal
|
|
|
+ )
|
|
|
+ holder.binding.counterLayout.visibility = View.VISIBLE
|
|
|
+ holder.binding.thumbnailDarkener.visibility = View.VISIBLE
|
|
|
} else {
|
|
|
- holder.binding.counterLayout.setVisibility(View.GONE);
|
|
|
- holder.binding.thumbnailDarkener.setVisibility(View.GONE);
|
|
|
+ holder.binding.counterLayout.visibility = View.GONE
|
|
|
+ holder.binding.thumbnailDarkener.visibility = View.GONE
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @NonNull
|
|
|
- @Override
|
|
|
- public SectionedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
|
- if (viewType == VIEW_TYPE_HEADER) {
|
|
|
- return new HeaderViewHolder(
|
|
|
- SyncedFoldersItemHeaderBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
|
|
|
- );
|
|
|
- } else if (viewType == VIEW_TYPE_FOOTER) {
|
|
|
- return new FooterViewHolder(
|
|
|
- SyncedFoldersFooterBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
|
|
|
- );
|
|
|
- } else if (viewType == VIEW_TYPE_EMPTY) {
|
|
|
- return new EmptyViewHolder(
|
|
|
- SyncedFoldersEmptyBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
|
|
|
- );
|
|
|
- } else {
|
|
|
- return new MainViewHolder(
|
|
|
- GridSyncItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private boolean isLastSection(int section) {
|
|
|
- return section >= getSectionCount() - 1;
|
|
|
- }
|
|
|
-
|
|
|
- public int getHiddenFolderCount() {
|
|
|
- if (syncFolderItems != null && filteredSyncFolderItems != null) {
|
|
|
- return syncFolderItems.size() - filteredSyncFolderItems.size();
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SectionedViewHolder {
|
|
|
+ return when (viewType) {
|
|
|
+ VIEW_TYPE_HEADER -> {
|
|
|
+ HeaderViewHolder(
|
|
|
+ SyncedFoldersItemHeaderBinding.inflate(
|
|
|
+ LayoutInflater.from(parent.context),
|
|
|
+ parent,
|
|
|
+ false
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ VIEW_TYPE_FOOTER -> {
|
|
|
+ FooterViewHolder(
|
|
|
+ SyncedFoldersFooterBinding.inflate(
|
|
|
+ LayoutInflater.from(parent.context),
|
|
|
+ parent,
|
|
|
+ false
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ VIEW_TYPE_EMPTY -> {
|
|
|
+ EmptyViewHolder(
|
|
|
+ SyncedFoldersEmptyBinding.inflate(
|
|
|
+ LayoutInflater.from(parent.context),
|
|
|
+ parent,
|
|
|
+ false
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ else -> {
|
|
|
+ MainViewHolder(
|
|
|
+ GridSyncItemBinding.inflate(
|
|
|
+ LayoutInflater.from(parent.context),
|
|
|
+ parent,
|
|
|
+ false
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public interface ClickListener {
|
|
|
- void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem);
|
|
|
- void onSyncFolderSettingsClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem);
|
|
|
- void onVisibilityToggleClick(int section, SyncedFolderDisplayItem item);
|
|
|
+ private fun isLastSection(section: Int): Boolean {
|
|
|
+ return section >= sectionCount - 1
|
|
|
}
|
|
|
|
|
|
- static class HeaderViewHolder extends SectionedViewHolder {
|
|
|
- protected SyncedFoldersItemHeaderBinding binding;
|
|
|
+ val hiddenFolderCount: Int
|
|
|
+ get() = syncFolderItems.size - filteredSyncFolderItems.size
|
|
|
|
|
|
- private HeaderViewHolder(SyncedFoldersItemHeaderBinding binding) {
|
|
|
- super(binding.getRoot());
|
|
|
- this.binding = binding;
|
|
|
- }
|
|
|
+ interface ClickListener {
|
|
|
+ fun onSyncStatusToggleClick(section: Int, syncedFolderDisplayItem: SyncedFolderDisplayItem?)
|
|
|
+ fun onSyncFolderSettingsClick(section: Int, syncedFolderDisplayItem: SyncedFolderDisplayItem?)
|
|
|
+ fun onVisibilityToggleClick(section: Int, item: SyncedFolderDisplayItem?)
|
|
|
}
|
|
|
|
|
|
- static class FooterViewHolder extends SectionedViewHolder {
|
|
|
- protected SyncedFoldersFooterBinding binding;
|
|
|
+ internal class HeaderViewHolder(var binding: SyncedFoldersItemHeaderBinding) : SectionedViewHolder(
|
|
|
+ binding.root
|
|
|
+ )
|
|
|
|
|
|
- private FooterViewHolder(SyncedFoldersFooterBinding binding) {
|
|
|
- super(binding.getRoot());
|
|
|
- this.binding = binding;
|
|
|
- }
|
|
|
- }
|
|
|
+ internal class FooterViewHolder(var binding: SyncedFoldersFooterBinding) : SectionedViewHolder(
|
|
|
+ binding.root
|
|
|
+ )
|
|
|
|
|
|
- static class EmptyViewHolder extends SectionedViewHolder {
|
|
|
- private EmptyViewHolder(SyncedFoldersEmptyBinding binding) {
|
|
|
- super(binding.getRoot());
|
|
|
- }
|
|
|
- }
|
|
|
+ internal class EmptyViewHolder(binding: SyncedFoldersEmptyBinding) : SectionedViewHolder(binding.root)
|
|
|
|
|
|
- static class MainViewHolder extends SectionedViewHolder {
|
|
|
- protected GridSyncItemBinding binding;
|
|
|
+ internal class MainViewHolder(var binding: GridSyncItemBinding) : SectionedViewHolder(
|
|
|
+ binding.root
|
|
|
+ )
|
|
|
|
|
|
- private MainViewHolder(GridSyncItemBinding binding) {
|
|
|
- super(binding.getRoot());
|
|
|
- this.binding = binding;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void setSyncButtonActiveIcon(ImageButton syncStatusButton, boolean enabled) {
|
|
|
+ private fun setSyncButtonActiveIcon(syncStatusButton: ImageButton, enabled: Boolean) {
|
|
|
if (enabled) {
|
|
|
syncStatusButton.setImageDrawable(
|
|
|
- viewThemeUtils.platform.tintPrimaryDrawable(context, R.drawable.ic_cloud_sync_on)
|
|
|
- );
|
|
|
+ viewThemeUtils.platform.tintDrawable(context, R.drawable.ic_cloud_sync_on, ColorRole.PRIMARY)
|
|
|
+ )
|
|
|
} else {
|
|
|
- syncStatusButton.setImageResource(R.drawable.ic_cloud_sync_off);
|
|
|
+ syncStatusButton.setImageResource(R.drawable.ic_cloud_sync_off)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ companion object {
|
|
|
+ private const val VIEW_TYPE_EMPTY = Int.MAX_VALUE
|
|
|
+ private const val VIEW_TYPE_ITEM = 1
|
|
|
+ private const val VIEW_TYPE_HEADER = 2
|
|
|
+ private const val VIEW_TYPE_FOOTER = 3
|
|
|
+ }
|
|
|
}
|