From 2bb7e5f6ad3d1152f92a20b7fff6eb76120ff8d4 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 22 Jun 2026 09:24:07 +0200 Subject: [PATCH 1/7] fix(editor): handle mime types Signed-off-by: alperozturk96 --- .../java/com/nextcloud/utils/EditorUtils.kt | 25 +++++++++++++------ .../ui/fragment/OCFileListFragment.java | 2 +- .../ui/helpers/FileOperationsHelper.java | 1 + 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/EditorUtils.kt b/app/src/main/java/com/nextcloud/utils/EditorUtils.kt index 3c1630e64308..92315b914439 100644 --- a/app/src/main/java/com/nextcloud/utils/EditorUtils.kt +++ b/app/src/main/java/com/nextcloud/utils/EditorUtils.kt @@ -1,6 +1,7 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-FileCopyrightText: 2022 Álvaro Brey * SPDX-FileCopyrightText: 2022 Nextcloud GmbH * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only @@ -16,17 +17,27 @@ import javax.inject.Inject class EditorUtils @Inject constructor(private val arbitraryDataProvider: ArbitraryDataProvider) { + /** + * Returns only supported mimetypes + */ fun getEditor(user: User?, mimeType: String?): Editor? { - val json = arbitraryDataProvider.getValue(user, ArbitraryDataProvider.DIRECT_EDITING) - if (json.isEmpty()) { - return null - } - val editors = Gson().fromJson(json, DirectEditing::class.java).editors.values + val editors = getEditors(user) ?: return null return editors.firstOrNull { mimeType in it.mimetypes } - ?: editors.firstOrNull { mimeType in it.optionalMimetypes } } - fun isEditorAvailable(user: User?, mimeType: String?): Boolean = getEditor(user, mimeType) != null + /** + * Returns supported mimetypes along with optional ones + */ + fun isEditorAvailable(user: User?, mimeType: String?): Boolean { + val editors = getEditors(user) ?: return false + return editors.any { mimeType in it.mimetypes || mimeType in it.optionalMimetypes } + } + + private fun getEditors(user: User?): Collection? { + val json = arbitraryDataProvider.getValue(user, ArbitraryDataProvider.DIRECT_EDITING) + if (json.isEmpty()) return null + return Gson().fromJson(json, DirectEditing::class.java).editors.values + } fun usesOfficeUserAgent(editor: Editor?): Boolean = editor?.id in OFFICE_EDITOR_IDS diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index f9b959d2ecfc..915ae978080e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1220,7 +1220,7 @@ private void handlePendingDownloadFile(OCFile file) { } else if (PreviewMediaActivity.Companion.canBePreviewed(file) && !file.isEncrypted() && mContainerActivity instanceof FileDisplayActivity fda) { setFabVisible(false); fda.startMediaPreview(file, 0, true, true, true, true); - } else if (editorUtils.isEditorAvailable(accountManager.getUser(), file.getMimeType()) && !file.isEncrypted()) { + } else if (editorUtils.getEditor(accountManager.getUser(), file.getMimeType()) != null && !file.isEncrypted()) { mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(file, getContext()); } else if (capability.getRichDocumentsMimeTypeList() != null && capability.getRichDocumentsMimeTypeList().contains(file.getMimeType()) && diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index a1b22caa96e5..22758112b41b 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -291,6 +291,7 @@ public void openFile(OCFile file) { List availableApps = fileActivity.getPackageManager(). queryIntentActivities(openFileWithIntent, PackageManager.GET_RESOLVED_FILTER); + // first always try to use available apps if (availableApps.isEmpty()) { Optional optionalUser = fileActivity.getUser(); From 23613e3dad4ad4143a698e4bac0b4073dc894033 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 8 Jul 2026 11:58:51 +0200 Subject: [PATCH 2/7] wip Signed-off-by: alperozturk96 # Conflicts: # app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt --- .../android/files/FileMenuFilterIT.kt | 54 +++++++++++++++++++ .../nextcloud/ui/fileactions/FileAction.kt | 2 + .../java/com/nextcloud/utils/EditorUtils.kt | 21 ++++++-- .../android/files/FileMenuFilter.java | 14 +++++ .../ui/asynctasks/TextEditorLoadUrlTask.java | 2 +- .../ui/fragment/OCFileListFragment.java | 4 +- app/src/main/res/values/ids.xml | 1 + app/src/main/res/values/strings.xml | 1 + 8 files changed, 94 insertions(+), 5 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index a4f61c7325f9..157a91d2b99c 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -330,6 +330,39 @@ class FileMenuFilterIT : AbstractIT() { } } + @Test + fun filter_openWithOnlyOffice_onlyForDownloadedFiles() { + every { + mockArbitraryDataProvider.getValue(any(), ArbitraryDataProvider.DIRECT_EDITING) + } returns ONLYOFFICE_DIRECT_EDITING_JSON + + configureCapability(OCCapability()) + + val downloadedFile = OCFile("/downloaded.docx").apply { + mimeType = OFFICE_MIMETYPE + storagePath = getDummyFile("downloaded.docx").absolutePath + } + val onlineOnlyFile = OCFile("/online.docx").apply { + mimeType = OFFICE_MIMETYPE + } + + launchActivity().use { + it.onActivity { activity -> + val filterFactory = FileMenuFilter.Factory(mockStorageManager, activity, editorUtils) + + val downloadedToHide = filterFactory + .newInstance(downloadedFile, mockComponentsGetter, true, user) + .getToHide(false) + assertFalse(downloadedToHide.contains(R.id.action_open_with_office)) + + val onlineToHide = filterFactory + .newInstance(onlineOnlyFile, mockComponentsGetter, true, user) + .getToHide(false) + assertTrue(onlineToHide.contains(R.id.action_open_with_office)) + } + } + } + private data class ExpectedLockVisibilities(val lockFile: Boolean, val unlockFile: Boolean) private fun configureCapability(capability: OCCapability) { @@ -363,4 +396,25 @@ class FileMenuFilterIT : AbstractIT() { } } } + + companion object { + private const val OFFICE_MIMETYPE = + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + + private val ONLYOFFICE_DIRECT_EDITING_JSON = + """ + { + "editors": { + "onlyoffice": { + "id": "onlyoffice", + "name": "OnlyOffice", + "mimetypes": [], + "optionalMimetypes": ["$OFFICE_MIMETYPE"], + "secure": false + } + }, + "creators": {} + } + """.trimIndent() + } } diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt index f30dbefbe86a..aa4ae09195d9 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt @@ -48,6 +48,7 @@ enum class FileAction( SEND_SHARE_FILE(R.id.action_send_share_file, R.string.action_send_share, R.drawable.ic_share), SEND_FILE(R.id.action_send_file, R.string.common_send, R.drawable.ic_share), OPEN_FILE_WITH(R.id.action_open_file_with, R.string.actionbar_open_with, R.drawable.ic_external), + OPEN_WITH_OFFICE(R.id.action_open_with_office, R.string.action_open_with_office, R.drawable.file_doc), STREAM_MEDIA(R.id.action_stream_media, R.string.stream, R.drawable.ic_play_arrow), SET_AS_WALLPAPER(R.id.action_set_as_wallpaper, R.string.set_picture_as, R.drawable.ic_wallpaper), @@ -87,6 +88,7 @@ enum class FileAction( SEND_SHARE_FILE, SEND_FILE, OPEN_FILE_WITH, + OPEN_WITH_OFFICE, SYNC_FOLDER ) diff --git a/app/src/main/java/com/nextcloud/utils/EditorUtils.kt b/app/src/main/java/com/nextcloud/utils/EditorUtils.kt index 92315b914439..8224fa316ca1 100644 --- a/app/src/main/java/com/nextcloud/utils/EditorUtils.kt +++ b/app/src/main/java/com/nextcloud/utils/EditorUtils.kt @@ -18,19 +18,34 @@ import javax.inject.Inject class EditorUtils @Inject constructor(private val arbitraryDataProvider: ArbitraryDataProvider) { /** - * Returns only supported mimetypes + * Returns an editor matching only the strictly supported mimetypes. */ fun getEditor(user: User?, mimeType: String?): Editor? { val editors = getEditors(user) ?: return null return editors.firstOrNull { mimeType in it.mimetypes } } + /** + * Returns an editor matching the supported mimetypes or, as a fallback, the optional ones. + */ + fun getAvailableEditor(user: User?, mimeType: String?): Editor? { + val editors = getEditors(user) ?: return null + return editors.firstOrNull { mimeType in it.mimetypes } + ?: editors.firstOrNull { mimeType in it.optionalMimetypes } + } + /** * Returns supported mimetypes along with optional ones */ - fun isEditorAvailable(user: User?, mimeType: String?): Boolean { + fun isEditorAvailable(user: User?, mimeType: String?): Boolean = getAvailableEditor(user, mimeType) != null + + /** + * Returns true when an office editor (e.g. OnlyOffice) can open the mimetype, + * either as a supported or optional mimetype. + */ + fun isOfficeEditorAvailable(user: User?, mimeType: String?): Boolean { val editors = getEditors(user) ?: return false - return editors.any { mimeType in it.mimetypes || mimeType in it.optionalMimetypes } + return editors.any { usesOfficeUserAgent(it) && (mimeType in it.mimetypes || mimeType in it.optionalMimetypes) } } private fun getEditors(user: User?): Collection? { diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 9f29055f94fe..78d75dd59732 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -158,6 +158,7 @@ private List filter(boolean inSingleFileFragment) { filterSelectAll(toHide, inSingleFileFragment); filterDeselectAll(toHide, inSingleFileFragment); filterOpenWith(toHide, synchronizing); + filterOpenWithOffice(toHide); filterCancelSync(toHide, synchronizing); filterSync(toHide, synchronizing); filterShareFile(toHide, capability); @@ -339,6 +340,19 @@ private void filterOpenWith(Collection toHide, boolean synchronizing) { } } + private void filterOpenWithOffice(Collection toHide) { + if (!isSingleFile()) { + toHide.add(R.id.action_open_with_office); + return; + } + + OCFile file = files.iterator().next(); + boolean canOpenLocally = file.isDown() && !file.isEncrypted(); + if (!canOpenLocally || !editorUtils.isOfficeEditorAvailable(user, file.getMimeType())) { + toHide.add(R.id.action_open_with_office); + } + } + private void filterDeselectAll(List toHide, boolean inSingleFileFragment) { if (inSingleFileFragment) { // Always hide in single file fragments diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/TextEditorLoadUrlTask.java b/app/src/main/java/com/owncloud/android/ui/asynctasks/TextEditorLoadUrlTask.java index 14c18dba9b72..360e8a347316 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/TextEditorLoadUrlTask.java +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/TextEditorLoadUrlTask.java @@ -41,7 +41,7 @@ protected String doInBackground(Void... voids) { return ""; } - Editor editor = editorUtils.getEditor(user, file.getMimeType()); + Editor editor = editorUtils.getAvailableEditor(user, file.getMimeType()); if (editor == null) { return ""; diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 915ae978080e..54f7504c2af2 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -148,7 +148,6 @@ import androidx.fragment.app.FragmentManager; import androidx.media3.common.util.UnstableApi; import kotlin.Unit; -import kotlin.jvm.functions.Function1; import static com.owncloud.android.datamodel.OCFile.ROOT_PATH; import static com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment.SETUP_ENCRYPTION_DIALOG_TAG; @@ -1355,6 +1354,9 @@ public boolean onFileActionChosen(@IdRes final int itemId, Set checkedFi } else if (itemId == R.id.action_open_file_with) { mContainerActivity.getFileOperationsHelper().openFile(singleFile); return true; + } else if (itemId == R.id.action_open_with_office) { + mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(singleFile, getContext()); + return true; } else if (itemId == R.id.action_stream_media) { mContainerActivity.getFileOperationsHelper().streamMediaFile(singleFile); return true; diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 34075e4237cf..b658bceaa75b 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -23,6 +23,7 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7734d4ce2a34..a2d0f796c3de 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1194,6 +1194,7 @@ Internal share link only works for users with access to this file Share internal link Edit + Open with office Failed to start editor Add folder description We couldnt locate the file on server. Another user may have deleted the file From 104c6aecf9e716f41ba6748028115d9ec3212eab Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 8 Jul 2026 12:37:26 +0200 Subject: [PATCH 3/7] fix spotbugs Signed-off-by: alperozturk96 --- .../com/owncloud/android/files/FileMenuFilter.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 78d75dd59732..7f41da91458a 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -314,9 +314,15 @@ private void filterEdit( */ @NextcloudServer(max = 18) private boolean isRichDocumentEditingSupported(OCCapability capability, String mimeType) { + final var mimeTypeList = capability.getRichDocumentsMimeTypeList(); + final var isMimeTypeListContainsMimeType = (mimeTypeList != null && mimeTypeList.contains(mimeType)); + + final var optionalMimeTypeList = capability.getRichDocumentsOptionalMimeTypeList(); + final var isOptionalMimeTypeListContainsMimeType = (optionalMimeTypeList != null && + optionalMimeTypeList.contains(mimeType)); + return isSingleFile() && - (capability.getRichDocumentsMimeTypeList().contains(mimeType) || - capability.getRichDocumentsOptionalMimeTypeList().contains(mimeType)) && + (isMimeTypeListContainsMimeType || isOptionalMimeTypeListContainsMimeType) && capability.getRichDocumentsDirectEditing().isTrue(); } From f1251f0150aac770876f6db442c6e70025e38cf9 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 8 Jul 2026 12:49:50 +0200 Subject: [PATCH 4/7] fix spotbugs Signed-off-by: alperozturk96 --- .../android/ui/fragment/OCFileListFragment.java | 10 +++++----- .../android/ui/helpers/FileOperationsHelper.java | 10 +--------- .../android/ui/preview/PreviewTextFileFragment.java | 3 ++- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 54f7504c2af2..98a19d37246e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -91,6 +91,7 @@ import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FolderPickerActivity; import com.owncloud.android.ui.activity.OnEnforceableRefreshListener; +import com.owncloud.android.ui.activity.TextEditorWebView; import com.owncloud.android.ui.activity.UploadFilesActivity; import com.owncloud.android.ui.adapter.CommonOCFileListAdapterInterface; import com.owncloud.android.ui.adapter.OCFileListAdapter; @@ -1220,7 +1221,7 @@ private void handlePendingDownloadFile(OCFile file) { setFabVisible(false); fda.startMediaPreview(file, 0, true, true, true, true); } else if (editorUtils.getEditor(accountManager.getUser(), file.getMimeType()) != null && !file.isEncrypted()) { - mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(file, getContext()); + TextEditorWebView.Companion.startTextEditor(file, getContext()); } else if (capability.getRichDocumentsMimeTypeList() != null && capability.getRichDocumentsMimeTypeList().contains(file.getMimeType()) && capability.getRichDocumentsDirectEditing().isTrue() && !file.isEncrypted()) { @@ -1355,16 +1356,15 @@ public boolean onFileActionChosen(@IdRes final int itemId, Set checkedFi mContainerActivity.getFileOperationsHelper().openFile(singleFile); return true; } else if (itemId == R.id.action_open_with_office) { - mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(singleFile, getContext()); + TextEditorWebView.Companion.startTextEditor(singleFile, getContext()); return true; } else if (itemId == R.id.action_stream_media) { mContainerActivity.getFileOperationsHelper().streamMediaFile(singleFile); return true; } else if (itemId == R.id.action_edit) { // should not be necessary, as menu item is filtered, but better play safe - if (editorUtils.isEditorAvailable(accountManager.getUser(), - singleFile.getMimeType())) { - mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(singleFile, getContext()); + if (editorUtils.isEditorAvailable(accountManager.getUser(), singleFile.getMimeType())) { + TextEditorWebView.Companion.startTextEditor(singleFile,getContext()); } else if (EditImageActivity.Companion.canBePreviewed(singleFile)) { ((FileDisplayActivity) mContainerActivity).startImageEditor(singleFile); } else { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 22758112b41b..86d326d5c6ae 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -296,7 +296,7 @@ public void openFile(OCFile file) { Optional optionalUser = fileActivity.getUser(); if (optionalUser.isPresent() && editorUtils.isEditorAvailable(optionalUser.get(), file.getMimeType())) { - openFileWithTextEditor(file, fileActivity); + TextEditorWebView.Companion.startTextEditor(file, fileActivity); return; } @@ -365,14 +365,6 @@ public void openFileAsRichDocument(OCFile file, Context context) { context.startActivity(collaboraWebViewIntent); } - public void openFileWithTextEditor(OCFile file, Context context) { - Intent textEditorIntent = new Intent(context, TextEditorWebView.class); - textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Text"); - textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_FILE, file); - textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false); - context.startActivity(textEditorIntent); - } - public void openRichWorkspaceWithTextEditor(OCFile file, String url, Context context) { Intent textEditorIntent = new Intent(context, TextEditorWebView.class); textEditorIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, "Text"); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java index 0b32cc0a9a92..dd6240c4cf2e 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java @@ -27,6 +27,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.activity.TextEditorWebView; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment; import com.owncloud.android.utils.DisplayUtils; @@ -310,7 +311,7 @@ private void onFileActionChosen(final int itemId) { } else if(itemId == R.id.action_cancel_sync){ containerActivity.getFileOperationsHelper().cancelTransference(getFile()); } else if (itemId == R.id.action_edit) { - containerActivity.getFileOperationsHelper().openFileWithTextEditor(getFile(), getContext()); + TextEditorWebView.Companion.startTextEditor(getFile(), getContext()); } } From be03c69673731e2b2ce393443beef3d3d623e63d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 17 Jul 2026 15:48:03 +0200 Subject: [PATCH 5/7] Open in web editor Signed-off-by: alperozturk96 --- .../android/files/FileMenuFilterIT.kt | 4 ++-- .../nextcloud/ui/fileactions/FileAction.kt | 2 +- .../android/files/FileMenuFilter.java | 4 ++-- .../android/ui/activity/TextEditorWebView.kt | 20 ++++++++++++++++++- .../ui/fragment/OCFileListFragment.java | 2 +- app/src/main/res/values/ids.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 7 files changed, 27 insertions(+), 9 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 157a91d2b99c..632de0e1c459 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -353,12 +353,12 @@ class FileMenuFilterIT : AbstractIT() { val downloadedToHide = filterFactory .newInstance(downloadedFile, mockComponentsGetter, true, user) .getToHide(false) - assertFalse(downloadedToHide.contains(R.id.action_open_with_office)) + assertFalse(downloadedToHide.contains(R.id.action_open_in_web_editor)) val onlineToHide = filterFactory .newInstance(onlineOnlyFile, mockComponentsGetter, true, user) .getToHide(false) - assertTrue(onlineToHide.contains(R.id.action_open_with_office)) + assertTrue(onlineToHide.contains(R.id.action_open_in_web_editor)) } } } diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt index aa4ae09195d9..3fabb9d01945 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt @@ -48,7 +48,7 @@ enum class FileAction( SEND_SHARE_FILE(R.id.action_send_share_file, R.string.action_send_share, R.drawable.ic_share), SEND_FILE(R.id.action_send_file, R.string.common_send, R.drawable.ic_share), OPEN_FILE_WITH(R.id.action_open_file_with, R.string.actionbar_open_with, R.drawable.ic_external), - OPEN_WITH_OFFICE(R.id.action_open_with_office, R.string.action_open_with_office, R.drawable.file_doc), + OPEN_WITH_OFFICE(R.id.action_open_in_web_editor, R.string.action_open_in_web_editor, R.drawable.file_doc), STREAM_MEDIA(R.id.action_stream_media, R.string.stream, R.drawable.ic_play_arrow), SET_AS_WALLPAPER(R.id.action_set_as_wallpaper, R.string.set_picture_as, R.drawable.ic_wallpaper), diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 7f41da91458a..86e4e343d572 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -348,14 +348,14 @@ private void filterOpenWith(Collection toHide, boolean synchronizing) { private void filterOpenWithOffice(Collection toHide) { if (!isSingleFile()) { - toHide.add(R.id.action_open_with_office); + toHide.add(R.id.action_open_in_web_editor); return; } OCFile file = files.iterator().next(); boolean canOpenLocally = file.isDown() && !file.isEncrypted(); if (!canOpenLocally || !editorUtils.isOfficeEditorAvailable(user, file.getMimeType())) { - toHide.add(R.id.action_open_with_office); + toHide.add(R.id.action_open_in_web_editor); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt b/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt index 2f950420b6ac..752f5720696f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt @@ -9,6 +9,8 @@ package com.owncloud.android.ui.activity import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent import androidx.core.net.toUri import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewFeature @@ -16,6 +18,7 @@ import com.nextcloud.android.common.ui.util.PlatformThemeUtil import com.nextcloud.client.appinfo.AppInfo import com.nextcloud.client.device.DeviceInfo import com.owncloud.android.R +import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.asynctasks.TextEditorLoadUrlTask import com.owncloud.android.utils.DisplayUtils import javax.inject.Inject @@ -27,6 +30,21 @@ class TextEditorWebView : EditorWebView() { @Inject lateinit var deviceInfo: DeviceInfo + companion object { + fun startTextEditor(file: OCFile?, context: Context?) { + val context = context ?: return + val file = file ?: return + + Intent(context, TextEditorWebView::class.java).apply { + putExtra(EXTRA_TITLE, "Text") + putExtra(EXTRA_FILE, file) + putExtra(EXTRA_SHOW_SIDEBAR, false) + }.also { + context.startActivity(it) + } + } + } + @SuppressLint("AddJavascriptInterface") // suppress warning as webview is only used > Lollipop override fun postOnCreate() { super.postOnCreate() @@ -37,7 +55,7 @@ class TextEditorWebView : EditorWebView() { } user.ifPresent { - val editor = editorUtils.getEditor(it, file?.mimeType) + val editor = editorUtils.getAvailableEditor(it, file?.mimeType) if (editorUtils.usesOfficeUserAgent(editor)) { webView.settings.userAgentString = generateOfficeUserAgent() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 98a19d37246e..af167aff68f3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1355,7 +1355,7 @@ public boolean onFileActionChosen(@IdRes final int itemId, Set checkedFi } else if (itemId == R.id.action_open_file_with) { mContainerActivity.getFileOperationsHelper().openFile(singleFile); return true; - } else if (itemId == R.id.action_open_with_office) { + } else if (itemId == R.id.action_open_in_web_editor) { TextEditorWebView.Companion.startTextEditor(singleFile, getContext()); return true; } else if (itemId == R.id.action_stream_media) { diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index b658bceaa75b..31a58feb98e8 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -23,7 +23,7 @@ - + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a2d0f796c3de..7c03dc35e5f6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1194,7 +1194,7 @@ Internal share link only works for users with access to this file Share internal link Edit - Open with office + Open in web editor Failed to start editor Add folder description We couldnt locate the file on server. Another user may have deleted the file From d09c32c9faba2047cc14b41dd584a1420f0c021b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 17 Jul 2026 15:48:58 +0200 Subject: [PATCH 6/7] Open in web editor Signed-off-by: alperozturk96 --- app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt index 3fabb9d01945..96e7b63a21d3 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt @@ -48,7 +48,7 @@ enum class FileAction( SEND_SHARE_FILE(R.id.action_send_share_file, R.string.action_send_share, R.drawable.ic_share), SEND_FILE(R.id.action_send_file, R.string.common_send, R.drawable.ic_share), OPEN_FILE_WITH(R.id.action_open_file_with, R.string.actionbar_open_with, R.drawable.ic_external), - OPEN_WITH_OFFICE(R.id.action_open_in_web_editor, R.string.action_open_in_web_editor, R.drawable.file_doc), + OPEN_IN_WEB_EDITOR(R.id.action_open_in_web_editor, R.string.action_open_in_web_editor, R.drawable.file_doc), STREAM_MEDIA(R.id.action_stream_media, R.string.stream, R.drawable.ic_play_arrow), SET_AS_WALLPAPER(R.id.action_set_as_wallpaper, R.string.set_picture_as, R.drawable.ic_wallpaper), @@ -88,7 +88,7 @@ enum class FileAction( SEND_SHARE_FILE, SEND_FILE, OPEN_FILE_WITH, - OPEN_WITH_OFFICE, + OPEN_IN_WEB_EDITOR, SYNC_FOLDER ) From a4d5b0b77adbbd07e9f7ed0f5e6fc68fdf03f131 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 17 Jul 2026 15:49:46 +0200 Subject: [PATCH 7/7] Open in web editor Signed-off-by: alperozturk96 --- .../main/java/com/owncloud/android/files/FileMenuFilter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 86e4e343d572..5df186df3931 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -158,7 +158,7 @@ private List filter(boolean inSingleFileFragment) { filterSelectAll(toHide, inSingleFileFragment); filterDeselectAll(toHide, inSingleFileFragment); filterOpenWith(toHide, synchronizing); - filterOpenWithOffice(toHide); + filterOpenInWebEditor(toHide); filterCancelSync(toHide, synchronizing); filterSync(toHide, synchronizing); filterShareFile(toHide, capability); @@ -346,7 +346,7 @@ private void filterOpenWith(Collection toHide, boolean synchronizing) { } } - private void filterOpenWithOffice(Collection toHide) { + private void filterOpenInWebEditor(Collection toHide) { if (!isSingleFile()) { toHide.add(R.id.action_open_in_web_editor); return;