mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-11-09 13:09:21 +03:00
feat: optimize image upload process and display an error message if upload fails (#4679)
* chore: optimize image upload * feat: show upload image status * chore: upload the ai image to cloud server
This commit is contained in:
parent
252699d249
commit
26f8bbf7c6
@ -104,12 +104,14 @@ class DocumentService {
|
||||
/// Upload a file to the cloud storage.
|
||||
Future<Either<FlowyError, UploadedFilePB>> uploadFile({
|
||||
required String localFilePath,
|
||||
bool isAsync = true,
|
||||
}) async {
|
||||
final workspace = await FolderEventReadCurrentWorkspace().send();
|
||||
return workspace.fold((l) async {
|
||||
final payload = UploadFileParamsPB(
|
||||
workspaceId: l.id,
|
||||
localFilePath: localFilePath,
|
||||
isAsync: isAsync,
|
||||
);
|
||||
final result = await DocumentEventUploadFile(payload).send();
|
||||
return result.swap();
|
||||
|
@ -615,7 +615,7 @@ class DocumentCoverState extends State<DocumentCover> {
|
||||
details = await saveImageToLocalStorage(details);
|
||||
} else {
|
||||
// else we should save the image to cloud storage
|
||||
details = await saveImageToCloudStorage(details);
|
||||
(details, _) = await saveImageToCloudStorage(details);
|
||||
}
|
||||
}
|
||||
widget.onChangeCover(type, details);
|
||||
|
@ -44,6 +44,8 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
|
||||
final documentService = DocumentService();
|
||||
late final editorState = context.read<EditorState>();
|
||||
|
||||
bool showLoading = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Widget child = DecoratedBox(
|
||||
@ -65,9 +67,19 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
|
||||
size: Size.square(24),
|
||||
),
|
||||
const HSpace(10),
|
||||
FlowyText(
|
||||
LocaleKeys.document_plugins_image_addAnImage.tr(),
|
||||
),
|
||||
...showLoading
|
||||
? [
|
||||
FlowyText(
|
||||
LocaleKeys.document_imageBlock_imageIsUploading.tr(),
|
||||
),
|
||||
const HSpace(8),
|
||||
const CircularProgressIndicator.adaptive(),
|
||||
]
|
||||
: [
|
||||
FlowyText(
|
||||
LocaleKeys.document_plugins_image_addAnImage.tr(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -188,6 +200,7 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
|
||||
final transaction = editorState.transaction;
|
||||
|
||||
String? path;
|
||||
String? errorMessage;
|
||||
CustomImageType imageType = CustomImageType.local;
|
||||
|
||||
// if the user is using local authenticator, we need to save the image to local storage
|
||||
@ -195,14 +208,22 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
|
||||
path = await saveImageToLocalStorage(url);
|
||||
} else {
|
||||
// else we should save the image to cloud storage
|
||||
path = await saveImageToCloudStorage(url);
|
||||
setState(() {
|
||||
showLoading = true;
|
||||
});
|
||||
(path, errorMessage) = await saveImageToCloudStorage(url);
|
||||
setState(() {
|
||||
showLoading = false;
|
||||
});
|
||||
imageType = CustomImageType.internal;
|
||||
}
|
||||
|
||||
if (mounted && path == null) {
|
||||
showSnackBarMessage(
|
||||
context,
|
||||
LocaleKeys.document_imageBlock_error_invalidImage.tr(),
|
||||
errorMessage == null
|
||||
? LocaleKeys.document_imageBlock_error_invalidImage.tr()
|
||||
: ': $errorMessage',
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -244,12 +265,8 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
|
||||
|
||||
final response = await get(uri);
|
||||
await File(copyToPath).writeAsBytes(response.bodyBytes);
|
||||
|
||||
final transaction = editorState.transaction;
|
||||
transaction.updateNode(widget.node, {
|
||||
ImageBlockKeys.url: copyToPath,
|
||||
});
|
||||
await editorState.apply(transaction);
|
||||
await insertLocalImage(copyToPath);
|
||||
await File(copyToPath).delete();
|
||||
} catch (e) {
|
||||
Log.error('cannot save image file', e);
|
||||
}
|
||||
|
@ -34,19 +34,22 @@ Future<String?> saveImageToLocalStorage(String localImagePath) async {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> saveImageToCloudStorage(String localImagePath) async {
|
||||
Future<(String? path, String? errorMessage)> saveImageToCloudStorage(
|
||||
String localImagePath,
|
||||
) async {
|
||||
final documentService = DocumentService();
|
||||
final result = await documentService.uploadFile(
|
||||
localFilePath: localImagePath,
|
||||
isAsync: false,
|
||||
);
|
||||
return result.fold(
|
||||
(l) => null,
|
||||
(l) => (null, l.msg),
|
||||
(r) async {
|
||||
await CustomImageCacheManager().putFile(
|
||||
r.url,
|
||||
File(localImagePath).readAsBytesSync(),
|
||||
);
|
||||
return r.url;
|
||||
return (r.url, null);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ class _ResizableImageState extends State<ResizableImage> {
|
||||
progressIndicatorBuilder: (context, url, progress) =>
|
||||
_buildLoading(context),
|
||||
);
|
||||
|
||||
child = _cacheImage!;
|
||||
} else {
|
||||
// load local file
|
||||
|
@ -0,0 +1,20 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
Future<bool> isImageExistOnCloud({
|
||||
required String url,
|
||||
required UserProfilePB userProfilePB,
|
||||
}) async {
|
||||
final header = <String, String>{};
|
||||
final token = userProfilePB.token;
|
||||
try {
|
||||
final decodedToken = jsonDecode(token);
|
||||
header['Authorization'] = 'Bearer ${decodedToken['access_token']}';
|
||||
final response = await http.get(Uri.http(url), headers: header);
|
||||
return response.statusCode == 200;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -862,7 +862,8 @@
|
||||
"successToAddImageToGallery": "Image added to gallery successfully",
|
||||
"unableToLoadImage": "Unable to load image",
|
||||
"maximumImageSize": "Maximum supported upload image size is 10MB",
|
||||
"uploadImageErrorImageSizeTooBig": "Image size must be less than 10MB"
|
||||
"uploadImageErrorImageSizeTooBig": "Image size must be less than 10MB",
|
||||
"imageIsUploading": "Image is uploading"
|
||||
},
|
||||
"codeBlock": {
|
||||
"language": {
|
||||
|
Loading…
Reference in New Issue
Block a user