fix: unable to upload image from clipboard (#4728)

* fix: unable to upload image from clipboard

* chore: apply suggestion
This commit is contained in:
Lucas.Xu 2024-02-25 17:50:35 +07:00 committed by GitHub
parent 537fa52e77
commit b60d25a0e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 78 additions and 29 deletions

View File

@ -12,7 +12,7 @@ import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pbserver.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart' import 'package:appflowy_editor/appflowy_editor.dart'
show show
EditorState, EditorState,
@ -54,6 +54,12 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
StreamSubscription? _subscription; StreamSubscription? _subscription;
bool get isLocalMode {
final userProfilePB = state.userProfilePB;
final type = userProfilePB?.authenticator ?? AuthenticatorPB.Local;
return type == AuthenticatorPB.Local;
}
@override @override
Future<void> close() async { Future<void> close() async {
await _documentListener.stop(); await _documentListener.stop();

View File

@ -1,12 +1,18 @@
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.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_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:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart'; import 'package:flowy_infra/uuid.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:provider/provider.dart';
extension PasteFromImage on EditorState { extension PasteFromImage on EditorState {
static final supportedImageFormats = [ static final supportedImageFormats = [
@ -20,11 +26,20 @@ extension PasteFromImage on EditorState {
return false; return false;
} }
final context = document.root.context;
if (context == null) {
return false;
}
final isLocalMode = context.read<DocumentBloc>().isLocalMode;
final path = await getIt<ApplicationDataStorage>().getPath(); final path = await getIt<ApplicationDataStorage>().getPath();
final imagePath = p.join( final imagePath = p.join(
path, path,
'images', 'images',
); );
try { try {
// create the directory if not exists // create the directory if not exists
final directory = Directory(imagePath); final directory = Directory(imagePath);
@ -33,14 +48,52 @@ extension PasteFromImage on EditorState {
} }
final copyToPath = p.join( final copyToPath = p.join(
imagePath, imagePath,
'${uuid()}.$format', 'tmp_${uuid()}.$format',
); );
await File(copyToPath).writeAsBytes(imageBytes); await File(copyToPath).writeAsBytes(imageBytes);
await insertImageNode(copyToPath); final String? path;
if (context.mounted) {
showSnackBarMessage(
context,
LocaleKeys.document_imageBlock_imageIsUploading.tr(),
);
}
if (isLocalMode) {
path = await saveImageToLocalStorage(copyToPath);
} else {
final result = await saveImageToCloudStorage(copyToPath);
final errorMessage = result.$2;
if (errorMessage != null && context.mounted) {
showSnackBarMessage(
context,
errorMessage,
);
return false;
}
path = result.$1;
}
if (path != null) {
await insertImageNode(path);
}
await File(copyToPath).delete();
return true; return true;
} catch (e) { } catch (e) {
Log.error('cannot copy image file', e); Log.error('cannot copy image file', e);
if (context.mounted) {
showSnackBarMessage(
context,
LocaleKeys.document_imageBlock_error_invalidImage.tr(),
);
} }
}
return false; return false;
} }
} }

View File

@ -13,7 +13,6 @@ import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/shared/appflowy_network_image.dart'; import 'package:appflowy/shared/appflowy_network_image.dart';
import 'package:appflowy/workspace/application/view/view_listener.dart'; import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide UploadImageMenu; import 'package:appflowy_editor/appflowy_editor.dart' hide UploadImageMenu;
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -629,9 +628,7 @@ class DocumentCoverState extends State<DocumentCover> {
} }
bool _isLocalMode() { bool _isLocalMode() {
final userProfilePB = context.read<DocumentBloc>().state.userProfilePB; return context.read<DocumentBloc>().isLocalMode;
final type = userProfilePB?.authenticator ?? AuthenticatorPB.Local;
return type == AuthenticatorPB.Local;
} }
} }

View File

@ -9,11 +9,9 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/image/cust
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/upload_image_menu.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/image/upload_image_menu.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/util/file_extension.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/home/toast.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log, UploadImageMenu; import 'package:appflowy_editor/appflowy_editor.dart' hide Log, UploadImageMenu;
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -194,24 +192,9 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
} }
Future<void> insertLocalImage(String? url) async { Future<void> insertLocalImage(String? url) async {
if (url == null || url.isEmpty) {
controller.close(); controller.close();
return;
}
final size = url.fileSize; if (url == null || url.isEmpty) {
if (size == null || size > 10 * 1024 * 1024) {
controller.close();
setState(() {
showLoading = false;
this.errorMessage =
LocaleKeys.document_imageBlock_uploadImageErrorImageSizeTooBig.tr();
});
// show error
showSnackBarMessage(
context,
LocaleKeys.document_imageBlock_uploadImageErrorImageSizeTooBig.tr(),
);
return; return;
} }
@ -223,6 +206,7 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
// if the user is using local authenticator, we need to save the image to local storage // if the user is using local authenticator, we need to save the image to local storage
if (_isLocalMode()) { if (_isLocalMode()) {
// don't limit the image size for local mode.
path = await saveImageToLocalStorage(url); path = await saveImageToLocalStorage(url);
} else { } else {
// else we should save the image to cloud storage // else we should save the image to cloud storage
@ -313,8 +297,6 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
} }
bool _isLocalMode() { bool _isLocalMode() {
final userProfilePB = context.read<DocumentBloc>().state.userProfilePB; return context.read<DocumentBloc>().isLocalMode;
final type = userProfilePB?.authenticator ?? AuthenticatorPB.Local;
return type == AuthenticatorPB.Local;
} }
} }

View File

@ -1,10 +1,13 @@
import 'dart:io'; import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/prelude.dart'; import 'package:appflowy/plugins/document/application/prelude.dart';
import 'package:appflowy/shared/custom_image_cache_manager.dart'; import 'package:appflowy/shared/custom_image_cache_manager.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/util/file_extension.dart';
import 'package:appflowy/workspace/application/settings/application_data_storage.dart'; import 'package:appflowy/workspace/application/settings/application_data_storage.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart'; import 'package:flowy_infra/uuid.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
@ -37,6 +40,14 @@ Future<String?> saveImageToLocalStorage(String localImagePath) async {
Future<(String? path, String? errorMessage)> saveImageToCloudStorage( Future<(String? path, String? errorMessage)> saveImageToCloudStorage(
String localImagePath, String localImagePath,
) async { ) async {
final size = localImagePath.fileSize;
if (size == null || size > 10 * 1024 * 1024) {
// 10MB
return (
null,
LocaleKeys.document_imageBlock_uploadImageErrorImageSizeTooBig.tr(),
);
}
final documentService = DocumentService(); final documentService = DocumentService();
final result = await documentService.uploadFile( final result = await documentService.uploadFile(
localFilePath: localImagePath, localFilePath: localImagePath,