mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: open emoji selection menu with keyboard short (#4133)
* feat: Implement emoji shortcut event (#2038) * test: emoji shortcut integration test (#2038) * test: Fixed testcase for emoji_shortcut_test (#2038) * fix: remove _showEmojiPickerMenu (#4133) * fix: change local variables with underscore --------- Co-authored-by: jazima <jazim.a.29@gmail.com>
This commit is contained in:
parent
d690ca2751
commit
e6aa57275a
@ -0,0 +1,41 @@
|
||||
import 'dart:io';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor/src/editor/editor_component/service/editor.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'util/keyboard.dart';
|
||||
import 'util/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
// May be better to move this to an existing test but unsure what it fits with
|
||||
group('Keyboard shortcuts related to emojis', () {
|
||||
testWidgets('cmd/ctrl+alt+e shortcut opens the emoji picker',
|
||||
(tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapGoButton();
|
||||
|
||||
final Finder editor = find.byType(AppFlowyEditor);
|
||||
await tester.tap(editor);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(EmojiSelectionMenu), findsNothing);
|
||||
|
||||
await FlowyTestKeyboard.simulateKeyDownEvent(
|
||||
[
|
||||
Platform.isMacOS
|
||||
? LogicalKeyboardKey.meta
|
||||
: LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.alt,
|
||||
LogicalKeyboardKey.keyE,
|
||||
],
|
||||
tester: tester,
|
||||
);
|
||||
|
||||
expect(find.byType(EmojiSelectionMenu), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
@ -23,6 +23,7 @@ import 'share_markdown_test.dart' as share_markdown_test;
|
||||
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
|
||||
import 'switch_folder_test.dart' as switch_folder_test;
|
||||
import 'tabs_test.dart' as tabs_test;
|
||||
import 'emoji_shortcut_test.dart' as emoji_shortcut_test;
|
||||
// import 'auth/supabase_auth_test.dart' as supabase_auth_test_runner;
|
||||
|
||||
/// The main task runner for all integration tests in AppFlowy.
|
||||
@ -69,6 +70,7 @@ Future<void> main() async {
|
||||
|
||||
// Others
|
||||
hotkeys_test.main();
|
||||
emoji_shortcut_test.main();
|
||||
|
||||
// Appearance integration test
|
||||
appearance_test_runner.main();
|
||||
|
@ -32,6 +32,7 @@ final List<CommandShortcutEvent> commandShortcutEvents = [
|
||||
customCutCommand,
|
||||
...customTextAlignCommands,
|
||||
...standardCommandShortcutEvents,
|
||||
emojiShortcutEvent,
|
||||
];
|
||||
|
||||
final List<CommandShortcutEvent> defaultCommandShortcutEvents = [
|
||||
@ -93,6 +94,7 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
customCutCommand,
|
||||
...customTextAlignCommands,
|
||||
...standardCommandShortcutEvents,
|
||||
emojiShortcutEvent,
|
||||
..._buildFindAndReplaceCommands(),
|
||||
];
|
||||
|
||||
|
@ -17,10 +17,12 @@ SelectionMenuItem emojiMenuItem = SelectionMenuItem(
|
||||
keywords: ['emoji'],
|
||||
handler: (editorState, menuService, context) {
|
||||
final container = Overlay.of(context);
|
||||
menuService.dismiss();
|
||||
showEmojiPickerMenu(
|
||||
container,
|
||||
editorState,
|
||||
menuService,
|
||||
menuService.alignment,
|
||||
menuService.offset,
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -28,12 +30,9 @@ SelectionMenuItem emojiMenuItem = SelectionMenuItem(
|
||||
void showEmojiPickerMenu(
|
||||
OverlayState container,
|
||||
EditorState editorState,
|
||||
SelectionMenuService menuService,
|
||||
Alignment alignment,
|
||||
Offset offset,
|
||||
) {
|
||||
menuService.dismiss();
|
||||
|
||||
final alignment = menuService.alignment;
|
||||
final offset = menuService.offset;
|
||||
final top = alignment == Alignment.topLeft ? offset.dy : null;
|
||||
final bottom = alignment == Alignment.bottomLeft ? offset.dy : null;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
export 'emoji_menu_item.dart';
|
||||
export 'emoji_shortcut_event.dart';
|
||||
export 'src/emji_picker_config.dart';
|
||||
export 'src/emoji_picker.dart';
|
||||
export 'src/emoji_picker_builder.dart';
|
||||
|
@ -0,0 +1,86 @@
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
|
||||
|
||||
final CommandShortcutEvent emojiShortcutEvent = CommandShortcutEvent(
|
||||
key: 'show emoji picker',
|
||||
command: 'ctrl+alt+e',
|
||||
macOSCommand: 'cmd+alt+e',
|
||||
handler: _emojiShortcutHandler,
|
||||
);
|
||||
|
||||
CommandShortcutEventHandler _emojiShortcutHandler = (editorState) {
|
||||
final selection = editorState.selection;
|
||||
if (selection == null) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
final context = editorState.getNodeAtPath(selection.start.path)?.context;
|
||||
if (context == null) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
final container = Overlay.of(context);
|
||||
|
||||
Alignment alignment = Alignment.topLeft;
|
||||
Offset offset = Offset.zero;
|
||||
|
||||
final selectionService = editorState.service.selectionService;
|
||||
final selectionRects = selectionService.selectionRects;
|
||||
if (selectionRects.isEmpty) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
final rect = selectionRects.first;
|
||||
|
||||
// Calculate the offset and alignment
|
||||
// Don't like these values being hardcoded but unsure how to grab the
|
||||
// values dynamically to match the /emoji command.
|
||||
const menuHeight = 200.0;
|
||||
const menuOffset = Offset(10, 10); // Tried (0, 10) but that looked off
|
||||
|
||||
final editorOffset =
|
||||
editorState.renderBox?.localToGlobal(Offset.zero) ?? Offset.zero;
|
||||
final editorHeight = editorState.renderBox!.size.height;
|
||||
final editorWidth = editorState.renderBox!.size.width;
|
||||
|
||||
// show below default
|
||||
alignment = Alignment.topLeft;
|
||||
final bottomRight = rect.bottomRight;
|
||||
final topRight = rect.topRight;
|
||||
var newOffset = bottomRight + menuOffset;
|
||||
offset = Offset(
|
||||
newOffset.dx,
|
||||
newOffset.dy,
|
||||
);
|
||||
|
||||
// show above
|
||||
if (newOffset.dy + menuHeight >= editorOffset.dy + editorHeight) {
|
||||
offset = topRight - menuOffset;
|
||||
alignment = Alignment.bottomLeft;
|
||||
|
||||
offset = Offset(
|
||||
newOffset.dx,
|
||||
MediaQuery.of(context).size.height - newOffset.dy,
|
||||
);
|
||||
}
|
||||
|
||||
// show on left
|
||||
if (offset.dx - editorOffset.dx > editorWidth / 2) {
|
||||
alignment = _alignment == Alignment.topLeft
|
||||
? Alignment.topRight
|
||||
: Alignment.bottomRight;
|
||||
|
||||
offset = Offset(
|
||||
editorWidth - offset.dx + editorOffset.dx,
|
||||
offset.dy,
|
||||
);
|
||||
}
|
||||
|
||||
showEmojiPickerMenu(
|
||||
container,
|
||||
editorState,
|
||||
alignment,
|
||||
offset,
|
||||
);
|
||||
|
||||
return KeyEventResult.handled;
|
||||
};
|
Loading…
Reference in New Issue
Block a user