Selaa lähdekoodia

Extract responsibilities from FileMenuFilter static methods to utility classes.

God class count -= 1

Signed-off-by: Álvaro Brey <alvaro.brey@nextcloud.com>
Álvaro Brey 2 vuotta sitten
vanhempi
commit
689a4bda6a
19 muutettua tiedostoa jossa 203 lisäystä ja 189 poistoa
  1. 17 6
      app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt
  2. 3 1
      app/src/debug/java/com/nextcloud/client/TestActivity.kt
  3. 2 2
      app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt
  4. 9 15
      app/src/main/java/com/nextcloud/ui/fileactions/FileActionsViewModel.kt
  5. 55 0
      app/src/main/java/com/nextcloud/utils/MenuUtils.kt
  6. 59 117
      app/src/main/java/com/owncloud/android/files/FileMenuFilter.java
  7. 5 1
      app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
  8. 4 4
      app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
  9. 6 3
      app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt
  10. 5 4
      app/src/main/java/com/owncloud/android/ui/asynctasks/TextEditorLoadUrlTask.java
  11. 4 7
      app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
  12. 7 5
      app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java
  13. 6 1
      app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt
  14. 6 7
      app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
  15. 5 5
      app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
  16. 4 4
      app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
  17. 0 1
      app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  18. 4 4
      app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java
  19. 2 2
      app/src/main/java/com/owncloud/android/ui/preview/pdf/PreviewPdfFragment.kt

+ 17 - 6
app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt

@@ -26,6 +26,7 @@ import androidx.test.core.app.launchActivity
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.nextcloud.client.TestActivity
 import com.nextcloud.client.account.User
+import com.nextcloud.utils.EditorUtils
 import com.owncloud.android.AbstractIT
 import com.owncloud.android.R
 import com.owncloud.android.datamodel.FileDataStorageManager
@@ -49,6 +50,7 @@ import org.junit.Test
 import org.junit.runner.RunWith
 import java.security.SecureRandom
 
