From 501432c819534eae063d30abe5ac90c71157744f Mon Sep 17 00:00:00 2001 From: Strycher Date: Fri, 12 Jun 2026 11:26:41 -0400 Subject: [PATCH] feat(#5): :shortcode: emoji autocomplete in the composer The maintainer's keyboard can't type emoji, so the composer now accepts :shortcode: input with an inline autocomplete: - Type `:` to open a bottom-anchored picker; arrows/Tab/click select, Esc dismisses. Best/exact match sits at the bottom, nearest the caret. - Enter completes an unambiguous emoji (single OR exact match) then sends, so `:rofl` + Enter ships the glyph, not the literal text. Ambiguous matches still send raw; Tab picks one deliberately. - A completed `:name:` (closing colon) auto-converts in place. - 1913 gemoji shortcodes bundled (lib/helpers/emoji_shortcodes.dart, MIT). - Byte-count aware via the existing ByteCountedTextField; shares the MentionAutocompleteField with @-mention input (both composers wired). Version 9.0.0+12 -> 9.1.0+14 (MINOR feature; build kept monotonic after the rebrand's +13 on the parallel chore/offband-rebrand branch). Grid/tap picker deferred (#5 follow-up). Co-Authored-By: Claude Opus 4.8 --- lib/helpers/emoji_shortcodes.dart | 1918 +++++++++++++++++++++++++ lib/screens/channel_chat_screen.dart | 2 + lib/screens/chat_screen.dart | 7 +- lib/widgets/mention_autocomplete.dart | 239 ++- pubspec.yaml | 2 +- 5 files changed, 2113 insertions(+), 55 deletions(-) create mode 100644 lib/helpers/emoji_shortcodes.dart diff --git a/lib/helpers/emoji_shortcodes.dart b/lib/helpers/emoji_shortcodes.dart new file mode 100644 index 0000000..55e4625 --- /dev/null +++ b/lib/helpers/emoji_shortcodes.dart @@ -0,0 +1,1918 @@ +// Emoji shortcode -> character map. Type :name: in a composer. +// Generated from github/gemoji (MIT licensed). Do not edit by hand. + +const Map emojiShortcodes = { + '+1': '๐Ÿ‘', + '-1': '๐Ÿ‘Ž', + '100': '๐Ÿ’ฏ', + '1234': '๐Ÿ”ข', + '1st_place_medal': '๐Ÿฅ‡', + '2nd_place_medal': '๐Ÿฅˆ', + '3rd_place_medal': '๐Ÿฅ‰', + '8ball': '๐ŸŽฑ', + 'a': '๐Ÿ…ฐ๏ธ', + 'ab': '๐Ÿ†Ž', + 'abacus': '๐Ÿงฎ', + 'abc': '๐Ÿ”ค', + 'abcd': '๐Ÿ”ก', + 'accept': '๐Ÿ‰‘', + 'accordion': '๐Ÿช—', + 'adhesive_bandage': '๐Ÿฉน', + 'adult': '๐Ÿง‘', + 'aerial_tramway': '๐Ÿšก', + 'afghanistan': '๐Ÿ‡ฆ๐Ÿ‡ซ', + 'airplane': 'โœˆ๏ธ', + 'aland_islands': '๐Ÿ‡ฆ๐Ÿ‡ฝ', + 'alarm_clock': 'โฐ', + 'albania': '๐Ÿ‡ฆ๐Ÿ‡ฑ', + 'alembic': 'โš—๏ธ', + 'algeria': '๐Ÿ‡ฉ๐Ÿ‡ฟ', + 'alien': '๐Ÿ‘ฝ', + 'ambulance': '๐Ÿš‘', + 'american_samoa': '๐Ÿ‡ฆ๐Ÿ‡ธ', + 'amphora': '๐Ÿบ', + 'anatomical_heart': '๐Ÿซ€', + 'anchor': 'โš“', + 'andorra': '๐Ÿ‡ฆ๐Ÿ‡ฉ', + 'angel': '๐Ÿ‘ผ', + 'anger': '๐Ÿ’ข', + 'angola': '๐Ÿ‡ฆ๐Ÿ‡ด', + 'angry': '๐Ÿ˜ ', + 'anguilla': '๐Ÿ‡ฆ๐Ÿ‡ฎ', + 'anguished': '๐Ÿ˜ง', + 'ant': '๐Ÿœ', + 'antarctica': '๐Ÿ‡ฆ๐Ÿ‡ถ', + 'antigua_barbuda': '๐Ÿ‡ฆ๐Ÿ‡ฌ', + 'apple': '๐ŸŽ', + 'aquarius': 'โ™’', + 'argentina': '๐Ÿ‡ฆ๐Ÿ‡ท', + 'aries': 'โ™ˆ', + 'armenia': '๐Ÿ‡ฆ๐Ÿ‡ฒ', + 'arrow_backward': 'โ—€๏ธ', + 'arrow_double_down': 'โฌ', + 'arrow_double_up': 'โซ', + 'arrow_down': 'โฌ‡๏ธ', + 'arrow_down_small': '๐Ÿ”ฝ', + 'arrow_forward': 'โ–ถ๏ธ', + 'arrow_heading_down': 'โคต๏ธ', + 'arrow_heading_up': 'โคด๏ธ', + 'arrow_left': 'โฌ…๏ธ', + 'arrow_lower_left': 'โ†™๏ธ', + 'arrow_lower_right': 'โ†˜๏ธ', + 'arrow_right': 'โžก๏ธ', + 'arrow_right_hook': 'โ†ช๏ธ', + 'arrow_up': 'โฌ†๏ธ', + 'arrow_up_down': 'โ†•๏ธ', + 'arrow_up_small': '๐Ÿ”ผ', + 'arrow_upper_left': 'โ†–๏ธ', + 'arrow_upper_right': 'โ†—๏ธ', + 'arrows_clockwise': '๐Ÿ”ƒ', + 'arrows_counterclockwise': '๐Ÿ”„', + 'art': '๐ŸŽจ', + 'articulated_lorry': '๐Ÿš›', + 'artificial_satellite': '๐Ÿ›ฐ๏ธ', + 'artist': '๐Ÿง‘โ€๐ŸŽจ', + 'aruba': '๐Ÿ‡ฆ๐Ÿ‡ผ', + 'ascension_island': '๐Ÿ‡ฆ๐Ÿ‡จ', + 'asterisk': '*๏ธโƒฃ', + 'astonished': '๐Ÿ˜ฒ', + 'astronaut': '๐Ÿง‘โ€๐Ÿš€', + 'athletic_shoe': '๐Ÿ‘Ÿ', + 'atm': '๐Ÿง', + 'atom_symbol': 'โš›๏ธ', + 'australia': '๐Ÿ‡ฆ๐Ÿ‡บ', + 'austria': '๐Ÿ‡ฆ๐Ÿ‡น', + 'auto_rickshaw': '๐Ÿ›บ', + 'avocado': '๐Ÿฅ‘', + 'axe': '๐Ÿช“', + 'azerbaijan': '๐Ÿ‡ฆ๐Ÿ‡ฟ', + 'b': '๐Ÿ…ฑ๏ธ', + 'baby': '๐Ÿ‘ถ', + 'baby_bottle': '๐Ÿผ', + 'baby_chick': '๐Ÿค', + 'baby_symbol': '๐Ÿšผ', + 'back': '๐Ÿ”™', + 'bacon': '๐Ÿฅ“', + 'badger': '๐Ÿฆก', + 'badminton': '๐Ÿธ', + 'bagel': '๐Ÿฅฏ', + 'baggage_claim': '๐Ÿ›„', + 'baguette_bread': '๐Ÿฅ–', + 'bahamas': '๐Ÿ‡ง๐Ÿ‡ธ', + 'bahrain': '๐Ÿ‡ง๐Ÿ‡ญ', + 'balance_scale': 'โš–๏ธ', + 'bald_man': '๐Ÿ‘จโ€๐Ÿฆฒ', + 'bald_woman': '๐Ÿ‘ฉโ€๐Ÿฆฒ', + 'ballet_shoes': '๐Ÿฉฐ', + 'balloon': '๐ŸŽˆ', + 'ballot_box': '๐Ÿ—ณ๏ธ', + 'ballot_box_with_check': 'โ˜‘๏ธ', + 'bamboo': '๐ŸŽ', + 'banana': '๐ŸŒ', + 'bangbang': 'โ€ผ๏ธ', + 'bangladesh': '๐Ÿ‡ง๐Ÿ‡ฉ', + 'banjo': '๐Ÿช•', + 'bank': '๐Ÿฆ', + 'bar_chart': '๐Ÿ“Š', + 'barbados': '๐Ÿ‡ง๐Ÿ‡ง', + 'barber': '๐Ÿ’ˆ', + 'baseball': 'โšพ', + 'basket': '๐Ÿงบ', + 'basketball': '๐Ÿ€', + 'basketball_man': 'โ›น๏ธโ€โ™‚๏ธ', + 'basketball_woman': 'โ›น๏ธโ€โ™€๏ธ', + 'bat': '๐Ÿฆ‡', + 'bath': '๐Ÿ›€', + 'bathtub': '๐Ÿ›', + 'battery': '๐Ÿ”‹', + 'beach_umbrella': '๐Ÿ–๏ธ', + 'beans': '๐Ÿซ˜', + 'bear': '๐Ÿป', + 'bearded_person': '๐Ÿง”', + 'beaver': '๐Ÿฆซ', + 'bed': '๐Ÿ›๏ธ', + 'bee': '๐Ÿ', + 'beer': '๐Ÿบ', + 'beers': '๐Ÿป', + 'beetle': '๐Ÿชฒ', + 'beginner': '๐Ÿ”ฐ', + 'belarus': '๐Ÿ‡ง๐Ÿ‡พ', + 'belgium': '๐Ÿ‡ง๐Ÿ‡ช', + 'belize': '๐Ÿ‡ง๐Ÿ‡ฟ', + 'bell': '๐Ÿ””', + 'bell_pepper': '๐Ÿซ‘', + 'bellhop_bell': '๐Ÿ›Ž๏ธ', + 'benin': '๐Ÿ‡ง๐Ÿ‡ฏ', + 'bento': '๐Ÿฑ', + 'bermuda': '๐Ÿ‡ง๐Ÿ‡ฒ', + 'beverage_box': '๐Ÿงƒ', + 'bhutan': '๐Ÿ‡ง๐Ÿ‡น', + 'bicyclist': '๐Ÿšด', + 'bike': '๐Ÿšฒ', + 'biking_man': '๐Ÿšดโ€โ™‚๏ธ', + 'biking_woman': '๐Ÿšดโ€โ™€๏ธ', + 'bikini': '๐Ÿ‘™', + 'billed_cap': '๐Ÿงข', + 'biohazard': 'โ˜ฃ๏ธ', + 'bird': '๐Ÿฆ', + 'birthday': '๐ŸŽ‚', + 'bison': '๐Ÿฆฌ', + 'biting_lip': '๐Ÿซฆ', + 'black_bird': '๐Ÿฆโ€โฌ›', + 'black_cat': '๐Ÿˆโ€โฌ›', + 'black_circle': 'โšซ', + 'black_flag': '๐Ÿด', + 'black_heart': '๐Ÿ–ค', + 'black_joker': '๐Ÿƒ', + 'black_large_square': 'โฌ›', + 'black_medium_small_square': 'โ—พ', + 'black_medium_square': 'โ—ผ๏ธ', + 'black_nib': 'โœ’๏ธ', + 'black_small_square': 'โ–ช๏ธ', + 'black_square_button': '๐Ÿ”ฒ', + 'blond_haired_man': '๐Ÿ‘ฑโ€โ™‚๏ธ', + 'blond_haired_person': '๐Ÿ‘ฑ', + 'blond_haired_woman': '๐Ÿ‘ฑโ€โ™€๏ธ', + 'blonde_woman': '๐Ÿ‘ฑโ€โ™€๏ธ', + 'blossom': '๐ŸŒผ', + 'blowfish': '๐Ÿก', + 'blue_book': '๐Ÿ“˜', + 'blue_car': '๐Ÿš™', + 'blue_heart': '๐Ÿ’™', + 'blue_square': '๐ŸŸฆ', + 'blueberries': '๐Ÿซ', + 'blush': '๐Ÿ˜Š', + 'boar': '๐Ÿ—', + 'boat': 'โ›ต', + 'bolivia': '๐Ÿ‡ง๐Ÿ‡ด', + 'bomb': '๐Ÿ’ฃ', + 'bone': '๐Ÿฆด', + 'book': '๐Ÿ“–', + 'bookmark': '๐Ÿ”–', + 'bookmark_tabs': '๐Ÿ“‘', + 'books': '๐Ÿ“š', + 'boom': '๐Ÿ’ฅ', + 'boomerang': '๐Ÿชƒ', + 'boot': '๐Ÿ‘ข', + 'bosnia_herzegovina': '๐Ÿ‡ง๐Ÿ‡ฆ', + 'botswana': '๐Ÿ‡ง๐Ÿ‡ผ', + 'bouncing_ball_man': 'โ›น๏ธโ€โ™‚๏ธ', + 'bouncing_ball_person': 'โ›น๏ธ', + 'bouncing_ball_woman': 'โ›น๏ธโ€โ™€๏ธ', + 'bouquet': '๐Ÿ’', + 'bouvet_island': '๐Ÿ‡ง๐Ÿ‡ป', + 'bow': '๐Ÿ™‡', + 'bow_and_arrow': '๐Ÿน', + 'bowing_man': '๐Ÿ™‡โ€โ™‚๏ธ', + 'bowing_woman': '๐Ÿ™‡โ€โ™€๏ธ', + 'bowl_with_spoon': '๐Ÿฅฃ', + 'bowling': '๐ŸŽณ', + 'boxing_glove': '๐ŸฅŠ', + 'boy': '๐Ÿ‘ฆ', + 'brain': '๐Ÿง ', + 'brazil': '๐Ÿ‡ง๐Ÿ‡ท', + 'bread': '๐Ÿž', + 'breast_feeding': '๐Ÿคฑ', + 'bricks': '๐Ÿงฑ', + 'bride_with_veil': '๐Ÿ‘ฐโ€โ™€๏ธ', + 'bridge_at_night': '๐ŸŒ‰', + 'briefcase': '๐Ÿ’ผ', + 'british_indian_ocean_territory': '๐Ÿ‡ฎ๐Ÿ‡ด', + 'british_virgin_islands': '๐Ÿ‡ป๐Ÿ‡ฌ', + 'broccoli': '๐Ÿฅฆ', + 'broken_heart': '๐Ÿ’”', + 'broom': '๐Ÿงน', + 'brown_circle': '๐ŸŸค', + 'brown_heart': '๐ŸคŽ', + 'brown_square': '๐ŸŸซ', + 'brunei': '๐Ÿ‡ง๐Ÿ‡ณ', + 'bubble_tea': '๐Ÿง‹', + 'bubbles': '๐Ÿซง', + 'bucket': '๐Ÿชฃ', + 'bug': '๐Ÿ›', + 'building_construction': '๐Ÿ—๏ธ', + 'bulb': '๐Ÿ’ก', + 'bulgaria': '๐Ÿ‡ง๐Ÿ‡ฌ', + 'bullettrain_front': '๐Ÿš…', + 'bullettrain_side': '๐Ÿš„', + 'burkina_faso': '๐Ÿ‡ง๐Ÿ‡ซ', + 'burrito': '๐ŸŒฏ', + 'burundi': '๐Ÿ‡ง๐Ÿ‡ฎ', + 'bus': '๐ŸšŒ', + 'business_suit_levitating': '๐Ÿ•ด๏ธ', + 'busstop': '๐Ÿš', + 'bust_in_silhouette': '๐Ÿ‘ค', + 'busts_in_silhouette': '๐Ÿ‘ฅ', + 'butter': '๐Ÿงˆ', + 'butterfly': '๐Ÿฆ‹', + 'cactus': '๐ŸŒต', + 'cake': '๐Ÿฐ', + 'calendar': '๐Ÿ“†', + 'call_me_hand': '๐Ÿค™', + 'calling': '๐Ÿ“ฒ', + 'cambodia': '๐Ÿ‡ฐ๐Ÿ‡ญ', + 'camel': '๐Ÿซ', + 'camera': '๐Ÿ“ท', + 'camera_flash': '๐Ÿ“ธ', + 'cameroon': '๐Ÿ‡จ๐Ÿ‡ฒ', + 'camping': '๐Ÿ•๏ธ', + 'canada': '๐Ÿ‡จ๐Ÿ‡ฆ', + 'canary_islands': '๐Ÿ‡ฎ๐Ÿ‡จ', + 'cancer': 'โ™‹', + 'candle': '๐Ÿ•ฏ๏ธ', + 'candy': '๐Ÿฌ', + 'canned_food': '๐Ÿฅซ', + 'canoe': '๐Ÿ›ถ', + 'cape_verde': '๐Ÿ‡จ๐Ÿ‡ป', + 'capital_abcd': '๐Ÿ” ', + 'capricorn': 'โ™‘', + 'car': '๐Ÿš—', + 'card_file_box': '๐Ÿ—ƒ๏ธ', + 'card_index': '๐Ÿ“‡', + 'card_index_dividers': '๐Ÿ—‚๏ธ', + 'caribbean_netherlands': '๐Ÿ‡ง๐Ÿ‡ถ', + 'carousel_horse': '๐ŸŽ ', + 'carpentry_saw': '๐Ÿชš', + 'carrot': '๐Ÿฅ•', + 'cartwheeling': '๐Ÿคธ', + 'cat': '๐Ÿฑ', + 'cat2': '๐Ÿˆ', + 'cayman_islands': '๐Ÿ‡ฐ๐Ÿ‡พ', + 'cd': '๐Ÿ’ฟ', + 'central_african_republic': '๐Ÿ‡จ๐Ÿ‡ซ', + 'ceuta_melilla': '๐Ÿ‡ช๐Ÿ‡ฆ', + 'chad': '๐Ÿ‡น๐Ÿ‡ฉ', + 'chains': 'โ›“๏ธ', + 'chair': '๐Ÿช‘', + 'champagne': '๐Ÿพ', + 'chart': '๐Ÿ’น', + 'chart_with_downwards_trend': '๐Ÿ“‰', + 'chart_with_upwards_trend': '๐Ÿ“ˆ', + 'checkered_flag': '๐Ÿ', + 'cheese': '๐Ÿง€', + 'cherries': '๐Ÿ’', + 'cherry_blossom': '๐ŸŒธ', + 'chess_pawn': 'โ™Ÿ๏ธ', + 'chestnut': '๐ŸŒฐ', + 'chicken': '๐Ÿ”', + 'child': '๐Ÿง’', + 'children_crossing': '๐Ÿšธ', + 'chile': '๐Ÿ‡จ๐Ÿ‡ฑ', + 'chipmunk': '๐Ÿฟ๏ธ', + 'chocolate_bar': '๐Ÿซ', + 'chopsticks': '๐Ÿฅข', + 'christmas_island': '๐Ÿ‡จ๐Ÿ‡ฝ', + 'christmas_tree': '๐ŸŽ„', + 'church': 'โ›ช', + 'cinema': '๐ŸŽฆ', + 'circus_tent': '๐ŸŽช', + 'city_sunrise': '๐ŸŒ‡', + 'city_sunset': '๐ŸŒ†', + 'cityscape': '๐Ÿ™๏ธ', + 'cl': '๐Ÿ†‘', + 'clamp': '๐Ÿ—œ๏ธ', + 'clap': '๐Ÿ‘', + 'clapper': '๐ŸŽฌ', + 'classical_building': '๐Ÿ›๏ธ', + 'climbing': '๐Ÿง—', + 'climbing_man': '๐Ÿง—โ€โ™‚๏ธ', + 'climbing_woman': '๐Ÿง—โ€โ™€๏ธ', + 'clinking_glasses': '๐Ÿฅ‚', + 'clipboard': '๐Ÿ“‹', + 'clipperton_island': '๐Ÿ‡จ๐Ÿ‡ต', + 'clock1': '๐Ÿ•', + 'clock10': '๐Ÿ•™', + 'clock1030': '๐Ÿ•ฅ', + 'clock11': '๐Ÿ•š', + 'clock1130': '๐Ÿ•ฆ', + 'clock12': '๐Ÿ•›', + 'clock1230': '๐Ÿ•ง', + 'clock130': '๐Ÿ•œ', + 'clock2': '๐Ÿ•‘', + 'clock230': '๐Ÿ•', + 'clock3': '๐Ÿ•’', + 'clock330': '๐Ÿ•ž', + 'clock4': '๐Ÿ•“', + 'clock430': '๐Ÿ•Ÿ', + 'clock5': '๐Ÿ•”', + 'clock530': '๐Ÿ• ', + 'clock6': '๐Ÿ••', + 'clock630': '๐Ÿ•ก', + 'clock7': '๐Ÿ•–', + 'clock730': '๐Ÿ•ข', + 'clock8': '๐Ÿ•—', + 'clock830': '๐Ÿ•ฃ', + 'clock9': '๐Ÿ•˜', + 'clock930': '๐Ÿ•ค', + 'closed_book': '๐Ÿ“•', + 'closed_lock_with_key': '๐Ÿ”', + 'closed_umbrella': '๐ŸŒ‚', + 'cloud': 'โ˜๏ธ', + 'cloud_with_lightning': '๐ŸŒฉ๏ธ', + 'cloud_with_lightning_and_rain': 'โ›ˆ๏ธ', + 'cloud_with_rain': '๐ŸŒง๏ธ', + 'cloud_with_snow': '๐ŸŒจ๏ธ', + 'clown_face': '๐Ÿคก', + 'clubs': 'โ™ฃ๏ธ', + 'cn': '๐Ÿ‡จ๐Ÿ‡ณ', + 'coat': '๐Ÿงฅ', + 'cockroach': '๐Ÿชณ', + 'cocktail': '๐Ÿธ', + 'coconut': '๐Ÿฅฅ', + 'cocos_islands': '๐Ÿ‡จ๐Ÿ‡จ', + 'coffee': 'โ˜•', + 'coffin': 'โšฐ๏ธ', + 'coin': '๐Ÿช™', + 'cold_face': '๐Ÿฅถ', + 'cold_sweat': '๐Ÿ˜ฐ', + 'collision': '๐Ÿ’ฅ', + 'colombia': '๐Ÿ‡จ๐Ÿ‡ด', + 'comet': 'โ˜„๏ธ', + 'comoros': '๐Ÿ‡ฐ๐Ÿ‡ฒ', + 'compass': '๐Ÿงญ', + 'computer': '๐Ÿ’ป', + 'computer_mouse': '๐Ÿ–ฑ๏ธ', + 'confetti_ball': '๐ŸŽŠ', + 'confounded': '๐Ÿ˜–', + 'confused': '๐Ÿ˜•', + 'congo_brazzaville': '๐Ÿ‡จ๐Ÿ‡ฌ', + 'congo_kinshasa': '๐Ÿ‡จ๐Ÿ‡ฉ', + 'congratulations': 'ใŠ—๏ธ', + 'construction': '๐Ÿšง', + 'construction_worker': '๐Ÿ‘ท', + 'construction_worker_man': '๐Ÿ‘ทโ€โ™‚๏ธ', + 'construction_worker_woman': '๐Ÿ‘ทโ€โ™€๏ธ', + 'control_knobs': '๐ŸŽ›๏ธ', + 'convenience_store': '๐Ÿช', + 'cook': '๐Ÿง‘โ€๐Ÿณ', + 'cook_islands': '๐Ÿ‡จ๐Ÿ‡ฐ', + 'cookie': '๐Ÿช', + 'cool': '๐Ÿ†’', + 'cop': '๐Ÿ‘ฎ', + 'copyright': 'ยฉ๏ธ', + 'coral': '๐Ÿชธ', + 'corn': '๐ŸŒฝ', + 'costa_rica': '๐Ÿ‡จ๐Ÿ‡ท', + 'cote_divoire': '๐Ÿ‡จ๐Ÿ‡ฎ', + 'couch_and_lamp': '๐Ÿ›‹๏ธ', + 'couple': '๐Ÿ‘ซ', + 'couple_with_heart': '๐Ÿ’‘', + 'couple_with_heart_man_man': '๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ', + 'couple_with_heart_woman_man': '๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ', + 'couple_with_heart_woman_woman': '๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ', + 'couplekiss': '๐Ÿ’', + 'couplekiss_man_man': '๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ', + 'couplekiss_man_woman': '๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ', + 'couplekiss_woman_woman': '๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ', + 'cow': '๐Ÿฎ', + 'cow2': '๐Ÿ„', + 'cowboy_hat_face': '๐Ÿค ', + 'crab': '๐Ÿฆ€', + 'crayon': '๐Ÿ–๏ธ', + 'credit_card': '๐Ÿ’ณ', + 'crescent_moon': '๐ŸŒ™', + 'cricket': '๐Ÿฆ—', + 'cricket_game': '๐Ÿ', + 'croatia': '๐Ÿ‡ญ๐Ÿ‡ท', + 'crocodile': '๐ŸŠ', + 'croissant': '๐Ÿฅ', + 'crossed_fingers': '๐Ÿคž', + 'crossed_flags': '๐ŸŽŒ', + 'crossed_swords': 'โš”๏ธ', + 'crown': '๐Ÿ‘‘', + 'crutch': '๐Ÿฉผ', + 'cry': '๐Ÿ˜ข', + 'crying_cat_face': '๐Ÿ˜ฟ', + 'crystal_ball': '๐Ÿ”ฎ', + 'cuba': '๐Ÿ‡จ๐Ÿ‡บ', + 'cucumber': '๐Ÿฅ’', + 'cup_with_straw': '๐Ÿฅค', + 'cupcake': '๐Ÿง', + 'cupid': '๐Ÿ’˜', + 'curacao': '๐Ÿ‡จ๐Ÿ‡ผ', + 'curling_stone': '๐ŸฅŒ', + 'curly_haired_man': '๐Ÿ‘จโ€๐Ÿฆฑ', + 'curly_haired_woman': '๐Ÿ‘ฉโ€๐Ÿฆฑ', + 'curly_loop': 'โžฐ', + 'currency_exchange': '๐Ÿ’ฑ', + 'curry': '๐Ÿ›', + 'cursing_face': '๐Ÿคฌ', + 'custard': '๐Ÿฎ', + 'customs': '๐Ÿ›ƒ', + 'cut_of_meat': '๐Ÿฅฉ', + 'cyclone': '๐ŸŒ€', + 'cyprus': '๐Ÿ‡จ๐Ÿ‡พ', + 'czech_republic': '๐Ÿ‡จ๐Ÿ‡ฟ', + 'dagger': '๐Ÿ—ก๏ธ', + 'dancer': '๐Ÿ’ƒ', + 'dancers': '๐Ÿ‘ฏ', + 'dancing_men': '๐Ÿ‘ฏโ€โ™‚๏ธ', + 'dancing_women': '๐Ÿ‘ฏโ€โ™€๏ธ', + 'dango': '๐Ÿก', + 'dark_sunglasses': '๐Ÿ•ถ๏ธ', + 'dart': '๐ŸŽฏ', + 'dash': '๐Ÿ’จ', + 'date': '๐Ÿ“…', + 'de': '๐Ÿ‡ฉ๐Ÿ‡ช', + 'deaf_man': '๐Ÿงโ€โ™‚๏ธ', + 'deaf_person': '๐Ÿง', + 'deaf_woman': '๐Ÿงโ€โ™€๏ธ', + 'deciduous_tree': '๐ŸŒณ', + 'deer': '๐ŸฆŒ', + 'denmark': '๐Ÿ‡ฉ๐Ÿ‡ฐ', + 'department_store': '๐Ÿฌ', + 'derelict_house': '๐Ÿš๏ธ', + 'desert': '๐Ÿœ๏ธ', + 'desert_island': '๐Ÿ๏ธ', + 'desktop_computer': '๐Ÿ–ฅ๏ธ', + 'detective': '๐Ÿ•ต๏ธ', + 'diamond_shape_with_a_dot_inside': '๐Ÿ’ ', + 'diamonds': 'โ™ฆ๏ธ', + 'diego_garcia': '๐Ÿ‡ฉ๐Ÿ‡ฌ', + 'disappointed': '๐Ÿ˜ž', + 'disappointed_relieved': '๐Ÿ˜ฅ', + 'disguised_face': '๐Ÿฅธ', + 'diving_mask': '๐Ÿคฟ', + 'diya_lamp': '๐Ÿช”', + 'dizzy': '๐Ÿ’ซ', + 'dizzy_face': '๐Ÿ˜ต', + 'djibouti': '๐Ÿ‡ฉ๐Ÿ‡ฏ', + 'dna': '๐Ÿงฌ', + 'do_not_litter': '๐Ÿšฏ', + 'dodo': '๐Ÿฆค', + 'dog': '๐Ÿถ', + 'dog2': '๐Ÿ•', + 'dollar': '๐Ÿ’ต', + 'dolls': '๐ŸŽŽ', + 'dolphin': '๐Ÿฌ', + 'dominica': '๐Ÿ‡ฉ๐Ÿ‡ฒ', + 'dominican_republic': '๐Ÿ‡ฉ๐Ÿ‡ด', + 'donkey': '๐Ÿซ', + 'door': '๐Ÿšช', + 'dotted_line_face': '๐Ÿซฅ', + 'doughnut': '๐Ÿฉ', + 'dove': '๐Ÿ•Š๏ธ', + 'dragon': '๐Ÿ‰', + 'dragon_face': '๐Ÿฒ', + 'dress': '๐Ÿ‘—', + 'dromedary_camel': '๐Ÿช', + 'drooling_face': '๐Ÿคค', + 'drop_of_blood': '๐Ÿฉธ', + 'droplet': '๐Ÿ’ง', + 'drum': '๐Ÿฅ', + 'duck': '๐Ÿฆ†', + 'dumpling': '๐ŸฅŸ', + 'dvd': '๐Ÿ“€', + 'e-mail': '๐Ÿ“ง', + 'eagle': '๐Ÿฆ…', + 'ear': '๐Ÿ‘‚', + 'ear_of_rice': '๐ŸŒพ', + 'ear_with_hearing_aid': '๐Ÿฆป', + 'earth_africa': '๐ŸŒ', + 'earth_americas': '๐ŸŒŽ', + 'earth_asia': '๐ŸŒ', + 'ecuador': '๐Ÿ‡ช๐Ÿ‡จ', + 'egg': '๐Ÿฅš', + 'eggplant': '๐Ÿ†', + 'egypt': '๐Ÿ‡ช๐Ÿ‡ฌ', + 'eight': '8๏ธโƒฃ', + 'eight_pointed_black_star': 'โœด๏ธ', + 'eight_spoked_asterisk': 'โœณ๏ธ', + 'eject_button': 'โ๏ธ', + 'el_salvador': '๐Ÿ‡ธ๐Ÿ‡ป', + 'electric_plug': '๐Ÿ”Œ', + 'elephant': '๐Ÿ˜', + 'elevator': '๐Ÿ›—', + 'elf': '๐Ÿง', + 'elf_man': '๐Ÿงโ€โ™‚๏ธ', + 'elf_woman': '๐Ÿงโ€โ™€๏ธ', + 'email': '๐Ÿ“ง', + 'empty_nest': '๐Ÿชน', + 'end': '๐Ÿ”š', + 'england': '๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ', + 'envelope': 'โœ‰๏ธ', + 'envelope_with_arrow': '๐Ÿ“ฉ', + 'equatorial_guinea': '๐Ÿ‡ฌ๐Ÿ‡ถ', + 'eritrea': '๐Ÿ‡ช๐Ÿ‡ท', + 'es': '๐Ÿ‡ช๐Ÿ‡ธ', + 'estonia': '๐Ÿ‡ช๐Ÿ‡ช', + 'ethiopia': '๐Ÿ‡ช๐Ÿ‡น', + 'eu': '๐Ÿ‡ช๐Ÿ‡บ', + 'euro': '๐Ÿ’ถ', + 'european_castle': '๐Ÿฐ', + 'european_post_office': '๐Ÿค', + 'european_union': '๐Ÿ‡ช๐Ÿ‡บ', + 'evergreen_tree': '๐ŸŒฒ', + 'exclamation': 'โ—', + 'exploding_head': '๐Ÿคฏ', + 'expressionless': '๐Ÿ˜‘', + 'eye': '๐Ÿ‘๏ธ', + 'eye_speech_bubble': '๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ', + 'eyeglasses': '๐Ÿ‘“', + 'eyes': '๐Ÿ‘€', + 'face_exhaling': '๐Ÿ˜ฎโ€๐Ÿ’จ', + 'face_holding_back_tears': '๐Ÿฅน', + 'face_in_clouds': '๐Ÿ˜ถโ€๐ŸŒซ๏ธ', + 'face_with_diagonal_mouth': '๐Ÿซค', + 'face_with_head_bandage': '๐Ÿค•', + 'face_with_open_eyes_and_hand_over_mouth': '๐Ÿซข', + 'face_with_peeking_eye': '๐Ÿซฃ', + 'face_with_spiral_eyes': '๐Ÿ˜ตโ€๐Ÿ’ซ', + 'face_with_thermometer': '๐Ÿค’', + 'facepalm': '๐Ÿคฆ', + 'facepunch': '๐Ÿ‘Š', + 'factory': '๐Ÿญ', + 'factory_worker': '๐Ÿง‘โ€๐Ÿญ', + 'fairy': '๐Ÿงš', + 'fairy_man': '๐Ÿงšโ€โ™‚๏ธ', + 'fairy_woman': '๐Ÿงšโ€โ™€๏ธ', + 'falafel': '๐Ÿง†', + 'falkland_islands': '๐Ÿ‡ซ๐Ÿ‡ฐ', + 'fallen_leaf': '๐Ÿ‚', + 'family': '๐Ÿ‘ช', + 'family_man_boy': '๐Ÿ‘จโ€๐Ÿ‘ฆ', + 'family_man_boy_boy': '๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ', + 'family_man_girl': '๐Ÿ‘จโ€๐Ÿ‘ง', + 'family_man_girl_boy': '๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ', + 'family_man_girl_girl': '๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง', + 'family_man_man_boy': '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ', + 'family_man_man_boy_boy': '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ', + 'family_man_man_girl': '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง', + 'family_man_man_girl_boy': '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ', + 'family_man_man_girl_girl': '๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง', + 'family_man_woman_boy': '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ', + 'family_man_woman_boy_boy': '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ', + 'family_man_woman_girl': '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง', + 'family_man_woman_girl_boy': '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ', + 'family_man_woman_girl_girl': '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง', + 'family_woman_boy': '๐Ÿ‘ฉโ€๐Ÿ‘ฆ', + 'family_woman_boy_boy': '๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ', + 'family_woman_girl': '๐Ÿ‘ฉโ€๐Ÿ‘ง', + 'family_woman_girl_boy': '๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ', + 'family_woman_girl_girl': '๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง', + 'family_woman_woman_boy': '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ', + 'family_woman_woman_boy_boy': '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ', + 'family_woman_woman_girl': '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง', + 'family_woman_woman_girl_boy': '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ', + 'family_woman_woman_girl_girl': '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง', + 'farmer': '๐Ÿง‘โ€๐ŸŒพ', + 'faroe_islands': '๐Ÿ‡ซ๐Ÿ‡ด', + 'fast_forward': 'โฉ', + 'fax': '๐Ÿ“ ', + 'fearful': '๐Ÿ˜จ', + 'feather': '๐Ÿชถ', + 'feet': '๐Ÿพ', + 'female_detective': '๐Ÿ•ต๏ธโ€โ™€๏ธ', + 'female_sign': 'โ™€๏ธ', + 'ferris_wheel': '๐ŸŽก', + 'ferry': 'โ›ด๏ธ', + 'field_hockey': '๐Ÿ‘', + 'fiji': '๐Ÿ‡ซ๐Ÿ‡ฏ', + 'file_cabinet': '๐Ÿ—„๏ธ', + 'file_folder': '๐Ÿ“', + 'film_projector': '๐Ÿ“ฝ๏ธ', + 'film_strip': '๐ŸŽž๏ธ', + 'finland': '๐Ÿ‡ซ๐Ÿ‡ฎ', + 'fire': '๐Ÿ”ฅ', + 'fire_engine': '๐Ÿš’', + 'fire_extinguisher': '๐Ÿงฏ', + 'firecracker': '๐Ÿงจ', + 'firefighter': '๐Ÿง‘โ€๐Ÿš’', + 'fireworks': '๐ŸŽ†', + 'first_quarter_moon': '๐ŸŒ“', + 'first_quarter_moon_with_face': '๐ŸŒ›', + 'fish': '๐ŸŸ', + 'fish_cake': '๐Ÿฅ', + 'fishing_pole_and_fish': '๐ŸŽฃ', + 'fist': 'โœŠ', + 'fist_left': '๐Ÿค›', + 'fist_oncoming': '๐Ÿ‘Š', + 'fist_raised': 'โœŠ', + 'fist_right': '๐Ÿคœ', + 'five': '5๏ธโƒฃ', + 'flags': '๐ŸŽ', + 'flamingo': '๐Ÿฆฉ', + 'flashlight': '๐Ÿ”ฆ', + 'flat_shoe': '๐Ÿฅฟ', + 'flatbread': '๐Ÿซ“', + 'fleur_de_lis': 'โšœ๏ธ', + 'flight_arrival': '๐Ÿ›ฌ', + 'flight_departure': '๐Ÿ›ซ', + 'flipper': '๐Ÿฌ', + 'floppy_disk': '๐Ÿ’พ', + 'flower_playing_cards': '๐ŸŽด', + 'flushed': '๐Ÿ˜ณ', + 'flute': '๐Ÿชˆ', + 'fly': '๐Ÿชฐ', + 'flying_disc': '๐Ÿฅ', + 'flying_saucer': '๐Ÿ›ธ', + 'fog': '๐ŸŒซ๏ธ', + 'foggy': '๐ŸŒ', + 'folding_hand_fan': '๐Ÿชญ', + 'fondue': '๐Ÿซ•', + 'foot': '๐Ÿฆถ', + 'football': '๐Ÿˆ', + 'footprints': '๐Ÿ‘ฃ', + 'fork_and_knife': '๐Ÿด', + 'fortune_cookie': '๐Ÿฅ ', + 'fountain': 'โ›ฒ', + 'fountain_pen': '๐Ÿ–‹๏ธ', + 'four': '4๏ธโƒฃ', + 'four_leaf_clover': '๐Ÿ€', + 'fox_face': '๐ŸฆŠ', + 'fr': '๐Ÿ‡ซ๐Ÿ‡ท', + 'framed_picture': '๐Ÿ–ผ๏ธ', + 'free': '๐Ÿ†“', + 'french_guiana': '๐Ÿ‡ฌ๐Ÿ‡ซ', + 'french_polynesia': '๐Ÿ‡ต๐Ÿ‡ซ', + 'french_southern_territories': '๐Ÿ‡น๐Ÿ‡ซ', + 'fried_egg': '๐Ÿณ', + 'fried_shrimp': '๐Ÿค', + 'fries': '๐ŸŸ', + 'frog': '๐Ÿธ', + 'frowning': '๐Ÿ˜ฆ', + 'frowning_face': 'โ˜น๏ธ', + 'frowning_man': '๐Ÿ™โ€โ™‚๏ธ', + 'frowning_person': '๐Ÿ™', + 'frowning_woman': '๐Ÿ™โ€โ™€๏ธ', + 'fu': '๐Ÿ–•', + 'fuelpump': 'โ›ฝ', + 'full_moon': '๐ŸŒ•', + 'full_moon_with_face': '๐ŸŒ', + 'funeral_urn': 'โšฑ๏ธ', + 'gabon': '๐Ÿ‡ฌ๐Ÿ‡ฆ', + 'gambia': '๐Ÿ‡ฌ๐Ÿ‡ฒ', + 'game_die': '๐ŸŽฒ', + 'garlic': '๐Ÿง„', + 'gb': '๐Ÿ‡ฌ๐Ÿ‡ง', + 'gear': 'โš™๏ธ', + 'gem': '๐Ÿ’Ž', + 'gemini': 'โ™Š', + 'genie': '๐Ÿงž', + 'genie_man': '๐Ÿงžโ€โ™‚๏ธ', + 'genie_woman': '๐Ÿงžโ€โ™€๏ธ', + 'georgia': '๐Ÿ‡ฌ๐Ÿ‡ช', + 'ghana': '๐Ÿ‡ฌ๐Ÿ‡ญ', + 'ghost': '๐Ÿ‘ป', + 'gibraltar': '๐Ÿ‡ฌ๐Ÿ‡ฎ', + 'gift': '๐ŸŽ', + 'gift_heart': '๐Ÿ’', + 'ginger_root': '๐Ÿซš', + 'giraffe': '๐Ÿฆ’', + 'girl': '๐Ÿ‘ง', + 'globe_with_meridians': '๐ŸŒ', + 'gloves': '๐Ÿงค', + 'goal_net': '๐Ÿฅ…', + 'goat': '๐Ÿ', + 'goggles': '๐Ÿฅฝ', + 'golf': 'โ›ณ', + 'golfing': '๐ŸŒ๏ธ', + 'golfing_man': '๐ŸŒ๏ธโ€โ™‚๏ธ', + 'golfing_woman': '๐ŸŒ๏ธโ€โ™€๏ธ', + 'goose': '๐Ÿชฟ', + 'gorilla': '๐Ÿฆ', + 'grapes': '๐Ÿ‡', + 'greece': '๐Ÿ‡ฌ๐Ÿ‡ท', + 'green_apple': '๐Ÿ', + 'green_book': '๐Ÿ“—', + 'green_circle': '๐ŸŸข', + 'green_heart': '๐Ÿ’š', + 'green_salad': '๐Ÿฅ—', + 'green_square': '๐ŸŸฉ', + 'greenland': '๐Ÿ‡ฌ๐Ÿ‡ฑ', + 'grenada': '๐Ÿ‡ฌ๐Ÿ‡ฉ', + 'grey_exclamation': 'โ•', + 'grey_heart': '๐Ÿฉถ', + 'grey_question': 'โ”', + 'grimacing': '๐Ÿ˜ฌ', + 'grin': '๐Ÿ˜', + 'grinning': '๐Ÿ˜€', + 'guadeloupe': '๐Ÿ‡ฌ๐Ÿ‡ต', + 'guam': '๐Ÿ‡ฌ๐Ÿ‡บ', + 'guard': '๐Ÿ’‚', + 'guardsman': '๐Ÿ’‚โ€โ™‚๏ธ', + 'guardswoman': '๐Ÿ’‚โ€โ™€๏ธ', + 'guatemala': '๐Ÿ‡ฌ๐Ÿ‡น', + 'guernsey': '๐Ÿ‡ฌ๐Ÿ‡ฌ', + 'guide_dog': '๐Ÿฆฎ', + 'guinea': '๐Ÿ‡ฌ๐Ÿ‡ณ', + 'guinea_bissau': '๐Ÿ‡ฌ๐Ÿ‡ผ', + 'guitar': '๐ŸŽธ', + 'gun': '๐Ÿ”ซ', + 'guyana': '๐Ÿ‡ฌ๐Ÿ‡พ', + 'hair_pick': '๐Ÿชฎ', + 'haircut': '๐Ÿ’‡', + 'haircut_man': '๐Ÿ’‡โ€โ™‚๏ธ', + 'haircut_woman': '๐Ÿ’‡โ€โ™€๏ธ', + 'haiti': '๐Ÿ‡ญ๐Ÿ‡น', + 'hamburger': '๐Ÿ”', + 'hammer': '๐Ÿ”จ', + 'hammer_and_pick': 'โš’๏ธ', + 'hammer_and_wrench': '๐Ÿ› ๏ธ', + 'hamsa': '๐Ÿชฌ', + 'hamster': '๐Ÿน', + 'hand': 'โœ‹', + 'hand_over_mouth': '๐Ÿคญ', + 'hand_with_index_finger_and_thumb_crossed': '๐Ÿซฐ', + 'handbag': '๐Ÿ‘œ', + 'handball_person': '๐Ÿคพ', + 'handshake': '๐Ÿค', + 'hankey': '๐Ÿ’ฉ', + 'hash': '#๏ธโƒฃ', + 'hatched_chick': '๐Ÿฅ', + 'hatching_chick': '๐Ÿฃ', + 'headphones': '๐ŸŽง', + 'headstone': '๐Ÿชฆ', + 'health_worker': '๐Ÿง‘โ€โš•๏ธ', + 'hear_no_evil': '๐Ÿ™‰', + 'heard_mcdonald_islands': '๐Ÿ‡ญ๐Ÿ‡ฒ', + 'heart': 'โค๏ธ', + 'heart_decoration': '๐Ÿ’Ÿ', + 'heart_eyes': '๐Ÿ˜', + 'heart_eyes_cat': '๐Ÿ˜ป', + 'heart_hands': '๐Ÿซถ', + 'heart_on_fire': 'โค๏ธโ€๐Ÿ”ฅ', + 'heartbeat': '๐Ÿ’“', + 'heartpulse': '๐Ÿ’—', + 'hearts': 'โ™ฅ๏ธ', + 'heavy_check_mark': 'โœ”๏ธ', + 'heavy_division_sign': 'โž—', + 'heavy_dollar_sign': '๐Ÿ’ฒ', + 'heavy_equals_sign': '๐ŸŸฐ', + 'heavy_exclamation_mark': 'โ—', + 'heavy_heart_exclamation': 'โฃ๏ธ', + 'heavy_minus_sign': 'โž–', + 'heavy_multiplication_x': 'โœ–๏ธ', + 'heavy_plus_sign': 'โž•', + 'hedgehog': '๐Ÿฆ”', + 'helicopter': '๐Ÿš', + 'herb': '๐ŸŒฟ', + 'hibiscus': '๐ŸŒบ', + 'high_brightness': '๐Ÿ”†', + 'high_heel': '๐Ÿ‘ ', + 'hiking_boot': '๐Ÿฅพ', + 'hindu_temple': '๐Ÿ›•', + 'hippopotamus': '๐Ÿฆ›', + 'hocho': '๐Ÿ”ช', + 'hole': '๐Ÿ•ณ๏ธ', + 'honduras': '๐Ÿ‡ญ๐Ÿ‡ณ', + 'honey_pot': '๐Ÿฏ', + 'honeybee': '๐Ÿ', + 'hong_kong': '๐Ÿ‡ญ๐Ÿ‡ฐ', + 'hook': '๐Ÿช', + 'horse': '๐Ÿด', + 'horse_racing': '๐Ÿ‡', + 'hospital': '๐Ÿฅ', + 'hot_face': '๐Ÿฅต', + 'hot_pepper': '๐ŸŒถ๏ธ', + 'hotdog': '๐ŸŒญ', + 'hotel': '๐Ÿจ', + 'hotsprings': 'โ™จ๏ธ', + 'hourglass': 'โŒ›', + 'hourglass_flowing_sand': 'โณ', + 'house': '๐Ÿ ', + 'house_with_garden': '๐Ÿก', + 'houses': '๐Ÿ˜๏ธ', + 'hugs': '๐Ÿค—', + 'hungary': '๐Ÿ‡ญ๐Ÿ‡บ', + 'hushed': '๐Ÿ˜ฏ', + 'hut': '๐Ÿ›–', + 'hyacinth': '๐Ÿชป', + 'ice_cream': '๐Ÿจ', + 'ice_cube': '๐ŸงŠ', + 'ice_hockey': '๐Ÿ’', + 'ice_skate': 'โ›ธ๏ธ', + 'icecream': '๐Ÿฆ', + 'iceland': '๐Ÿ‡ฎ๐Ÿ‡ธ', + 'id': '๐Ÿ†”', + 'identification_card': '๐Ÿชช', + 'ideograph_advantage': '๐Ÿ‰', + 'imp': '๐Ÿ‘ฟ', + 'inbox_tray': '๐Ÿ“ฅ', + 'incoming_envelope': '๐Ÿ“จ', + 'index_pointing_at_the_viewer': '๐Ÿซต', + 'india': '๐Ÿ‡ฎ๐Ÿ‡ณ', + 'indonesia': '๐Ÿ‡ฎ๐Ÿ‡ฉ', + 'infinity': 'โ™พ๏ธ', + 'information_desk_person': '๐Ÿ’', + 'information_source': 'โ„น๏ธ', + 'innocent': '๐Ÿ˜‡', + 'interrobang': 'โ‰๏ธ', + 'iphone': '๐Ÿ“ฑ', + 'iran': '๐Ÿ‡ฎ๐Ÿ‡ท', + 'iraq': '๐Ÿ‡ฎ๐Ÿ‡ถ', + 'ireland': '๐Ÿ‡ฎ๐Ÿ‡ช', + 'isle_of_man': '๐Ÿ‡ฎ๐Ÿ‡ฒ', + 'israel': '๐Ÿ‡ฎ๐Ÿ‡ฑ', + 'it': '๐Ÿ‡ฎ๐Ÿ‡น', + 'izakaya_lantern': '๐Ÿฎ', + 'jack_o_lantern': '๐ŸŽƒ', + 'jamaica': '๐Ÿ‡ฏ๐Ÿ‡ฒ', + 'japan': '๐Ÿ—พ', + 'japanese_castle': '๐Ÿฏ', + 'japanese_goblin': '๐Ÿ‘บ', + 'japanese_ogre': '๐Ÿ‘น', + 'jar': '๐Ÿซ™', + 'jeans': '๐Ÿ‘–', + 'jellyfish': '๐Ÿชผ', + 'jersey': '๐Ÿ‡ฏ๐Ÿ‡ช', + 'jigsaw': '๐Ÿงฉ', + 'jordan': '๐Ÿ‡ฏ๐Ÿ‡ด', + 'joy': '๐Ÿ˜‚', + 'joy_cat': '๐Ÿ˜น', + 'joystick': '๐Ÿ•น๏ธ', + 'jp': '๐Ÿ‡ฏ๐Ÿ‡ต', + 'judge': '๐Ÿง‘โ€โš–๏ธ', + 'juggling_person': '๐Ÿคน', + 'kaaba': '๐Ÿ•‹', + 'kangaroo': '๐Ÿฆ˜', + 'kazakhstan': '๐Ÿ‡ฐ๐Ÿ‡ฟ', + 'kenya': '๐Ÿ‡ฐ๐Ÿ‡ช', + 'key': '๐Ÿ”‘', + 'keyboard': 'โŒจ๏ธ', + 'keycap_ten': '๐Ÿ”Ÿ', + 'khanda': '๐Ÿชฏ', + 'kick_scooter': '๐Ÿ›ด', + 'kimono': '๐Ÿ‘˜', + 'kiribati': '๐Ÿ‡ฐ๐Ÿ‡ฎ', + 'kiss': '๐Ÿ’‹', + 'kissing': '๐Ÿ˜—', + 'kissing_cat': '๐Ÿ˜ฝ', + 'kissing_closed_eyes': '๐Ÿ˜š', + 'kissing_heart': '๐Ÿ˜˜', + 'kissing_smiling_eyes': '๐Ÿ˜™', + 'kite': '๐Ÿช', + 'kiwi_fruit': '๐Ÿฅ', + 'kneeling_man': '๐ŸงŽโ€โ™‚๏ธ', + 'kneeling_person': '๐ŸงŽ', + 'kneeling_woman': '๐ŸงŽโ€โ™€๏ธ', + 'knife': '๐Ÿ”ช', + 'knot': '๐Ÿชข', + 'koala': '๐Ÿจ', + 'koko': '๐Ÿˆ', + 'kosovo': '๐Ÿ‡ฝ๐Ÿ‡ฐ', + 'kr': '๐Ÿ‡ฐ๐Ÿ‡ท', + 'kuwait': '๐Ÿ‡ฐ๐Ÿ‡ผ', + 'kyrgyzstan': '๐Ÿ‡ฐ๐Ÿ‡ฌ', + 'lab_coat': '๐Ÿฅผ', + 'label': '๐Ÿท๏ธ', + 'lacrosse': '๐Ÿฅ', + 'ladder': '๐Ÿชœ', + 'lady_beetle': '๐Ÿž', + 'lantern': '๐Ÿฎ', + 'laos': '๐Ÿ‡ฑ๐Ÿ‡ฆ', + 'large_blue_circle': '๐Ÿ”ต', + 'large_blue_diamond': '๐Ÿ”ท', + 'large_orange_diamond': '๐Ÿ”ถ', + 'last_quarter_moon': '๐ŸŒ—', + 'last_quarter_moon_with_face': '๐ŸŒœ', + 'latin_cross': 'โœ๏ธ', + 'latvia': '๐Ÿ‡ฑ๐Ÿ‡ป', + 'laughing': '๐Ÿ˜†', + 'leafy_green': '๐Ÿฅฌ', + 'leaves': '๐Ÿƒ', + 'lebanon': '๐Ÿ‡ฑ๐Ÿ‡ง', + 'ledger': '๐Ÿ“’', + 'left_luggage': '๐Ÿ›…', + 'left_right_arrow': 'โ†”๏ธ', + 'left_speech_bubble': '๐Ÿ—จ๏ธ', + 'leftwards_arrow_with_hook': 'โ†ฉ๏ธ', + 'leftwards_hand': '๐Ÿซฒ', + 'leftwards_pushing_hand': '๐Ÿซท', + 'leg': '๐Ÿฆต', + 'lemon': '๐Ÿ‹', + 'leo': 'โ™Œ', + 'leopard': '๐Ÿ†', + 'lesotho': '๐Ÿ‡ฑ๐Ÿ‡ธ', + 'level_slider': '๐ŸŽš๏ธ', + 'liberia': '๐Ÿ‡ฑ๐Ÿ‡ท', + 'libra': 'โ™Ž', + 'libya': '๐Ÿ‡ฑ๐Ÿ‡พ', + 'liechtenstein': '๐Ÿ‡ฑ๐Ÿ‡ฎ', + 'light_blue_heart': '๐Ÿฉต', + 'light_rail': '๐Ÿšˆ', + 'link': '๐Ÿ”—', + 'lion': '๐Ÿฆ', + 'lips': '๐Ÿ‘„', + 'lipstick': '๐Ÿ’„', + 'lithuania': '๐Ÿ‡ฑ๐Ÿ‡น', + 'lizard': '๐ŸฆŽ', + 'llama': '๐Ÿฆ™', + 'lobster': '๐Ÿฆž', + 'lock': '๐Ÿ”’', + 'lock_with_ink_pen': '๐Ÿ”', + 'lollipop': '๐Ÿญ', + 'long_drum': '๐Ÿช˜', + 'loop': 'โžฟ', + 'lotion_bottle': '๐Ÿงด', + 'lotus': '๐Ÿชท', + 'lotus_position': '๐Ÿง˜', + 'lotus_position_man': '๐Ÿง˜โ€โ™‚๏ธ', + 'lotus_position_woman': '๐Ÿง˜โ€โ™€๏ธ', + 'loud_sound': '๐Ÿ”Š', + 'loudspeaker': '๐Ÿ“ข', + 'love_hotel': '๐Ÿฉ', + 'love_letter': '๐Ÿ’Œ', + 'love_you_gesture': '๐ŸคŸ', + 'low_battery': '๐Ÿชซ', + 'low_brightness': '๐Ÿ”…', + 'luggage': '๐Ÿงณ', + 'lungs': '๐Ÿซ', + 'luxembourg': '๐Ÿ‡ฑ๐Ÿ‡บ', + 'lying_face': '๐Ÿคฅ', + 'm': 'โ“‚๏ธ', + 'macau': '๐Ÿ‡ฒ๐Ÿ‡ด', + 'macedonia': '๐Ÿ‡ฒ๐Ÿ‡ฐ', + 'madagascar': '๐Ÿ‡ฒ๐Ÿ‡ฌ', + 'mag': '๐Ÿ”', + 'mag_right': '๐Ÿ”Ž', + 'mage': '๐Ÿง™', + 'mage_man': '๐Ÿง™โ€โ™‚๏ธ', + 'mage_woman': '๐Ÿง™โ€โ™€๏ธ', + 'magic_wand': '๐Ÿช„', + 'magnet': '๐Ÿงฒ', + 'mahjong': '๐Ÿ€„', + 'mailbox': '๐Ÿ“ซ', + 'mailbox_closed': '๐Ÿ“ช', + 'mailbox_with_mail': '๐Ÿ“ฌ', + 'mailbox_with_no_mail': '๐Ÿ“ญ', + 'malawi': '๐Ÿ‡ฒ๐Ÿ‡ผ', + 'malaysia': '๐Ÿ‡ฒ๐Ÿ‡พ', + 'maldives': '๐Ÿ‡ฒ๐Ÿ‡ป', + 'male_detective': '๐Ÿ•ต๏ธโ€โ™‚๏ธ', + 'male_sign': 'โ™‚๏ธ', + 'mali': '๐Ÿ‡ฒ๐Ÿ‡ฑ', + 'malta': '๐Ÿ‡ฒ๐Ÿ‡น', + 'mammoth': '๐Ÿฆฃ', + 'man': '๐Ÿ‘จ', + 'man_artist': '๐Ÿ‘จโ€๐ŸŽจ', + 'man_astronaut': '๐Ÿ‘จโ€๐Ÿš€', + 'man_beard': '๐Ÿง”โ€โ™‚๏ธ', + 'man_cartwheeling': '๐Ÿคธโ€โ™‚๏ธ', + 'man_cook': '๐Ÿ‘จโ€๐Ÿณ', + 'man_dancing': '๐Ÿ•บ', + 'man_facepalming': '๐Ÿคฆโ€โ™‚๏ธ', + 'man_factory_worker': '๐Ÿ‘จโ€๐Ÿญ', + 'man_farmer': '๐Ÿ‘จโ€๐ŸŒพ', + 'man_feeding_baby': '๐Ÿ‘จโ€๐Ÿผ', + 'man_firefighter': '๐Ÿ‘จโ€๐Ÿš’', + 'man_health_worker': '๐Ÿ‘จโ€โš•๏ธ', + 'man_in_manual_wheelchair': '๐Ÿ‘จโ€๐Ÿฆฝ', + 'man_in_motorized_wheelchair': '๐Ÿ‘จโ€๐Ÿฆผ', + 'man_in_tuxedo': '๐Ÿคตโ€โ™‚๏ธ', + 'man_judge': '๐Ÿ‘จโ€โš–๏ธ', + 'man_juggling': '๐Ÿคนโ€โ™‚๏ธ', + 'man_mechanic': '๐Ÿ‘จโ€๐Ÿ”ง', + 'man_office_worker': '๐Ÿ‘จโ€๐Ÿ’ผ', + 'man_pilot': '๐Ÿ‘จโ€โœˆ๏ธ', + 'man_playing_handball': '๐Ÿคพโ€โ™‚๏ธ', + 'man_playing_water_polo': '๐Ÿคฝโ€โ™‚๏ธ', + 'man_scientist': '๐Ÿ‘จโ€๐Ÿ”ฌ', + 'man_shrugging': '๐Ÿคทโ€โ™‚๏ธ', + 'man_singer': '๐Ÿ‘จโ€๐ŸŽค', + 'man_student': '๐Ÿ‘จโ€๐ŸŽ“', + 'man_teacher': '๐Ÿ‘จโ€๐Ÿซ', + 'man_technologist': '๐Ÿ‘จโ€๐Ÿ’ป', + 'man_with_gua_pi_mao': '๐Ÿ‘ฒ', + 'man_with_probing_cane': '๐Ÿ‘จโ€๐Ÿฆฏ', + 'man_with_turban': '๐Ÿ‘ณโ€โ™‚๏ธ', + 'man_with_veil': '๐Ÿ‘ฐโ€โ™‚๏ธ', + 'mandarin': '๐ŸŠ', + 'mango': '๐Ÿฅญ', + 'mans_shoe': '๐Ÿ‘ž', + 'mantelpiece_clock': '๐Ÿ•ฐ๏ธ', + 'manual_wheelchair': '๐Ÿฆฝ', + 'maple_leaf': '๐Ÿ', + 'maracas': '๐Ÿช‡', + 'marshall_islands': '๐Ÿ‡ฒ๐Ÿ‡ญ', + 'martial_arts_uniform': '๐Ÿฅ‹', + 'martinique': '๐Ÿ‡ฒ๐Ÿ‡ถ', + 'mask': '๐Ÿ˜ท', + 'massage': '๐Ÿ’†', + 'massage_man': '๐Ÿ’†โ€โ™‚๏ธ', + 'massage_woman': '๐Ÿ’†โ€โ™€๏ธ', + 'mate': '๐Ÿง‰', + 'mauritania': '๐Ÿ‡ฒ๐Ÿ‡ท', + 'mauritius': '๐Ÿ‡ฒ๐Ÿ‡บ', + 'mayotte': '๐Ÿ‡พ๐Ÿ‡น', + 'meat_on_bone': '๐Ÿ–', + 'mechanic': '๐Ÿง‘โ€๐Ÿ”ง', + 'mechanical_arm': '๐Ÿฆพ', + 'mechanical_leg': '๐Ÿฆฟ', + 'medal_military': '๐ŸŽ–๏ธ', + 'medal_sports': '๐Ÿ…', + 'medical_symbol': 'โš•๏ธ', + 'mega': '๐Ÿ“ฃ', + 'melon': '๐Ÿˆ', + 'melting_face': '๐Ÿซ ', + 'memo': '๐Ÿ“', + 'men_wrestling': '๐Ÿคผโ€โ™‚๏ธ', + 'mending_heart': 'โค๏ธโ€๐Ÿฉน', + 'menorah': '๐Ÿ•Ž', + 'mens': '๐Ÿšน', + 'mermaid': '๐Ÿงœโ€โ™€๏ธ', + 'merman': '๐Ÿงœโ€โ™‚๏ธ', + 'merperson': '๐Ÿงœ', + 'metal': '๐Ÿค˜', + 'metro': '๐Ÿš‡', + 'mexico': '๐Ÿ‡ฒ๐Ÿ‡ฝ', + 'microbe': '๐Ÿฆ ', + 'micronesia': '๐Ÿ‡ซ๐Ÿ‡ฒ', + 'microphone': '๐ŸŽค', + 'microscope': '๐Ÿ”ฌ', + 'middle_finger': '๐Ÿ–•', + 'military_helmet': '๐Ÿช–', + 'milk_glass': '๐Ÿฅ›', + 'milky_way': '๐ŸŒŒ', + 'minibus': '๐Ÿš', + 'minidisc': '๐Ÿ’ฝ', + 'mirror': '๐Ÿชž', + 'mirror_ball': '๐Ÿชฉ', + 'mobile_phone_off': '๐Ÿ“ด', + 'moldova': '๐Ÿ‡ฒ๐Ÿ‡ฉ', + 'monaco': '๐Ÿ‡ฒ๐Ÿ‡จ', + 'money_mouth_face': '๐Ÿค‘', + 'money_with_wings': '๐Ÿ’ธ', + 'moneybag': '๐Ÿ’ฐ', + 'mongolia': '๐Ÿ‡ฒ๐Ÿ‡ณ', + 'monkey': '๐Ÿ’', + 'monkey_face': '๐Ÿต', + 'monocle_face': '๐Ÿง', + 'monorail': '๐Ÿš', + 'montenegro': '๐Ÿ‡ฒ๐Ÿ‡ช', + 'montserrat': '๐Ÿ‡ฒ๐Ÿ‡ธ', + 'moon': '๐ŸŒ”', + 'moon_cake': '๐Ÿฅฎ', + 'moose': '๐ŸซŽ', + 'morocco': '๐Ÿ‡ฒ๐Ÿ‡ฆ', + 'mortar_board': '๐ŸŽ“', + 'mosque': '๐Ÿ•Œ', + 'mosquito': '๐ŸฆŸ', + 'motor_boat': '๐Ÿ›ฅ๏ธ', + 'motor_scooter': '๐Ÿ›ต', + 'motorcycle': '๐Ÿ๏ธ', + 'motorized_wheelchair': '๐Ÿฆผ', + 'motorway': '๐Ÿ›ฃ๏ธ', + 'mount_fuji': '๐Ÿ—ป', + 'mountain': 'โ›ฐ๏ธ', + 'mountain_bicyclist': '๐Ÿšต', + 'mountain_biking_man': '๐Ÿšตโ€โ™‚๏ธ', + 'mountain_biking_woman': '๐Ÿšตโ€โ™€๏ธ', + 'mountain_cableway': '๐Ÿš ', + 'mountain_railway': '๐Ÿšž', + 'mountain_snow': '๐Ÿ”๏ธ', + 'mouse': '๐Ÿญ', + 'mouse2': '๐Ÿ', + 'mouse_trap': '๐Ÿชค', + 'movie_camera': '๐ŸŽฅ', + 'moyai': '๐Ÿ—ฟ', + 'mozambique': '๐Ÿ‡ฒ๐Ÿ‡ฟ', + 'mrs_claus': '๐Ÿคถ', + 'muscle': '๐Ÿ’ช', + 'mushroom': '๐Ÿ„', + 'musical_keyboard': '๐ŸŽน', + 'musical_note': '๐ŸŽต', + 'musical_score': '๐ŸŽผ', + 'mute': '๐Ÿ”‡', + 'mx_claus': '๐Ÿง‘โ€๐ŸŽ„', + 'myanmar': '๐Ÿ‡ฒ๐Ÿ‡ฒ', + 'nail_care': '๐Ÿ’…', + 'name_badge': '๐Ÿ“›', + 'namibia': '๐Ÿ‡ณ๐Ÿ‡ฆ', + 'national_park': '๐Ÿž๏ธ', + 'nauru': '๐Ÿ‡ณ๐Ÿ‡ท', + 'nauseated_face': '๐Ÿคข', + 'nazar_amulet': '๐Ÿงฟ', + 'necktie': '๐Ÿ‘”', + 'negative_squared_cross_mark': 'โŽ', + 'nepal': '๐Ÿ‡ณ๐Ÿ‡ต', + 'nerd_face': '๐Ÿค“', + 'nest_with_eggs': '๐Ÿชบ', + 'nesting_dolls': '๐Ÿช†', + 'netherlands': '๐Ÿ‡ณ๐Ÿ‡ฑ', + 'neutral_face': '๐Ÿ˜', + 'new': '๐Ÿ†•', + 'new_caledonia': '๐Ÿ‡ณ๐Ÿ‡จ', + 'new_moon': '๐ŸŒ‘', + 'new_moon_with_face': '๐ŸŒš', + 'new_zealand': '๐Ÿ‡ณ๐Ÿ‡ฟ', + 'newspaper': '๐Ÿ“ฐ', + 'newspaper_roll': '๐Ÿ—ž๏ธ', + 'next_track_button': 'โญ๏ธ', + 'ng': '๐Ÿ†–', + 'ng_man': '๐Ÿ™…โ€โ™‚๏ธ', + 'ng_woman': '๐Ÿ™…โ€โ™€๏ธ', + 'nicaragua': '๐Ÿ‡ณ๐Ÿ‡ฎ', + 'niger': '๐Ÿ‡ณ๐Ÿ‡ช', + 'nigeria': '๐Ÿ‡ณ๐Ÿ‡ฌ', + 'night_with_stars': '๐ŸŒƒ', + 'nine': '9๏ธโƒฃ', + 'ninja': '๐Ÿฅท', + 'niue': '๐Ÿ‡ณ๐Ÿ‡บ', + 'no_bell': '๐Ÿ”•', + 'no_bicycles': '๐Ÿšณ', + 'no_entry': 'โ›”', + 'no_entry_sign': '๐Ÿšซ', + 'no_good': '๐Ÿ™…', + 'no_good_man': '๐Ÿ™…โ€โ™‚๏ธ', + 'no_good_woman': '๐Ÿ™…โ€โ™€๏ธ', + 'no_mobile_phones': '๐Ÿ“ต', + 'no_mouth': '๐Ÿ˜ถ', + 'no_pedestrians': '๐Ÿšท', + 'no_smoking': '๐Ÿšญ', + 'non-potable_water': '๐Ÿšฑ', + 'norfolk_island': '๐Ÿ‡ณ๐Ÿ‡ซ', + 'north_korea': '๐Ÿ‡ฐ๐Ÿ‡ต', + 'northern_mariana_islands': '๐Ÿ‡ฒ๐Ÿ‡ต', + 'norway': '๐Ÿ‡ณ๐Ÿ‡ด', + 'nose': '๐Ÿ‘ƒ', + 'notebook': '๐Ÿ““', + 'notebook_with_decorative_cover': '๐Ÿ“”', + 'notes': '๐ŸŽถ', + 'nut_and_bolt': '๐Ÿ”ฉ', + 'o': 'โญ•', + 'o2': '๐Ÿ…พ๏ธ', + 'ocean': '๐ŸŒŠ', + 'octopus': '๐Ÿ™', + 'oden': '๐Ÿข', + 'office': '๐Ÿข', + 'office_worker': '๐Ÿง‘โ€๐Ÿ’ผ', + 'oil_drum': '๐Ÿ›ข๏ธ', + 'ok': '๐Ÿ†—', + 'ok_hand': '๐Ÿ‘Œ', + 'ok_man': '๐Ÿ™†โ€โ™‚๏ธ', + 'ok_person': '๐Ÿ™†', + 'ok_woman': '๐Ÿ™†โ€โ™€๏ธ', + 'old_key': '๐Ÿ—๏ธ', + 'older_adult': '๐Ÿง“', + 'older_man': '๐Ÿ‘ด', + 'older_woman': '๐Ÿ‘ต', + 'olive': '๐Ÿซ’', + 'om': '๐Ÿ•‰๏ธ', + 'oman': '๐Ÿ‡ด๐Ÿ‡ฒ', + 'on': '๐Ÿ”›', + 'oncoming_automobile': '๐Ÿš˜', + 'oncoming_bus': '๐Ÿš', + 'oncoming_police_car': '๐Ÿš”', + 'oncoming_taxi': '๐Ÿš–', + 'one': '1๏ธโƒฃ', + 'one_piece_swimsuit': '๐Ÿฉฑ', + 'onion': '๐Ÿง…', + 'open_book': '๐Ÿ“–', + 'open_file_folder': '๐Ÿ“‚', + 'open_hands': '๐Ÿ‘', + 'open_mouth': '๐Ÿ˜ฎ', + 'open_umbrella': 'โ˜‚๏ธ', + 'ophiuchus': 'โ›Ž', + 'orange': '๐ŸŠ', + 'orange_book': '๐Ÿ“™', + 'orange_circle': '๐ŸŸ ', + 'orange_heart': '๐Ÿงก', + 'orange_square': '๐ŸŸง', + 'orangutan': '๐Ÿฆง', + 'orthodox_cross': 'โ˜ฆ๏ธ', + 'otter': '๐Ÿฆฆ', + 'outbox_tray': '๐Ÿ“ค', + 'owl': '๐Ÿฆ‰', + 'ox': '๐Ÿ‚', + 'oyster': '๐Ÿฆช', + 'package': '๐Ÿ“ฆ', + 'page_facing_up': '๐Ÿ“„', + 'page_with_curl': '๐Ÿ“ƒ', + 'pager': '๐Ÿ“Ÿ', + 'paintbrush': '๐Ÿ–Œ๏ธ', + 'pakistan': '๐Ÿ‡ต๐Ÿ‡ฐ', + 'palau': '๐Ÿ‡ต๐Ÿ‡ผ', + 'palestinian_territories': '๐Ÿ‡ต๐Ÿ‡ธ', + 'palm_down_hand': '๐Ÿซณ', + 'palm_tree': '๐ŸŒด', + 'palm_up_hand': '๐Ÿซด', + 'palms_up_together': '๐Ÿคฒ', + 'panama': '๐Ÿ‡ต๐Ÿ‡ฆ', + 'pancakes': '๐Ÿฅž', + 'panda_face': '๐Ÿผ', + 'paperclip': '๐Ÿ“Ž', + 'paperclips': '๐Ÿ–‡๏ธ', + 'papua_new_guinea': '๐Ÿ‡ต๐Ÿ‡ฌ', + 'parachute': '๐Ÿช‚', + 'paraguay': '๐Ÿ‡ต๐Ÿ‡พ', + 'parasol_on_ground': 'โ›ฑ๏ธ', + 'parking': '๐Ÿ…ฟ๏ธ', + 'parrot': '๐Ÿฆœ', + 'part_alternation_mark': 'ใ€ฝ๏ธ', + 'partly_sunny': 'โ›…', + 'partying_face': '๐Ÿฅณ', + 'passenger_ship': '๐Ÿ›ณ๏ธ', + 'passport_control': '๐Ÿ›‚', + 'pause_button': 'โธ๏ธ', + 'paw_prints': '๐Ÿพ', + 'pea_pod': '๐Ÿซ›', + 'peace_symbol': 'โ˜ฎ๏ธ', + 'peach': '๐Ÿ‘', + 'peacock': '๐Ÿฆš', + 'peanuts': '๐Ÿฅœ', + 'pear': '๐Ÿ', + 'pen': '๐Ÿ–Š๏ธ', + 'pencil': '๐Ÿ“', + 'pencil2': 'โœ๏ธ', + 'penguin': '๐Ÿง', + 'pensive': '๐Ÿ˜”', + 'people_holding_hands': '๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘', + 'people_hugging': '๐Ÿซ‚', + 'performing_arts': '๐ŸŽญ', + 'persevere': '๐Ÿ˜ฃ', + 'person_bald': '๐Ÿง‘โ€๐Ÿฆฒ', + 'person_curly_hair': '๐Ÿง‘โ€๐Ÿฆฑ', + 'person_feeding_baby': '๐Ÿง‘โ€๐Ÿผ', + 'person_fencing': '๐Ÿคบ', + 'person_in_manual_wheelchair': '๐Ÿง‘โ€๐Ÿฆฝ', + 'person_in_motorized_wheelchair': '๐Ÿง‘โ€๐Ÿฆผ', + 'person_in_tuxedo': '๐Ÿคต', + 'person_red_hair': '๐Ÿง‘โ€๐Ÿฆฐ', + 'person_white_hair': '๐Ÿง‘โ€๐Ÿฆณ', + 'person_with_crown': '๐Ÿซ…', + 'person_with_probing_cane': '๐Ÿง‘โ€๐Ÿฆฏ', + 'person_with_turban': '๐Ÿ‘ณ', + 'person_with_veil': '๐Ÿ‘ฐ', + 'peru': '๐Ÿ‡ต๐Ÿ‡ช', + 'petri_dish': '๐Ÿงซ', + 'philippines': '๐Ÿ‡ต๐Ÿ‡ญ', + 'phone': 'โ˜Ž๏ธ', + 'pick': 'โ›๏ธ', + 'pickup_truck': '๐Ÿ›ป', + 'pie': '๐Ÿฅง', + 'pig': '๐Ÿท', + 'pig2': '๐Ÿ–', + 'pig_nose': '๐Ÿฝ', + 'pill': '๐Ÿ’Š', + 'pilot': '๐Ÿง‘โ€โœˆ๏ธ', + 'pinata': '๐Ÿช…', + 'pinched_fingers': '๐ŸคŒ', + 'pinching_hand': '๐Ÿค', + 'pineapple': '๐Ÿ', + 'ping_pong': '๐Ÿ“', + 'pink_heart': '๐Ÿฉท', + 'pirate_flag': '๐Ÿดโ€โ˜ ๏ธ', + 'pisces': 'โ™“', + 'pitcairn_islands': '๐Ÿ‡ต๐Ÿ‡ณ', + 'pizza': '๐Ÿ•', + 'placard': '๐Ÿชง', + 'place_of_worship': '๐Ÿ›', + 'plate_with_cutlery': '๐Ÿฝ๏ธ', + 'play_or_pause_button': 'โฏ๏ธ', + 'playground_slide': '๐Ÿ›', + 'pleading_face': '๐Ÿฅบ', + 'plunger': '๐Ÿช ', + 'point_down': '๐Ÿ‘‡', + 'point_left': '๐Ÿ‘ˆ', + 'point_right': '๐Ÿ‘‰', + 'point_up': 'โ˜๏ธ', + 'point_up_2': '๐Ÿ‘†', + 'poland': '๐Ÿ‡ต๐Ÿ‡ฑ', + 'polar_bear': '๐Ÿปโ€โ„๏ธ', + 'police_car': '๐Ÿš“', + 'police_officer': '๐Ÿ‘ฎ', + 'policeman': '๐Ÿ‘ฎโ€โ™‚๏ธ', + 'policewoman': '๐Ÿ‘ฎโ€โ™€๏ธ', + 'poodle': '๐Ÿฉ', + 'poop': '๐Ÿ’ฉ', + 'popcorn': '๐Ÿฟ', + 'portugal': '๐Ÿ‡ต๐Ÿ‡น', + 'post_office': '๐Ÿฃ', + 'postal_horn': '๐Ÿ“ฏ', + 'postbox': '๐Ÿ“ฎ', + 'potable_water': '๐Ÿšฐ', + 'potato': '๐Ÿฅ”', + 'potted_plant': '๐Ÿชด', + 'pouch': '๐Ÿ‘', + 'poultry_leg': '๐Ÿ—', + 'pound': '๐Ÿ’ท', + 'pouring_liquid': '๐Ÿซ—', + 'pout': '๐Ÿ˜ก', + 'pouting_cat': '๐Ÿ˜พ', + 'pouting_face': '๐Ÿ™Ž', + 'pouting_man': '๐Ÿ™Žโ€โ™‚๏ธ', + 'pouting_woman': '๐Ÿ™Žโ€โ™€๏ธ', + 'pray': '๐Ÿ™', + 'prayer_beads': '๐Ÿ“ฟ', + 'pregnant_man': '๐Ÿซƒ', + 'pregnant_person': '๐Ÿซ„', + 'pregnant_woman': '๐Ÿคฐ', + 'pretzel': '๐Ÿฅจ', + 'previous_track_button': 'โฎ๏ธ', + 'prince': '๐Ÿคด', + 'princess': '๐Ÿ‘ธ', + 'printer': '๐Ÿ–จ๏ธ', + 'probing_cane': '๐Ÿฆฏ', + 'puerto_rico': '๐Ÿ‡ต๐Ÿ‡ท', + 'punch': '๐Ÿ‘Š', + 'purple_circle': '๐ŸŸฃ', + 'purple_heart': '๐Ÿ’œ', + 'purple_square': '๐ŸŸช', + 'purse': '๐Ÿ‘›', + 'pushpin': '๐Ÿ“Œ', + 'put_litter_in_its_place': '๐Ÿšฎ', + 'qatar': '๐Ÿ‡ถ๐Ÿ‡ฆ', + 'question': 'โ“', + 'rabbit': '๐Ÿฐ', + 'rabbit2': '๐Ÿ‡', + 'raccoon': '๐Ÿฆ', + 'racehorse': '๐ŸŽ', + 'racing_car': '๐ŸŽ๏ธ', + 'radio': '๐Ÿ“ป', + 'radio_button': '๐Ÿ”˜', + 'radioactive': 'โ˜ข๏ธ', + 'rage': '๐Ÿ˜ก', + 'railway_car': '๐Ÿšƒ', + 'railway_track': '๐Ÿ›ค๏ธ', + 'rainbow': '๐ŸŒˆ', + 'rainbow_flag': '๐Ÿณ๏ธโ€๐ŸŒˆ', + 'raised_back_of_hand': '๐Ÿคš', + 'raised_eyebrow': '๐Ÿคจ', + 'raised_hand': 'โœ‹', + 'raised_hand_with_fingers_splayed': '๐Ÿ–๏ธ', + 'raised_hands': '๐Ÿ™Œ', + 'raising_hand': '๐Ÿ™‹', + 'raising_hand_man': '๐Ÿ™‹โ€โ™‚๏ธ', + 'raising_hand_woman': '๐Ÿ™‹โ€โ™€๏ธ', + 'ram': '๐Ÿ', + 'ramen': '๐Ÿœ', + 'rat': '๐Ÿ€', + 'razor': '๐Ÿช’', + 'receipt': '๐Ÿงพ', + 'record_button': 'โบ๏ธ', + 'recycle': 'โ™ป๏ธ', + 'red_car': '๐Ÿš—', + 'red_circle': '๐Ÿ”ด', + 'red_envelope': '๐Ÿงง', + 'red_haired_man': '๐Ÿ‘จโ€๐Ÿฆฐ', + 'red_haired_woman': '๐Ÿ‘ฉโ€๐Ÿฆฐ', + 'red_square': '๐ŸŸฅ', + 'registered': 'ยฎ๏ธ', + 'relaxed': 'โ˜บ๏ธ', + 'relieved': '๐Ÿ˜Œ', + 'reminder_ribbon': '๐ŸŽ—๏ธ', + 'repeat': '๐Ÿ”', + 'repeat_one': '๐Ÿ”‚', + 'rescue_worker_helmet': 'โ›‘๏ธ', + 'restroom': '๐Ÿšป', + 'reunion': '๐Ÿ‡ท๐Ÿ‡ช', + 'revolving_hearts': '๐Ÿ’ž', + 'rewind': 'โช', + 'rhinoceros': '๐Ÿฆ', + 'ribbon': '๐ŸŽ€', + 'rice': '๐Ÿš', + 'rice_ball': '๐Ÿ™', + 'rice_cracker': '๐Ÿ˜', + 'rice_scene': '๐ŸŽ‘', + 'right_anger_bubble': '๐Ÿ—ฏ๏ธ', + 'rightwards_hand': '๐Ÿซฑ', + 'rightwards_pushing_hand': '๐Ÿซธ', + 'ring': '๐Ÿ’', + 'ring_buoy': '๐Ÿ›Ÿ', + 'ringed_planet': '๐Ÿช', + 'robot': '๐Ÿค–', + 'rock': '๐Ÿชจ', + 'rocket': '๐Ÿš€', + 'rofl': '๐Ÿคฃ', + 'roll_eyes': '๐Ÿ™„', + 'roll_of_paper': '๐Ÿงป', + 'roller_coaster': '๐ŸŽข', + 'roller_skate': '๐Ÿ›ผ', + 'romania': '๐Ÿ‡ท๐Ÿ‡ด', + 'rooster': '๐Ÿ“', + 'rose': '๐ŸŒน', + 'rosette': '๐Ÿต๏ธ', + 'rotating_light': '๐Ÿšจ', + 'round_pushpin': '๐Ÿ“', + 'rowboat': '๐Ÿšฃ', + 'rowing_man': '๐Ÿšฃโ€โ™‚๏ธ', + 'rowing_woman': '๐Ÿšฃโ€โ™€๏ธ', + 'ru': '๐Ÿ‡ท๐Ÿ‡บ', + 'rugby_football': '๐Ÿ‰', + 'runner': '๐Ÿƒ', + 'running': '๐Ÿƒ', + 'running_man': '๐Ÿƒโ€โ™‚๏ธ', + 'running_shirt_with_sash': '๐ŸŽฝ', + 'running_woman': '๐Ÿƒโ€โ™€๏ธ', + 'rwanda': '๐Ÿ‡ท๐Ÿ‡ผ', + 'sa': '๐Ÿˆ‚๏ธ', + 'safety_pin': '๐Ÿงท', + 'safety_vest': '๐Ÿฆบ', + 'sagittarius': 'โ™', + 'sailboat': 'โ›ต', + 'sake': '๐Ÿถ', + 'salt': '๐Ÿง‚', + 'saluting_face': '๐Ÿซก', + 'samoa': '๐Ÿ‡ผ๐Ÿ‡ธ', + 'san_marino': '๐Ÿ‡ธ๐Ÿ‡ฒ', + 'sandal': '๐Ÿ‘ก', + 'sandwich': '๐Ÿฅช', + 'santa': '๐ŸŽ…', + 'sao_tome_principe': '๐Ÿ‡ธ๐Ÿ‡น', + 'sari': '๐Ÿฅป', + 'sassy_man': '๐Ÿ’โ€โ™‚๏ธ', + 'sassy_woman': '๐Ÿ’โ€โ™€๏ธ', + 'satellite': '๐Ÿ“ก', + 'satisfied': '๐Ÿ˜†', + 'saudi_arabia': '๐Ÿ‡ธ๐Ÿ‡ฆ', + 'sauna_man': '๐Ÿง–โ€โ™‚๏ธ', + 'sauna_person': '๐Ÿง–', + 'sauna_woman': '๐Ÿง–โ€โ™€๏ธ', + 'sauropod': '๐Ÿฆ•', + 'saxophone': '๐ŸŽท', + 'scarf': '๐Ÿงฃ', + 'school': '๐Ÿซ', + 'school_satchel': '๐ŸŽ’', + 'scientist': '๐Ÿง‘โ€๐Ÿ”ฌ', + 'scissors': 'โœ‚๏ธ', + 'scorpion': '๐Ÿฆ‚', + 'scorpius': 'โ™', + 'scotland': '๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ', + 'scream': '๐Ÿ˜ฑ', + 'scream_cat': '๐Ÿ™€', + 'screwdriver': '๐Ÿช›', + 'scroll': '๐Ÿ“œ', + 'seal': '๐Ÿฆญ', + 'seat': '๐Ÿ’บ', + 'secret': 'ใŠ™๏ธ', + 'see_no_evil': '๐Ÿ™ˆ', + 'seedling': '๐ŸŒฑ', + 'selfie': '๐Ÿคณ', + 'senegal': '๐Ÿ‡ธ๐Ÿ‡ณ', + 'serbia': '๐Ÿ‡ท๐Ÿ‡ธ', + 'service_dog': '๐Ÿ•โ€๐Ÿฆบ', + 'seven': '7๏ธโƒฃ', + 'sewing_needle': '๐Ÿชก', + 'seychelles': '๐Ÿ‡ธ๐Ÿ‡จ', + 'shaking_face': '๐Ÿซจ', + 'shallow_pan_of_food': '๐Ÿฅ˜', + 'shamrock': 'โ˜˜๏ธ', + 'shark': '๐Ÿฆˆ', + 'shaved_ice': '๐Ÿง', + 'sheep': '๐Ÿ‘', + 'shell': '๐Ÿš', + 'shield': '๐Ÿ›ก๏ธ', + 'shinto_shrine': 'โ›ฉ๏ธ', + 'ship': '๐Ÿšข', + 'shirt': '๐Ÿ‘•', + 'shit': '๐Ÿ’ฉ', + 'shoe': '๐Ÿ‘ž', + 'shopping': '๐Ÿ›๏ธ', + 'shopping_cart': '๐Ÿ›’', + 'shorts': '๐Ÿฉณ', + 'shower': '๐Ÿšฟ', + 'shrimp': '๐Ÿฆ', + 'shrug': '๐Ÿคท', + 'shushing_face': '๐Ÿคซ', + 'sierra_leone': '๐Ÿ‡ธ๐Ÿ‡ฑ', + 'signal_strength': '๐Ÿ“ถ', + 'singapore': '๐Ÿ‡ธ๐Ÿ‡ฌ', + 'singer': '๐Ÿง‘โ€๐ŸŽค', + 'sint_maarten': '๐Ÿ‡ธ๐Ÿ‡ฝ', + 'six': '6๏ธโƒฃ', + 'six_pointed_star': '๐Ÿ”ฏ', + 'skateboard': '๐Ÿ›น', + 'ski': '๐ŸŽฟ', + 'skier': 'โ›ท๏ธ', + 'skull': '๐Ÿ’€', + 'skull_and_crossbones': 'โ˜ ๏ธ', + 'skunk': '๐Ÿฆจ', + 'sled': '๐Ÿ›ท', + 'sleeping': '๐Ÿ˜ด', + 'sleeping_bed': '๐Ÿ›Œ', + 'sleepy': '๐Ÿ˜ช', + 'slightly_frowning_face': '๐Ÿ™', + 'slightly_smiling_face': '๐Ÿ™‚', + 'slot_machine': '๐ŸŽฐ', + 'sloth': '๐Ÿฆฅ', + 'slovakia': '๐Ÿ‡ธ๐Ÿ‡ฐ', + 'slovenia': '๐Ÿ‡ธ๐Ÿ‡ฎ', + 'small_airplane': '๐Ÿ›ฉ๏ธ', + 'small_blue_diamond': '๐Ÿ”น', + 'small_orange_diamond': '๐Ÿ”ธ', + 'small_red_triangle': '๐Ÿ”บ', + 'small_red_triangle_down': '๐Ÿ”ป', + 'smile': '๐Ÿ˜„', + 'smile_cat': '๐Ÿ˜ธ', + 'smiley': '๐Ÿ˜ƒ', + 'smiley_cat': '๐Ÿ˜บ', + 'smiling_face_with_tear': '๐Ÿฅฒ', + 'smiling_face_with_three_hearts': '๐Ÿฅฐ', + 'smiling_imp': '๐Ÿ˜ˆ', + 'smirk': '๐Ÿ˜', + 'smirk_cat': '๐Ÿ˜ผ', + 'smoking': '๐Ÿšฌ', + 'snail': '๐ŸŒ', + 'snake': '๐Ÿ', + 'sneezing_face': '๐Ÿคง', + 'snowboarder': '๐Ÿ‚', + 'snowflake': 'โ„๏ธ', + 'snowman': 'โ›„', + 'snowman_with_snow': 'โ˜ƒ๏ธ', + 'soap': '๐Ÿงผ', + 'sob': '๐Ÿ˜ญ', + 'soccer': 'โšฝ', + 'socks': '๐Ÿงฆ', + 'softball': '๐ŸฅŽ', + 'solomon_islands': '๐Ÿ‡ธ๐Ÿ‡ง', + 'somalia': '๐Ÿ‡ธ๐Ÿ‡ด', + 'soon': '๐Ÿ”œ', + 'sos': '๐Ÿ†˜', + 'sound': '๐Ÿ”‰', + 'south_africa': '๐Ÿ‡ฟ๐Ÿ‡ฆ', + 'south_georgia_south_sandwich_islands': '๐Ÿ‡ฌ๐Ÿ‡ธ', + 'south_sudan': '๐Ÿ‡ธ๐Ÿ‡ธ', + 'space_invader': '๐Ÿ‘พ', + 'spades': 'โ™ ๏ธ', + 'spaghetti': '๐Ÿ', + 'sparkle': 'โ‡๏ธ', + 'sparkler': '๐ŸŽ‡', + 'sparkles': 'โœจ', + 'sparkling_heart': '๐Ÿ’–', + 'speak_no_evil': '๐Ÿ™Š', + 'speaker': '๐Ÿ”ˆ', + 'speaking_head': '๐Ÿ—ฃ๏ธ', + 'speech_balloon': '๐Ÿ’ฌ', + 'speedboat': '๐Ÿšค', + 'spider': '๐Ÿ•ท๏ธ', + 'spider_web': '๐Ÿ•ธ๏ธ', + 'spiral_calendar': '๐Ÿ—“๏ธ', + 'spiral_notepad': '๐Ÿ—’๏ธ', + 'sponge': '๐Ÿงฝ', + 'spoon': '๐Ÿฅ„', + 'squid': '๐Ÿฆ‘', + 'sri_lanka': '๐Ÿ‡ฑ๐Ÿ‡ฐ', + 'st_barthelemy': '๐Ÿ‡ง๐Ÿ‡ฑ', + 'st_helena': '๐Ÿ‡ธ๐Ÿ‡ญ', + 'st_kitts_nevis': '๐Ÿ‡ฐ๐Ÿ‡ณ', + 'st_lucia': '๐Ÿ‡ฑ๐Ÿ‡จ', + 'st_martin': '๐Ÿ‡ฒ๐Ÿ‡ซ', + 'st_pierre_miquelon': '๐Ÿ‡ต๐Ÿ‡ฒ', + 'st_vincent_grenadines': '๐Ÿ‡ป๐Ÿ‡จ', + 'stadium': '๐ŸŸ๏ธ', + 'standing_man': '๐Ÿงโ€โ™‚๏ธ', + 'standing_person': '๐Ÿง', + 'standing_woman': '๐Ÿงโ€โ™€๏ธ', + 'star': 'โญ', + 'star2': '๐ŸŒŸ', + 'star_and_crescent': 'โ˜ช๏ธ', + 'star_of_david': 'โœก๏ธ', + 'star_struck': '๐Ÿคฉ', + 'stars': '๐ŸŒ ', + 'station': '๐Ÿš‰', + 'statue_of_liberty': '๐Ÿ—ฝ', + 'steam_locomotive': '๐Ÿš‚', + 'stethoscope': '๐Ÿฉบ', + 'stew': '๐Ÿฒ', + 'stop_button': 'โน๏ธ', + 'stop_sign': '๐Ÿ›‘', + 'stopwatch': 'โฑ๏ธ', + 'straight_ruler': '๐Ÿ“', + 'strawberry': '๐Ÿ“', + 'stuck_out_tongue': '๐Ÿ˜›', + 'stuck_out_tongue_closed_eyes': '๐Ÿ˜', + 'stuck_out_tongue_winking_eye': '๐Ÿ˜œ', + 'student': '๐Ÿง‘โ€๐ŸŽ“', + 'studio_microphone': '๐ŸŽ™๏ธ', + 'stuffed_flatbread': '๐Ÿฅ™', + 'sudan': '๐Ÿ‡ธ๐Ÿ‡ฉ', + 'sun_behind_large_cloud': '๐ŸŒฅ๏ธ', + 'sun_behind_rain_cloud': '๐ŸŒฆ๏ธ', + 'sun_behind_small_cloud': '๐ŸŒค๏ธ', + 'sun_with_face': '๐ŸŒž', + 'sunflower': '๐ŸŒป', + 'sunglasses': '๐Ÿ˜Ž', + 'sunny': 'โ˜€๏ธ', + 'sunrise': '๐ŸŒ…', + 'sunrise_over_mountains': '๐ŸŒ„', + 'superhero': '๐Ÿฆธ', + 'superhero_man': '๐Ÿฆธโ€โ™‚๏ธ', + 'superhero_woman': '๐Ÿฆธโ€โ™€๏ธ', + 'supervillain': '๐Ÿฆน', + 'supervillain_man': '๐Ÿฆนโ€โ™‚๏ธ', + 'supervillain_woman': '๐Ÿฆนโ€โ™€๏ธ', + 'surfer': '๐Ÿ„', + 'surfing_man': '๐Ÿ„โ€โ™‚๏ธ', + 'surfing_woman': '๐Ÿ„โ€โ™€๏ธ', + 'suriname': '๐Ÿ‡ธ๐Ÿ‡ท', + 'sushi': '๐Ÿฃ', + 'suspension_railway': '๐ŸšŸ', + 'svalbard_jan_mayen': '๐Ÿ‡ธ๐Ÿ‡ฏ', + 'swan': '๐Ÿฆข', + 'swaziland': '๐Ÿ‡ธ๐Ÿ‡ฟ', + 'sweat': '๐Ÿ˜“', + 'sweat_drops': '๐Ÿ’ฆ', + 'sweat_smile': '๐Ÿ˜…', + 'sweden': '๐Ÿ‡ธ๐Ÿ‡ช', + 'sweet_potato': '๐Ÿ ', + 'swim_brief': '๐Ÿฉฒ', + 'swimmer': '๐ŸŠ', + 'swimming_man': '๐ŸŠโ€โ™‚๏ธ', + 'swimming_woman': '๐ŸŠโ€โ™€๏ธ', + 'switzerland': '๐Ÿ‡จ๐Ÿ‡ญ', + 'symbols': '๐Ÿ”ฃ', + 'synagogue': '๐Ÿ•', + 'syria': '๐Ÿ‡ธ๐Ÿ‡พ', + 'syringe': '๐Ÿ’‰', + 't-rex': '๐Ÿฆ–', + 'taco': '๐ŸŒฎ', + 'tada': '๐ŸŽ‰', + 'taiwan': '๐Ÿ‡น๐Ÿ‡ผ', + 'tajikistan': '๐Ÿ‡น๐Ÿ‡ฏ', + 'takeout_box': '๐Ÿฅก', + 'tamale': '๐Ÿซ”', + 'tanabata_tree': '๐ŸŽ‹', + 'tangerine': '๐ŸŠ', + 'tanzania': '๐Ÿ‡น๐Ÿ‡ฟ', + 'taurus': 'โ™‰', + 'taxi': '๐Ÿš•', + 'tea': '๐Ÿต', + 'teacher': '๐Ÿง‘โ€๐Ÿซ', + 'teapot': '๐Ÿซ–', + 'technologist': '๐Ÿง‘โ€๐Ÿ’ป', + 'teddy_bear': '๐Ÿงธ', + 'telephone': 'โ˜Ž๏ธ', + 'telephone_receiver': '๐Ÿ“ž', + 'telescope': '๐Ÿ”ญ', + 'tennis': '๐ŸŽพ', + 'tent': 'โ›บ', + 'test_tube': '๐Ÿงช', + 'thailand': '๐Ÿ‡น๐Ÿ‡ญ', + 'thermometer': '๐ŸŒก๏ธ', + 'thinking': '๐Ÿค”', + 'thong_sandal': '๐Ÿฉด', + 'thought_balloon': '๐Ÿ’ญ', + 'thread': '๐Ÿงต', + 'three': '3๏ธโƒฃ', + 'thumbsdown': '๐Ÿ‘Ž', + 'thumbsup': '๐Ÿ‘', + 'ticket': '๐ŸŽซ', + 'tickets': '๐ŸŽŸ๏ธ', + 'tiger': '๐Ÿฏ', + 'tiger2': '๐Ÿ…', + 'timer_clock': 'โฒ๏ธ', + 'timor_leste': '๐Ÿ‡น๐Ÿ‡ฑ', + 'tipping_hand_man': '๐Ÿ’โ€โ™‚๏ธ', + 'tipping_hand_person': '๐Ÿ’', + 'tipping_hand_woman': '๐Ÿ’โ€โ™€๏ธ', + 'tired_face': '๐Ÿ˜ซ', + 'tm': 'โ„ข๏ธ', + 'togo': '๐Ÿ‡น๐Ÿ‡ฌ', + 'toilet': '๐Ÿšฝ', + 'tokelau': '๐Ÿ‡น๐Ÿ‡ฐ', + 'tokyo_tower': '๐Ÿ—ผ', + 'tomato': '๐Ÿ…', + 'tonga': '๐Ÿ‡น๐Ÿ‡ด', + 'tongue': '๐Ÿ‘…', + 'toolbox': '๐Ÿงฐ', + 'tooth': '๐Ÿฆท', + 'toothbrush': '๐Ÿชฅ', + 'top': '๐Ÿ”', + 'tophat': '๐ŸŽฉ', + 'tornado': '๐ŸŒช๏ธ', + 'tr': '๐Ÿ‡น๐Ÿ‡ท', + 'trackball': '๐Ÿ–ฒ๏ธ', + 'tractor': '๐Ÿšœ', + 'traffic_light': '๐Ÿšฅ', + 'train': '๐Ÿš‹', + 'train2': '๐Ÿš†', + 'tram': '๐ŸšŠ', + 'transgender_flag': '๐Ÿณ๏ธโ€โšง๏ธ', + 'transgender_symbol': 'โšง๏ธ', + 'triangular_flag_on_post': '๐Ÿšฉ', + 'triangular_ruler': '๐Ÿ“', + 'trident': '๐Ÿ”ฑ', + 'trinidad_tobago': '๐Ÿ‡น๐Ÿ‡น', + 'tristan_da_cunha': '๐Ÿ‡น๐Ÿ‡ฆ', + 'triumph': '๐Ÿ˜ค', + 'troll': '๐ŸงŒ', + 'trolleybus': '๐ŸšŽ', + 'trophy': '๐Ÿ†', + 'tropical_drink': '๐Ÿน', + 'tropical_fish': '๐Ÿ ', + 'truck': '๐Ÿšš', + 'trumpet': '๐ŸŽบ', + 'tshirt': '๐Ÿ‘•', + 'tulip': '๐ŸŒท', + 'tumbler_glass': '๐Ÿฅƒ', + 'tunisia': '๐Ÿ‡น๐Ÿ‡ณ', + 'turkey': '๐Ÿฆƒ', + 'turkmenistan': '๐Ÿ‡น๐Ÿ‡ฒ', + 'turks_caicos_islands': '๐Ÿ‡น๐Ÿ‡จ', + 'turtle': '๐Ÿข', + 'tuvalu': '๐Ÿ‡น๐Ÿ‡ป', + 'tv': '๐Ÿ“บ', + 'twisted_rightwards_arrows': '๐Ÿ”€', + 'two': '2๏ธโƒฃ', + 'two_hearts': '๐Ÿ’•', + 'two_men_holding_hands': '๐Ÿ‘ฌ', + 'two_women_holding_hands': '๐Ÿ‘ญ', + 'u5272': '๐Ÿˆน', + 'u5408': '๐Ÿˆด', + 'u55b6': '๐Ÿˆบ', + 'u6307': '๐Ÿˆฏ', + 'u6708': '๐Ÿˆท๏ธ', + 'u6709': '๐Ÿˆถ', + 'u6e80': '๐Ÿˆต', + 'u7121': '๐Ÿˆš', + 'u7533': '๐Ÿˆธ', + 'u7981': '๐Ÿˆฒ', + 'u7a7a': '๐Ÿˆณ', + 'uganda': '๐Ÿ‡บ๐Ÿ‡ฌ', + 'uk': '๐Ÿ‡ฌ๐Ÿ‡ง', + 'ukraine': '๐Ÿ‡บ๐Ÿ‡ฆ', + 'umbrella': 'โ˜”', + 'unamused': '๐Ÿ˜’', + 'underage': '๐Ÿ”ž', + 'unicorn': '๐Ÿฆ„', + 'united_arab_emirates': '๐Ÿ‡ฆ๐Ÿ‡ช', + 'united_nations': '๐Ÿ‡บ๐Ÿ‡ณ', + 'unlock': '๐Ÿ”“', + 'up': '๐Ÿ†™', + 'upside_down_face': '๐Ÿ™ƒ', + 'uruguay': '๐Ÿ‡บ๐Ÿ‡พ', + 'us': '๐Ÿ‡บ๐Ÿ‡ธ', + 'us_outlying_islands': '๐Ÿ‡บ๐Ÿ‡ฒ', + 'us_virgin_islands': '๐Ÿ‡ป๐Ÿ‡ฎ', + 'uzbekistan': '๐Ÿ‡บ๐Ÿ‡ฟ', + 'v': 'โœŒ๏ธ', + 'vampire': '๐Ÿง›', + 'vampire_man': '๐Ÿง›โ€โ™‚๏ธ', + 'vampire_woman': '๐Ÿง›โ€โ™€๏ธ', + 'vanuatu': '๐Ÿ‡ป๐Ÿ‡บ', + 'vatican_city': '๐Ÿ‡ป๐Ÿ‡ฆ', + 'venezuela': '๐Ÿ‡ป๐Ÿ‡ช', + 'vertical_traffic_light': '๐Ÿšฆ', + 'vhs': '๐Ÿ“ผ', + 'vibration_mode': '๐Ÿ“ณ', + 'video_camera': '๐Ÿ“น', + 'video_game': '๐ŸŽฎ', + 'vietnam': '๐Ÿ‡ป๐Ÿ‡ณ', + 'violin': '๐ŸŽป', + 'virgo': 'โ™', + 'volcano': '๐ŸŒ‹', + 'volleyball': '๐Ÿ', + 'vomiting_face': '๐Ÿคฎ', + 'vs': '๐Ÿ†š', + 'vulcan_salute': '๐Ÿ––', + 'waffle': '๐Ÿง‡', + 'wales': '๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ', + 'walking': '๐Ÿšถ', + 'walking_man': '๐Ÿšถโ€โ™‚๏ธ', + 'walking_woman': '๐Ÿšถโ€โ™€๏ธ', + 'wallis_futuna': '๐Ÿ‡ผ๐Ÿ‡ซ', + 'waning_crescent_moon': '๐ŸŒ˜', + 'waning_gibbous_moon': '๐ŸŒ–', + 'warning': 'โš ๏ธ', + 'wastebasket': '๐Ÿ—‘๏ธ', + 'watch': 'โŒš', + 'water_buffalo': '๐Ÿƒ', + 'water_polo': '๐Ÿคฝ', + 'watermelon': '๐Ÿ‰', + 'wave': '๐Ÿ‘‹', + 'wavy_dash': 'ใ€ฐ๏ธ', + 'waxing_crescent_moon': '๐ŸŒ’', + 'waxing_gibbous_moon': '๐ŸŒ”', + 'wc': '๐Ÿšพ', + 'weary': '๐Ÿ˜ฉ', + 'wedding': '๐Ÿ’’', + 'weight_lifting': '๐Ÿ‹๏ธ', + 'weight_lifting_man': '๐Ÿ‹๏ธโ€โ™‚๏ธ', + 'weight_lifting_woman': '๐Ÿ‹๏ธโ€โ™€๏ธ', + 'western_sahara': '๐Ÿ‡ช๐Ÿ‡ญ', + 'whale': '๐Ÿณ', + 'whale2': '๐Ÿ‹', + 'wheel': '๐Ÿ›ž', + 'wheel_of_dharma': 'โ˜ธ๏ธ', + 'wheelchair': 'โ™ฟ', + 'white_check_mark': 'โœ…', + 'white_circle': 'โšช', + 'white_flag': '๐Ÿณ๏ธ', + 'white_flower': '๐Ÿ’ฎ', + 'white_haired_man': '๐Ÿ‘จโ€๐Ÿฆณ', + 'white_haired_woman': '๐Ÿ‘ฉโ€๐Ÿฆณ', + 'white_heart': '๐Ÿค', + 'white_large_square': 'โฌœ', + 'white_medium_small_square': 'โ—ฝ', + 'white_medium_square': 'โ—ป๏ธ', + 'white_small_square': 'โ–ซ๏ธ', + 'white_square_button': '๐Ÿ”ณ', + 'wilted_flower': '๐Ÿฅ€', + 'wind_chime': '๐ŸŽ', + 'wind_face': '๐ŸŒฌ๏ธ', + 'window': '๐ŸชŸ', + 'wine_glass': '๐Ÿท', + 'wing': '๐Ÿชฝ', + 'wink': '๐Ÿ˜‰', + 'wireless': '๐Ÿ›œ', + 'wolf': '๐Ÿบ', + 'woman': '๐Ÿ‘ฉ', + 'woman_artist': '๐Ÿ‘ฉโ€๐ŸŽจ', + 'woman_astronaut': '๐Ÿ‘ฉโ€๐Ÿš€', + 'woman_beard': '๐Ÿง”โ€โ™€๏ธ', + 'woman_cartwheeling': '๐Ÿคธโ€โ™€๏ธ', + 'woman_cook': '๐Ÿ‘ฉโ€๐Ÿณ', + 'woman_dancing': '๐Ÿ’ƒ', + 'woman_facepalming': '๐Ÿคฆโ€โ™€๏ธ', + 'woman_factory_worker': '๐Ÿ‘ฉโ€๐Ÿญ', + 'woman_farmer': '๐Ÿ‘ฉโ€๐ŸŒพ', + 'woman_feeding_baby': '๐Ÿ‘ฉโ€๐Ÿผ', + 'woman_firefighter': '๐Ÿ‘ฉโ€๐Ÿš’', + 'woman_health_worker': '๐Ÿ‘ฉโ€โš•๏ธ', + 'woman_in_manual_wheelchair': '๐Ÿ‘ฉโ€๐Ÿฆฝ', + 'woman_in_motorized_wheelchair': '๐Ÿ‘ฉโ€๐Ÿฆผ', + 'woman_in_tuxedo': '๐Ÿคตโ€โ™€๏ธ', + 'woman_judge': '๐Ÿ‘ฉโ€โš–๏ธ', + 'woman_juggling': '๐Ÿคนโ€โ™€๏ธ', + 'woman_mechanic': '๐Ÿ‘ฉโ€๐Ÿ”ง', + 'woman_office_worker': '๐Ÿ‘ฉโ€๐Ÿ’ผ', + 'woman_pilot': '๐Ÿ‘ฉโ€โœˆ๏ธ', + 'woman_playing_handball': '๐Ÿคพโ€โ™€๏ธ', + 'woman_playing_water_polo': '๐Ÿคฝโ€โ™€๏ธ', + 'woman_scientist': '๐Ÿ‘ฉโ€๐Ÿ”ฌ', + 'woman_shrugging': '๐Ÿคทโ€โ™€๏ธ', + 'woman_singer': '๐Ÿ‘ฉโ€๐ŸŽค', + 'woman_student': '๐Ÿ‘ฉโ€๐ŸŽ“', + 'woman_teacher': '๐Ÿ‘ฉโ€๐Ÿซ', + 'woman_technologist': '๐Ÿ‘ฉโ€๐Ÿ’ป', + 'woman_with_headscarf': '๐Ÿง•', + 'woman_with_probing_cane': '๐Ÿ‘ฉโ€๐Ÿฆฏ', + 'woman_with_turban': '๐Ÿ‘ณโ€โ™€๏ธ', + 'woman_with_veil': '๐Ÿ‘ฐโ€โ™€๏ธ', + 'womans_clothes': '๐Ÿ‘š', + 'womans_hat': '๐Ÿ‘’', + 'women_wrestling': '๐Ÿคผโ€โ™€๏ธ', + 'womens': '๐Ÿšบ', + 'wood': '๐Ÿชต', + 'woozy_face': '๐Ÿฅด', + 'world_map': '๐Ÿ—บ๏ธ', + 'worm': '๐Ÿชฑ', + 'worried': '๐Ÿ˜Ÿ', + 'wrench': '๐Ÿ”ง', + 'wrestling': '๐Ÿคผ', + 'writing_hand': 'โœ๏ธ', + 'x': 'โŒ', + 'x_ray': '๐Ÿฉป', + 'yarn': '๐Ÿงถ', + 'yawning_face': '๐Ÿฅฑ', + 'yellow_circle': '๐ŸŸก', + 'yellow_heart': '๐Ÿ’›', + 'yellow_square': '๐ŸŸจ', + 'yemen': '๐Ÿ‡พ๐Ÿ‡ช', + 'yen': '๐Ÿ’ด', + 'yin_yang': 'โ˜ฏ๏ธ', + 'yo_yo': '๐Ÿช€', + 'yum': '๐Ÿ˜‹', + 'zambia': '๐Ÿ‡ฟ๐Ÿ‡ฒ', + 'zany_face': '๐Ÿคช', + 'zap': 'โšก', + 'zebra': '๐Ÿฆ“', + 'zero': '0๏ธโƒฃ', + 'zimbabwe': '๐Ÿ‡ฟ๐Ÿ‡ผ', + 'zipper_mouth_face': '๐Ÿค', + 'zombie': '๐ŸงŸ', + 'zombie_man': '๐ŸงŸโ€โ™‚๏ธ', + 'zombie_woman': '๐ŸงŸโ€โ™€๏ธ', + 'zzz': '๐Ÿ’ค', +}; diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index 146b1a9..564e274 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -27,6 +27,7 @@ import '../services/chat_text_scale_service.dart'; import '../services/translation_service.dart'; import '../utils/emoji_utils.dart'; import '../widgets/mention_autocomplete.dart'; +import '../helpers/emoji_shortcodes.dart'; import '../widgets/chat_zoom_wrapper.dart'; import '../widgets/emoji_picker.dart'; import '../widgets/gif_message.dart'; @@ -1248,6 +1249,7 @@ class _ChannelChatScreenState extends State { controller: _textController, focusNode: _textFieldFocusNode, candidates: _buildMentionCandidates(connector), + emojiShortcodes: emojiShortcodes, hintText: context.l10n.chat_typeMessage, onSubmitted: (_) => _sendMessage(), encoder: diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index 5e9f960..d9e9cd5 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -30,7 +30,8 @@ import '../services/path_history_service.dart'; import '../services/translation_service.dart'; import '../widgets/chat_zoom_wrapper.dart'; import '../widgets/elements_ui.dart'; -import '../widgets/byte_count_input.dart'; +import '../widgets/mention_autocomplete.dart'; +import '../helpers/emoji_shortcodes.dart'; import 'channel_message_path_screen.dart'; import 'map_screen.dart'; import '../utils/emoji_utils.dart'; @@ -621,10 +622,12 @@ class _ChatScreenState extends State { ), ); } - return ByteCountedTextField( + return MentionAutocompleteField( maxBytes: maxBytes, controller: _textController, focusNode: _textFieldFocusNode, + candidates: const [], + emojiShortcodes: emojiShortcodes, hintText: context.l10n.chat_typeMessage, onSubmitted: (_) => _sendMessage(connector), encoder: diff --git a/lib/widgets/mention_autocomplete.dart b/lib/widgets/mention_autocomplete.dart index 4ecca57..df43ca7 100644 --- a/lib/widgets/mention_autocomplete.dart +++ b/lib/widgets/mention_autocomplete.dart @@ -20,19 +20,33 @@ class MentionCandidate { }); } -/// Wraps [ByteCountedTextField] with an `@`-mention autocomplete dropdown. +/// One row in the autocomplete dropdown. +class _Entry { + final String label; + final String? emoji; // leading glyph (emoji rows) + final IconData? icon; // leading icon (mention rows) + final String insert; // replacement text for the trigger token + const _Entry({required this.label, this.emoji, this.icon, required this.insert}); +} + +/// Wraps [ByteCountedTextField] with autocomplete for `@`-mentions and +/// `:emoji:` shortcodes. /// -/// Typing `@` at the start of a word opens a dropdown above the field listing -/// matching [candidates]. Recent channel senders sit at the bottom (most recent -/// closest to the input and auto-highlighted); other contacts stack above in -/// alpha order with A nearest the input. Up/Down move the highlight, Tab or -/// click selects, Esc dismisses, Enter sends. Selecting replaces the `@query` -/// with `@[ExactName] ` at the cursor. +/// - Typing `@` at the start of a word lists matching [candidates] (recent +/// senders at the bottom, contacts above) and inserts `@[ExactName] `. +/// - Typing `:` at the start of a word lists matching [emojiShortcodes] and +/// inserts the emoji character. Typing a full `:name:` auto-converts it. +/// +/// Up/Down move the highlight, Tab or click selects, Esc dismisses. Enter +/// sends, and first completes an unambiguous emoji (single or exact shortcode +/// match) so it ships the glyph rather than the literal text. Either feature +/// is disabled by leaving its data empty/null. class MentionAutocompleteField extends StatefulWidget { final int maxBytes; final TextEditingController controller; final FocusNode focusNode; final List candidates; + final Map? emojiShortcodes; final String? hintText; final ValueChanged? onSubmitted; final String Function(String)? encoder; @@ -43,7 +57,8 @@ class MentionAutocompleteField extends StatefulWidget { required this.maxBytes, required this.controller, required this.focusNode, - required this.candidates, + this.candidates = const [], + this.emojiShortcodes, this.hintText, this.onSubmitted, this.encoder, @@ -59,17 +74,14 @@ class _MentionAutocompleteFieldState extends State { final LayerLink _link = LayerLink(); OverlayEntry? _overlay; - /// Match list ordered top-to-bottom: contacts (Z..A) then recent (old..new). - List _matches = const []; - - /// Index in [_matches] where the recent section begins. + List<_Entry> _matches = const []; int _recentStart = 0; - - /// Currently highlighted index (bottom-most by default). int _highlighted = -1; + int _tokenStart = -1; - /// Index of the triggering `@` in the controller text. - int _atIndex = -1; + /// Active emoji query while the dropdown shows emoji matches (null for + /// mentions or when closed). Lets Enter complete an unambiguous emoji + send. + String? _emojiQuery; @override void initState() { @@ -94,7 +106,30 @@ class _MentionAutocompleteFieldState extends State { if (!widget.focusNode.hasFocus) _close(); } + /// A "word" char (ASCII letter/digit). A trigger is only suppressed when it + /// sits immediately after one of these (e.g. `http://`, `3:30`), so a colon + /// right after an emoji or punctuation still opens the picker. + static bool _isWordChar(String c) { + final u = c.codeUnitAt(0); + return (u >= 0x61 && u <= 0x7a) || // a-z + (u >= 0x41 && u <= 0x5a) || // A-Z + (u >= 0x30 && u <= 0x39); // 0-9 + } + + static bool _isShortcodeChar(String c) { + final u = c.codeUnitAt(0); + return (u >= 0x61 && u <= 0x7a) || // a-z + (u >= 0x30 && u <= 0x39) || // 0-9 + c == '_' || + c == '+' || + c == '-'; + } + void _onChanged() { + // Cursor-driven trigger detection (same shape as multi_trigger_autocomplete's + // invokingTrigger). It does not special-case the IME composing region โ€” + // fine for hardware keyboards; a known limitation for CJK/IME input, which + // the reference package doesn't handle either. final value = widget.controller.value; final sel = value.selection; final text = value.text; @@ -107,35 +142,75 @@ class _MentionAutocompleteFieldState extends State { _close(); return; } - // Walk back from the caret to an `@` that begins a word, with no - // whitespace (or a `]`, which would break the bracket form) in between. + + // Auto-convert a completed :name: when the closing colon is typed. + final shortcodes = widget.emojiShortcodes; + if (shortcodes != null && caret >= 2 && text[caret - 1] == ':') { + int j = caret - 2; + while (j >= 0 && _isShortcodeChar(text[j])) { + j--; + } + if (j >= 0 && text[j] == ':' && (j == 0 || !_isWordChar(text[j - 1]))) { + final name = text.substring(j + 1, caret - 1); + final glyph = shortcodes[name]; + if (name.isNotEmpty && glyph != null) { + final newText = text.substring(0, j) + glyph + text.substring(caret); + widget.controller.value = TextEditingValue( + text: newText, + selection: TextSelection.collapsed(offset: j + glyph.length), + ); + _close(); + return; + } + } + } + + // Walk back to a trigger char (@ or :) that begins a word. int i = caret - 1; + String? trigger; while (i >= 0) { final ch = text[i]; - if (ch == '@') break; + if (ch == '@') { + trigger = '@'; + break; + } + if (ch == ':') { + trigger = ':'; + break; + } if (ch == ' ' || ch == '\n' || ch == '\t' || ch == ']') { - _close(); - return; + break; } i--; } - if (i < 0 || text[i] != '@') { + if (trigger == null || i < 0) { _close(); return; } - // `@` must begin a word: preceded by start-of-text or whitespace. - if (i > 0) { - final prev = text[i - 1]; - if (prev != ' ' && prev != '\n' && prev != '\t') { - _close(); - return; - } + if (i > 0 && _isWordChar(text[i - 1])) { + _close(); + return; + } + final query = text.substring(i + 1, caret); + // No real shortcode or name is this long; avoid pathological scans. + if (query.length > 64) { + _close(); + return; + } + _tokenStart = i; + if (trigger == '@') { + _filterMentions(query); + } else { + _filterEmoji(query); } - _atIndex = i; - _filter(text.substring(i + 1, caret)); } - void _filter(String query) { + void _filterMentions(String query) { + _emojiQuery = null; + if (widget.candidates.isEmpty) { + _close(); + return; + } final q = query.toLowerCase(); final matched = widget.candidates.where( (c) => c.name.toLowerCase().startsWith(q), @@ -152,12 +227,9 @@ class _MentionAutocompleteFieldState extends State { } } final recent = recentByName.values.toList(); - - // Contacts: alpha with Z at top, A at bottom (descending). contacts.sort( (a, b) => b.name.toLowerCase().compareTo(a.name.toLowerCase()), ); - // Recent: oldest at top, most recent at bottom. recent.sort((a, b) { final ta = a.lastSeen; final tb = b.lastSeen; @@ -174,9 +246,52 @@ class _MentionAutocompleteFieldState extends State { _close(); return; } - _matches = combined; + _matches = combined + .map( + (c) => _Entry( + label: c.name, + icon: c.recent ? Icons.history : Icons.person_outline, + insert: '@[${c.name}] ', + ), + ) + .toList(); _recentStart = contacts.length; - _highlighted = combined.length - 1; + _highlighted = _matches.length - 1; + _show(); + } + + void _filterEmoji(String query) { + final shortcodes = widget.emojiShortcodes; + if (shortcodes == null || query.isEmpty) { + _close(); + return; + } + for (final ch in query.split('')) { + if (!_isShortcodeChar(ch)) { + _close(); + return; + } + } + final names = shortcodes.keys.where((k) => k.startsWith(query)).toList(); + if (names.isEmpty) { + _close(); + return; + } + names.sort((a, b) { + if (a == query && b != query) return -1; + if (b == query && a != query) return 1; + final byLen = a.length.compareTo(b.length); + if (byLen != 0) return byLen; + return a.compareTo(b); + }); + // Best 8, then reversed so the best sits at the bottom (nearest the input). + final top = names.take(8).toList().reversed.toList(); + _matches = top + .map((k) => _Entry(label: ':$k:', emoji: shortcodes[k], insert: shortcodes[k]!)) + .toList(); + _recentStart = _matches.length; // no divider for emoji + _highlighted = _matches.length - 1; + _emojiQuery = query; _show(); } @@ -199,7 +314,8 @@ class _MentionAutocompleteFieldState extends State { _remove(); _matches = const []; _highlighted = -1; - _atIndex = -1; + _tokenStart = -1; + _emojiQuery = null; } } @@ -227,25 +343,38 @@ class _MentionAutocompleteFieldState extends State { } if (key == LogicalKeyboardKey.enter || key == LogicalKeyboardKey.numpadEnter) { + // For an unambiguous emoji shortcode (a single match, or the exact name), + // Enter completes the glyph first, then sends โ€” so `:rofl` + Enter ships + // the emoji, not the literal text. Ambiguous matches still send raw; use + // Tab to pick one deliberately. + final q = _emojiQuery; + if (q != null && _matches.isNotEmpty) { + final best = _matches[_highlighted]; + if (_matches.length == 1 || best.label == ':$q:') { + _select(best); // inserts the glyph and closes the dropdown + widget.onSubmitted?.call(widget.controller.text); + return KeyEventResult.handled; + } + } final text = widget.controller.text; _close(); widget.onSubmitted?.call(text); return KeyEventResult.handled; } + return KeyEventResult.ignored; } - void _select(MentionCandidate c) { + void _select(_Entry entry) { final text = widget.controller.text; final caret = widget.controller.selection.baseOffset; - if (_atIndex < 0 || caret < _atIndex || caret > text.length) { + if (_tokenStart < 0 || caret < _tokenStart || caret > text.length) { _close(); return; } - final insertion = '@[${c.name}] '; final newText = - text.substring(0, _atIndex) + insertion + text.substring(caret); - final cursor = _atIndex + insertion.length; + text.substring(0, _tokenStart) + entry.insert + text.substring(caret); + final cursor = _tokenStart + entry.insert.length; widget.controller.value = TextEditingValue( text: newText, selection: TextSelection.collapsed(offset: cursor), @@ -264,11 +393,11 @@ class _MentionAutocompleteFieldState extends State { if (i == _recentStart && _recentStart > 0 && _recentStart < _matches.length) { children.add(_recentDivider(theme)); } - final c = _matches[i]; + final e = _matches[i]; final selected = i == _highlighted; children.add( InkWell( - onTap: () => _select(c), + onTap: () => _select(e), child: Container( width: double.infinity, color: selected @@ -277,15 +406,18 @@ class _MentionAutocompleteFieldState extends State { padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( children: [ - Icon( - c.recent ? Icons.history : Icons.person_outline, - size: 15, - color: theme.colorScheme.onSurfaceVariant, - ), + if (e.emoji != null) + Text(e.emoji!, style: const TextStyle(fontSize: 16)) + else + Icon( + e.icon, + size: 15, + color: theme.colorScheme.onSurfaceVariant, + ), const SizedBox(width: 8), Expanded( child: Text( - c.name, + e.label, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( @@ -319,7 +451,10 @@ class _MentionAutocompleteFieldState extends State { constraints: const BoxConstraints(maxHeight: 220), child: SingleChildScrollView( reverse: true, - child: Column(mainAxisSize: MainAxisSize.min, children: children), + child: Column( + mainAxisSize: MainAxisSize.min, + children: children, + ), ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 72cca35..a1498af 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 9.0.0+12 +version: 9.1.0+14 environment: sdk: ^3.9.2