Эх сурвалжийг харах

Merge pull request #6757 from nextcloud/removeBigSpinner

Remove big spinner
Tobias Kaminsky 4 жил өмнө
parent
commit
7436fbede7
64 өөрчлөгдсөн 1458 нэмэгдсэн , 819 устгасан
  1. 1 0
      drawable_resources/ic_image-outline.svg
  2. BIN
      screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer.png
  3. BIN
      screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer_dark_blue.png
  4. BIN
      screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer.png
  5. BIN
      screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer_dark_blue.png
  6. BIN
      screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open.png
  7. BIN
      screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open_dark_blue.png
  8. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail.png
  9. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail_dark_blue.png
  10. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_loading.png
  11. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_loading_dark_blue.png
  12. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.fragment.ContactListFragmentIT_showContactListFragmentLoading.png
  13. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.fragment.ContactListFragmentIT_showContactListFragmentLoading_dark_blue.png
  14. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment.png
  15. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment_dark_blue.png
  16. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading.png
  17. BIN
      screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading_dark_blue.png
  18. 1 1
      scripts/analysis/lint-results.txt
  19. 2 2
      src/androidTest/java/com/nextcloud/client/ActivitiesActivityIT.java
  20. 2 2
      src/androidTest/java/com/nextcloud/client/FileDisplayActivityScreenshotIT.java
  21. 49 0
      src/androidTest/java/com/owncloud/android/ui/fragment/ContactListFragmentIT.kt
  22. 16 0
      src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinActivityIT.kt
  23. 48 0
      src/main/java/com/nextcloud/ui/SquareLoaderImageView.java
  24. 53 106
      src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java
  25. 2 0
      src/main/java/com/owncloud/android/ui/activities/ActivitiesContract.java
  26. 5 1
      src/main/java/com/owncloud/android/ui/activities/ActivitiesPresenter.java
  27. 2 2
      src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java
  28. 76 112
      src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java
  29. 1 10
      src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
  30. 8 21
      src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java
  31. 0 1
      src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java
  32. 14 13
      src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
  33. 6 21
      src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java
  34. 33 35
      src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java
  35. 0 1
      src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
  36. 1 1
      src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java
  37. 1 1
      src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
  38. 45 69
      src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java
  39. 1 1
      src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java
  40. 59 71
      src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
  41. 130 159
      src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  42. 27 22
      src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java
  43. 27 47
      src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java
  44. 15 19
      src/main/java/com/owncloud/android/ui/preview/PreviewTextStringFragment.java
  45. 29 21
      src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java
  46. 8 0
      src/main/res/drawable/ic_image_outline.xml
  47. 26 0
      src/main/res/layout/activity_list_item_header_shimmer.xml
  48. 67 0
      src/main/res/layout/activity_list_item_shimmer.xml
  49. 26 2
      src/main/res/layout/activity_list_layout.xml
  50. 18 7
      src/main/res/layout/contactlist_fragment.xml
  51. 40 0
      src/main/res/layout/contactlist_list_item_shimmer.xml
  52. 0 6
      src/main/res/layout/empty_list.xml
  53. 57 25
      src/main/res/layout/file_details_activities_fragment.xml
  54. 37 11
      src/main/res/layout/fragment_preview_media.xml
  55. 31 5
      src/main/res/layout/notifications_layout.xml
  56. 77 9
      src/main/res/layout/preview_image_fragment.xml
  57. 16 4
      src/main/res/layout/synced_folders_layout.xml
  58. 161 0
      src/main/res/layout/synced_folders_list_item_shimmer.xml
  59. 23 1
      src/main/res/layout/text_file_preview.xml
  60. 13 0
      src/main/res/layout/trashbin_activity.xml
  61. 92 0
      src/main/res/layout/trashbin_item_shimmer.xml
  62. 93 1
      src/main/res/layout/user_info_layout.xml
  63. 0 2
      src/main/res/values/dims.xml
  64. 19 7
      src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.java

+ 1 - 0
drawable_resources/ic_image-outline.svg

@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M13.96,12.29L11.21,15.83L9.25,13.47L6.5,17H17.5L13.96,12.29Z" /></svg>

BIN
screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer.png


BIN
screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer_dark_blue.png


BIN
screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer.png


BIN
screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer_dark_blue.png


BIN
screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open.png


BIN
screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open_dark_blue.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail_dark_blue.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_loading.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_loading_dark_blue.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.fragment.ContactListFragmentIT_showContactListFragmentLoading.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.fragment.ContactListFragmentIT_showContactListFragmentLoading_dark_blue.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment_dark_blue.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading.png


BIN
screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading_dark_blue.png


+ 1 - 1
scripts/analysis/lint-results.txt

@@ -1,2 +1,2 @@
 DO NOT TOUCH; GENERATED BY DRONE
-      <span class="mdl-layout-title">Lint Report: 306 warnings</span>
+      <span class="mdl-layout-title">Lint Report: 276 warnings</span>

+ 2 - 2
src/androidTest/java/com/nextcloud/client/ActivitiesActivityIT.java

@@ -60,8 +60,8 @@ public class ActivitiesActivityIT extends AbstractIT {
         onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
 
         sut.runOnUiThread(() -> {
-            sut.emptyContentContainer.setVisibility(View.VISIBLE);
-            sut.recyclerView.setVisibility(View.INVISIBLE);
+            sut.getBinding().emptyList.emptyListView.setVisibility(View.VISIBLE);
+            sut.getBinding().list.setVisibility(View.INVISIBLE);
         });
 
         waitForIdleSync();

+ 2 - 2
src/androidTest/java/com/nextcloud/client/FileDisplayActivityScreenshotIT.java

@@ -54,7 +54,7 @@ public class FileDisplayActivityScreenshotIT extends AbstractIT {
         FileDisplayActivity sut = activityRule.launchActivity(null);
 
         sut.getListOfFilesFragment().setFabEnabled(false);
-        sut.getListOfFilesFragment().setEmptyListLoadingMessage(false);
+        sut.getListOfFilesFragment().setEmptyListLoadingMessage();
         sut.getListOfFilesFragment().setLoading(false);
         waitForIdleSync();
 
@@ -69,7 +69,7 @@ public class FileDisplayActivityScreenshotIT extends AbstractIT {
         onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
 
         sut.getListOfFilesFragment().setFabEnabled(false);
-        sut.getListOfFilesFragment().setEmptyListLoadingMessage(false);
+        sut.getListOfFilesFragment().setEmptyListLoadingMessage();
         sut.getListOfFilesFragment().setLoading(false);
         waitForIdleSync();
 

+ 49 - 0
src/androidTest/java/com/owncloud/android/ui/fragment/ContactListFragmentIT.kt

@@ -0,0 +1,49 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2020 Andy Scherzinger
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.fragment
+
+import androidx.test.espresso.intent.rule.IntentsTestRule
+import com.owncloud.android.AbstractIT
+import com.owncloud.android.R
+import com.owncloud.android.datamodel.OCFile
+import com.owncloud.android.ui.activity.ContactsPreferenceActivity
+import com.owncloud.android.ui.fragment.contactsbackup.ContactListFragment
+import com.owncloud.android.utils.ScreenshotTest
+import org.junit.Rule
+import org.junit.Test
+
+class ContactListFragmentIT : AbstractIT() {
+    @get:Rule
+    val testActivityRule = IntentsTestRule(ContactsPreferenceActivity::class.java, true, false)
+
+    val file = OCFile("/", "00000001")
+
+    @Test
+    @ScreenshotTest
+    fun showContactListFragmentLoading() {
+        val sut = testActivityRule.launchActivity(null)
+        val transaction = sut.supportFragmentManager.beginTransaction()
+        transaction.replace(R.id.frame_container, ContactListFragment.newInstance(file, user))
+        transaction.commit()
+
+        waitForIdleSync()
+        screenshot(sut)
+    }
+}

+ 16 - 0
src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinActivityIT.kt

@@ -84,4 +84,20 @@ class TrashbinActivityIT : AbstractIT() {
 
         screenshot(sut)
     }
+
+    @Test
+    @ScreenshotTest
+    fun loading() {
+        val sut: TrashbinActivity = activityRule.launchActivity(null)
+
+        val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY)
+
+        sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut)
+
+        sut.runOnUiThread { sut.showInitialLoading() }
+
+        shortSleep()
+
+        screenshot(sut)
+    }
 }

+ 48 - 0
src/main/java/com/nextcloud/ui/SquareLoaderImageView.java

@@ -0,0 +1,48 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2020 Andy Scherzinger
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.elyeproj.loaderviewlibrary.LoaderImageView;
+
+/**
+ * Square version of loader image.
+ */
+class SquareLoaderImageView extends LoaderImageView {
+    public SquareLoaderImageView(Context context) {
+        super(context);
+    }
+
+    public SquareLoaderImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SquareLoaderImageView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+    }
+}

+ 53 - 106
src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java

@@ -19,18 +19,14 @@
 package com.owncloud.android.ui.activities;
 
 import android.content.Intent;
-import android.graphics.PorterDuff;
 import android.os.Bundle;
 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.nextcloud.client.network.ClientFactory;
 import com.nextcloud.common.NextcloudClient;
 import com.owncloud.android.R;
+import com.owncloud.android.databinding.ActivityListLayoutBinding;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.utils.Log_OC;
@@ -52,55 +48,25 @@ import java.util.List;
 import javax.inject.Inject;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-import butterknife.BindString;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.Unbinder;
 
 import static com.owncloud.android.ui.activity.FileActivity.EXTRA_ACCOUNT;
 import static com.owncloud.android.ui.activity.FileActivity.EXTRA_FILE;
 
+/**
+ * This Activity presents activities feed.
+ */
 public class ActivitiesActivity extends DrawerActivity implements ActivityListInterface, ActivitiesContract.View {
     private static final String TAG = ActivitiesActivity.class.getSimpleName();
-    private static final int UNDEFINED = -1;
-
-    @BindView(R.id.empty_list_view)
-    public LinearLayout emptyContentContainer;
-
-    @BindView(R.id.swipe_containing_list)
-    public SwipeRefreshLayout swipeListRefreshLayout;
-
-    @BindView(R.id.empty_list_view_text)
-    public TextView emptyContentMessage;
-
-    @BindView(R.id.empty_list_view_headline)
-    public TextView emptyContentHeadline;
-
-    @BindView(R.id.empty_list_icon)
-    public ImageView emptyContentIcon;
-
-    @BindView(R.id.empty_list_progress)
-    public ProgressBar emptyContentProgressBar;
-
-    @BindView(android.R.id.list)
-    public RecyclerView recyclerView;
-
-    @BindString(R.string.activities_no_results_headline)
-    public String noResultsHeadline;
-
-    @BindString(R.string.activities_no_results_message)
-    public String noResultsMessage;
 
+    private ActivityListLayoutBinding binding;
     private ActivityListAdapter adapter;
-    private Unbinder unbinder;
     private int lastGiven;
-
     private boolean isLoadingActivities;
+    private ActivitiesContract.ActionListener actionListener;
 
-    private ActivitiesContract.ActionListener mActionListener;
     @Inject ActivitiesRepository activitiesRepository;
     @Inject FilesRepository filesRepository;
     @Inject ClientFactory clientFactory;
@@ -110,47 +76,38 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn
         Log_OC.v(TAG, "onCreate() start");
         super.onCreate(savedInstanceState);
 
-        mActionListener = new ActivitiesPresenter(activitiesRepository, filesRepository, this);
+        actionListener = new ActivitiesPresenter(activitiesRepository, filesRepository, this);
 
-        setContentView(R.layout.activity_list_layout);
-        unbinder = ButterKnife.bind(this);
+        binding = ActivityListLayoutBinding.inflate(getLayoutInflater());
+        setContentView(binding.getRoot());
 
         // setup toolbar
         setupToolbar();
 
-        ThemeUtils.colorSwipeRefreshLayout(this, swipeListRefreshLayout);
+        ThemeUtils.colorSwipeRefreshLayout(this, binding.swipeContainingList);
 
         // setup drawer
         setupDrawer(R.id.nav_activity);
         updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_activities));
 
-        swipeListRefreshLayout.setOnRefreshListener(() -> {
+        binding.swipeContainingList.setOnRefreshListener(() -> {
             // We set lastGiven variable to undefined here since when manually refreshing
             // activities data we want to clear the list and reset the pagination.
-            lastGiven = UNDEFINED;
-            mActionListener.loadActivities(lastGiven);
+            lastGiven = ActivitiesContract.ActionListener.UNDEFINED;
+            actionListener.loadActivities(lastGiven);
         });
-
-        // Since we use swipe-to-refresh for progress indication we can hide the inherited
-        // progressBar, message and headline
-        emptyContentProgressBar.setVisibility(View.GONE);
-        emptyContentMessage.setVisibility(View.INVISIBLE);
-        emptyContentHeadline.setVisibility(View.INVISIBLE);
     }
 
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        unbinder.unbind();
+    @VisibleForTesting
+    public ActivityListLayoutBinding getBinding() {
+        return binding;
     }
 
     /**
      * sets up the UI elements and loads all activity items.
      */
     private void setupContent() {
-        emptyContentIcon.setImageResource(R.drawable.ic_activity);
-        emptyContentProgressBar.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryAccentColor(this),
-                                                                          PorterDuff.Mode.SRC_IN);
+        binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_activity);
 
         FileDataStorageManager storageManager = new FileDataStorageManager(getAccount(), getContentResolver());
         adapter = new ActivityListAdapter(this,
@@ -160,12 +117,12 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn
                                           getCapabilities(),
                                           clientFactory,
                                           false);
-        recyclerView.setAdapter(adapter);
+        binding.list.setAdapter(adapter);
 
         LinearLayoutManager layoutManager = new LinearLayoutManager(this);
 
-        recyclerView.setLayoutManager(layoutManager);
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+        binding.list.setLayoutManager(layoutManager);
+        binding.list.addOnScrollListener(new RecyclerView.OnScrollListener() {
 
             @Override
             public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
@@ -179,41 +136,37 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn
                 if (!isLoadingActivities && (totalItemCount - visibleItemCount) <= (firstVisibleItemIndex + 5)
                     && lastGiven > 0) {
                     // Almost reached the end, continue to load new activities
-                    mActionListener.loadActivities(lastGiven);
+                    actionListener.loadActivities(lastGiven);
                 }
             }
         });
 
-        mActionListener.loadActivities(UNDEFINED);
+        actionListener.loadActivities(ActivitiesContract.ActionListener.UNDEFINED);
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         boolean retval = true;
 
-        switch (item.getItemId()) {
-            case android.R.id.home:
-                if (isDrawerOpen()) {
-                    closeDrawer();
-                } else {
-                    openDrawer();
-                }
-                break;
-            default:
-                Log_OC.w(TAG, "Unknown menu item triggered");
-                retval = super.onOptionsItemSelected(item);
-                break;
+        if (item.getItemId() == android.R.id.home) {
+            if (isDrawerOpen()) {
+                closeDrawer();
+            } else {
+                openDrawer();
+            }
+        } else {
+            Log_OC.w(TAG, "Unknown menu item triggered");
+            retval = super.onOptionsItemSelected(item);
         }
 
         return retval;
     }
 
