feat: auto pop up the menu after inserting image block (#3698)

This commit is contained in:
Lucas.Xu 2023-10-15 13:04:24 +08:00 committed by GitHub
parent 8436bc6144
commit 11daa15b89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 13 deletions

View File

@ -9,6 +9,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/image/uplo
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide UploadImageMenu;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@ -41,8 +42,13 @@ void main() {
await tester.editor.tapSlashMenuItemWithName('Image');
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
await tester.tapButton(find.byType(ImagePlaceholder));
expect(
find.descendant(
of: find.byType(ImagePlaceholder),
matching: find.byType(AppFlowyPopover),
),
findsOneWidget,
);
expect(find.byType(UploadImageMenu), findsOneWidget);
final image = await rootBundle.load('assets/test/images/sample.jpeg');
@ -84,8 +90,13 @@ void main() {
await tester.editor.tapSlashMenuItemWithName('Image');
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
await tester.tapButton(find.byType(ImagePlaceholder));
expect(
find.descendant(
of: find.byType(ImagePlaceholder),
matching: find.byType(AppFlowyPopover),
),
findsOneWidget,
);
expect(find.byType(UploadImageMenu), findsOneWidget);
await tester.tapButtonWithName(
@ -133,8 +144,13 @@ void main() {
await tester.editor.tapSlashMenuItemWithName('Image');
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
await tester.tapButton(find.byType(ImagePlaceholder));
expect(
find.descendant(
of: find.byType(ImagePlaceholder),
matching: find.byType(AppFlowyPopover),
),
findsOneWidget,
);
expect(find.byType(UploadImageMenu), findsOneWidget);
await tester.tapButtonWithName(

View File

@ -3,6 +3,8 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
const kImagePlaceholderKey = 'imagePlaceholderKey';
typedef CustomImageBlockComponentMenuBuilder = Widget Function(
Node node,
CustomImageBlockComponentState state,
@ -93,8 +95,10 @@ class CustomImageBlockComponentState extends State<CustomImageBlockComponent>
MediaQuery.of(context).size.width;
final height = attributes[ImageBlockKeys.height]?.toDouble();
final imagePlaceholderKey = node.extraInfos?[kImagePlaceholderKey];
Widget child = src.isEmpty
? ImagePlaceholder(
key: imagePlaceholderKey is GlobalKey ? imagePlaceholderKey : null,
node: node,
)
: ResizableImage(

View File

@ -28,10 +28,10 @@ class ImagePlaceholder extends StatefulWidget {
final Node node;
@override
State<ImagePlaceholder> createState() => _ImagePlaceholderState();
State<ImagePlaceholder> createState() => ImagePlaceholderState();
}
class _ImagePlaceholderState extends State<ImagePlaceholder> {
class ImagePlaceholderState extends State<ImagePlaceholder> {
final controller = PopoverController();
late final editorState = context.read<EditorState>();

View File

@ -1,4 +1,7 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:flutter/material.dart';
final customImageMenuItem = SelectionMenuItem(
name: AppFlowyEditorLocalizations.current.image,
@ -9,6 +12,54 @@ final customImageMenuItem = SelectionMenuItem(
),
keywords: ['image', 'picture', 'img', 'photo'],
handler: (editorState, menuService, context) async {
return await editorState.insertImageNode('');
// use the key to retrieve the state of the image block to show the popover automatically
final imagePlaceholderKey = GlobalKey<ImagePlaceholderState>();
await editorState.insertEmptyImageBlock(imagePlaceholderKey);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
imagePlaceholderKey.currentState?.controller.show();
});
},
);
extension InsertImage on EditorState {
Future<void> insertEmptyImageBlock(GlobalKey key) async {
final selection = this.selection;
if (selection == null || !selection.isCollapsed) {
return;
}
final node = getNodeAtPath(selection.end.path);
if (node == null) {
return;
}
final emptyImage = imageNode(url: '')
..extraInfos = {
kImagePlaceholderKey: key,
};
final transaction = this.transaction;
// if the current node is empty paragraph, replace it with image node
if (node.type == ParagraphBlockKeys.type &&
(node.delta?.isEmpty ?? false)) {
transaction
..insertNode(
node.path,
emptyImage,
)
..deleteNode(node);
} else {
transaction.insertNode(
node.path.next,
emptyImage,
);
}
transaction.afterSelection = Selection.collapsed(
Position(
path: node.path.next,
offset: 0,
),
);
return apply(transaction);
}
}

View File

@ -54,8 +54,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "194fe2f"
resolved-ref: "194fe2fec9ce00baa2d5f2afbbfe0a45b3a7b158"
ref: d1027c4
resolved-ref: d1027c4d83a8cf78227e7d742c050ca945cef23a
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git
version: "1.4.4"
@ -1890,4 +1890,4 @@ packages:
version: "1.1.1"
sdks:
dart: ">=3.0.0 <4.0.0"
flutter: ">=3.10.1"
flutter: ">=3.10.1"

View File

@ -47,7 +47,7 @@ dependencies:
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "194fe2f"
ref: "d1027c4"
appflowy_popover:
path: packages/appflowy_popover