[Fix] delete cover image document update (#2224)

* fix: reset cover on deleting selected cover image

* feat: add alert dialog on delete

* fix: update cover image list when file not found

* fix: missing const in change cover popup

* fix: added dialog string in translation file

* fix: analytical issue in changeCoverPopover

* fix: added trailing commas in change_cover_popover
This commit is contained in:
GouravShDev 2023-04-13 17:51:15 +05:30 committed by GitHub
parent 92f980347f
commit 01ced3bdc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 14 deletions

View File

@ -384,7 +384,9 @@
"pickFromFiles": "Pick from files",
"couldNotFetchImage": "Could not fetch image",
"imageSavingFailed": "Image Saving Failed",
"addIcon": "Add Icon"
"addIcon": "Add Icon",
"coverRemoveAlert" : "It will be removed from cover after it is deleted.",
"alertDialogConfirmation" : "Are you sure, you want to continue?"
}
}
},

View File

@ -79,8 +79,10 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ChangeCoverPopoverBloc()
..add(const ChangeCoverPopoverEvent.fetchPickedImagePaths()),
create: (context) => ChangeCoverPopoverBloc(
editorState: widget.editorState,
node: widget.node,
)..add(const ChangeCoverPopoverEvent.fetchPickedImagePaths()),
child: BlocBuilder<ChangeCoverPopoverBloc, ChangeCoverPopoverState>(
builder: (context, state) {
return Padding(
@ -149,10 +151,31 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
hoverColor: Theme.of(context).colorScheme.secondaryContainer,
LocaleKeys.document_plugins_cover_clearAll.tr(),
fontColor: Theme.of(context).colorScheme.tertiary,
onPressed: () {
context
.read<ChangeCoverPopoverBloc>()
.add(const ChangeCoverPopoverEvent.clearAllImages());
onPressed: () async {
final hasFileImageCover = CoverSelectionType.fromString(
widget.node.attributes[kCoverSelectionTypeAttribute],
) ==
CoverSelectionType.file;
final changeCoverBloc = context.read<ChangeCoverPopoverBloc>();
if (hasFileImageCover) {
await showDialog(
context: context,
builder: (context) {
return DeleteImageAlertDialog(
onSubmit: () {
changeCoverBloc.add(
const ChangeCoverPopoverEvent.clearAllImages(),
);
Navigator.pop(context);
},
);
},
);
} else {
context
.read<ChangeCoverPopoverBloc>()
.add(const ChangeCoverPopoverEvent.clearAllImages());
}
},
mainAxisAlignment: MainAxisAlignment.end,
),
@ -263,6 +286,32 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
images[index - 1],
);
},
onImageDelete: () async {
final changeCoverBloc =
context.read<ChangeCoverPopoverBloc>();
final deletingCurrentCover =
widget.node.attributes[kCoverSelectionAttribute] ==
images[index - 1];
if (deletingCurrentCover) {
await showDialog(
context: context,
builder: (context) {
return DeleteImageAlertDialog(
onSubmit: () {
changeCoverBloc.add(
ChangeCoverPopoverEvent.deleteImage(
images[index - 1],
),
);
Navigator.pop(context);
},
);
},
);
} else {
changeCoverBloc.add(DeleteImage(images[index - 1]));
}
},
imagePath: images[index - 1],
);
},
@ -285,14 +334,68 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
}
}
class DeleteImageAlertDialog extends StatelessWidget {
const DeleteImageAlertDialog({
Key? key,
required this.onSubmit,
}) : super(key: key);
final Function() onSubmit;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: FlowyText.semibold(
"Image is used in cover",
fontSize: 20,
color: Theme.of(context).colorScheme.tertiary,
),
content: Container(
constraints: const BoxConstraints(minHeight: 100),
padding: const EdgeInsets.symmetric(
vertical: 20,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(LocaleKeys.document_plugins_cover_coverRemoveAlert).tr(),
const SizedBox(
height: 4,
),
const Text(
LocaleKeys.document_plugins_cover_alertDialogConfirmation,
).tr(),
],
),
),
contentPadding: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text(LocaleKeys.button_Cancel).tr(),
),
TextButton(
onPressed: onSubmit,
child: const Text(LocaleKeys.button_OK).tr(),
),
],
);
}
}
class ImageGridItem extends StatefulWidget {
const ImageGridItem({
Key? key,
required this.onImageSelect,
required this.onImageDelete,
required this.imagePath,
}) : super(key: key);
final Function() onImageSelect;
final Function() onImageDelete;
final String imagePath;
@override
@ -343,11 +446,7 @@ class _ImageGridItemState extends State<ImageGridItem> {
'editor/delete',
color: Theme.of(context).colorScheme.tertiary,
),
onPressed: () {
context.read<ChangeCoverPopoverBloc>().add(
ChangeCoverPopoverEvent.deleteImage(widget.imagePath),
);
},
onPressed: widget.onImageDelete,
),
),
],

