mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-09-23 15:38:07 +00:00
feat: delete the previous image when the cover changes in local mode (#6368)
* remove unecessary images from localstorage * feat: Add handler for deleting previous cover image on cover image change * fix: add local image case for versions after 0.5.5 * fix: add try catch block and delete action to bottom of function * chore: add test case for uploading and deleting image in localmode --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
parent
73463cd7e3
commit
b965a5f3ae
@ -1,15 +1,23 @@
|
|||||||
|
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/header/document_cover_widget.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/document_cover_widget.dart';
|
||||||
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart';
|
||||||
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
|
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
|
||||||
import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart';
|
import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
|
import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
import '../../shared/emoji.dart';
|
import '../../shared/emoji.dart';
|
||||||
|
import '../../shared/mock/mock_file_picker.dart';
|
||||||
import '../../shared/util.dart';
|
import '../../shared/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -60,6 +68,59 @@ void main() {
|
|||||||
tester.expectToSeeNoDocumentCover();
|
tester.expectToSeeNoDocumentCover();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('document cover local image tests', (tester) async {
|
||||||
|
await tester.initializeAppFlowy();
|
||||||
|
await tester.tapAnonymousSignInButton();
|
||||||
|
|
||||||
|
tester.expectToSeeNoDocumentCover();
|
||||||
|
|
||||||
|
// Hover over cover toolbar to show 'Add Cover' and 'Add Icon' buttons
|
||||||
|
await tester.editor.hoverOnCoverToolbar();
|
||||||
|
|
||||||
|
// Insert a document cover
|
||||||
|
await tester.editor.tapOnAddCover();
|
||||||
|
tester.expectToSeeDocumentCover(CoverType.asset);
|
||||||
|
|
||||||
|
// Hover over the cover to show the 'Change Cover' and delete buttons
|
||||||
|
await tester.editor.hoverOnCover();
|
||||||
|
tester.expectChangeCoverAndDeleteButton();
|
||||||
|
|
||||||
|
// Change cover to a local image image
|
||||||
|
final imagePath = await rootBundle.load('assets/test/images/sample.jpeg');
|
||||||
|
final tempDirectory = await getTemporaryDirectory();
|
||||||
|
final localImagePath = p.join(tempDirectory.path, 'sample.jpeg');
|
||||||
|
final imageFile = File(localImagePath)
|
||||||
|
..writeAsBytesSync(imagePath.buffer.asUint8List());
|
||||||
|
|
||||||
|
await tester.editor.hoverOnCover();
|
||||||
|
await tester.editor.tapOnChangeCover();
|
||||||
|
|
||||||
|
final uploadButton = find.findTextInFlowyText(
|
||||||
|
LocaleKeys.document_imageBlock_upload_label.tr(),
|
||||||
|
);
|
||||||
|
await tester.tapButton(uploadButton);
|
||||||
|
|
||||||
|
mockPickFilePaths(paths: [localImagePath]);
|
||||||
|
await tester.tapButtonWithName(
|
||||||
|
LocaleKeys.document_imageBlock_upload_placeholder.tr(),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
tester.expectToSeeDocumentCover(CoverType.file);
|
||||||
|
|
||||||
|
// Remove the cover
|
||||||
|
await tester.editor.hoverOnCover();
|
||||||
|
await tester.editor.tapOnRemoveCover();
|
||||||
|
tester.expectToSeeNoDocumentCover();
|
||||||
|
|
||||||
|
// Test if deleteImageFromLocalStorage(localImagePath) function is called once
|
||||||
|
await tester.pump(kDoubleTapTimeout);
|
||||||
|
expect(deleteImageTestCounter, 1);
|
||||||
|
|
||||||
|
// delete temp files
|
||||||
|
await imageFile.delete();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('document icon tests', (tester) async {
|
testWidgets('document icon tests', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapAnonymousSignInButton();
|
await tester.tapAnonymousSignInButton();
|
||||||
|
@ -763,15 +763,29 @@ class DocumentCoverState extends State<DocumentCover> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onCoverChanged(CoverType type, String? details) async {
|
Future<void> onCoverChanged(CoverType type, String? details) async {
|
||||||
if (type == CoverType.file && details != null && !isURL(details)) {
|
final previousType = CoverType.fromString(
|
||||||
|
widget.node.attributes[DocumentHeaderBlockKeys.coverType],
|
||||||
|
);
|
||||||
|
final previousDetails =
|
||||||
|
widget.node.attributes[DocumentHeaderBlockKeys.coverDetails];
|
||||||
|
|
||||||
|
bool isFileType(CoverType type, String? details) =>
|
||||||
|
type == CoverType.file && details != null && !isURL(details);
|
||||||
|
|
||||||
|
if (isFileType(type, details)) {
|
||||||
if (_isLocalMode()) {
|
if (_isLocalMode()) {
|
||||||
details = await saveImageToLocalStorage(details);
|
details = await saveImageToLocalStorage(details!);
|
||||||
} else {
|
} else {
|
||||||
// else we should save the image to cloud storage
|
// else we should save the image to cloud storage
|
||||||
(details, _) = await saveImageToCloudStorage(details, widget.view.id);
|
(details, _) = await saveImageToCloudStorage(details!, widget.view.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
widget.onChangeCover(type, details);
|
widget.onChangeCover(type, details);
|
||||||
|
|
||||||
|
// After cover change,delete from localstorage if previous cover was image type
|
||||||
|
if (isFileType(previousType, previousDetails) && _isLocalMode()) {
|
||||||
|
await deleteImageFromLocalStorage(previousDetails);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOverlayButtonsHidden(bool value) {
|
void setOverlayButtonsHidden(bool value) {
|
||||||
|
@ -117,3 +117,16 @@ Future<List<ImageBlockData>> extractAndUploadImages(
|
|||||||
|
|
||||||
return images;
|
return images;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
int deleteImageTestCounter = 0;
|
||||||
|
|
||||||
|
Future<void> deleteImageFromLocalStorage(String localImagePath) async {
|
||||||
|
try {
|
||||||
|
await File(localImagePath)
|
||||||
|
.delete()
|
||||||
|
.whenComplete(() => deleteImageTestCounter++);
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('cannot delete image file', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -226,6 +226,14 @@ class EditorMigration {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
extra = {
|
||||||
|
ViewExtKeys.coverKey: {
|
||||||
|
ViewExtKeys.coverTypeKey:
|
||||||
|
PageStyleCoverImageType.localImage.toString(),
|
||||||
|
ViewExtKeys.coverValueKey: coverDetails,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user