fix: support pasting web image on mobile (#5987)

* fix: support pasting web image on mobile

* fix: permission check will deactive editor focus
This commit is contained in:
Lucas.Xu 2024-08-17 11:04:56 +08:00 committed by GitHub
parent e6bf6a5c7d
commit 44fb610269
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 70 additions and 17 deletions

View File

@ -100,9 +100,7 @@ class ClipboardService {
for (final item in reader.items) { for (final item in reader.items) {
final availableFormats = await item.rawReader!.getAvailableFormats(); final availableFormats = await item.rawReader!.getAvailableFormats();
Log.debug( Log.info('availableFormats: $availableFormats');
'availableFormats: $availableFormats',
);
} }
final plainText = await reader.readValue(Formats.plainText); final plainText = await reader.readValue(Formats.plainText);
@ -115,6 +113,8 @@ class ClipboardService {
image = ('jpeg', await reader.readFile(Formats.jpeg)); image = ('jpeg', await reader.readFile(Formats.jpeg));
} else if (reader.canProvide(Formats.gif)) { } else if (reader.canProvide(Formats.gif)) {
image = ('gif', await reader.readFile(Formats.gif)); image = ('gif', await reader.readFile(Formats.gif));
} else if (reader.canProvide(Formats.webp)) {
image = ('webp', await reader.readFile(Formats.webp));
} }
return ClipboardServiceData( return ClipboardServiceData(

View File

@ -76,6 +76,7 @@ CommandShortcutEventHandler _pasteCommandHandler = (editorState) {
image.$1, image.$1,
image.$2!, image.$2!,
documentId, documentId,
selection: selection,
); );
if (result) { if (result) {
Log.info('Pasted image'); Log.info('Pasted image');

View File

@ -9,7 +9,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/image/imag
import 'package:appflowy/shared/patterns/common_patterns.dart'; import 'package:appflowy/shared/patterns/common_patterns.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/settings/application_data_storage.dart'; import 'package:appflowy/workspace/application/settings/application_data_storage.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart'; import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log; import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:cross_file/cross_file.dart'; import 'package:cross_file/cross_file.dart';
@ -23,6 +23,7 @@ extension PasteFromImage on EditorState {
'png', 'png',
'jpeg', 'jpeg',
'gif', 'gif',
'webp',
]; ];
Future<void> dropImages( Future<void> dropImages(
@ -64,18 +65,26 @@ extension PasteFromImage on EditorState {
Future<bool> pasteImage( Future<bool> pasteImage(
String format, String format,
Uint8List imageBytes, Uint8List imageBytes,
String documentId, String documentId, {
) async { Selection? selection,
if (!supportedImageFormats.contains(format)) { }) async {
return false;
}
final context = document.root.context; final context = document.root.context;
if (context == null) { if (context == null) {
return false; return false;
} }
if (!supportedImageFormats.contains(format)) {
Log.info('unsupported format: $format');
if (PlatformExtension.isMobile) {
showToastNotification(
context,
message: LocaleKeys.document_imageBlock_error_invalidImageFormat.tr(),
);
}
return false;
}
final isLocalMode = context.read<DocumentBloc>().isLocalMode; final isLocalMode = context.read<DocumentBloc>().isLocalMode;
final path = await getIt<ApplicationDataStorage>().getPath(); final path = await getIt<ApplicationDataStorage>().getPath();
@ -105,9 +114,9 @@ extension PasteFromImage on EditorState {
final errorMessage = result.$2; final errorMessage = result.$2;
if (errorMessage != null && context.mounted) { if (errorMessage != null && context.mounted) {
showSnackBarMessage( showToastNotification(
context, context,
errorMessage, message: errorMessage,
); );
return false; return false;
} }
@ -116,7 +125,7 @@ extension PasteFromImage on EditorState {
} }
if (path != null) { if (path != null) {
await insertImageNode(path); await insertImageNode(path, selection: selection);
} }
await File(copyToPath).delete(); await File(copyToPath).delete();
@ -124,13 +133,55 @@ extension PasteFromImage on EditorState {
} catch (e) { } catch (e) {
Log.error('cannot copy image file', e); Log.error('cannot copy image file', e);
if (context.mounted) { if (context.mounted) {
showSnackBarMessage( showToastNotification(
context, context,
LocaleKeys.document_imageBlock_error_invalidImage.tr(), message: LocaleKeys.document_imageBlock_error_invalidImage.tr(),
); );
} }
} }
return false; return false;
} }
Future<void> insertImageNode(
String src, {
Selection? selection,
}) async {
selection ??= this.selection;
if (selection == null || !selection.isCollapsed) {
return;
}
final node = getNodeAtPath(selection.end.path);
if (node == null) {
return;
}
final transaction = this.transaction;
// if the current node is empty paragraph, replace it with image node
if (node.type == ParagraphBlockKeys.type &&
(node.delta?.isEmpty ?? false)) {
transaction
..insertNode(
node.path,
imageNode(
url: src,
),
)
..deleteNode(node);
} else {
transaction.insertNode(
node.path.next,
imageNode(
url: src,
),
);
}
transaction.afterSelection = Selection.collapsed(
Position(
path: node.path.next,
),
);
return apply(transaction);
}
} }

View File

@ -1,6 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -23,7 +24,7 @@ List<ContextMenuButtonItem> buildMobileFloatingToolbarItems(
ContextMenuButtonItem( ContextMenuButtonItem(
label: LocaleKeys.editor_copy.tr(), label: LocaleKeys.editor_copy.tr(),
onPressed: () { onPressed: () {
copyCommand.execute(editorState); customCopyCommand.execute(editorState);
closeToolbar(); closeToolbar();
}, },
), ),
@ -34,7 +35,7 @@ List<ContextMenuButtonItem> buildMobileFloatingToolbarItems(
ContextMenuButtonItem( ContextMenuButtonItem(
label: LocaleKeys.editor_paste.tr(), label: LocaleKeys.editor_paste.tr(),
onPressed: () { onPressed: () {
pasteCommand.execute(editorState); customPasteCommand.execute(editorState);
closeToolbar(); closeToolbar();
}, },
), ),