+// TODO update this class to an unit test checking FileActions instead of an actual menu, and not using filter()
 @RunWith(AndroidJUnit4::class)
 class FileMenuFilterIT : AbstractIT() {
 
@@ -67,6 +69,9 @@ class FileMenuFilterIT : AbstractIT() {
     @MockK
     private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder
 
+    @MockK
+    private lateinit var mockEditorUtils: EditorUtils
+
     @Before
     fun setup() {
         MockKAnnotations.init(this)
@@ -78,6 +83,8 @@ class FileMenuFilterIT : AbstractIT() {
         every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder
         every { mockStorageManager.getFileById(any()) } returns OCFile("/")
         every { mockStorageManager.getFolderContent(any(), any()) } returns ArrayList<OCFile>()
+        every { mockEditorUtils.isEditorAvailable(any(), any()) } returns false
+        every { mockEditorUtils.getEditor(any(), any()) } returns null
     }
 
     @Test
@@ -188,7 +195,10 @@ class FileMenuFilterIT : AbstractIT() {
             it.onActivity { activity ->
                 val menu = getMenu(activity)
 
-                var sut = FileMenuFilter(encryptedFolder, mockComponentsGetter, activity, true, user)
+                val filterFactory =
+                    FileMenuFilter.Factory(mockStorageManager, activity, mockEditorUtils)
+
+                var sut = filterFactory.newInstance(encryptedFolder, mockComponentsGetter, true, user)
                 sut.filter(menu, false)
 
                 // encrypted folder, with content
@@ -196,21 +206,21 @@ class FileMenuFilterIT : AbstractIT() {
                 assertFalse(menu.findItem(R.id.action_encrypted).isVisible)
 
                 // encrypted, but empty folder
-                sut = FileMenuFilter(encryptedEmptyFolder, mockComponentsGetter, activity, true, user)
+                sut = filterFactory.newInstance(encryptedEmptyFolder, mockComponentsGetter, true, user)
                 sut.filter(menu, false)
 
                 assertTrue(menu.findItem(R.id.action_unset_encrypted).isVisible)
                 assertFalse(menu.findItem(R.id.action_encrypted).isVisible)
 
                 // regular folder, with content
-                sut = FileMenuFilter(normalFolder, mockComponentsGetter, activity, true, user)
+                sut = filterFactory.newInstance(normalFolder, mockComponentsGetter, true, user)
                 sut.filter(menu, false)
 
                 assertFalse(menu.findItem(R.id.action_unset_encrypted).isVisible)
                 assertFalse(menu.findItem(R.id.action_encrypted).isVisible)
 
                 // regular folder, without content
-                sut = FileMenuFilter(normalEmptyFolder, mockComponentsGetter, activity, true, user)
+                sut = filterFactory.newInstance(normalEmptyFolder, mockComponentsGetter, true, user)
                 sut.filter(menu, false)
 
                 assertFalse(menu.findItem(R.id.action_unset_encrypted).isVisible)
@@ -229,7 +239,6 @@ class FileMenuFilterIT : AbstractIT() {
     private fun configureCapability(capability: OCCapability) {
         every { mockStorageManager.getCapability(any<User>()) } returns capability
         every { mockStorageManager.getCapability(any<String>()) } returns capability
-        every { mockComponentsGetter.storageManager } returns mockStorageManager
     }
 
     private fun getMenu(activity: TestActivity): Menu {
@@ -250,7 +259,9 @@ class FileMenuFilterIT : AbstractIT() {
             it.onActivity { activity ->
                 val menu = getMenu(activity)
 
-                val sut = FileMenuFilter(file, mockComponentsGetter, activity, true, user)
+                val filterFactory =
+                    FileMenuFilter.Factory(mockStorageManager, activity, mockEditorUtils)
+                val sut = filterFactory.newInstance(file, mockComponentsGetter, true, user)
 
                 sut.filter(menu, false)
 

+ 3 - 1
app/src/debug/java/com/nextcloud/client/TestActivity.kt

@@ -27,8 +27,10 @@ import androidx.fragment.app.Fragment
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 import com.nextcloud.client.network.Connectivity
 import com.nextcloud.client.network.ConnectivityService
+import com.nextcloud.utils.EditorUtils
 import com.owncloud.android.R
 import com.owncloud.android.databinding.TestLayoutBinding
+import com.owncloud.android.datamodel.ArbitraryDataProvider
 import com.owncloud.android.datamodel.FileDataStorageManager
 import com.owncloud.android.datamodel.OCFile
 import com.owncloud.android.files.services.FileDownloader
@@ -144,7 +146,7 @@ class TestActivity :
 
     override fun getFileOperationsHelper(): FileOperationsHelper {
         if (!this::fileOperation.isInitialized) {
-            fileOperation = FileOperationsHelper(this, userAccountManager, connectivityServiceMock)
+            fileOperation = FileOperationsHelper(this, userAccountManager, connectivityServiceMock, EditorUtils(ArbitraryDataProvider(contentResolver)))
         }
 
         return fileOperation

+ 2 - 2
app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt

@@ -44,9 +44,9 @@ import javax.inject.Inject
 // TODO give events back
 // TODO drag handle
 // TODO theming
+// TODO scrollable (for small screens)
 class FileActionsBottomSheet private constructor() : BottomSheetDialogFragment(), Injectable {
 
-    // TODO refactor FileMenuFilter and inject needed things into it
     lateinit var componentsGetter: ComponentsGetter
 
     // TODO replace with fragment listener from Activity
@@ -69,7 +69,7 @@ class FileActionsBottomSheet private constructor() : BottomSheetDialogFragment()
         // TODO pass only IDs, fetch from DB to avoid TransactionTooLarge
         val files: Array<OCFile>? = args.getParcelableArray(ARG_FILES) as Array<OCFile>?
         require(files != null)
-        val numberOfAllFiles = args.getInt(ARG_ALL_FILES_COUNT, 1)
+        val numberOfAllFiles: Int = args.getInt(ARG_ALL_FILES_COUNT, 1)
         val isOverflow = args.getBoolean(ARG_IS_OVERFLOW, false)
 
         viewModel = ViewModelProvider(this, vmFactory)[FileActionsViewModel::class.java]

+ 9 - 15
app/src/main/java/com/nextcloud/ui/fileactions/FileActionsViewModel.kt

@@ -22,12 +22,10 @@
 
 package com.nextcloud.ui.fileactions
 
-import android.app.Application
-import android.content.Context
 import androidx.annotation.IdRes
-import androidx.lifecycle.AndroidViewModel
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
 import com.nextcloud.client.account.CurrentAccountProvider
 import com.owncloud.android.datamodel.OCFile
 import com.owncloud.android.files.FileMenuFilter
@@ -35,19 +33,16 @@ import com.owncloud.android.ui.activity.ComponentsGetter
 import javax.inject.Inject
 
 class FileActionsViewModel @Inject constructor(
-    application: Application,
-    private val currentAccountProvider: CurrentAccountProvider
+    private val currentAccountProvider: CurrentAccountProvider,
+    private val filterFactory: FileMenuFilter.Factory
 ) :
-    AndroidViewModel(application) {
+    ViewModel() {
 
     sealed interface UiState {
         object Loading : UiState
         class Loaded(val actions: List<FileAction>) : UiState
     }
 
-    private val context: Context
-        get() = getApplication()
-
     private val _uiState: MutableLiveData<UiState> = MutableLiveData(UiState.Loading)
     val uiState: LiveData<UiState>
         get() = _uiState
@@ -60,15 +55,14 @@ class FileActionsViewModel @Inject constructor(
     fun load(
         files: Collection<OCFile>,
         componentsGetter: ComponentsGetter,
-        numberOfAllFiles: Int,
-        isOverflow: Boolean
+        numberOfAllFiles: Int?,
+        isOverflow: Boolean?
     ) {
-        val toHide = FileMenuFilter(
-            numberOfAllFiles,
+        val toHide = filterFactory.newInstance(
+            numberOfAllFiles ?: 1,
             files.toList(),
             componentsGetter,
-            context,
-            isOverflow,
+            isOverflow ?: false,
             currentAccountProvider.user
         )
             .getToHide(false)

+ 55 - 0
app/src/main/java/com/nextcloud/utils/MenuUtils.kt

@@ -0,0 +1,55 @@
+/*
+ * Nextcloud Android client application
+ *
+ *  @author Álvaro Brey
+ *  Copyright (C) 2022 Álvaro Brey
+ *  Copyright (C) 2022 Nextcloud GmbH
+ *
+ * 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.utils
+
+import android.view.Menu
+import android.view.MenuItem
+import androidx.core.view.children
+
+object MenuUtils {
+
+    @JvmStatic
+    fun showMenuItem(item: MenuItem?) {
+        item?.apply {
+            isVisible = true
+            isEnabled = true
+        }
+    }
+
+    @JvmStatic
+    fun hideMenuItem(item: MenuItem?) {
+        item?.apply {
+            isVisible = false
+            isEnabled = false
+        }
+    }
+
+    @JvmStatic
+    fun hideAll(menu: Menu?) {
+        menu?.children?.forEach(::hideMenuItem)
+    }
+
+    @JvmStatic
+    fun hideMenuItems(vararg items: MenuItem?) {
+        items.filterNotNull().forEach(::hideMenuItem)
+    }
+}

+ 59 - 117
app/src/main/java/com/owncloud/android/files/FileMenuFilter.java

@@ -22,21 +22,19 @@
 package com.owncloud.android.files;
 
 import android.accounts.AccountManager;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.view.Menu;
 import android.view.MenuItem;
 
-import com.google.gson.Gson;
 import com.nextcloud.android.files.FileLockingHelper;
 import com.nextcloud.client.account.User;
+import com.nextcloud.utils.EditorUtils;
+import com.nextcloud.utils.MenuUtils;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.ArbitraryDataProvider;
+import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.lib.common.DirectEditing;
-import com.owncloud.android.lib.common.Editor;
 import com.owncloud.android.lib.resources.status.OCCapability;
 import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
 import com.owncloud.android.ui.activity.ComponentsGetter;
@@ -49,9 +47,9 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
+import javax.inject.Inject;
+
 import androidx.annotation.IdRes;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 
 /**
  * Filters out the file actions available in a given {@link Menu} for a given {@link OCFile}
@@ -70,24 +68,54 @@ public class FileMenuFilter {
     private final boolean overflowMenu;
     private final User user;
     private final String userId;
-
-    /**
-     * Constructor
-     *
-     * @param numberOfAllFiles  Number of all displayed files
-     * @param files             Collection of {@link OCFile} file targets of the action to filter in the {@link Menu}.
-     * @param componentsGetter  Accessor to app components, needed to access synchronization services
-     * @param context           Android {@link Context}, needed to access build setup resources.
-     * @param overflowMenu      true if the overflow menu items are being filtered
-     * @param user              currently active user
-     */
-    public FileMenuFilter(int numberOfAllFiles,
-                          Collection<OCFile> files,
-                          ComponentsGetter componentsGetter,
-                          Context context,
-                          boolean overflowMenu,
-                          User user
-    ) {
+    private final FileDataStorageManager storageManager;
+    private final EditorUtils editorUtils;
+
+
+    public static class Factory {
+        private FileDataStorageManager storageManager;
+        private Context context;
+        private EditorUtils editorUtils;
+
+        @Inject
+        public Factory(final FileDataStorageManager storageManager, final Context context, final EditorUtils editorUtils) {
+            this.storageManager = storageManager;
+            this.context = context;
+            this.editorUtils = editorUtils;
+        }
+
+        /**
+         * @param numberOfAllFiles Number of all displayed files
+         * @param files            Collection of {@link OCFile} file targets of the action to filter in the {@link Menu}.
+         * @param componentsGetter Accessor to app components, needed to access synchronization services
+         * @param overflowMenu     true if the overflow menu items are being filtered
+         * @param user             currently active user
+         */
+        public FileMenuFilter newInstance(final int numberOfAllFiles, final Collection<OCFile> files, final ComponentsGetter componentsGetter, boolean overflowMenu, User user) {
+            return new FileMenuFilter(storageManager, editorUtils, numberOfAllFiles, files, componentsGetter, context, overflowMenu, user);
+        }
+
+        /**
+         * @param file             {@link OCFile} file target
+         * @param componentsGetter Accessor to app components, needed to access synchronization services
+         * @param overflowMenu     true if the overflow menu items are being filtered
+         * @param user             currently active user
+         */
+        public FileMenuFilter newInstance(final OCFile file, final ComponentsGetter componentsGetter, boolean overflowMenu, User user) {
+            return newInstance(1, Collections.singletonList(file), componentsGetter, overflowMenu, user);
+        }
+    }
+
+
+    private FileMenuFilter(FileDataStorageManager storageManager, EditorUtils editorUtils, int numberOfAllFiles,
+                           Collection<OCFile> files,
+                           ComponentsGetter componentsGetter,
+                           Context context,
+                           boolean overflowMenu,
+                           User user
+                          ) {
+        this.storageManager = storageManager;
+        this.editorUtils = editorUtils;
         this.numberOfAllFiles = numberOfAllFiles;
         this.files = files;
         this.componentsGetter = componentsGetter;
@@ -100,25 +128,6 @@ public class FileMenuFilter {
                          com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
     }
 
-    /**
-     * Constructor
-     *
-     * @param file              {@link OCFile} target of the action to filter in the {@link Menu}.
-     * @param componentsGetter  Accessor to app components, needed to access synchronization services
-     * @param context           Android {@link Context}, needed to access build setup resources.
-     * @param overflowMenu      true if the overflow menu items are being filtered
-     * @param user              currently active user
-     */
-    @VisibleForTesting // TODO remove this constructor for testing too
-    public FileMenuFilter(OCFile file,
-                          ComponentsGetter componentsGetter,
-                          Context context,
-                          boolean overflowMenu,
-                          User user
-    ) {
-        this(1, Collections.singletonList(file), componentsGetter, context, overflowMenu, user);
-    }
-
     /**
      * Temporary while migrating to bottom sheet
      *
@@ -144,7 +153,7 @@ public class FileMenuFilter {
      */
     public void filter(Menu menu, boolean inSingleFileFragment) {
         if (files == null || files.isEmpty()) {
-            hideAll(menu);
+            MenuUtils.hideAll(menu);
         } else {
             List<Integer> toShow = new ArrayList<>();
             List<Integer> toHide = new ArrayList<>();
@@ -154,7 +163,7 @@ public class FileMenuFilter {
             for (int i : toShow) {
                 final MenuItem item = menu.findItem(i);
                 if (item != null) {
-                    showMenuItem(item);
+                    MenuUtils.showMenuItem(item);
                 } else {
                     // group
                     menu.setGroupVisible(i, true);
@@ -164,7 +173,7 @@ public class FileMenuFilter {
             for (int i : toHide) {
                 final MenuItem item = menu.findItem(i);
                 if (item != null) {
-                    hideMenuItem(item);
+                    MenuUtils.hideMenuItem(item);
                 } else {
                     // group
                     menu.setGroupVisible(i, false);
@@ -173,41 +182,6 @@ public class FileMenuFilter {
         }
     }
 
-    public static void hideAll(Menu menu) {
-        if (menu != null) {
-            for (int i = 0; i < menu.size(); i++) {
-                hideMenuItem(menu.getItem(i));
-            }
-        }
-    }
-
-    /**
-     * hides a given {@link MenuItem}.
-     *
-     * @param item the {@link MenuItem} to be hidden
-     */
-    public static void hideMenuItem(MenuItem item) {
-        if (item != null) {
-            item.setVisible(false);
-            item.setEnabled(false);
-        }
-    }
-
-    private static void showMenuItem(MenuItem item) {
-        if (item != null) {
-            item.setVisible(true);
-            item.setEnabled(true);
-        }
-    }
-
-    public static void hideMenuItems(MenuItem... items) {
-        if (items != null) {
-            for (MenuItem item : items) {
-                hideMenuItem(item);
-            }
-        }
-    }
-
     /**
      * Decides what actions must be shown and hidden implementing the different rule sets.
      *  @param toShow                List to save the options that must be shown in the menu.
@@ -218,7 +192,7 @@ public class FileMenuFilter {
                         List<Integer> toHide,
                         boolean inSingleFileFragment) {
         boolean synchronizing = anyFileSynchronizing();
-        OCCapability capability = componentsGetter.getStorageManager().getCapability(user.getAccountName());
+        OCCapability capability = storageManager.getCapability(user.getAccountName());
         boolean endToEndEncryptionEnabled = capability.getEndToEndEncryption().isTrue();
         boolean fileLockingEnabled = capability.getFilesLockingVersion() != null;
 
@@ -373,45 +347,13 @@ public class FileMenuFilter {
 
         String mimeType = files.iterator().next().getMimeType();
 
-        if (isRichDocumentEditingSupported(capability, mimeType) || isEditorAvailable(context.getContentResolver(),
-                                                                                      user,
-                                                                                      mimeType)) {
+        if (isRichDocumentEditingSupported(capability, mimeType) || editorUtils.isEditorAvailable(user, mimeType)) {
             toShow.add(R.id.action_edit);
         } else {
             toHide.add(R.id.action_edit);
         }
     }
 
-    public static boolean isEditorAvailable(ContentResolver contentResolver, User user, String mimeType) {
-        return getEditor(contentResolver, user, mimeType) != null;
-    }
-
-    @Nullable
-    // TODO this does NOT belong in this class
-    public static Editor getEditor(ContentResolver contentResolver, User user, String mimeType) {
-        String json = new ArbitraryDataProvider(contentResolver).getValue(user, ArbitraryDataProvider.DIRECT_EDITING);
-
-        if (json.isEmpty()) {
-            return null;
-        }
-
-        DirectEditing directEditing = new Gson().fromJson(json, DirectEditing.class);
-
-        for (Editor editor : directEditing.getEditors().values()) {
-            if (editor.getMimetypes().contains(mimeType)) {
-                return editor;
-            }
-        }
-
-        for (Editor editor : directEditing.getEditors().values()) {
-            if (editor.getOptionalMimetypes().contains(mimeType)) {
-                return editor;
-            }
-        }
-
-        return null;
-    }
-
     /**
      * This will be replaced by unified editor and can be removed once EOL of corresponding server version.
      */
@@ -630,7 +572,7 @@ public class FileMenuFilter {
 
     private boolean hasEncryptedParent() {
         OCFile folder = files.iterator().next();
-        OCFile parent = componentsGetter.getStorageManager().getFileById(folder.getParentId());
+        OCFile parent = storageManager.getFileById(folder.getParentId());
 
         return parent != null && parent.isEncrypted();
     }

+ 5 - 1
app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java

@@ -45,6 +45,7 @@ import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.network.ConnectivityService;
+import com.nextcloud.utils.EditorUtils;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -174,6 +175,9 @@ public abstract class FileActivity extends DrawerActivity
     @Inject
     BackgroundJobManager backgroundJobManager;
 
+    @Inject
+    EditorUtils editorUtils;
+
     @Override
     public void showFiles(boolean onDeviceOnly) {
         // must be specialized in subclasses
@@ -196,7 +200,7 @@ public abstract class FileActivity extends DrawerActivity
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mHandler = new Handler();
-        mFileOperationsHelper = new FileOperationsHelper(this, getUserAccountManager(), connectivityService);
+        mFileOperationsHelper = new FileOperationsHelper(this, getUserAccountManager(), connectivityService, editorUtils);
 
         if (savedInstanceState != null) {
             mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);

+ 4 - 4
app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -2110,7 +2110,7 @@ public class FileDisplayActivity extends FileActivity
         } else {
             FileOperationsHelper fileOperationsHelper = new FileOperationsHelper(this,
                                                                                  getUserAccountManager(),
-                                                                                 connectivityService);
+                                                                                 connectivityService, editorUtils);
             fileOperationsHelper.startSyncForFileAndIntent(file, showDetailsIntent);
         }
     }
@@ -2131,7 +2131,7 @@ public class FileDisplayActivity extends FileActivity
         } else {
             FileOperationsHelper fileOperationsHelper = new FileOperationsHelper(this,
                                                                                  getUserAccountManager(),
-                                                                                 connectivityService);
+                                                                                 connectivityService, editorUtils);
             fileOperationsHelper.startSyncForFileAndIntent(file, showDetailsIntent);
         }
     }
@@ -2163,7 +2163,7 @@ public class FileDisplayActivity extends FileActivity
             previewIntent.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, autoplay);
             FileOperationsHelper fileOperationsHelper = new FileOperationsHelper(this,
                                                                                  getUserAccountManager(),
-                                                                                 connectivityService);
+                                                                                 connectivityService, editorUtils);
             fileOperationsHelper.startSyncForFileAndIntent(file, previewIntent);
         }
     }
@@ -2197,7 +2197,7 @@ public class FileDisplayActivity extends FileActivity
             previewIntent.putExtra(TEXT_PREVIEW, true);
             FileOperationsHelper fileOperationsHelper = new FileOperationsHelper(this,
                                                                                  getUserAccountManager(),
-                                                                                 connectivityService);
+                                                                                 connectivityService, editorUtils);
             fileOperationsHelper.startSyncForFileAndIntent(file, previewIntent);
         }
     }

+ 6 - 3
app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt

@@ -29,8 +29,8 @@ import androidx.webkit.WebViewFeature
 import com.nextcloud.android.common.ui.util.PlatformThemeUtil
 import com.nextcloud.client.appinfo.AppInfo
 import com.nextcloud.client.device.DeviceInfo
+import com.nextcloud.utils.EditorUtils
 import com.owncloud.android.R
-import com.owncloud.android.files.FileMenuFilter
 import com.owncloud.android.ui.asynctasks.TextEditorLoadUrlTask
 import com.owncloud.android.utils.theme.ThemeUtils
 import javax.inject.Inject
@@ -45,6 +45,9 @@ class TextEditorWebView : EditorWebView() {
     @Inject
     lateinit var themeUtils: ThemeUtils
 
+    @Inject
+    lateinit var editorUtils: EditorUtils
+
     @SuppressLint("AddJavascriptInterface") // suppress warning as webview is only used > Lollipop
     override fun postOnCreate() {
         super.postOnCreate()
@@ -54,7 +57,7 @@ class TextEditorWebView : EditorWebView() {
             finish()
         }
 
-        val editor = FileMenuFilter.getEditor(contentResolver, user.get(), file.mimeType)
+        val editor = editorUtils.getEditor(user.get(), file.mimeType)
 
         if (editor != null && editor.id == "onlyoffice") {
             getWebView().settings.userAgentString = generateOnlyOfficeUserAgent()
@@ -79,7 +82,7 @@ class TextEditorWebView : EditorWebView() {
 
     override fun loadUrl(url: String?) {
         if (url.isNullOrEmpty()) {
-            TextEditorLoadUrlTask(this, user.get(), file).execute()
+            TextEditorLoadUrlTask(this, user.get(), file, editorUtils).execute()
         }
     }
 

+ 5 - 4
app/src/main/java/com/owncloud/android/ui/asynctasks/TextEditorLoadUrlTask.java

@@ -20,13 +20,12 @@
  */
 package com.owncloud.android.ui.asynctasks;
 
-import android.accounts.Account;
 import android.os.AsyncTask;
 
 import com.nextcloud.android.lib.resources.directediting.DirectEditingOpenFileRemoteOperation;
 import com.nextcloud.client.account.User;
+import com.nextcloud.utils.EditorUtils;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.lib.common.Editor;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.ui.activity.EditorWebView;
@@ -35,14 +34,16 @@ import java.lang.ref.WeakReference;
 
 public class TextEditorLoadUrlTask extends AsyncTask<Void, Void, String> {
 
+    private final EditorUtils editorUtils;
     private WeakReference<EditorWebView> editorWebViewWeakReference;
     private OCFile file;
     private User user;
 
-    public TextEditorLoadUrlTask(EditorWebView editorWebView, User user, OCFile file) {
+    public TextEditorLoadUrlTask(EditorWebView editorWebView, User user, OCFile file, EditorUtils editorUtils) {
         this.user = user;
         this.editorWebViewWeakReference = new WeakReference<>(editorWebView);
         this.file = file;
+        this.editorUtils = editorUtils;
     }
 
     @Override
@@ -53,7 +54,7 @@ public class TextEditorLoadUrlTask extends AsyncTask<Void, Void, String> {
             return "";
         }
 
-        Editor editor = FileMenuFilter.getEditor(editorWebView.getContentResolver(), user, file.getMimeType());
+        Editor editor = editorUtils.getEditor(user, file.getMimeType());
 
         if (editor == null) {
             return "";

+ 4 - 7
app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -35,7 +35,6 @@ import android.view.Menu;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.widget.PopupMenu;
 import android.widget.ProgressBar;
 
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -48,13 +47,13 @@ import com.nextcloud.client.network.ClientFactory;
 import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
+import com.nextcloud.utils.MenuUtils;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.FileDetailsFragmentBinding;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
-import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 import com.owncloud.android.lib.common.OwnCloudClient;
@@ -80,8 +79,6 @@ import org.greenrobot.eventbus.ThreadMode;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
 
 import javax.inject.Inject;
 
@@ -365,7 +362,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
     public void onPrepareOptionsMenu(@NonNull Menu menu) {
         super.onPrepareOptionsMenu(menu);
 
-        FileMenuFilter.hideAll(menu);
+        MenuUtils.hideAll(menu);
     }
 
     private void prepareOptionsMenu(Menu menu) {
@@ -384,8 +381,8 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
 
         // TODO handle this
         if (getFile().isFolder()) {
-            FileMenuFilter.hideMenuItems(menu.findItem(R.id.action_send_file));
-            FileMenuFilter.hideMenuItems(menu.findItem(R.id.action_sync_file));
+            MenuUtils.hideMenuItem(menu.findItem(R.id.action_send_file));
+            MenuUtils.hideMenuItem(menu.findItem(R.id.action_sync_file));
         }
     }
 

+ 7 - 5
app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java

@@ -28,12 +28,12 @@ import com.google.gson.Gson;
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.device.DeviceInfo;
 import com.nextcloud.client.di.Injectable;
+import com.nextcloud.utils.EditorUtils;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.FileListActionsBottomSheetCreatorBinding;
 import com.owncloud.android.databinding.FileListActionsBottomSheetFragmentBinding;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.lib.common.Creator;
 import com.owncloud.android.lib.common.DirectEditing;
 import com.owncloud.android.lib.resources.status.OCCapability;
@@ -56,6 +56,7 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In
     private final OCFile file;
     private final ThemeUtils themeUtils;
     private final ViewThemeUtils viewThemeUtils;
+    private final EditorUtils editorUtils;
 
 
     public OCFileListBottomSheetDialog(FileActivity fileActivity,
@@ -64,7 +65,8 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In
                                        User user,
                                        OCFile file,
                                        ThemeUtils themeUtils,
-                                       ViewThemeUtils viewThemeUtils) {
+                                       ViewThemeUtils viewThemeUtils,
+                                       EditorUtils editorUtils) {
         super(fileActivity);
         this.actions = actions;
         this.fileActivity = fileActivity;
@@ -73,6 +75,7 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In
         this.file = file;
         this.themeUtils = themeUtils;
         this.viewThemeUtils = viewThemeUtils;
+        this.editorUtils = editorUtils;
     }
 
     @Override
@@ -142,9 +145,8 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In
         }
 
         // create rich workspace
-        if (FileMenuFilter.isEditorAvailable(getContext().getContentResolver(),
-                                             user,
-                                             MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN) &&
+        if (editorUtils.isEditorAvailable(user,
+                                          MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN) &&
             file != null && !file.isEncrypted()) {
             // richWorkspace
             // == "": no info set -> show button

+ 6 - 1
app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt

@@ -27,6 +27,7 @@ import androidx.fragment.app.DialogFragment
 import com.nextcloud.client.account.User
 import com.nextcloud.client.device.DeviceInfo
 import com.nextcloud.client.di.Injectable
+import com.nextcloud.utils.EditorUtils
 import com.owncloud.android.datamodel.OCFile
 import com.owncloud.android.ui.activity.FileActivity
 import com.owncloud.android.utils.theme.ThemeUtils
@@ -47,6 +48,9 @@ class OCFileListBottomSheetDialogFragment(
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
 
+    @Inject
+    lateinit var editorUtils: EditorUtils
+
     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
         return OCFileListBottomSheetDialog(
             fileActivity,
@@ -55,7 +59,8 @@ class OCFileListBottomSheetDialogFragment(
             user,
             file,
             themeUtils,
-            viewThemeUtils
+            viewThemeUtils,
+            editorUtils
         )
     }
 }

+ 6 - 7
app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -57,6 +57,7 @@ import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.client.utils.Throttler;
 import com.nextcloud.common.NextcloudClient;
 import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
+import com.nextcloud.utils.EditorUtils;
 import com.nextcloud.utils.view.FastScrollUtils;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
@@ -64,7 +65,6 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.datamodel.VirtualFolderType;
-import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.lib.common.Creator;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
@@ -195,6 +195,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
     @Inject BackgroundJobManager backgroundJobManager;
     @Inject ViewThemeUtils viewThemeUtils;
     @Inject FastScrollUtils fastScrollUtils;
+    @Inject EditorUtils editorUtils;
 
     protected FileFragment.ContainerActivity mContainerActivity;
 
@@ -1055,9 +1056,8 @@ public class OCFileListFragment extends ExtendedListFragment implements
                             // stream media preview on >= NC14
                             setFabVisible(false);
                             ((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true, true, true);
-                        } else if (FileMenuFilter.isEditorAvailable(requireContext().getContentResolver(),
-                                                                    accountManager.getUser(),
-                                                                    file.getMimeType()) &&
+                        } else if (editorUtils.isEditorAvailable(accountManager.getUser(),
+                                                                 file.getMimeType()) &&
                             !file.isEncrypted()) {
                             mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(file, getContext());
                         } else if (capability.getRichDocumentsMimeTypeList().contains(file.getMimeType()) &&
@@ -1127,9 +1127,8 @@ public class OCFileListFragment extends ExtendedListFragment implements
                 return true;
             } else if (itemId == R.id.action_edit) {
                 // should not be necessary, as menu item is filtered, but better play safe
-                if (FileMenuFilter.isEditorAvailable(requireContext().getContentResolver(),
-                                                     accountManager.getUser(),
-                                                     singleFile.getMimeType())) {
+                if (editorUtils.isEditorAvailable(accountManager.getUser(),
+                                                  singleFile.getMimeType())) {
                     mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(singleFile, getContext());
                 } else {
                     mContainerActivity.getFileOperationsHelper().openFileAsRichDocument(singleFile, getContext());

+ 5 - 5
app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

@@ -51,12 +51,12 @@ import com.nextcloud.client.account.User;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.java.util.Optional;
+import com.nextcloud.utils.EditorUtils;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.files.StreamMediaFileOperation;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
@@ -130,16 +130,18 @@ public class FileOperationsHelper {
     private final FileActivity fileActivity;
     private final CurrentAccountProvider currentAccount;
     private final ConnectivityService connectivityService;
+    private final EditorUtils editorUtils;
 
     /// Identifier of operation in progress which result shouldn't be lost
     private long mWaitingForOpId = Long.MAX_VALUE;
 
     public FileOperationsHelper(FileActivity fileActivity,
                                 CurrentAccountProvider currentAccount,
-                                ConnectivityService connectivityService) {
+                                ConnectivityService connectivityService, EditorUtils editorUtils) {
         this.fileActivity = fileActivity;
         this.currentAccount = currentAccount;
         this.connectivityService = connectivityService;
+        this.editorUtils = editorUtils;
     }
 
     @Nullable
@@ -304,9 +306,7 @@ public class FileOperationsHelper {
             if (launchables.isEmpty()) {
                 Optional<User> optionalUser = fileActivity.getUser();
 
-                if (optionalUser.isPresent() && FileMenuFilter.isEditorAvailable(fileActivity.getContentResolver(),
-                                                                                 optionalUser.get(),
-                                                                                 file.getMimeType())) {
+                if (optionalUser.isPresent() && editorUtils.isEditorAvailable(optionalUser.get(), file.getMimeType())) {
                     openFileWithTextEditor(file, fileActivity);
                 } else {
                     Account account = fileActivity.getAccount();

+ 4 - 4
app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java

@@ -54,12 +54,12 @@ import com.nextcloud.client.di.Injectable;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
+import com.nextcloud.utils.MenuUtils;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.PreviewImageFragmentBinding;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
-import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
@@ -374,7 +374,7 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
         // additional restriction for this fragment
         // TODO allow renaming in PreviewImageFragment
         // TODO allow refresh file in PreviewImageFragment
-        FileMenuFilter.hideMenuItems(
+        MenuUtils.hideMenuItems(
             menu.findItem(R.id.action_rename_file),
             menu.findItem(R.id.action_sync_file),
             menu.findItem(R.id.action_select_all),
@@ -382,10 +382,10 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
             menu.findItem(R.id.action_copy),
             menu.findItem(R.id.action_favorite),
             menu.findItem(R.id.action_unset_favorite)
-                                    );
+                               );
 
         if (getFile() != null && getFile().isSharedWithMe() && !getFile().canReshare()) {
-            FileMenuFilter.hideMenuItem(menu.findItem(R.id.action_send_share_file));
+            MenuUtils.hideMenuItem(menu.findItem(R.id.action_send_share_file));
         }
     }
 

+ 0 - 1
app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -62,7 +62,6 @@ import com.owncloud.android.R;
 import com.owncloud.android.databinding.FragmentPreviewMediaBinding;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
-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;

+ 4 - 4
app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java

@@ -35,9 +35,9 @@ import android.widget.TextView;
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
+import com.nextcloud.utils.MenuUtils;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
@@ -291,7 +291,7 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
 
         // TODO remove in bottom sheet too
         // additional restriction for this fragment
-        FileMenuFilter.hideMenuItems(
+        MenuUtils.hideMenuItems(
             menu.findItem(R.id.action_rename_file),
             menu.findItem(R.id.action_select_all),
             menu.findItem(R.id.action_move),
@@ -299,10 +299,10 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
             menu.findItem(R.id.action_sync_file),
             menu.findItem(R.id.action_favorite),
             menu.findItem(R.id.action_unset_favorite)
-                                    );
+                               );
 
         if (getFile().isSharedWithMe() && !getFile().canReshare()) {
-            FileMenuFilter.hideMenuItem(menu.findItem(R.id.action_send_share_file));
+            MenuUtils.hideMenuItem(menu.findItem(R.id.action_send_share_file));
         }
     }
 

+ 2 - 2
app/src/main/java/com/owncloud/android/ui/preview/pdf/PreviewPdfFragment.kt

@@ -33,10 +33,10 @@ import androidx.lifecycle.ViewModelProvider
 import com.google.android.material.snackbar.Snackbar
 import com.nextcloud.client.di.Injectable
 import com.nextcloud.client.di.ViewModelFactory
+import com.nextcloud.utils.MenuUtils
 import com.owncloud.android.R
 import com.owncloud.android.databinding.PreviewPdfFragmentBinding
 import com.owncloud.android.datamodel.OCFile
-import com.owncloud.android.files.FileMenuFilter
 import com.owncloud.android.ui.activity.FileDisplayActivity
 import com.owncloud.android.ui.preview.PreviewBitmapActivity
 import com.owncloud.android.utils.DisplayUtils
@@ -111,7 +111,7 @@ class PreviewPdfFragment : Fragment(), Injectable {
 
     override fun onPrepareOptionsMenu(menu: Menu) {
         super.onPrepareOptionsMenu(menu)
-        FileMenuFilter.hideAll(menu)
+        MenuUtils.hideAll(menu)
     }
 
     override fun onResume() {