123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- /*
- * Nextcloud Android client application
- *
- * @author Andy Scherzinger
- * Copyright (C) 2016 Andy Scherzinger
- * Copyright (C) 2016 Nextcloud
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- 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.FrameLayout;
- import android.widget.ImageButton;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.PopupMenu;
- import android.widget.RelativeLayout;
- import android.widget.TextView;
- 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.datamodel.MediaFolderType;
- import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
- import com.owncloud.android.datamodel.ThumbnailsCacheManager;
- import com.owncloud.android.utils.ThemeUtils;
- import java.io.File;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Locale;
- import androidx.annotation.NonNull;
- import butterknife.BindView;
- import butterknife.ButterKnife;
- /**
- * 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 final int VIEW_TYPE_EMPTY = Integer.MAX_VALUE;
- private boolean hideItems;
- public SyncedFolderAdapter(Context context, Clock clock, int gridWidth, ClickListener listener, boolean light) {
- 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;
- shouldShowHeadersForEmptySections(true);
- shouldShowFooters(true);
- }
- public void toggleHiddenItemsVisibility() {
- hideItems = !hideItems;
- filteredSyncFolderItems.clear();
- filteredSyncFolderItems.addAll(filterHiddenItems(syncFolderItems, hideItems));
- notifyDataSetChanged();
- }
- public void setSyncFolderItems(List<SyncedFolderDisplayItem> syncFolderItems) {
- this.syncFolderItems.clear();
- this.syncFolderItems.addAll(syncFolderItems);
- this.filteredSyncFolderItems.clear();
- this.filteredSyncFolderItems.addAll(filterHiddenItems(this.syncFolderItems, hideItems));
- }
- public void setSyncFolderItem(int location, SyncedFolderDisplayItem syncFolderItem) {
- if (hideItems && syncFolderItem.isHidden() && filteredSyncFolderItems.contains(syncFolderItem)) {
- filteredSyncFolderItems.remove(location);
- } else {
- if (filteredSyncFolderItems.contains(syncFolderItem)) {
- filteredSyncFolderItems.set(filteredSyncFolderItems.indexOf(syncFolderItem), syncFolderItem);
- } else {
- filteredSyncFolderItems.add(syncFolderItem);
- }
- }
- if (syncFolderItems.contains(syncFolderItem)) {
- syncFolderItems.set(syncFolderItems.indexOf(syncFolderItem), syncFolderItem);
- } else {
- syncFolderItems.add(syncFolderItem);
- }
- notifyDataSetChanged();
- }
- public void addSyncFolderItem(SyncedFolderDisplayItem syncFolderItem) {
- 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();
- }
- }
- public void removeItem(int section) {
- if (filteredSyncFolderItems.contains(syncFolderItems.get(section))) {
- filteredSyncFolderItems.remove(syncFolderItems.get(section));
- notifyDataSetChanged();
- }
- syncFolderItems.remove(section);
- }
- /**
- * Filter for hidden items
- *
- * @param items Collection of items to filter
- * @return Non-hidden items
- */
- private List<SyncedFolderDisplayItem> filterHiddenItems(List<SyncedFolderDisplayItem> items, boolean hide) {
- if (!hide) {
- return items;
- } else {
- List<SyncedFolderDisplayItem> result = new ArrayList<>();
- for (SyncedFolderDisplayItem item : items) {
- if (!item.isHidden() && !result.contains(item)) {
- result.add(item);
- }
- }
- return result;
- }
- }
- @Override
- public int getSectionCount() {
- if (filteredSyncFolderItems.size() > 0) {
- return filteredSyncFolderItems.size() + 1;
- } else {
- return 0;
- }
- }
- public int getUnfilteredSectionCount() {
- if (syncFolderItems.size() > 0) {
- return syncFolderItems.size() + 1;
- } else {
- return 0;
- }
- }
- @Override
- public int getItemCount(int section) {
- if (section < filteredSyncFolderItems.size()) {
- List<String> filePaths = filteredSyncFolderItems.get(section).getFilePaths();
- if (filePaths != null) {
- return filteredSyncFolderItems.get(section).getFilePaths().size();
- } else {
- return 1;
- }
- } else {
- return 1;
- }
- }
- public SyncedFolderDisplayItem get(int section) {
- return filteredSyncFolderItems.get(section);
- }
- @Override
- public int getItemViewType(int section, int relativePosition, int absolutePosition) {
- if (isLastSection(section)) {
- return VIEW_TYPE_EMPTY;
- } else {
- return VIEW_TYPE_ITEM;
- }
- }
- @Override
- public int getHeaderViewType(int section) {
- if (isLastSection(section)) {
- return VIEW_TYPE_EMPTY;
- } else {
- return VIEW_TYPE_HEADER;
- }
- }
- @Override
- public int getFooterViewType(int section) {
- if (isLastSection(section) && showFooter()) {
- return VIEW_TYPE_FOOTER;
- } else {
- // only show footer after last item and only if folders have been hidden
- return VIEW_TYPE_EMPTY;
- }
- }
- private boolean showFooter() {
- return syncFolderItems.size() > filteredSyncFolderItems.size();
- }
- /**
- * returns the section of a synced folder for the given local path and type.
- *
- * @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
- */
- 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().getId().equals(type)) {
- return i;
- }
- }
- return -1;
- }
- @Override
- public void onBindHeaderViewHolder(SectionedViewHolder commonHolder, final int section, boolean expanded) {
- if (section < filteredSyncFolderItems.size()) {
- HeaderViewHolder holder = (HeaderViewHolder) commonHolder;
- holder.mainHeaderContainer.setVisibility(View.VISIBLE);
- holder.title.setText(filteredSyncFolderItems.get(section).getFolderName());
- if (MediaFolderType.VIDEO == filteredSyncFolderItems.get(section).getType()) {
- holder.type.setImageResource(R.drawable.video_32dp);
- } else if (MediaFolderType.IMAGE == filteredSyncFolderItems.get(section).getType()) {
- holder.type.setImageResource(R.drawable.image_32dp);
- } else {
- holder.type.setImageResource(R.drawable.folder_star_32dp);
- }
- holder.syncStatusButton.setVisibility(View.VISIBLE);
- holder.syncStatusButton.setTag(section);
- holder.syncStatusButton.setOnClickListener(v -> {
- filteredSyncFolderItems.get(section).setEnabled(
- !filteredSyncFolderItems.get(section).isEnabled(),
- clock.getCurrentTime()
- );
- setSyncButtonActiveIcon(holder.syncStatusButton, filteredSyncFolderItems.get(section).isEnabled());
- clickListener.onSyncStatusToggleClick(section, filteredSyncFolderItems.get(section));
- });
- setSyncButtonActiveIcon(holder.syncStatusButton, filteredSyncFolderItems.get(section).isEnabled());
- if (light) {
- holder.menuButton.setVisibility(View.GONE);
- } else {
- holder.menuButton.setVisibility(View.VISIBLE);
- holder.menuButton.setTag(section);
- holder.menuButton.setOnClickListener(v -> onOverflowIconClicked(section,
- filteredSyncFolderItems.get(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());
- 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);
- } else {
- // default: R.id.action_create_custom_folder
- clickListener.onSyncFolderSettingsClick(section, item);
- }
- return true;
- }
- @Override
- public void onBindFooterViewHolder(SectionedViewHolder holder, int section) {
- if (isLastSection(section) && showFooter()) {
- FooterViewHolder footerHolder = (FooterViewHolder) holder;
- footerHolder.title.setOnClickListener(v -> toggleHiddenItemsVisibility());
- footerHolder.title.setText(
- context.getResources().getQuantityString(
- R.plurals.synced_folders_show_hidden_folders,
- getHiddenFolderCount(),
- getHiddenFolderCount()
- )
- );
- }
- }
- @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;
- File file = new File(filteredSyncFolderItems.get(section).getFilePaths().get(relativePosition));
- ThumbnailsCacheManager.MediaThumbnailGenerationTask task =
- new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.image, context);
- ThumbnailsCacheManager.AsyncMediaThumbnailDrawable asyncDrawable =
- new ThumbnailsCacheManager.AsyncMediaThumbnailDrawable(
- context.getResources(),
- ThumbnailsCacheManager.mDefaultImg,
- task
- );
- holder.image.setImageDrawable(asyncDrawable);
- task.execute(file);
- // set proper tag
- holder.image.setTag(file.hashCode());
- holder.itemView.setTag(relativePosition % gridWidth);
- if (filteredSyncFolderItems.get(section).getNumberOfFiles() > gridTotal && relativePosition >= gridTotal - 1) {
- holder.counterValue.setText(String.format(Locale.US, "%d",
- filteredSyncFolderItems.get(section).getNumberOfFiles() - gridTotal));
- holder.counterBar.setVisibility(View.VISIBLE);
- holder.thumbnailDarkener.setVisibility(View.VISIBLE);
- } else {
- holder.counterBar.setVisibility(View.GONE);
- holder.thumbnailDarkener.setVisibility(View.GONE);
- }
- }
- }
- @NonNull
- @Override
- public SectionedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- if (viewType == VIEW_TYPE_HEADER) {
- View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.synced_folders_item_header, parent, false);
- return new HeaderViewHolder(v);
- } else if (viewType == VIEW_TYPE_FOOTER) {
- View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.synced_folders_footer, parent, false);
- return new FooterViewHolder(v);
- } else if (viewType == VIEW_TYPE_EMPTY) {
- View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.synced_folders_empty, parent, false);
- return new EmptyViewHolder(v);
- } else {
- View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_sync_item, parent, false);
- return new MainViewHolder(v);
- }
- }
- 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;
- }
- }
- public interface ClickListener {
- void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem);
- void onSyncFolderSettingsClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem);
- void onVisibilityToggleClick(int section, SyncedFolderDisplayItem item);
- }
- static class HeaderViewHolder extends SectionedViewHolder {
- @BindView(R.id.header_container)
- public RelativeLayout mainHeaderContainer;
- @BindView(R.id.type)
- public ImageView type;
- @BindView(R.id.title)
- public TextView title;
- @BindView(R.id.syncStatusButton)
- public ImageButton syncStatusButton;
- @BindView(R.id.settingsButton)
- public ImageButton menuButton;
- private HeaderViewHolder(View itemView) {
- super(itemView);
- ButterKnife.bind(this, itemView);
- }
- }
- static class FooterViewHolder extends SectionedViewHolder {
- @BindView(R.id.footer_container)
- public LinearLayout mainFooterContainer;
- @BindView(R.id.footer_text)
- public TextView title;
- private FooterViewHolder(View itemView) {
- super(itemView);
- ButterKnife.bind(this, itemView);
- }
- }
- static class EmptyViewHolder extends SectionedViewHolder {
- private EmptyViewHolder(View itemView) {
- super(itemView);
- }
- }
- static class MainViewHolder extends SectionedViewHolder {
- @BindView(R.id.grid_item_container)
- public FrameLayout item_container;
- @BindView(R.id.thumbnail)
- public ImageView image;
- @BindView(R.id.counterLayout)
- public LinearLayout counterBar;
- @BindView(R.id.counter)
- public TextView counterValue;
- @BindView(R.id.thumbnailDarkener)
- public ImageView thumbnailDarkener;
- private MainViewHolder(View itemView) {
- super(itemView);
- ButterKnife.bind(this, itemView);
- }
- }
- private void setSyncButtonActiveIcon(ImageButton syncStatusButton, boolean enabled) {
- if (enabled) {
- syncStatusButton.setImageDrawable(ThemeUtils.tintDrawable(R.drawable.ic_cloud_sync_on,
- ThemeUtils.primaryColor(context)));
- } else {
- syncStatusButton.setImageResource(R.drawable.ic_cloud_sync_off);
- }
- }
- }
|