mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
[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:
parent
92f980347f
commit
01ced3bdc0
@ -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?"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user