View File

@ -2,6 +2,8 @@ import 'dart:async';
import 'dart:io';
import 'package:appflowy/plugins/document/presentation/plugins/cover/change_cover_popover.dart';
import 'package:appflowy/plugins/document/presentation/plugins/cover/cover_node_widget.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -10,9 +12,12 @@ part 'change_cover_popover_bloc.freezed.dart';
class ChangeCoverPopoverBloc
extends Bloc<ChangeCoverPopoverEvent, ChangeCoverPopoverState> {
final EditorState editorState;
final Node node;
late final SharedPreferences _prefs;
final _initCompleter = Completer<void>();
ChangeCoverPopoverBloc() : super(const ChangeCoverPopoverState.initial()) {
ChangeCoverPopoverBloc({required this.editorState, required this.node})
: super(const ChangeCoverPopoverState.initial()) {
SharedPreferences.getInstance().then((prefs) {
_prefs = prefs;
_initCompleter.complete();
@ -26,8 +31,13 @@ class ChangeCoverPopoverBloc
},
deleteImage: (DeleteImage deleteImage) async {
final currentState = state;
final currentlySelectedImage =
node.attributes[kCoverSelectionAttribute];
if (currentState is Loaded) {
await _deleteImageInStorage(deleteImage.path);
if (currentlySelectedImage == deleteImage.path) {
_removeCoverImageFromNode();
}
final updateImageList = currentState.imageNames
.where((path) => path != deleteImage.path)
.toList();
@ -37,9 +47,15 @@ class ChangeCoverPopoverBloc
},
clearAllImages: (ClearAllImages clearAllImages) async {
final currentState = state;
final currentlySelectedImage =
node.attributes[kCoverSelectionAttribute];
if (currentState is Loaded) {
for (final image in currentState.imageNames) {
await _deleteImageInStorage(image);
if (currentlySelectedImage == image) {
_removeCoverImageFromNode();
}
}
await _updateImagePathsInStorage([]);
emit(const Loaded([]));
@ -56,6 +72,7 @@ class ChangeCoverPopoverBloc
return imageNames;
}
imageNames.removeWhere((name) => !File(name).existsSync());
_prefs.setStringList(kLocalImagesKey, imageNames);
return imageNames;
}
@ -69,6 +86,15 @@ class ChangeCoverPopoverBloc
final imageFile = File(path);
await imageFile.delete();
}
Future<void> _removeCoverImageFromNode() async {
final transaction = editorState.transaction;
transaction.updateNode(node, {
kCoverSelectionTypeAttribute: CoverSelectionType.initial.toString(),
kIconSelectionAttribute: node.attributes[kIconSelectionAttribute]
});
return editorState.apply(transaction);
}
}
@freezed

View File

@ -443,8 +443,18 @@ class _CoverImageState extends State<_CoverImage> {
final Widget coverImage;
switch (selectionType) {
case CoverSelectionType.file:
final imageFile =
File(widget.node.attributes[kCoverSelectionAttribute]);
if (!imageFile.existsSync()) {
// reset cover state
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.onCoverChanged(CoverSelectionType.initial, null);
});
coverImage = const SizedBox();
break;
}
coverImage = Image.file(
File(widget.node.attributes[kCoverSelectionAttribute]),
imageFile,
fit: BoxFit.cover,
);
break;