Browse Source

show/hide improvements when list is completed hidden + nicer empty UI + action button

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 5 years ago
parent
commit
ca6918f9fc

+ 103 - 18
src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java

@@ -38,9 +38,12 @@ import android.view.Menu;
 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.FragmentManager;
 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 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
         }
 
         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 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
      * 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 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
         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 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
         if (mAdapter.getItemCount() > 0 && !force) {
             return;
         }
-        setListShown(false);
+        showLoadingContent();
         final List<MediaFolder> mediaFolders = MediaProvider.getImageFolders(getContentResolver(),
                 perFolderMediaItemLimit, this, false);
         mediaFolders.addAll(MediaProvider.getVideoFolders(getContentResolver(), perFolderMediaItemLimit,
@@ -274,7 +305,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
 
         mAdapter.setSyncFolderItems(syncFolderItems);
         mAdapter.notifyDataSetChanged();
-        setListShown(true);
+        showList();
 
         if (!TextUtils.isEmpty(path)) {
             int section = mAdapter.getSectionByLocalPathAndType(path, type);
@@ -493,15 +524,31 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
     }
 
     /**
-     * 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 class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
         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 class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
     @Override
     protected void onResume() {
         super.onResume();
-
         setDrawerMenuItemChecked(R.id.nav_synced_folders);
     }
 

+ 23 - 0
src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java

@@ -169,6 +169,14 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
         }
     }
 
+    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 class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
         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 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
         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);

+ 14 - 2
src/main/res/layout/empty_list.xml

@@ -19,6 +19,7 @@
   License along with this program. If not, see <http://www.gnu.org/licenses/>.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
               android:id="@+id/empty_list_view"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
@@ -50,7 +51,7 @@
         android:ellipsize="end"
         android:gravity="center"
         android:maxLines="2"
-        android:paddingBottom="@dimen/standard_padding"
+        android:paddingBottom="@dimen/standard_half_padding"
         android:paddingTop="@dimen/standard_padding"
         android:text="@string/file_list_loading"
         android:textSize="26sp"/>
@@ -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"/>
 
-</LinearLayout>
+    <com.google.android.material.button.MaterialButton
+        android:id="@+id/empty_list_view_action"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:theme="@style/Button.Primary"
+        app:cornerRadius="@dimen/button_corner_radius"
+        android:layout_marginTop="@dimen/standard_double_margin"
+        android:visibility="gone"/>
+
+</LinearLayout>

+ 1 - 33
src/main/res/layout/synced_folders_layout.xml

@@ -50,39 +50,7 @@
             android:orientation="vertical"
             app:layout_behavior="@string/appbar_scrolling_view_behavior">
 
-            <LinearLayout
-                android:id="@android:id/progress"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:orientation="vertical"
-                android:visibility="gone">
-
-                <ProgressBar
-                    android:id="@+id/syncedFoldersProgressBar"
-                    android:layout_width="@dimen/synced_folders_progress_bar_layout_width"
-                    android:layout_height="@dimen/synced_folders_progress_bar_layout_height"
-                    android:layout_gravity="center_horizontal"/>
-
-                <TextView
-                    android:id="@+id/progressText"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_horizontal"
-                    android:layout_margin="@dimen/standard_half_margin"
-                    android:text="@string/synced_folders_loading_folders"
-                    android:textSize="26sp"/>
-            </LinearLayout>
-
-            <TextView
-                android:id="@android:id/empty"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_margin="@dimen/standard_margin"
-                android:gravity="center"
-                android:text="@string/synced_folders_no_results"
-                android:visibility="gone"/>
+            <include layout="@layout/empty_list" />
 
             <androidx.recyclerview.widget.RecyclerView
                 android:id="@android:id/list"

+ 1 - 1
src/main/res/menu/synced_folders_adapter.xml

@@ -20,7 +20,7 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:id="@+id/action_auto_upload_folder_toggle_visibility"
-        android:title="@string/autoupload_hide_item" />
+        android:title="@string/autoupload_hide_folder" />
 
     <item
         android:id="@+id/action_auto_upload_folder_settings"

+ 9 - 1
src/main/res/values/strings.xml

@@ -554,7 +554,15 @@
     <string name="choose_remote_folder">Choose remote folder…</string>
     <string name="choose_local_folder">Choose local folder…</string>
     <string name="synced_folders_loading_folders">Loading folders…</string>
-    <string name="synced_folders_no_results">No media folders found.</string>
+    <string name="synced_folders_no_results">No media folders found</string>
+    <plurals name="synced_folders_show_hidden_folders">
+        <item quantity="one">Show %1$d hidden folder</item>
+        <item quantity="other">Show %1$d hidden folders</item>
+    </plurals>
+    <plurals name="synced_folders_hidden_folders_count">
+        <item quantity="one">%1$d hidden folder</item>
+        <item quantity="other">%1$d hidden folders</item>
+    </plurals>
     <string name="synced_folders_preferences">Preferences for auto uploading</string>
     <string name="synced_folders_new_info">Instant uploading has been revamped completely. Re-configure your auto upload from within the main menu.\n\nEnjoy the new and extended auto uploading.</string>
     <string name="synced_folders_preferences_folder_path">For %1$s</string>