-
     @Override
     protected void onResume() {
         super.onResume();
 
-        mActionListener.onResume();
+        actionListener.onResume();
 
         setDrawerMenuItemChecked(R.id.nav_activity);
 
@@ -223,13 +176,13 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn
     @Override
     public void onActivityClicked(RichObject richObject) {
         String path = FileUtils.PATH_SEPARATOR + richObject.getPath();
-        mActionListener.openActivity(path, this);
+        actionListener.openActivity(path, this);
     }
 
     @Override
     public void showActivities(List<Object> activities, NextcloudClient client, int lastGiven) {
         boolean clear = false;
-        if (this.lastGiven == UNDEFINED) {
+        if (this.lastGiven == ActivitiesContract.ActionListener.UNDEFINED) {
             clear = true;
         }
         adapter.setActivityItems(activities, client, clear);
@@ -237,13 +190,13 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn
 
         // Hide the recyclerView if list is empty
         if (adapter.isEmpty()) {
-            showEmptyContent(noResultsHeadline, noResultsMessage);
-            recyclerView.setVisibility(View.INVISIBLE);
+            showEmptyContent(getString(R.string.activities_no_results_headline), getString(R.string.activities_no_results_message));
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.list.setVisibility(View.GONE);
         } else {
-            emptyContentMessage.setVisibility(View.INVISIBLE);
-            emptyContentHeadline.setVisibility(View.INVISIBLE);
-
-            recyclerView.setVisibility(View.VISIBLE);
+            binding.emptyList.emptyListView.setVisibility(View.GONE);
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.list.setVisibility(View.VISIBLE);
         }
     }
 
@@ -278,38 +231,32 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn
 
     @Override
     public void showLoadingMessage() {
-        emptyContentHeadline.setText(R.string.file_list_loading);
-        emptyContentMessage.setText("");
-
-        emptyContentIcon.setVisibility(View.GONE);
-        emptyContentProgressBar.setVisibility(View.VISIBLE);
+        binding.emptyList.emptyListView.setVisibility(View.GONE);
     }
 
     @Override
     public void showEmptyContent(String headline, String message) {
-        if (emptyContentContainer != null && emptyContentMessage != null) {
-            emptyContentHeadline.setText(headline);
-            emptyContentMessage.setText(message);
-
-            emptyContentProgressBar.setVisibility(View.GONE);
-            emptyContentIcon.setVisibility(View.VISIBLE);
-            emptyContentHeadline.setVisibility(View.VISIBLE);
-            emptyContentMessage.setVisibility(View.VISIBLE);
-
-        }
+        binding.emptyList.emptyListViewHeadline.setText(headline);
+        binding.emptyList.emptyListViewText.setText(message);
+        binding.loadingContent.setVisibility(View.GONE);
+        binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
+        binding.emptyList.emptyListViewHeadline.setVisibility(View.VISIBLE);
+        binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
+        binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
     }
 
     @Override
     public void setProgressIndicatorState(boolean isActive) {
         isLoadingActivities = isActive;
-        swipeListRefreshLayout.post(() -> swipeListRefreshLayout.setRefreshing(isActive));
-
+        if (!adapter.isEmpty()) {
+            binding.swipeContainingList.post(() -> binding.swipeContainingList.setRefreshing(isActive));
+        }
     }
 
     @Override
     protected void onStop() {
         super.onStop();
 
-        mActionListener.onStop();
+        actionListener.onStop();
     }
 }

+ 2 - 0
src/main/java/com/owncloud/android/ui/activities/ActivitiesContract.java

@@ -38,6 +38,8 @@ public interface ActivitiesContract {
     }
 
     interface ActionListener {
+        int UNDEFINED = -1;
+
         void loadActivities(int lastGiven);
 
         void openActivity(String fileUrl, BaseActivity baseActivity);

+ 5 - 1
src/main/java/com/owncloud/android/ui/activities/ActivitiesPresenter.java

@@ -48,7 +48,11 @@ public class ActivitiesPresenter implements ActivitiesContract.ActionListener {
 
     @Override
     public void loadActivities(int lastGiven) {
-        activitiesView.setProgressIndicatorState(true);
+        if (UNDEFINED == lastGiven) {
+            activitiesView.showLoadingMessage();
+        } else {
+            activitiesView.setProgressIndicatorState(true);
+        }
         activitiesRepository.getActivities(lastGiven, new ActivitiesRepository.LoadActivitiesCallback() {
             @Override
             public void onActivitiesLoaded(List<Object> activities, NextcloudClient client, int lastGiven) {

+ 2 - 2
src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java

@@ -45,8 +45,8 @@ import androidx.fragment.app.FragmentTransaction;
  */
 public class ContactsPreferenceActivity extends FileActivity implements FileFragment.ContainerActivity {
     public static final String TAG = ContactsPreferenceActivity.class.getSimpleName();
-    protected static final String EXTRA_FILE = "FILE";
-    protected static final String EXTRA_USER = "USER";
+    public static final String EXTRA_FILE = "FILE";
+    public static final String EXTRA_USER = "USER";
     /**
      * Warning: default for this extra is different between this activity and {@link ContactsBackupFragment}
      */

+ 76 - 112
src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java

@@ -24,15 +24,10 @@
 
 package com.owncloud.android.ui.activity;
 
-import android.graphics.PorterDuff;
 import android.os.Bundle;
 import android.view.Menu;
 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.snackbar.Snackbar;
 import com.nextcloud.client.account.User;
@@ -41,6 +36,7 @@ import com.nextcloud.client.jobs.NotificationWork;
 import com.nextcloud.client.network.ClientFactory;
 import com.nextcloud.java.util.Optional;
 import com.owncloud.android.R;
+import com.owncloud.android.databinding.NotificationsLayoutBinding;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
@@ -61,12 +57,6 @@ import javax.inject.Inject;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-import butterknife.BindString;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.Unbinder;
 
 /**
  * Activity displaying all server side stored notification items.
@@ -75,36 +65,7 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
 
     private static final String TAG = NotificationsActivity.class.getSimpleName();
 
-    @BindView(R.id.empty_list_view)
-    public LinearLayout emptyContentContainer;
-
-    public SwipeRefreshLayout swipeListRefreshLayout;
-
-    public SwipeRefreshLayout swipeEmptyListRefreshLayout;
-
-    @BindView(R.id.empty_list_view_text)
-    public TextView emptyContentMessage;
-
-    @BindView(R.id.empty_list_view_headline)
-    public TextView emptyContentHeadline;
-
-    @BindView(R.id.empty_list_icon)
-    public ImageView emptyContentIcon;
-
-    @BindView(R.id.empty_list_progress)
-    public ProgressBar emptyContentProgressBar;
-
-    @BindView(android.R.id.list)
-    public RecyclerView recyclerView;
-
-    @BindString(R.string.notifications_no_results_headline)
-    public String noResultsHeadline;
-
-    @BindString(R.string.notifications_no_results_message)
-    public String noResultsMessage;
-
-    private Unbinder unbinder;
-
+    private NotificationsLayoutBinding binding;
     private NotificationListAdapter adapter;
     private Snackbar snackbar;
     private OwnCloudClient client;
@@ -117,8 +78,8 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
         Log_OC.v(TAG, "onCreate() start");
         super.onCreate(savedInstanceState);
 
-        setContentView(R.layout.notifications_layout);
-        unbinder = ButterKnife.bind(this);
+        binding = NotificationsLayoutBinding.inflate(getLayoutInflater());
+        setContentView(binding.getRoot());
 
         optionalUser = getUser();
 
@@ -140,27 +101,29 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
 
         updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_notifications));
 
-        swipeEmptyListRefreshLayout = findViewById(R.id.swipe_containing_empty);
-        swipeListRefreshLayout = findViewById(R.id.swipe_containing_list);
-        ThemeUtils.colorSwipeRefreshLayout(this, swipeListRefreshLayout);
-        ThemeUtils.colorSwipeRefreshLayout(this, swipeEmptyListRefreshLayout);
+        ThemeUtils.colorSwipeRefreshLayout(this, binding.swipeContainingList);
+        ThemeUtils.colorSwipeRefreshLayout(this, binding.swipeContainingEmpty);
 
         // setup drawer
         setupDrawer(R.id.nav_notifications);
 
         if (!optionalUser.isPresent()) {
             // show error
-            runOnUiThread(() -> setEmptyContent(noResultsHeadline, getString(R.string.account_not_found)));
+            runOnUiThread(() -> setEmptyContent(
+                getString(R.string.notifications_no_results_headline),
+                getString(R.string.account_not_found))
+                         );
             return;
         }
 
-        swipeListRefreshLayout.setOnRefreshListener(() -> {
+        binding.swipeContainingList.setOnRefreshListener(() -> {
             setLoadingMessage();
+            binding.swipeContainingList.setRefreshing(true);
             fetchAndSetData();
         });
 
-        swipeEmptyListRefreshLayout.setOnRefreshListener(() -> {
-            setLoadingMessage();
+        binding.swipeContainingEmpty.setOnRefreshListener(() -> {
+            setLoadingMessageEmpty();
             fetchAndSetData();
         });
 
@@ -177,8 +140,9 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
             String pushUrl = getResources().getString(R.string.push_server_url);
 
             if (pushUrl.isEmpty()) {
-                snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_not_implemented,
-                        Snackbar.LENGTH_INDEFINITE);
+                snackbar = Snackbar.make(binding.emptyList.emptyListView,
+                                         R.string.push_notifications_not_implemented,
+                                         Snackbar.LENGTH_INDEFINITE);
             } else {
                 final ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
                 final String accountName = optionalUser.isPresent() ? optionalUser.get().getAccountName() : "";
@@ -186,14 +150,16 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
                                                                      UserAccountManager.ACCOUNT_USES_STANDARD_PASSWORD);
 
                 if (usesOldLogin) {
-                    snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_old_login,
-                            Snackbar.LENGTH_INDEFINITE);
+                    snackbar = Snackbar.make(binding.emptyList.emptyListView,
+                                             R.string.push_notifications_old_login,
+                                             Snackbar.LENGTH_INDEFINITE);
                 } else {
                     String pushValue = arbitraryDataProvider.getValue(accountName, PushUtils.KEY_PUSH);
 
                     if (pushValue == null || pushValue.isEmpty()) {
-                        snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_temp_error,
-                                Snackbar.LENGTH_INDEFINITE);
+                        snackbar = Snackbar.make(binding.emptyList.emptyListView,
+                                                 R.string.push_notifications_temp_error,
+                                                 Snackbar.LENGTH_INDEFINITE);
                     }
                 }
             }
@@ -220,23 +186,16 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
         setupPushWarning();
     }
 
-    public void onDestroy() {
-        super.onDestroy();
-        unbinder.unbind();
-    }
-
     /**
      * sets up the UI elements and loads all notification items.
      */
     private void setupContent() {
-        emptyContentIcon.setImageResource(R.drawable.ic_notification);
-        emptyContentProgressBar.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryAccentColor(this),
-                                                                          PorterDuff.Mode.SRC_IN);
-        setLoadingMessage();
+        binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification);
+        setLoadingMessageEmpty();
 
         LinearLayoutManager layoutManager = new LinearLayoutManager(this);
 
-        recyclerView.setLayoutManager(layoutManager);
+        binding.list.setLayoutManager(layoutManager);
 
         fetchAndSetData();
     }
@@ -244,14 +203,18 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
     @VisibleForTesting
     public void populateList(List<Notification> notifications) {
         adapter.setNotificationItems(notifications);
+        binding.loadingContent.setVisibility(View.GONE);
 
         if (notifications.size() > 0) {
-            swipeEmptyListRefreshLayout.setVisibility(View.GONE);
-            swipeListRefreshLayout.setVisibility(View.VISIBLE);
+            binding.swipeContainingEmpty.setVisibility(View.GONE);
+            binding.swipeContainingList.setVisibility(View.VISIBLE);
         } else {
-            setEmptyContent(noResultsHeadline, noResultsMessage);
-            swipeListRefreshLayout.setVisibility(View.GONE);
-            swipeEmptyListRefreshLayout.setVisibility(View.VISIBLE);
+            setEmptyContent(
+                getString(R.string.notifications_no_results_headline),
+                getString(R.string.notifications_no_results_message)
+                           );
+            binding.swipeContainingList.setVisibility(View.GONE);
+            binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
         }
     }
 
@@ -268,7 +231,7 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
 
             if (adapter == null) {
                 adapter = new NotificationListAdapter(client, this);
-                recyclerView.setAdapter(adapter);
+                binding.list.setAdapter(adapter);
             }
 
             RemoteOperation getRemoteNotificationOperation = new GetNotificationsRemoteOperation();
@@ -281,7 +244,7 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
             } else {
                 Log_OC.d(TAG, result.getLogMessage());
                 // show error
-                runOnUiThread(() -> setEmptyContent(noResultsHeadline, result.getLogMessage()));
+                runOnUiThread(() -> setEmptyContent(getString(R.string.notifications_no_results_headline), result.getLogMessage()));
             }
 
             hideRefreshLayoutLoader();
@@ -292,8 +255,8 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
 
     private void hideRefreshLayoutLoader() {
         runOnUiThread(() -> {
-            swipeListRefreshLayout.setRefreshing(false);
-            swipeEmptyListRefreshLayout.setRefreshing(false);
+            binding.swipeContainingList.setRefreshing(false);
+            binding.swipeContainingEmpty.setRefreshing(false);
         });
     }
 
@@ -307,52 +270,51 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
     public boolean onOptionsItemSelected(MenuItem item) {
         boolean retval = true;
 
-        switch (item.getItemId()) {
-            case android.R.id.home:
-                if (isDrawerOpen()) {
-                    closeDrawer();
-                } else {
-                    openDrawer();
-                }
-                break;
-
-            case R.id.action_empty_notifications:
-                new DeleteAllNotificationsTask(client, this).execute();
-                break;
-
-            default:
-                retval = super.onOptionsItemSelected(item);
-                break;
+        int itemId = item.getItemId();
+        if (itemId == android.R.id.home) {
+            if (isDrawerOpen()) {
+                closeDrawer();
+            } else {
+                openDrawer();
+            }
+        } else if (itemId == R.id.action_empty_notifications) {
+            new DeleteAllNotificationsTask(client, this).execute();
+        } else {
+            retval = super.onOptionsItemSelected(item);
         }
 
         return retval;
     }
 
     private void setLoadingMessage() {
-        emptyContentHeadline.setText(R.string.notifications_loading_activity);
-        emptyContentMessage.setText("");
+        binding.swipeContainingEmpty.setVisibility(View.GONE);
+    }
 
-        emptyContentIcon.setVisibility(View.GONE);
-        emptyContentProgressBar.setVisibility(View.VISIBLE);
+    @VisibleForTesting
+    public void setLoadingMessageEmpty() {
+        binding.swipeContainingList.setVisibility(View.GONE);
+        binding.emptyList.emptyListView.setVisibility(View.GONE);
+        binding.loadingContent.setVisibility(View.VISIBLE);
     }
 
     @VisibleForTesting
     public void setEmptyContent(String headline, String message) {
-        if (emptyContentContainer != null && emptyContentMessage != null) {
-            emptyContentHeadline.setText(headline);
-            emptyContentMessage.setText(message);
-            emptyContentMessage.setVisibility(View.VISIBLE);
-
-            emptyContentProgressBar.setVisibility(View.GONE);
-            emptyContentIcon.setImageResource(R.drawable.ic_notification);
-            emptyContentIcon.setVisibility(View.VISIBLE);
-        }
+        binding.swipeContainingList.setVisibility(View.GONE);
+        binding.loadingContent.setVisibility(View.GONE);
+        binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
+        binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
+
+        binding.emptyList.emptyListViewHeadline.setText(headline);
+        binding.emptyList.emptyListViewText.setText(message);
+        binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification);
+
+        binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
+        binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
     }
 
     @Override
     protected void onResume() {
         super.onResume();
-
         setDrawerMenuItemChecked(R.id.nav_notifications);
     }
 
@@ -369,9 +331,10 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
         adapter.removeNotification(holder);
 
         if (adapter.getItemCount() == 0) {
-            setEmptyContent(noResultsHeadline, noResultsMessage);
-            swipeListRefreshLayout.setVisibility(View.GONE);
-            swipeEmptyListRefreshLayout.setVisibility(View.VISIBLE);
+            setEmptyContent(getString(R.string.notifications_no_results_headline), getString(R.string.notifications_no_results_message));
+            binding.swipeContainingList.setVisibility(View.GONE);
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
         }
     }
 
@@ -379,9 +342,10 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio
     public void onRemovedAllNotifications(boolean isSuccess) {
         if (isSuccess) {
             adapter.removeAllNotifications();
-            setEmptyContent(noResultsHeadline, noResultsMessage);
-            swipeListRefreshLayout.setVisibility(View.GONE);
-            swipeEmptyListRefreshLayout.setVisibility(View.VISIBLE);
+            setEmptyContent(getString(R.string.notifications_no_results_headline), getString(R.string.notifications_no_results_message));
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.swipeContainingList.setVisibility(View.GONE);
+            binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
         } else {
             DisplayUtils.showSnackMessage(this, getString(R.string.clear_notifications_failed));
         }

+ 1 - 10
src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java

@@ -36,7 +36,6 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Color;
-import android.graphics.PorterDuff;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -57,7 +56,6 @@ import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
-import android.widget.ProgressBar;
 import android.widget.Spinner;
 import android.widget.TextView;
 import android.widget.Toast;
@@ -166,7 +164,6 @@ public class ReceiveExternalFilesActivity extends FileActivity
     private TextView mEmptyListMessage;
     private TextView mEmptyListHeadline;
     private ImageView mEmptyListIcon;
-    private ProgressBar mEmptyListProgress;
     private MaterialButton sortButton;
 
     @Override
@@ -332,7 +329,7 @@ public class ReceiveExternalFilesActivity extends FileActivity
         }
 
         @Override
-        public void onAttach(Context context) {
+        public void onAttach(@NonNull Context context) {
             super.onAttach(context);
         }
 
@@ -800,9 +797,6 @@ public class ReceiveExternalFilesActivity extends FileActivity
         mEmptyListMessage = findViewById(R.id.empty_list_view_text);
         mEmptyListHeadline = findViewById(R.id.empty_list_view_headline);
         mEmptyListIcon = findViewById(R.id.empty_list_icon);
-        mEmptyListProgress = findViewById(R.id.empty_list_progress);
-        mEmptyListProgress.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryColor(this),
-                PorterDuff.Mode.SRC_IN);
     }
 
     public void setMessageForEmptyList(@StringRes final int headline, @StringRes final int message,
@@ -811,11 +805,8 @@ public class ReceiveExternalFilesActivity extends FileActivity
             if (mEmptyListContainer != null && mEmptyListMessage != null) {
                 mEmptyListHeadline.setText(headline);
                 mEmptyListMessage.setText(message);
-
                 mEmptyListIcon.setImageDrawable(ThemeUtils.tintDrawable(icon, ThemeUtils.primaryColor(this, true)));
-
                 mEmptyListIcon.setVisibility(View.VISIBLE);
-                mEmptyListProgress.setVisibility(View.GONE);
                 mEmptyListMessage.setVisibility(View.VISIBLE);
             }
         });

+ 8 - 21
src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java

@@ -159,6 +159,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
             mDrawerToggle.setDrawerIndicatorEnabled(false);
         }
 
+        // TODO: The content loading should be done asynchronously
         setupContent();
 
         if (ThemeUtils.themingEnabled(this)) {
@@ -491,7 +492,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
      */
     private void showList() {
         binding.list.setVisibility(View.VISIBLE);
-        binding.emptyList.emptyListProgress.setVisibility(View.GONE);
+        binding.loadingContent.setVisibility(View.GONE);
         checkAndShowEmptyListContent();
     }
 
@@ -602,42 +603,28 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
         checkAndShowEmptyListContent();
     }
 
-    private void showEmptyContent(String headline, String message) {
-        showEmptyContent(headline, message, false);
-        binding.emptyList.emptyListViewAction.setVisibility(View.GONE);
-    }
-
     private void showEmptyContent(String headline, String message, String action) {
-        showEmptyContent(headline, message, false);
+        showEmptyContent(headline, message);
         binding.emptyList.emptyListViewAction.setText(action);
         binding.emptyList.emptyListViewAction.setVisibility(View.VISIBLE);
         binding.emptyList.emptyListViewText.setVisibility(View.GONE);
     }
 
     private void showLoadingContent() {
-        showEmptyContent(
-            getString(R.string.drawer_synced_folders),
-            getString(R.string.synced_folders_loading_folders),
-            true
-        );
+        binding.loadingContent.setVisibility(View.VISIBLE);
         binding.emptyList.emptyListViewAction.setVisibility(View.GONE);
     }
 
-    private void showEmptyContent(String headline, String message, boolean loading) {
+    private void showEmptyContent(String headline, String message) {
+        binding.emptyList.emptyListViewAction.setVisibility(View.GONE);
         binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
         binding.list.setVisibility(View.GONE);
+        binding.loadingContent.setVisibility(View.GONE);
 
         binding.emptyList.emptyListViewHeadline.setText(headline);
         binding.emptyList.emptyListViewText.setText(message);
         binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
-
-        if (loading) {
-            binding.emptyList.emptyListProgress.setVisibility(View.VISIBLE);
-            binding.emptyList.emptyListIcon.setVisibility(View.GONE);
-        } else {
-            binding.emptyList.emptyListProgress.setVisibility(View.GONE);
-            binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
-        }
+        binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
     }
 
     @Override

+ 0 - 1
src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java

@@ -140,7 +140,6 @@ public class UploadListActivity extends FileActivity {
     private void setupContent() {
         binding.list.setEmptyView(binding.emptyList.getRoot());
         binding.emptyList.getRoot().setVisibility(View.GONE);
-        binding.emptyList.emptyListProgress.setVisibility(View.GONE);
         binding.emptyList.emptyListIcon.setImageResource(R.drawable.uploads);
         binding.emptyList.emptyListIcon.getDrawable().mutate();
         binding.emptyList.emptyListIcon.setAlpha(0.5f);

+ 14 - 13
src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java

@@ -27,7 +27,6 @@
 
 package com.owncloud.android.ui.activity;
 
-import android.graphics.PorterDuff;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
@@ -189,14 +188,8 @@ public class UserInfoActivity extends DrawerActivity implements Injectable {
     }
 
     private void setMultiListLoadingMessage() {
-        binding.emptyList.emptyListViewHeadline.setText(R.string.file_list_loading);
-        binding.emptyList.emptyListViewText.setText("");
-
-        binding.emptyList.emptyListIcon.setVisibility(View.GONE);
-        binding.emptyList.emptyListViewText.setVisibility(View.GONE);
-        binding.emptyList.emptyListProgress.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryColor(this),
-                                                                                      PorterDuff.Mode.SRC_IN);
-        binding.emptyList.emptyListProgress.setVisibility(View.VISIBLE);
+        binding.userinfoList.setVisibility(View.GONE);
+        binding.emptyList.emptyListView.setVisibility(View.GONE);
     }
 
     private void setErrorMessageForMultiList(String headline, String message, @DrawableRes int errorResource) {
@@ -204,9 +197,10 @@ public class UserInfoActivity extends DrawerActivity implements Injectable {
         binding.emptyList.emptyListViewText.setText(message);
         binding.emptyList.emptyListIcon.setImageResource(errorResource);
 
-        binding.emptyList.emptyListProgress.setVisibility(View.GONE);
         binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
         binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
+        binding.userinfoList.setVisibility(View.GONE);
+        binding.loadingContent.setVisibility(View.GONE);
     }
 
     private void setHeaderImage() {
@@ -270,18 +264,25 @@ public class UserInfoActivity extends DrawerActivity implements Injectable {
             binding.userinfoFullName.setText(userInfo.getDisplayName());
         }
 
-        if (userInfo.getPhone() == null && userInfo.getEmail() == null && userInfo.getAddress() == null
-            && userInfo.getTwitter() == null && userInfo.getWebsite() == null) {
+        if (TextUtils.isEmpty(userInfo.getPhone()) && TextUtils.isEmpty(userInfo.getEmail())
+            && TextUtils.isEmpty(userInfo.getAddress()) && TextUtils.isEmpty(userInfo.getTwitter())
+            && TextUtils.isEmpty(userInfo.getWebsite())) {
+            binding.userinfoList.setVisibility(View.GONE);
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
 
             setErrorMessageForMultiList(getString(R.string.userinfo_no_info_headline),
                                         getString(R.string.userinfo_no_info_text), R.drawable.ic_user);
         } else {
+            binding.loadingContent.setVisibility(View.VISIBLE);
             binding.emptyList.emptyListView.setVisibility(View.GONE);
-            binding.userinfoList.setVisibility(View.VISIBLE);
 
             if (binding.userinfoList.getAdapter() instanceof UserInfoAdapter) {
                 binding.userinfoList.setAdapter(new UserInfoAdapter(createUserInfoDetails(userInfo), tint));
             }
+
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.userinfoList.setVisibility(View.VISIBLE);
         }
     }
 

+ 6 - 21
src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java

@@ -28,7 +28,6 @@ import android.animation.LayoutTransition;
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.PorterDuff;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -49,7 +48,6 @@ import android.widget.AdapterView.OnItemClickListener;
 import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import com.google.android.material.button.MaterialButton;
@@ -123,7 +121,6 @@ public class ExtendedListFragment extends Fragment implements
     protected TextView mEmptyListMessage;
     protected TextView mEmptyListHeadline;
     protected ImageView mEmptyListIcon;
-    protected ProgressBar mEmptyListProgress;
 
     // Save the state of the scroll in browsing
     private ArrayList<Integer> mIndexes;
@@ -419,9 +416,6 @@ public class ExtendedListFragment extends Fragment implements
         mEmptyListMessage = view.findViewById(R.id.empty_list_view_text);
         mEmptyListHeadline = view.findViewById(R.id.empty_list_view_headline);
         mEmptyListIcon = view.findViewById(R.id.empty_list_icon);
-        mEmptyListProgress = view.findViewById(R.id.empty_list_progress);
-        mEmptyListProgress.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryColor(getContext(), true),
-                                                                     PorterDuff.Mode.SRC_IN);
     }
 
     /**
@@ -621,7 +615,6 @@ public class ExtendedListFragment extends Fragment implements
                     }
 
                     mEmptyListIcon.setVisibility(View.VISIBLE);
-                    mEmptyListProgress.setVisibility(View.GONE);
                     mEmptyListMessage.setVisibility(View.VISIBLE);
                 }
             }
@@ -667,24 +660,16 @@ public class ExtendedListFragment extends Fragment implements
         });
     }
 
-    public void setEmptyListLoadingMessage() {
-        setEmptyListLoadingMessage(true);
-    }
-
     /**
      * Set message for empty list view.
      */
-    public void setEmptyListLoadingMessage(boolean showSpinner) {
-        new Handler(Looper.getMainLooper()).post(new Runnable() {
-            @Override
-            public void run() {
-                if (mEmptyListContainer != null && mEmptyListMessage != null) {
-                    mEmptyListHeadline.setText(R.string.file_list_loading);
-                    mEmptyListMessage.setText("");
+    public void setEmptyListLoadingMessage() {
+        new Handler(Looper.getMainLooper()).post(() -> {
+            if (mEmptyListContainer != null && mEmptyListMessage != null) {
+                mEmptyListHeadline.setText(R.string.file_list_loading);
+                mEmptyListMessage.setText("");
 
-                    mEmptyListIcon.setVisibility(View.GONE);
-                    mEmptyListProgress.setVisibility(showSpinner ? View.VISIBLE : View.INVISIBLE);
-                }
+                mEmptyListIcon.setVisibility(View.GONE);
             }
         });
     }

+ 33 - 35
src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java

@@ -68,6 +68,7 @@ import java.util.List;
 
 import javax.inject.Inject;
 
+import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.res.ResourcesCompat;
@@ -76,7 +77,6 @@ import androidx.fragment.app.FragmentActivity;
 import androidx.lifecycle.Lifecycle;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 public class FileDetailActivitiesFragment extends Fragment implements
     ActivityListInterface,
@@ -145,8 +145,16 @@ public class FileDetailActivitiesFragment extends Fragment implements
 
         fetchAndSetData(-1);
 
-        binding.swipeContainingList.setOnRefreshListener(() -> onRefreshListLayout(binding.swipeContainingList));
-        binding.swipeContainingEmpty.setOnRefreshListener(() -> onRefreshListLayout(binding.swipeContainingEmpty));
+        binding.swipeContainingList.setOnRefreshListener(() -> {
+            setLoadingMessage();
+            binding.swipeContainingList.setRefreshing(true);
+            fetchAndSetData(-1);
+        });
+
+        binding.swipeContainingEmpty.setOnRefreshListener(() -> {
+            setLoadingMessageEmpty();
+            fetchAndSetData(-1);
+        });
 
         callback = new VersionListInterface.CommentCallback() {
 
@@ -188,19 +196,15 @@ public class FileDetailActivitiesFragment extends Fragment implements
         }
     }
 
-    private void onRefreshListLayout(SwipeRefreshLayout refreshLayout) {
-        setLoadingMessage();
-        if (refreshLayout != null && refreshLayout.isRefreshing()) {
-            refreshLayout.setRefreshing(false);
-        }
-        fetchAndSetData(-1);
+    private void setLoadingMessage() {
+        binding.swipeContainingEmpty.setVisibility(View.GONE);
     }
 
-    private void setLoadingMessage() {
-        binding.emptyList.emptyListViewHeadline.setText(R.string.file_list_loading);
-        binding.emptyList.emptyListViewText.setText("");
-        binding.emptyList.emptyListIcon.setVisibility(View.GONE);
-        binding.emptyList.emptyListProgress.setVisibility(View.VISIBLE);
+    @VisibleForTesting
+    public void setLoadingMessageEmpty() {
+        binding.swipeContainingList.setVisibility(View.GONE);
+        binding.emptyList.emptyListView.setVisibility(View.GONE);
+        binding.loadingContent.setVisibility(View.VISIBLE);
     }
 
     @Override
@@ -217,9 +221,8 @@ public class FileDetailActivitiesFragment extends Fragment implements
         OCCapability capability = storageManager.getCapability(user.getAccountName());
         restoreFileVersionSupported = capability.getFilesVersioning().isTrue();
 
-        binding.emptyList.emptyListProgress.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryAccentColor(getContext()),
-                                                                          PorterDuff.Mode.SRC_IN);
         binding.emptyList.emptyListIcon.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_activity, null));
+        binding.emptyList.emptyListView.setVisibility(View.GONE);
 
         adapter = new ActivityAndVersionListAdapter(getContext(),
                                                     accountManager,
@@ -269,15 +272,11 @@ public class FileDetailActivitiesFragment extends Fragment implements
             return;
         }
 
-        final SwipeRefreshLayout empty = binding.swipeContainingEmpty;
-        final SwipeRefreshLayout list = binding.swipeContainingList;
         final User user = accountManager.getUser();
 
         if (user.isAnonymous()) {
             activity.runOnUiThread(() -> {
                 setEmptyContent(getString(R.string.common_error), getString(R.string.file_detail_activity_error));
-                list.setVisibility(View.GONE);
-                empty.setVisibility(View.VISIBLE);
             });
             return;
         }
@@ -379,39 +378,37 @@ public class FileDetailActivitiesFragment extends Fragment implements
                 getString(R.string.activities_no_results_headline),
                 getString(R.string.activities_no_results_message)
                            );
-            binding.swipeContainingList.setVisibility(View.GONE);
-            binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
         } else {
             binding.swipeContainingList.setVisibility(View.VISIBLE);
             binding.swipeContainingEmpty.setVisibility(View.GONE);
+            binding.emptyList.emptyListView.setVisibility(View.GONE);
         }
         isLoadingActivities = false;
     }
 
     private void setEmptyContent(String headline, String message) {
-        binding.emptyList.emptyListIcon.setImageDrawable(ResourcesCompat.getDrawable(requireContext().getResources(),
-                                                                                     R.drawable.ic_activity,
-                                                                                     null));
-        binding.emptyList.emptyListViewHeadline.setText(headline);
-        binding.emptyList.emptyListViewText.setText(message);
-
-        binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
-        binding.emptyList.emptyListProgress.setVisibility(View.GONE);
-        binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
+        setInfoContent(R.drawable.ic_activity, headline, message);
     }
 
     @VisibleForTesting
     public void setErrorContent(String message) {
-        binding.emptyList.emptyListViewHeadline.setText(R.string.common_error);
+        setInfoContent(R.drawable.ic_list_empty_error, getString(R.string.common_error), message);
+    }
+
+    private void setInfoContent(@DrawableRes int icon, String headline, String message) {
         binding.emptyList.emptyListIcon.setImageDrawable(ResourcesCompat.getDrawable(requireContext().getResources(),
-                                                                                     R.drawable.ic_list_empty_error,
+                                                                                     icon,
                                                                                      null));
+        binding.emptyList.emptyListViewHeadline.setText(headline);
         binding.emptyList.emptyListViewText.setText(message);
 
+        binding.swipeContainingList.setVisibility(View.GONE);
+        binding.loadingContent.setVisibility(View.GONE);
+
+        binding.emptyList.emptyListViewHeadline.setVisibility(View.VISIBLE);
         binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
-        binding.emptyList.emptyListProgress.setVisibility(View.GONE);
         binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
-        binding.swipeContainingList.setVisibility(View.GONE);
+        binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
         binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
     }
 
@@ -420,6 +417,7 @@ public class FileDetailActivitiesFragment extends Fragment implements
             if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
                 binding.swipeContainingList.setRefreshing(false);
                 binding.swipeContainingEmpty.setRefreshing(false);
+                binding.emptyList.emptyListView.setVisibility(View.GONE);
                 isLoadingActivities = false;
             }
         });

