Преглед на файлове

feat: emoji picker improvement (#3591)

Yijing Huang преди 1 година
родител
ревизия
eb20c7c117
променени са 35 файла, в които са добавени 302 реда и са изтрити 4606 реда
  1. 1 1
      frontend/appflowy_flutter/integration_test/util/database_test_op.dart
  2. 1 2
      frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/row_banner.dart
  3. 1 0
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart
  4. 1 2
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart
  5. 0 4
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/emoji_picker.dart
  6. 0 165
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/config.dart
  7. 0 338
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/emoji_picker.dart
  8. 2 2
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart
  9. 3 12
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/emoji_popover.dart
  10. 0 1
      frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/plugins.dart
  11. 1 11
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/emoji_menu_item.dart
  12. 6 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart
  13. 68 75
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/default_emoji_picker_view.dart
  14. 94 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emji_picker_config.dart
  15. 0 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_lists.dart
  16. 52 50
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_picker.dart
  17. 2 2
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_picker_builder.dart
  18. 4 4
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_view_state.dart
  19. 34 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/flowy_emoji_picker_config.dart
  20. 21 23
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/models/emoji_category_models.dart
  21. 0 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/models/emoji_model.dart
  22. 0 0
      frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/models/recent_emoji_model.dart
  23. 0 4
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/emoji_picker.dart
  24. 0 169
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/config.dart
  25. 0 321
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/default_emoji_picker_view.dart
  26. 0 3223
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/emoji_lists.dart
  27. 0 18
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/emoji_picker_builder.dart
  28. 0 21
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/emoji_view_state.dart
  29. 0 91
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/models/category_models.dart
  30. 0 32
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/models/emoji_model.dart
  31. 0 30
      frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/models/recent_emoji_model.dart
  32. 2 2
      frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/dandelion.dart
  33. 1 1
      frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/lavender.dart
  34. 5 2
      frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scroll_bar.dart
  35. 3 0
      frontend/resources/translations/en.json

+ 1 - 1
frontend/appflowy_flutter/integration_test/util/database_test_op.dart

@@ -54,7 +54,7 @@ import 'package:appflowy/plugins/database_view/widgets/row/row_document.dart';
 import 'package:appflowy/plugins/database_view/widgets/row/row_property.dart';
 import 'package:appflowy/plugins/database_view/widgets/setting/database_setting.dart';
 import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
-import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_menu_item.dart';
 import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
 import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
 import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';

+ 1 - 2
frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/row_banner.dart

@@ -5,8 +5,7 @@ import 'package:appflowy/plugins/database_view/application/field/field_info.dart
 import 'package:appflowy/plugins/database_view/application/row/row_banner_bloc.dart';
 import 'package:appflowy/plugins/database_view/application/row/row_controller.dart';
 import 'package:appflowy/plugins/database_view/widgets/row/row_action.dart';
-import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_picker.dart';
-import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';

+ 1 - 0
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart

@@ -8,6 +8,7 @@ import 'package:appflowy/plugins/inline_actions/inline_actions_command.dart';
 import 'package:appflowy/plugins/inline_actions/inline_actions_service.dart';
 import 'package:appflowy/workspace/application/appearance.dart';
 import 'package:appflowy/workspace/application/settings/shortcuts/settings_shortcuts_service.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
 import 'package:appflowy_editor/appflowy_editor.dart';
 import 'package:collection/collection.dart';
 import 'package:flowy_infra/theme_extension.dart';

+ 1 - 2
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart

@@ -1,5 +1,4 @@
-import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_picker.dart';
-import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flutter/material.dart';

+ 0 - 4
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/emoji_picker.dart

@@ -1,4 +0,0 @@
-export 'src/config.dart';
-export 'src/emoji_picker.dart';
-export 'src/emoji_picker_builder.dart';
-export 'src/models/emoji_model.dart';

+ 0 - 165
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/config.dart

@@ -1,165 +0,0 @@
-import 'dart:math';
-
-import 'package:flutter/material.dart';
-
-import 'models/category_models.dart';
-import 'emoji_picker.dart';
-
-/// Config for customizations
-class Config {
-  /// Constructor
-  const Config({
-    this.columns = 7,
-    this.emojiSizeMax = 32.0,
-    this.verticalSpacing = 0,
-    this.horizontalSpacing = 0,
-    this.initCategory = Category.RECENT,
-    this.bgColor = const Color(0xFFEBEFF2),
-    this.indicatorColor = Colors.blue,
-    this.iconColor = Colors.grey,
-    this.iconColorSelected = Colors.blue,
-    this.progressIndicatorColor = Colors.blue,
-    this.backspaceColor = Colors.blue,
-    this.showRecentsTab = true,
-    this.recentsLimit = 28,
-    this.noRecentsText = 'No Recents',
-    this.noRecentsStyle = const TextStyle(fontSize: 20, color: Colors.black26),
-    this.tabIndicatorAnimDuration = kTabScrollDuration,
-    this.categoryIcons = const CategoryIcons(),
-    this.buttonMode = ButtonMode.MATERIAL,
-  });
-
-  /// Number of emojis per row
-  final int columns;
-
-  /// Width and height the emoji will be maximal displayed
-  /// Can be smaller due to screen size and amount of columns
-  final double emojiSizeMax;
-
-  /// Vertical spacing between emojis
-  final double verticalSpacing;
-
-  /// Horizontal spacing between emojis
-  final double horizontalSpacing;
-
-  /// The initial [Category] that will be selected
-  /// This [Category] will have its button in the bottombar darkened
-  final Category initCategory;
-
-  /// The background color of the Widget
-  final Color bgColor;
-
-  /// The color of the category indicator
-  final Color indicatorColor;
-
-  /// The color of the category icons
-  final Color iconColor;
-
-  /// The color of the category icon when selected
-  final Color iconColorSelected;
-
-  /// The color of the loading indicator during initialization
-  final Color progressIndicatorColor;
-
-  /// The color of the backspace icon button
-  final Color backspaceColor;
-
-  /// Show extra tab with recently used emoji
-  final bool showRecentsTab;
-
-  /// Limit of recently used emoji that will be saved
-  final int recentsLimit;
-
-  /// The text to be displayed if no recent emojis to display
-  final String noRecentsText;
-
-  /// The text style for [noRecentsText]
-  final TextStyle noRecentsStyle;
-
-  /// Duration of tab indicator to animate to next category
-  final Duration tabIndicatorAnimDuration;
-
-  /// Determines the icon to display for each [Category]
-  final CategoryIcons categoryIcons;
-
-  /// Change between Material and Cupertino button style
-  final ButtonMode buttonMode;
-
-  /// Get Emoji size based on properties and screen width
-  double getEmojiSize(double width) {
-    final maxSize = width / columns;
-    return min(maxSize, emojiSizeMax);
-  }
-
-  /// Returns the icon for the category
-  IconData getIconForCategory(Category category) {
-    switch (category) {
-      case Category.RECENT:
-        return categoryIcons.recentIcon;
-      case Category.SMILEYS:
-        return categoryIcons.smileyIcon;
-      case Category.ANIMALS:
-        return categoryIcons.animalIcon;
-      case Category.FOODS:
-        return categoryIcons.foodIcon;
-      case Category.TRAVEL:
-        return categoryIcons.travelIcon;
-      case Category.ACTIVITIES:
-        return categoryIcons.activityIcon;
-      case Category.OBJECTS:
-        return categoryIcons.objectIcon;
-      case Category.SYMBOLS:
-        return categoryIcons.symbolIcon;
-      case Category.FLAGS:
-        return categoryIcons.flagIcon;
-      case Category.SEARCH:
-        return categoryIcons.searchIcon;
-      default:
-        throw Exception('Unsupported Category');
-    }
-  }
-
-  @override
-  bool operator ==(other) {
-    return (other is Config) &&
-        other.columns == columns &&
-        other.emojiSizeMax == emojiSizeMax &&
-        other.verticalSpacing == verticalSpacing &&
-        other.horizontalSpacing == horizontalSpacing &&
-        other.initCategory == initCategory &&
-        other.bgColor == bgColor &&
-        other.indicatorColor == indicatorColor &&
-        other.iconColor == iconColor &&
-        other.iconColorSelected == iconColorSelected &&
-        other.progressIndicatorColor == progressIndicatorColor &&
-        other.backspaceColor == backspaceColor &&
-        other.showRecentsTab == showRecentsTab &&
-        other.recentsLimit == recentsLimit &&
-        other.noRecentsText == noRecentsText &&
-        other.noRecentsStyle == noRecentsStyle &&
-        other.tabIndicatorAnimDuration == tabIndicatorAnimDuration &&
-        other.categoryIcons == categoryIcons &&
-        other.buttonMode == buttonMode;
-  }
-
-  @override
-  int get hashCode =>
-      columns.hashCode ^
-      emojiSizeMax.hashCode ^
-      verticalSpacing.hashCode ^
-      horizontalSpacing.hashCode ^
-      initCategory.hashCode ^
-      bgColor.hashCode ^
-      indicatorColor.hashCode ^
-      iconColor.hashCode ^
-      iconColorSelected.hashCode ^
-      progressIndicatorColor.hashCode ^
-      backspaceColor.hashCode ^
-      showRecentsTab.hashCode ^
-      recentsLimit.hashCode ^
-      noRecentsText.hashCode ^
-      noRecentsStyle.hashCode ^
-      tabIndicatorAnimDuration.hashCode ^
-      categoryIcons.hashCode ^
-      buttonMode.hashCode;
-}

+ 0 - 338
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/emoji_picker.dart

@@ -1,338 +0,0 @@
-// ignore_for_file: constant_identifier_names
-
-import 'dart:convert';
-import 'dart:io';
-import 'dart:math';
-
-import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
-import 'package:shared_preferences/shared_preferences.dart';
-import 'models/category_models.dart';
-import 'config.dart';
-import 'default_emoji_picker_view.dart';
-import 'models/emoji_model.dart';
-import 'emoji_lists.dart' as emoji_list;
-import 'emoji_view_state.dart';
-import 'models/recent_emoji_model.dart';
-
-/// All the possible categories that [Emoji] can be put into
-///
-/// All [Category] are shown in the category bar
-enum Category {
-  /// Searched emojis
-  SEARCH,
-
-  /// Recent emojis
-  RECENT,
-
-  /// Smiley emojis
-  SMILEYS,
-
-  /// Animal emojis
-  ANIMALS,
-
-  /// Food emojis
-  FOODS,
-
-  /// Activity emojis
-  ACTIVITIES,
-
-  /// Travel emojis
-  TRAVEL,
-
-  /// Objects emojis
-  OBJECTS,
-
-  /// Sumbol emojis
-  SYMBOLS,
-
-  /// Flag emojis
-  FLAGS,
-}
-
-/// Enum to alter the keyboard button style
-enum ButtonMode {
-  /// Android button style - gives the button a splash color with ripple effect
-  MATERIAL,
-
-  /// iOS button style - gives the button a fade out effect when pressed
-  CUPERTINO
-}
-
-/// Callback function for when emoji is selected
-///
-/// The function returns the selected [Emoji] as well
-/// as the [Category] from which it originated
-typedef OnEmojiSelected = void Function(Category category, Emoji emoji);
-
-/// Callback function for backspace button
-typedef OnBackspacePressed = void Function();
-
-/// Callback function for custom view
-typedef EmojiViewBuilder = Widget Function(Config config, EmojiViewState state);
-
-/// The Emoji Keyboard widget
-///
-/// This widget displays a grid of [Emoji] sorted by [Category]
-/// which the user can horizontally scroll through.
-///
-/// There is also a bottombar which displays all the possible [Category]
-/// and allow the user to quickly switch to that [Category]
-class EmojiPicker extends StatefulWidget {
-  /// EmojiPicker for flutter
-  const EmojiPicker({
-    Key? key,
-    required this.onEmojiSelected,
-    this.onBackspacePressed,
-    this.config = const Config(),
-    this.customWidget,
-  }) : super(key: key);
-
-  /// Custom widget
-  final EmojiViewBuilder? customWidget;
-
-  /// The function called when the emoji is selected
-  final OnEmojiSelected onEmojiSelected;
-
-  /// The function called when backspace button is pressed
-  final OnBackspacePressed? onBackspacePressed;
-
-  /// Config for customizations
-  final Config config;
-
-  @override
-  EmojiPickerState createState() => EmojiPickerState();
-}
-
-class EmojiPickerState extends State<EmojiPicker> {
-  static const platform = MethodChannel('emoji_picker_flutter');
-
-  List<CategoryEmoji> categoryEmoji = List.empty(growable: true);
-  List<RecentEmoji> recentEmoji = List.empty(growable: true);
-  late Future<void> updateEmojiFuture;
-
-  // Prevent emojis to be reloaded with every build
-  bool loaded = false;
-
-  @override
-  void initState() {
-    super.initState();
-    updateEmojiFuture = _updateEmojis();
-  }
-
-  @override
-  void didUpdateWidget(covariant EmojiPicker oldWidget) {
-    if (oldWidget.config != widget.config) {
-      // Config changed - rebuild EmojiPickerView completely
-      loaded = false;
-      updateEmojiFuture = _updateEmojis();
-    }
-    super.didUpdateWidget(oldWidget);
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    if (!loaded) {
-      // Load emojis
-      updateEmojiFuture.then(
-        (value) => WidgetsBinding.instance.addPostFrameCallback((_) {
-          if (!mounted) return;
-          setState(() {
-            loaded = true;
-          });
-        }),
-      );
-
-      // Show loading indicator
-      return const Center(child: CircularProgressIndicator());
-    }
-    if (widget.config.showRecentsTab) {
-      categoryEmoji[0].emoji =
-          recentEmoji.map((e) => e.emoji).toList().cast<Emoji>();
-    }
-
-    final state = EmojiViewState(
-      categoryEmoji,
-      _getOnEmojiListener(),
-      widget.onBackspacePressed,
-    );
-
-    // Build
-    return widget.customWidget == null
-        ? DefaultEmojiPickerView(widget.config, state)
-        : widget.customWidget!(widget.config, state);
-  }
-
-  // Add recent emoji handling to tap listener
-  OnEmojiSelected _getOnEmojiListener() {
-    return (category, emoji) {
-      if (widget.config.showRecentsTab) {
-        _addEmojiToRecentlyUsed(emoji).then((value) {
-          if (category != Category.RECENT && mounted) {
-            setState(() {
-              // rebuild to update recent emoji tab
-              // when it is not current tab
-            });
-          }
-        });
-      }
-      widget.onEmojiSelected(category, emoji);
-    };
-  }
-
-  // Initialize emoji data
-  Future<void> _updateEmojis() async {
-    categoryEmoji.clear();
-    if (widget.config.showRecentsTab) {
-      recentEmoji = await _getRecentEmojis();
-      final List<Emoji> recentEmojiMap =
-          recentEmoji.map((e) => e.emoji).toList().cast<Emoji>();
-      categoryEmoji.add(CategoryEmoji(Category.RECENT, recentEmojiMap));
-    }
-    categoryEmoji.addAll([
-      CategoryEmoji(
-        Category.SMILEYS,
-        await _getAvailableEmojis(emoji_list.smileys, title: 'smileys'),
-      ),
-      CategoryEmoji(
-        Category.ANIMALS,
-        await _getAvailableEmojis(emoji_list.animals, title: 'animals'),
-      ),
-      CategoryEmoji(
-        Category.FOODS,
-        await _getAvailableEmojis(emoji_list.foods, title: 'foods'),
-      ),
-      CategoryEmoji(
-        Category.ACTIVITIES,
-        await _getAvailableEmojis(
-          emoji_list.activities,
-          title: 'activities',
-        ),
-      ),
-      CategoryEmoji(
-        Category.TRAVEL,
-        await _getAvailableEmojis(emoji_list.travel, title: 'travel'),
-      ),
-      CategoryEmoji(
-        Category.OBJECTS,
-        await _getAvailableEmojis(emoji_list.objects, title: 'objects'),
-      ),
-      CategoryEmoji(
-        Category.SYMBOLS,
-        await _getAvailableEmojis(emoji_list.symbols, title: 'symbols'),
-      ),
-      CategoryEmoji(
-        Category.FLAGS,
-        await _getAvailableEmojis(emoji_list.flags, title: 'flags'),
-      )
-    ]);
-  }
-
-  // Get available emoji for given category title
-  Future<List<Emoji>> _getAvailableEmojis(
-    Map<String, String> map, {
-    required String title,
-  }) async {
-    Map<String, String>? newMap;
-
-    // Get Emojis cached locally if available
-    newMap = await _restoreFilteredEmojis(title);
-
-    if (newMap == null) {
-      // Check if emoji is available on this platform
-      newMap = await _getPlatformAvailableEmoji(map);
-      // Save available Emojis to local storage for faster loading next time
-      if (newMap != null) {
-        await _cacheFilteredEmojis(title, newMap);
-      }
-    }
-
-    // Map to Emoji Object
-    return newMap!.entries
-        .map<Emoji>((entry) => Emoji(entry.key, entry.value))
-        .toList();
-  }
-
-  // Check if emoji is available on current platform
-  Future<Map<String, String>?> _getPlatformAvailableEmoji(
-    Map<String, String> emoji,
-  ) async {
-    if (Platform.isAndroid) {
-      Map<String, String>? filtered = {};
-      const delimiter = '|';
-      try {
-        final entries = emoji.values.join(delimiter);
-        final keys = emoji.keys.join(delimiter);
-        final result = (await platform.invokeMethod<String>(
-          'checkAvailability',
-          {'emojiKeys': keys, 'emojiEntries': entries},
-        )) as String;
-        final resultKeys = result.split(delimiter);
-        for (var i = 0; i < resultKeys.length; i++) {
-          filtered[resultKeys[i]] = emoji[resultKeys[i]]!;
-        }
-      } on PlatformException catch (_) {
-        filtered = null;
-      }
-      return filtered;
-    } else {
-      return emoji;
-    }
-  }
-
-  // Restore locally cached emoji
-  Future<Map<String, String>?> _restoreFilteredEmojis(String title) async {
-    final prefs = await SharedPreferences.getInstance();
-    final emojiJson = prefs.getString(title);
-    if (emojiJson == null) {
-      return null;
-    }
-    final emojis =
-        Map<String, String>.from(jsonDecode(emojiJson) as Map<String, dynamic>);
-    return emojis;
-  }
-
-  // Stores filtered emoji locally for faster access next time
-  Future<void> _cacheFilteredEmojis(
-    String title,
-    Map<String, String> emojis,
-  ) async {
-    final prefs = await SharedPreferences.getInstance();
-    final emojiJson = jsonEncode(emojis);
-    prefs.setString(title, emojiJson);
-  }
-
-  // Returns list of recently used emoji from cache
-  Future<List<RecentEmoji>> _getRecentEmojis() async {
-    final prefs = await SharedPreferences.getInstance();
-    final emojiJson = prefs.getString('recent');
-    if (emojiJson == null) {
-      return [];
-    }
-    final json = jsonDecode(emojiJson) as List<dynamic>;
-    return json.map<RecentEmoji>(RecentEmoji.fromJson).toList();
-  }
-
-  // Add an emoji to recently used list or increase its counter
-  Future<void> _addEmojiToRecentlyUsed(Emoji emoji) async {
-    final prefs = await SharedPreferences.getInstance();
-    final recentEmojiIndex =
-        recentEmoji.indexWhere((element) => element.emoji.emoji == emoji.emoji);
-    if (recentEmojiIndex != -1) {
-      // Already exist in recent list
-      // Just update counter
-      recentEmoji[recentEmojiIndex].counter++;
-    } else {
-      recentEmoji.add(RecentEmoji(emoji, 1));
-    }
-    // Sort by counter desc
-    recentEmoji.sort((a, b) => b.counter - a.counter);
-    // Limit entries to recentsLimit
-    recentEmoji = recentEmoji.sublist(
-      0,
-      min(widget.config.recentsLimit, recentEmoji.length),
-    );
-    // save locally
-    prefs.setString('recent', jsonEncode(recentEmoji));
-  }
-}

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart

@@ -2,7 +2,7 @@ import 'dart:io';
 
 import 'package:appflowy/generated/flowy_svgs.g.dart';
 import 'package:appflowy/generated/locale_keys.g.dart';
-import 'package:appflowy/workspace/presentation/widgets/emoji_picker/emoji_picker.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
 import 'package:appflowy_editor/appflowy_editor.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:easy_localization/easy_localization.dart';
@@ -257,7 +257,7 @@ class _DocumentHeaderToolbarState extends State<DocumentHeaderToolbar> {
           controller: _popoverController,
           offset: const Offset(0, 8),
           direction: PopoverDirection.bottomWithCenterAligned,
-          constraints: BoxConstraints.loose(const Size(320, 380)),
+          constraints: BoxConstraints.loose(const Size(300, 250)),
           child: FlowyButton(
             leftIconSize: const Size.square(18),
             useIntrinsicWidth: true,

+ 3 - 12
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/emoji_popover.dart

@@ -1,6 +1,6 @@
 import 'package:appflowy/generated/flowy_svgs.g.dart';
 import 'package:appflowy/generated/locale_keys.g.dart';
-import 'package:appflowy/workspace/presentation/widgets/emoji_picker/emoji_picker.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
 import 'package:appflowy_editor/appflowy_editor.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
@@ -8,6 +8,7 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
 
 import 'package:flutter/material.dart';
 
+/// Add icon menu in Header
 class EmojiPopover extends StatefulWidget {
   final EditorState editorState;
   final Node node;
@@ -46,17 +47,7 @@ class _EmojiPopoverState extends State<EmojiPopover> {
             onEmojiSelected: (category, emoji) {
               widget.onEmojiChanged(emoji);
             },
-            config: Config(
-              columns: 8,
-              emojiSizeMax: 28,
-              bgColor: Colors.transparent,
-              iconColor: Theme.of(context).iconTheme.color!,
-              iconColorSelected: Theme.of(context).colorScheme.onSurface,
-              selectedHoverColor: Theme.of(context).colorScheme.secondary,
-              progressIndicatorColor: Theme.of(context).iconTheme.color!,
-              buttonMode: ButtonMode.CUPERTINO,
-              initCategory: Category.RECENT,
-            ),
+            config: buildFlowyEmojiPickerConfig(context),
           ),
         ),
       ],

+ 0 - 1
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/plugins.dart

@@ -12,7 +12,6 @@ export 'copy_and_paste/custom_paste_command.dart';
 export 'database/database_view_block_component.dart';
 export 'database/inline_database_menu_item.dart';
 export 'database/referenced_database_menu_item.dart';
-export 'emoji_picker/emoji_menu_item.dart';
 export 'extensions/flowy_tint_extension.dart';
 export 'find_and_replace/find_and_replace_menu.dart';
 export 'font/customize_font_toolbar_item.dart';

+ 1 - 11
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/emoji_menu_item.dart

@@ -113,17 +113,7 @@ class _EmojiSelectionMenuState extends State<EmojiSelectionMenu> {
   Widget build(BuildContext context) {
     return EmojiPicker(
       onEmojiSelected: (category, emoji) => widget.onSubmitted(emoji),
-      config: const Config(
-        columns: 7,
-        emojiSizeMax: 28,
-        bgColor: Colors.transparent,
-        iconColor: Colors.grey,
-        iconColorSelected: Color(0xff333333),
-        indicatorColor: Color(0xff333333),
-        progressIndicatorColor: Color(0xff333333),
-        buttonMode: ButtonMode.CUPERTINO,
-        initCategory: Category.RECENT,
-      ),
+      config: buildFlowyEmojiPickerConfig(context),
     );
   }
 }

+ 6 - 0
frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart

@@ -0,0 +1,6 @@
+export 'emoji_menu_item.dart';
+export 'src/emji_picker_config.dart';
+export 'src/emoji_picker.dart';
+export 'src/emoji_picker_builder.dart';
+export 'src/flowy_emoji_picker_config.dart';
+export 'src/models/emoji_model.dart';

+ 68 - 75
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/default_emoji_picker_view.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/default_emoji_picker_view.dart

@@ -1,16 +1,19 @@
-import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
+import 'package:flowy_infra_ui/style_widget/hover.dart';
 import 'package:flutter/material.dart';
-import 'config.dart';
+import 'emji_picker_config.dart';
 import 'emoji_picker.dart';
 import 'emoji_picker_builder.dart';
 import 'emoji_view_state.dart';
-import 'models/category_models.dart';
+import 'models/emoji_category_models.dart';
 import 'models/emoji_model.dart';
 
 class DefaultEmojiPickerView extends EmojiPickerBuilder {
-  const DefaultEmojiPickerView(Config config, EmojiViewState state, {Key? key})
-      : super(config, state, key: key);
+  const DefaultEmojiPickerView(
+    EmojiPickerConfig config,
+    EmojiViewState state, {
+    Key? key,
+  }) : super(config, state, key: key);
 
   @override
   DefaultEmojiPickerViewState createState() => DefaultEmojiPickerViewState();
@@ -22,11 +25,12 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
   TabController? _tabController;
   final TextEditingController _emojiController = TextEditingController();
   final FocusNode _emojiFocusNode = FocusNode();
-  CategoryEmoji searchEmojiList = CategoryEmoji(Category.SEARCH, <Emoji>[]);
+  EmojiCategoryGroup searchEmojiList =
+      EmojiCategoryGroup(EmojiCategory.SEARCH, <Emoji>[]);
 
   @override
   void initState() {
-    var initCategory = widget.state.categoryEmoji.indexWhere(
+    var initCategory = widget.state.emojiCategoryGroupList.indexWhere(
       (element) => element.category == widget.config.initCategory,
     );
     if (initCategory == -1) {
@@ -34,7 +38,7 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
     }
     _tabController = TabController(
       initialIndex: initCategory,
-      length: widget.state.categoryEmoji.length,
+      length: widget.state.emojiCategoryGroupList.length,
       vsync: this,
     );
     _pageController = PageController(initialPage: initCategory);
@@ -49,7 +53,7 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
         );
       } else {
         searchEmojiList.emoji.clear();
-        for (final element in widget.state.categoryEmoji) {
+        for (final element in widget.state.emojiCategoryGroupList) {
           searchEmojiList.emoji.addAll(
             element.emoji.where((item) {
               return item.name.toLowerCase().contains(query);
@@ -66,6 +70,8 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
   void dispose() {
     _emojiController.dispose();
     _emojiFocusNode.dispose();
+    _pageController?.dispose();
+    _tabController?.dispose();
     super.dispose();
   }
 
@@ -100,56 +106,50 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
     return LayoutBuilder(
       builder: (context, constraints) {
         final emojiSize = widget.config.getEmojiSize(constraints.maxWidth);
+        final style = Theme.of(context);
 
         return Container(
           color: widget.config.bgColor,
-          padding: const EdgeInsets.all(5.0),
+          padding: const EdgeInsets.all(4),
           child: Column(
             children: [
+              const VSpace(4),
+              // search bar
               SizedBox(
-                height: 25.0,
+                height: 32.0,
                 child: TextField(
                   controller: _emojiController,
                   focusNode: _emojiFocusNode,
                   autofocus: true,
-                  style: const TextStyle(fontSize: 14.0),
-                  cursorWidth: 1.0,
-                  cursorColor: Colors.black,
+                  style: style.textTheme.bodyMedium,
+                  cursorColor: style.textTheme.bodyMedium?.color,
                   decoration: InputDecoration(
-                    contentPadding: const EdgeInsets.symmetric(horizontal: 5.0),
-                    hintText: "Search emoji",
-                    focusedBorder: OutlineInputBorder(
-                      borderRadius: BorderRadius.circular(4.0),
-                      borderSide: const BorderSide(),
-                      gapPadding: 0.0,
-                    ),
-                    border: OutlineInputBorder(
-                      borderRadius: BorderRadius.circular(4.0),
-                      borderSide: const BorderSide(),
-                      gapPadding: 0.0,
-                    ),
-                    filled: true,
-                    fillColor: Colors.white,
-                    hoverColor: Colors.white,
+                    contentPadding: const EdgeInsets.all(8),
+                    hintText: widget.config.searchHintText,
+                    hintStyle: widget.config.serachHintTextStyle,
+                    enabledBorder: widget.config.serachBarEnableBorder,
+                    focusedBorder: widget.config.serachBarFocusedBorder,
                   ),
                 ),
               ),
+              const VSpace(4),
               Row(
                 children: [
                   Expanded(
                     child: TabBar(
-                      labelColor: widget.config.iconColorSelected,
-                      unselectedLabelColor: widget.config.iconColor,
+                      labelColor: widget.config.selectedCategoryIconColor,
+                      unselectedLabelColor: widget.config.categoryIconColor,
                       controller: isEmojiSearching()
                           ? TabController(length: 1, vsync: this)
                           : _tabController,
                       labelPadding: EdgeInsets.zero,
-                      indicatorColor: widget.config.indicatorColor,
-                      padding: const EdgeInsets.symmetric(vertical: 5.0),
+                      indicatorColor:
+                          widget.config.selectedCategoryIconBackgroundColor,
+                      padding: const EdgeInsets.symmetric(vertical: 4.0),
                       indicator: BoxDecoration(
                         border: Border.all(color: Colors.transparent),
                         borderRadius: BorderRadius.circular(4.0),
-                        color: Colors.grey.withOpacity(0.5),
+                        color: style.colorScheme.secondary,
                       ),
                       onTap: (index) {
                         _pageController!.animateToPage(
@@ -159,8 +159,8 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
                         );
                       },
                       tabs: isEmojiSearching()
-                          ? [_buildCategory(Category.SEARCH, emojiSize)]
-                          : widget.state.categoryEmoji
+                          ? [_buildCategory(EmojiCategory.SEARCH, emojiSize)]
+                          : widget.state.emojiCategoryGroupList
                               .asMap()
                               .entries
                               .map<Widget>(
@@ -179,20 +179,15 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
                 child: PageView.builder(
                   itemCount: searchEmojiList.emoji.isNotEmpty
                       ? 1
-                      : widget.state.categoryEmoji.length,
+                      : widget.state.emojiCategoryGroupList.length,
                   controller: _pageController,
                   physics: const NeverScrollableScrollPhysics(),
-                  // onPageChanged: (index) {
-                  //   _tabController!.animateTo(
-                  //     index,
-                  //     duration: widget.config.tabIndicatorAnimDuration,
-                  //   );
-                  // },
                   itemBuilder: (context, index) {
-                    final CategoryEmoji catEmoji = isEmojiSearching()
-                        ? searchEmojiList
-                        : widget.state.categoryEmoji[index];
-                    return _buildPage(emojiSize, catEmoji);
+                    final EmojiCategoryGroup emojiCategoryGroup =
+                        isEmojiSearching()
+                            ? searchEmojiList
+                            : widget.state.emojiCategoryGroupList[index];
+                    return _buildPage(emojiSize, emojiCategoryGroup);
                   },
                 ),
               ),
@@ -203,7 +198,7 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
     );
   }
 
-  Widget _buildCategory(Category category, double categorySize) {
+  Widget _buildCategory(EmojiCategory category, double categorySize) {
     return Tab(
       height: categorySize,
       child: Icon(
@@ -229,39 +224,39 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
     );
   }
 
-  Widget _buildPage(double emojiSize, CategoryEmoji categoryEmoji) {
+  Widget _buildPage(double emojiSize, EmojiCategoryGroup emojiCategoryGroup) {
     // Display notice if recent has no entries yet
     final scrollController = ScrollController();
 
-    if (categoryEmoji.category == Category.RECENT &&
-        categoryEmoji.emoji.isEmpty) {
+    if (emojiCategoryGroup.category == EmojiCategory.RECENT &&
+        emojiCategoryGroup.emoji.isEmpty) {
       return _buildNoRecent();
-    } else if (categoryEmoji.category == Category.SEARCH &&
-        categoryEmoji.emoji.isEmpty) {
-      return const Center(child: Text("No Emoji Found"));
+    } else if (emojiCategoryGroup.category == EmojiCategory.SEARCH &&
+        emojiCategoryGroup.emoji.isEmpty) {
+      return Center(child: Text(widget.config.noEmojiFoundText));
     }
     // Build page normally
     return ScrollbarListStack(
       axis: Axis.vertical,
       controller: scrollController,
       barSize: 4.0,
-      scrollbarPadding: const EdgeInsets.symmetric(horizontal: 5.0),
-      handleColor: const Color(0xffDFE0E0),
-      trackColor: const Color(0xffDFE0E0),
+      scrollbarPadding: const EdgeInsets.symmetric(horizontal: 4.0),
+      handleColor: widget.config.scrollBarHandleColor,
+      showTrack: true,
       child: ScrollConfiguration(
         behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
         child: GridView.builder(
           controller: scrollController,
           padding: const EdgeInsets.all(0),
           gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
-            crossAxisCount: widget.config.columns,
+            crossAxisCount: widget.config.emojiNumberPerRow,
             mainAxisSpacing: widget.config.verticalSpacing,
             crossAxisSpacing: widget.config.horizontalSpacing,
           ),
-          itemCount: categoryEmoji.emoji.length,
+          itemCount: emojiCategoryGroup.emoji.length,
           itemBuilder: (context, index) {
-            final item = categoryEmoji.emoji[index];
-            return _buildEmoji(emojiSize, categoryEmoji, item);
+            final item = emojiCategoryGroup.emoji[index];
+            return _buildEmoji(emojiSize, emojiCategoryGroup, item);
           },
           cacheExtent: 10,
         ),
@@ -271,21 +266,20 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
 
   Widget _buildEmoji(
     double emojiSize,
-    CategoryEmoji categoryEmoji,
+    EmojiCategoryGroup emojiCategoryGroup,
     Emoji emoji,
   ) {
     return _buildButtonWidget(
       onPressed: () {
-        widget.state.onEmojiSelected(categoryEmoji.category, emoji);
+        widget.state.onEmojiSelected(emojiCategoryGroup.category, emoji);
       },
-      child: FittedBox(
-        fit: BoxFit.scaleDown,
-        child: Text(
-          emoji.emoji,
-          textScaleFactor: 1.0,
-          style: TextStyle(
-            fontSize: emojiSize,
-            backgroundColor: Colors.transparent,
+      child: FlowyHover(
+        child: FittedBox(
+          child: Text(
+            emoji.emoji,
+            style: TextStyle(
+              fontSize: emojiSize,
+            ),
           ),
         ),
       ),
@@ -294,10 +288,9 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
 
   Widget _buildNoRecent() {
     return Center(
-      child: FlowyText.regular(
+      child: Text(
         widget.config.noRecentsText,
-        color: Theme.of(context).colorScheme.tertiary.withAlpha(77),
-        fontSize: widget.config.noRecentsStyle.fontSize,
+        style: widget.config.noRecentsStyle,
         textAlign: TextAlign.center,
       ),
     );

+ 94 - 0
frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emji_picker_config.dart

@@ -0,0 +1,94 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+import 'models/emoji_category_models.dart';
+import 'emoji_picker.dart';
+
+part 'emji_picker_config.freezed.dart';
+
+@freezed
+class EmojiPickerConfig with _$EmojiPickerConfig {
+  // private empty constructor is used to make method work in freezed
+  // https://pub.dev/packages/freezed#adding-getters-and-methods-to-our-models
+  const EmojiPickerConfig._();
+  const factory EmojiPickerConfig({
+    @Default(7) int emojiNumberPerRow,
+    // The maximum size(width and height) of emoji
+    // It also depaneds on the screen size and emojiNumberPerRow
+    @Default(32) double emojiSizeMax,
+    // Vertical spacing between emojis
+    @Default(0) double verticalSpacing,
+    // Horizontal spacing between emojis
+    @Default(0) double horizontalSpacing,
+    // The initial [EmojiCategory] that will be selected
+    @Default(EmojiCategory.RECENT) EmojiCategory initCategory,
+    // The background color of the Widget
+    @Default(Color(0xFFEBEFF2)) Color? bgColor,
+    // The color of the category icons
+    @Default(Colors.grey) Color? categoryIconColor,
+    // The color of the category icon when selected
+    @Default(Colors.blue) Color? selectedCategoryIconColor,
+    // The color of the category indicator
+    @Default(Colors.blue) Color? selectedCategoryIconBackgroundColor,
+    // The color of the loading indicator during initialization
+    @Default(Colors.blue) Color? progressIndicatorColor,
+    // The color of the backspace icon button
+    @Default(Colors.blue) Color? backspaceColor,
+    // Show extra tab with recently used emoji
+    @Default(true) bool showRecentsTab,
+    // Limit of recently used emoji that will be saved
+    @Default(28) int recentsLimit,
+    @Default('Search emoji') String searchHintText,
+    TextStyle? serachHintTextStyle,
+    InputBorder? serachBarEnableBorder,
+    InputBorder? serachBarFocusedBorder,
+    // The text to be displayed if no recent emojis to display
+    @Default('No recent emoji') String noRecentsText,
+    TextStyle? noRecentsStyle,
+    // The text to be displayed if no emoji found
+    @Default('No emoji found') String noEmojiFoundText,
+    Color? scrollBarHandleColor,
+    // Duration of tab indicator to animate to next category
+    @Default(kTabScrollDuration) Duration tabIndicatorAnimDuration,
+    // Determines the icon to display for each [EmojiCategory]
+    @Default(EmojiCategoryIcons()) EmojiCategoryIcons emojiCategoryIcons,
+    // Change between Material and Cupertino button style
+    @Default(ButtonMode.MATERIAL) ButtonMode buttonMode,
+  }) = _EmojiPickerConfig;
+
+  /// Get Emoji size based on properties and screen width
+  double getEmojiSize(double width) {
+    final maxSize = width / emojiNumberPerRow;
+    return min(maxSize, emojiSizeMax);
+  }
+
+  /// Returns the icon for the category
+  IconData getIconForCategory(EmojiCategory category) {
+    switch (category) {
+      case EmojiCategory.RECENT:
+        return emojiCategoryIcons.recentIcon;
+      case EmojiCategory.SMILEYS:
+        return emojiCategoryIcons.smileyIcon;
+      case EmojiCategory.ANIMALS:
+        return emojiCategoryIcons.animalIcon;
+      case EmojiCategory.FOODS:
+        return emojiCategoryIcons.foodIcon;
+      case EmojiCategory.TRAVEL:
+        return emojiCategoryIcons.travelIcon;
+      case EmojiCategory.ACTIVITIES:
+        return emojiCategoryIcons.activityIcon;
+      case EmojiCategory.OBJECTS:
+        return emojiCategoryIcons.objectIcon;
+      case EmojiCategory.SYMBOLS:
+        return emojiCategoryIcons.symbolIcon;
+      case EmojiCategory.FLAGS:
+        return emojiCategoryIcons.flagIcon;
+      case EmojiCategory.SEARCH:
+        return emojiCategoryIcons.searchIcon;
+      default:
+        throw Exception('Unsupported EmojiCategory');
+    }
+  }
+}

+ 0 - 0
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/emoji_lists.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_lists.dart


+ 52 - 50
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/emoji_picker.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_picker.dart

@@ -7,18 +7,16 @@ import 'dart:math';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:shared_preferences/shared_preferences.dart';
-import 'models/category_models.dart';
-import 'config.dart';
+import 'models/emoji_category_models.dart';
+import 'emji_picker_config.dart';
 import 'default_emoji_picker_view.dart';
 import 'models/emoji_model.dart';
 import 'emoji_lists.dart' as emoji_list;
 import 'emoji_view_state.dart';
 import 'models/recent_emoji_model.dart';
 
-/// All the possible categories that [Emoji] can be put into
-///
-/// All [Category] are shown in the category bar
-enum Category {
+/// The emoji category shown on the category tab
+enum EmojiCategory {
   /// Searched emojis
   SEARCH,
 
@@ -62,29 +60,32 @@ enum ButtonMode {
 /// Callback function for when emoji is selected
 ///
 /// The function returns the selected [Emoji] as well
-/// as the [Category] from which it originated
-typedef OnEmojiSelected = void Function(Category category, Emoji emoji);
+/// as the [EmojiCategory] from which it originated
+typedef OnEmojiSelected = void Function(EmojiCategory category, Emoji emoji);
 
 /// Callback function for backspace button
 typedef OnBackspacePressed = void Function();
 
 /// Callback function for custom view
-typedef EmojiViewBuilder = Widget Function(Config config, EmojiViewState state);
+typedef EmojiViewBuilder = Widget Function(
+  EmojiPickerConfig config,
+  EmojiViewState state,
+);
 
 /// The Emoji Keyboard widget
 ///
-/// This widget displays a grid of [Emoji] sorted by [Category]
+/// This widget displays a grid of [Emoji] sorted by [EmojiCategory]
 /// which the user can horizontally scroll through.
 ///
-/// There is also a bottombar which displays all the possible [Category]
-/// and allow the user to quickly switch to that [Category]
+/// There is also a bottombar which displays all the possible [EmojiCategory]
+/// and allow the user to quickly switch to that [EmojiCategory]
 class EmojiPicker extends StatefulWidget {
   /// EmojiPicker for flutter
   const EmojiPicker({
     Key? key,
     required this.onEmojiSelected,
     this.onBackspacePressed,
-    this.config = const Config(),
+    this.config = const EmojiPickerConfig(),
     this.customWidget,
   }) : super(key: key);
 
@@ -98,7 +99,7 @@ class EmojiPicker extends StatefulWidget {
   final OnBackspacePressed? onBackspacePressed;
 
   /// Config for customizations
-  final Config config;
+  final EmojiPickerConfig config;
 
   @override
   EmojiPickerState createState() => EmojiPickerState();
@@ -107,8 +108,8 @@ class EmojiPicker extends StatefulWidget {
 class EmojiPickerState extends State<EmojiPicker> {
   static const platform = MethodChannel('emoji_picker_flutter');
 
-  List<CategoryEmoji> categoryEmoji = List.empty(growable: true);
-  List<RecentEmoji> recentEmoji = List.empty(growable: true);
+  List<EmojiCategoryGroup> emojiCategoryGroupList = List.empty(growable: true);
+  List<RecentEmoji> recentEmojiList = List.empty(growable: true);
   late Future<void> updateEmojiFuture;
 
   // Prevent emojis to be reloaded with every build
@@ -123,7 +124,7 @@ class EmojiPickerState extends State<EmojiPicker> {
   @override
   void didUpdateWidget(covariant EmojiPicker oldWidget) {
     if (oldWidget.config != widget.config) {
-      // Config changed - rebuild EmojiPickerView completely
+      // EmojiPickerConfig changed - rebuild EmojiPickerView completely
       loaded = false;
       updateEmojiFuture = _updateEmojis();
     }
@@ -147,12 +148,12 @@ class EmojiPickerState extends State<EmojiPicker> {
       return const Center(child: CircularProgressIndicator());
     }
     if (widget.config.showRecentsTab) {
-      categoryEmoji[0].emoji =
-          recentEmoji.map((e) => e.emoji).toList().cast<Emoji>();
+      emojiCategoryGroupList[0].emoji =
+          recentEmojiList.map((e) => e.emoji).toList().cast<Emoji>();
     }
 
     final state = EmojiViewState(
-      categoryEmoji,
+      emojiCategoryGroupList,
       _getOnEmojiListener(),
       widget.onBackspacePressed,
     );
@@ -168,7 +169,7 @@ class EmojiPickerState extends State<EmojiPicker> {
     return (category, emoji) {
       if (widget.config.showRecentsTab) {
         _addEmojiToRecentlyUsed(emoji).then((value) {
-          if (category != Category.RECENT && mounted) {
+          if (category != EmojiCategory.RECENT && mounted) {
             setState(() {
               // rebuild to update recent emoji tab
               // when it is not current tab
@@ -182,47 +183,48 @@ class EmojiPickerState extends State<EmojiPicker> {
 
   // Initialize emoji data
   Future<void> _updateEmojis() async {
-    categoryEmoji.clear();
+    emojiCategoryGroupList.clear();
     if (widget.config.showRecentsTab) {
-      recentEmoji = await _getRecentEmojis();
+      recentEmojiList = await _getRecentEmojis();
       final List<Emoji> recentEmojiMap =
-          recentEmoji.map((e) => e.emoji).toList().cast<Emoji>();
-      categoryEmoji.add(CategoryEmoji(Category.RECENT, recentEmojiMap));
+          recentEmojiList.map((e) => e.emoji).toList().cast<Emoji>();
+      emojiCategoryGroupList
+          .add(EmojiCategoryGroup(EmojiCategory.RECENT, recentEmojiMap));
     }
-    categoryEmoji.addAll([
-      CategoryEmoji(
-        Category.SMILEYS,
+    emojiCategoryGroupList.addAll([
+      EmojiCategoryGroup(
+        EmojiCategory.SMILEYS,
         await _getAvailableEmojis(emoji_list.smileys, title: 'smileys'),
       ),
-      CategoryEmoji(
-        Category.ANIMALS,
+      EmojiCategoryGroup(
+        EmojiCategory.ANIMALS,
         await _getAvailableEmojis(emoji_list.animals, title: 'animals'),
       ),
-      CategoryEmoji(
-        Category.FOODS,
+      EmojiCategoryGroup(
+        EmojiCategory.FOODS,
         await _getAvailableEmojis(emoji_list.foods, title: 'foods'),
       ),
-      CategoryEmoji(
-        Category.ACTIVITIES,
+      EmojiCategoryGroup(
+        EmojiCategory.ACTIVITIES,
         await _getAvailableEmojis(
           emoji_list.activities,
           title: 'activities',
         ),
       ),
-      CategoryEmoji(
-        Category.TRAVEL,
+      EmojiCategoryGroup(
+        EmojiCategory.TRAVEL,
         await _getAvailableEmojis(emoji_list.travel, title: 'travel'),
       ),
-      CategoryEmoji(
-        Category.OBJECTS,
+      EmojiCategoryGroup(
+        EmojiCategory.OBJECTS,
         await _getAvailableEmojis(emoji_list.objects, title: 'objects'),
       ),
-      CategoryEmoji(
-        Category.SYMBOLS,
+      EmojiCategoryGroup(
+        EmojiCategory.SYMBOLS,
         await _getAvailableEmojis(emoji_list.symbols, title: 'symbols'),
       ),
-      CategoryEmoji(
-        Category.FLAGS,
+      EmojiCategoryGroup(
+        EmojiCategory.FLAGS,
         await _getAvailableEmojis(emoji_list.flags, title: 'flags'),
       )
     ]);
@@ -316,23 +318,23 @@ class EmojiPickerState extends State<EmojiPicker> {
   // Add an emoji to recently used list or increase its counter
   Future<void> _addEmojiToRecentlyUsed(Emoji emoji) async {
     final prefs = await SharedPreferences.getInstance();
-    final recentEmojiIndex =
-        recentEmoji.indexWhere((element) => element.emoji.emoji == emoji.emoji);
+    final recentEmojiIndex = recentEmojiList
+        .indexWhere((element) => element.emoji.emoji == emoji.emoji);
     if (recentEmojiIndex != -1) {
       // Already exist in recent list
       // Just update counter
-      recentEmoji[recentEmojiIndex].counter++;
+      recentEmojiList[recentEmojiIndex].counter++;
     } else {
-      recentEmoji.add(RecentEmoji(emoji, 1));
+      recentEmojiList.add(RecentEmoji(emoji, 1));
     }
     // Sort by counter desc
-    recentEmoji.sort((a, b) => b.counter - a.counter);
+    recentEmojiList.sort((a, b) => b.counter - a.counter);
     // Limit entries to recentsLimit
-    recentEmoji = recentEmoji.sublist(
+    recentEmojiList = recentEmojiList.sublist(
       0,
-      min(widget.config.recentsLimit, recentEmoji.length),
+      min(widget.config.recentsLimit, recentEmojiList.length),
     );
     // save locally
-    prefs.setString('recent', jsonEncode(recentEmoji));
+    prefs.setString('recent', jsonEncode(recentEmojiList));
   }
 }

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/emoji_picker_builder.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_picker_builder.dart

@@ -1,6 +1,6 @@
 import 'package:flutter/material.dart';
 
-import 'config.dart';
+import 'emji_picker_config.dart';
 import 'emoji_view_state.dart';
 
 /// Template class for custom implementation
@@ -11,7 +11,7 @@ abstract class EmojiPickerBuilder extends StatefulWidget {
       : super(key: key);
 
   /// Config for customizations
-  final Config config;
+  final EmojiPickerConfig config;
 
   /// State that holds current emoji data
   final EmojiViewState state;

+ 4 - 4
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/emoji_view_state.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/emoji_view_state.dart

@@ -1,17 +1,17 @@
-import 'models/category_models.dart';
+import 'models/emoji_category_models.dart';
 import 'emoji_picker.dart';
 
 /// State that holds current emoji data
 class EmojiViewState {
   /// Constructor
   EmojiViewState(
-    this.categoryEmoji,
+    this.emojiCategoryGroupList,
     this.onEmojiSelected,
     this.onBackspacePressed,
   );
 
-  /// List of all category including their emoji
-  final List<CategoryEmoji> categoryEmoji;
+  /// List of all categories including their emojis
+  final List<EmojiCategoryGroup> emojiCategoryGroupList;
 
   /// Callback when pressed on emoji
   final OnEmojiSelected onEmojiSelected;

+ 34 - 0
frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/flowy_emoji_picker_config.dart

@@ -0,0 +1,34 @@
+import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/src/emji_picker_config.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+EmojiPickerConfig buildFlowyEmojiPickerConfig(BuildContext context) {
+  final style = Theme.of(context);
+  return EmojiPickerConfig(
+    bgColor: style.cardColor,
+    categoryIconColor: style.iconTheme.color,
+    selectedCategoryIconColor: style.colorScheme.onSurface,
+    selectedCategoryIconBackgroundColor: style.colorScheme.primary,
+    progressIndicatorColor: style.colorScheme.primary,
+    backspaceColor: style.colorScheme.primary,
+    searchHintText: LocaleKeys.emoji_search.tr(),
+    serachHintTextStyle: style.textTheme.bodyMedium?.copyWith(
+      color: style.hintColor,
+    ),
+    serachBarEnableBorder: OutlineInputBorder(
+      borderRadius: BorderRadius.circular(4),
+      borderSide: BorderSide(color: style.dividerColor),
+    ),
+    serachBarFocusedBorder: OutlineInputBorder(
+      borderRadius: BorderRadius.circular(4),
+      borderSide: BorderSide(
+        color: style.colorScheme.primary,
+      ),
+    ),
+    noRecentsText: LocaleKeys.emoji_noRecent.tr(),
+    noRecentsStyle: style.textTheme.bodyMedium,
+    noEmojiFoundText: LocaleKeys.emoji_noEmojiFound.tr(),
+    scrollBarHandleColor: style.colorScheme.onBackground,
+  );
+}

+ 21 - 23
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/models/category_models.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/models/emoji_category_models.dart

@@ -3,13 +3,11 @@ import 'package:flutter/material.dart';
 import 'emoji_model.dart';
 import '../emoji_picker.dart';
 
-/// Container for Category and their emoji
-class CategoryEmoji {
-  /// Constructor
-  CategoryEmoji(this.category, this.emoji);
+/// EmojiCategory with its emojis
+class EmojiCategoryGroup {
+  EmojiCategoryGroup(this.category, this.emoji);
 
-  /// Category instance
-  final Category category;
+  final EmojiCategory category;
 
   /// List of emoji of this category
   List<Emoji> emoji;
@@ -20,10 +18,10 @@ class CategoryEmoji {
   }
 }
 
-/// Class that defines the icon representing a [Category]
-class CategoryIcon {
+/// Class that defines the icon representing a [EmojiCategory]
+class EmojiCategoryIcon {
   /// Icon of Category
-  const CategoryIcon({
+  const EmojiCategoryIcon({
     required this.icon,
     this.color = const Color(0xffd3d3d3),
     this.selectedColor = const Color(0xffb2b2b2),
@@ -39,14 +37,14 @@ class CategoryIcon {
   final Color selectedColor;
 }
 
-/// Class used to define all the [CategoryIcon] shown for each [Category]
+/// Class used to define all the [EmojiCategoryIcon] shown for each [EmojiCategory]
 ///
 /// This allows the keyboard to be personalized by changing icons shown.
-/// If a [CategoryIcon] is set as null or not defined during initialization,
+/// If a [EmojiCategoryIcon] is set as null or not defined during initialization,
 /// the default icons will be used instead
-class CategoryIcons {
+class EmojiCategoryIcons {
   /// Constructor
-  const CategoryIcons({
+  const EmojiCategoryIcons({
     this.recentIcon = Icons.access_time,
     this.smileyIcon = Icons.tag_faces,
     this.animalIcon = Icons.pets,
@@ -59,33 +57,33 @@ class CategoryIcons {
     this.searchIcon = Icons.search,
   });
 
-  /// Icon for [Category.RECENT]
+  /// Icon for [EmojiCategory.RECENT]
   final IconData recentIcon;
 
-  /// Icon for [Category.SMILEYS]
+  /// Icon for [EmojiCategory.SMILEYS]
   final IconData smileyIcon;
 
-  /// Icon for [Category.ANIMALS]
+  /// Icon for [EmojiCategory.ANIMALS]
   final IconData animalIcon;
 
-  /// Icon for [Category.FOODS]
+  /// Icon for [EmojiCategory.FOODS]
   final IconData foodIcon;
 
-  /// Icon for [Category.ACTIVITIES]
+  /// Icon for [EmojiCategory.ACTIVITIES]
   final IconData activityIcon;
 
-  /// Icon for [Category.TRAVEL]
+  /// Icon for [EmojiCategory.TRAVEL]
   final IconData travelIcon;
 
-  /// Icon for [Category.OBJECTS]
+  /// Icon for [EmojiCategory.OBJECTS]
   final IconData objectIcon;
 
-  /// Icon for [Category.SYMBOLS]
+  /// Icon for [EmojiCategory.SYMBOLS]
   final IconData symbolIcon;
 
-  /// Icon for [Category.FLAGS]
+  /// Icon for [EmojiCategory.FLAGS]
   final IconData flagIcon;
 
-  /// Icon for [Category.SEARCH]
+  /// Icon for [EmojiCategory.SEARCH]
   final IconData searchIcon;
 }

+ 0 - 0
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/models/emoji_model.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/models/emoji_model.dart


+ 0 - 0
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/emoji_picker/src/models/recent_emoji_model.dart → frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/emoji_picker/src/models/recent_emoji_model.dart


+ 0 - 4
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/emoji_picker.dart

@@ -1,4 +0,0 @@
-export 'src/config.dart';
-export 'src/models/emoji_model.dart';
-export 'src/emoji_picker.dart';
-export 'src/emoji_picker_builder.dart';

+ 0 - 169
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/config.dart

@@ -1,169 +0,0 @@
-import 'dart:math';
-
-import 'package:flutter/material.dart';
-
-import 'models/category_models.dart';
-import 'emoji_picker.dart';
-
-/// Config for customizations
-class Config {
-  /// Constructor
-  const Config({
-    this.columns = 7,
-    this.emojiSizeMax = 32.0,
-    this.verticalSpacing = 0,
-    this.horizontalSpacing = 0,
-    this.initCategory = Category.RECENT,
-    this.bgColor = const Color(0xFFEBEFF2),
-    this.indicatorColor = Colors.blue,
-    this.selectedHoverColor = Colors.grey,
-    this.iconColor = Colors.grey,
-    this.iconColorSelected = Colors.blue,
-    this.progressIndicatorColor = Colors.blue,
-    this.backspaceColor = Colors.blue,
-    this.showRecentsTab = true,
-    this.recentsLimit = 28,
-    this.noRecentsText = 'No Recents',
-    this.noRecentsStyle = const TextStyle(fontSize: 20, color: Colors.black26),
-    this.tabIndicatorAnimDuration = kTabScrollDuration,
-    this.categoryIcons = const CategoryIcons(),
-    this.buttonMode = ButtonMode.MATERIAL,
-  });
-
-  /// Number of emojis per row
-  final int columns;
-
-  /// Width and height the emoji will be maximal displayed
-  /// Can be smaller due to screen size and amount of columns
-  final double emojiSizeMax;
-
-  /// Vertical spacing between emojis
-  final double verticalSpacing;
-
-  /// Horizontal spacing between emojis
-  final double horizontalSpacing;
-
-  /// The initial [Category] that will be selected
-  /// This [Category] will have its button in the bottombar darkened
-  final Category initCategory;
-
-  /// The background color of the Widget
-  final Color bgColor;
-
-  /// The color of the category indicator
-  final Color indicatorColor;
-
-  /// The background color of the selected category
-  final Color selectedHoverColor;
-
-  /// The color of the category icons
-  final Color iconColor;
-
-  /// The color of the category icon when selected
-  final Color iconColorSelected;
-
-  /// The color of the loading indicator during initialization
-  final Color progressIndicatorColor;
-
-  /// The color of the backspace icon button
-  final Color backspaceColor;
-
-  /// Show extra tab with recently used emoji
-  final bool showRecentsTab;
-
-  /// Limit of recently used emoji that will be saved
-  final int recentsLimit;
-
-  /// The text to be displayed if no recent emojis to display
-  final String noRecentsText;
-
-  /// The text style for [noRecentsText]
-  final TextStyle noRecentsStyle;
-
-  /// Duration of tab indicator to animate to next category
-  final Duration tabIndicatorAnimDuration;
-
-  /// Determines the icon to display for each [Category]
-  final CategoryIcons categoryIcons;
-
-  /// Change between Material and Cupertino button style
-  final ButtonMode buttonMode;
-
-  /// Get Emoji size based on properties and screen width
-  double getEmojiSize(double width) {
-    final maxSize = width / columns;
-    return min(maxSize, emojiSizeMax);
-  }
-
-  /// Returns the icon for the category
-  IconData getIconForCategory(Category category) {
-    switch (category) {
-      case Category.RECENT:
-        return categoryIcons.recentIcon;
-      case Category.SMILEYS:
-        return categoryIcons.smileyIcon;
-      case Category.ANIMALS:
-        return categoryIcons.animalIcon;
-      case Category.FOODS:
-        return categoryIcons.foodIcon;
-      case Category.TRAVEL:
-        return categoryIcons.travelIcon;
-      case Category.ACTIVITIES:
-        return categoryIcons.activityIcon;
-      case Category.OBJECTS:
-        return categoryIcons.objectIcon;
-      case Category.SYMBOLS:
-        return categoryIcons.symbolIcon;
-      case Category.FLAGS:
-        return categoryIcons.flagIcon;
-      case Category.SEARCH:
-        return categoryIcons.searchIcon;
-      default:
-        throw Exception('Unsupported Category');
-    }
-  }
-
-  @override
-  bool operator ==(other) {
-    return (other is Config) &&
-        other.columns == columns &&
-        other.emojiSizeMax == emojiSizeMax &&
-        other.verticalSpacing == verticalSpacing &&
-        other.horizontalSpacing == horizontalSpacing &&
-        other.initCategory == initCategory &&
-        other.bgColor == bgColor &&
-        other.indicatorColor == indicatorColor &&
-        other.iconColor == iconColor &&
-        other.iconColorSelected == iconColorSelected &&
-        other.progressIndicatorColor == progressIndicatorColor &&
-        other.backspaceColor == backspaceColor &&
-        other.showRecentsTab == showRecentsTab &&
-        other.recentsLimit == recentsLimit &&
-        other.noRecentsText == noRecentsText &&
-        other.noRecentsStyle == noRecentsStyle &&
-        other.tabIndicatorAnimDuration == tabIndicatorAnimDuration &&
-        other.categoryIcons == categoryIcons &&
-        other.buttonMode == buttonMode;
-  }
-
-  @override
-  int get hashCode =>
-      columns.hashCode ^
-      emojiSizeMax.hashCode ^
-      verticalSpacing.hashCode ^
-      horizontalSpacing.hashCode ^
-      initCategory.hashCode ^
-      bgColor.hashCode ^
-      indicatorColor.hashCode ^
-      iconColor.hashCode ^
-      iconColorSelected.hashCode ^
-      progressIndicatorColor.hashCode ^
-      backspaceColor.hashCode ^
-      showRecentsTab.hashCode ^
-      recentsLimit.hashCode ^
-      noRecentsText.hashCode ^
-      noRecentsStyle.hashCode ^
-      tabIndicatorAnimDuration.hashCode ^
-      categoryIcons.hashCode ^
-      buttonMode.hashCode;
-}

+ 0 - 321
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/default_emoji_picker_view.dart

@@ -1,321 +0,0 @@
-import 'package:flowy_infra/size.dart';
-import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
-import 'package:flowy_infra_ui/widget/spacing.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/material.dart';
-
-import 'models/category_models.dart';
-import 'config.dart';
-import 'models/emoji_model.dart';
-import 'emoji_picker.dart';
-import 'emoji_picker_builder.dart';
-import 'emoji_view_state.dart';
-
-class DefaultEmojiPickerView extends EmojiPickerBuilder {
-  const DefaultEmojiPickerView(Config config, EmojiViewState state, {Key? key})
-      : super(config, state, key: key);
-
-  @override
-  DefaultEmojiPickerViewState createState() => DefaultEmojiPickerViewState();
-}
-
-class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
-    with TickerProviderStateMixin {
-  PageController? _pageController;
-  TabController? _tabController;
-  final TextEditingController _emojiController = TextEditingController();
-  final FocusNode _emojiFocusNode = FocusNode();
-  final CategoryEmoji _categoryEmoji =
-      CategoryEmoji(Category.SEARCH, List.empty(growable: true));
-  CategoryEmoji searchEmojiList = CategoryEmoji(Category.SEARCH, <Emoji>[]);
-
-  @override
-  void initState() {
-    var initCategory = widget.state.categoryEmoji.indexWhere(
-      (element) => element.category == widget.config.initCategory,
-    );
-    if (initCategory == -1) {
-      initCategory = 0;
-    }
-    _tabController = TabController(
-      initialIndex: initCategory,
-      length: widget.state.categoryEmoji.length,
-      vsync: this,
-    );
-    _pageController = PageController(initialPage: initCategory);
-    _emojiFocusNode.requestFocus();
-
-    _emojiController.addListener(() {
-      final String query = _emojiController.text.toLowerCase();
-      if (query.isEmpty) {
-        searchEmojiList.emoji.clear();
-        _pageController!.jumpToPage(
-          _tabController!.index,
-        );
-      } else {
-        searchEmojiList.emoji.clear();
-        for (final element in widget.state.categoryEmoji) {
-          searchEmojiList.emoji.addAll(
-            element.emoji.where((item) {
-              return item.name.toLowerCase().contains(query);
-            }).toList(),
-          );
-        }
-      }
-      setState(() {});
-    });
-    super.initState();
-  }
-
-  @override
-  void dispose() {
-    _emojiController.dispose();
-    _emojiFocusNode.dispose();
-    super.dispose();
-  }
-
-  Widget _buildBackspaceButton() {
-    if (widget.state.onBackspacePressed != null) {
-      return Material(
-        type: MaterialType.transparency,
-        child: IconButton(
-          padding: const EdgeInsets.only(bottom: 2),
-          icon: Icon(
-            Icons.backspace,
-            color: widget.config.backspaceColor,
-          ),
-          onPressed: () {
-            widget.state.onBackspacePressed!();
-          },
-        ),
-      );
-    }
-    return Container();
-  }
-
-  bool isEmojiSearching() {
-    final bool result =
-        searchEmojiList.emoji.isNotEmpty || _emojiController.text.isNotEmpty;
-
-    return result;
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return LayoutBuilder(
-      builder: (context, constraints) {
-        final emojiSize = widget.config.getEmojiSize(constraints.maxWidth);
-
-        return Container(
-          color: widget.config.bgColor,
-          padding: const EdgeInsets.all(4.0),
-          child: Column(
-            children: [
-              SizedBox(
-                height: 40,
-                child: TextField(
-                  controller: _emojiController,
-                  focusNode: _emojiFocusNode,
-                  autofocus: true,
-                  cursorWidth: 1.0,
-                  cursorColor: Theme.of(context).colorScheme.tertiary,
-                  style: Theme.of(context).textTheme.bodyMedium?.copyWith(
-                        fontSize: FontSizes.s16,
-                        fontWeight: FontWeight.w400,
-                      ),
-                  decoration: InputDecoration(
-                    contentPadding: const EdgeInsets.symmetric(horizontal: 10),
-                    hintText: "Search emoji",
-                    focusedBorder: OutlineInputBorder(
-                      borderSide: BorderSide(
-                        color: Theme.of(context).colorScheme.tertiary,
-                        width: 2,
-                      ),
-                    ),
-                    border: OutlineInputBorder(
-                      borderSide: BorderSide(
-                        color: Theme.of(context).colorScheme.tertiary,
-                      ),
-                    ),
-                    filled: true,
-                    fillColor: Colors.transparent,
-                    hoverColor: Colors.transparent,
-                  ),
-                ),
-              ),
-              const VSpace(6),
-              Row(
-                children: [
-                  Expanded(
-                    child: TabBar(
-                      labelColor: widget.config.iconColorSelected,
-                      unselectedLabelColor: widget.config.iconColor,
-                      controller: isEmojiSearching()
-                          ? TabController(length: 1, vsync: this)
-                          : _tabController,
-                      labelPadding: EdgeInsets.zero,
-                      indicatorColor: widget.config.indicatorColor,
-                      padding: const EdgeInsets.symmetric(vertical: 5.0),
-                      indicator: BoxDecoration(
-                        borderRadius: BorderRadius.circular(4.0),
-                        color: widget.config.selectedHoverColor,
-                      ),
-                      onTap: (index) {
-                        _pageController!.animateToPage(
-                          index,
-                          duration: widget.config.tabIndicatorAnimDuration,
-                          curve: Curves.ease,
-                        );
-                      },
-                      tabs: isEmojiSearching()
-                          ? [_buildCategory(Category.SEARCH, emojiSize)]
-                          : widget.state.categoryEmoji
-                              .asMap()
-                              .entries
-                              .map<Widget>(
-                                (item) => _buildCategory(
-                                  item.value.category,
-                                  emojiSize,
-                                ),
-                              )
-                              .toList(),
-                    ),
-                  ),
-                  _buildBackspaceButton(),
-                ],
-              ),
-              Flexible(
-                child: PageView.builder(
-                  itemCount: searchEmojiList.emoji.isNotEmpty
-                      ? 1
-                      : widget.state.categoryEmoji.length,
-                  controller: _pageController,
-                  physics: const NeverScrollableScrollPhysics(),
-                  // onPageChanged: (index) {
-                  //   _tabController!.animateTo(
-                  //     index,
-                  //     duration: widget.config.tabIndicatorAnimDuration,
-                  //   );
-                  // },
-                  itemBuilder: (context, index) {
-                    final CategoryEmoji catEmoji = isEmojiSearching()
-                        ? searchEmojiList
-                        : widget.state.categoryEmoji[index];
-                    return _buildPage(emojiSize, catEmoji);
-                  },
-                ),
-              ),
-            ],
-          ),
-        );
-      },
-    );
-  }
-
-  Widget _buildCategory(Category category, double categorySize) {
-    return Tab(
-      height: categorySize,
-      child: Icon(
-        widget.config.getIconForCategory(category),
-        size: categorySize / 1.3,
-      ),
-    );
-  }
-
-  Widget _buildButtonWidget({
-    required VoidCallback onPressed,
-    required Widget child,
-  }) {
-    if (widget.config.buttonMode == ButtonMode.MATERIAL) {
-      return TextButton(
-        onPressed: onPressed,
-        style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.zero)),
-        child: child,
-      );
-    }
-    return CupertinoButton(
-      padding: EdgeInsets.zero,
-      onPressed: onPressed,
-      child: child,
-    );
-  }
-
-  Widget _buildPage(double emojiSize, CategoryEmoji categoryEmoji) {
-    // Display notice if recent has no entries yet
-    final scrollController = ScrollController();
-
-    if (categoryEmoji.category == Category.RECENT &&
-        categoryEmoji.emoji.isEmpty) {
-      return _buildNoRecent();
-    } else if (categoryEmoji.category == Category.SEARCH &&
-        categoryEmoji.emoji.isEmpty) {
-      return const Center(child: Text("No Emoji Found"));
-    }
-    // Build page normally
-    return ScrollbarListStack(
-      axis: Axis.vertical,
-      controller: scrollController,
-      barSize: 4.0,
-      scrollbarPadding: const EdgeInsets.symmetric(horizontal: 5.0),
-      handleColor: const Color(0xffDFE0E0),
-      trackColor: const Color(0xffDFE0E0),
-      child: ScrollConfiguration(
-        behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
-        child: GridView.count(
-          scrollDirection: Axis.vertical,
-          physics: const ScrollPhysics(),
-          controller: scrollController,
-          shrinkWrap: true,
-          // primary: true,
-          padding: const EdgeInsets.all(0),
-          crossAxisCount: widget.config.columns,
-          mainAxisSpacing: widget.config.verticalSpacing,
-          crossAxisSpacing: widget.config.horizontalSpacing,
-          children: _categoryEmoji.emoji.isNotEmpty
-              ? _categoryEmoji.emoji
-                  .map<Widget>((e) => _buildEmoji(emojiSize, categoryEmoji, e))
-                  .toList()
-              : categoryEmoji.emoji
-                  .map<Widget>(
-                    (item) => _buildEmoji(emojiSize, categoryEmoji, item),
-                  )
-                  .toList(),
-        ),
-      ),
-    );
-  }
-
-  Widget _buildEmoji(
-    double emojiSize,
-    CategoryEmoji categoryEmoji,
-    Emoji emoji,
-  ) {
-    return _buildButtonWidget(
-      onPressed: () {
-        widget.state.onEmojiSelected(categoryEmoji.category, emoji);
-      },
-      child: FittedBox(
-        fit: BoxFit.scaleDown,
-        child: Text(
-          emoji.emoji,
-          textScaleFactor: 1.0,
-          style: TextStyle(
-            fontSize: emojiSize,
-            backgroundColor: Colors.transparent,
-            color: Theme.of(context).iconTheme.color,
-          ),
-        ),
-      ),
-    );
-  }
-
-  Widget _buildNoRecent() {
-    return Center(
-      child: Text(
-        widget.config.noRecentsText,
-        style: widget.config.noRecentsStyle,
-        textAlign: TextAlign.center,
-      ),
-    );
-  }
-}

+ 0 - 3223
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/emoji_lists.dart

@@ -1,3223 +0,0 @@
-// Copyright information
-// File originally from https://github.com/JeffG05/emoji_picker
-
-// import 'emoji.dart';
-
-// final List<Map<String, String>> temp = [smileys, animals, foods, activities, travel, objects, symbols, flags];
-
-// final List<Emoji> emojiSearchList = temp
-//     .map((element) {
-//       return element.entries.map<Emoji>((entry) => Emoji(entry.key, entry.value)).toList();
-//     })
-//     .toList()
-//     .first;
-
-/// Map of all possible emojis along with their names in [Category.SMILEYS]
-final Map<String, String> smileys = Map.fromIterables([
-  'Grinning Face',
-  'Grinning Face With Big Eyes',
-  'Grinning Face With Smiling Eyes',
-  'Beaming Face With Smiling Eyes',
-  'Grinning Squinting Face',
-  'Grinning Face With Sweat',
-  'Rolling on the Floor Laughing',
-  'Face With Tears of Joy',
-  'Slightly Smiling Face',
-  'Upside-Down Face',
-  'Winking Face',
-  'Smiling Face With Smiling Eyes',
-  'Smiling Face With Halo',
-  'Smiling Face With Hearts',
-  'Smiling Face With Heart-Eyes',
-  'Star-Struck',
-  'Face Blowing a Kiss',
-  'Kissing Face',
-  'Smiling Face',
-  'Kissing Face With Closed Eyes',
-  'Kissing Face With Smiling Eyes',
-  'Face Savoring Food',
-  'Face With Tongue',
-  'Winking Face With Tongue',
-  'Zany Face',
-  'Squinting Face With Tongue',
-  'Money-Mouth Face',
-  'Hugging Face',
-  'Face With Hand Over Mouth',
-  'Shushing Face',
-  'Thinking Face',
-  'Zipper-Mouth Face',
-  'Face With Raised Eyebrow',
-  'Neutral Face',
-  'Expressionless Face',
-  'Face Without Mouth',
-  'Smirking Face',
-  'Unamused Face',
-  'Face With Rolling Eyes',
-  'Grimacing Face',
-  'Lying Face',
-  'Relieved Face',
-  'Pensive Face',
-  'Sleepy Face',
-  'Drooling Face',
-  'Sleeping Face',
-  'Face With Medical Mask',
-  'Face With Thermometer',
-  'Face With Head-Bandage',
-  'Nauseated Face',
-  'Face Vomiting',
-  'Sneezing Face',
-  'Hot Face',
-  'Cold Face',
-  'Woozy Face',
-  'Dizzy Face',
-  'Exploding Head',
-  'Cowboy Hat Face',
-  'Partying Face',
-  'Smiling Face With Sunglasses',
-  'Nerd Face',
-  'Face With Monocle',
-  'Confused Face',
-  'Worried Face',
-  'Slightly Frowning Face',
-  'Frowning Face',
-  'Face With Open Mouth',
-  'Hushed Face',
-  'Astonished Face',
-  'Flushed Face',
-  'Pleading Face',
-  'Frowning Face With Open Mouth',
-  'Anguished Face',
-  'Fearful Face',
-  'Anxious Face With Sweat',
-  'Sad but Relieved Face',
-  'Crying Face',
-  'Loudly Crying Face',
-  'Face Screaming in Fear',
-  'Confounded Face',
-  'Persevering Face',
-  'Disappointed Face',
-  'Downcast Face With Sweat',
-  'Weary Face',
-  'Tired Face',
-  'Face With Steam From Nose',
-  'Pouting Face',
-  'Angry Face',
-  'Face With Symbols on Mouth',
-  'Smiling Face With Horns',
-  'Angry Face With Horns',
-  'Skull',
-  'Skull and Crossbones',
-  'Pile of Poo',
-  'Clown Face',
-  'Ogre',
-  'Goblin',
-  'Ghost',
-  'Alien',
-  'Alien Monster',
-  'Robot Face',
-  'Grinning Cat Face',
-  'Grinning Cat Face With Smiling Eyes',
-  'Cat Face With Tears of Joy',
-  'Smiling Cat Face With Heart-Eyes',
-  'Cat Face With Wry Smile',
-  'Kissing Cat Face',
-  'Weary Cat Face',
-  'Crying Cat Face',
-  'Pouting Cat Face',
-  'Kiss Mark',
-  'Waving Hand',
-  'Raised Back of Hand',
-  'Hand With Fingers Splayed',
-  'Raised Hand',
-  'Vulcan Salute',
-  'OK Hand',
-  'Victory Hand',
-  'Crossed Fingers',
-  'Love-You Gesture',
-  'Sign of the Horns',
-  'Call Me Hand',
-  'Backhand Index Pointing Left',
-  'Backhand Index Pointing Right',
-  'Backhand Index Pointing Up',
-  'Middle Finger',
-  'Backhand Index Pointing Down',
-  'Index Pointing Up',
-  'Thumbs Up',
-  'Thumbs Down',
-  'Raised Fist',
-  'Oncoming Fist',
-  'Left-Facing Fist',
-  'Right-Facing Fist',
-  'Clapping Hands',
-  'Raising Hands',
-  'Open Hands',
-  'Palms Up Together',
-  'Handshake',
-  'Folded Hands',
-  'Writing Hand',
-  'Nail Polish',
-  'Selfie',
-  'Flexed Biceps',
-  'Leg',
-  'Foot',
-  'Ear',
-  'Nose',
-  'Brain',
-  'Tooth',
-  'Bone',
-  'Eyes',
-  'Eye',
-  'Tongue',
-  'Mouth',
-  'Baby',
-  'Child',
-  'Boy',
-  'Girl',
-  'Person',
-  'Man',
-  'Man: Beard',
-  'Man: Blond Hair',
-  'Man: Red Hair',
-  'Man: Curly Hair',
-  'Man: White Hair',
-  'Man: Bald',
-  'Woman',
-  'Woman: Blond Hair',
-  'Woman: Red Hair',
-  'Woman: Curly Hair',
-  'Woman: White Hair',
-  'Woman: Bald',
-  'Older Person',
-  'Old Man',
-  'Old Woman',
-  'Man Frowning',
-  'Woman Frowning',
-  'Man Pouting',
-  'Woman Pouting',
-  'Man Gesturing No',
-  'Woman Gesturing No',
-  'Man Gesturing OK',
-  'Woman Gesturing OK',
-  'Man Tipping Hand',
-  'Woman Tipping Hand',
-  'Man Raising Hand',
-  'Woman Raising Hand',
-  'Man Bowing',
-  'Woman Bowing',
-  'Man Facepalming',
-  'Woman Facepalming',
-  'Man Shrugging',
-  'Woman Shrugging',
-  'Man Health Worker',
-  'Woman Health Worker',
-  'Man Student',
-  'Woman Student',
-  'Man Teacher',
-  'Woman Teacher',
-  'Man Judge',
-  'Woman Judge',
-  'Man Farmer',
-  'Woman Farmer',
-  'Man Cook',
-  'Woman Cook',
-  'Man Mechanic',
-  'Woman Mechanic',
-  'Man Factory Worker',
-  'Woman Factory Worker',
-  'Man Office Worker',
-  'Woman Office Worker',
-  'Man Scientist',
-  'Woman Scientist',
-  'Man Technologist',
-  'Woman Technologist',
-  'Man Singer',
-  'Woman Singer',
-  'Man Artist',
-  'Woman Artist',
-  'Man Pilot',
-  'Woman Pilot',
-  'Man Astronaut',
-  'Woman Astronaut',
-  'Man Firefighter',
-  'Woman Firefighter',
-  'Man Police Officer',
-  'Woman Police Officer',
-  'Man Detective',
-  'Woman Detective',
-  'Man Guard',
-  'Woman Guard',
-  'Man Construction Worker',
-  'Woman Construction Worker',
-  'Prince',
-  'Princess',
-  'Man Wearing Turban',
-  'Woman Wearing Turban',
-  'Man With Chinese Cap',
-  'Woman With Headscarf',
-  'Man in Tuxedo',
-  'Bride With Veil',
-  'Pregnant Woman',
-  'Breast-Feeding',
-  'Baby Angel',
-  'Santa Claus',
-  'Mrs. Claus',
-  'Man Superhero',
-  'Woman Superhero',
-  'Man Supervillain',
-  'Woman Supervillain',
-  'Man Mage',
-  'Woman Mage',
-  'Man Fairy',
-  'Woman Fairy',
-  'Man Vampire',
-  'Woman Vampire',
-  'Merman',
-  'Mermaid',
-  'Man Elf',
-  'Woman Elf',
-  'Man Genie',
-  'Woman Genie',
-  'Man Zombie',
-  'Woman Zombie',
-  'Man Getting Massage',
-  'Woman Getting Massage',
-  'Man Getting Haircut',
-  'Woman Getting Haircut',
-  'Man Walking',
-  'Woman Walking',
-  'Man Running',
-  'Woman Running',
-  'Woman Dancing',
-  'Man Dancing',
-  'Man in Suit Levitating',
-  'Men With Bunny Ears',
-  'Women With Bunny Ears',
-  'Man in Steamy Room',
-  'Woman in Steamy Room',
-  'Person in Lotus Position',
-  'Women Holding Hands',
-  'Woman and Man Holding Hands',
-  'Men Holding Hands',
-  'Kiss',
-  'Kiss: Man, Man',
-  'Kiss: Woman, Woman',
-  'Couple With Heart',
-  'Couple With Heart: Man, Man',
-  'Couple With Heart: Woman, Woman',
-  'Family',
-  'Family: Man, Woman, Boy',
-  'Family: Man, Woman, Girl',
-  'Family: Man, Woman, Girl, Boy',
-  'Family: Man, Woman, Boy, Boy',
-  'Family: Man, Woman, Girl, Girl',
-  'Family: Man, Man, Boy',
-  'Family: Man, Man, Girl',
-  'Family: Man, Man, Girl, Boy',
-  'Family: Man, Man, Boy, Boy',
-  'Family: Man, Man, Girl, Girl',
-  'Family: Woman, Woman, Boy',
-  'Family: Woman, Woman, Girl',
-  'Family: Woman, Woman, Girl, Boy',
-  'Family: Woman, Woman, Boy, Boy',
-  'Family: Woman, Woman, Girl, Girl',
-  'Family: Man, Boy',
-  'Family: Man, Boy, Boy',
-  'Family: Man, Girl',
-  'Family: Man, Girl, Boy',
-  'Family: Man, Girl, Girl',
-  'Family: Woman, Boy',
-  'Family: Woman, Boy, Boy',
-  'Family: Woman, Girl',
-  'Family: Woman, Girl, Boy',
-  'Family: Woman, Girl, Girl',
-  'Speaking Head',
-  'Bust in Silhouette',
-  'Busts in Silhouette',
-  'Footprints',
-  'Luggage',
-  'Closed Umbrella',
-  'Umbrella',
-  'Thread',
-  'Yarn',
-  'Glasses',
-  'Sunglasses',
-  'Goggles',
-  'Lab Coat',
-  'Necktie',
-  'T-Shirt',
-  'Jeans',
-  'Scarf',
-  'Gloves',
-  'Coat',
-  'Socks',
-  'Dress',
-  'Kimono',
-  'Bikini',
-  'Woman’s Clothes',
-  'Purse',
-  'Handbag',
-  'Clutch Bag',
-  'Backpack',
-  'Man’s Shoe',
-  'Running Shoe',
-  'Hiking Boot',
-  'Flat Shoe',
-  'High-Heeled Shoe',
-  'Woman’s Sandal',
-  'Woman’s Boot',
-  'Crown',
-  'Woman’s Hat',
-  'Top Hat',
-  'Graduation Cap',
-  'Billed Cap',
-  'Rescue Worker’s Helmet',
-  'Lipstick',
-  'Ring',
-  'Briefcase'
-], [
-  '😀',
-  '😃',
-  '😄',
-  '😁',
-  '😆',
-  '😅',
-  '🤣',
-  '😂',
-  '🙂',
-  '🙃',
-  '😉',
-  '😊',
-  '😇',
-  '🥰',
-  '😍',
-  '🤩',
-  '😘',
-  '😗',
-  '☺',
-  '😚',
-  '😙',
-  '😋',
-  '😛',
-  '😜',
-  '🤪',
-  '😝',
-  '🤑',
-  '🤗',
-  '🤭',
-  '🤫',
-  '🤔',
-  '🤐',
-  '🤨',
-  '😐',
-  '😑',
-  '😶',
-  '😏',
-  '😒',
-  '🙄',
-  '😬',
-  '🤥',
-  '😌',
-  '😔',
-  '😪',
-  '🤤',
-  '😴',
-  '😷',
-  '🤒',
-  '🤕',
-  '🤢',
-  '🤮',
-  '🤧',
-  '🥵',
-  '🥶',
-  '🥴',
-  '😵',
-  '🤯',
-  '🤠',
-  '🥳',
-  '😎',
-  '🤓',
-  '🧐',
-  '😕',
-  '😟',
-  '🙁',
-  '☹️',
-  '😮',
-  '😯',
-  '😲',
-  '😳',
-  '🥺',
-  '😦',
-  '😧',
-  '😨',
-  '😰',
-  '😥',
-  '😢',
-  '😭',
-  '😱',
-  '😖',
-  '😣',
-  '😞',
-  '😓',
-  '😩',
-  '😫',
-  '😤',
-  '😡',
-  '😠',
-  '🤬',
-  '😈',
-  '👿',
-  '💀',
-  '☠',
-  '💩',
-  '🤡',
-  '👹',
-  '👺',
-  '👻',
-  '👽',
-  '👾',
-  '🤖',
-  '😺',
-  '😸',
-  '😹',
-  '😻',
-  '😼',
-  '😽',
-  '🙀',
-  '😿',
-  '😾',
-  '💋',
-  '👋',
-  '🤚',
-  '🖐',
-  '✋',
-  '🖖',
-  '👌',
-  '✌',
-  '🤞',
-  '🤟',
-  '🤘',
-  '🤙',
-  '👈',
-  '👉',
-  '👆',
-  '🖕',
-  '👇',
-  '☝',
-  '👍',
-  '👎',
-  '✊',
-  '👊',
-  '🤛',
-  '🤜',
-  '👏',
-  '🙌',
-  '👐',
-  '🤲',
-  '🤝',
-  '🙏',
-  '✍',
-  '💅',
-  '🤳',
-  '💪',
-  '🦵',
-  '🦶',
-  '👂',
-  '👃',
-  '🧠',
-  '🦷',
-  '🦴',
-  '👀',
-  '👁',
-  '👅',
-  '👄',
-  '👶',
-  '🧒',
-  '👦',
-  '👧',
-  '🧑',
-  '👨',
-  '🧔',
-  '👱',
-  '👨‍🦰',
-  '👨‍🦱',
-  '👨‍🦳',
-  '👨‍🦲',
-  '👩',
-  '👱',
-  '👩‍🦰',
-  '👩‍🦱',
-  '👩‍🦳',
-  '👩‍🦲',
-  '🧓',
-  '👴',
-  '👵',
-  '🙍',
-  '🙍',
-  '🙎',
-  '🙎',
-  '🙅',
-  '🙅',
-  '🙆',
-  '🙆',
-  '💁',
-  '💁',
-  '🙋',
-  '🙋',
-  '🙇',
-  '🙇',
-  '🤦',
-  '🤦',
-  '🤷',
-  '🤷',
-  '👨‍⚕️',
-  '👩‍⚕️',
-  '👨‍🎓',
-  '👩‍🎓',
-  '👨‍🏫',
-  '👩‍🏫',
-  '👨‍⚖️',
-  '👩‍⚖️',
-  '👨‍🌾',
-  '👩‍🌾',
-  '👨‍🍳',
-  '👩‍🍳',
-  '👨‍🔧',
-  '👩‍🔧',
-  '👨‍🏭',
-  '👩‍🏭',
-  '👨‍💼',
-  '👩‍💼',
-  '👨‍🔬',
-  '👩‍🔬',
-  '👨‍💻',
-  '👩‍💻',
-  '👨‍🎤',
-  '👩‍🎤',
-  '👨‍🎨',
-  '👩‍🎨',
-  '👨‍✈️',
-  '👩‍✈️',
-  '👨‍🚀',
-  '👩‍🚀',
-  '👨‍🚒',
-  '👩‍🚒',
-  '👮',
-  '👮',
-  '🕵️',
-  '🕵️',
-  '💂',
-  '💂',
-  '👷',
-  '👷',
-  '🤴',
-  '👸',
-  '👳',
-  '👳',
-  '👲',
-  '🧕',
-  '🤵',
-  '👰',
-  '🤰',
-  '🤱',
-  '👼',
-  '🎅',
-  '🤶',
-  '🦸',
-  '🦸',
-  '🦹',
-  '🦹',
-  '🧙',
-  '🧙',
-  '🧚',
-  '🧚',
-  '🧛',
-  '🧛',
-  '🧜',
-  '🧜',
-  '🧝',
-  '🧝',
-  '🧞',
-  '🧞',
-  '🧟',
-  '🧟',
-  '💆',
-  '💆',
-  '💇',
-  '💇',
-  '🚶',
-  '🚶',
-  '🏃',
-  '🏃',
-  '💃',
-  '🕺',
-  '🕴',
-  '👯',
-  '👯',
-  '🧖',
-  '🧖',
-  '🧘',
-  '👭',
-  '👫',
-  '👬',
-  '💏',
-  '👨‍❤️‍💋‍👨',
-  '👩‍❤️‍💋‍👩',
-  '💑',
-  '👨‍❤️‍👨',
-  '👩‍❤️‍👩',
-  '👪',
-  '👨‍👩‍👦',
-  '👨‍👩‍👧',
-  '👨‍👩‍👧‍👦',
-  '👨‍👩‍👦‍👦',
-  '👨‍👩‍👧‍👧',
-  '👨‍👨‍👦',
-  '👨‍👨‍👧',
-  '👨‍👨‍👧‍👦',
-  '👨‍👨‍👦‍👦',
-  '👨‍👨‍👧‍👧',
-  '👩‍👩‍👦',
-  '👩‍👩‍👧',
-  '👩‍👩‍👧‍👦',
-  '👩‍👩‍👦‍👦',
-  '👩‍👩‍👧‍👧',
-  '👨‍👦',
-  '👨‍👦‍👦',
-  '👨‍👧',
-  '👨‍👧‍👦',
-  '👨‍👧‍👧',
-  '👩‍👦',
-  '👩‍👦‍👦',
-  '👩‍👧',
-  '👩‍👧‍👦',
-  '👩‍👧‍👧',
-  '🗣',
-  '👤',
-  '👥',
-  '👣',
-  '🧳',
-  '🌂',
-  '☂',
-  '🧵',
-  '🧶',
-  '👓',
-  '🕶',
-  '🥽',
-  '🥼',
-  '👔',
-  '👕',
-  '👖',
-  '🧣',
-  '🧤',
-  '🧥',
-  '🧦',
-  '👗',
-  '👘',
-  '👙',
-  '👚',
-  '👛',
-  '👜',
-  '👝',
-  '🎒',
-  '👞',
-  '👟',
-  '🥾',
-  '🥿',
-  '👠',
-  '👡',
-  '👢',
-  '👑',
-  '👒',
-  '🎩',
-  '🎓',
-  '🧢',
-  '⛑',
-  '💄',
-  '💍',
-  '💼'
-]);
-
-/// Map of all possible emojis along with their names in [Category.ANIMALS]
-final Map<String, String> animals = Map.fromIterables([
-  'Dog Face',
-  'Cat Face',
-  'Mouse Face',
-  'Hamster Face',
-  'Rabbit Face',
-  'Fox Face',
-  'Bear Face',
-  'Panda Face',
-  'Koala Face',
-  'Tiger Face',
-  'Lion Face',
-  'Cow Face',
-  'Pig Face',
-  'Pig Nose',
-  'Frog Face',
-  'Monkey Face',
-  'See-No-Evil Monkey',
-  'Hear-No-Evil Monkey',
-  'Speak-No-Evil Monkey',
-  'Monkey',
-  'Collision',
-  'Dizzy',
-  'Sweat Droplets',
-  'Dashing Away',
-  'Gorilla',
-  'Dog',
-  'Poodle',
-  'Wolf Face',
-  'Raccoon',
-  'Cat',
-  'Tiger',
-  'Leopard',
-  'Horse Face',
-  'Horse',
-  'Unicorn Face',
-  'Zebra',
-  'Ox',
-  'Water Buffalo',
-  'Cow',
-  'Pig',
-  'Boar',
-  'Ram',
-  'Ewe',
-  'Goat',
-  'Camel',
-  'Two-Hump Camel',
-  'Llama',
-  'Giraffe',
-  'Elephant',
-  'Rhinoceros',
-  'Hippopotamus',
-  'Mouse',
-  'Rat',
-  'Rabbit',
-  'Chipmunk',
-  'Hedgehog',
-  'Bat',
-  'Kangaroo',
-  'Badger',
-  'Paw Prints',
-  'Turkey',
-  'Chicken',
-  'Rooster',
-  'Hatching Chick',
-  'Baby Chick',
-  'Front-Facing Baby Chick',
-  'Bird',
-  'Penguin',
-  'Dove',
-  'Eagle',
-  'Duck',
-  'Swan',
-  'Owl',
-  'Peacock',
-  'Parrot',
-  'Crocodile',
-  'Turtle',
-  'Lizard',
-  'Snake',
-  'Dragon Face',
-  'Dragon',
-  'Sauropod',
-  'T-Rex',
-  'Spouting Whale',
-  'Whale',
-  'Dolphin',
-  'Fish',
-  'Tropical Fish',
-  'Blowfish',
-  'Shark',
-  'Octopus',
-  'Spiral Shell',
-  'Snail',
-  'Butterfly',
-  'Bug',
-  'Ant',
-  'Honeybee',
-  'Lady Beetle',
-  'Cricket',
-  'Spider',
-  'Spider Web',
-  'Scorpion',
-  'Mosquito',
-  'Microbe',
-  'Bouquet',
-  'Cherry Blossom',
-  'White Flower',
-  'Rosette',
-  'Rose',
-  'Wilted Flower',
-  'Hibiscus',
-  'Sunflower',
-  'Blossom',
-  'Tulip',
-  'Seedling',
-  'Evergreen Tree',
-  'Deciduous Tree',
-  'Palm Tree',
-  'Cactus',
-  'Sheaf of Rice',
-  'Herb',
-  'Shamrock',
-  'Four Leaf Clover',
-  'Maple Leaf',
-  'Fallen Leaf',
-  'Leaf Fluttering in Wind',
-  'Mushroom',
-  'Chestnut',
-  'Crab',
-  'Lobster',
-  'Shrimp',
-  'Squid',
-  'Globe Showing Europe-Africa',
-  'Globe Showing Americas',
-  'Globe Showing Asia-Australia',
-  'Globe With Meridians',
-  'New Moon',
-  'Waxing Crescent Moon',
-  'First Quarter Moon',
-  'Waxing Gibbous Moon',
-  'Full Moon',
-  'Waning Gibbous Moon',
-  'Last Quarter Moon',
-  'Waning Crescent Moon',
-  'Crescent Moon',
-  'New Moon Face',
-  'First Quarter Moon Face',
-  'Last Quarter Moon Face',
-  'Sun',
-  'Full Moon Face',
-  'Sun With Face',
-  'Star',
-  'Glowing Star',
-  'Shooting Star',
-  'Cloud',
-  'Sun Behind Cloud',
-  'Cloud With Lightning and Rain',
-  'Sun Behind Small Cloud',
-  'Sun Behind Large Cloud',
-  'Sun Behind Rain Cloud',
-  'Cloud With Rain',
-  'Cloud With Snow',
-  'Cloud With Lightning',
-  'Tornado',
-  'Fog',
-  'Wind Face',
-  'Rainbow',
-  'Umbrella',
-  'Umbrella With Rain Drops',
-  'High Voltage',
-  'Snowflake',
-  'Snowman Without Snow',
-  'Snowman',
-  'Comet',
-  'Fire',
-  'Droplet',
-  'Water Wave',
-  'Christmas Tree',
-  'Sparkles',
-  'Tanabata Tree',
-  'Pine Decoration'
-], [
-  '🐶',
-  '🐱',
-  '🐭',
-  '🐹',
-  '🐰',
-  '🦊',
-  '🐻',
-  '🐼',
-  '🐨',
-  '🐯',
-  '🦁',
-  '🐮',
-  '🐷',
-  '🐽',
-  '🐸',
-  '🐵',
-  '🙈',
-  '🙉',
-  '🙊',
-  '🐒',
-  '💥',
-  '💫',
-  '💦',
-  '💨',
-  '🦍',
-  '🐕',
-  '🐩',
-  '🐺',
-  '🦝',
-  '🐈',
-  '🐅',
-  '🐆',
-  '🐴',
-  '🐎',
-  '🦄',
-  '🦓',
-  '🐂',
-  '🐃',
-  '🐄',
-  '🐖',
-  '🐗',
-  '🐏',
-  '🐑',
-  '🐐',
-  '🐪',
-  '🐫',
-  '🦙',
-  '🦒',
-  '🐘',
-  '🦏',
-  '🦛',
-  '🐁',
-  '🐀',
-  '🐇',
-  '🐿',
-  '🦔',
-  '🦇',
-  '🦘',
-  '🦡',
-  '🐾',
-  '🦃',
-  '🐔',
-  '🐓',
-  '🐣',
-  '🐤',
-  '🐥',
-  '🐦',
-  '🐧',
-  '🕊',
-  '🦅',
-  '🦆',
-  '🦢',
-  '🦉',
-  '🦚',
-  '🦜',
-  '🐊',
-  '🐢',
-  '🦎',
-  '🐍',
-  '🐲',
-  '🐉',
-  '🦕',
-  '🦖',
-  '🐳',
-  '🐋',
-  '🐬',
-  '🐟',
-  '🐠',
-  '🐡',
-  '🦈',
-  '🐙',
-  '🐚',
-  '🐌',
-  '🦋',
-  '🐛',
-  '🐜',
-  '🐝',
-  '🐞',
-  '🦗',
-  '🕷',
-  '🕸',
-  '🦂',
-  '🦟',
-  '🦠',
-  '💐',
-  '🌸',
-  '💮',
-  '🏵',
-  '🌹',
-  '🥀',
-  '🌺',
-  '🌻',
-  '🌼',
-  '🌷',
-  '🌱',
-  '🌲',
-  '🌳',
-  '🌴',
-  '🌵',
-  '🌾',
-  '🌿',
-  '☘',
-  '🍀',
-  '🍁',
-  '🍂',
-  '🍃',
-  '🍄',
-  '🌰',
-  '🦀',
-  '🦞',
-  '🦐',
-  '🦑',
-  '🌍',
-  '🌎',
-  '🌏',
-  '🌐',
-  '🌑',
-  '🌒',
-  '🌓',
-  '🌔',
-  '🌕',
-  '🌖',
-  '🌗',
-  '🌘',
-  '🌙',
-  '🌚',
-  '🌛',
-  '🌜',
-  '☀',
-  '🌝',
-  '🌞',
-  '⭐',
-  '🌟',
-  '🌠',
-  '☁',
-  '⛅',
-  '⛈',
-  '🌤',
-  '🌥',
-  '🌦',
-  '🌧',
-  '🌨',
-  '🌩',
-  '🌪',
-  '🌫',
-  '🌬',
-  '🌈',
-  '☂',
-  '☔',
-  '⚡',
-  '❄',
-  '☃',
-  '⛄',
-  '☄',
-  '🔥',
-  '💧',
-  '🌊',
-  '🎄',
-  '✨',
-  '🎋',
-  '🎍'
-]);
-
-/// Map of all possible emojis along with their names in [Category.FOODS]
-final Map<String, String> foods = Map.fromIterables([
-  'Grapes',
-  'Melon',
-  'Watermelon',
-  'Tangerine',
-  'Lemon',
-  'Banana',
-  'Pineapple',
-  'Mango',
-  'Red Apple',
-  'Green Apple',
-  'Pear',
-  'Peach',
-  'Cherries',
-  'Strawberry',
-  'Kiwi Fruit',
-  'Tomato',
-  'Coconut',
-  'Avocado',
-  'Eggplant',
-  'Potato',
-  'Carrot',
-  'Ear of Corn',
-  'Hot Pepper',
-  'Cucumber',
-  'Leafy Green',
-  'Broccoli',
-  'Mushroom',
-  'Peanuts',
-  'Chestnut',
-  'Bread',
-  'Croissant',
-  'Baguette Bread',
-  'Pretzel',
-  'Bagel',
-  'Pancakes',
-  'Cheese Wedge',
-  'Meat on Bone',
-  'Poultry Leg',
-  'Cut of Meat',
-  'Bacon',
-  'Hamburger',
-  'French Fries',
-  'Pizza',
-  'Hot Dog',
-  'Sandwich',
-  'Taco',
-  'Burrito',
-  'Stuffed Flatbread',
-  'Cooking',
-  'Shallow Pan of Food',
-  'Pot of Food',
-  'Bowl With Spoon',
-  'Green Salad',
-  'Popcorn',
-  'Salt',
-  'Canned Food',
-  'Bento Box',
-  'Rice Cracker',
-  'Rice Ball',
-  'Cooked Rice',
-  'Curry Rice',
-  'Steaming Bowl',
-  'Spaghetti',
-  'Roasted Sweet Potato',
-  'Oden',
-  'Sushi',
-  'Fried Shrimp',
-  'Fish Cake With Swirl',
-  'Moon Cake',
-  'Dango',
-  'Dumpling',
-  'Fortune Cookie',
-  'Takeout Box',
-  'Soft Ice Cream',
-  'Shaved Ice',
-  'Ice Cream',
-  'Doughnut',
-  'Cookie',
-  'Birthday Cake',
-  'Shortcake',
-  'Cupcake',
-  'Pie',
-  'Chocolate Bar',
-  'Candy',
-  'Lollipop',
-  'Custard',
-  'Honey Pot',
-  'Baby Bottle',
-  'Glass of Milk',
-  'Hot Beverage',
-  'Teacup Without Handle',
-  'Sake',
-  'Bottle With Popping Cork',
-  'Wine Glass',
-  'Cocktail Glass',
-  'Tropical Drink',
-  'Beer Mug',
-  'Clinking Beer Mugs',
-  'Clinking Glasses',
-  'Tumbler Glass',
-  'Cup With Straw',
-  'Chopsticks',
-  'Fork and Knife With Plate',
-  'Fork and Knife',
-  'Spoon'
-], [
-  '🍇',
-  '🍈',
-  '🍉',
-  '🍊',
-  '🍋',
-  '🍌',
-  '🍍',
-  '🥭',
-  '🍎',
-  '🍏',
-  '🍐',
-  '🍑',
-  '🍒',
-  '🍓',
-  '🥝',
-  '🍅',
-  '🥥',
-  '🥑',
-  '🍆',
-  '🥔',
-  '🥕',
-  '🌽',
-  '🌶',
-  '🥒',
-  '🥬',
-  '🥦',
-  '🍄',
-  '🥜',
-  '🌰',
-  '🍞',
-  '🥐',
-  '🥖',
-  '🥨',
-  '🥯',
-  '🥞',
-  '🧀',
-  '🍖',
-  '🍗',
-  '🥩',
-  '🥓',
-  '🍔',
-  '🍟',
-  '🍕',
-  '🌭',
-  '🥪',
-  '🌮',
-  '🌯',
-  '🥙',
-  '🍳',
-  '🥘',
-  '🍲',
-  '🥣',
-  '🥗',
-  '🍿',
-  '🧂',
-  '🥫',
-  '🍱',
-  '🍘',
-  '🍙',
-  '🍚',
-  '🍛',
-  '🍜',
-  '🍝',
-  '🍠',
-  '🍢',
-  '🍣',
-  '🍤',
-  '🍥',
-  '🥮',
-  '🍡',
-  '🥟',
-  '🥠',
-  '🥡',
-  '🍦',
-  '🍧',
-  '🍨',
-  '🍩',
-  '🍪',
-  '🎂',
-  '🍰',
-  '🧁',
-  '🥧',
-  '🍫',
-  '🍬',
-  '🍭',
-  '🍮',
-  '🍯',
-  '🍼',
-  '🥛',
-  '☕',
-  '🍵',
-  '🍶',
-  '🍾',
-  '🍷',
-  '🍸',
-  '🍹',
-  '🍺',
-  '🍻',
-  '🥂',
-  '🥃',
-  '🥤',
-  '🥢',
-  '🍽',
-  '🍴',
-  '🥄'
-]);
-
-/// Map of all possible emojis along with their names in [Category.TRAVEL]
-final Map<String, String> travel = Map.fromIterables([
-  'Person Rowing Boat',
-  'Map of Japan',
-  'Snow-Capped Mountain',
-  'Mountain',
-  'Volcano',
-  'Mount Fuji',
-  'Camping',
-  'Beach With Umbrella',
-  'Desert',
-  'Desert Island',
-  'National Park',
-  'Stadium',
-  'Classical Building',
-  'Building Construction',
-  'Houses',
-  'Derelict House',
-  'House',
-  'House With Garden',
-  'Office Building',
-  'Japanese Post Office',
-  'Post Office',
-  'Hospital',
-  'Bank',
-  'Hotel',
-  'Love Hotel',
-  'Convenience Store',
-  'School',
-  'Department Store',
-  'Factory',
-  'Japanese Castle',
-  'Castle',
-  'Wedding',
-  'Tokyo Tower',
-  'Statue of Liberty',
-  'Church',
-  'Mosque',
-  'Synagogue',
-  'Shinto Shrine',
-  'Kaaba',
-  'Fountain',
-  'Tent',
-  'Foggy',
-  'Night With Stars',
-  'Cityscape',
-  'Sunrise Over Mountains',
-  'Sunrise',
-  'Cityscape at Dusk',
-  'Sunset',
-  'Bridge at Night',
-  'Carousel Horse',
-  'Ferris Wheel',
-  'Roller Coaster',
-  'Locomotive',
-  'Railway Car',
-  'High-Speed Train',
-  'Bullet Train',
-  'Train',
-  'Metro',
-  'Light Rail',
-  'Station',
-  'Tram',
-  'Monorail',
-  'Mountain Railway',
-  'Tram Car',
-  'Bus',
-  'Oncoming Bus',
-  'Trolleybus',
-  'Minibus',
-  'Ambulance',
-  'Fire Engine',
-  'Police Car',
-  'Oncoming Police Car',
-  'Taxi',
-  'Oncoming Taxi',
-  'Automobile',
-  'Oncoming Automobile',
-  'Delivery Truck',
-  'Articulated Lorry',
-  'Tractor',
-  'Racing Car',
-  'Motorcycle',
-  'Motor Scooter',
-  'Bicycle',
-  'Kick Scooter',
-  'Bus Stop',
-  'Railway Track',
-  'Fuel Pump',
-  'Police Car Light',
-  'Horizontal Traffic Light',
-  'Vertical Traffic Light',
-  'Construction',
-  'Anchor',
-  'Sailboat',
-  'Speedboat',
-  'Passenger Ship',
-  'Ferry',
-  'Motor Boat',
-  'Ship',
-  'Airplane',
-  'Small Airplane',
-  'Airplane Departure',
-  'Airplane Arrival',
-  'Seat',
-  'Helicopter',
-  'Suspension Railway',
-  'Mountain Cableway',
-  'Aerial Tramway',
-  'Satellite',
-  'Rocket',
-  'Flying Saucer',
-  'Shooting Star',
-  'Milky Way',
-  'Umbrella on Ground',
-  'Fireworks',
-  'Sparkler',
-  'Moon Viewing Ceremony',
-  'Yen Banknote',
-  'Dollar Banknote',
-  'Euro Banknote',
-  'Pound Banknote',
-  'Moai',
-  'Passport Control',
-  'Customs',
-  'Baggage Claim',
-  'Left Luggage'
-], [
-  '🚣',
-  '🗾',
-  '🏔',
-  '⛰',
-  '🌋',
-  '🗻',
-  '🏕',
-  '🏖',
-  '🏜',
-  '🏝',
-  '🏞',
-  '🏟',
-  '🏛',
-  '🏗',
-  '🏘',
-  '🏚',
-  '🏠',
-  '🏡',
-  '🏢',
-  '🏣',
-  '🏤',
-  '🏥',
-  '🏦',
-  '🏨',
-  '🏩',
-  '🏪',
-  '🏫',
-  '🏬',
-  '🏭',
-  '🏯',
-  '🏰',
-  '💒',
-  '🗼',
-  '🗽',
-  '⛪',
-  '🕌',
-  '🕍',
-  '⛩',
-  '🕋',
-  '⛲',
-  '⛺',
-  '🌁',
-  '🌃',
-  '🏙',
-  '🌄',
-  '🌅',
-  '🌆',
-  '🌇',
-  '🌉',
-  '🎠',
-  '🎡',
-  '🎢',
-  '🚂',
-  '🚃',
-  '🚄',
-  '🚅',
-  '🚆',
-  '🚇',
-  '🚈',
-  '🚉',
-  '🚊',
-  '🚝',
-  '🚞',
-  '🚋',
-  '🚌',
-  '🚍',
-  '🚎',
-  '🚐',
-  '🚑',
-  '🚒',
-  '🚓',
-  '🚔',
-  '🚕',
-  '🚖',
-  '🚗',
-  '🚘',
-  '🚚',
-  '🚛',
-  '🚜',
-  '🏎',
-  '🏍',
-  '🛵',
-  '🚲',
-  '🛴',
-  '🚏',
-  '🛤',
-  '⛽',
-  '🚨',
-  '🚥',
-  '🚦',
-  '🚧',
-  '⚓',
-  '⛵',
-  '🚤',
-  '🛳',
-  '⛴',
-  '🛥',
-  '🚢',
-  '✈',
-  '🛩',
-  '🛫',
-  '🛬',
-  '💺',
-  '🚁',
-  '🚟',
-  '🚠',
-  '🚡',
-  '🛰',
-  '🚀',
-  '🛸',
-  '🌠',
-  '🌌',
-  '⛱',
-  '🎆',
-  '🎇',
-  '🎑',
-  '💴',
-  '💵',
-  '💶',
-  '💷',
-  '🗿',
-  '🛂',
-  '🛃',
-  '🛄',
-  '🛅'
-]);
-
-/// Map of all possible emojis along with their names in [Category.ACTIVITIES]
-final Map<String, String> activities = Map.fromIterables([
-  'Man in Suit Levitating',
-  'Man Climbing',
-  'Woman Climbing',
-  'Horse Racing',
-  'Skier',
-  'Snowboarder',
-  'Man Golfing',
-  'Woman Golfing',
-  'Man Surfing',
-  'Woman Surfing',
-  'Man Rowing Boat',
-  'Woman Rowing Boat',
-  'Man Swimming',
-  'Woman Swimming',
-  'Man Bouncing Ball',
-  'Woman Bouncing Ball',
-  'Man Lifting Weights',
-  'Woman Lifting Weights',
-  'Man Biking',
-  'Woman Biking',
-  'Man Mountain Biking',
-  'Woman Mountain Biking',
-  'Man Cartwheeling',
-  'Woman Cartwheeling',
-  'Men Wrestling',
-  'Women Wrestling',
-  'Man Playing Water Polo',
-  'Woman Playing Water Polo',
-  'Man Playing Handball',
-  'Woman Playing Handball',
-  'Man Juggling',
-  'Woman Juggling',
-  'Man in Lotus Position',
-  'Woman in Lotus Position',
-  'Circus Tent',
-  'Skateboard',
-  'Reminder Ribbon',
-  'Admission Tickets',
-  'Ticket',
-  'Military Medal',
-  'Trophy',
-  'Sports Medal',
-  '1st Place Medal',
-  '2nd Place Medal',
-  '3rd Place Medal',
-  'Soccer Ball',
-  'Baseball',
-  'Softball',
-  'Basketball',
-  'Volleyball',
-  'American Football',
-  'Rugby Football',
-  'Tennis',
-  'Flying Disc',
-  'Bowling',
-  'Cricket Game',
-  'FieldPB Hockey',
-  'Ice Hockey',
-  'Lacrosse',
-  'Ping Pong',
-  'Badminton',
-  'Boxing Glove',
-  'Martial Arts Uniform',
-  'Flag in Hole',
-  'Ice Skate',
-  'Fishing Pole',
-  'Running Shirt',
-  'Skis',
-  'Sled',
-  'Curling Stone',
-  'Direct Hit',
-  'Pool 8 Ball',
-  'Video Game',
-  'Slot Machine',
-  'Game Die',
-  'Jigsaw',
-  'Chess Pawn',
-  'Performing Arts',
-  'Artist Palette',
-  'Thread',
-  'Yarn',
-  'Musical Score',
-  'Microphone',
-  'Headphone',
-  'Saxophone',
-  'Guitar',
-  'Musical Keyboard',
-  'Trumpet',
-  'Violin',
-  'Drum',
-  'Clapper Board',
-  'Bow and Arrow'
-], [
-  '🕴',
-  '🧗',
-  '🧗',
-  '🏇',
-  '⛷',
-  '🏂',
-  '🏌️',
-  '🏌️',
-  '🏄',
-  '🏄',
-  '🚣',
-  '🚣',
-  '🏊',
-  '🏊',
-  '⛹️',
-  '⛹️',
-  '🏋️',
-  '🏋️',
-  '🚴',
-  '🚴',
-  '🚵',
-  '🚵',
-  '🤸',
-  '🤸',
-  '🤼',
-  '🤼',
-  '🤽',
-  '🤽',
-  '🤾',
-  '🤾',
-  '🤹',
-  '🤹',
-  '🧘🏻‍♂️',
-  '🧘🏻‍♀️',
-  '🎪',
-  '🛹',
-  '🎗',
-  '🎟',
-  '🎫',
-  '🎖',
-  '🏆',
-  '🏅',
-  '🥇',
-  '🥈',
-  '🥉',
-  '⚽',
-  '⚾',
-  '🥎',
-  '🏀',
-  '🏐',
-  '🏈',
-  '🏉',
-  '🎾',
-  '🥏',
-  '🎳',
-  '🏏',
-  '🏑',
-  '🏒',
-  '🥍',
-  '🏓',
-  '🏸',
-  '🥊',
-  '🥋',
-  '⛳',
-  '⛸',
-  '🎣',
-  '🎽',
-  '🎿',
-  '🛷',
-  '🥌',
-  '🎯',
-  '🎱',
-  '🎮',
-  '🎰',
-  '🎲',
-  '🧩',
-  '♟',
-  '🎭',
-  '🎨',
-  '🧵',
-  '🧶',
-  '🎼',
-  '🎤',
-  '🎧',
-  '🎷',
-  '🎸',
-  '🎹',
-  '🎺',
-  '🎻',
-  '🥁',
-  '🎬',
-  '🏹'
-]);
-
-/// Map of all possible emojis along with their names in [Category.OBJECTS]
-final Map<String, String> objects = Map.fromIterables([
-  'Love Letter',
-  'Hole',
-  'Bomb',
-  'Person Taking Bath',
-  'Person in Bed',
-  'Kitchen Knife',
-  'Amphora',
-  'World Map',
-  'Compass',
-  'Brick',
-  'Barber Pole',
-  'Oil Drum',
-  'Bellhop Bell',
-  'Luggage',
-  'Hourglass Done',
-  'Hourglass Not Done',
-  'Watch',
-  'Alarm Clock',
-  'Stopwatch',
-  'Timer Clock',
-  'Mantelpiece Clock',
-  'Thermometer',
-  'Umbrella on Ground',
-  'Firecracker',
-  'Balloon',
-  'Party Popper',
-  'Confetti Ball',
-  'Japanese Dolls',
-  'Carp Streamer',
-  'Wind Chime',
-  'Red Envelope',
-  'Ribbon',
-  'Wrapped Gift',
-  'Crystal Ball',
-  'Nazar Amulet',
-  'Joystick',
-  'Teddy Bear',
-  'Framed Picture',
-  'Thread',
-  'Yarn',
-  'Shopping Bags',
-  'Prayer Beads',
-  'Gem Stone',
-  'Postal Horn',
-  'Studio Microphone',
-  'Level Slider',
-  'Control Knobs',
-  'Radio',
-  'Mobile Phone',
-  'Mobile Phone With Arrow',
-  'Telephone',
-  'Telephone Receiver',
-  'Pager',
-  'Fax Machine',
-  'Battery',
-  'Electric Plug',
-  'Laptop Computer',
-  'Desktop Computer',
-  'Printer',
-  'Keyboard',
-  'Computer Mouse',
-  'Trackball',
-  'Computer Disk',
-  'Floppy Disk',
-  'Optical Disk',
-  'DVD',
-  'Abacus',
-  'Movie Camera',
-  'Film Frames',
-  'Film Projector',
-  'Television',
-  'Camera',
-  'Camera With Flash',
-  'Video Camera',
-  'Videocassette',
-  'Magnifying Glass Tilted Left',
-  'Magnifying Glass Tilted Right',
-  'Candle',
-  'Light Bulb',
-  'Flashlight',
-  'Red Paper Lantern',
-  'Notebook With Decorative Cover',
-  'Closed Book',
-  'Open Book',
-  'Green Book',
-  'Blue Book',
-  'Orange Book',
-  'Books',
-  'Notebook',
-  'Page With Curl',
-  'Scroll',
-  'Page Facing Up',
-  'Newspaper',
-  'Rolled-Up Newspaper',
-  'Bookmark Tabs',
-  'Bookmark',
-  'Label',
-  'Money Bag',
-  'Yen Banknote',
-  'Dollar Banknote',
-  'Euro Banknote',
-  'Pound Banknote',
-  'Money With Wings',
-  'Credit Card',
-  'Receipt',
-  'Envelope',
-  'E-Mail',
-  'Incoming Envelope',
-  'Envelope With Arrow',
-  'Outbox Tray',
-  'Inbox Tray',
-  'Package',
-  'Closed Mailbox With Raised Flag',
-  'Closed Mailbox With Lowered Flag',
-  'Open Mailbox With Raised Flag',
-  'Open Mailbox With Lowered Flag',
-  'Postbox',
-  'Ballot Box With Ballot',
-  'Pencil',
-  'Black Nib',
-  'Fountain Pen',
-  'Pen',
-  'Paintbrush',
-  'Crayon',
-  'Memo',
-  'File Folder',
-  'Open File Folder',
-  'Card Index Dividers',
-  'Calendar',
-  'Tear-Off Calendar',
-  'Spiral Notepad',
-  'Spiral Calendar',
-  'Card Index',
-  'Chart Increasing',
-  'Chart Decreasing',
-  'Bar Chart',
-  'Clipboard',
-  'Pushpin',
-  'Round Pushpin',
-  'Paperclip',
-  'Linked Paperclips',
-  'Straight Ruler',
-  'Triangular Ruler',
-  'Scissors',
-  'Card File Box',
-  'File Cabinet',
-  'Wastebasket',
-  'Locked',
-  'Unlocked',
-  'Locked With Pen',
-  'Locked With Key',
-  'Key',
-  'Old Key',
-  'Hammer',
-  'Pick',
-  'Hammer and Pick',
-  'Hammer and Wrench',
-  'Dagger',
-  'Crossed Swords',
-  'Pistol',
-  'Shield',
-  'Wrench',
-  'Nut and Bolt',
-  'Gear',
-  'Clamp',
-  'Balance Scale',
-  'Link',
-  'Chains',
-  'Toolbox',
-  'Magnet',
-  'Alembic',
-  'Test Tube',
-  'Petri Dish',
-  'DNA',
-  'Microscope',
-  'Telescope',
-  'Satellite Antenna',
-  'Syringe',
-  'Pill',
-  'Door',
-  'Bed',
-  'Couch and Lamp',
-  'Toilet',
-  'Shower',
-  'Bathtub',
-  'Lotion Bottle',
-  'Safety Pin',
-  'Broom',
-  'Basket',
-  'Roll of Paper',
-  'Soap',
-  'Sponge',
-  'Fire Extinguisher',
-  'Cigarette',
-  'Coffin',
-  'Funeral Urn',
-  'Moai',
-  'Potable Water'
-], [
-  '💌',
-  '🕳',
-  '💣',
-  '🛀',
-  '🛌',
-  '🔪',
-  '🏺',
-  '🗺',
-  '🧭',
-  '🧱',
-  '💈',
-  '🛢',
-  '🛎',
-  '🧳',
-  '⌛',
-  '⏳',
-  '⌚',
-  '⏰',
-  '⏱',
-  '⏲',
-  '🕰',
-  '🌡',
-  '⛱',
-  '🧨',
-  '🎈',
-  '🎉',
-  '🎊',
-  '🎎',
-  '🎏',
-  '🎐',
-  '🧧',
-  '🎀',
-  '🎁',
-  '🔮',
-  '🧿',
-  '🕹',
-  '🧸',
-  '🖼',
-  '🧵',
-  '🧶',
-  '🛍',
-  '📿',
-  '💎',
-  '📯',
-  '🎙',
-  '🎚',
-  '🎛',
-  '📻',
-  '📱',
-  '📲',
-  '☎',
-  '📞',
-  '📟',
-  '📠',
-  '🔋',
-  '🔌',
-  '💻',
-  '🖥',
-  '🖨',
-  '⌨',
-  '🖱',
-  '🖲',
-  '💽',
-  '💾',
-  '💿',
-  '📀',
-  '🧮',
-  '🎥',
-  '🎞',
-  '📽',
-  '📺',
-  '📷',
-  '📸',
-  '📹',
-  '📼',
-  '🔍',
-  '🔎',
-  '🕯',
-  '💡',
-  '🔦',
-  '🏮',
-  '📔',
-  '📕',
-  '📖',
-  '📗',
-  '📘',
-  '📙',
-  '📚',
-  '📓',
-  '📃',
-  '📜',
-  '📄',
-  '📰',
-  '🗞',
-  '📑',
-  '🔖',
-  '🏷',
-  '💰',
-  '💴',
-  '💵',
-  '💶',
-  '💷',
-  '💸',
-  '💳',
-  '🧾',
-  '✉',
-  '📧',
-  '📨',
-  '📩',
-  '📤',
-  '📥',
-  '📦',
-  '📫',
-  '📪',
-  '📬',
-  '📭',
-  '📮',
-  '🗳',
-  '✏',
-  '✒',
-  '🖋',
-  '🖊',
-  '🖌',
-  '🖍',
-  '📝',
-  '📁',
-  '📂',
-  '🗂',
-  '📅',
-  '📆',
-  '🗒',
-  '🗓',
-  '📇',
-  '📈',
-  '📉',
-  '📊',
-  '📋',
-  '📌',
-  '📍',
-  '📎',
-  '🖇',
-  '📏',
-  '📐',
-  '✂',
-  '🗃',
-  '🗄',
-  '🗑',
-  '🔒',
-  '🔓',
-  '🔏',
-  '🔐',
-  '🔑',
-  '🗝',
-  '🔨',
-  '⛏',
-  '⚒',
-  '🛠',
-  '🗡',
-  '⚔',
-  '🔫',
-  '🛡',
-  '🔧',
-  '🔩',
-  '⚙',
-  '🗜',
-  '⚖',
-  '🔗',
-  '⛓',
-  '🧰',
-  '🧲',
-  '⚗',
-  '🧪',
-  '🧫',
-  '🧬',
-  '🔬',
-  '🔭',
-  '📡',
-  '💉',
-  '💊',
-  '🚪',
-  '🛏',
-  '🛋',
-  '🚽',
-  '🚿',
-  '🛁',
-  '🧴',
-  '🧷',
-  '🧹',
-  '🧺',
-  '🧻',
-  '🧼',
-  '🧽',
-  '🧯',
-  '🚬',
-  '⚰',
-  '⚱',
-  '🗿',
-  '🚰'
-]);
-
-/// Map of all possible emojis along with their names in [Category.SYMBOLS]
-final Map<String, String> symbols = Map.fromIterables([
-  'Heart With Arrow',
-  'Heart With Ribbon',
-  'Sparkling Heart',
-  'Growing Heart',
-  'Beating Heart',
-  'Revolving Hearts',
-  'Two Hearts',
-  'Heart Decoration',
-  'Heavy Heart Exclamation',
-  'Broken Heart',
-  'Red Heart',
-  'Orange Heart',
-  'Yellow Heart',
-  'Green Heart',
-  'Blue Heart',
-  'Purple Heart',
-  'Black Heart',
-  'Hundred Points',
-  'Anger Symbol',
-  'Speech Balloon',
-  'Eye in Speech Bubble',
-  'Right Anger Bubble',
-  'Thought Balloon',
-  'Zzz',
-  'White Flower',
-  'Hot Springs',
-  'Barber Pole',
-  'Stop Sign',
-  'Twelve O’Clock',
-  'Twelve-Thirty',
-  'One O’Clock',
-  'One-Thirty',
-  'Two O’Clock',
-  'Two-Thirty',
-  'Three O’Clock',
-  'Three-Thirty',
-  'Four O’Clock',
-  'Four-Thirty',
-  'Five O’Clock',
-  'Five-Thirty',
-  'Six O’Clock',
-  'Six-Thirty',
-  'Seven O’Clock',
-  'Seven-Thirty',
-  'Eight O’Clock',
-  'Eight-Thirty',
-  'Nine O’Clock',
-  'Nine-Thirty',
-  'Ten O’Clock',
-  'Ten-Thirty',
-  'Eleven O’Clock',
-  'Eleven-Thirty',
-  'Cyclone',
-  'Spade Suit',
-  'Heart Suit',
-  'Diamond Suit',
-  'Club Suit',
-  'Joker',
-  'Mahjong Red Dragon',
-  'Flower Playing Cards',
-  'Muted Speaker',
-  'Speaker Low Volume',
-  'Speaker Medium Volume',
-  'Speaker High Volume',
-  'Loudspeaker',
-  'Megaphone',
-  'Postal Horn',
-  'Bell',
-  'Bell With Slash',
-  'Musical Note',
-  'Musical Notes',
-  'ATM Sign',
-  'Litter in Bin Sign',
-  'Potable Water',
-  'Wheelchair Symbol',
-  'Men’s Room',
-  'Women’s Room',
-  'Restroom',
-  'Baby Symbol',
-  'Water Closet',
-  'Warning',
-  'Children Crossing',
-  'No Entry',
-  'Prohibited',
-  'No Bicycles',
-  'No Smoking',
-  'No Littering',
-  'Non-Potable Water',
-  'No Pedestrians',
-  'No One Under Eighteen',
-  'Radioactive',
-  'Biohazard',
-  'Up Arrow',
-  'Up-Right Arrow',
-  'Right Arrow',
-  'Down-Right Arrow',
-  'Down Arrow',
-  'Down-Left Arrow',
-  'Left Arrow',
-  'Up-Left Arrow',
-  'Up-Down Arrow',
-  'Left-Right Arrow',
-  'Right Arrow Curving Left',
-  'Left Arrow Curving Right',
-  'Right Arrow Curving Up',
-  'Right Arrow Curving Down',
-  'Clockwise Vertical Arrows',
-  'Counterclockwise Arrows Button',
-  'Back Arrow',
-  'End Arrow',
-  'On! Arrow',
-  'Soon Arrow',
-  'Top Arrow',
-  'Place of Worship',
-  'Atom Symbol',
-  'Om',
-  'Star of David',
-  'Wheel of Dharma',
-  'Yin Yang',
-  'Latin Cross',
-  'Orthodox Cross',
-  'Star and Crescent',
-  'Peace Symbol',
-  'Menorah',
-  'Dotted Six-Pointed Star',
-  'Aries',
-  'Taurus',
-  'Gemini',
-  'Cancer',
-  'Leo',
-  'Virgo',
-  'Libra',
-  'Scorpio',
-  'Sagittarius',
-  'Capricorn',
-  'Aquarius',
-  'Pisces',
-  'Ophiuchus',
-  'Shuffle Tracks Button',
-  'Repeat Button',
-  'Repeat Single Button',
-  'Play Button',
-  'Fast-Forward Button',
-  'Reverse Button',
-  'Fast Reverse Button',
-  'Upwards Button',
-  'Fast Up Button',
-  'Downwards Button',
-  'Fast Down Button',
-  'Stop Button',
-  'Eject Button',
-  'Cinema',
-  'Dim Button',
-  'Bright Button',
-  'Antenna Bars',
-  'Vibration Mode',
-  'Mobile Phone Off',
-  'Infinity',
-  'Recycling Symbol',
-  'Trident Emblem',
-  'Name Badge',
-  'Japanese Symbol for Beginner',
-  'Heavy Large Circle',
-  'White Heavy Check Mark',
-  'Ballot Box With Check',
-  'Heavy Check Mark',
-  'Heavy Multiplication X',
-  'Cross Mark',
-  'Cross Mark Button',
-  'Heavy Plus Sign',
-  'Heavy Minus Sign',
-  'Heavy Division Sign',
-  'Curly Loop',
-  'Double Curly Loop',
-  'Part Alternation Mark',
-  'Eight-Spoked Asterisk',
-  'Eight-Pointed Star',
-  'Sparkle',
-  'Double Exclamation Mark',
-  'Exclamation Question Mark',
-  'Question Mark',
-  'White Question Mark',
-  'White Exclamation Mark',
-  'Exclamation Mark',
-  'Copyright',
-  'Registered',
-  'Trade Mark',
-  'Keycap Number Sign',
-  'Keycap Digit Zero',
-  'Keycap Digit One',
-  'Keycap Digit Two',
-  'Keycap Digit Three',
-  'Keycap Digit Four',
-  'Keycap Digit Five',
-  'Keycap Digit Six',
-  'Keycap Digit Seven',
-  'Keycap Digit Eight',
-  'Keycap Digit Nine',
-  'Keycap: 10',
-  'Input Latin Uppercase',
-  'Input Latin Lowercase',
-  'Input Numbers',
-  'Input Symbols',
-  'Input Latin Letters',
-  'A Button (Blood Type)',
-  'AB Button (Blood Type)',
-  'B Button (Blood Type)',
-  'CL Button',
-  'Cool Button',
-  'Free Button',
-  'Information',
-  'ID Button',
-  'Circled M',
-  'New Button',
-  'NG Button',
-  'O Button (Blood Type)',
-  'OK Button',
-  'P Button',
-  'SOS Button',
-  'Up! Button',
-  'Vs Button',
-  'Japanese “Here” Button',
-  'Japanese “Service Charge” Button',
-  'Japanese “Monthly Amount” Button',
-  'Japanese “Not Free of Charge” Button',
-  'Japanese “Reserved” Button',
-  'Japanese “Bargain” Button',
-  'Japanese “Discount” Button',
-  'Japanese “Free of Charge” Button',
-  'Japanese “Prohibited” Button',
-  'Japanese “Acceptable” Button',
-  'Japanese “Application” Button',
-  'Japanese “Passing Grade” Button',
-  'Japanese “Vacancy” Button',
-  'Japanese “Congratulations” Button',
-  'Japanese “Secret” Button',
-  'Japanese “Open for Business” Button',
-  'Japanese “No Vacancy” Button',
-  'Red Circle',
-  'Blue Circle',
-  'Black Circle',
-  'White Circle',
-  'Black Large Square',
-  'White Large Square',
-  'Black Medium Square',
-  'White Medium Square',
-  'Black Medium-Small Square',
-  'White Medium-Small Square',
-  'Black Small Square',
-  'White Small Square',
-  'Large Orange Diamond',
-  'Large Blue Diamond',
-  'Small Orange Diamond',
-  'Small Blue Diamond',
-  'Red Triangle Pointed Up',
-  'Red Triangle Pointed Down',
-  'Diamond With a Dot',
-  'White Square Button',
-  'Black Square Button'
-], [
-  '💘',
-  '💝',
-  '💖',
-  '💗',
-  '💓',
-  '💞',
-  '💕',
-  '💟',
-  '❣',
-  '💔',
-  '❤',
-  '🧡',
-  '💛',
-  '💚',
-  '💙',
-  '💜',
-  '🖤',
-  '💯',
-  '💢',
-  '💬',
-  '👁️‍🗨️',
-  '🗯',
-  '💭',
-  '💤',
-  '💮',
-  '♨',
-  '💈',
-  '🛑',
-  '🕛',
-  '🕧',
-  '🕐',
-  '🕜',
-  '🕑',
-  '🕝',
-  '🕒',
-  '🕞',
-  '🕓',
-  '🕟',
-  '🕔',
-  '🕠',
-  '🕕',
-  '🕡',
-  '🕖',
-  '🕢',
-  '🕗',
-  '🕣',
-  '🕘',
-  '🕤',
-  '🕙',
-  '🕥',
-  '🕚',
-  '🕦',
-  '🌀',
-  '♠',
-  '♥',
-  '♦',
-  '♣',
-  '🃏',
-  '🀄',
-  '🎴',
-  '🔇',
-  '🔈',
-  '🔉',
-  '🔊',
-  '📢',
-  '📣',
-  '📯',
-  '🔔',
-  '🔕',
-  '🎵',
-  '🎶',
-  '🏧',
-  '🚮',
-  '🚰',
-  '♿',
-  '🚹',
-  '🚺',
-  '🚻',
-  '🚼',
-  '🚾',
-  '⚠',
-  '🚸',
-  '⛔',
-  '🚫',
-  '🚳',
-  '🚭',
-  '🚯',
-  '🚱',
-  '🚷',
-  '🔞',
-  '☢',
-  '☣',
-  '⬆',
-  '↗',
-  '➡',
-  '↘',
-  '⬇',
-  '↙',
-  '⬅',
-  '↖',
-  '↕',
-  '↔',
-  '↩',
-  '↪',
-  '⤴',
-  '⤵',
-  '🔃',
-  '🔄',
-  '🔙',
-  '🔚',
-  '🔛',
-  '🔜',
-  '🔝',
-  '🛐',
-  '⚛',
-  '🕉',
-  '✡',
-  '☸',
-  '☯',
-  '✝',
-  '☦',
-  '☪',
-  '☮',
-  '🕎',
-  '🔯',
-  '♈',
-  '♉',
-  '♊',
-  '♋',
-  '♌',
-  '♍',
-  '♎',
-  '♏',
-  '♐',
-  '♑',
-  '♒',
-  '♓',
-  '⛎',
-  '🔀',
-  '🔁',
-  '🔂',
-  '▶',
-  '⏩',
-  '◀',
-  '⏪',
-  '🔼',
-  '⏫',
-  '🔽',
-  '⏬',
-  '⏹',
-  '⏏',
-  '🎦',
-  '🔅',
-  '🔆',
-  '📶',
-  '📳',
-  '📴',
-  '♾',
-  '♻',
-  '🔱',
-  '📛',
-  '🔰',
-  '⭕',
-  '✅',
-  '☑',
-  '✔',
-  '✖',
-  '❌',
-  '❎',
-  '➕',
-  '➖',
-  '➗',
-  '➰',
-  '➿',
-  '〽',
-  '✳',
-  '✴',
-  '❇',
-  '‼',
-  '⁉',
-  '❓',
-  '❔',
-  '❕',
-  '❗',
-  '©',
-  '®',
-  '™',
-  '#️⃣',
-  '0️⃣',
-  '1️⃣',
-  '2️⃣',
-  '3️⃣',
-  '4️⃣',
-  '5️⃣',
-  '6️⃣',
-  '7️⃣',
-  '8️⃣',
-  '9️⃣',
-  '🔟',
-  '🔠',
-  '🔡',
-  '🔢',
-  '🔣',
-  '🔤',
-  '🅰',
-  '🆎',
-  '🅱',
-  '🆑',
-  '🆒',
-  '🆓',
-  'ℹ',
-  '🆔',
-  'Ⓜ',
-  '🆕',
-  '🆖',
-  '🅾',
-  '🆗',
-  '🅿',
-  '🆘',
-  '🆙',
-  '🆚',
-  '🈁',
-  '🈂',
-  '🈷',
-  '🈶',
-  '🈯',
-  '🉐',
-  '🈹',
-  '🈚',
-  '🈲',
-  '🉑',
-  '🈸',
-  '🈴',
-  '🈳',
-  '㊗',
-  '㊙',
-  '🈺',
-  '🈵',
-  '🔴',
-  '🔵',
-  '⚫',
-  '⚪',
-  '⬛',
-  '⬜',
-  '◼',
-  '◻',
-  '◾',
-  '◽',
-  '▪',
-  '▫',
-  '🔶',
-  '🔷',
-  '🔸',
-  '🔹',
-  '🔺',
-  '🔻',
-  '💠',
-  '🔳',
-  '🔲'
-]);
-
-/// Map of all possible emojis along with their names in [Category.FLAGS]
-final Map<String, String> flags = Map.fromIterables([
-  'Chequered Flag',
-  'Triangular Flag',
-  'Crossed Flags',
-  'Black Flag',
-  'White Flag',
-  'Rainbow Flag',
-  'Pirate Flag',
-  'Flag: Ascension Island',
-  'Flag: Andorra',
-  'Flag: United Arab Emirates',
-  'Flag: Afghanistan',
-  'Flag: Antigua &amp; Barbuda',
-  'Flag: Anguilla',
-  'Flag: Albania',
-  'Flag: Armenia',
-  'Flag: Angola',
-  'Flag: Antarctica',
-  'Flag: argentina',
-  'Flag: American Samoa',
-  'Flag: Austria',
-  'Flag: Australia',
-  'Flag: Aruba',
-  'Flag: Åland Islands',
-  'Flag: Azerbaijan',
-  'Flag: Bosnia &amp; Herzegovina',
-  'Flag: Barbados',
-  'Flag: Bangladesh',
-  'Flag: Belgium',
-  'Flag: Burkina Faso',
-  'Flag: Bulgaria',
-  'Flag: Bahrain',
-  'Flag: Burundi',
-  'Flag: Benin',
-  'Flag: St. Barthélemy',
-  'Flag: Bermuda',
-  'Flag: Brunei',
-  'Flag: Bolivia',
-  'Flag: Caribbean Netherlands',
-  'Flag: Brazil',
-  'Flag: Bahamas',
-  'Flag: Bhutan',
-  'Flag: Bouvet Island',
-  'Flag: Botswana',
-  'Flag: Belarus',
-  'Flag: Belize',
-  'Flag: Canada',
-  'Flag: Cocos (Keeling) Islands',
-  'Flag: Congo - Kinshasa',
-  'Flag: Central African Republic',
-  'Flag: Congo - Brazzaville',
-  'Flag: Switzerland',
-  'Flag: Côte d’Ivoire',
-  'Flag: Cook Islands',
-  'Flag: Chile',
-  'Flag: Cameroon',
-  'Flag: China',
-  'Flag: Colombia',
-  'Flag: Clipperton Island',
-  'Flag: Costa Rica',
-  'Flag: Cuba',
-  'Flag: Cape Verde',
-  'Flag: Curaçao',
-  'Flag: Christmas Island',
-  'Flag: Cyprus',
-  'Flag: Czechia',
-  'Flag: Germany',
-  'Flag: Diego Garcia',
-  'Flag: Djibouti',
-  'Flag: Denmark',
-  'Flag: Dominica',
-  'Flag: Dominican Republic',
-  'Flag: Algeria',
-  'Flag: Ceuta &amp; Melilla',
-  'Flag: Ecuador',
-  'Flag: Estonia',
-  'Flag: Egypt',
-  'Flag: Western Sahara',
-  'Flag: Eritrea',
-  'Flag: Spain',
-  'Flag: Ethiopia',
-  'Flag: European Union',
-  'Flag: Finland',
-  'Flag: Fiji',
-  'Flag: Falkland Islands',
-  'Flag: Micronesia',
-  'Flag: Faroe Islands',
-  'Flag: france',
-  'Flag: Gabon',
-  'Flag: United Kingdom',
-  'Flag: Grenada',
-  'Flag: Georgia',
-  'Flag: French Guiana',
-  'Flag: Guernsey',
-  'Flag: Ghana',
-  'Flag: Gibraltar',
-  'Flag: Greenland',
-  'Flag: Gambia',
-  'Flag: Guinea',
-  'Flag: Guadeloupe',
-  'Flag: Equatorial Guinea',
-  'Flag: Greece',
-  'Flag: South Georgia &amp; South Sandwich Islands',
-  'Flag: Guatemala',
-  'Flag: Guam',
-  'Flag: Guinea-Bissau',
-  'Flag: Guyana',
-  'Flag: Hong Kong SAR China',
-  'Flag: Heard &amp; McDonald Islands',
-  'Flag: Honduras',
-  'Flag: Croatia',
-  'Flag: Haiti',
-  'Flag: Hungary',
-  'Flag: Canary Islands',
-  'Flag: Indonesia',
-  'Flag: Ireland',
-  'Flag: Israel',
-  'Flag: Isle of Man',
-  'Flag: India',
-  'Flag: British Indian Ocean Territory',
-  'Flag: Iraq',
-  'Flag: Iran',
-  'Flag: Iceland',
-  'Flag: Italy',
-  'Flag: Jersey',
-  'Flag: Jamaica',
-  'Flag: Jordan',
-  'Flag: Japan',
-  'Flag: Kenya',
-  'Flag: Kyrgyzstan',
-  'Flag: Cambodia',
-  'Flag: Kiribati',
-  'Flag: Comoros',
-  'Flag: St. Kitts &amp; Nevis',
-  'Flag: North Korea',
-  'Flag: South Korea',
-  'Flag: Kuwait',
-  'Flag: Cayman Islands',
-  'Flag: Kazakhstan',
-  'Flag: Laos',
-  'Flag: Lebanon',
-  'Flag: St. Lucia',
-  'Flag: Liechtenstein',
-  'Flag: Sri Lanka',
-  'Flag: Liberia',
-  'Flag: Lesotho',
-  'Flag: Lithuania',
-  'Flag: Luxembourg',
-  'Flag: Latvia',
-  'Flag: Libya',
-  'Flag: Morocco',
-  'Flag: Monaco',
-  'Flag: Moldova',
-  'Flag: Montenegro',
-  'Flag: St. Martin',
-  'Flag: Madagascar',
-  'Flag: Marshall Islands',
-  'Flag: North Macedonia',
-  'Flag: Mali',
-  'Flag: Myanmar (Burma)',
-  'Flag: Mongolia',
-  'Flag: Macau Sar China',
-  'Flag: Northern Mariana Islands',
-  'Flag: Martinique',
-  'Flag: Mauritania',
-  'Flag: Montserrat',
-  'Flag: Malta',
-  'Flag: Mauritius',
-  'Flag: Maldives',
-  'Flag: Malawi',
-  'Flag: Mexico',
-  'Flag: Malaysia',
-  'Flag: Mozambique',
-  'Flag: Namibia',
-  'Flag: New Caledonia',
-  'Flag: Niger',
-  'Flag: Norfolk Island',
-  'Flag: Nigeria',
-  'Flag: Nicaragua',
-  'Flag: Netherlands',
-  'Flag: Norway',
-  'Flag: Nepal',
-  'Flag: Nauru',
-  'Flag: Niue',
-  'Flag: New Zealand',
-  'Flag: Oman',
-  'Flag: Panama',
-  'Flag: Peru',
-  'Flag: French Polynesia',
-  'Flag: Papua New Guinea',
-  'Flag: Philippines',
-  'Flag: Pakistan',
-  'Flag: Poland',
-  'Flag: St. Pierre &amp; Miquelon',
-  'Flag: Pitcairn Islands',
-  'Flag: Puerto Rico',
-  'Flag: Palestinian Territories',
-  'Flag: Portugal',
-  'Flag: Palau',
-  'Flag: Paraguay',
-  'Flag: Qatar',
-  'Flag: Réunion',
-  'Flag: Romania',
-  'Flag: Serbia',
-  'Flag: Russia',
-  'Flag: Rwanda',
-  'Flag: Saudi Arabia',
-  'Flag: Solomon Islands',
-  'Flag: Seychelles',
-  'Flag: Sudan',
-  'Flag: Sweden',
-  'Flag: Singapore',
-  'Flag: St. Helena',
-  'Flag: Slovenia',
-  'Flag: Svalbard &amp; Jan Mayen',
-  'Flag: Slovakia',
-  'Flag: Sierra Leone',
-  'Flag: San Marino',
-  'Flag: Senegal',
-  'Flag: Somalia',
-  'Flag: Suriname',
-  'Flag: South Sudan',
-  'Flag: São Tomé &amp; Príncipe',
-  'Flag: El Salvador',
-  'Flag: Sint Maarten',
-  'Flag: Syria',
-  'Flag: Swaziland',
-  'Flag: Tristan Da Cunha',
-  'Flag: Turks &amp; Caicos Islands',
-  'Flag: Chad',
-  'Flag: French Southern Territories',
-  'Flag: Togo',
-  'Flag: Thailand',
-  'Flag: Tajikistan',
-  'Flag: Tokelau',
-  'Flag: Timor-Leste',
-  'Flag: Turkmenistan',
-  'Flag: Tunisia',
-  'Flag: Tonga',
-  'Flag: Turkey',
-  'Flag: Trinidad &amp; Tobago',
-  'Flag: Tuvalu',
-  'Flag: Taiwan',
-  'Flag: Tanzania',
-  'Flag: Ukraine',
-  'Flag: Uganda',
-  'Flag: U.S. Outlying Islands',
-  'Flag: United Nations',
-  'Flag: United States',
-  'Flag: Uruguay',
-  'Flag: Uzbekistan',
-  'Flag: Vatican City',
-  'Flag: St. Vincent &amp; Grenadines',
-  'Flag: Venezuela',
-  'Flag: British Virgin Islands',
-  'Flag: U.S. Virgin Islands',
-  'Flag: Vietnam',
-  'Flag: Vanuatu',
-  'Flag: Wallis &amp; Futuna',
-  'Flag: Samoa',
-  'Flag: Kosovo',
-  'Flag: Yemen',
-  'Flag: Mayotte',
-  'Flag: South Africa',
-  'Flag: Zambia',
-  'Flag: Zimbabwe'
-], [
-  '🏁',
-  '🚩',
-  '🎌',
-  '🏴',
-  '🏳',
-  '🏳️‍🌈',
-  '🏴‍☠️',
-  '🇦🇨',
-  '🇦🇩',
-  '🇦🇪',
-  '🇦🇫',
-  '🇦🇬',
-  '🇦🇮',
-  '🇦🇱',
-  '🇦🇲',
-  '🇦🇴',
-  '🇦🇶',
-  '🇦🇷',
-  '🇦🇸',
-  '🇦🇹',
-  '🇦🇺',
-  '🇦🇼',
-  '🇦🇽',
-  '🇦🇿',
-  '🇧🇦',
-  '🇧🇧',
-  '🇧🇩',
-  '🇧🇪',
-  '🇧🇫',
-  '🇧🇬',
-  '🇧🇭',
-  '🇧🇮',
-  '🇧🇯',
-  '🇧🇱',
-  '🇧🇲',
-  '🇧🇳',
-  '🇧🇴',
-  '🇧🇶',
-  '🇧🇷',
-  '🇧🇸',
-  '🇧🇹',
-  '🇧🇻',
-  '🇧🇼',
-  '🇧🇾',
-  '🇧🇿',
-  '🇨🇦',
-  '🇨🇨',
-  '🇨🇩',
-  '🇨🇫',
-  '🇨🇬',
-  '🇨🇭',
-  '🇨🇮',
-  '🇨🇰',
-  '🇨🇱',
-  '🇨🇲',
-  '🇨🇳',
-  '🇨🇴',
-  '🇨🇵',
-  '🇨🇷',
-  '🇨🇺',
-  '🇨🇻',
-  '🇨🇼',
-  '🇨🇽',
-  '🇨🇾',
-  '🇨🇿',
-  '🇩🇪',
-  '🇩🇬',
-  '🇩🇯',
-  '🇩🇰',
-  '🇩🇲',
-  '🇩🇴',
-  '🇩🇿',
-  '🇪🇦',
-  '🇪🇨',
-  '🇪🇪',
-  '🇪🇬',
-  '🇪🇭',
-  '🇪🇷',
-  '🇪🇸',
-  '🇪🇹',
-  '🇪🇺',
-  '🇫🇮',
-  '🇫🇯',
-  '🇫🇰',
-  '🇫🇲',
-  '🇫🇴',
-  '🇫🇷',
-  '🇬🇦',
-  '🇬🇧',
-  '🇬🇩',
-  '🇬🇪',
-  '🇬🇫',
-  '🇬🇬',
-  '🇬🇭',
-  '🇬🇮',
-  '🇬🇱',
-  '🇬🇲',
-  '🇬🇳',
-  '🇬🇵',
-  '🇬🇶',
-  '🇬🇷',
-  '🇬🇸',
-  '🇬🇹',
-  '🇬🇺',
-  '🇬🇼',
-  '🇬🇾',
-  '🇭🇰',
-  '🇭🇲',
-  '🇭🇳',
-  '🇭🇷',
-  '🇭🇹',
-  '🇭🇺',
-  '🇮🇨',
-  '🇮🇩',
-  '🇮🇪',
-  '🇮🇱',
-  '🇮🇲',
-  '🇮🇳',
-  '🇮🇴',
-  '🇮🇶',
-  '🇮🇷',
-  '🇮🇸',
-  '🇮🇹',
-  '🇯🇪',
-  '🇯🇲',
-  '🇯🇴',
-  '🇯🇵',
-  '🇰🇪',
-  '🇰🇬',
-  '🇰🇭',
-  '🇰🇮',
-  '🇰🇲',
-  '🇰🇳',
-  '🇰🇵',
-  '🇰🇷',
-  '🇰🇼',
-  '🇰🇾',
-  '🇰🇿',
-  '🇱🇦',
-  '🇱🇧',
-  '🇱🇨',
-  '🇱🇮',
-  '🇱🇰',
-  '🇱🇷',
-  '🇱🇸',
-  '🇱🇹',
-  '🇱🇺',
-  '🇱🇻',
-  '🇱🇾',
-  '🇲🇦',
-  '🇲🇨',
-  '🇲🇩',
-  '🇲🇪',
-  '🇲🇫',
-  '🇲🇬',
-  '🇲🇭',
-  '🇲🇰',
-  '🇲🇱',
-  '🇲🇲',
-  '🇲🇳',
-  '🇲🇴',
-  '🇲🇵',
-  '🇲🇶',
-  '🇲🇷',
-  '🇲🇸',
-  '🇲🇹',
-  '🇲🇺',
-  '🇲🇻',
-  '🇲🇼',
-  '🇲🇽',
-  '🇲🇾',
-  '🇲🇿',
-  '🇳🇦',
-  '🇳🇨',
-  '🇳🇪',
-  '🇳🇫',
-  '🇳🇬',
-  '🇳🇮',
-  '🇳🇱',
-  '🇳🇴',
-  '🇳🇵',
-  '🇳🇷',
-  '🇳🇺',
-  '🇳🇿',
-  '🇴🇲',
-  '🇵🇦',
-  '🇵🇪',
-  '🇵🇫',
-  '🇵🇬',
-  '🇵🇭',
-  '🇵🇰',
-  '🇵🇱',
-  '🇵🇲',
-  '🇵🇳',
-  '🇵🇷',
-  '🇵🇸',
-  '🇵🇹',
-  '🇵🇼',
-  '🇵🇾',
-  '🇶🇦',
-  '🇷🇪',
-  '🇷🇴',
-  '🇷🇸',
-  '🇷🇺',
-  '🇷🇼',
-  '🇸🇦',
-  '🇸🇧',
-  '🇸🇨',
-  '🇸🇩',
-  '🇸🇪',
-  '🇸🇬',
-  '🇸🇭',
-  '🇸🇮',
-  '🇸🇯',
-  '🇸🇰',
-  '🇸🇱',
-  '🇸🇲',
-  '🇸🇳',
-  '🇸🇴',
-  '🇸🇷',
-  '🇸🇸',
-  '🇸🇹',
-  '🇸🇻',
-  '🇸🇽',
-  '🇸🇾',
-  '🇸🇿',
-  '🇹🇦',
-  '🇹🇨',
-  '🇹🇩',
-  '🇹🇫',
-  '🇹🇬',
-  '🇹🇭',
-  '🇹🇯',
-  '🇹🇰',
-  '🇹🇱',
-  '🇹🇲',
-  '🇹🇳',
-  '🇹🇴',
-  '🇹🇷',
-  '🇹🇹',
-  '🇹🇻',
-  '🇹🇼',
-  '🇹🇿',
-  '🇺🇦',
-  '🇺🇬',
-  '🇺🇲',
-  '🇺🇳',
-  '🇺🇸',
-  '🇺🇾',
-  '🇺🇿',
-  '🇻🇦',
-  '🇻🇨',
-  '🇻🇪',
-  '🇻🇬',
-  '🇻🇮',
-  '🇻🇳',
-  '🇻🇺',
-  '🇼🇫',
-  '🇼🇸',
-  '🇽🇰',
-  '🇾🇪',
-  '🇾🇹',
-  '🇿🇦',
-  '🇿🇲',
-  '🇿🇼'
-]);

+ 0 - 18
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/emoji_picker_builder.dart

@@ -1,18 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'config.dart';
-import 'emoji_view_state.dart';
-
-/// Template class for custom implementation
-/// Inherit this class to create your own EmojiPicker
-abstract class EmojiPickerBuilder extends StatefulWidget {
-  /// Constructor
-  const EmojiPickerBuilder(this.config, this.state, {Key? key})
-      : super(key: key);
-
-  /// Config for customizations
-  final Config config;
-
-  /// State that holds current emoji data
-  final EmojiViewState state;
-}

+ 0 - 21
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/emoji_view_state.dart

@@ -1,21 +0,0 @@
-import 'models/category_models.dart';
-import 'emoji_picker.dart';
-
-/// State that holds current emoji data
-class EmojiViewState {
-  /// Constructor
-  EmojiViewState(
-    this.categoryEmoji,
-    this.onEmojiSelected,
-    this.onBackspacePressed,
-  );
-
-  /// List of all category including their emoji
-  final List<CategoryEmoji> categoryEmoji;
-
-  /// Callback when pressed on emoji
-  final OnEmojiSelected onEmojiSelected;
-
-  /// Callback when pressed on backspace
-  final OnBackspacePressed? onBackspacePressed;
-}

+ 0 - 91
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/models/category_models.dart

@@ -1,91 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'emoji_model.dart';
-import '../emoji_picker.dart';
-
-/// Container for Category and their emoji
-class CategoryEmoji {
-  /// Constructor
-  CategoryEmoji(this.category, this.emoji);
-
-  /// Category instance
-  final Category category;
-
-  /// List of emoji of this category
-  List<Emoji> emoji;
-
-  @override
-  String toString() {
-    return 'Name: $category, Emoji: $emoji';
-  }
-}
-
-/// Class that defines the icon representing a [Category]
-class CategoryIcon {
-  /// Icon of Category
-  const CategoryIcon({
-    required this.icon,
-    this.color = const Color(0xffd3d3d3),
-    this.selectedColor = const Color(0xffb2b2b2),
-  });
-
-  /// The icon to represent the category
-  final IconData icon;
-
-  /// The default color of the icon
-  final Color color;
-
-  /// The color of the icon once the category is selected
-  final Color selectedColor;
-}
-
-/// Class used to define all the [CategoryIcon] shown for each [Category]
-///
-/// This allows the keyboard to be personalized by changing icons shown.
-/// If a [CategoryIcon] is set as null or not defined during initialization,
-/// the default icons will be used instead
-class CategoryIcons {
-  /// Constructor
-  const CategoryIcons({
-    this.recentIcon = Icons.access_time,
-    this.smileyIcon = Icons.tag_faces,
-    this.animalIcon = Icons.pets,
-    this.foodIcon = Icons.fastfood,
-    this.activityIcon = Icons.directions_run,
-    this.travelIcon = Icons.location_city,
-    this.objectIcon = Icons.lightbulb_outline,
-    this.symbolIcon = Icons.emoji_symbols,
-    this.flagIcon = Icons.flag,
-    this.searchIcon = Icons.search,
-  });
-
-  /// Icon for [Category.RECENT]
-  final IconData recentIcon;
-
-  /// Icon for [Category.SMILEYS]
-  final IconData smileyIcon;
-
-  /// Icon for [Category.ANIMALS]
-  final IconData animalIcon;
-
-  /// Icon for [Category.FOODS]
-  final IconData foodIcon;
-
-  /// Icon for [Category.ACTIVITIES]
-  final IconData activityIcon;
-
-  /// Icon for [Category.TRAVEL]
-  final IconData travelIcon;
-
-  /// Icon for [Category.OBJECTS]
-  final IconData objectIcon;
-
-  /// Icon for [Category.SYMBOLS]
-  final IconData symbolIcon;
-
-  /// Icon for [Category.FLAGS]
-  final IconData flagIcon;
-
-  /// Icon for [Category.SEARCH]
-  final IconData searchIcon;
-}

+ 0 - 32
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/models/emoji_model.dart

@@ -1,32 +0,0 @@
-/// A class to store data for each individual emoji
-class Emoji {
-  /// Emoji constructor
-  const Emoji(this.name, this.emoji);
-
-  /// The name or description for this emoji
-  final String name;
-
-  /// The unicode string for this emoji
-  ///
-  /// This is the string that should be displayed to view the emoji
-  final String emoji;
-
-  @override
-  String toString() {
-    // return 'Name: $name, Emoji: $emoji';
-    return name;
-  }
-
-  /// Parse Emoji from json
-  static Emoji fromJson(Map<String, dynamic> json) {
-    return Emoji(json['name'] as String, json['emoji'] as String);
-  }
-
-  ///  Encode Emoji to json
-  Map<String, dynamic> toJson() {
-    return {
-      'name': name,
-      'emoji': emoji,
-    };
-  }
-}

+ 0 - 30
frontend/appflowy_flutter/lib/workspace/presentation/widgets/emoji_picker/src/models/recent_emoji_model.dart

@@ -1,30 +0,0 @@
-import 'emoji_model.dart';
-
-/// Class that holds an recent emoji
-/// Recent Emoji has an instance of the emoji
-/// And a counter, which counts how often this emoji
-/// has been used before
-class RecentEmoji {
-  /// Constructor
-  RecentEmoji(this.emoji, this.counter);
-
-  /// Emoji instance
-  final Emoji emoji;
-
-  /// Counter how often emoji has been used before
-  int counter = 0;
-
-  /// Parse RecentEmoji from json
-  static RecentEmoji fromJson(dynamic json) {
-    return RecentEmoji(
-      Emoji.fromJson(json['emoji'] as Map<String, dynamic>),
-      json['counter'] as int,
-    );
-  }
-
-  /// Encode RecentEmoji to json
-  Map<String, dynamic> toJson() => {
-        'emoji': emoji,
-        'counter': counter,
-      };
-}

+ 2 - 2
frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/dandelion.dart

@@ -57,7 +57,7 @@ class DandelionColorScheme extends FlowyColorScheme {
           main1: _lightDandelionYellow,
           // cursor color
           main2: _lightDandelionYellow,
-          shadow: _black,
+          shadow: const Color.fromRGBO(0, 0, 0, 0.15),
           sidebarBg: _lightDandelionGreen,
           divider: _lightShader6,
           topbarBg: _white,
@@ -111,7 +111,7 @@ class DandelionColorScheme extends FlowyColorScheme {
           tint9: const Color(0x4d0029FF),
           main1: _darkMain1,
           main2: _darkMain1,
-          shadow: _black,
+          shadow: const Color(0xff0F131C),
           sidebarBg: const Color(0xff232B38),
           divider: _darkShader3,
           topbarBg: _darkShader1,

+ 1 - 1
frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/lavender.dart

@@ -107,7 +107,7 @@ class LavenderColorScheme extends FlowyColorScheme {
           tint9: const Color(0x4d0029FF),
           main1: _darkMain1,
           main2: _darkMain1,
-          shadow: _black,
+          shadow: const Color(0xff0F131C),
           sidebarBg: const Color(0xff2D223B),
           divider: _darkShader3,
           topbarBg: _darkShader1,

+ 5 - 2
frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scroll_bar.dart

@@ -124,8 +124,8 @@ class ScrollbarState extends State<StyledScrollbar> {
         // Track color
         var trackColor = widget.trackColor ??
             (Theme.of(context).brightness == Brightness.dark
-                ? AFThemeExtension.of(context).greyHover.withOpacity(.1)
-                : AFThemeExtension.of(context).greyHover.withOpacity(.3));
+                ? AFThemeExtension.of(context).lightGreyHover
+                : AFThemeExtension.of(context).greyHover);
 
         // Layout the stack, it just contains a child, and
         return Stack(
@@ -225,6 +225,7 @@ class ScrollbarListStack extends StatelessWidget {
   final EdgeInsets? scrollbarPadding;
   final Color? handleColor;
   final Color? trackColor;
+  final bool showTrack;
   final bool autoHideScrollbar;
 
   const ScrollbarListStack({
@@ -238,6 +239,7 @@ class ScrollbarListStack extends StatelessWidget {
     this.handleColor,
     this.autoHideScrollbar = true,
     this.trackColor,
+    this.showTrack = false,
   });
 
   @override
@@ -262,6 +264,7 @@ class ScrollbarListStack extends StatelessWidget {
             trackColor: trackColor,
             handleColor: handleColor,
             autoHideScrollbar: autoHideScrollbar,
+            showTrack: showTrack,
           ),
         )
             // The animate will be used by the children that using styled_widget.

+ 3 - 0
frontend/resources/translations/en.json

@@ -755,6 +755,9 @@
     "gray": "Gray"
   },
   "emoji": {
+    "search": "Search emoji",
+    "noRecent": "No recent emoji",
+    "noEmojiFound": "No emoji found",
     "filter": "Filter",
     "random": "Random",
     "selectSkinTone": "Select skin tone",