Merge pull request #10148 from nextcloud/proseMirror

Test proseMirror with custom user agent
This commit is contained in:
Tobias Kaminsky 2022-05-25 15:40:54 +02:00 committed by GitHub
commit c1cf416872
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 69 deletions

View file

@ -22,24 +22,20 @@
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.owncloud.android.R;
import com.owncloud.android.datamodel.ArbitraryDataProvider;
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;
import com.owncloud.android.utils.EditorUtils;
import com.owncloud.android.utils.MimeTypeUtil;
import com.owncloud.android.utils.NextcloudServer;
@ -49,8 +45,6 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import androidx.annotation.Nullable;
/**
* Filters out the file actions available in a given {@link Menu} for a given {@link OCFile}
* according to the current state of the latest.
@ -352,44 +346,16 @@ public class FileMenuFilter {
String mimeType = files.iterator().next().getMimeType();
if (isRichDocumentEditingSupported(capability, mimeType) || isEditorAvailable(context.getContentResolver(),
user,
mimeType)) {
if (isRichDocumentEditingSupported(capability, mimeType) ||
EditorUtils.isEditorAvailable(context.getContentResolver(),
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
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.
*/

View file

@ -179,7 +179,7 @@ public class ExternalSiteWebView extends FileActivity {
webSettings.setLoadWithOverviewMode(true);
// user agent
webSettings.setUserAgentString(MainApp.getUserAgent());
setUserAgentString(webSettings);
// no private data storing
webSettings.setSavePassword(false);
@ -199,6 +199,10 @@ public class ExternalSiteWebView extends FileActivity {
}
}
protected void setUserAgentString(WebSettings webSettings) {
webSettings.setUserAgentString(MainApp.getUserAgent());
}
private void setupActionBar(String title) {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {

View file

@ -23,14 +23,15 @@ package com.owncloud.android.ui.activity
import android.annotation.SuppressLint
import android.net.Uri
import android.webkit.WebSettings
import android.widget.Toast
import androidx.webkit.WebSettingsCompat
import androidx.webkit.WebViewFeature
import com.nextcloud.client.appinfo.AppInfo
import com.nextcloud.client.device.DeviceInfo
import com.owncloud.android.R
import com.owncloud.android.files.FileMenuFilter
import com.owncloud.android.ui.asynctasks.TextEditorLoadUrlTask
import com.owncloud.android.utils.EditorUtils
import com.owncloud.android.utils.theme.ThemeUtils
import javax.inject.Inject
@ -53,29 +54,33 @@ class TextEditorWebView : EditorWebView() {
finish()
}
val editor = FileMenuFilter.getEditor(contentResolver, user.get(), file.mimeType)
if (editor != null && editor.id == "onlyoffice") {
getWebView().settings.userAgentString = generateOnlyOfficeUserAgent()
}
getWebView().addJavascriptInterface(MobileInterface(), "DirectEditingMobileInterface")
webView.addJavascriptInterface(MobileInterface(), "DirectEditingMobileInterface")
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
WebSettingsCompat.setForceDarkStrategy(
getWebView().settings,
webView.settings,
WebSettingsCompat.DARK_STRATEGY_WEB_THEME_DARKENING_ONLY
)
}
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK) && themeUtils.isDarkModeActive(this)) {
WebSettingsCompat.setForceDark(getWebView().settings, WebSettingsCompat.FORCE_DARK_ON)
WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON)
}
getWebView().setDownloadListener { url, _, _, _, _ -> downloadFile(Uri.parse(url)) }
webView.setDownloadListener { url, _, _, _, _ -> downloadFile(Uri.parse(url)) }
loadUrl(intent.getStringExtra(ExternalSiteWebView.EXTRA_URL))
}
override fun setUserAgentString(webSettings: WebSettings?) {
val editor = EditorUtils.getEditor(contentResolver, user.get(), file.mimeType)
if (editor != null && editor.id == ONLYOFFICE) {
webView.settings.userAgentString = generateOnlyOfficeUserAgent()
}
// For Text/prosemirror we keep default user agent to not mess around with their special treatments
}
override fun loadUrl(url: String?) {
if (url.isNullOrEmpty()) {
TextEditorLoadUrlTask(this, user.get(), file).execute()
@ -87,4 +92,8 @@ class TextEditorWebView : EditorWebView() {
return String.format(userAgent, deviceInfo.androidVersion, appInfo.getAppVersion(this))
}
companion object {
const val ONLYOFFICE = "onlyoffice"
}
}

View file

@ -26,10 +26,10 @@ import android.os.AsyncTask;
import com.nextcloud.android.lib.resources.directediting.DirectEditingOpenFileRemoteOperation;
import com.nextcloud.client.account.User;
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;
import com.owncloud.android.utils.EditorUtils;
import java.lang.ref.WeakReference;
@ -55,7 +55,7 @@ public class TextEditorLoadUrlTask extends AsyncTask<Void, Void, String> {
return "";
}
Editor editor = FileMenuFilter.getEditor(editorWebView.getContentResolver(), user, file.getMimeType());
Editor editor = EditorUtils.getEditor(editorWebView.getContentResolver(), user, file.getMimeType());
if (editor == null) {
return "";

View file

@ -35,19 +35,17 @@ 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;
import com.owncloud.android.ui.activity.AppScanActivity;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.utils.EditorUtils;
import com.owncloud.android.utils.MimeTypeUtil;
import com.owncloud.android.utils.theme.ThemeColorUtils;
import com.owncloud.android.utils.theme.ThemeDrawableUtils;
import com.owncloud.android.utils.theme.ThemeUtils;
import javax.inject.Inject;
/**
* FAB menu {@link android.app.Dialog} styled as a bottom sheet for main actions.
*/
@ -155,9 +153,9 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In
}
// create rich workspace
if (FileMenuFilter.isEditorAvailable(getContext().getContentResolver(),
user,
MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN) &&
if (EditorUtils.isEditorAvailable(getContext().getContentResolver(),
user,
MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN) &&
file != null && !file.isEncrypted()) {
// richWorkspace
// == "": no info set -> show button

View file

@ -104,6 +104,7 @@ import com.owncloud.android.ui.preview.PreviewImageFragment;
import com.owncloud.android.ui.preview.PreviewMediaFragment;
import com.owncloud.android.ui.preview.PreviewTextFileFragment;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.EditorUtils;
import com.owncloud.android.utils.EncryptionUtils;
import com.owncloud.android.utils.FileSortOrder;
import com.owncloud.android.utils.FileStorageUtils;
@ -1062,9 +1063,9 @@ public class OCFileListFragment extends ExtendedListFragment implements
setFabVisible(false);
resetHeaderScrollingState();
((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true, true, true);
} else if (FileMenuFilter.isEditorAvailable(requireContext().getContentResolver(),
accountManager.getUser(),
file.getMimeType()) &&
} else if (EditorUtils.isEditorAvailable(requireContext().getContentResolver(),
accountManager.getUser(),
file.getMimeType()) &&
!file.isEncrypted()) {
mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(file, getContext());
} else if (capability.getRichDocumentsMimeTypeList().contains(file.getMimeType()) &&
@ -1131,9 +1132,9 @@ 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(requireContext().getContentResolver(),
accountManager.getUser(),
singleFile.getMimeType())) {
mContainerActivity.getFileOperationsHelper().openFileWithTextEditor(singleFile, getContext());
} else {
mContainerActivity.getFileOperationsHelper().openFileAsRichDocument(singleFile, getContext());

View file

@ -55,7 +55,6 @@ import com.owncloud.android.MainApp;
import com.owncloud.android.R;
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;
@ -82,6 +81,7 @@ import com.owncloud.android.ui.events.FavoriteEvent;
import com.owncloud.android.ui.events.FileLockEvent;
import com.owncloud.android.ui.events.SyncEventFinished;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.EditorUtils;
import com.owncloud.android.utils.FileStorageUtils;
import com.owncloud.android.utils.PermissionUtil;
import com.owncloud.android.utils.UriUtils;
@ -302,9 +302,9 @@ 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(fileActivity.getContentResolver(),
optionalUser.get(),
file.getMimeType())) {
openFileWithTextEditor(file, fileActivity);
} else {
Account account = fileActivity.getAccount();

View file

@ -0,0 +1,48 @@
/*
*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2022 Tobias Kaminsky
* 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 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.utils
import android.content.ContentResolver
import com.google.gson.Gson
import com.nextcloud.client.account.User
import com.owncloud.android.datamodel.ArbitraryDataProvider
import com.owncloud.android.lib.common.DirectEditing
import com.owncloud.android.lib.common.Editor
object EditorUtils {
@JvmStatic
fun isEditorAvailable(contentResolver: ContentResolver?, user: User?, mimeType: String?): Boolean {
return getEditor(contentResolver, user, mimeType) != null
}
@JvmStatic
fun getEditor(contentResolver: ContentResolver?, user: User?, mimeType: String?): Editor? {
val json = ArbitraryDataProvider(contentResolver).getValue(user, ArbitraryDataProvider.DIRECT_EDITING)
if (json.isEmpty()) {
return null
}
val directEditing = Gson().fromJson(json, DirectEditing::class.java)
val editors = directEditing.editors.values
return editors.firstOrNull { it.mimetypes.contains(mimeType) || it.optionalMimetypes.contains(mimeType) }
}
}