+ 0 - 1
src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -682,7 +682,6 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
 
         binding.emptyList.emptyListViewHeadline.setText(R.string.file_details_no_content);
 
-        binding.emptyList.emptyListProgress.setVisibility(View.GONE);
         binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_list_empty_error);
         binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
     }

+ 1 - 1
src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java

@@ -129,7 +129,7 @@ public class GalleryFragment extends OCFileListFragment {
     private void handleSearchEvent() {
         prepareCurrentSearch(searchEvent);
         searchFragment = true;
-        setEmptyListLoadingMessage(false);
+        setEmptyListLoadingMessage();
 
         if (refresh || preferences.getPhotoSearchTimestamp() == 0 ||
             System.currentTimeMillis() - preferences.getPhotoSearchTimestamp() >= 30 * 1000) {

+ 1 - 1
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -959,7 +959,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
                     } else {
                         // update state and view of this fragment
                         searchFragment = false;
-                        setEmptyListLoadingMessage(false);
+                        setEmptyListLoadingMessage();
                         listDirectory(file, MainApp.isOnlyOnDevice(), false);
                         // then, notify parent activity to let it update its state and view
                         mContainerActivity.onBrowsedDownTo(file);

+ 45 - 69
src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java

@@ -42,13 +42,8 @@ import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
-import android.widget.Button;
 import android.widget.CheckedTextView;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
 import android.widget.Toast;
 
 import com.bumptech.glide.request.animation.GlideAnimation;
@@ -65,6 +60,7 @@ import com.nextcloud.client.files.downloader.TransferState;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.network.ClientFactory;
 import com.owncloud.android.R;
+import com.owncloud.android.databinding.ContactlistFragmentBinding;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.TextDrawable;
@@ -98,8 +94,6 @@ import androidx.appcompat.app.AlertDialog;
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
-import butterknife.BindView;
-import butterknife.ButterKnife;
 import ezvcard.Ezvcard;
 import ezvcard.VCard;
 import ezvcard.property.Photo;
@@ -119,33 +113,10 @@ public class ContactListFragment extends FileFragment implements Injectable {
 
     private static final int SINGLE_ACCOUNT = 1;
 
-    @BindView(R.id.contactlist_recyclerview)
-    public RecyclerView recyclerView;
-
-    @BindView(R.id.contactlist_restore_selected_container)
-    public LinearLayout restoreContactsContainer;
-
-    @BindView(R.id.contactlist_restore_selected)
-    public Button restoreContacts;
-
-    @BindView(R.id.empty_list_view_text)
-    public TextView emptyContentMessage;
-
-    @BindView(R.id.empty_list_view_headline)
-    public TextView emptyContentHeadline;
-
-    @BindView(R.id.empty_list_icon)
-    public ImageView emptyContentIcon;
-
-    @BindView(R.id.empty_list_progress)
-    public ProgressBar emptyContentProgressBar;
-
-    @BindView(R.id.empty_list_container)
-    public RelativeLayout emptyListContainer;
-
+    private ContactlistFragmentBinding binding;
 
     private ContactListAdapter contactListAdapter;
-    private List<VCard> vCards = new ArrayList<>();
+    private final List<VCard> vCards = new ArrayList<>();
     private OCFile ocFile;
     @Inject UserAccountManager accountManager;
     @Inject ClientFactory clientFactory;
@@ -173,8 +144,8 @@ public class ContactListFragment extends FileFragment implements Injectable {
     @Override
     public View onCreateView(@NonNull final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 
-        View view = inflater.inflate(R.layout.contactlist_fragment, container, false);
-        ButterKnife.bind(this, view);
+        binding = ContactlistFragmentBinding.inflate(inflater, container, false);
+        View view = binding.getRoot();
 
         setHasOptionsMenu(true);
 
@@ -189,8 +160,6 @@ public class ContactListFragment extends FileFragment implements Injectable {
             contactsPreferenceActivity.setDrawerIndicatorEnabled(false);
         }
 
-        recyclerView = view.findViewById(R.id.contactlist_recyclerview);
-
         if (savedInstanceState == null) {
             contactListAdapter = new ContactListAdapter(accountManager, clientFactory, getContext(), vCards);
         } else {
@@ -206,8 +175,8 @@ public class ContactListFragment extends FileFragment implements Injectable {
             }
             contactListAdapter = new ContactListAdapter(accountManager, getContext(), vCards, checkedItems);
         }
-        recyclerView.setAdapter(contactListAdapter);
-        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        binding.contactlistRecyclerview.setAdapter(contactListAdapter);
+        binding.contactlistRecyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
 
         ocFile = getArguments().getParcelable(FILE_NAME);
         setFile(ocFile);
@@ -222,17 +191,16 @@ public class ContactListFragment extends FileFragment implements Injectable {
             loadContactsTask.execute();
         }
 
-        restoreContacts.setOnClickListener(new View.OnClickListener() {
+        binding.contactlistRestoreSelected.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-
                 if (checkAndAskForContactsWritePermission()) {
                     getAccountForImport();
                 }
             }
         });
 
-        restoreContacts.setTextColor(ThemeUtils.primaryAccentColor(getContext()));
+        binding.contactlistRestoreSelected.setTextColor(ThemeUtils.primaryAccentColor(getContext()));
 
         return view;
     }
@@ -254,9 +222,9 @@ public class ContactListFragment extends FileFragment implements Injectable {
     @Subscribe(threadMode = ThreadMode.MAIN)
     public void onMessageEvent(VCardToggleEvent event) {
         if (event.showRestoreButton) {
-            restoreContactsContainer.setVisibility(View.VISIBLE);
+            binding.contactlistRestoreSelectedContainer.setVisibility(View.VISIBLE);
         } else {
-            restoreContactsContainer.setVisibility(View.GONE);
+            binding.contactlistRestoreSelectedContainer.setVisibility(View.GONE);
         }
     }
 
@@ -267,6 +235,12 @@ public class ContactListFragment extends FileFragment implements Injectable {
         contactsPreferenceActivity.setDrawerIndicatorEnabled(true);
     }
 
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        binding = null;
+    }
+
     public void onResume() {
         super.onResume();
         ContactsPreferenceActivity contactsPreferenceActivity = (ContactsPreferenceActivity) getActivity();
@@ -312,11 +286,7 @@ public class ContactListFragment extends FileFragment implements Injectable {
     }
 
     private void setLoadingMessage() {
-        emptyContentHeadline.setText(R.string.file_list_loading);
-        emptyContentMessage.setText("");
-
-        emptyContentIcon.setVisibility(View.GONE);
-        emptyContentProgressBar.setVisibility(View.VISIBLE);
+        binding.loadingListContainer.setVisibility(View.VISIBLE);
     }
 
     private void setSelectAllMenuItem(MenuItem selectAll, boolean checked) {
@@ -369,7 +339,13 @@ public class ContactListFragment extends FileFragment implements Injectable {
                                                           getFile().getStoragePath(),
                                                           contactListAdapter.getCheckedIntArray());
 
-        Snackbar.make(recyclerView, R.string.contacts_preferences_import_scheduled, Snackbar.LENGTH_LONG).show();
+        Snackbar
+            .make(
+                binding.contactlistRecyclerview,
+                R.string.contacts_preferences_import_scheduled,
+                Snackbar.LENGTH_LONG
+                 )
+            .show();
 
         Handler handler = new Handler();
         handler.postDelayed(new Runnable() {
@@ -393,10 +369,10 @@ public class ContactListFragment extends FileFragment implements Injectable {
         Cursor cursor = null;
         try {
             cursor = getContext().getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI,
-                    new String[]{ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE},
-                    null,
-                    null,
-                    null);
+                                                             new String[]{ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE},
+                                                             null,
+                                                             null,
+                                                             null);
 
             if (cursor != null && cursor.getCount() > 0) {
                 while (cursor.moveToNext()) {
@@ -426,12 +402,12 @@ public class ContactListFragment extends FileFragment implements Injectable {
             ArrayAdapter adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, contactsAccounts);
             AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
             builder.setTitle(R.string.contactlist_account_chooser_title)
-                    .setAdapter(adapter, new DialogInterface.OnClickListener() {
-                        @Override
-                        public void onClick(DialogInterface dialog, int which) {
-                            importContacts(contactsAccounts.get(which));
-                        }
-                    }).show();
+                .setAdapter(adapter, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        importContacts(contactsAccounts.get(which));
+                    }
+                }).show();
         }
     }
 
@@ -439,7 +415,7 @@ public class ContactListFragment extends FileFragment implements Injectable {
         // check permissions
         if (!PermissionUtil.checkSelfPermission(getContext(), Manifest.permission.WRITE_CONTACTS)) {
             requestPermissions(new String[]{Manifest.permission.WRITE_CONTACTS},
-                    PermissionUtil.PERMISSIONS_WRITE_CONTACTS);
+                               PermissionUtil.PERMISSIONS_WRITE_CONTACTS);
             return false;
         } else {
             return true;
@@ -458,7 +434,7 @@ public class ContactListFragment extends FileFragment implements Injectable {
                     } else {
                         if (getView() != null) {
                             Snackbar.make(getView(), R.string.contactlist_no_permission, Snackbar.LENGTH_LONG)
-                                    .show();
+                                .show();
                         } else {
                             Toast.makeText(getContext(), R.string.contactlist_no_permission, Toast.LENGTH_LONG).show();
                         }
@@ -498,7 +474,7 @@ public class ContactListFragment extends FileFragment implements Injectable {
 
         @Override
         public int hashCode() {
-            return Arrays.hashCode(new Object[] {displayName, name, type});
+            return Arrays.hashCode(new Object[]{displayName, name, type});
         }
     }
 
@@ -549,7 +525,7 @@ public class ContactListFragment extends FileFragment implements Injectable {
         @Override
         protected void onPostExecute(Boolean bool) {
             if (!isCancelled()) {
-                emptyListContainer.setVisibility(View.GONE);
+                binding.loadingListContainer.setVisibility(View.GONE);
                 contactListAdapter.replaceVCards(vCards);
             }
         }
@@ -651,11 +627,11 @@ class ContactListAdapter extends RecyclerView.Adapter<ContactListFragment.Contac
             } else {
                 try {
                     holder.getBadge().setImageDrawable(
-                            TextDrawable.createNamedAvatar(
-                                    holder.getName().getText().toString(),
-                                    context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius)
-                            )
-                    );
+                        TextDrawable.createNamedAvatar(
+                            holder.getName().getText().toString(),
+                            context.getResources().getDimension(R.dimen.list_item_avatar_icon_radius)
+                                                      )
+                                                      );
                 } catch (Exception e) {
                     holder.getBadge().setImageResource(R.drawable.ic_user);
                 }
@@ -672,7 +648,7 @@ class ContactListAdapter extends RecyclerView.Adapter<ContactListFragment.Contac
         if (data != null && data.length > 0) {
             Bitmap thumbnail = BitmapFactory.decodeByteArray(data, 0, data.length);
             RoundedBitmapDrawable drawable = BitmapUtils.bitmapToCircularBitmapDrawable(context.getResources(),
-                    thumbnail);
+                                                                                        thumbnail);
 
             imageView.setImageDrawable(drawable);
         } else if (url != null) {

+ 1 - 1
src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -71,7 +71,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 
 /**
- *  Holds a swiping galley where image files contained in an ownCloud directory are shown
+ *  Holds a swiping galley where image files contained in an Nextcloud directory are shown
  */
 @SuppressWarnings("PMD.AvoidDuplicateLiterals")
 public class PreviewImageActivity extends FileActivity implements

+ 59 - 71
src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java

@@ -46,10 +46,9 @@ import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
 
 import com.caverock.androidsvg.SVG;
 import com.caverock.androidsvg.SVGParseException;
@@ -112,14 +111,6 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
     private static final String MIME_TYPE_GIF = "image/gif";
     private static final String MIME_TYPE_SVG = "image/svg+xml";
 
-    private PhotoView imageView;
-
-    private LinearLayout multiListContainer;
-    private TextView multiListMessage;
-    private TextView multiListHeadline;
-    private ImageView multiListIcon;
-    private ProgressBar multiListProgress;
-
     private Boolean showResizedImage;
 
     private Bitmap bitmap;
@@ -200,27 +191,17 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
         binding = PreviewImageFragmentBinding.inflate(inflater, container, false);
         View view = binding.getRoot();
 
-        imageView = view.findViewById(R.id.image);
-        imageView.setVisibility(View.GONE);
+        binding.image.setVisibility(View.GONE);
 
         view.setOnClickListener(v -> togglePreviewImageFullScreen());
 
-        imageView.setOnClickListener(v -> togglePreviewImageFullScreen());
+        binding.image.setOnClickListener(v -> togglePreviewImageFullScreen());
 
-        setupMultiView();
         setMultiListLoadingMessage();
 
         return view;
     }
 
-    private void setupMultiView() {
-        multiListContainer = binding.emptyList.emptyListView;
-        multiListMessage = binding.emptyList.emptyListViewText;
-        multiListHeadline = binding.emptyList.emptyListViewHeadline;
-        multiListIcon = binding.emptyList.emptyListIcon;
-        multiListProgress = binding.emptyList.emptyListProgress;
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -231,7 +212,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
             if (!ignoreFirstSavedState) {
                 OCFile file = savedInstanceState.getParcelable(EXTRA_FILE);
                 setFile(file);
-                imageView.setScale(Math.min(imageView.getMaximumScale(), savedInstanceState.getFloat(EXTRA_ZOOM)));
+                binding.image.setScale(Math.min(binding.image.getMaximumScale(), savedInstanceState.getFloat(EXTRA_ZOOM)));
             } else {
                 ignoreFirstSavedState = false;
             }
@@ -242,7 +223,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
     public void onSaveInstanceState(@NonNull Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        outState.putFloat(EXTRA_ZOOM, imageView.getScale());
+        outState.putFloat(EXTRA_ZOOM, binding.image.getScale());
         outState.putParcelable(EXTRA_FILE, getFile());
     }
 
@@ -250,7 +231,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
     public void onStart() {
         super.onStart();
         if (getFile() != null) {
-            imageView.setTag(getFile().getFileId());
+            binding.image.setTag(getFile().getFileId());
 
             Point screenSize = DisplayUtils.getScreenSize(getActivity());
             int width = screenSize.x;
@@ -260,27 +241,27 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
                 Bitmap resizedImage = getResizedBitmap(getFile(), width, height);
 
                 if (resizedImage != null && !getFile().isUpdateThumbnailNeeded()) {
-                    imageView.setImageBitmap(resizedImage);
-                    imageView.setVisibility(View.VISIBLE);
+                    binding.image.setImageBitmap(resizedImage);
+                    binding.image.setVisibility(View.VISIBLE);
                     bitmap = resizedImage;
                 } else {
                     // show thumbnail while loading resized image
                     Bitmap thumbnail = getResizedBitmap(getFile(), width, height);
 
                     if (thumbnail != null) {
-                        imageView.setImageBitmap(thumbnail);
-                        imageView.setVisibility(View.VISIBLE);
+                        binding.image.setImageBitmap(thumbnail);
+                        binding.image.setVisibility(View.VISIBLE);
                         bitmap = thumbnail;
                     } else {
                         thumbnail = ThumbnailsCacheManager.mDefaultImg;
                     }
 
                     // generate new resized image
-                    if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(getFile(), imageView) &&
+                    if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(getFile(), binding.image) &&
                         containerActivity.getStorageManager() != null) {
                         final ThumbnailsCacheManager.ResizedImageGenerationTask task =
                             new ThumbnailsCacheManager.ResizedImageGenerationTask(this,
-                                                                                  imageView,
+                                                                                  binding.image,
                                                                                   containerActivity.getStorageManager(),
                                                                                   connectivityService,
                                                                                   containerActivity.getStorageManager().getAccount());
@@ -293,16 +274,20 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
                                 resizedImage,
                                 task
                             );
-                        imageView.setImageDrawable(asyncDrawable);
+                        binding.image.setImageDrawable(asyncDrawable);
                         task.execute(getFile());
                     }
                 }
-                multiListContainer.setVisibility(View.GONE);
-                imageView.setBackgroundColor(getResources().getColor(R.color.background_color_inverse));
-                imageView.setVisibility(View.VISIBLE);
+                binding.emptyListView.setVisibility(View.GONE);
+                binding.emptyListProgress.setVisibility(View.GONE);
+                binding.image.setBackgroundColor(getResources().getColor(R.color.background_color_inverse));
+                binding.image.setVisibility(View.VISIBLE);
 
             } else {
-                loadBitmapTask = new LoadBitmapTask(imageView);
+                loadBitmapTask = new LoadBitmapTask(binding.image, binding.emptyListView, binding.emptyListProgress);
+                binding.image.setVisibility(View.GONE);
+                binding.emptyListView.setVisibility(View.GONE);
+                binding.emptyListProgress.setVisibility(View.VISIBLE);
                 loadBitmapTask.execute(getFile());
             }
         } else {
@@ -486,7 +471,9 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
          * Using a weak reference will avoid memory leaks if the target ImageView is retired from
          * memory before the load finishes.
          */
-        private final WeakReference<PhotoView> mImageViewRef;
+        private final WeakReference<PhotoView> imageViewRef;
+        private final WeakReference<LinearLayout> infoViewRef;
+        private final WeakReference<FrameLayout> progressViewRef;
 
         /**
          * Error message to show when a load fails.
@@ -499,8 +486,10 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
          *
          * @param imageView Target {@link ImageView} where the bitmap will be loaded into.
          */
-        LoadBitmapTask(PhotoView imageView) {
-            mImageViewRef = new WeakReference<>(imageView);
+        LoadBitmapTask(PhotoView imageView, LinearLayout infoView, FrameLayout progressView) {
+            imageViewRef = new WeakReference<>(imageView);
+            infoViewRef = new WeakReference<>(infoView);
+            progressViewRef = new WeakReference<>(progressView);
         }
 
         @Override
@@ -618,7 +607,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
         }
 
         private void showLoadedImage(LoadImage result) {
-            final PhotoView imageView = mImageViewRef.get();
+            final PhotoView imageView = imageViewRef.get();
             Bitmap bitmap = result.bitmap;
             Drawable drawable = result.drawable;
 
@@ -635,7 +624,6 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
                         imageView.setImageBitmap(bitmap);
                     }
 
-                    imageView.setVisibility(View.VISIBLE);
                     PreviewImageFragment.this.bitmap = bitmap;  // needs to be kept for recycling when not useful
                 } else {
                     if (drawable != null
@@ -644,8 +632,15 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
                         imageView.setImageDrawable(generateCheckerboardLayeredDrawable(result, null));
                     }
                 }
+                final LinearLayout infoView = infoViewRef.get();
+                if (infoView != null) {
+                    infoView.setVisibility(View.GONE);
+                }
 
-                multiListContainer.setVisibility(View.GONE);
+                final FrameLayout progressView = progressViewRef.get();
+                if (progressView != null) {
+                    progressView.setVisibility(View.GONE);
+                }
                 imageView.setBackgroundColor(getResources().getColor(R.color.background_color_inverse));
                 imageView.setVisibility(View.VISIBLE);
             }
@@ -697,40 +692,33 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
     }
 
     private void showErrorMessage(@StringRes int errorMessageId) {
-        imageView.setBackgroundColor(Color.TRANSPARENT);
         setSorryMessageForMultiList(errorMessageId);
     }
 
     private void setMultiListLoadingMessage() {
-        if (multiListContainer != null) {
-            multiListHeadline.setText(R.string.file_list_loading);
-            multiListMessage.setText("");
-
-            multiListIcon.setVisibility(View.GONE);
-            multiListProgress.setVisibility(View.VISIBLE);
-        }
+        binding.image.setVisibility(View.GONE);
+        binding.emptyListView.setVisibility(View.GONE);
+        binding.emptyListProgress.setVisibility(View.VISIBLE);
     }
 
     private void setSorryMessageForMultiList(@StringRes int message) {
-        if (multiListContainer != null && multiListMessage != null) {
-            multiListHeadline.setText(R.string.preview_sorry);
-            multiListMessage.setText(message);
-            multiListIcon.setImageResource(R.drawable.file_image);
-
-            multiListContainer.setBackgroundColor(getResources().getColor(R.color.bg_default));
-            multiListHeadline.setTextColor(getResources().getColor(R.color.standard_grey));
-            multiListMessage.setTextColor(getResources().getColor(R.color.standard_grey));
-
-            multiListMessage.setVisibility(View.VISIBLE);
-            multiListIcon.setVisibility(View.VISIBLE);
-            multiListProgress.setVisibility(View.GONE);
-        }
+        binding.emptyListViewHeadline.setText(R.string.preview_sorry);
+        binding.emptyListViewText.setText(message);
+        binding.emptyListIcon.setImageResource(R.drawable.file_image);
+
+        binding.emptyListView.setBackgroundColor(getResources().getColor(R.color.bg_default));
+        binding.emptyListViewHeadline.setTextColor(getResources().getColor(R.color.standard_grey));
+        binding.emptyListViewText.setTextColor(getResources().getColor(R.color.standard_grey));
+
+        binding.image.setVisibility(View.GONE);
+        binding.emptyListView.setVisibility(View.VISIBLE);
+        binding.emptyListProgress.setVisibility(View.GONE);
     }
 
     public void setErrorPreviewMessage() {
         try {
             if (getActivity() != null) {
-                Snackbar.make(multiListContainer,
+                Snackbar.make(binding.emptyListView,
                               R.string.resized_image_not_possible_download,
                               Snackbar.LENGTH_INDEFINITE)
                     .setAction(R.string.common_yes, v -> {
@@ -738,7 +726,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
                                    if (activity != null) {
                                        activity.requestForDownload(getFile());
                                    } else {
-                                       Snackbar.make(multiListContainer,
+                                       Snackbar.make(binding.emptyListView,
                                                      getResources().getString(R.string.could_not_download_image),
                                                      Snackbar.LENGTH_INDEFINITE).show();
                                    }
@@ -752,7 +740,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
 
     public void setNoConnectionErrorMessage() {
         try {
-            Snackbar.make(multiListContainer, R.string.auth_no_net_conn_title, Snackbar.LENGTH_LONG).show();
+            Snackbar.make(binding.emptyListView, R.string.auth_no_net_conn_title, Snackbar.LENGTH_LONG).show();
         } catch (IllegalArgumentException e) {
             Log_OC.d(TAG, e.getMessage());
         }
@@ -795,8 +783,8 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
             && getActivity() instanceof PreviewImageActivity) {
             PreviewImageActivity previewImageActivity = (PreviewImageActivity) getActivity();
 
-            if (imageView.getDrawable() instanceof LayerDrawable) {
-                LayerDrawable layerDrawable = (LayerDrawable) imageView.getDrawable();
+            if (binding.image.getDrawable() instanceof LayerDrawable) {
+                LayerDrawable layerDrawable = (LayerDrawable) binding.image.getDrawable();
                 Drawable layerOne;
 
                 if (previewImageActivity.isSystemUIVisible()) {
@@ -807,8 +795,8 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
 
                 layerDrawable.setDrawableByLayerId(layerDrawable.getId(0), layerOne);
 
-                imageView.setImageDrawable(layerDrawable);
-                imageView.invalidate();
+                binding.image.setImageDrawable(layerDrawable);
+                binding.image.invalidate();
             }
         }
     }
@@ -820,7 +808,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
     }
 
     public PhotoView getImageView() {
-        return imageView;
+        return binding.image;
     }
 
     private class LoadImage {

+ 130 - 159
src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -3,8 +3,10 @@
  *
  *   @author David A. Velasco
  *   @author Chris Narkiewicz
+ *   @author Andy Scherzinger
  *   Copyright (C) 2016 ownCloud Inc.
  *   Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
+ *   Copyright (C) 2020 Andy Scherzinger
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -17,7 +19,6 @@
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
  */
 package com.owncloud.android.ui.preview;
 
@@ -45,12 +46,7 @@ import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-import android.widget.VideoView;
 
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
@@ -60,13 +56,13 @@ import com.nextcloud.client.media.ErrorFormat;
 import com.nextcloud.client.media.PlayerServiceConnection;
 import com.nextcloud.client.network.ClientFactory;
 import com.owncloud.android.R;
+import com.owncloud.android.databinding.FragmentPreviewMediaBinding;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.files.StreamMediaFileOperation;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.media.MediaControlView;
 import com.owncloud.android.ui.activity.DrawerActivity;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
@@ -78,7 +74,6 @@ import java.lang.ref.WeakReference;
 
 import javax.inject.Inject;
 
-import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.StringRes;
 import androidx.drawerlayout.widget.DrawerLayout;
@@ -108,35 +103,26 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     private static final String AUTOPLAY = "AUTOPLAY";
 
     private User user;
-    private ImageView mImagePreview;
-    private VideoView mVideoPreview;
-    private int mSavedPlaybackPosition;
-
-    private RelativeLayout mPreviewContainer;
-
-    private LinearLayout mMultiListContainer;
-    private TextView mMultiListMessage;
-    private TextView mMultiListHeadline;
-    private ImageView mMultiListIcon;
-    private ProgressBar mMultiListProgress;
+    private int savedPlaybackPosition;
 
-    private MediaControlView mMediaController;
-    private boolean mAutoplay;
-    private boolean mPrepared;
-    private PlayerServiceConnection mMediaPlayerServiceConnection;
+    private boolean autoplay;
+    private boolean prepared;
+    private PlayerServiceConnection mediaPlayerServiceConnection;
 
-    private Uri mVideoUri;
+    private Uri videoUri;
     @Inject ClientFactory clientFactory;
     @Inject UserAccountManager accountManager;
     @Inject DeviceInfo deviceInfo;
+    FragmentPreviewMediaBinding binding;
+    LinearLayout emptyListView;
 
     /**
      * Creates a fragment to preview a file.
-     *
-     * When 'fileToDetail' or 'ocAccount' are null
+     * <p>
+     * When 'fileToDetail' or 'user' are null
      *
      * @param fileToDetail An {@link OCFile} to preview in the fragment
-     * @param user    Currently active user
+     * @param user         Currently active user
      */
     public static PreviewMediaFragment newInstance(OCFile fileToDetail, User user, int startPlaybackPosition,
                                                    boolean autoplay) {
@@ -164,8 +150,8 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
      */
     public PreviewMediaFragment() {
         super();
-        mSavedPlaybackPosition = 0;
-        mAutoplay = true;
+        savedPlaybackPosition = 0;
+        autoplay = true;
     }
 
     @Override
@@ -177,9 +163,9 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
 
         setFile(bundle.getParcelable(FILE));
         user = bundle.getParcelable(USER);
-        mSavedPlaybackPosition = bundle.getInt(PLAYBACK_POSITION);
-        mAutoplay = bundle.getBoolean(AUTOPLAY);
-        mMediaPlayerServiceConnection = new PlayerServiceConnection(getContext());
+        savedPlaybackPosition = bundle.getInt(PLAYBACK_POSITION);
+        autoplay = bundle.getBoolean(AUTOPLAY);
+        mediaPlayerServiceConnection = new PlayerServiceConnection(getContext());
     }
 
     @Override
@@ -187,49 +173,30 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         super.onCreateView(inflater, container, savedInstanceState);
         Log_OC.v(TAG, "onCreateView");
 
+        binding = FragmentPreviewMediaBinding.inflate(inflater, container, false);
+        View view = binding.getRoot();
 
-        View view = inflater.inflate(R.layout.file_preview, container, false);
-
-        mPreviewContainer = view.findViewById(R.id.file_preview_container);
-        mImagePreview = view.findViewById(R.id.image_preview);
-        mVideoPreview = view.findViewById(R.id.video_preview);
-        mVideoPreview.setOnTouchListener(this);
+        emptyListView = binding.emptyView.emptyListView;
 
-        mMediaController = view.findViewById(R.id.media_controller);
+        binding.videoPreview.setOnTouchListener(this);
 
-        setupMultiView(view);
-        setMultiListLoadingMessage();
+        setLoadingView();
         return view;
     }
 
-    private void setupMultiView(View view) {
-        mMultiListContainer = view.findViewById(R.id.empty_list_view);
-        mMultiListMessage = view.findViewById(R.id.empty_list_view_text);
-        mMultiListHeadline = view.findViewById(R.id.empty_list_view_headline);
-        mMultiListIcon = view.findViewById(R.id.empty_list_icon);
-        mMultiListProgress = view.findViewById(R.id.empty_list_progress);
-    }
-
-    private void setMultiListLoadingMessage() {
-        if (mMultiListContainer != null) {
-            mMultiListHeadline.setText(R.string.file_list_loading);
-            mMultiListMessage.setText("");
-
-            mMultiListIcon.setVisibility(View.GONE);
-            mMultiListProgress.setVisibility(View.VISIBLE);
-        }
+    private void setLoadingView() {
+        binding.progress.setVisibility(View.VISIBLE);
+        binding.emptyView.emptyListView.setVisibility(View.GONE);
     }
 
-    private void setMessageForMultiList(String headline, @StringRes int message, @DrawableRes int icon) {
-        if (mMultiListContainer != null && mMultiListMessage != null) {
-            mMultiListHeadline.setText(headline);
-            mMultiListMessage.setText(message);
-            mMultiListIcon.setImageResource(icon);
-
-            mMultiListMessage.setVisibility(View.VISIBLE);
-            mMultiListIcon.setVisibility(View.VISIBLE);
-            mMultiListProgress.setVisibility(View.GONE);
-        }
+    private void setVideoErrorMessage(String headline, @StringRes int message) {
+        binding.emptyView.emptyListViewHeadline.setText(headline);
+        binding.emptyView.emptyListViewText.setText(message);
+        binding.emptyView.emptyListIcon.setImageResource(R.drawable.file_movie);
+        binding.emptyView.emptyListViewText.setVisibility(View.VISIBLE);
+        binding.emptyView.emptyListIcon.setVisibility(View.VISIBLE);
+        binding.progress.setVisibility(View.GONE);
+        binding.emptyView.emptyListView.setVisibility(View.VISIBLE);
     }
 
     @Override
@@ -249,18 +216,18 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
             file = savedInstanceState.getParcelable(EXTRA_FILE);
             setFile(file);
             user = savedInstanceState.getParcelable(EXTRA_USER);
-            mSavedPlaybackPosition = savedInstanceState.getInt(EXTRA_PLAY_POSITION);
-            mAutoplay = savedInstanceState.getBoolean(EXTRA_PLAYING);
+            savedPlaybackPosition = savedInstanceState.getInt(EXTRA_PLAY_POSITION);
+            autoplay = savedInstanceState.getBoolean(EXTRA_PLAYING);
         }
 
         if (file != null) {
             if (MimeTypeUtil.isVideo(file)) {
-                mVideoPreview.setVisibility(View.VISIBLE);
-                mImagePreview.setVisibility(View.GONE);
+                binding.videoPreview.setVisibility(View.VISIBLE);
+                binding.imagePreview.setVisibility(View.GONE);
                 prepareVideo();
             } else {
-                mVideoPreview.setVisibility(View.GONE);
-                mImagePreview.setVisibility(View.VISIBLE);
+                binding.videoPreview.setVisibility(View.GONE);
+                binding.imagePreview.setVisibility(View.VISIBLE);
                 extractAndSetCoverArt(file);
             }
         }
@@ -280,12 +247,12 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
                 byte[] data = mmr.getEmbeddedPicture();
                 if (data != null) {
                     Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
-                    mImagePreview.setImageBitmap(bitmap); //associated cover art in bitmap
+                    binding.imagePreview.setImageBitmap(bitmap); //associated cover art in bitmap
                 } else {
-                    mImagePreview.setImageResource(R.drawable.logo);
+                    binding.imagePreview.setImageResource(R.drawable.logo);
                 }
             } catch (Throwable t) {
-                mImagePreview.setImageResource(R.drawable.logo);
+                binding.imagePreview.setImageResource(R.drawable.logo);
             }
         }
     }
@@ -299,15 +266,15 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         outState.putParcelable(EXTRA_USER, user);
 
         if (MimeTypeUtil.isVideo(getFile())) {
-            if (mVideoPreview != null) {
-                mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
-                mAutoplay = mVideoPreview.isPlaying();
-                outState.putInt(EXTRA_PLAY_POSITION, mSavedPlaybackPosition);
-                outState.putBoolean(EXTRA_PLAYING, mAutoplay);
+            if (binding.videoPreview != null) {
+                savedPlaybackPosition = binding.videoPreview.getCurrentPosition();
+                autoplay = binding.videoPreview.isPlaying();
+                outState.putInt(EXTRA_PLAY_POSITION, savedPlaybackPosition);
+                outState.putBoolean(EXTRA_PLAYING, autoplay);
             }
-        } else if(mMediaPlayerServiceConnection.isConnected()) {
-            outState.putInt(EXTRA_PLAY_POSITION, mMediaPlayerServiceConnection.getCurrentPosition());
-            outState.putBoolean(EXTRA_PLAYING, mMediaPlayerServiceConnection.isPlaying());
+        } else if(mediaPlayerServiceConnection.isConnected()) {
+            outState.putInt(EXTRA_PLAY_POSITION, mediaPlayerServiceConnection.getCurrentPosition());
+            outState.putBoolean(EXTRA_PLAYING, mediaPlayerServiceConnection.isPlaying());
         }
     }
 
@@ -318,15 +285,16 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         OCFile file = getFile();
         if (file != null) {
             // bind to any existing player
-            mMediaPlayerServiceConnection.bind();
+            mediaPlayerServiceConnection.bind();
 
             if (MimeTypeUtil.isAudio(file)) {
-                mMediaController.setMediaPlayer(mMediaPlayerServiceConnection);
-                mMediaPlayerServiceConnection.start(user, file, mAutoplay, mSavedPlaybackPosition);
-                mMultiListContainer.setVisibility(View.GONE);
-                mPreviewContainer.setVisibility(View.VISIBLE);
+                binding.mediaController.setMediaPlayer(mediaPlayerServiceConnection);
+                mediaPlayerServiceConnection.start(user, file, autoplay, savedPlaybackPosition);
+                binding.emptyView.emptyListView.setVisibility(View.GONE);
+                binding.progress.setVisibility(View.GONE);
+                binding.filePreviewContainer.setVisibility(View.VISIBLE);
             } else if (MimeTypeUtil.isVideo(file)) {
-                if (mMediaPlayerServiceConnection.isConnected()) {
+                if (mediaPlayerServiceConnection.isConnected()) {
                     // always stop player
                     stopAudio();
                 }
@@ -336,18 +304,18 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     }
 
     private void stopAudio() {
-        mMediaPlayerServiceConnection.stop();
+        mediaPlayerServiceConnection.stop();
     }
 
     @Override
-    public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
+    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
         menu.removeItem(R.id.action_search);
         inflater.inflate(R.menu.item_file, menu);
     }
 
     @Override
-    public void onPrepareOptionsMenu(Menu menu) {
+    public void onPrepareOptionsMenu(@NonNull Menu menu) {
         super.onPrepareOptionsMenu(menu);
 
         if (containerActivity.getStorageManager() != null) {
@@ -419,31 +387,25 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.action_send_share_file: {
-                sendShareFile();
-                return true;
-            }
-            case R.id.action_open_file_with: {
-                openFile();
-                return true;
-            }
-            case R.id.action_remove_file: {
-                RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(getFile());
-                dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
-                return true;
-            }
-            case R.id.action_see_details: {
-                seeDetails();
-                return true;
-            }
-            case R.id.action_sync_file: {
-                containerActivity.getFileOperationsHelper().syncFile(getFile());
-                return true;
-            }
-            default:
-                return super.onOptionsItemSelected(item);
+        int itemId = item.getItemId();
+        if (itemId == R.id.action_send_share_file) {
+            sendShareFile();
+            return true;
+        } else if (itemId == R.id.action_open_file_with) {
+            openFile();
+            return true;
+        } else if (itemId == R.id.action_remove_file) {
+            RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(getFile());
+            dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
+            return true;
+        } else if (itemId == R.id.action_see_details) {
+            seeDetails();
+            return true;
+        } else if (itemId == R.id.action_sync_file) {
+            containerActivity.getFileOperationsHelper().syncFile(getFile());
+            return true;
         }
+        return super.onOptionsItemSelected(item);
     }
 
     /**
@@ -468,19 +430,19 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     private void prepareVideo() {
         // create helper to get more control on the playback
         VideoHelper videoHelper = new VideoHelper();
-        mVideoPreview.setOnPreparedListener(videoHelper);
-        mVideoPreview.setOnCompletionListener(videoHelper);
-        mVideoPreview.setOnErrorListener(videoHelper);
+        binding.videoPreview.setOnPreparedListener(videoHelper);
+        binding.videoPreview.setOnCompletionListener(videoHelper);
+        binding.videoPreview.setOnErrorListener(videoHelper);
     }
 
     private void playVideo() {
         // create and prepare control panel for the user
-        mMediaController.setMediaPlayer(mVideoPreview);
+        binding.mediaController.setMediaPlayer(binding.videoPreview);
 
         // load the video file in the video player
         // when done, VideoHelper#onPrepared() will be called
         if (getFile().isDown()) {
-            mVideoPreview.setVideoURI(getFile().getStorageUri());
+            binding.videoPreview.setVideoURI(getFile().getStorageUri());
         } else {
             try {
                 OwnCloudClient client = clientFactory.create(user);
@@ -519,13 +481,13 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
             final Context context = previewMediaFragment != null ? previewMediaFragment.getContext() : null;
             if (previewMediaFragment != null && context != null) {
                 if (uri != null) {
-                    previewMediaFragment.mVideoUri = uri;
-                    previewMediaFragment.mVideoPreview.setVideoURI(uri);
+                    previewMediaFragment.videoUri = uri;
+                    previewMediaFragment.binding.videoPreview.setVideoURI(uri);
                 } else {
-                    previewMediaFragment.mMultiListContainer.setVisibility(View.VISIBLE);
-                    previewMediaFragment.setMessageForMultiList(
+                    previewMediaFragment.emptyListView.setVisibility(View.VISIBLE);
+                    previewMediaFragment.setVideoErrorMessage(
                         previewMediaFragment.getString(R.string.stream_not_possible_headline),
-                        R.string.stream_not_possible_message, R.drawable.file_movie);
+                        R.string.stream_not_possible_message);
                 }
             } else {
                 Log_OC.e(TAG, "Error streaming file: no previewMediaFragment!");
@@ -545,15 +507,16 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         @Override
         public void onPrepared(MediaPlayer vp) {
             Log_OC.v(TAG, "onPrepared");
-            mMultiListContainer.setVisibility(View.GONE);
-            mPreviewContainer.setVisibility(View.VISIBLE);
-            mVideoPreview.seekTo(mSavedPlaybackPosition);
-            if (mAutoplay) {
-                mVideoPreview.start();
+            binding.emptyView.emptyListView.setVisibility(View.GONE);
+            binding.progress.setVisibility(View.GONE);
+            binding.filePreviewContainer.setVisibility(View.VISIBLE);
+            binding.videoPreview.seekTo(savedPlaybackPosition);
+            if (autoplay) {
+                binding.videoPreview.start();
             }
-            mMediaController.setEnabled(true);
-            mMediaController.updatePausePlay();
-            mPrepared = true;
+            binding.mediaController.setEnabled(true);
+            binding.mediaController.updatePausePlay();
+            prepared = true;
         }
 
 
@@ -568,9 +531,9 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         public void onCompletion(MediaPlayer mp) {
             Log_OC.v(TAG, "completed");
             if (mp != null) {
-                mVideoPreview.seekTo(0);
+                binding.videoPreview.seekTo(0);
             } // else : called from onError()
-            mMediaController.updatePausePlay();
+            binding.mediaController.updatePausePlay();
         }
 
         /**
@@ -583,12 +546,13 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         @Override
         public boolean onError(MediaPlayer mp, int what, int extra) {
             Log_OC.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
-            mPreviewContainer.setVisibility(View.GONE);
+            binding.filePreviewContainer.setVisibility(View.GONE);
+            binding.progress.setVisibility(View.GONE);
             final Context context = getActivity();
-            if (mVideoPreview.getWindowToken() != null && context != null) {
+            if (binding.videoPreview.getWindowToken() != null && context != null) {
                 String message = ErrorFormat.toString(context, what, extra);
-                mMultiListContainer.setVisibility(View.VISIBLE);
-                setMessageForMultiList(message, R.string.preview_sorry, R.drawable.file_movie);
+                binding.emptyView.emptyListView.setVisibility(View.VISIBLE);
+                setVideoErrorMessage(message, R.string.preview_sorry);
             }
             return true;
         }
@@ -613,17 +577,24 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         super.onDestroy();
     }
 
+    @Override
+    public void onDestroyView() {
+        Log_OC.v(TAG, "onDestroyView");
+        super.onDestroyView();
+        binding = null;
+    }
+
     @Override
     public void onStop() {
         Log_OC.v(TAG, "onStop");
-        mMediaPlayerServiceConnection.unbind();
+        mediaPlayerServiceConnection.unbind();
         toggleDrawerLockMode(containerActivity, DrawerLayout.LOCK_MODE_UNLOCKED);
         super.onStop();
     }
 
     @Override
     public boolean onTouch(View v, MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_DOWN && v.equals(mVideoPreview)) {
+        if (event.getAction() == MotionEvent.ACTION_DOWN && v.equals(binding.videoPreview)) {
             // added a margin on the left to avoid interfering with gesture to open navigation drawer
             if (event.getX() / Resources.getSystem().getDisplayMetrics().density > MIN_DENSITY_RATIO) {
                 startFullScreenVideo();
@@ -634,14 +605,14 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     }
 
     private void startFullScreenVideo() {
-        Intent i = new Intent(getActivity(), PreviewVideoActivity.class);
-        i.putExtra(FileActivity.EXTRA_ACCOUNT, user.toPlatformAccount());
-        i.putExtra(FileActivity.EXTRA_FILE, getFile());
-        i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
-        i.putExtra(PreviewVideoActivity.EXTRA_STREAM_URL, mVideoUri);
-        mVideoPreview.pause();
-        i.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPreview.getCurrentPosition());
-        startActivityForResult(i, FileActivity.REQUEST_CODE__LAST_SHARED + 1);
+        Intent intent = new Intent(getActivity(), PreviewVideoActivity.class);
+        intent.putExtra(FileActivity.EXTRA_ACCOUNT, user.toPlatformAccount());
+        intent.putExtra(FileActivity.EXTRA_FILE, getFile());
+        intent.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, binding.videoPreview.isPlaying());
+        intent.putExtra(PreviewVideoActivity.EXTRA_STREAM_URL, videoUri);
+        binding.videoPreview.pause();
+        intent.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, binding.videoPreview.getCurrentPosition());
+        startActivityForResult(intent, FileActivity.REQUEST_CODE__LAST_SHARED + 1);
     }
 
     @Override
@@ -655,8 +626,8 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
         Log_OC.v(TAG, "onActivityResult " + this);
         super.onActivityResult(requestCode, resultCode, data);
         if (resultCode == Activity.RESULT_OK) {
-            mSavedPlaybackPosition = data.getIntExtra(PreviewVideoActivity.EXTRA_START_POSITION, 0);
-            mAutoplay = data.getBooleanExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, false);
+            savedPlaybackPosition = data.getIntExtra(PreviewVideoActivity.EXTRA_START_POSITION, 0);
+            autoplay = data.getBooleanExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, false);
         }
     }
 
@@ -683,9 +654,9 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     public void stopPreview(boolean stopAudio) {
         OCFile file = getFile();
         if (MimeTypeUtil.isAudio(file) && stopAudio) {
-            mMediaPlayerServiceConnection.pause();
+            mediaPlayerServiceConnection.pause();
         } else if (MimeTypeUtil.isVideo(file)) {
-            mVideoPreview.stopPlayback();
+            binding.videoPreview.stopPlayback();
         }
     }
 
@@ -700,11 +671,11 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
     }
 
     public int getPosition() {
-        if (mPrepared) {
-            mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
+        if (prepared) {
+            savedPlaybackPosition = binding.videoPreview.getCurrentPosition();
         }
-        Log_OC.v(TAG, "getting position: " + mSavedPlaybackPosition);
-        return mSavedPlaybackPosition;
+        Log_OC.v(TAG, "getting position: " + savedPlaybackPosition);
+        return savedPlaybackPosition;
     }
 
     private void toggleDrawerLockMode(ContainerActivity containerActivity, int lockMode) {

+ 27 - 22
src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java

@@ -31,6 +31,7 @@ import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import com.nextcloud.client.account.User;
@@ -107,9 +108,9 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
         }
 
         if (args.containsKey(FileDisplayActivity.EXTRA_SEARCH_QUERY)) {
-            mSearchQuery = args.getString(FileDisplayActivity.EXTRA_SEARCH_QUERY);
+            searchQuery = args.getString(FileDisplayActivity.EXTRA_SEARCH_QUERY);
         }
-        mSearchOpen = args.getBoolean(FileDisplayActivity.EXTRA_SEARCH, false);
+        searchOpen = args.getBoolean(FileDisplayActivity.EXTRA_SEARCH, false);
 
         if (savedInstanceState == null) {
             if (file == null) {
@@ -123,7 +124,7 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
             account = savedInstanceState.getParcelable(EXTRA_ACCOUNT);
         }
 
-        mHandler = new Handler();
+        handler = new Handler();
         setFile(file);
     }
 
@@ -140,7 +141,8 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
 
     @Override
     void loadAndShowTextPreview() {
-        textLoadAsyncTask = new TextLoadAsyncTask(new WeakReference<>(mTextPreview));
+        textLoadAsyncTask = new TextLoadAsyncTask(new WeakReference<>(binding.textPreview),
+                                                  new WeakReference<>(binding.emptyListProgress));
         textLoadAsyncTask.execute(getFile().getStoragePath());
     }
 
@@ -149,10 +151,12 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
      */
     private class TextLoadAsyncTask extends AsyncTask<Object, Void, StringWriter> {
         private static final int PARAMS_LENGTH = 1;
-        private final WeakReference<TextView> mTextViewReference;
+        private final WeakReference<TextView> textViewReference;
+        private final WeakReference<FrameLayout> progressViewReference;
 
-        private TextLoadAsyncTask(WeakReference<TextView> textView) {
-            mTextViewReference = textView;
+        private TextLoadAsyncTask(WeakReference<TextView> textView, WeakReference<FrameLayout> progressView) {
+            textViewReference = textView;
+            progressViewReference = progressView;
         }
 
         @Override
@@ -210,25 +214,26 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
 
         @Override
         protected void onPostExecute(final StringWriter stringWriter) {
-            final TextView textView = mTextViewReference.get();
+            final TextView textView = textViewReference.get();
 
             if (textView != null) {
-                mOriginalText = stringWriter.toString();
-                setText(textView, mOriginalText, getFile(), requireActivity());
+                originalText = stringWriter.toString();
+                setText(textView, originalText, getFile(), requireActivity());
 
-                if (mSearchView != null) {
-                    mSearchView.setOnQueryTextListener(PreviewTextFileFragment.this);
+                if (searchView != null) {
+                    searchView.setOnQueryTextListener(PreviewTextFileFragment.this);
 
-                    if (mSearchOpen) {
-                        mSearchView.setQuery(mSearchQuery, true);
+                    if (searchOpen) {
+                        searchView.setQuery(searchQuery, true);
                     }
                 }
 
                 textView.setVisibility(View.VISIBLE);
             }
 
-            if (mMultiListContainer != null) {
-                mMultiListContainer.setVisibility(View.GONE);
+            final FrameLayout progress = progressViewReference.get();
+            if (progress != null) {
+                progress.setVisibility(View.GONE);
             }
         }
     }
@@ -243,13 +248,13 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
 
         MenuItem menuItem = menu.findItem(R.id.action_search);
         menuItem.setVisible(true);
-        mSearchView = (SearchView) MenuItemCompat.getActionView(menuItem);
-        mSearchView.setMaxWidth(Integer.MAX_VALUE);
+        searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
+        searchView.setMaxWidth(Integer.MAX_VALUE);
 
-        if (mSearchOpen) {
-            mSearchView.setIconified(false);
-            mSearchView.setQuery(mSearchQuery, false);
-            mSearchView.clearFocus();
+        if (searchOpen) {
+            searchView.setIconified(false);
+            searchView.setQuery(searchQuery, false);
+            searchView.clearFocus();
         }
     }
 

+ 27 - 47
src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java

@@ -32,14 +32,13 @@ import android.text.method.LinkMovementMethod;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.device.DeviceInfo;
 import com.nextcloud.client.di.Injectable;
 import com.owncloud.android.R;
+import com.owncloud.android.databinding.TextFilePreviewBinding;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
@@ -79,23 +78,17 @@ import io.noties.prism4j.annotations.PrismBundle;
 public abstract class PreviewTextFragment extends FileFragment implements SearchView.OnQueryTextListener, Injectable {
     private static final String TAG = PreviewTextFragment.class.getSimpleName();
 
-
-    protected SearchView mSearchView;
-    protected String mSearchQuery = "";
-    protected boolean mSearchOpen;
-    protected TextView mTextPreview;
-    protected Handler mHandler;
-    protected String mOriginalText;
-    protected View mMultiListContainer;
-
-    private TextView mMultiListMessage;
-    private TextView mMultiListHeadline;
-    private ImageView mMultiListIcon;
-    private ProgressBar mMultiListProgress;
+    protected SearchView searchView;
+    protected String searchQuery = "";
+    protected boolean searchOpen;
+    protected Handler handler;
+    protected String originalText;
 
     @Inject UserAccountManager accountManager;
     @Inject DeviceInfo deviceInfo;
 
+    protected TextFilePreviewBinding binding;
+
     /**
      * {@inheritDoc}
      */
@@ -105,31 +98,12 @@ public abstract class PreviewTextFragment extends FileFragment implements Search
         super.onCreateView(inflater, container, savedInstanceState);
         Log_OC.e(TAG, "onCreateView");
 
-        View ret = inflater.inflate(R.layout.text_file_preview, container, false);
-        mTextPreview = ret.findViewById(R.id.text_preview);
-
-        setupMultiView(ret);
-        setMultiListLoadingMessage();
-
-        return ret;
-    }
-
-    private void setupMultiView(View view) {
-        mMultiListContainer = view.findViewById(R.id.empty_list_view);
-        mMultiListMessage = view.findViewById(R.id.empty_list_view_text);
-        mMultiListHeadline = view.findViewById(R.id.empty_list_view_headline);
-        mMultiListIcon = view.findViewById(R.id.empty_list_icon);
-        mMultiListProgress = view.findViewById(R.id.empty_list_progress);
-    }
+        binding = TextFilePreviewBinding.inflate(inflater, container, false);
+        View view = binding.getRoot();
 
-    private void setMultiListLoadingMessage() {
-        if (mMultiListContainer != null) {
-            mMultiListHeadline.setText(R.string.file_list_loading);
-            mMultiListMessage.setText("");
+        binding.emptyListProgress.setVisibility(View.VISIBLE);
 
-            mMultiListIcon.setVisibility(View.GONE);
-            mMultiListProgress.setVisibility(View.VISIBLE);
-        }
+        return view;
     }
 
     @Override
@@ -140,6 +114,12 @@ public abstract class PreviewTextFragment extends FileFragment implements Search
         loadAndShowTextPreview();
     }
 
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        binding = null;
+    }
+
     abstract void loadAndShowTextPreview();
 
     @Override
@@ -156,28 +136,28 @@ public abstract class PreviewTextFragment extends FileFragment implements Search
 
 
     private void performSearch(final String query, int delay) {
-        mHandler.removeCallbacksAndMessages(null);
+        handler.removeCallbacksAndMessages(null);
 
-        if (mOriginalText != null) {
+        if (originalText != null) {
             if (getActivity() instanceof FileDisplayActivity) {
                 FileDisplayActivity fileDisplayActivity = (FileDisplayActivity) getActivity();
                 fileDisplayActivity.setSearchQuery(query);
             }
-            mHandler.postDelayed(() -> {
+            handler.postDelayed(() -> {
                 if (query != null && !query.isEmpty()) {
                     if (getContext() != null && getContext().getResources() != null) {
-                        String coloredText = StringUtils.searchAndColor(mOriginalText, query,
-                            getContext().getResources().getColor(R.color.primary));
-                        mTextPreview.setText(Html.fromHtml(coloredText.replace("\n", "<br \\>")));
+                        String coloredText = StringUtils.searchAndColor(originalText, query,
+                                                                        getContext().getResources().getColor(R.color.primary));
+                        binding.textPreview.setText(Html.fromHtml(coloredText.replace("\n", "<br \\>")));
                     }
                 } else {
-                    setText(mTextPreview, mOriginalText, getFile(), getActivity());
+                    setText(binding.textPreview, originalText, getFile(), getActivity());
                 }
             }, delay);
         }
 
-        if (delay == 0 && mSearchView != null) {
-            mSearchView.clearFocus();
+        if (delay == 0 && searchView != null) {
+            searchView.clearFocus();
         }
     }
 

+ 15 - 19
src/main/java/com/owncloud/android/ui/preview/PreviewTextStringFragment.java

@@ -78,11 +78,11 @@ public class PreviewTextStringFragment extends PreviewTextFragment {
         Bundle args = getArguments();
 
         if (args.containsKey(FileDisplayActivity.EXTRA_SEARCH_QUERY)) {
-            mSearchQuery = args.getString(FileDisplayActivity.EXTRA_SEARCH_QUERY);
+            searchQuery = args.getString(FileDisplayActivity.EXTRA_SEARCH_QUERY);
         }
-        mSearchOpen = args.getBoolean(FileDisplayActivity.EXTRA_SEARCH, false);
+        searchOpen = args.getBoolean(FileDisplayActivity.EXTRA_SEARCH, false);
 
-        mHandler = new Handler();
+        handler = new Handler();
     }
 
     /**
@@ -126,27 +126,23 @@ public class PreviewTextStringFragment extends PreviewTextFragment {
 
         MenuItem menuItem = menu.findItem(R.id.action_search);
         menuItem.setVisible(true);
-        mSearchView = (SearchView) MenuItemCompat.getActionView(menuItem);
-        mSearchView.setOnQueryTextListener(this);
-        mSearchView.setMaxWidth(Integer.MAX_VALUE);
-
-        if (mSearchOpen) {
-            mSearchView.setIconified(false);
-            mSearchView.setQuery(mSearchQuery, true);
-            mSearchView.clearFocus();
+        searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
+        searchView.setOnQueryTextListener(this);
+        searchView.setMaxWidth(Integer.MAX_VALUE);
+
+        if (searchOpen) {
+            searchView.setIconified(false);
+            searchView.setQuery(searchQuery, true);
+            searchView.clearFocus();
         }
     }
 
     void loadAndShowTextPreview() {
-        if (mTextPreview != null) {
-            mOriginalText = getFile().getRichWorkspace();
-            setText(mTextPreview, mOriginalText, getFile(), requireActivity(), true, false);
-            mTextPreview.setVisibility(View.VISIBLE);
-        }
+        originalText = getFile().getRichWorkspace();
+        setText(binding.textPreview, originalText, getFile(), requireActivity(), true, false);
 
-        if (mMultiListContainer != null) {
-            mMultiListContainer.setVisibility(View.GONE);
-        }
+        binding.textPreview.setVisibility(View.VISIBLE);
+        binding.emptyListProgress.setVisibility(View.GONE);
     }
 
     private void edit() {

+ 29 - 21
src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java

@@ -67,6 +67,7 @@ public class TrashbinActivity extends DrawerActivity implements
     TrashbinContract.View,
     Injectable {
 
+    public static final int EMPTY_LIST_COUNT = 1;
     @Inject AppPreferences preferences;
     @Inject CurrentAccountProvider accountProvider;
     @Inject ClientFactory clientFactory;
@@ -138,31 +139,30 @@ public class TrashbinActivity extends DrawerActivity implements
     }
 
     protected void loadFolder() {
-        binding.swipeContainingList.setRefreshing(true);
+        if (trashbinListAdapter.getItemCount() > EMPTY_LIST_COUNT) {
+            binding.swipeContainingList.setRefreshing(true);
+        } else {
+            showInitialLoading();
+        }
         trashbinPresenter.loadFolder();
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         boolean retval = true;
-        switch (item.getItemId()) {
-            case android.R.id.home:
-                if (isDrawerOpen()) {
-                    closeDrawer();
-                } else if (trashbinPresenter.isRoot()) {
-                    onBackPressed();
-                } else {
-                    openDrawer();
-                }
-                break;
-
-            case R.id.action_empty_trashbin:
-                trashbinPresenter.emptyTrashbin();
-                break;
-
-            default:
-                retval = super.onOptionsItemSelected(item);
-                break;
+        int itemId = item.getItemId();
+        if (itemId == android.R.id.home) {
+            if (isDrawerOpen()) {
+                closeDrawer();
+            } else if (trashbinPresenter.isRoot()) {
+                onBackPressed();
+            } else {
+                openDrawer();
+            }
+        } else if (itemId == R.id.action_empty_trashbin) {
+            trashbinPresenter.emptyTrashbin();
+        } else {
+            retval = super.onOptionsItemSelected(item);
         }
 
         return retval;
@@ -236,7 +236,8 @@ public class TrashbinActivity extends DrawerActivity implements
         if (active) {
             trashbinListAdapter.setTrashbinFiles(trashbinFiles, true);
             binding.swipeContainingList.setRefreshing(false);
-            binding.emptyList.emptyListProgress.setVisibility(View.GONE);
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.list.setVisibility(View.VISIBLE);
         }
     }
 
@@ -262,9 +263,17 @@ public class TrashbinActivity extends DrawerActivity implements
         }
     }
 
+    @VisibleForTesting
+    public void showInitialLoading() {
+        binding.loadingContent.setVisibility(View.VISIBLE);
+        binding.list.setVisibility(View.GONE);
+    }
+
     @Override
     public void showError(int message) {
         if (active) {
+            binding.loadingContent.setVisibility(View.GONE);
+            binding.list.setVisibility(View.VISIBLE);
             binding.swipeContainingList.setRefreshing(false);
 
             binding.emptyList.emptyListViewHeadline.setText(R.string.common_error);
@@ -275,7 +284,6 @@ public class TrashbinActivity extends DrawerActivity implements
             binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
             binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
             binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
-            binding.emptyList.emptyListProgress.setVisibility(View.GONE);
         }
     }
 }

+ 8 - 0
src/main/res/drawable/ic_image_outline.xml

@@ -0,0 +1,8 @@
+<!-- drawable/image_outline.xml -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path android:fillColor="#000" android:pathData="M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M13.96,12.29L11.21,15.83L9.25,13.47L6.5,17H17.5L13.96,12.29Z" />
+</vector>

+ 26 - 0
src/main/res/layout/activity_list_item_header_shimmer.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2020 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<com.elyeproj.loaderviewlibrary.LoaderTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/shimmer_header"
+    android:layout_width="140dp"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="@dimen/standard_list_item_size"
+    android:layout_marginTop="@dimen/standard_margin"
+    android:layout_marginBottom="40dp" />

+ 67 - 0
src/main/res/layout/activity_list_item_shimmer.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2020 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:padding="@dimen/standard_padding">
+
+    <com.elyeproj.loaderviewlibrary.LoaderImageView
+        android:id="@+id/activity_icon"
+        android:layout_width="@dimen/activity_icon_width"
+        android:layout_height="@dimen/activity_icon_height"
+        android:layout_alignParentTop="true"
+        android:contentDescription="@null"
+        app:corners="100" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_toEndOf="@id/activity_icon"
+        android:orientation="vertical"
+        android:paddingTop="2dp"
+        android:paddingStart="@dimen/activity_icon_layout_right_end_margin"
+        android:paddingEnd="@dimen/zero">
+
+        <com.elyeproj.loaderviewlibrary.LoaderTextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textStyle="bold" />
+
+        <com.elyeproj.loaderviewlibrary.LoaderTextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp" />
+
+        <com.elyeproj.loaderviewlibrary.LoaderTextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp" />
+
+        <com.elyeproj.loaderviewlibrary.LoaderTextView
+            android:layout_width="120dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:layout_marginTop="12dp" />
+
+    </LinearLayout>
+
+</RelativeLayout>

+ 26 - 2
src/main/res/layout/activity_list_layout.xml

@@ -23,7 +23,8 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clickable="true"
-    android:fitsSystemWindows="true">
+    android:fitsSystemWindows="true"
+    android:focusable="true">
 
     <androidx.coordinatorlayout.widget.CoordinatorLayout
         android:layout_width="match_parent"
@@ -59,7 +60,30 @@
 
             </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
 
-            <include layout="@layout/empty_list" />
+            <include
+                android:id="@+id/empty_list"
+                layout="@layout/empty_list" />
+
+            <LinearLayout
+                android:id="@+id/loading_content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <com.elyeproj.loaderviewlibrary.LoaderTextView
+                    android:id="@+id/shimmer_header"
+                    android:layout_width="140dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/standard_list_item_size"
+                    android:layout_marginTop="@dimen/standard_margin"
+                    android:layout_marginBottom="40dp" />
+
+                <include layout="@layout/activity_list_item_shimmer" />
+                <include layout="@layout/activity_list_item_shimmer" />
+                <include layout="@layout/activity_list_item_shimmer" />
+                <include layout="@layout/activity_list_item_shimmer" />
+
+            </LinearLayout>
         </FrameLayout>
     </androidx.coordinatorlayout.widget.CoordinatorLayout>
 

+ 18 - 7
src/main/res/layout/contactlist_fragment.xml

@@ -20,6 +20,7 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    xmlns:tools="http://schemas.android.com/tools"
     android:animateLayoutChanges="true"
     android:orientation="vertical">
 
@@ -33,7 +34,8 @@
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"
-            android:choiceMode="multipleChoice" />
+            android:choiceMode="multipleChoice"
+            tools:listitem="@layout/contactlist_list_item" />
 
         <LinearLayout
             android:id="@+id/contactlist_restore_selected_container"
@@ -59,12 +61,21 @@
         </LinearLayout>
     </LinearLayout>
 
-    <RelativeLayout
-        android:id="@+id/empty_list_container"
-        android:layout_width="wrap_content"
+    <LinearLayout
+        android:id="@+id/loading_list_container"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_centerInParent="true">
+        android:orientation="vertical">
 
-        <include layout="@layout/empty_list" />
-    </RelativeLayout>
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+        <include layout="@layout/contactlist_list_item_shimmer" />
+    </LinearLayout>
 </RelativeLayout>

+ 40 - 0
src/main/res/layout/contactlist_list_item_shimmer.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2020 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/standard_list_item_size"
+    android:orientation="horizontal">
+
+    <com.elyeproj.loaderviewlibrary.LoaderImageView
+        android:layout_width="@dimen/contactlist_item_icon_layout_width"
+        android:layout_height="@dimen/contactlist_item_icon_layout_height"
+        android:layout_margin="@dimen/standard_margin"
+        android:contentDescription="@null"
+        app:corners="100" />
+
+    <com.elyeproj.loaderviewlibrary.LoaderTextView
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginEnd="@dimen/standard_double_margin"
+        android:layout_weight="1" />
+
+</LinearLayout>

+ 0 - 6
src/main/res/layout/empty_list.xml

@@ -36,12 +36,6 @@
         android:src="@drawable/ic_list_empty_folder"
         android:visibility="gone" />
 
-    <ProgressBar
-        android:id="@+id/empty_list_progress"
-        android:layout_width="@dimen/empty_list_progress_layout_width"
-        android:layout_height="@dimen/empty_list_progress_layout_height"
-        android:layout_gravity="center_horizontal" />
-
     <TextView
         android:id="@+id/empty_list_view_headline"
         android:layout_width="match_parent"

+ 57 - 25
src/main/res/layout/file_details_activities_fragment.xml

@@ -17,9 +17,9 @@
   You should have received a copy of the GNU Affero General Public
   License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
-
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
@@ -27,8 +27,8 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/zero"
         android:layout_marginStart="@dimen/standard_padding"
+        android:layout_marginEnd="@dimen/zero"
         android:orientation="horizontal">
 
         <com.google.android.material.textfield.TextInputEditText
@@ -52,34 +52,66 @@
 
     </LinearLayout>
 
-    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-        android:id="@+id/swipe_containing_list"
+    <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:footerDividersEnabled="false"
-        android:visibility="visible">
+        android:layout_height="match_parent">
 
-        <androidx.recyclerview.widget.RecyclerView
-            android:id="@android:id/list"
+        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+            android:id="@+id/swipe_containing_list"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:clipToPadding="false"
-            android:scrollbarStyle="outsideOverlay"
-            android:scrollbars="vertical"
-            android:visibility="visible"/>
+            android:footerDividersEnabled="false"
+            android:visibility="visible">
 
-    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@android:id/list"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_marginLeft="-3dp"
+                android:layout_marginRight="-3dp"
+                android:layout_marginBottom="-3dp"
+                android:background="@color/bg_default"
+                android:clipToPadding="false"
+                android:scrollbarStyle="outsideOverlay"
+                android:scrollbars="vertical"
+                android:visibility="visible"
+                tools:listitem="@layout/activity_list_item" />
 
-    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-        android:id="@+id/swipe_containing_empty"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:footerDividersEnabled="false"
-        android:visibility="visible">
-
-        <include
-            android:id="@+id/empty_list"
-            layout="@layout/empty_list" />
-    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+
+        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+            android:id="@+id/swipe_containing_empty"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:footerDividersEnabled="false"
+            android:visibility="visible">
+
+            <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+                <LinearLayout
+                    android:id="@+id/loading_content"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:visibility="visible">
+
+                    <include layout="@layout/activity_list_item_shimmer" />
+
+                    <include layout="@layout/activity_list_item_shimmer" />
+
+                    <include layout="@layout/activity_list_item_shimmer" />
+
+                </LinearLayout>
+
+                <include
+                    android:id="@+id/empty_list"
+                    layout="@layout/empty_list" />
+
+            </FrameLayout>
+        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+
+    </FrameLayout>
 
 </LinearLayout>

+ 37 - 11
src/main/res/layout/file_preview.xml → src/main/res/layout/fragment_preview_media.xml

@@ -2,6 +2,7 @@
 <!--
   ownCloud Android client application
 
+  Copyright (C) 2020 Andy Scherzinger
   Copyright (C) 2015 ownCloud Inc.
 
   This program is free software: you can redistribute it and/or modify
@@ -19,12 +20,13 @@
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                xmlns:tools="http://schemas.android.com/tools"
-                android:id="@+id/top"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center"
-                tools:context=".ui.fragment.FilePreviewFragment">
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/top"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    tools:context=".ui.preview.PreviewMediaFragment">
 
     <RelativeLayout
         android:id="@+id/file_preview_container"
@@ -38,8 +40,7 @@
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_above="@+id/media_controller"
-            android:layout_alignParentTop="true"
-            >
+            android:layout_alignParentTop="true">
 
             <ImageView
                 android:id="@+id/image_preview"
@@ -55,8 +56,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:layout_gravity="center"
-                android:visibility="gone"
-                />
+                android:visibility="gone" />
 
         </FrameLayout>
 
@@ -69,9 +69,35 @@
     </RelativeLayout>
 
     <FrameLayout
+        android:id="@+id/progress"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-        <include layout="@layout/empty_list" />
+
+        <com.elyeproj.loaderviewlibrary.LoaderImageView
+            android:layout_width="@dimen/empty_list_icon_layout_width"
+            android:layout_height="@dimen/empty_list_icon_layout_width"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            app:corners="24" />
+
+        <ImageView
+            android:layout_width="@dimen/empty_list_icon_layout_width"
+            android:layout_height="@dimen/empty_list_icon_layout_height"
+            android:padding="@dimen/standard_half_padding"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            android:src="@drawable/file_movie"
+            app:tint="@color/bg_default" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <include
+            android:id="@+id/empty_view"
+            layout="@layout/empty_list" />
     </FrameLayout>
 
 </RelativeLayout>

+ 31 - 5
src/main/res/layout/notifications_layout.xml

@@ -19,13 +19,14 @@
   License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
 <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/drawer_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clickable="true"
-    android:fitsSystemWindows="true">
+    android:fitsSystemWindows="true"
+    android:focusable="true">
 
     <androidx.coordinatorlayout.widget.CoordinatorLayout
         android:layout_width="match_parent"
@@ -53,11 +54,11 @@
                     android:layout_marginLeft="-3dp"
                     android:layout_marginRight="-3dp"
                     android:layout_marginBottom="-3dp"
+                    android:background="@color/bg_default"
                     android:clipToPadding="false"
                     android:scrollbarStyle="outsideOverlay"
                     android:scrollbars="vertical"
                     android:visibility="visible"
-                    android:background="@color/bg_default"
                     tools:listitem="@layout/notification_list_item" />
 
             </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@@ -69,7 +70,32 @@
                 android:footerDividersEnabled="false"
                 android:visibility="visible">
 
-                <include layout="@layout/empty_list"/>
+                <FrameLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent">
+
+                    <LinearLayout
+                        android:id="@+id/loading_content"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:visibility="visible">
+
+                        <include layout="@layout/activity_list_item_shimmer" />
+
+                        <include layout="@layout/activity_list_item_shimmer" />
+
+                        <include layout="@layout/activity_list_item_shimmer" />
+
+                        <include layout="@layout/activity_list_item_shimmer" />
+
+                    </LinearLayout>
+
+                    <include
+                        android:id="@+id/empty_list"
+                        layout="@layout/empty_list" />
+
+                </FrameLayout>
             </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
 
         </FrameLayout>
@@ -79,6 +105,6 @@
         layout="@layout/drawer"
         android:layout_width="@dimen/drawer_width"
         android:layout_height="match_parent"
-        android:layout_gravity="start"/>
+        android:layout_gravity="start" />
 
 </androidx.drawerlayout.widget.DrawerLayout>

+ 77 - 9
src/main/res/layout/preview_image_fragment.xml

@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
   ownCloud Android client application
 
   Copyright (C) 2015  ownCloud Inc.
@@ -17,8 +16,8 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/top"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -28,12 +27,81 @@
         android:id="@+id/image"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_centerInParent="true"
         android:layout_margin="@dimen/zero"
         android:contentDescription="@string/preview_image_description"
         android:src="@drawable/image_fail" />
 
-    <include
-        android:id="@+id/emptyList"
-        layout="@layout/empty_list" />
-</RelativeLayout>
+    <LinearLayout
+        android:id="@+id/empty_list_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:layout_margin="@dimen/standard_margin"
+        android:gravity="center_vertical|center_horizontal"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/standard_double_margin">
+
+        <ImageView
+            android:id="@+id/empty_list_icon"
+            android:layout_width="@dimen/empty_list_icon_layout_width"
+            android:layout_height="@dimen/empty_list_icon_layout_height"
+            android:contentDescription="@string/file_list_folder"
+            android:src="@drawable/file_image" />
+
+        <TextView
+            android:id="@+id/empty_list_view_headline"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:ellipsize="end"
+            android:gravity="center"
+            android:maxLines="2"
+            android:paddingTop="@dimen/standard_padding"
+            android:paddingBottom="@dimen/standard_half_padding"
+            android:text="@string/file_list_loading"
+            android:textSize="26sp" />
+
+        <TextView
+            android:id="@+id/empty_list_view_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            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" />
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/empty_list_view_action"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/standard_half_margin"
+            android:theme="@style/Button.Primary"
+            android:visibility="gone"
+            app:cornerRadius="@dimen/button_corner_radius" />
+    </LinearLayout>
+
+    <FrameLayout
+        android:id="@+id/empty_list_progress"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <com.elyeproj.loaderviewlibrary.LoaderImageView
+            android:layout_width="@dimen/empty_list_icon_layout_width"
+            android:layout_height="@dimen/empty_list_icon_layout_width"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            app:corners="24" />
+
+        <ImageView
+            android:layout_width="@dimen/empty_list_icon_layout_width"
+            android:layout_height="@dimen/empty_list_icon_layout_height"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            android:src="@drawable/ic_image_outline"
+            app:tint="@color/bg_default" />
+
+    </FrameLayout>
+</FrameLayout>

+ 16 - 4
src/main/res/layout/synced_folders_layout.xml

@@ -40,10 +40,6 @@
             android:orientation="vertical"
             app:layout_behavior="@string/appbar_scrolling_view_behavior">
 
-            <include
-                android:id="@+id/emptyList"
-                layout="@layout/empty_list" />
-
             <androidx.recyclerview.widget.RecyclerView
                 android:id="@android:id/list"
                 android:layout_width="match_parent"
@@ -55,6 +51,22 @@
                 android:scrollbarStyle="outsideOverlay"
                 android:scrollbars="vertical"
                 android:visibility="visible" />
+
+            <include
+                android:id="@+id/emptyList"
+                layout="@layout/empty_list" />
+
+            <LinearLayout
+                android:id="@+id/loading_content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+                <include layout="@layout/synced_folders_list_item_shimmer" />
+                <include layout="@layout/synced_folders_list_item_shimmer" />
+
+            </LinearLayout>
         </FrameLayout>
 
     </androidx.coordinatorlayout.widget.CoordinatorLayout>

+ 161 - 0
src/main/res/layout/synced_folders_list_item_shimmer.xml

@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2020 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <RelativeLayout
+        android:id="@+id/header_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/standard_margin"
+        android:layout_marginTop="12dp"
+        android:layout_marginEnd="@dimen/zero"
+        android:layout_marginBottom="11dp">
+
+        <LinearLayout
+            android:id="@+id/title_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignTop="@+id/buttonBar"
+            android:layout_alignBottom="@+id/buttonBar"
+            android:layout_alignParentStart="true"
+            android:layout_toStartOf="@+id/buttonBar">
+
+            <com.elyeproj.loaderviewlibrary.LoaderImageView
+                android:id="@+id/type"
+                android:layout_width="@dimen/synced_folders_item_type_layout_width"
+                android:layout_height="@dimen/synced_folders_item_type_layout_height"
+                android:layout_gravity="start|center_vertical"
+                android:layout_marginEnd="@dimen/synced_folders_item_type_layout_right_end_margin"
+                android:contentDescription="@null"
+                app:corners="100" />
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="start|center_vertical"
+                android:textStyle="bold" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/buttonBar"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true">
+
+            <com.elyeproj.loaderviewlibrary.LoaderImageView
+                android:id="@+id/syncStatusButton"
+                android:layout_width="@dimen/synced_folders_item_type_layout_width"
+                android:layout_height="@dimen/synced_folders_item_type_layout_height"
+                android:layout_gravity="start|center_vertical"
+                android:layout_marginStart="@dimen/standard_margin"
+                android:layout_marginEnd="@dimen/standard_margin"
+                android:contentDescription="@null"
+                app:corners="100" />
+
+            <com.elyeproj.loaderviewlibrary.LoaderImageView
+                android:id="@+id/settingsButton"
+                android:layout_width="16dp"
+                android:layout_height="@dimen/synced_folders_item_type_layout_height"
+                android:layout_gravity="start|center_vertical"
+                android:layout_marginEnd="@dimen/standard_margin"
+                android:contentDescription="@null" />
+
+        </LinearLayout>
+    </RelativeLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="-3dp"
+        android:orientation="horizontal">
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="3dp"
+        android:layout_marginEnd="-3dp"
+        android:orientation="horizontal">
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+        <com.nextcloud.ui.SquareLoaderImageView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="3dp"
+            android:layout_weight="1"
+            android:contentDescription="@null" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 23 - 1
src/main/res/layout/text_file_preview.xml

@@ -41,5 +41,27 @@
 
     </ScrollView>
 
-    <include layout="@layout/empty_list" />
+    <FrameLayout
+        android:id="@+id/empty_list_progress"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <com.elyeproj.loaderviewlibrary.LoaderImageView
+            android:layout_width="@dimen/empty_list_icon_layout_width"
+            android:layout_height="@dimen/empty_list_icon_layout_width"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            app:corners="24" />
+
+        <ImageView
+            android:layout_width="@dimen/empty_list_icon_layout_width"
+            android:layout_height="@dimen/empty_list_icon_layout_height"
+            android:padding="@dimen/standard_half_padding"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            android:src="@drawable/file_text"
+            app:tint="@color/bg_default" />
+
+    </FrameLayout>
+
 </androidx.coordinatorlayout.widget.CoordinatorLayout>

+ 13 - 0
src/main/res/layout/trashbin_activity.xml

@@ -57,6 +57,19 @@
                     android:layout_height="match_parent" />
             </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
 
+            <LinearLayout
+                android:id="@+id/loading_content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+                <include layout="@layout/trashbin_item_shimmer" />
+                <include layout="@layout/trashbin_item_shimmer" />
+                <include layout="@layout/trashbin_item_shimmer" />
+
+            </LinearLayout>
+
             <include
                 android:id="@+id/empty_list"
                 layout="@layout/empty_list" />

+ 92 - 0
src/main/res/layout/trashbin_item_shimmer.xml

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2020 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/ListItemLayout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/standard_list_item_size"
+    android:background="?android:attr/selectableItemBackground"
+    android:descendantFocusability="blocksDescendants"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:baselineAligned="false"
+        android:orientation="horizontal"
+        android:paddingTop="@dimen/standard_padding"
+        android:paddingBottom="@dimen/standard_padding"
+        android:paddingEnd="@dimen/standard_padding"
+        android:paddingStart="@dimen/zero">
+
+        <com.elyeproj.loaderviewlibrary.LoaderImageView
+            android:id="@+id/thumbnail"
+            android:layout_width="@dimen/file_icon_size"
+            android:layout_height="@dimen/file_icon_size"
+            android:layout_marginLeft="@dimen/standard_margin"
+            android:layout_marginRight="@dimen/standard_margin"
+            android:contentDescription="@null"
+            app:corners="16" />
+
+        <LinearLayout
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="top"
+            android:orientation="vertical">
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:id="@+id/Filename"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="@dimen/standard_quarter_margin"
+                android:textStyle="bold" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal">
+
+                <com.elyeproj.loaderviewlibrary.LoaderTextView
+                    android:id="@+id/fileSize"
+                    android:layout_width="80dp"
+                    android:layout_height="12sp" />
+
+                <com.elyeproj.loaderviewlibrary.LoaderTextView
+                    android:id="@+id/deletionTimestamp"
+                    android:layout_width="80dp"
+                    android:layout_height="12sp"
+                    android:layout_marginStart="@dimen/standard_half_margin"
+                    android:layout_marginEnd="@dimen/standard_half_margin" />
+
+            </LinearLayout>
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:id="@+id/originalLocation"
+                android:layout_width="100dp"
+                android:layout_height="12sp"
+                android:layout_marginTop="4dp" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 93 - 1
src/main/res/layout/user_info_layout.xml

@@ -104,10 +104,102 @@
         app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
         tools:itemCount="3"
         tools:listitem="@layout/user_info_details_table_item"
-        tools:visibility="visible" />
+        tools:visibility="gone" />
 
     <include
         android:id="@+id/emptyList"
         layout="@layout/empty_list" />
 
+    <LinearLayout
+        android:id="@+id/loading_content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/iconized_single_line_item_layout_height"
+            android:orientation="horizontal">
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="@dimen/iconized_single_line_item_icon_size"
+                android:layout_height="@dimen/iconized_single_line_item_icon_size"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                app:corners="100" />
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                android:layout_marginEnd="@dimen/standard_margin" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/iconized_single_line_item_layout_height"
+            android:orientation="horizontal">
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="@dimen/iconized_single_line_item_icon_size"
+                android:layout_height="@dimen/iconized_single_line_item_icon_size"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                app:corners="100" />
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                android:layout_marginEnd="@dimen/standard_margin" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/iconized_single_line_item_layout_height"
+            android:orientation="horizontal">
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="@dimen/iconized_single_line_item_icon_size"
+                android:layout_height="@dimen/iconized_single_line_item_icon_size"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                app:corners="100" />
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                android:layout_marginEnd="@dimen/standard_margin" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/iconized_single_line_item_layout_height"
+            android:orientation="horizontal">
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="@dimen/iconized_single_line_item_icon_size"
+                android:layout_height="@dimen/iconized_single_line_item_icon_size"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                app:corners="100" />
+
+            <com.elyeproj.loaderviewlibrary.LoaderTextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/user_info_icon_horizontal_margin"
+                android:layout_marginEnd="@dimen/standard_margin" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
 </LinearLayout>

+ 0 - 2
src/main/res/values/dims.xml

@@ -101,8 +101,6 @@
     <dimen name="contactlist_item_icon_layout_height">40dp</dimen>
     <dimen name="empty_list_icon_layout_width">72dp</dimen>
     <dimen name="empty_list_icon_layout_height">72dp</dimen>
-    <dimen name="empty_list_progress_layout_width">72dp</dimen>
-    <dimen name="empty_list_progress_layout_height">72dp</dimen>
     <dimen name="file_details_username_text_size">16sp</dimen>
     <dimen name="grid_image_shared_icon_layout_top_margin">24dp</dimen>
     <dimen name="grid_image_local_file_indicator_layout_width">16dp</dimen>

+ 19 - 7
src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.java

@@ -79,11 +79,11 @@ public class ActivitiesPresenterTest {
     }
 
     @Test
-    public void loadActivitiesFromRepositoryIntoView() {
+    public void loadInitialActivitiesFromRepositoryIntoView() {
         // When loading activities from repository is requested from presenter...
         activitiesPresenter.loadActivities(-1);
-        // Progress indicator is shown in view
-        verify(view).setProgressIndicatorState(eq(true));
+        // empty list view is hidden in view
+        verify(view).showLoadingMessage();
         // Repository starts retrieving activities from server
         verify(activitiesRepository).getActivities(eq(-1), loadActivitiesCallbackArgumentCaptor.capture());
         // Repository returns data
@@ -95,17 +95,29 @@ public class ActivitiesPresenterTest {
     }
 
     @Test
-    public void loadActivitiesFromRepositoryShowError() {
+    public void loadFollowUpActivitiesFromRepositoryIntoView() {
         // When loading activities from repository is requested from presenter...
-        activitiesPresenter.loadActivities(-1);
+        activitiesPresenter.loadActivities(1);
         // Progress indicator is shown in view
         verify(view).setProgressIndicatorState(eq(true));
         // Repository starts retrieving activities from server
-        verify(activitiesRepository).getActivities(eq(-1), loadActivitiesCallbackArgumentCaptor.capture());
+        verify(activitiesRepository).getActivities(eq(1), loadActivitiesCallbackArgumentCaptor.capture());
         // Repository returns data
-        loadActivitiesCallbackArgumentCaptor.getValue().onActivitiesLoadedError("error");
+        loadActivitiesCallbackArgumentCaptor.getValue().onActivitiesLoaded(activitiesList, nextcloudClient, 1);
         // Progress indicator is hidden
         verify(view).setProgressIndicatorState(eq(false));
+        // List of activities is shown in view.
+        verify(view).showActivities(eq(activitiesList), eq(nextcloudClient), eq(1));
+    }
+
+    @Test
+    public void loadActivitiesFromRepositoryShowError() {
+        // When loading activities from repository is requested from presenter...
+        activitiesPresenter.loadActivities(-1);
+        // Repository starts retrieving activities from server
+        verify(activitiesRepository).getActivities(eq(-1), loadActivitiesCallbackArgumentCaptor.capture());
+        // Repository returns data
+        loadActivitiesCallbackArgumentCaptor.getValue().onActivitiesLoadedError("error");
         // Correct error is shown in view
         verify(view).showActivitiesLoadError(eq("error"));
     }