2025-03-26 13:24:16 +08:00
|
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
2025-04-02 14:15:14 +08:00
|
|
|
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
2025-03-26 13:24:16 +08:00
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
import 'package:universal_platform/universal_platform.dart';
|
|
|
|
|
|
|
|
import 'emoji_menu.dart';
|
|
|
|
|
2025-04-02 14:15:14 +08:00
|
|
|
const _emojiCharacter = ':';
|
|
|
|
final _letterRegExp = RegExp(r'^[a-zA-Z]$');
|
2025-03-26 13:24:16 +08:00
|
|
|
|
|
|
|
CharacterShortcutEvent emojiCommand(BuildContext context) =>
|
|
|
|
CharacterShortcutEvent(
|
|
|
|
key: 'Opens Emoji Menu',
|
2025-04-02 14:15:14 +08:00
|
|
|
character: '',
|
|
|
|
regExp: _letterRegExp,
|
|
|
|
handler: (editorState) async {
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
handlerWithCharacter: (editorState, character) {
|
|
|
|
emojiMenuService = EmojiMenu(
|
2025-03-26 13:24:16 +08:00
|
|
|
context: context,
|
|
|
|
editorState: editorState,
|
|
|
|
);
|
2025-04-02 14:15:14 +08:00
|
|
|
return emojiCommandHandler(editorState, context, character);
|
2025-03-26 13:24:16 +08:00
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
EmojiMenuService? emojiMenuService;
|
|
|
|
|
|
|
|
Future<bool> emojiCommandHandler(
|
|
|
|
EditorState editorState,
|
|
|
|
BuildContext context,
|
2025-04-02 14:15:14 +08:00
|
|
|
String character,
|
2025-03-26 13:24:16 +08:00
|
|
|
) async {
|
|
|
|
final selection = editorState.selection;
|
|
|
|
|
|
|
|
if (UniversalPlatform.isMobile || selection == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!selection.isCollapsed) {
|
|
|
|
await editorState.deleteSelection(selection);
|
|
|
|
}
|
|
|
|
|
2025-04-02 14:15:14 +08:00
|
|
|
final node = editorState.getNodeAtPath(selection.end.path);
|
|
|
|
final delta = node?.delta;
|
|
|
|
if (node == null ||
|
|
|
|
delta == null ||
|
|
|
|
delta.isEmpty ||
|
|
|
|
node.type == CodeBlockKeys.type) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection.end.offset > 0) {
|
|
|
|
final plain = delta.toPlainText();
|
|
|
|
|
|
|
|
final previousCharacter = plain[selection.end.offset - 1];
|
|
|
|
if (previousCharacter != _emojiCharacter) return false;
|
|
|
|
if (!context.mounted) return false;
|
|
|
|
|
|
|
|
await editorState.insertTextAtPosition(
|
|
|
|
character,
|
|
|
|
position: selection.start,
|
|
|
|
);
|
|
|
|
|
|
|
|
emojiMenuService?.show(character);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2025-03-26 13:24:16 +08:00
|
|
|
}
|