mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: remove keyword when click selection menu item
This commit is contained in:
parent
206b06f023
commit
5782dec45c
@ -29,7 +29,7 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
|
||||
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
|
||||
path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
|
||||
rich_clipboard_macos: 43364b66b9dc69d203eb8dd6d758e2d12e02723c
|
||||
url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3
|
||||
|
@ -37,7 +37,7 @@ class SelectionMenuItemWidget extends StatelessWidget {
|
||||
: MaterialStateProperty.all(Colors.transparent),
|
||||
),
|
||||
label: Text(
|
||||
item.name,
|
||||
item.name(),
|
||||
textAlign: TextAlign.left,
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
|
@ -124,7 +124,7 @@ List<SelectionMenuItem> get defaultSelectionMenuItems =>
|
||||
_defaultSelectionMenuItems;
|
||||
final List<SelectionMenuItem> _defaultSelectionMenuItems = [
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.text,
|
||||
name: () => AppFlowyEditorLocalizations.current.text,
|
||||
icon: _selectionMenuIcon('text'),
|
||||
keywords: ['text'],
|
||||
handler: (editorState, _, __) {
|
||||
@ -132,7 +132,7 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
|
||||
},
|
||||
),
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.heading1,
|
||||
name: () => AppFlowyEditorLocalizations.current.heading1,
|
||||
icon: _selectionMenuIcon('h1'),
|
||||
keywords: ['heading 1, h1'],
|
||||
handler: (editorState, _, __) {
|
||||
@ -140,7 +140,7 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
|
||||
},
|
||||
),
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.heading2,
|
||||
name: () => AppFlowyEditorLocalizations.current.heading2,
|
||||
icon: _selectionMenuIcon('h2'),
|
||||
keywords: ['heading 2, h2'],
|
||||
handler: (editorState, _, __) {
|
||||
@ -148,7 +148,7 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
|
||||
},
|
||||
),
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.heading3,
|
||||
name: () => AppFlowyEditorLocalizations.current.heading3,
|
||||
icon: _selectionMenuIcon('h3'),
|
||||
keywords: ['heading 3, h3'],
|
||||
handler: (editorState, _, __) {
|
||||
@ -156,13 +156,13 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
|
||||
},
|
||||
),
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.image,
|
||||
name: () => AppFlowyEditorLocalizations.current.image,
|
||||
icon: _selectionMenuIcon('image'),
|
||||
keywords: ['image'],
|
||||
handler: showImageUploadMenu,
|
||||
),
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.bulletedList,
|
||||
name: () => AppFlowyEditorLocalizations.current.bulletedList,
|
||||
icon: _selectionMenuIcon('bulleted_list'),
|
||||
keywords: ['bulleted list', 'list', 'unordered list'],
|
||||
handler: (editorState, _, __) {
|
||||
@ -170,7 +170,7 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
|
||||
},
|
||||
),
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.checkbox,
|
||||
name: () => AppFlowyEditorLocalizations.current.checkbox,
|
||||
icon: _selectionMenuIcon('checkbox'),
|
||||
keywords: ['todo list', 'list', 'checkbox list'],
|
||||
handler: (editorState, _, __) {
|
||||
@ -178,7 +178,7 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
|
||||
},
|
||||
),
|
||||
SelectionMenuItem(
|
||||
name: AppFlowyEditorLocalizations.current.quote,
|
||||
name: () => AppFlowyEditorLocalizations.current.quote,
|
||||
icon: _selectionMenuIcon('quote'),
|
||||
keywords: ['quote', 'refer'],
|
||||
handler: (editorState, _, __) {
|
||||
|
@ -6,27 +6,54 @@ import 'package:appflowy_editor/src/render/selection_menu/selection_menu_service
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
typedef SelectionMenuItemHandler = void Function(
|
||||
EditorState editorState,
|
||||
SelectionMenuService menuService,
|
||||
BuildContext context,
|
||||
);
|
||||
|
||||
/// Selection Menu Item
|
||||
class SelectionMenuItem {
|
||||
SelectionMenuItem({
|
||||
required this.name,
|
||||
required this.icon,
|
||||
required this.keywords,
|
||||
required this.handler,
|
||||
});
|
||||
required SelectionMenuItemHandler handler,
|
||||
}) {
|
||||
this.handler = (editorState, menuService, context) {
|
||||
_deleteToSlash(editorState);
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
handler(editorState, menuService, context);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
final String name;
|
||||
final String Function() name;
|
||||
final Widget icon;
|
||||
|
||||
/// Customizes keywords for item.
|
||||
///
|
||||
/// The keywords are used to quickly retrieve items.
|
||||
final List<String> keywords;
|
||||
final void Function(
|
||||
EditorState editorState,
|
||||
SelectionMenuService menuService,
|
||||
BuildContext context,
|
||||
) handler;
|
||||
late final SelectionMenuItemHandler handler;
|
||||
|
||||
void _deleteToSlash(EditorState editorState) {
|
||||
final selectionService = editorState.service.selectionService;
|
||||
final selection = selectionService.currentSelection.value;
|
||||
final nodes = selectionService.currentSelectedNodes;
|
||||
if (selection != null && nodes.length == 1) {
|
||||
final node = nodes.first as TextNode;
|
||||
final end = selection.start.offset;
|
||||
final start = node.toRawString().substring(0, end).lastIndexOf('/');
|
||||
TransactionBuilder(editorState)
|
||||
..deleteText(
|
||||
node,
|
||||
start,
|
||||
selection.start.offset - start,
|
||||
)
|
||||
..commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SelectionMenuWidget extends StatefulWidget {
|
||||
@ -204,11 +231,8 @@ class _SelectionMenuWidgetState extends State<SelectionMenuWidget> {
|
||||
|
||||
if (event.logicalKey == LogicalKeyboardKey.enter) {
|
||||
if (0 <= _selectedIndex && _selectedIndex < _showingItems.length) {
|
||||
_deleteLastCharacters(length: keyword.length + 1);
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
_showingItems[_selectedIndex]
|
||||
.handler(widget.editorState, widget.menuService, context);
|
||||
});
|
||||
_showingItems[_selectedIndex]
|
||||
.handler(widget.editorState, widget.menuService, context);
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
} else if (event.logicalKey == LogicalKeyboardKey.escape) {
|
||||
|
@ -17,7 +17,7 @@ void main() async {
|
||||
final menuService = _TestSelectionMenuService();
|
||||
const icon = Icon(Icons.abc);
|
||||
final item = SelectionMenuItem(
|
||||
name: 'example',
|
||||
name: () => 'example',
|
||||
icon: icon,
|
||||
keywords: ['example A', 'example B'],
|
||||
handler: (editorState, menuService, context) {
|
||||
|
@ -13,29 +13,40 @@ void main() async {
|
||||
});
|
||||
|
||||
group('selection_menu_widget.dart', () {
|
||||
// const i = defaultSelectionMenuItems.length;
|
||||
//
|
||||
// Because the `defaultSelectionMenuItems` uses localization,
|
||||
// and the MaterialApp has not been initialized at the time of getting the value,
|
||||
// it will crash.
|
||||
//
|
||||
// Use const value temporarily instead.
|
||||
const i = 7;
|
||||
testWidgets('Selects number.$i item in selection menu', (tester) async {
|
||||
final editor = await _prepare(tester);
|
||||
for (var j = 0; j < i; j++) {
|
||||
await editor.pressLogicKey(LogicalKeyboardKey.arrowDown);
|
||||
}
|
||||
for (var i = 0; i < defaultSelectionMenuItems.length; i += 1) {
|
||||
testWidgets('Selects number.$i item in selection menu with enter', (
|
||||
tester) async {
|
||||
final editor = await _prepare(tester);
|
||||
for (var j = 0; j < i; j++) {
|
||||
await editor.pressLogicKey(LogicalKeyboardKey.arrowDown);
|
||||
}
|
||||
|
||||
await editor.pressLogicKey(LogicalKeyboardKey.enter);
|
||||
expect(
|
||||
find.byType(SelectionMenuWidget, skipOffstage: false),
|
||||
findsNothing,
|
||||
);
|
||||
if (defaultSelectionMenuItems[i].name != 'Image') {
|
||||
await _testDefaultSelectionMenuItems(i, editor);
|
||||
}
|
||||
});
|
||||
await editor.pressLogicKey(LogicalKeyboardKey.enter);
|
||||
expect(
|
||||
find.byType(SelectionMenuWidget, skipOffstage: false),
|
||||
findsNothing,
|
||||
);
|
||||
if (defaultSelectionMenuItems[i].name() != 'Image') {
|
||||
await _testDefaultSelectionMenuItems(i, editor);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('Selects number.$i item in selection menu with click', (
|
||||
tester) async {
|
||||
final editor = await _prepare(tester);
|
||||
|
||||
await tester.tap(find.byType(SelectionMenuItemWidget).at(i));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.byType(SelectionMenuWidget, skipOffstage: false),
|
||||
findsNothing,
|
||||
);
|
||||
if (defaultSelectionMenuItems[i].name() != 'Image') {
|
||||
await _testDefaultSelectionMenuItems(i, editor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testWidgets('Search item in selection menu util no results',
|
||||
(tester) async {
|
||||
@ -138,23 +149,27 @@ Future<void> _testDefaultSelectionMenuItems(
|
||||
int index, EditorWidgetTester editor) async {
|
||||
expect(editor.documentLength, 4);
|
||||
expect(editor.documentSelection, Selection.single(path: [2], startOffset: 0));
|
||||
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), 'Welcome to Appflowy 😁');
|
||||
final node = editor.nodeAtPath([2]);
|
||||
final item = defaultSelectionMenuItems[index];
|
||||
if (item.name == 'Text') {
|
||||
final itemName = item.name();
|
||||
if (itemName == 'Text') {
|
||||
expect(node?.subtype == null, true);
|
||||
} else if (item.name == 'Heading 1') {
|
||||
} else if (itemName == 'Heading 1') {
|
||||
expect(node?.subtype, BuiltInAttributeKey.heading);
|
||||
expect(node?.attributes.heading, BuiltInAttributeKey.h1);
|
||||
} else if (item.name == 'Heading 2') {
|
||||
} else if (itemName == 'Heading 2') {
|
||||
expect(node?.subtype, BuiltInAttributeKey.heading);
|
||||
expect(node?.attributes.heading, BuiltInAttributeKey.h2);
|
||||
} else if (item.name == 'Heading 3') {
|
||||
} else if (itemName == 'Heading 3') {
|
||||
expect(node?.subtype, BuiltInAttributeKey.heading);
|
||||
expect(node?.attributes.heading, BuiltInAttributeKey.h3);
|
||||
} else if (item.name == 'Bulleted list') {
|
||||
} else if (itemName == 'Bulleted list') {
|
||||
expect(node?.subtype, BuiltInAttributeKey.bulletedList);
|
||||
} else if (item.name == 'Checkbox') {
|
||||
} else if (itemName == 'Checkbox') {
|
||||
expect(node?.subtype, BuiltInAttributeKey.checkbox);
|
||||
expect(node?.attributes.check, false);
|
||||
} else if (itemName == 'Quote') {
|
||||
expect(node?.subtype, BuiltInAttributeKey.quote);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user