Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: emoji shortcut feature #4111

Closed
wants to merge 10 commits into from
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_shortcut/emoji_shortcut_builder.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:collection/collection.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';

const arrowKeys = [
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.arrowLeft,
LogicalKeyboardKey.arrowDown,
LogicalKeyboardKey.arrowUp,
];

// Keyboard keys to type "halo"
const haloKeys = [
LogicalKeyboardKey.keyH,
LogicalKeyboardKey.keyA,
LogicalKeyboardKey.keyL,
LogicalKeyboardKey.keyO,
];

// Keyboard keys to type "imp"
const impKeys = [
LogicalKeyboardKey.keyI,
LogicalKeyboardKey.keyM,
LogicalKeyboardKey.keyP,
];

// Keyboard keys to type "robot"
const robotKeys = [
LogicalKeyboardKey.keyR,
LogicalKeyboardKey.keyO,
LogicalKeyboardKey.keyB,
LogicalKeyboardKey.keyO,
LogicalKeyboardKey.keyT,
];

// Keyboard keys to type "kenya"
const kenyaKeys = [
LogicalKeyboardKey.shift,
LogicalKeyboardKey.keyK,
LogicalKeyboardKey.keyE,
LogicalKeyboardKey.keyN,
LogicalKeyboardKey.keyY,
LogicalKeyboardKey.keyA,
];

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

group('Insert Emoji', () {
testWidgets('smiling face with halo', (tester) async {
await insertEmoji(tester, '😇', haloKeys, []);
});

testWidgets('imp', (tester) async {
await insertEmoji(tester, '🦐', impKeys, []);
});

testWidgets('robot', (tester) async {
await insertEmoji(tester, '🤖', robotKeys, []);
});

testWidgets('kenya', (tester) async {
await insertEmoji(tester, '🇰🇪', kenyaKeys, []);
});
});

group('Insert Emoji using arrow keys', () {
testWidgets('smiling face with halo via arrow keys', (tester) async {
await insertEmoji(
tester,
'😇',
haloKeys.slice(0, haloKeys.length - 2),
arrowKeys,
);
});

testWidgets('imp via arrow keys', (tester) async {
await insertEmoji(
tester,
'🦐',
impKeys.slice(0, impKeys.length - 1),
arrowKeys,
);
});

testWidgets('robot via arrow keys', (tester) async {
await insertEmoji(
tester,
'🤖',
robotKeys.slice(0, robotKeys.length - 2),
arrowKeys,
);
});

testWidgets('kenya via arrow keys', (tester) async {
await insertEmoji(
tester,
'🇰🇪',
kenyaKeys.slice(0, robotKeys.length - 2),
arrowKeys,
);
});
});
}

Future<void> insertEmoji(
WidgetTester tester,
String expected,
List<LogicalKeyboardKey> emojiKeys,
List<LogicalKeyboardKey> arrowKeys,
) async {
await tester.initializeAppFlowy();

await tester.tapGoButton();

tester.expectToSeeHomePage();

await tester.createNewPageWithName(
name: 'Test $expected ${arrowKeys.isEmpty ? "" : " (keyboard) "}',
layout: ViewLayoutPB.Document,
openAfterCreated: true,
);

await tester.editor.tapLineOfEditorAt(0);

// Determine whether the emoji picker hasn't been opened
expect(find.byType(EmojiShortcutPickerView), findsNothing);

// Press ':' to open the menu
await tester.ime.insertText(':');

// Determine whether the shortcut works and the emoji picker is opened
expect(find.byType(EmojiShortcutPickerView), findsOneWidget);

// Perform specific keyboard events to find and insert emoji
await FlowyTestKeyboard.simulateKeyDownEvent(tester: tester, [
// Type emoji text
...emojiKeys,

// Press arrow keyboard combination eg: [RIGHT, DOWN, LEFT, UP]
...arrowKeys,

// Press ENTER to insert the emoji and replace text
LogicalKeyboardKey.enter,
]);

// Check if typed text is replaced by emoji
expect(
tester.editor.getCurrentEditorState().document.last!.delta!.toPlainText(),
expected,
);

// Determine whether the emoji picker is closed
expect(find.byType(EmojiShortcutPickerView), findsNothing);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'document_with_toggle_list_test.dart' as document_with_toggle_list_test;
import 'edit_document_test.dart' as document_edit_test;
import 'document_inline_page_reference_test.dart'
as document_inline_page_reference_test;
import 'document_emoji_shortcut_test.dart' as document_with_emoji_shortcut;

void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Expand All @@ -38,4 +39,5 @@ void startTesting() {
document_option_action_test.main();
document_with_image_block_test.main();
document_inline_page_reference_test.main();
document_with_emoji_shortcut.main();
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
style: styleCustomizer.selectionMenuStyleBuilder(),
),

// emoji shortcut command
emojiShortcutCommand(context),

...standardCharacterShortcutEvents
..removeWhere(
(element) => element == slashCommand,
Expand Down
Loading
Loading