From 23e44243dab83554126695ae8b3b039cf306d3f3 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Fri, 1 Nov 2019 22:37:55 +0100 Subject: [PATCH 1/9] show/hide auto upload list items Signed-off-by: Andy Scherzinger --- .../android/datamodel/SyncedFolder.java | 27 +- .../datamodel/SyncedFolderDisplayItem.java | 17 +- .../datamodel/SyncedFolderProvider.java | 5 +- .../com/owncloud/android/db/ProviderMeta.java | 3 +- .../providers/FileContentProvider.java | 27 +- .../ui/activity/SyncedFoldersActivity.java | 108 ++++--- .../ui/adapter/SyncedFolderAdapter.java | 306 ++++++++++++++---- .../dialog/parcel/SyncedFolderParcelable.java | 168 +++++----- src/main/res/layout/synced_folders_empty.xml | 6 + src/main/res/layout/synced_folders_footer.xml | 38 +++ src/main/res/menu/synced_folders_adapter.xml | 28 ++ src/main/res/values/strings.xml | 6 + .../activity/SyncedFoldersActivityTest.java | 3 +- 13 files changed, 528 insertions(+), 214 deletions(-) create mode 100644 src/main/res/layout/synced_folders_empty.xml create mode 100644 src/main/res/layout/synced_folders_footer.xml create mode 100644 src/main/res/menu/synced_folders_adapter.xml diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java index 91b42b813469..fa4d5823c38e 100644 --- a/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java +++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java @@ -23,14 +23,12 @@ import java.io.Serializable; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; /** * Synced folder entity containing all information per synced folder. */ -@AllArgsConstructor public class SyncedFolder implements Serializable, Cloneable { public static final long UNPERSISTED_ID = Long.MIN_VALUE; public static final long EMPTY_ENABLED_TIMESTAMP_MS = -1; @@ -39,14 +37,15 @@ public class SyncedFolder implements Serializable, Cloneable { @Getter @Setter private long id; @Getter @Setter private String localPath; @Getter @Setter private String remotePath; - @Getter @Setter private Boolean wifiOnly; - @Getter @Setter private Boolean chargingOnly; - @Getter @Setter private Boolean subfolderByDate; + @Getter @Setter private boolean wifiOnly; + @Getter @Setter private boolean chargingOnly; + @Getter @Setter private boolean subfolderByDate; @Getter @Setter private String account; - @Getter @Setter private Integer uploadAction; + @Getter @Setter private int uploadAction; @Getter private boolean enabled; @Getter private long enabledTimestampMs; @Getter @Setter private MediaFolderType type; + @Getter @Setter private boolean hidden; /** * constructor for new, to be persisted entity. @@ -61,12 +60,13 @@ public class SyncedFolder implements Serializable, Cloneable { * @param enabled flag if synced folder config is active * @param timestampMs the current timestamp in milliseconds * @param type the type of the folder + * @param hidden hide item flag */ - public SyncedFolder(String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly, - Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled, - long timestampMs, MediaFolderType type) { + public SyncedFolder(String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, + boolean subfolderByDate, String account, int uploadAction, boolean enabled, + long timestampMs, MediaFolderType type, boolean hidden) { this(UNPERSISTED_ID, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, - enabled, timestampMs, type); + enabled, timestampMs, type, hidden); } /** @@ -74,9 +74,9 @@ public SyncedFolder(String localPath, String remotePath, Boolean wifiOnly, Boole * * @param id id */ - protected SyncedFolder(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly, - Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled, - long timestampMs, MediaFolderType type) { + protected SyncedFolder(long id, String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, + boolean subfolderByDate, String account, int uploadAction, boolean enabled, + long timestampMs, MediaFolderType type, boolean hidden) { this.id = id; this.localPath = localPath; this.remotePath = remotePath; @@ -87,6 +87,7 @@ protected SyncedFolder(long id, String localPath, String remotePath, Boolean wif this.uploadAction = uploadAction; this.setEnabled(enabled, timestampMs); this.type = type; + this.hidden = hidden; } /** diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java index 7420b1889295..5b51b37e0154 100644 --- a/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java +++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java @@ -53,24 +53,25 @@ public class SyncedFolderDisplayItem extends SyncedFolder { * @param folderName the UI info for the folder's name * @param numberOfFiles the UI info for number of files within the folder * @param type the type of the folder + * @param hidden hide item flag */ - public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly, - Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled, + public SyncedFolderDisplayItem(long id, String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, + boolean subfolderByDate, String account, int uploadAction, boolean enabled, long timestampMs, List filePaths, String folderName, long numberOfFiles, - MediaFolderType type) + MediaFolderType type, boolean hidden) { super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, - timestampMs, type); + timestampMs, type, hidden); this.filePaths = filePaths; this.folderName = folderName; this.numberOfFiles = numberOfFiles; } - public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly, - Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled, - long timestampMs, String folderName, MediaFolderType type) { + public SyncedFolderDisplayItem(long id, String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, + boolean subfolderByDate, String account, int uploadAction, boolean enabled, + long timestampMs, String folderName, MediaFolderType type, boolean hidden) { super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, - timestampMs, type); + timestampMs, type, hidden); this.folderName = folderName; } } diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java index 8a66a4058a1b..6a8caf710671 100644 --- a/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -354,9 +354,11 @@ private SyncedFolder createSyncedFolderFromCursor(Cursor cursor) { ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS)); MediaFolderType type = MediaFolderType.getById(cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE))); + Boolean hidden = cursor.getInt(cursor.getColumnIndex( + ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN)) == 1; syncedFolder = new SyncedFolder(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, - accountName, uploadAction, enabled, enabledTimestampMs, type); + accountName, uploadAction, enabled, enabledTimestampMs, type, hidden); } return syncedFolder; } @@ -380,6 +382,7 @@ private ContentValues createContentValuesFromSyncedFolder(SyncedFolder syncedFol cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ACCOUNT, syncedFolder.getAccount()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION, syncedFolder.getUploadAction()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE, syncedFolder.getType().getId()); + cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN, syncedFolder.getHidden()); return cv; } diff --git a/src/main/java/com/owncloud/android/db/ProviderMeta.java b/src/main/java/com/owncloud/android/db/ProviderMeta.java index 8bbe982b15d2..a9dad01cd914 100644 --- a/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -31,7 +31,7 @@ */ public class ProviderMeta { public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 50; + public static final int DB_VERSION = 51; private ProviderMeta() { // No instance @@ -225,6 +225,7 @@ static public class ProviderTableMeta implements BaseColumns { public static final String SYNCED_FOLDER_SUBFOLDER_BY_DATE = "subfolder_by_date"; public static final String SYNCED_FOLDER_ACCOUNT = "account"; public static final String SYNCED_FOLDER_UPLOAD_ACTION = "upload_option"; + public static final String SYNCED_FOLDER_HIDDEN = "hidden"; // Columns of external links table public static final String EXTERNAL_LINKS_ICON_URL = "icon_url"; diff --git a/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/src/main/java/com/owncloud/android/providers/FileContentProvider.java index 78824925e414..d1bfda3b10fe 100644 --- a/src/main/java/com/owncloud/android/providers/FileContentProvider.java +++ b/src/main/java/com/owncloud/android/providers/FileContentProvider.java @@ -833,7 +833,8 @@ private void createSyncedFoldersTable(SQLiteDatabase db) { + ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE + " INTEGER, " // subfolder by date + ProviderTableMeta.SYNCED_FOLDER_ACCOUNT + " TEXT, " // account + ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION + " INTEGER, " // upload action - + ProviderTableMeta.SYNCED_FOLDER_TYPE + " INTEGER );" // type + + ProviderTableMeta.SYNCED_FOLDER_TYPE + " INTEGER, " // type + + ProviderTableMeta.SYNCED_FOLDER_HIDDEN + " INTEGER );" // hidden ); } @@ -2045,6 +2046,24 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (!upgraded) { Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); } + + if (oldVersion < 51 && newVersion >= 51) { + Log_OC.i(SQL, "Entering in the #51 add show/hide to folderSync table"); + db.beginTransaction(); + try { + db.execSQL(ALTER_TABLE + ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME + + ADD_COLUMN + ProviderTableMeta.SYNCED_FOLDER_HIDDEN + " INTEGER "); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + + if (!upgraded) { + Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); + } } @Override @@ -2057,6 +2076,12 @@ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(ALTER_TABLE + ProviderTableMeta.CAPABILITIES_TABLE_NAME + REMOVE_COLUMN + ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION); } + + if(oldVersion == 50 && newVersion < 50) { + db.execSQL(ALTER_TABLE + ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME + + REMOVE_COLUMN + ProviderTableMeta.SYNCED_FOLDER_HIDDEN); + + } } } } diff --git a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java index 972522d6336f..3d08d4193b4e 100644 --- a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java @@ -50,6 +50,7 @@ import com.owncloud.android.BuildConfig; import com.owncloud.android.MainApp; import com.owncloud.android.R; +import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.MediaFolder; import com.owncloud.android.datamodel.MediaFolderType; import com.owncloud.android.datamodel.MediaProvider; @@ -382,9 +383,9 @@ private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull Sy syncedFolder.getId(), syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), - syncedFolder.getWifiOnly(), - syncedFolder.getChargingOnly(), - syncedFolder.getSubfolderByDate(), + syncedFolder.isWifiOnly(), + syncedFolder.isChargingOnly(), + syncedFolder.isSubfolderByDate(), syncedFolder.getAccount(), syncedFolder.getUploadAction(), syncedFolder.isEnabled(), @@ -392,7 +393,8 @@ private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull Sy filePaths, localFolder.getName(), files.length, - syncedFolder.getType()); + syncedFolder.getType(), + syncedFolder.isHidden()); } /** @@ -408,9 +410,9 @@ private SyncedFolderDisplayItem createSyncedFolder(@NonNull SyncedFolder syncedF syncedFolder.getId(), syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), - syncedFolder.getWifiOnly(), - syncedFolder.getChargingOnly(), - syncedFolder.getSubfolderByDate(), + syncedFolder.isWifiOnly(), + syncedFolder.isChargingOnly(), + syncedFolder.isSubfolderByDate(), syncedFolder.getAccount(), syncedFolder.getUploadAction(), syncedFolder.isEnabled(), @@ -418,7 +420,8 @@ private SyncedFolderDisplayItem createSyncedFolder(@NonNull SyncedFolder syncedF mediaFolder.filePaths, mediaFolder.folderName, mediaFolder.numberOfFiles, - mediaFolder.type); + mediaFolder.type, + syncedFolder.isHidden()); } /** @@ -443,7 +446,8 @@ private SyncedFolderDisplayItem createSyncedFolderFromMediaFolder(@NonNull Media mediaFolder.filePaths, mediaFolder.folderName, mediaFolder.numberOfFiles, - mediaFolder.type); + mediaFolder.type, + false); } private File[] getFileList(File localFolder) { @@ -523,8 +527,8 @@ public boolean onOptionsItemSelected(MenuItem item) { Log.d(TAG, "Show custom folder dialog"); SyncedFolderDisplayItem emptyCustomFolder = new SyncedFolderDisplayItem( SyncedFolder.UNPERSISTED_ID, null, null, true, false, - false, getAccount().name, - FileUploader.LOCAL_BEHAVIOUR_FORGET, false, clock.getCurrentTime(), null, MediaFolderType.CUSTOM); + false, getAccount().name, FileUploader.LOCAL_BEHAVIOUR_FORGET, false, + clock.getCurrentTime(), null, MediaFolderType.CUSTOM, false); onSyncFolderSettingsClick(0, emptyCustomFolder); } @@ -581,6 +585,14 @@ public void onSyncFolderSettingsClick(int section, SyncedFolderDisplayItem synce mSyncedFolderPreferencesDialogFragment.show(ft, SYNCED_FOLDER_PREFERENCES_DIALOG_TAG); } + @Override + public void onVisibilityToggleClick(int section, SyncedFolderDisplayItem syncedFolder) { + syncedFolder.setHidden(!syncedFolder.isHidden()); + + saveOrUpdateSyncedFolder(syncedFolder); + mAdapter.setSyncFolderItem(section, syncedFolder); + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SyncedFolderPreferencesDialogFragment.REQUEST_CODE__SELECT_REMOTE_FOLDER @@ -606,39 +618,21 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { SyncedFolder.UNPERSISTED_ID, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), syncedFolder.getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(), syncedFolder.getAccount(), syncedFolder.getUploadAction(), syncedFolder.getEnabled(), - clock.getCurrentTime(), new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType()); - long storedId = mSyncedFolderProvider.storeSyncedFolder(newCustomFolder); - if (storedId != -1) { - newCustomFolder.setId(storedId); - if (newCustomFolder.isEnabled()) { - FilesSyncHelper.insertAllDBEntriesForSyncedFolder(newCustomFolder); - } - } + clock.getCurrentTime(), new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType(), syncedFolder.getHidden()); + + saveOrUpdateSyncedFolder(newCustomFolder); mAdapter.addSyncFolderItem(newCustomFolder); } else { SyncedFolderDisplayItem item = mAdapter.get(syncedFolder.getSection()); - item = updateSyncedFolderItem(item, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), syncedFolder + updateSyncedFolderItem(item, syncedFolder.getId(), syncedFolder.getLocalPath(), + syncedFolder.getRemotePath(), syncedFolder .getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(), syncedFolder .getUploadAction(), syncedFolder.getEnabled()); - if (syncedFolder.getId() == UNPERSISTED_ID) { - // newly set up folder sync config - long storedId = mSyncedFolderProvider.storeSyncedFolder(item); - if (storedId != -1) { - item.setId(storedId); - if (item.isEnabled()) { - FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item); - } - } - } else { - // existing synced folder setup to be updated - mSyncedFolderProvider.updateSyncFolder(item); - if (item.isEnabled()) { - FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item); - } - } + saveOrUpdateSyncedFolder(item); - mAdapter.setSyncFolderItem(syncedFolder.getSection(), item); + // TODO test if notifiyItemChanged is suffiecient (should improve performance) + mAdapter.notifyDataSetChanged(); } mSyncedFolderPreferencesDialogFragment = null; @@ -648,6 +642,40 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { } } + private void saveOrUpdateSyncedFolder(SyncedFolderDisplayItem item) { + if (item.getId() == UNPERSISTED_ID) { + // newly set up folder sync config + storeSyncedFolder(item); + } else { + // existing synced folder setup to be updated + mSyncedFolderProvider.updateSyncFolder(item); + if (item.isEnabled()) { + FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item); + } else { + String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + item.getId(); + + ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(MainApp.getAppContext(). + getContentResolver()); + arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey); + } + } + } + + private void storeSyncedFolder(SyncedFolderDisplayItem item) { + ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(MainApp.getAppContext(). + getContentResolver()); + long storedId = mSyncedFolderProvider.storeSyncedFolder(item); + if (storedId != -1) { + item.setId(storedId); + if (item.isEnabled()) { + FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item); + } else { + String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + item.getId(); + arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey); + } + } + } + @Override public void onCancelSyncedFolderPreference() { mSyncedFolderPreferencesDialogFragment = null; @@ -670,9 +698,9 @@ public void onDeleteSyncedFolderPreference(SyncedFolderParcelable syncedFolder) * @param subfolderByDate created sub folders * @param uploadAction upload action * @param enabled is sync enabled - * @return the updated item */ - private SyncedFolderDisplayItem updateSyncedFolderItem(SyncedFolderDisplayItem item, + private void updateSyncedFolderItem(SyncedFolderDisplayItem item, + long id, String localPath, String remotePath, Boolean wifiOnly, @@ -680,6 +708,7 @@ private SyncedFolderDisplayItem updateSyncedFolderItem(SyncedFolderDisplayItem i Boolean subfolderByDate, Integer uploadAction, Boolean enabled) { + item.setId(id); item.setLocalPath(localPath); item.setRemotePath(remotePath); item.setWifiOnly(wifiOnly); @@ -687,7 +716,6 @@ private SyncedFolderDisplayItem updateSyncedFolderItem(SyncedFolderDisplayItem i item.setSubfolderByDate(subfolderByDate); item.setUploadAction(uploadAction); item.setEnabled(enabled, clock.getCurrentTime()); - return item; } @Override diff --git a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java index 7588b323da7f..2c636b1b3b87 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java @@ -23,11 +23,14 @@ 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; @@ -54,64 +57,167 @@ */ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter { - private final Context mContext; + private final Context context; private final Clock clock; - private final int mGridWidth; - private final int mGridTotal; - private final ClickListener mListener; - private final List mSyncFolderItems; - private final boolean mLight; + private final int gridWidth; + private final int gridTotal; + private final ClickListener clickListener; + private final List syncFolderItems; + private final List 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) { - mContext = context; + this.context = context; this.clock = clock; - mGridWidth = gridWidth; - mGridTotal = gridWidth * 2; - mListener = listener; - mSyncFolderItems = new ArrayList<>(); - mLight = light; + this.gridWidth = gridWidth; + gridTotal = gridWidth * 2; + clickListener = listener; + syncFolderItems = new ArrayList<>(); + filteredSyncFolderItems = new ArrayList<>(); + this.light = light; + this.hideItems = true; shouldShowHeadersForEmptySections(true); + shouldShowFooters(true); + } + + private void toggleHiddenItemsVisibility() { + hideItems = !hideItems; + filteredSyncFolderItems.clear(); + filteredSyncFolderItems.addAll(filterHiddenItems(syncFolderItems, hideItems)); + notifyDataSetChanged(); } public void setSyncFolderItems(List syncFolderItems) { - mSyncFolderItems.clear(); - mSyncFolderItems.addAll(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) { - mSyncFolderItems.set(location, syncFolderItem); + // show all items OR + 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) { - mSyncFolderItems.add(syncFolderItem); - notifyDataSetChanged(); + syncFolderItems.add(syncFolderItem); + + // add item for display when either all items should be shown (!hideItems) + // or if items should be hi + if (!hideItems || !syncFolderItem.isHidden()) { + filteredSyncFolderItems.add(syncFolderItem); + notifyDataSetChanged(); + } } public void removeItem(int section) { - mSyncFolderItems.remove(section); - notifyDataSetChanged(); + 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 filterHiddenItems(List items, boolean hide) { + if (hide) { + List ret = new ArrayList<>(); + + for (SyncedFolderDisplayItem item : items) { + if (!item.isHidden() && !ret.contains(item)) { + ret.add(item); + } + } + + return ret; + } else { + return items; + } } @Override public int getSectionCount() { - return mSyncFolderItems.size(); + if (filteredSyncFolderItems.size() > 0) { + return filteredSyncFolderItems.size() + 1; + } else { + return 0; + } } @Override public int getItemCount(int section) { - List filePaths = mSyncFolderItems.get(section).getFilePaths(); + if (section < filteredSyncFolderItems.size()) { + List filePaths = filteredSyncFolderItems.get(section).getFilePaths(); - if (filePaths != null) { - return mSyncFolderItems.get(section).getFilePaths().size(); + if (filePaths != null) { + return filteredSyncFolderItems.get(section).getFilePaths().size(); + } else { + return 1; + } } else { return 1; } } public SyncedFolderDisplayItem get(int section) { - return mSyncFolderItems.get(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(); } /** @@ -122,9 +228,9 @@ public SyncedFolderDisplayItem get(int section) { * @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 < mSyncFolderItems.size(); i++) { - if (mSyncFolderItems.get(i).getLocalPath().equalsIgnoreCase(localPath) && - mSyncFolderItems.get(i).getType().getId().equals(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; } } @@ -134,70 +240,95 @@ public int getSectionByLocalPathAndType(String localPath, int type) { @Override public void onBindHeaderViewHolder(SectionedViewHolder commonHolder, final int section, boolean expanded) { - HeaderViewHolder holder = (HeaderViewHolder) commonHolder; + 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.mainHeaderContainer.setVisibility(View.VISIBLE); + 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)); + } + } + } - holder.title.setText(mSyncFolderItems.get(section).getFolderName()); + 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)); - if (MediaFolderType.VIDEO == mSyncFolderItems.get(section).getType()) { - holder.type.setImageResource(R.drawable.video_32dp); - } else if (MediaFolderType.IMAGE == mSyncFolderItems.get(section).getType()) { - holder.type.setImageResource(R.drawable.image_32dp); + if (item.isHidden()) { + popup.getMenu() + .findItem(R.id.action_auto_upload_folder_toggle_visibility) + .setTitle(R.string.autoupload_show_folder); } else { - holder.type.setImageResource(R.drawable.folder_star_32dp); + popup.getMenu() + .findItem(R.id.action_auto_upload_folder_toggle_visibility) + .setTitle(R.string.autoupload_hide_folder); } + popup.show(); + } - holder.syncStatusButton.setVisibility(View.VISIBLE); - holder.syncStatusButton.setTag(section); - holder.syncStatusButton.setOnClickListener(v -> { - mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled(), clock.getCurrentTime()); - setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled()); - mListener.onSyncStatusToggleClick(section, mSyncFolderItems.get(section)); - }); - setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled()); - - holder.syncStatusButton.setVisibility(View.VISIBLE); - holder.syncStatusButton.setTag(section); - holder.syncStatusButton.setOnClickListener(v -> { - mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled(), clock.getCurrentTime()); - setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled()); - mListener.onSyncStatusToggleClick(section, mSyncFolderItems.get(section)); - }); - setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled()); - - if (mLight) { - holder.menuButton.setVisibility(View.GONE); + 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 { - holder.menuButton.setVisibility(View.VISIBLE); - holder.menuButton.setTag(section); - holder.menuButton.setOnClickListener(v -> mListener.onSyncFolderSettingsClick(section, - mSyncFolderItems.get(section))); + // default: R.id.action_create_custom_folder + clickListener.onSyncFolderSettingsClick(section, item); } + return true; } @Override public void onBindFooterViewHolder(SectionedViewHolder holder, int section) { - // not needed + if (isLastSection(section) && showFooter()) { + FooterViewHolder footerHolder = (FooterViewHolder) holder; + footerHolder.title.setOnClickListener(v -> toggleHiddenItemsVisibility()); + } } - @Override public void onBindViewHolder(SectionedViewHolder commonHolder, int section, int relativePosition, int absolutePosition) { - if (mSyncFolderItems.get(section).getFilePaths() != null) { + if (section < filteredSyncFolderItems.size() && filteredSyncFolderItems.get(section).getFilePaths() != null) { MainViewHolder holder = (MainViewHolder) commonHolder; - File file = new File(mSyncFolderItems.get(section).getFilePaths().get(relativePosition)); + File file = new File(filteredSyncFolderItems.get(section).getFilePaths().get(relativePosition)); ThumbnailsCacheManager.MediaThumbnailGenerationTask task = - new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.image, mContext); + new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.image, context); ThumbnailsCacheManager.AsyncMediaThumbnailDrawable asyncDrawable = new ThumbnailsCacheManager.AsyncMediaThumbnailDrawable( - mContext.getResources(), - ThumbnailsCacheManager.mDefaultImg, - task + context.getResources(), + ThumbnailsCacheManager.mDefaultImg, + task ); holder.image.setImageDrawable(asyncDrawable); @@ -206,11 +337,11 @@ public void onBindViewHolder(SectionedViewHolder commonHolder, int section, int // set proper tag holder.image.setTag(file.hashCode()); - holder.itemView.setTag(relativePosition % mGridWidth); + holder.itemView.setTag(relativePosition % gridWidth); - if (mSyncFolderItems.get(section).getNumberOfFiles() > mGridTotal && relativePosition >= mGridTotal - 1) { + if (filteredSyncFolderItems.get(section).getNumberOfFiles() > gridTotal && relativePosition >= gridTotal - 1) { holder.counterValue.setText(String.format(Locale.US, "%d", - mSyncFolderItems.get(section).getNumberOfFiles() - mGridTotal)); + filteredSyncFolderItems.get(section).getNumberOfFiles() - gridTotal)); holder.counterBar.setVisibility(View.VISIBLE); holder.thumbnailDarkener.setVisibility(View.VISIBLE); } else { @@ -226,15 +357,26 @@ public SectionedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int vie 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 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 { @@ -259,7 +401,29 @@ private HeaderViewHolder(View 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; @@ -281,7 +445,7 @@ private MainViewHolder(View itemView) { private void setSyncButtonActiveIcon(ImageButton syncStatusButton, boolean enabled) { if (enabled) { syncStatusButton.setImageDrawable(ThemeUtils.tintDrawable(R.drawable.ic_cloud_sync_on, - ThemeUtils.primaryColor(mContext))); + ThemeUtils.primaryColor(context))); } else { syncStatusButton.setImageResource(R.drawable.ic_cloud_sync_off); } diff --git a/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java b/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java index c435857cc961..d867e568a4c6 100644 --- a/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java +++ b/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java @@ -34,63 +34,67 @@ */ @NoArgsConstructor public class SyncedFolderParcelable implements Parcelable { - private String mFolderName; - private String mLocalPath; - private String mRemotePath; - private Boolean mWifiOnly = false; - private Boolean mChargingOnly = false; - private Boolean mEnabled = false; - private Boolean mSubfolderByDate = false; - private Integer mUploadAction; - private MediaFolderType mType; - private long mId; - private String mAccount; - private int mSection; + private String folderName; + private String localPath; + private String remotePath; + private Boolean wifiOnly = false; + private Boolean chargingOnly = false; + private Boolean enabled = false; + private Boolean subfolderByDate = false; + private Integer uploadAction; + private MediaFolderType type; + private Boolean hidden = false; + private long id; + private String account; + private int section; public SyncedFolderParcelable(SyncedFolderDisplayItem syncedFolderDisplayItem, int section) { - mId = syncedFolderDisplayItem.getId(); - mFolderName = syncedFolderDisplayItem.getFolderName(); - mLocalPath = syncedFolderDisplayItem.getLocalPath(); - mRemotePath = syncedFolderDisplayItem.getRemotePath(); - mWifiOnly = syncedFolderDisplayItem.getWifiOnly(); - mChargingOnly = syncedFolderDisplayItem.getChargingOnly(); - mEnabled = syncedFolderDisplayItem.isEnabled(); - mSubfolderByDate = syncedFolderDisplayItem.getSubfolderByDate(); - mType = syncedFolderDisplayItem.getType(); - mAccount = syncedFolderDisplayItem.getAccount(); - mUploadAction = syncedFolderDisplayItem.getUploadAction(); - mSection = section; + id = syncedFolderDisplayItem.getId(); + folderName = syncedFolderDisplayItem.getFolderName(); + localPath = syncedFolderDisplayItem.getLocalPath(); + remotePath = syncedFolderDisplayItem.getRemotePath(); + wifiOnly = syncedFolderDisplayItem.getWifiOnly(); + chargingOnly = syncedFolderDisplayItem.getChargingOnly(); + enabled = syncedFolderDisplayItem.isEnabled(); + subfolderByDate = syncedFolderDisplayItem.getSubfolderByDate(); + type = syncedFolderDisplayItem.getType(); + account = syncedFolderDisplayItem.getAccount(); + uploadAction = syncedFolderDisplayItem.getUploadAction(); + this.section = section; + hidden = syncedFolderDisplayItem.getHidden(); } private SyncedFolderParcelable(Parcel read) { - mId = read.readLong(); - mFolderName = read.readString(); - mLocalPath = read.readString(); - mRemotePath = read.readString(); - mWifiOnly = read.readInt()!= 0; - mChargingOnly = read.readInt() != 0; - mEnabled = read.readInt() != 0; - mSubfolderByDate = read.readInt() != 0; - mType = MediaFolderType.getById(read.readInt()); - mAccount = read.readString(); - mUploadAction = read.readInt(); - mSection = read.readInt(); + id = read.readLong(); + folderName = read.readString(); + localPath = read.readString(); + remotePath = read.readString(); + wifiOnly = read.readInt()!= 0; + chargingOnly = read.readInt() != 0; + enabled = read.readInt() != 0; + subfolderByDate = read.readInt() != 0; + type = MediaFolderType.getById(read.readInt()); + account = read.readString(); + uploadAction = read.readInt(); + section = read.readInt(); + hidden = read.readInt() != 0; } @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mId); - dest.writeString(mFolderName); - dest.writeString(mLocalPath); - dest.writeString(mRemotePath); - dest.writeInt(mWifiOnly ? 1 : 0); - dest.writeInt(mChargingOnly ? 1 : 0); - dest.writeInt(mEnabled ? 1 : 0); - dest.writeInt(mSubfolderByDate ? 1 : 0); - dest.writeInt(mType.getId()); - dest.writeString(mAccount); - dest.writeInt(mUploadAction); - dest.writeInt(mSection); + dest.writeLong(id); + dest.writeString(folderName); + dest.writeString(localPath); + dest.writeString(remotePath); + dest.writeInt(wifiOnly ? 1 : 0); + dest.writeInt(chargingOnly ? 1 : 0); + dest.writeInt(enabled ? 1 : 0); + dest.writeInt(subfolderByDate ? 1 : 0); + dest.writeInt(type.getId()); + dest.writeString(account); + dest.writeInt(uploadAction); + dest.writeInt(section); + dest.writeInt(hidden ? 1 : 0); } public static final Creator CREATOR = @@ -113,75 +117,83 @@ public int describeContents() { } public String getFolderName() { - return mFolderName; + return folderName; } public void setFolderName(String mFolderName) { - this.mFolderName = mFolderName; + this.folderName = mFolderName; } public String getLocalPath() { - return mLocalPath; + return localPath; } public void setLocalPath(String mLocalPath) { - this.mLocalPath = mLocalPath; + this.localPath = mLocalPath; } public String getRemotePath() { - return mRemotePath; + return remotePath; } public void setRemotePath(String mRemotePath) { - this.mRemotePath = mRemotePath; + this.remotePath = mRemotePath; } public Boolean getWifiOnly() { - return mWifiOnly; + return wifiOnly; } public void setWifiOnly(Boolean mWifiOnly) { - this.mWifiOnly = mWifiOnly; + this.wifiOnly = mWifiOnly; } public Boolean getChargingOnly() { - return mChargingOnly; + return chargingOnly; } public void setChargingOnly(Boolean mChargingOnly) { - this.mChargingOnly = mChargingOnly; + this.chargingOnly = mChargingOnly; } public Boolean getEnabled() { - return mEnabled; + return enabled; } public void setEnabled(boolean mEnabled) { - this.mEnabled = mEnabled; + this.enabled = mEnabled; } public Boolean getSubfolderByDate() { - return mSubfolderByDate; + return subfolderByDate; } public void setSubfolderByDate(Boolean mSubfolderByDate) { - this.mSubfolderByDate = mSubfolderByDate; + this.subfolderByDate = mSubfolderByDate; } public MediaFolderType getType() { - return mType; + return type; } public void setType(MediaFolderType mType) { - this.mType = mType; + this.type = mType; + } + + public Boolean getHidden() { + return hidden; + } + + public void setHidden(boolean mHidden) { + this.hidden = mHidden; } public Integer getUploadAction() { - return mUploadAction; + return uploadAction; } public Integer getUploadActionInteger() { - switch (mUploadAction) { + switch (uploadAction) { case FileUploader.LOCAL_BEHAVIOUR_FORGET: return 0; case FileUploader.LOCAL_BEHAVIOUR_MOVE: @@ -195,38 +207,38 @@ public Integer getUploadActionInteger() { public void setUploadAction(String mUploadAction) { switch (mUploadAction) { case "LOCAL_BEHAVIOUR_FORGET": - this.mUploadAction = FileUploader.LOCAL_BEHAVIOUR_FORGET; + this.uploadAction = FileUploader.LOCAL_BEHAVIOUR_FORGET; break; case "LOCAL_BEHAVIOUR_MOVE": - this.mUploadAction = FileUploader.LOCAL_BEHAVIOUR_MOVE; + this.uploadAction = FileUploader.LOCAL_BEHAVIOUR_MOVE; break; case "LOCAL_BEHAVIOUR_DELETE": - this.mUploadAction = FileUploader.LOCAL_BEHAVIOUR_DELETE; + this.uploadAction = FileUploader.LOCAL_BEHAVIOUR_DELETE; break; } } public long getId() { - return mId; + return id; } - public void setId(long mId) { - this.mId = mId; + public void setId(long id) { + this.id = id; } public String getAccount() { - return mAccount; + return account; } - public void setAccount(String mAccount) { - this.mAccount = mAccount; + public void setAccount(String account) { + this.account = account; } public int getSection() { - return mSection; + return section; } - public void setSection(int mSection) { - this.mSection = mSection; + public void setSection(int section) { + this.section = section; } } diff --git a/src/main/res/layout/synced_folders_empty.xml b/src/main/res/layout/synced_folders_empty.xml new file mode 100644 index 000000000000..b17c9141d0d0 --- /dev/null +++ b/src/main/res/layout/synced_folders_empty.xml @@ -0,0 +1,6 @@ + + + + diff --git a/src/main/res/layout/synced_folders_footer.xml b/src/main/res/layout/synced_folders_footer.xml new file mode 100644 index 000000000000..1112c5d0649a --- /dev/null +++ b/src/main/res/layout/synced_folders_footer.xml @@ -0,0 +1,38 @@ + + + + + + + diff --git a/src/main/res/menu/synced_folders_adapter.xml b/src/main/res/menu/synced_folders_adapter.xml new file mode 100644 index 000000000000..50b8a92ea3df --- /dev/null +++ b/src/main/res/menu/synced_folders_adapter.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 185272de0e65..33ddc3bb7456 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -627,6 +627,9 @@ Set up a custom folder Create new custom folder setup + Show folder + Hide folder + Configure Configure folders @@ -901,4 +904,7 @@ folder file Share internal link + Hide folder in auto upload list + Hide folder + Show hidden folders diff --git a/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java b/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java index 2861b3e3c058..81de268fdab1 100644 --- a/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java +++ b/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java @@ -181,6 +181,7 @@ private SyncedFolderDisplayItem create(String folderName, Boolean enabled) { new ArrayList(), folderName, 2, - MediaFolderType.IMAGE); + MediaFolderType.IMAGE, + false); } } From ca6918f9fcd0ae309aad58ba80d247fc9eb9062e Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sat, 2 Nov 2019 18:06:20 +0100 Subject: [PATCH 2/9] show/hide improvements when list is completed hidden + nicer empty UI + action button Signed-off-by: Andy Scherzinger --- .../ui/activity/SyncedFoldersActivity.java | 121 +++++++++++++++--- .../ui/adapter/SyncedFolderAdapter.java | 23 ++++ src/main/res/layout/empty_list.xml | 16 ++- src/main/res/layout/synced_folders_layout.xml | 34 +---- src/main/res/menu/synced_folders_adapter.xml | 2 +- src/main/res/values/strings.xml | 10 +- 6 files changed, 151 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java index 3d08d4193b4e..c5f8a70d842b 100644 --- a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java @@ -38,9 +38,12 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ProgressBar; import android.widget.TextView; +import com.google.android.material.button.MaterialButton; import com.nextcloud.client.account.User; import com.nextcloud.client.core.Clock; import com.nextcloud.client.device.PowerManagementService; @@ -89,6 +92,10 @@ import androidx.fragment.app.FragmentTransaction; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; import static android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS; import static com.owncloud.android.datamodel.SyncedFolderDisplayItem.UNPERSISTED_ID; @@ -104,10 +111,28 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA private static final String SYNCED_FOLDER_PREFERENCES_DIALOG_TAG = "SYNCED_FOLDER_PREFERENCES_DIALOG"; private static final String TAG = SyncedFoldersActivity.class.getSimpleName(); - private RecyclerView mRecyclerView; + @BindView(R.id.empty_list_view) + public LinearLayout emptyContentContainer; + + @BindView(R.id.empty_list_icon) + public ImageView emptyContentIcon; + + @BindView(R.id.empty_list_progress) + public ProgressBar emptyContentProgressBar; + + @BindView(R.id.empty_list_view_headline) + public TextView emptyContentHeadline; + + @BindView(R.id.empty_list_view_text) + public TextView emptyContentMessage; + + @BindView(R.id.empty_list_view_action) + public MaterialButton emptyContentActionButton; + + @BindView(android.R.id.list) + public RecyclerView mRecyclerView; + private SyncedFolderAdapter mAdapter; - private LinearLayout mProgress; - private TextView mEmpty; private SyncedFolderProvider mSyncedFolderProvider; private SyncedFolderPreferencesDialogFragment mSyncedFolderPreferencesDialogFragment; private boolean showSidebar = true; @@ -127,6 +152,7 @@ protected void onCreate(Bundle savedInstanceState) { } setContentView(R.layout.synced_folders_layout); + ButterKnife.bind(this); if (getIntent() != null && getIntent().getExtras() != null) { final String accountName = getIntent().getExtras().getString(NotificationJob.KEY_NOTIFICATION_ACCOUNT); @@ -220,15 +246,13 @@ private void showPowerCheckDialog() { * sets up the UI elements and loads all media/synced folders. */ private void setupContent() { - mRecyclerView = findViewById(android.R.id.list); - - mProgress = findViewById(android.R.id.progress); - mEmpty = findViewById(android.R.id.empty); - final int gridWidth = getResources().getInteger(R.integer.media_grid_width); boolean lightVersion = getResources().getBoolean(R.bool.syncedFolder_light); mAdapter = new SyncedFolderAdapter(this, clock, gridWidth, this, lightVersion); mSyncedFolderProvider = new SyncedFolderProvider(getContentResolver(), preferences, clock); + emptyContentIcon.setImageResource(R.drawable.nav_synced_folders); + emptyContentActionButton.setBackgroundColor(ThemeUtils.primaryColor(this)); + emptyContentActionButton.setTextColor(ThemeUtils.fontColor(this)); final GridLayoutManager lm = new GridLayoutManager(this, gridWidth); mAdapter.setLayoutManager(lm); @@ -240,6 +264,13 @@ private void setupContent() { load(gridWidth * 2, false); } + @OnClick(R.id.empty_list_view_action) + public void showHiddenItems() { + mAdapter.toggleHiddenItemsVisibility(); + emptyContentContainer.setVisibility(View.GONE); + mRecyclerView.setVisibility(View.VISIBLE); + } + /** * loads all media/synced folders, adds them to the recycler view adapter and shows the list. * @@ -249,7 +280,7 @@ private void load(final int perFolderMediaItemLimit, boolean force) { if (mAdapter.getItemCount() > 0 && !force) { return; } - setListShown(false); + showLoadingContent(); final List mediaFolders = MediaProvider.getImageFolders(getContentResolver(), perFolderMediaItemLimit, this, false); mediaFolders.addAll(MediaProvider.getVideoFolders(getContentResolver(), perFolderMediaItemLimit, @@ -274,7 +305,7 @@ private void load(final int perFolderMediaItemLimit, boolean force) { mAdapter.setSyncFolderItems(syncFolderItems); mAdapter.notifyDataSetChanged(); - setListShown(true); + showList(); if (!TextUtils.isEmpty(path)) { int section = mAdapter.getSectionByLocalPathAndType(path, type); @@ -493,15 +524,31 @@ private Map createSyncedFoldersMap(List sync } /** - * show/hide recycler view list or the empty message / progress info. - * - * @param shown flag if list should be shown + * show recycler view list or the empty message info (in case list is empty). */ - private void setListShown(boolean shown) { + private void showList() { if (mRecyclerView != null) { - mRecyclerView.setVisibility(shown ? View.VISIBLE : View.GONE); - mProgress.setVisibility(shown ? View.GONE : View.VISIBLE); - mEmpty.setVisibility(shown && mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + mRecyclerView.setVisibility(View.VISIBLE ); + emptyContentProgressBar.setVisibility(View.GONE); + + if (mAdapter.getSectionCount() == 0 && mAdapter.getUnfilteredSectionCount() > mAdapter.getSectionCount()) { + emptyContentContainer.setVisibility(View.VISIBLE); + int hiddenFoldersCount = mAdapter.getHiddenFolderCount(); + + showEmptyContent(getString(R.string.drawer_synced_folders), + getResources().getQuantityString(R.plurals.synced_folders_hidden_folders_count, + hiddenFoldersCount, + hiddenFoldersCount), + getResources().getQuantityString(R.plurals.synced_folders_show_hidden_folders, + hiddenFoldersCount, + hiddenFoldersCount)); + } else if (mAdapter.getSectionCount() == 0 && mAdapter.getUnfilteredSectionCount() == 0) { + emptyContentContainer.setVisibility(View.VISIBLE); + showEmptyContent(getString(R.string.drawer_synced_folders), + getString(R.string.synced_folders_no_results)); + } else { + emptyContentContainer.setVisibility(View.GONE); + } } } @@ -593,6 +640,45 @@ public void onVisibilityToggleClick(int section, SyncedFolderDisplayItem syncedF mAdapter.setSyncFolderItem(section, syncedFolder); } + private void showEmptyContent(String headline, String message) { + showEmptyContent(headline, message, false); + emptyContentActionButton.setVisibility(View.GONE); + } + + private void showEmptyContent(String headline, String message, String action) { + showEmptyContent(headline, message, false); + emptyContentActionButton.setText(action); + emptyContentActionButton.setVisibility(View.VISIBLE); + } + + private void showLoadingContent() { + showEmptyContent( + getString(R.string.drawer_synced_folders), + getString(R.string.synced_folders_loading_folders), + true + ); + emptyContentActionButton.setVisibility(View.GONE); + } + + private void showEmptyContent(String headline, String message, boolean loading) { + if (emptyContentContainer != null) { + emptyContentContainer.setVisibility(View.VISIBLE); + mRecyclerView.setVisibility(View.GONE); + + emptyContentHeadline.setText(headline); + emptyContentMessage.setText(message); + emptyContentMessage.setVisibility(View.VISIBLE); + + if (loading) { + emptyContentProgressBar.setVisibility(View.VISIBLE); + emptyContentIcon.setVisibility(View.GONE); + } else { + emptyContentProgressBar.setVisibility(View.GONE); + emptyContentIcon.setVisibility(View.VISIBLE); + } + } + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SyncedFolderPreferencesDialogFragment.REQUEST_CODE__SELECT_REMOTE_FOLDER @@ -742,7 +828,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String permissi @Override protected void onResume() { super.onResume(); - setDrawerMenuItemChecked(R.id.nav_synced_folders); } diff --git a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java index 2c636b1b3b87..1aa354dd89db 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java @@ -169,6 +169,14 @@ public int getSectionCount() { } } + public int getUnfilteredSectionCount() { + if (syncFolderItems.size() > 0) { + return syncFolderItems.size() + 1; + } else { + return 0; + } + } + @Override public int getItemCount(int section) { if (section < filteredSyncFolderItems.size()) { @@ -310,6 +318,13 @@ 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() + ) + ); } } @@ -373,6 +388,14 @@ 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); diff --git a/src/main/res/layout/empty_list.xml b/src/main/res/layout/empty_list.xml index 2951f2ae12c9..4dfc592e5fac 100644 --- a/src/main/res/layout/empty_list.xml +++ b/src/main/res/layout/empty_list.xml @@ -19,6 +19,7 @@ License along with this program. If not, see . --> @@ -62,7 +63,18 @@ android:layout_gravity="center_horizontal" android:ellipsize="end" android:gravity="center" + android:paddingTop="@dimen/standard_half_padding" + android:paddingBottom="@dimen/standard_half_padding" android:text="@string/file_list_empty" android:visibility="gone"/> - \ No newline at end of file + + + diff --git a/src/main/res/layout/synced_folders_layout.xml b/src/main/res/layout/synced_folders_layout.xml index 9973ea5bcc3d..2846dec1e0ab 100644 --- a/src/main/res/layout/synced_folders_layout.xml +++ b/src/main/res/layout/synced_folders_layout.xml @@ -50,39 +50,7 @@ android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> - - - - - - - - + + android:title="@string/autoupload_hide_folder" /> Choose remote folder… Choose local folder… Loading folders… - No media folders found. + No media folders found + + Show %1$d hidden folder + Show %1$d hidden folders + + + %1$d hidden folder + %1$d hidden folders + Preferences for auto uploading Instant uploading has been revamped completely. Re-configure your auto upload from within the main menu.\n\nEnjoy the new and extended auto uploading. For %1$s From bedc2b48ee104c7256df25424210e572034c5f63 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sat, 2 Nov 2019 18:21:24 +0100 Subject: [PATCH 3/9] housekeeping, removing unused resources Signed-off-by: Andy Scherzinger --- src/main/res/layout/synced_folders_footer.xml | 3 ++- src/main/res/values/dims.xml | 2 -- src/main/res/values/strings.xml | 3 --- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/res/layout/synced_folders_footer.xml b/src/main/res/layout/synced_folders_footer.xml index 1112c5d0649a..46cc018b65c5 100644 --- a/src/main/res/layout/synced_folders_footer.xml +++ b/src/main/res/layout/synced_folders_footer.xml @@ -18,6 +18,7 @@ License along with this program. If not, see . --> diff --git a/src/main/res/values/dims.xml b/src/main/res/values/dims.xml index 1db7bb7af6b7..42a3bd131bd6 100644 --- a/src/main/res/values/dims.xml +++ b/src/main/res/values/dims.xml @@ -133,8 +133,6 @@ 32dp 32dp 24dp - 72dp - 72dp -3dp 12dp 16sp diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index aa0edd4d13b6..d53671c4ccbe 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -912,7 +912,4 @@ folder file Share internal link - Hide folder in auto upload list - Hide folder - Show hidden folders From 7c62ad6b06492400ed7156d671fc73543c31f268 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sat, 2 Nov 2019 18:45:18 +0100 Subject: [PATCH 4/9] unify use of boolean, make use of lombok getter/setters, remove unneeded boolean boxing Signed-off-by: Andy Scherzinger --- .../datamodel/SyncedFolderProvider.java | 20 +-- .../owncloud/android/jobs/FilesSyncJob.java | 6 +- .../ui/activity/SyncedFoldersActivity.java | 21 ++- .../ui/adapter/SyncedFolderAdapter.java | 6 +- ...SyncedFolderPreferencesDialogFragment.java | 16 +- .../dialog/parcel/SyncedFolderParcelable.java | 140 +++--------------- .../activity/SyncedFoldersActivityTest.java | 12 +- 7 files changed, 56 insertions(+), 165 deletions(-) diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java index 6a8caf710671..f5fc3009d777 100644 --- a/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -338,23 +338,23 @@ private SyncedFolder createSyncedFolderFromCursor(Cursor cursor) { ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_LOCAL_PATH)); String remotePath = cursor.getString(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_REMOTE_PATH)); - Boolean wifiOnly = cursor.getInt(cursor.getColumnIndex( + boolean wifiOnly = cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_WIFI_ONLY)) == 1; - Boolean chargingOnly = cursor.getInt(cursor.getColumnIndex( + boolean chargingOnly = cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_CHARGING_ONLY)) == 1; - Boolean subfolderByDate = cursor.getInt(cursor.getColumnIndex( + boolean subfolderByDate = cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE)) == 1; String accountName = cursor.getString(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ACCOUNT)); - Integer uploadAction = cursor.getInt(cursor.getColumnIndex( + int uploadAction = cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION)); - Boolean enabled = cursor.getInt(cursor.getColumnIndex( + boolean enabled = cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED)) == 1; long enabledTimestampMs = cursor.getLong(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS)); MediaFolderType type = MediaFolderType.getById(cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE))); - Boolean hidden = cursor.getInt(cursor.getColumnIndex( + boolean hidden = cursor.getInt(cursor.getColumnIndex( ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN)) == 1; syncedFolder = new SyncedFolder(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, @@ -374,15 +374,15 @@ private ContentValues createContentValuesFromSyncedFolder(SyncedFolder syncedFol ContentValues cv = new ContentValues(); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_LOCAL_PATH, syncedFolder.getLocalPath()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_REMOTE_PATH, syncedFolder.getRemotePath()); - cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_WIFI_ONLY, syncedFolder.getWifiOnly()); - cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_CHARGING_ONLY, syncedFolder.getChargingOnly()); + cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_WIFI_ONLY, syncedFolder.isWifiOnly()); + cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_CHARGING_ONLY, syncedFolder.isChargingOnly()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED, syncedFolder.isEnabled()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS, syncedFolder.getEnabledTimestampMs()); - cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE, syncedFolder.getSubfolderByDate()); + cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE, syncedFolder.isSubfolderByDate()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ACCOUNT, syncedFolder.getAccount()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION, syncedFolder.getUploadAction()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE, syncedFolder.getType().getId()); - cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN, syncedFolder.getHidden()); + cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN, syncedFolder.isHidden()); return cv; } diff --git a/src/main/java/com/owncloud/android/jobs/FilesSyncJob.java b/src/main/java/com/owncloud/android/jobs/FilesSyncJob.java index 5c7a9771aac1..32b3002d7f9c 100644 --- a/src/main/java/com/owncloud/android/jobs/FilesSyncJob.java +++ b/src/main/java/com/owncloud/android/jobs/FilesSyncJob.java @@ -192,10 +192,10 @@ private void syncFolder(Context context, Resources resources, boolean lightVersi remotePath = resources.getString(R.string.syncedFolder_remote_folder); } else { - needsCharging = syncedFolder.getChargingOnly(); - needsWifi = syncedFolder.getWifiOnly(); + needsCharging = syncedFolder.isChargingOnly(); + needsWifi = syncedFolder.isWifiOnly(); uploadAction = syncedFolder.getUploadAction(); - subfolderByDate = syncedFolder.getSubfolderByDate(); + subfolderByDate = syncedFolder.isSubfolderByDate(); remotePath = syncedFolder.getRemotePath(); } diff --git a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java index c5f8a70d842b..e683d1cff003 100644 --- a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java @@ -95,7 +95,6 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; -import butterknife.Unbinder; import static android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS; import static com.owncloud.android.datamodel.SyncedFolderDisplayItem.UNPERSISTED_ID; @@ -702,9 +701,9 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { if (MediaFolderType.CUSTOM == syncedFolder.getType() && syncedFolder.getId() == UNPERSISTED_ID) { SyncedFolderDisplayItem newCustomFolder = new SyncedFolderDisplayItem( SyncedFolder.UNPERSISTED_ID, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), - syncedFolder.getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(), - syncedFolder.getAccount(), syncedFolder.getUploadAction(), syncedFolder.getEnabled(), - clock.getCurrentTime(), new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType(), syncedFolder.getHidden()); + syncedFolder.isWifiOnly(), syncedFolder.isChargingOnly(), syncedFolder.isSubfolderByDate(), + syncedFolder.getAccount(), syncedFolder.getUploadAction(), syncedFolder.isEnabled(), + clock.getCurrentTime(), new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType(), syncedFolder.isHidden()); saveOrUpdateSyncedFolder(newCustomFolder); mAdapter.addSyncFolderItem(newCustomFolder); @@ -712,8 +711,8 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { SyncedFolderDisplayItem item = mAdapter.get(syncedFolder.getSection()); updateSyncedFolderItem(item, syncedFolder.getId(), syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), syncedFolder - .getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(), syncedFolder - .getUploadAction(), syncedFolder.getEnabled()); + .isWifiOnly(), syncedFolder.isChargingOnly(), syncedFolder.isSubfolderByDate(), syncedFolder + .getUploadAction(), syncedFolder.isEnabled()); saveOrUpdateSyncedFolder(item); @@ -723,7 +722,7 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { mSyncedFolderPreferencesDialogFragment = null; - if (syncedFolder.getEnabled()) { + if (syncedFolder.isEnabled()) { showBatteryOptimizationInfo(); } } @@ -789,11 +788,11 @@ private void updateSyncedFolderItem(SyncedFolderDisplayItem item, long id, String localPath, String remotePath, - Boolean wifiOnly, - Boolean chargingOnly, - Boolean subfolderByDate, + boolean wifiOnly, + boolean chargingOnly, + boolean subfolderByDate, Integer uploadAction, - Boolean enabled) { + boolean enabled) { item.setId(id); item.setLocalPath(localPath); item.setRemotePath(remotePath); diff --git a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java index 1aa354dd89db..f595d76a953e 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java @@ -145,7 +145,9 @@ public void removeItem(int section) { * @return Non-hidden items */ private List filterHiddenItems(List items, boolean hide) { - if (hide) { + if (!hide) { + return items; + } else { List ret = new ArrayList<>(); for (SyncedFolderDisplayItem item : items) { @@ -155,8 +157,6 @@ private List filterHiddenItems(List= Build.VERSION_CODES.JELLY_BEAN_MR1) { - mUploadOnChargingCheckbox.setChecked(mSyncedFolder.getChargingOnly()); + mUploadOnChargingCheckbox.setChecked(mSyncedFolder.isChargingOnly()); } - mUploadUseSubfoldersCheckbox.setChecked(mSyncedFolder.getSubfolderByDate()); + mUploadUseSubfoldersCheckbox.setChecked(mSyncedFolder.isSubfolderByDate()); mUploadBehaviorSummary.setText(mUploadBehaviorItemStrings[mSyncedFolder.getUploadActionInteger()]); } @@ -344,7 +344,7 @@ private void setupListeners(View view) { new OnClickListener() { @Override public void onClick(View v) { - mSyncedFolder.setWifiOnly(!mSyncedFolder.getWifiOnly()); + mSyncedFolder.setWifiOnly(!mSyncedFolder.isWifiOnly()); mUploadOnWifiCheckbox.toggle(); } }); @@ -355,7 +355,7 @@ public void onClick(View v) { new OnClickListener() { @Override public void onClick(View v) { - mSyncedFolder.setChargingOnly(!mSyncedFolder.getChargingOnly()); + mSyncedFolder.setChargingOnly(!mSyncedFolder.isChargingOnly()); mUploadOnChargingCheckbox.toggle(); } }); @@ -365,7 +365,7 @@ public void onClick(View v) { new OnClickListener() { @Override public void onClick(View v) { - mSyncedFolder.setSubfolderByDate(!mSyncedFolder.getSubfolderByDate()); + mSyncedFolder.setSubfolderByDate(!mSyncedFolder.isSubfolderByDate()); mUploadUseSubfoldersCheckbox.toggle(); } }); @@ -401,7 +401,7 @@ public void onClick(View v) { view.findViewById(R.id.sync_enabled).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - setEnabled(!mSyncedFolder.getEnabled()); + setEnabled(!mSyncedFolder.isEnabled()); } }); diff --git a/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java b/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java index d867e568a4c6..2152eeb29e83 100644 --- a/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java +++ b/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java @@ -27,41 +27,43 @@ import com.owncloud.android.datamodel.SyncedFolderDisplayItem; import com.owncloud.android.files.services.FileUploader; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; /** * Parcelable for {@link SyncedFolderDisplayItem} objects to transport them from/to dialog fragments. */ @NoArgsConstructor public class SyncedFolderParcelable implements Parcelable { - private String folderName; - private String localPath; - private String remotePath; - private Boolean wifiOnly = false; - private Boolean chargingOnly = false; - private Boolean enabled = false; - private Boolean subfolderByDate = false; - private Integer uploadAction; - private MediaFolderType type; - private Boolean hidden = false; - private long id; - private String account; - private int section; + @Getter @Setter private String folderName; + @Getter @Setter private String localPath; + @Getter @Setter private String remotePath; + @Getter @Setter private boolean wifiOnly = false; + @Getter @Setter private boolean chargingOnly = false; + @Getter @Setter private boolean enabled = false; + @Getter @Setter private boolean subfolderByDate = false; + @Getter private Integer uploadAction; + @Getter @Setter private MediaFolderType type; + @Getter @Setter private boolean hidden = false; + @Getter @Setter private long id; + @Getter @Setter private String account; + @Getter @Setter private int section; public SyncedFolderParcelable(SyncedFolderDisplayItem syncedFolderDisplayItem, int section) { id = syncedFolderDisplayItem.getId(); folderName = syncedFolderDisplayItem.getFolderName(); localPath = syncedFolderDisplayItem.getLocalPath(); remotePath = syncedFolderDisplayItem.getRemotePath(); - wifiOnly = syncedFolderDisplayItem.getWifiOnly(); - chargingOnly = syncedFolderDisplayItem.getChargingOnly(); + wifiOnly = syncedFolderDisplayItem.isWifiOnly(); + chargingOnly = syncedFolderDisplayItem.isChargingOnly(); enabled = syncedFolderDisplayItem.isEnabled(); - subfolderByDate = syncedFolderDisplayItem.getSubfolderByDate(); + subfolderByDate = syncedFolderDisplayItem.isSubfolderByDate(); type = syncedFolderDisplayItem.getType(); account = syncedFolderDisplayItem.getAccount(); uploadAction = syncedFolderDisplayItem.getUploadAction(); this.section = section; - hidden = syncedFolderDisplayItem.getHidden(); + hidden = syncedFolderDisplayItem.isHidden(); } private SyncedFolderParcelable(Parcel read) { @@ -116,82 +118,6 @@ public int describeContents() { return 0; } - public String getFolderName() { - return folderName; - } - - public void setFolderName(String mFolderName) { - this.folderName = mFolderName; - } - - public String getLocalPath() { - return localPath; - } - - public void setLocalPath(String mLocalPath) { - this.localPath = mLocalPath; - } - - public String getRemotePath() { - return remotePath; - } - - public void setRemotePath(String mRemotePath) { - this.remotePath = mRemotePath; - } - - public Boolean getWifiOnly() { - return wifiOnly; - } - - public void setWifiOnly(Boolean mWifiOnly) { - this.wifiOnly = mWifiOnly; - } - - public Boolean getChargingOnly() { - return chargingOnly; - } - - public void setChargingOnly(Boolean mChargingOnly) { - this.chargingOnly = mChargingOnly; - } - - public Boolean getEnabled() { - return enabled; - } - - public void setEnabled(boolean mEnabled) { - this.enabled = mEnabled; - } - - public Boolean getSubfolderByDate() { - return subfolderByDate; - } - - public void setSubfolderByDate(Boolean mSubfolderByDate) { - this.subfolderByDate = mSubfolderByDate; - } - - public MediaFolderType getType() { - return type; - } - - public void setType(MediaFolderType mType) { - this.type = mType; - } - - public Boolean getHidden() { - return hidden; - } - - public void setHidden(boolean mHidden) { - this.hidden = mHidden; - } - - public Integer getUploadAction() { - return uploadAction; - } - public Integer getUploadActionInteger() { switch (uploadAction) { case FileUploader.LOCAL_BEHAVIOUR_FORGET: @@ -204,8 +130,8 @@ public Integer getUploadActionInteger() { return 0; } - public void setUploadAction(String mUploadAction) { - switch (mUploadAction) { + public void setUploadAction(String uploadAction) { + switch (uploadAction) { case "LOCAL_BEHAVIOUR_FORGET": this.uploadAction = FileUploader.LOCAL_BEHAVIOUR_FORGET; break; @@ -217,28 +143,4 @@ public void setUploadAction(String mUploadAction) { break; } } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getAccount() { - return account; - } - - public void setAccount(String account) { - this.account = account; - } - - public int getSection() { - return section; - } - - public void setSection(int section) { - this.section = section; - } } diff --git a/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java b/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java index 81de268fdab1..50046bb01bb3 100644 --- a/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java +++ b/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java @@ -32,8 +32,6 @@ import java.util.Collections; import java.util.List; -import third_parties.daveKoeller.AlphanumComparator; - import static org.junit.Assert.assertTrue; public class SyncedFoldersActivityTest { @@ -123,14 +121,6 @@ private boolean sortAndTest(List sortedList) { return test(sortedList, SyncedFoldersActivity.sortSyncedFolderItems(unsortedList)); } - private List sort(List sortedList) { - List unsortedList = shuffle(sortedList); - - Collections.sort(unsortedList, new AlphanumComparator<>()); - - return unsortedList; - } - private boolean test(List target, List actual) { for (int i = 0; i < target.size(); i++) { @@ -167,7 +157,7 @@ private boolean test(List target, List Date: Sat, 2 Nov 2019 21:51:04 +0000 Subject: [PATCH 5/9] Drone: update FindBugs results to reflect reduced error/warning count [skip ci] Signed-off-by: nextcloud-android-bot --- scripts/analysis/findbugs-results.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/analysis/findbugs-results.txt b/scripts/analysis/findbugs-results.txt index 2da56739379b..8e9088e93bac 100644 --- a/scripts/analysis/findbugs-results.txt +++ b/scripts/analysis/findbugs-results.txt @@ -1 +1 @@ -418 \ No newline at end of file +411 \ No newline at end of file From 3e872df68cee31c2fa109107ee37b41930ab87eb Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sat, 2 Nov 2019 23:02:58 +0100 Subject: [PATCH 6/9] add more spotbug exclusions (for 3rd party libs) Signed-off-by: Andy Scherzinger --- spotbugs-filter.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spotbugs-filter.xml b/spotbugs-filter.xml index 05c145793143..1b374ca4fed1 100644 --- a/spotbugs-filter.xml +++ b/spotbugs-filter.xml @@ -17,7 +17,8 @@ - + + @@ -30,7 +31,7 @@ - + @@ -39,6 +40,10 @@ + + + + From 74bfe473c498d1a36fb5542ff79f14cc1c51304c Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 5 Nov 2019 22:26:39 +0100 Subject: [PATCH 7/9] remove action button, use checkable menu item for shown/hidden state display (design review) Signed-off-by: Andy Scherzinger --- .../ui/activity/SyncedFoldersActivity.java | 27 +++++-------------- .../ui/adapter/SyncedFolderAdapter.java | 14 +++------- src/main/res/layout/empty_list.xml | 11 -------- src/main/res/menu/synced_folders_adapter.xml | 3 ++- src/main/res/values/strings.xml | 5 ---- 5 files changed, 12 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java index e683d1cff003..a0d4bb9c4c00 100644 --- a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java @@ -43,7 +43,6 @@ import android.widget.ProgressBar; import android.widget.TextView; -import com.google.android.material.button.MaterialButton; import com.nextcloud.client.account.User; import com.nextcloud.client.core.Clock; import com.nextcloud.client.device.PowerManagementService; @@ -125,9 +124,6 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA @BindView(R.id.empty_list_view_text) public TextView emptyContentMessage; - @BindView(R.id.empty_list_view_action) - public MaterialButton emptyContentActionButton; - @BindView(android.R.id.list) public RecyclerView mRecyclerView; @@ -250,8 +246,6 @@ private void setupContent() { mAdapter = new SyncedFolderAdapter(this, clock, gridWidth, this, lightVersion); mSyncedFolderProvider = new SyncedFolderProvider(getContentResolver(), preferences, clock); emptyContentIcon.setImageResource(R.drawable.nav_synced_folders); - emptyContentActionButton.setBackgroundColor(ThemeUtils.primaryColor(this)); - emptyContentActionButton.setTextColor(ThemeUtils.fontColor(this)); final GridLayoutManager lm = new GridLayoutManager(this, gridWidth); mAdapter.setLayoutManager(lm); @@ -263,11 +257,13 @@ private void setupContent() { load(gridWidth * 2, false); } - @OnClick(R.id.empty_list_view_action) + @OnClick(R.id.empty_list_view_text) public void showHiddenItems() { - mAdapter.toggleHiddenItemsVisibility(); - emptyContentContainer.setVisibility(View.GONE); - mRecyclerView.setVisibility(View.VISIBLE); + if (mAdapter.getSectionCount() == 0 && mAdapter.getUnfilteredSectionCount() > mAdapter.getSectionCount()) { + mAdapter.toggleHiddenItemsVisibility(); + emptyContentContainer.setVisibility(View.GONE); + mRecyclerView.setVisibility(View.VISIBLE); + } } /** @@ -535,9 +531,6 @@ private void showList() { int hiddenFoldersCount = mAdapter.getHiddenFolderCount(); showEmptyContent(getString(R.string.drawer_synced_folders), - getResources().getQuantityString(R.plurals.synced_folders_hidden_folders_count, - hiddenFoldersCount, - hiddenFoldersCount), getResources().getQuantityString(R.plurals.synced_folders_show_hidden_folders, hiddenFoldersCount, hiddenFoldersCount)); @@ -641,13 +634,6 @@ public void onVisibilityToggleClick(int section, SyncedFolderDisplayItem syncedF private void showEmptyContent(String headline, String message) { showEmptyContent(headline, message, false); - emptyContentActionButton.setVisibility(View.GONE); - } - - private void showEmptyContent(String headline, String message, String action) { - showEmptyContent(headline, message, false); - emptyContentActionButton.setText(action); - emptyContentActionButton.setVisibility(View.VISIBLE); } private void showLoadingContent() { @@ -656,7 +642,6 @@ private void showLoadingContent() { getString(R.string.synced_folders_loading_folders), true ); - emptyContentActionButton.setVisibility(View.GONE); } private void showEmptyContent(String headline, String message, boolean loading) { diff --git a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java index f595d76a953e..c0eba3eda368 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java @@ -289,17 +289,11 @@ public void onBindHeaderViewHolder(SectionedViewHolder commonHolder, final int s 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.setOnMenuItemClickListener(i -> optionsItemSelected(i, section, item)); + popup.getMenu() + .findItem(R.id.action_auto_upload_folder_toggle_visibility) + .setChecked(item.isHidden()); - if (item.isHidden()) { - popup.getMenu() - .findItem(R.id.action_auto_upload_folder_toggle_visibility) - .setTitle(R.string.autoupload_show_folder); - } else { - popup.getMenu() - .findItem(R.id.action_auto_upload_folder_toggle_visibility) - .setTitle(R.string.autoupload_hide_folder); - } popup.show(); } diff --git a/src/main/res/layout/empty_list.xml b/src/main/res/layout/empty_list.xml index 4dfc592e5fac..f4ea188252e9 100644 --- a/src/main/res/layout/empty_list.xml +++ b/src/main/res/layout/empty_list.xml @@ -19,7 +19,6 @@ License along with this program. If not, see . --> - - diff --git a/src/main/res/menu/synced_folders_adapter.xml b/src/main/res/menu/synced_folders_adapter.xml index 9e6a6d08ad56..bab5c7cea05c 100644 --- a/src/main/res/menu/synced_folders_adapter.xml +++ b/src/main/res/menu/synced_folders_adapter.xml @@ -20,7 +20,8 @@ + android:title="@string/autoupload_hide_folder" + android:checkable="true"/> Show %1$d hidden folder Show %1$d hidden folders - - %1$d hidden folder - %1$d hidden folders - Preferences for auto uploading Instant uploading has been revamped completely. Re-configure your auto upload from within the main menu.\n\nEnjoy the new and extended auto uploading. For %1$s @@ -635,7 +631,6 @@ Set up a custom folder Create new custom folder setup - Show folder Hide folder Configure Configure folders From d17c8534936516a26f09e34cb484a292e660fc99 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 27 Nov 2019 21:33:38 +0100 Subject: [PATCH 8/9] re-add button/action and improve upon code review Signed-off-by: Andy Scherzinger --- .../android/datamodel/SyncedFolder.java | 29 +++- .../datamodel/SyncedFolderDisplayItem.java | 34 +++-- .../providers/FileContentProvider.java | 6 - .../ui/activity/SyncedFoldersActivity.java | 129 +++++++++++------- .../ui/adapter/SyncedFolderAdapter.java | 13 +- src/main/res/layout/empty_list.xml | 11 ++ 6 files changed, 142 insertions(+), 80 deletions(-) diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java index fa4d5823c38e..20a72eed10b0 100644 --- a/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java +++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java @@ -62,9 +62,17 @@ public class SyncedFolder implements Serializable, Cloneable { * @param type the type of the folder * @param hidden hide item flag */ - public SyncedFolder(String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, - boolean subfolderByDate, String account, int uploadAction, boolean enabled, - long timestampMs, MediaFolderType type, boolean hidden) { + public SyncedFolder(String localPath, + String remotePath, + boolean wifiOnly, + boolean chargingOnly, + boolean subfolderByDate, + String account, + int uploadAction, + boolean enabled, + long timestampMs, + MediaFolderType type, + boolean hidden) { this(UNPERSISTED_ID, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, timestampMs, type, hidden); } @@ -74,9 +82,18 @@ public SyncedFolder(String localPath, String remotePath, boolean wifiOnly, boole * * @param id id */ - protected SyncedFolder(long id, String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, - boolean subfolderByDate, String account, int uploadAction, boolean enabled, - long timestampMs, MediaFolderType type, boolean hidden) { + protected SyncedFolder(long id, + String localPath, + String remotePath, + boolean wifiOnly, + boolean chargingOnly, + boolean subfolderByDate, + String account, + int uploadAction, + boolean enabled, + long timestampMs, + MediaFolderType type, + boolean hidden) { this.id = id; this.localPath = localPath; this.remotePath = remotePath; diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java index 5b51b37e0154..09521e3bef4a 100644 --- a/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java +++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java @@ -55,11 +55,21 @@ public class SyncedFolderDisplayItem extends SyncedFolder { * @param type the type of the folder * @param hidden hide item flag */ - public SyncedFolderDisplayItem(long id, String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, - boolean subfolderByDate, String account, int uploadAction, boolean enabled, - long timestampMs, List filePaths, String folderName, long numberOfFiles, - MediaFolderType type, boolean hidden) - { + public SyncedFolderDisplayItem(long id, + String localPath, + String remotePath, + boolean wifiOnly, + boolean chargingOnly, + boolean subfolderByDate, + String account, + int uploadAction, + boolean enabled, + long timestampMs, + List filePaths, + String folderName, + long numberOfFiles, + MediaFolderType type, + boolean hidden) { super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, timestampMs, type, hidden); this.filePaths = filePaths; @@ -67,9 +77,17 @@ public SyncedFolderDisplayItem(long id, String localPath, String remotePath, boo this.numberOfFiles = numberOfFiles; } - public SyncedFolderDisplayItem(long id, String localPath, String remotePath, boolean wifiOnly, boolean chargingOnly, - boolean subfolderByDate, String account, int uploadAction, boolean enabled, - long timestampMs, String folderName, MediaFolderType type, boolean hidden) { + public SyncedFolderDisplayItem(long id, + String localPath, + String remotePath, + boolean wifiOnly, + boolean chargingOnly, + boolean subfolderByDate, + String account, + int uploadAction, + boolean enabled, + long timestampMs, + String folderName, MediaFolderType type, boolean hidden) { super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, timestampMs, type, hidden); this.folderName = folderName; diff --git a/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/src/main/java/com/owncloud/android/providers/FileContentProvider.java index d1bfda3b10fe..e66e5deb4428 100644 --- a/src/main/java/com/owncloud/android/providers/FileContentProvider.java +++ b/src/main/java/com/owncloud/android/providers/FileContentProvider.java @@ -2076,12 +2076,6 @@ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(ALTER_TABLE + ProviderTableMeta.CAPABILITIES_TABLE_NAME + REMOVE_COLUMN + ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION); } - - if(oldVersion == 50 && newVersion < 50) { - db.execSQL(ALTER_TABLE + ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME + - REMOVE_COLUMN + ProviderTableMeta.SYNCED_FOLDER_HIDDEN); - - } } } } diff --git a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java index a0d4bb9c4c00..6eb7b53f5ac6 100644 --- a/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java @@ -21,7 +21,6 @@ package com.owncloud.android.ui.activity; -import android.accounts.Account; import android.annotation.SuppressLint; import android.app.Activity; import android.app.NotificationManager; @@ -43,6 +42,7 @@ import android.widget.ProgressBar; import android.widget.TextView; +import com.google.android.material.button.MaterialButton; import com.nextcloud.client.account.User; import com.nextcloud.client.core.Clock; import com.nextcloud.client.device.PowerManagementService; @@ -124,12 +124,15 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA @BindView(R.id.empty_list_view_text) public TextView emptyContentMessage; + @BindView(R.id.empty_list_view_action) + public MaterialButton emptyContentActionButton; + @BindView(android.R.id.list) public RecyclerView mRecyclerView; - private SyncedFolderAdapter mAdapter; - private SyncedFolderProvider mSyncedFolderProvider; - private SyncedFolderPreferencesDialogFragment mSyncedFolderPreferencesDialogFragment; + private SyncedFolderAdapter adapter; + private SyncedFolderProvider syncedFolderProvider; + private SyncedFolderPreferencesDialogFragment syncedFolderPreferencesDialogFragment; private boolean showSidebar = true; private String path; @@ -243,24 +246,26 @@ private void showPowerCheckDialog() { private void setupContent() { final int gridWidth = getResources().getInteger(R.integer.media_grid_width); boolean lightVersion = getResources().getBoolean(R.bool.syncedFolder_light); - mAdapter = new SyncedFolderAdapter(this, clock, gridWidth, this, lightVersion); - mSyncedFolderProvider = new SyncedFolderProvider(getContentResolver(), preferences, clock); + adapter = new SyncedFolderAdapter(this, clock, gridWidth, this, lightVersion); + syncedFolderProvider = new SyncedFolderProvider(getContentResolver(), preferences, clock); emptyContentIcon.setImageResource(R.drawable.nav_synced_folders); + emptyContentActionButton.setBackgroundColor(ThemeUtils.primaryColor(this)); + emptyContentActionButton.setTextColor(ThemeUtils.fontColor(this)); final GridLayoutManager lm = new GridLayoutManager(this, gridWidth); - mAdapter.setLayoutManager(lm); + adapter.setLayoutManager(lm); int spacing = getResources().getDimensionPixelSize(R.dimen.media_grid_spacing); mRecyclerView.addItemDecoration(new MediaGridItemDecoration(spacing)); mRecyclerView.setLayoutManager(lm); - mRecyclerView.setAdapter(mAdapter); + mRecyclerView.setAdapter(adapter); load(gridWidth * 2, false); } - @OnClick(R.id.empty_list_view_text) + @OnClick(R.id.empty_list_view_action) public void showHiddenItems() { - if (mAdapter.getSectionCount() == 0 && mAdapter.getUnfilteredSectionCount() > mAdapter.getSectionCount()) { - mAdapter.toggleHiddenItemsVisibility(); + if (adapter.getSectionCount() == 0 && adapter.getUnfilteredSectionCount() > adapter.getSectionCount()) { + adapter.toggleHiddenItemsVisibility(); emptyContentContainer.setVisibility(View.GONE); mRecyclerView.setVisibility(View.VISIBLE); } @@ -272,7 +277,7 @@ public void showHiddenItems() { * @param perFolderMediaItemLimit the amount of media items to be loaded/shown per media folder */ private void load(final int perFolderMediaItemLimit, boolean force) { - if (mAdapter.getItemCount() > 0 && !force) { + if (adapter.getItemCount() > 0 && !force) { return; } showLoadingContent(); @@ -281,14 +286,14 @@ private void load(final int perFolderMediaItemLimit, boolean force) { mediaFolders.addAll(MediaProvider.getVideoFolders(getContentResolver(), perFolderMediaItemLimit, this, false)); - List syncedFolderArrayList = mSyncedFolderProvider.getSyncedFolders(); + List syncedFolderArrayList = syncedFolderProvider.getSyncedFolders(); List currentAccountSyncedFoldersList = new ArrayList<>(); User user = getUserAccountManager().getUser(); for (SyncedFolder syncedFolder : syncedFolderArrayList) { if (syncedFolder.getAccount().equals(user.getAccountName())) { // delete non-existing & disabled synced folders if (!new File(syncedFolder.getLocalPath()).exists() && !syncedFolder.isEnabled()) { - mSyncedFolderProvider.deleteSyncedFolder(syncedFolder.getId()); + syncedFolderProvider.deleteSyncedFolder(syncedFolder.getId()); } else { currentAccountSyncedFoldersList.add(syncedFolder); } @@ -298,14 +303,14 @@ private void load(final int perFolderMediaItemLimit, boolean force) { List syncFolderItems = sortSyncedFolderItems( mergeFolderData(currentAccountSyncedFoldersList, mediaFolders)); - mAdapter.setSyncFolderItems(syncFolderItems); - mAdapter.notifyDataSetChanged(); + adapter.setSyncFolderItems(syncFolderItems); + adapter.notifyDataSetChanged(); showList(); if (!TextUtils.isEmpty(path)) { - int section = mAdapter.getSectionByLocalPathAndType(path, type); + int section = adapter.getSectionByLocalPathAndType(path, type); if (section >= 0) { - onSyncFolderSettingsClick(section, mAdapter.get(section)); + onSyncFolderSettingsClick(section, adapter.get(section)); } } } @@ -523,24 +528,31 @@ private Map createSyncedFoldersMap(List sync */ private void showList() { if (mRecyclerView != null) { - mRecyclerView.setVisibility(View.VISIBLE ); + mRecyclerView.setVisibility(View.VISIBLE); emptyContentProgressBar.setVisibility(View.GONE); - if (mAdapter.getSectionCount() == 0 && mAdapter.getUnfilteredSectionCount() > mAdapter.getSectionCount()) { - emptyContentContainer.setVisibility(View.VISIBLE); - int hiddenFoldersCount = mAdapter.getHiddenFolderCount(); - - showEmptyContent(getString(R.string.drawer_synced_folders), - getResources().getQuantityString(R.plurals.synced_folders_show_hidden_folders, - hiddenFoldersCount, - hiddenFoldersCount)); - } else if (mAdapter.getSectionCount() == 0 && mAdapter.getUnfilteredSectionCount() == 0) { - emptyContentContainer.setVisibility(View.VISIBLE); - showEmptyContent(getString(R.string.drawer_synced_folders), - getString(R.string.synced_folders_no_results)); - } else { - emptyContentContainer.setVisibility(View.GONE); - } + checkAndShowEmptyListContent(); + } + } + + private void checkAndShowEmptyListContent() { + if (adapter.getSectionCount() == 0 && adapter.getUnfilteredSectionCount() > adapter.getSectionCount()) { + emptyContentContainer.setVisibility(View.VISIBLE); + int hiddenFoldersCount = adapter.getHiddenFolderCount(); + + showEmptyContent(getString(R.string.drawer_synced_folders), + getResources().getQuantityString(R.plurals.synced_folders_show_hidden_folders, + hiddenFoldersCount, + hiddenFoldersCount), + getResources().getQuantityString(R.plurals.synced_folders_show_hidden_folders, + hiddenFoldersCount, + hiddenFoldersCount)); + } else if (adapter.getSectionCount() == 0 && adapter.getUnfilteredSectionCount() == 0) { + emptyContentContainer.setVisibility(View.VISIBLE); + showEmptyContent(getString(R.string.drawer_synced_folders), + getString(R.string.synced_folders_no_results)); + } else { + emptyContentContainer.setVisibility(View.GONE); } } @@ -597,10 +609,10 @@ public void showFiles(boolean onDeviceOnly) { @Override public void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem) { if (syncedFolderDisplayItem.getId() > UNPERSISTED_ID) { - mSyncedFolderProvider.updateSyncedFolderEnabled(syncedFolderDisplayItem.getId(), - syncedFolderDisplayItem.isEnabled()); + syncedFolderProvider.updateSyncedFolderEnabled(syncedFolderDisplayItem.getId(), + syncedFolderDisplayItem.isEnabled()); } else { - long storedId = mSyncedFolderProvider.storeSyncedFolder(syncedFolderDisplayItem); + long storedId = syncedFolderProvider.storeSyncedFolder(syncedFolderDisplayItem); if (storedId != -1) { syncedFolderDisplayItem.setId(storedId); } @@ -619,9 +631,9 @@ public void onSyncFolderSettingsClick(int section, SyncedFolderDisplayItem synce FragmentTransaction ft = fm.beginTransaction(); ft.addToBackStack(null); - mSyncedFolderPreferencesDialogFragment = SyncedFolderPreferencesDialogFragment.newInstance( + syncedFolderPreferencesDialogFragment = SyncedFolderPreferencesDialogFragment.newInstance( syncedFolderDisplayItem, section); - mSyncedFolderPreferencesDialogFragment.show(ft, SYNCED_FOLDER_PREFERENCES_DIALOG_TAG); + syncedFolderPreferencesDialogFragment.show(ft, SYNCED_FOLDER_PREFERENCES_DIALOG_TAG); } @Override @@ -629,11 +641,21 @@ public void onVisibilityToggleClick(int section, SyncedFolderDisplayItem syncedF syncedFolder.setHidden(!syncedFolder.isHidden()); saveOrUpdateSyncedFolder(syncedFolder); - mAdapter.setSyncFolderItem(section, syncedFolder); + adapter.setSyncFolderItem(section, syncedFolder); + + checkAndShowEmptyListContent(); } private void showEmptyContent(String headline, String message) { showEmptyContent(headline, message, false); + emptyContentActionButton.setVisibility(View.GONE); + } + + private void showEmptyContent(String headline, String message, String action) { + showEmptyContent(headline, message, false); + emptyContentActionButton.setText(action); + emptyContentActionButton.setVisibility(View.VISIBLE); + emptyContentMessage.setVisibility(View.GONE); } private void showLoadingContent() { @@ -642,6 +664,7 @@ private void showLoadingContent() { getString(R.string.synced_folders_loading_folders), true ); + emptyContentActionButton.setVisibility(View.GONE); } private void showEmptyContent(String headline, String message, boolean loading) { @@ -666,14 +689,14 @@ private void showEmptyContent(String headline, String message, boolean loading) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SyncedFolderPreferencesDialogFragment.REQUEST_CODE__SELECT_REMOTE_FOLDER - && resultCode == RESULT_OK && mSyncedFolderPreferencesDialogFragment != null) { + && resultCode == RESULT_OK && syncedFolderPreferencesDialogFragment != null) { OCFile chosenFolder = data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER); - mSyncedFolderPreferencesDialogFragment.setRemoteFolderSummary(chosenFolder.getRemotePath()); + syncedFolderPreferencesDialogFragment.setRemoteFolderSummary(chosenFolder.getRemotePath()); } if (requestCode == SyncedFolderPreferencesDialogFragment.REQUEST_CODE__SELECT_LOCAL_FOLDER - && resultCode == RESULT_OK && mSyncedFolderPreferencesDialogFragment != null) { + && resultCode == RESULT_OK && syncedFolderPreferencesDialogFragment != null) { String localPath = data.getStringExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES); - mSyncedFolderPreferencesDialogFragment.setLocalFolderSummary(localPath); + syncedFolderPreferencesDialogFragment.setLocalFolderSummary(localPath); } else { super.onActivityResult(requestCode, resultCode, data); } @@ -691,9 +714,9 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { clock.getCurrentTime(), new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType(), syncedFolder.isHidden()); saveOrUpdateSyncedFolder(newCustomFolder); - mAdapter.addSyncFolderItem(newCustomFolder); + adapter.addSyncFolderItem(newCustomFolder); } else { - SyncedFolderDisplayItem item = mAdapter.get(syncedFolder.getSection()); + SyncedFolderDisplayItem item = adapter.get(syncedFolder.getSection()); updateSyncedFolderItem(item, syncedFolder.getId(), syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), syncedFolder .isWifiOnly(), syncedFolder.isChargingOnly(), syncedFolder.isSubfolderByDate(), syncedFolder @@ -702,10 +725,10 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { saveOrUpdateSyncedFolder(item); // TODO test if notifiyItemChanged is suffiecient (should improve performance) - mAdapter.notifyDataSetChanged(); + adapter.notifyDataSetChanged(); } - mSyncedFolderPreferencesDialogFragment = null; + syncedFolderPreferencesDialogFragment = null; if (syncedFolder.isEnabled()) { showBatteryOptimizationInfo(); @@ -718,7 +741,7 @@ private void saveOrUpdateSyncedFolder(SyncedFolderDisplayItem item) { storeSyncedFolder(item); } else { // existing synced folder setup to be updated - mSyncedFolderProvider.updateSyncFolder(item); + syncedFolderProvider.updateSyncFolder(item); if (item.isEnabled()) { FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item); } else { @@ -734,7 +757,7 @@ private void saveOrUpdateSyncedFolder(SyncedFolderDisplayItem item) { private void storeSyncedFolder(SyncedFolderDisplayItem item) { ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(MainApp.getAppContext(). getContentResolver()); - long storedId = mSyncedFolderProvider.storeSyncedFolder(item); + long storedId = syncedFolderProvider.storeSyncedFolder(item); if (storedId != -1) { item.setId(storedId); if (item.isEnabled()) { @@ -748,13 +771,13 @@ private void storeSyncedFolder(SyncedFolderDisplayItem item) { @Override public void onCancelSyncedFolderPreference() { - mSyncedFolderPreferencesDialogFragment = null; + syncedFolderPreferencesDialogFragment = null; } @Override public void onDeleteSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { - mSyncedFolderProvider.deleteSyncedFolder(syncedFolder.getId()); - mAdapter.removeItem(syncedFolder.getSection()); + syncedFolderProvider.deleteSyncedFolder(syncedFolder.getId()); + adapter.removeItem(syncedFolder.getSection()); } /** diff --git a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java index c0eba3eda368..57c72e554905 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java @@ -83,7 +83,7 @@ public SyncedFolderAdapter(Context context, Clock clock, int gridWidth, ClickLis shouldShowFooters(true); } - private void toggleHiddenItemsVisibility() { + public void toggleHiddenItemsVisibility() { hideItems = !hideItems; filteredSyncFolderItems.clear(); filteredSyncFolderItems.addAll(filterHiddenItems(syncFolderItems, hideItems)); @@ -99,7 +99,6 @@ public void setSyncFolderItems(List syncFolderItems) { } public void setSyncFolderItem(int location, SyncedFolderDisplayItem syncFolderItem) { - // show all items OR if (hideItems && syncFolderItem.isHidden() && filteredSyncFolderItems.contains(syncFolderItem)) { filteredSyncFolderItems.remove(location); } else { @@ -123,7 +122,7 @@ public void addSyncFolderItem(SyncedFolderDisplayItem syncFolderItem) { syncFolderItems.add(syncFolderItem); // add item for display when either all items should be shown (!hideItems) - // or if items should be hi + // or if item should be shown (!.isHidden()) if (!hideItems || !syncFolderItem.isHidden()) { filteredSyncFolderItems.add(syncFolderItem); notifyDataSetChanged(); @@ -148,15 +147,15 @@ private List filterHiddenItems(List ret = new ArrayList<>(); + List result = new ArrayList<>(); for (SyncedFolderDisplayItem item : items) { - if (!item.isHidden() && !ret.contains(item)) { - ret.add(item); + if (!item.isHidden() && !result.contains(item)) { + result.add(item); } } - return ret; + return result; } } diff --git a/src/main/res/layout/empty_list.xml b/src/main/res/layout/empty_list.xml index f4ea188252e9..2cfc7790e98f 100644 --- a/src/main/res/layout/empty_list.xml +++ b/src/main/res/layout/empty_list.xml @@ -19,6 +19,7 @@ License along with this program. If not, see . --> + + From 1f4e85768198dddd5611daad884d137537914e4c Mon Sep 17 00:00:00 2001 From: nextcloud-android-bot Date: Wed, 27 Nov 2019 20:55:41 +0000 Subject: [PATCH 9/9] Drone: update FindBugs results to reflect reduced error/warning count [skip ci] Signed-off-by: nextcloud-android-bot --- scripts/analysis/findbugs-results.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/analysis/findbugs-results.txt b/scripts/analysis/findbugs-results.txt index 8e9088e93bac..009bd2c17f2d 100644 --- a/scripts/analysis/findbugs-results.txt +++ b/scripts/analysis/findbugs-results.txt @@ -1 +1 @@ -411 \ No newline at end of file +407 \ No newline at end of file