From eab7416328e3a10d65144b7d6edfb424b5e647e4 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 2 Sep 2026 18:39:05 +0200 Subject: [PATCH 1/6] feat(chat): add emoji search and backspace to message input Adds a new panel between the message input and the emoji picker with a search field and a backspace button. - The bundled androidx emoji2-emojipicker library has no search API and its emoji dataset isn't accessible from app code, so search is powered by a standalone keyword dataset (assets/emoji_keywords.json, derived from Unicode CLDR emoji names, scoped to the ~1770 emoji the library itself bundles) loaded via EmojiKeywordProvider. Matches replace the picker grid; picking one inserts it and records it as a recent emoji like the built-in grid does. - The backspace button deletes the emoji/character before the cursor, using BreakIterator for grapheme-cluster-aware deletion so multi- codepoint emoji (flags, ZWJ sequences, skin tones) are removed whole. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: Marcel Hibbe --- app/src/main/assets/emoji_keywords.json | 1 + .../main/assets/emoji_keywords.json.license | 2 + .../talk/chat/MessageInputFragment.kt | 164 ++++++++++++++++-- .../talk/utils/EmojiKeywordProvider.kt | 69 ++++++++ .../res/drawable/ic_baseline_backspace_24.xml | 18 ++ .../main/res/layout/emoji_search_panel.xml | 89 ++++++++++ .../res/layout/fragment_message_input.xml | 6 + app/src/main/res/values/strings.xml | 4 + 8 files changed, 342 insertions(+), 11 deletions(-) create mode 100644 app/src/main/assets/emoji_keywords.json create mode 100644 app/src/main/assets/emoji_keywords.json.license create mode 100644 app/src/main/java/com/nextcloud/talk/utils/EmojiKeywordProvider.kt create mode 100644 app/src/main/res/drawable/ic_baseline_backspace_24.xml create mode 100644 app/src/main/res/layout/emoji_search_panel.xml diff --git a/app/src/main/assets/emoji_keywords.json b/app/src/main/assets/emoji_keywords.json new file mode 100644 index 00000000000..850609c651f --- /dev/null +++ b/app/src/main/assets/emoji_keywords.json @@ -0,0 +1 @@ +[{"emoji":"๐Ÿ˜€","name":"grinning face","keywords":["grinning","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ƒ","name":"grinning face with big eyes","keywords":["grinning","face","big","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜„","name":"grinning face with smiling eyes","keywords":["grinning","face","smiling","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜","name":"beaming face with smiling eyes","keywords":["beaming","face","smiling","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜†","name":"grinning squinting face","keywords":["grinning","squinting","face","smiley","emotion"]},{"emoji":"๐Ÿ˜…","name":"grinning face with sweat","keywords":["grinning","face","sweat","smiley","emotion"]},{"emoji":"๐Ÿ˜‚","name":"face with tears of joy","keywords":["face","tears","joy","smiley","emotion"]},{"emoji":"๐Ÿคฃ","name":"rolling on the floor laughing","keywords":["rolling","floor","laughing","smiley","emotion","face"]},{"emoji":"๐Ÿ˜ญ","name":"loudly crying face","keywords":["loudly","crying","face","smiley","emotion"]},{"emoji":"๐Ÿ˜‰","name":"winking face","keywords":["winking","face","smiley","emotion"]},{"emoji":"๐Ÿ˜—","name":"kissing face","keywords":["kissing","face","smiley","emotion"]},{"emoji":"๐Ÿ˜™","name":"kissing face with smiling eyes","keywords":["kissing","face","smiling","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜š","name":"kissing face with closed eyes","keywords":["kissing","face","closed","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜˜","name":"face blowing a kiss","keywords":["face","blowing","kiss","smiley","emotion"]},{"emoji":"๐Ÿฅฐ","name":"smiling face with hearts","keywords":["smiling","face","hearts","smiley","emotion"]},{"emoji":"๐Ÿ˜","name":"smiling face with heart-eyes","keywords":["smiling","face","heart","eyes","smiley","emotion"]},{"emoji":"๐Ÿคฉ","name":"star-struck","keywords":["star","struck","smiley","emotion","face"]},{"emoji":"๐Ÿฅณ","name":"partying face","keywords":["partying","face","smiley","emotion"]},{"emoji":"๐Ÿซ ","name":"melting face","keywords":["melting","face","smiley","emotion"]},{"emoji":"๐Ÿ™ƒ","name":"upside-down face","keywords":["upside","down","face","smiley","emotion"]},{"emoji":"๐Ÿ™‚","name":"slightly smiling face","keywords":["slightly","smiling","face","smiley","emotion"]},{"emoji":"๐Ÿฅฒ","name":"smiling face with tear","keywords":["smiling","face","tear","smiley","emotion"]},{"emoji":"๐Ÿฅน","name":"face holding back tears","keywords":["face","holding","back","tears","smiley","emotion"]},{"emoji":"๐Ÿ˜Š","name":"smiling face with smiling eyes","keywords":["smiling","face","eyes","smiley","emotion"]},{"emoji":"โ˜บ๏ธ","name":"smiling face","keywords":["smiling","face","smiley","emotion"]},{"emoji":"๐Ÿ˜Œ","name":"relieved face","keywords":["relieved","face","smiley","emotion"]},{"emoji":"๐Ÿ™‚โ€โ†•๏ธ","name":"head shaking vertically","keywords":["head","shaking","vertically","smiley","emotion","face"]},{"emoji":"๐Ÿ™‚โ€โ†”๏ธ","name":"head shaking horizontally","keywords":["head","shaking","horizontally","smiley","emotion","face"]},{"emoji":"๐Ÿ˜","name":"smirking face","keywords":["smirking","face","smiley","emotion"]},{"emoji":"๐Ÿคค","name":"drooling face","keywords":["drooling","face","smiley","emotion"]},{"emoji":"๐Ÿ˜‹","name":"face savoring food","keywords":["face","savoring","food","smiley","emotion"]},{"emoji":"๐Ÿ˜›","name":"face with tongue","keywords":["face","tongue","smiley","emotion"]},{"emoji":"๐Ÿ˜","name":"squinting face with tongue","keywords":["squinting","face","tongue","smiley","emotion"]},{"emoji":"๐Ÿ˜œ","name":"winking face with tongue","keywords":["winking","face","tongue","smiley","emotion"]},{"emoji":"๐Ÿคช","name":"zany face","keywords":["zany","face","smiley","emotion"]},{"emoji":"๐Ÿฅด","name":"woozy face","keywords":["woozy","face","smiley","emotion"]},{"emoji":"๐Ÿ˜”","name":"pensive face","keywords":["pensive","face","smiley","emotion"]},{"emoji":"๐Ÿฅบ","name":"pleading face","keywords":["pleading","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ฌ","name":"grimacing face","keywords":["grimacing","face","smiley","emotion"]},{"emoji":"๐Ÿ˜‘","name":"expressionless face","keywords":["expressionless","face","smiley","emotion"]},{"emoji":"๐Ÿ˜","name":"neutral face","keywords":["neutral","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ถ","name":"face without mouth","keywords":["face","without","mouth","smiley","emotion"]},{"emoji":"๐Ÿ˜ถโ€๐ŸŒซ๏ธ","name":"face in clouds","keywords":["face","clouds","smiley","emotion"]},{"emoji":"๐Ÿซฅ","name":"dotted line face","keywords":["dotted","line","face","smiley","emotion"]},{"emoji":"๐Ÿค","name":"zipper-mouth face","keywords":["zipper","mouth","face","smiley","emotion"]},{"emoji":"๐Ÿซก","name":"saluting face","keywords":["saluting","face","smiley","emotion"]},{"emoji":"๐Ÿค”","name":"thinking face","keywords":["thinking","face","smiley","emotion"]},{"emoji":"๐Ÿคซ","name":"shushing face","keywords":["shushing","face","smiley","emotion"]},{"emoji":"๐Ÿซข","name":"face with open eyes and hand over mouth","keywords":["face","open","eyes","hand","over","mouth","smiley","emotion"]},{"emoji":"๐Ÿคญ","name":"face with hand over mouth","keywords":["face","hand","over","mouth","smiley","emotion"]},{"emoji":"๐Ÿฅฑ","name":"yawning face","keywords":["yawning","face","smiley","emotion"]},{"emoji":"๐Ÿค—","name":"smiling face with open hands","keywords":["smiling","face","open","hands","smiley","emotion"]},{"emoji":"๐Ÿซฃ","name":"face with peeking eye","keywords":["face","peeking","eye","smiley","emotion"]},{"emoji":"๐Ÿ˜ฑ","name":"face screaming in fear","keywords":["face","screaming","fear","smiley","emotion"]},{"emoji":"๐Ÿคจ","name":"face with raised eyebrow","keywords":["face","raised","eyebrow","smiley","emotion"]},{"emoji":"๐Ÿง","name":"face with monocle","keywords":["face","monocle","smiley","emotion"]},{"emoji":"๐Ÿ˜’","name":"unamused face","keywords":["unamused","face","smiley","emotion"]},{"emoji":"๐Ÿ™„","name":"face with rolling eyes","keywords":["face","rolling","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜ฎโ€๐Ÿ’จ","name":"face exhaling","keywords":["face","exhaling","smiley","emotion"]},{"emoji":"๐Ÿ˜ค","name":"face with steam from nose","keywords":["face","steam","from","nose","smiley","emotion"]},{"emoji":"๐Ÿ˜ ","name":"angry face","keywords":["angry","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ก","name":"enraged face","keywords":["enraged","face","smiley","emotion"]},{"emoji":"๐Ÿคฌ","name":"face with symbols on mouth","keywords":["face","symbols","mouth","smiley","emotion"]},{"emoji":"๐Ÿ˜ž","name":"disappointed face","keywords":["disappointed","face","smiley","emotion"]},{"emoji":"๐Ÿ˜“","name":"downcast face with sweat","keywords":["downcast","face","sweat","smiley","emotion"]},{"emoji":"๐Ÿ˜Ÿ","name":"worried face","keywords":["worried","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ฅ","name":"sad but relieved face","keywords":["sad","but","relieved","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ข","name":"crying face","keywords":["crying","face","smiley","emotion"]},{"emoji":"โ˜น๏ธ","name":"frowning face","keywords":["frowning","face","smiley","emotion"]},{"emoji":"๐Ÿ™","name":"slightly frowning face","keywords":["slightly","frowning","face","smiley","emotion"]},{"emoji":"๐Ÿซค","name":"face with diagonal mouth","keywords":["face","diagonal","mouth","smiley","emotion"]},{"emoji":"๐Ÿ˜•","name":"confused face","keywords":["confused","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ฐ","name":"anxious face with sweat","keywords":["anxious","face","sweat","smiley","emotion"]},{"emoji":"๐Ÿ˜จ","name":"fearful face","keywords":["fearful","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ง","name":"anguished face","keywords":["anguished","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ฆ","name":"frowning face with open mouth","keywords":["frowning","face","open","mouth","smiley","emotion"]},{"emoji":"๐Ÿ˜ฎ","name":"face with open mouth","keywords":["face","open","mouth","smiley","emotion"]},{"emoji":"๐Ÿ˜ฏ","name":"hushed face","keywords":["hushed","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ฒ","name":"astonished face","keywords":["astonished","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ณ","name":"flushed face","keywords":["flushed","face","smiley","emotion"]},{"emoji":"๐Ÿคฏ","name":"exploding head","keywords":["exploding","head","smiley","emotion","face"]},{"emoji":"๐Ÿ˜–","name":"confounded face","keywords":["confounded","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ฃ","name":"persevering face","keywords":["persevering","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ฉ","name":"weary face","keywords":["weary","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ซ","name":"tired face","keywords":["tired","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ต","name":"face with crossed-out eyes","keywords":["face","crossed","out","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜ตโ€๐Ÿ’ซ","name":"face with spiral eyes","keywords":["face","spiral","eyes","smiley","emotion"]},{"emoji":"๐Ÿซจ","name":"shaking face","keywords":["shaking","face","smiley","emotion"]},{"emoji":"๐Ÿฅถ","name":"cold face","keywords":["cold","face","smiley","emotion"]},{"emoji":"๐Ÿฅต","name":"hot face","keywords":["hot","face","smiley","emotion"]},{"emoji":"๐Ÿคข","name":"nauseated face","keywords":["nauseated","face","smiley","emotion"]},{"emoji":"๐Ÿคฎ","name":"face vomiting","keywords":["face","vomiting","smiley","emotion"]},{"emoji":"๐Ÿซฉ","name":"face with bags under eyes","keywords":["face","bags","under","eyes","smiley","emotion"]},{"emoji":"๐Ÿ˜ด","name":"sleeping face","keywords":["sleeping","face","smiley","emotion"]},{"emoji":"๐Ÿ˜ช","name":"sleepy face","keywords":["sleepy","face","smiley","emotion"]},{"emoji":"๐Ÿคง","name":"sneezing face","keywords":["sneezing","face","smiley","emotion"]},{"emoji":"๐Ÿค’","name":"face with thermometer","keywords":["face","thermometer","smiley","emotion"]},{"emoji":"๐Ÿค•","name":"face with head-bandage","keywords":["face","head","bandage","smiley","emotion"]},{"emoji":"๐Ÿ˜ท","name":"face with medical mask","keywords":["face","medical","mask","smiley","emotion"]},{"emoji":"๐Ÿคฅ","name":"lying face","keywords":["lying","face","smiley","emotion"]},{"emoji":"๐Ÿ˜‡","name":"smiling face with halo","keywords":["smiling","face","halo","smiley","emotion"]},{"emoji":"๐Ÿค ","name":"cowboy hat face","keywords":["cowboy","hat","face","smiley","emotion"]},{"emoji":"๐Ÿค‘","name":"money-mouth face","keywords":["money","mouth","face","smiley","emotion"]},{"emoji":"๐Ÿค“","name":"nerd face","keywords":["nerd","face","smiley","emotion"]},{"emoji":"๐Ÿ˜Ž","name":"smiling face with sunglasses","keywords":["smiling","face","sunglasses","smiley","emotion"]},{"emoji":"๐Ÿฅธ","name":"disguised face","keywords":["disguised","face","smiley","emotion"]},{"emoji":"๐Ÿคก","name":"clown face","keywords":["clown","face","smiley","emotion"]},{"emoji":"๐Ÿ’ฉ","name":"pile of poo","keywords":["pile","poo","smiley","emotion","face"]},{"emoji":"๐Ÿ˜ˆ","name":"smiling face with horns","keywords":["smiling","face","horns","smiley","emotion"]},{"emoji":"๐Ÿ‘ฟ","name":"angry face with horns","keywords":["angry","face","horns","smiley","emotion"]},{"emoji":"๐Ÿ‘ป","name":"ghost","keywords":["ghost","smiley","emotion","face"]},{"emoji":"๐Ÿ’€","name":"skull","keywords":["skull","smiley","emotion","face"]},{"emoji":"โ˜ ๏ธ","name":"skull and crossbones","keywords":["skull","crossbones","smiley","emotion","face"]},{"emoji":"๐Ÿ‘น","name":"ogre","keywords":["ogre","smiley","emotion","face"]},{"emoji":"๐Ÿ‘บ","name":"goblin","keywords":["goblin","smiley","emotion","face"]},{"emoji":"โ˜ƒ๏ธ","name":"snowman","keywords":["snowman","smiley","emotion","face"]},{"emoji":"โ›„","name":"snowman without snow","keywords":["snowman","without","snow","smiley","emotion","face"]},{"emoji":"๐ŸŽƒ","name":"jack-o-lantern","keywords":["jack","lantern","smiley","emotion","face"]},{"emoji":"๐Ÿค–","name":"robot","keywords":["robot","smiley","emotion","face"]},{"emoji":"๐Ÿ‘ฝ","name":"alien","keywords":["alien","smiley","emotion","face"]},{"emoji":"๐Ÿ‘พ","name":"alien monster","keywords":["alien","monster","smiley","emotion","face"]},{"emoji":"๐ŸŒš","name":"new moon face","keywords":["new","moon","face","smiley","emotion"]},{"emoji":"๐ŸŒ","name":"full moon face","keywords":["full","moon","face","smiley","emotion"]},{"emoji":"๐ŸŒž","name":"sun with face","keywords":["sun","face","smiley","emotion"]},{"emoji":"๐ŸŒ›","name":"first quarter moon face","keywords":["first","quarter","moon","face","smiley","emotion"]},{"emoji":"๐ŸŒœ","name":"last quarter moon face","keywords":["last","quarter","moon","face","smiley","emotion"]},{"emoji":"๐Ÿ˜บ","name":"grinning cat","keywords":["grinning","cat","smiley","emotion","face"]},{"emoji":"๐Ÿ˜ธ","name":"grinning cat with smiling eyes","keywords":["grinning","cat","smiling","eyes","smiley","emotion","face"]},{"emoji":"๐Ÿ˜น","name":"cat with tears of joy","keywords":["cat","tears","joy","smiley","emotion","face"]},{"emoji":"๐Ÿ˜ป","name":"smiling cat with heart-eyes","keywords":["smiling","cat","heart","eyes","smiley","emotion","face"]},{"emoji":"๐Ÿ˜ผ","name":"cat with wry smile","keywords":["cat","wry","smile","smiley","emotion","face"]},{"emoji":"๐Ÿ˜ฝ","name":"kissing cat","keywords":["kissing","cat","smiley","emotion","face"]},{"emoji":"๐Ÿ™€","name":"weary cat","keywords":["weary","cat","smiley","emotion","face"]},{"emoji":"๐Ÿ˜ฟ","name":"crying cat","keywords":["crying","cat","smiley","emotion","face"]},{"emoji":"๐Ÿ˜พ","name":"pouting cat","keywords":["pouting","cat","smiley","emotion","face"]},{"emoji":"๐Ÿ™ˆ","name":"see-no-evil monkey","keywords":["see","no","evil","monkey","smiley","emotion","face"]},{"emoji":"๐Ÿ™‰","name":"hear-no-evil monkey","keywords":["hear","no","evil","monkey","smiley","emotion","face"]},{"emoji":"๐Ÿ™Š","name":"speak-no-evil monkey","keywords":["speak","no","evil","monkey","smiley","emotion","face"]},{"emoji":"๐Ÿ’ซ","name":"dizzy","keywords":["dizzy","smiley","emotion","face"]},{"emoji":"โญ","name":"star","keywords":["star","smiley","emotion","face"]},{"emoji":"๐ŸŒŸ","name":"glowing star","keywords":["glowing","star","smiley","emotion","face"]},{"emoji":"โœจ","name":"sparkles","keywords":["sparkles","smiley","emotion","face"]},{"emoji":"โšก","name":"high voltage","keywords":["high","voltage","smiley","emotion","face"]},{"emoji":"๐Ÿ’ฅ","name":"collision","keywords":["collision","smiley","emotion","face"]},{"emoji":"๐Ÿ’ข","name":"anger symbol","keywords":["anger","symbol","smiley","emotion","face"]},{"emoji":"๐Ÿ’จ","name":"dashing away","keywords":["dashing","away","smiley","emotion","face"]},{"emoji":"๐Ÿ’ฆ","name":"sweat droplets","keywords":["sweat","droplets","smiley","emotion","face"]},{"emoji":"๐Ÿ’ค","name":"ZZZ","keywords":["zzz","smiley","emotion","face"]},{"emoji":"๐Ÿ•ณ๏ธ","name":"hole","keywords":["hole","smiley","emotion","face"]},{"emoji":"๐Ÿ”ฅ","name":"fire","keywords":["fire","smiley","emotion","face"]},{"emoji":"๐Ÿ’ฏ","name":"hundred points","keywords":["hundred","points","smiley","emotion","face"]},{"emoji":"๐ŸŽ‰","name":"party popper","keywords":["party","popper","smiley","emotion","face"]},{"emoji":"๐ŸŽŠ","name":"confetti ball","keywords":["confetti","ball","smiley","emotion","face"]},{"emoji":"โค๏ธ","name":"red heart","keywords":["red","heart","smiley","emotion","face"]},{"emoji":"๐Ÿงก","name":"orange heart","keywords":["orange","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’›","name":"yellow heart","keywords":["yellow","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’š","name":"green heart","keywords":["green","heart","smiley","emotion","face"]},{"emoji":"๐Ÿฉต","name":"light blue heart","keywords":["light","blue","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’™","name":"blue heart","keywords":["blue","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’œ","name":"purple heart","keywords":["purple","heart","smiley","emotion","face"]},{"emoji":"๐ŸคŽ","name":"brown heart","keywords":["brown","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ–ค","name":"black heart","keywords":["black","heart","smiley","emotion","face"]},{"emoji":"๐Ÿฉถ","name":"grey heart","keywords":["grey","heart","smiley","emotion","face"]},{"emoji":"๐Ÿค","name":"white heart","keywords":["white","heart","smiley","emotion","face"]},{"emoji":"๐Ÿฉท","name":"pink heart","keywords":["pink","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’˜","name":"heart with arrow","keywords":["heart","arrow","smiley","emotion","face"]},{"emoji":"๐Ÿ’","name":"heart with ribbon","keywords":["heart","ribbon","smiley","emotion","face"]},{"emoji":"๐Ÿ’–","name":"sparkling heart","keywords":["sparkling","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’—","name":"growing heart","keywords":["growing","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’“","name":"beating heart","keywords":["beating","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’ž","name":"revolving hearts","keywords":["revolving","hearts","smiley","emotion","face"]},{"emoji":"๐Ÿ’•","name":"two hearts","keywords":["two","hearts","smiley","emotion","face"]},{"emoji":"๐Ÿ’Œ","name":"love letter","keywords":["love","letter","smiley","emotion","face"]},{"emoji":"๐Ÿ’Ÿ","name":"heart decoration","keywords":["heart","decoration","smiley","emotion","face"]},{"emoji":"โ™ฅ๏ธ","name":"heart suit","keywords":["heart","suit","smiley","emotion","face"]},{"emoji":"โฃ๏ธ","name":"heart exclamation","keywords":["heart","exclamation","smiley","emotion","face"]},{"emoji":"โค๏ธโ€๐Ÿฉน","name":"mending heart","keywords":["mending","heart","smiley","emotion","face"]},{"emoji":"๐Ÿ’”","name":"broken heart","keywords":["broken","heart","smiley","emotion","face"]},{"emoji":"โค๏ธโ€๐Ÿ”ฅ","name":"heart on fire","keywords":["heart","fire","smiley","emotion","face"]},{"emoji":"๐Ÿ’‹","name":"kiss mark","keywords":["kiss","mark","smiley","emotion","face"]},{"emoji":"๐Ÿซ‚","name":"people hugging","keywords":["people","hugging","smiley","emotion","face"]},{"emoji":"๐Ÿ‘ฅ","name":"busts in silhouette","keywords":["busts","silhouette","smiley","emotion","face"]},{"emoji":"๐Ÿ‘ค","name":"bust in silhouette","keywords":["bust","silhouette","smiley","emotion","face"]},{"emoji":"๐Ÿ—ฃ๏ธ","name":"speaking head","keywords":["speaking","head","smiley","emotion","face"]},{"emoji":"๐Ÿ‘ฃ","name":"footprints","keywords":["footprints","smiley","emotion","face"]},{"emoji":"๐Ÿซ†","name":"fingerprint","keywords":["fingerprint","smiley","emotion","face"]},{"emoji":"๐Ÿง ","name":"brain","keywords":["brain","smiley","emotion","face"]},{"emoji":"๐Ÿซ€","name":"anatomical heart","keywords":["anatomical","heart","smiley","emotion","face"]},{"emoji":"๐Ÿซ","name":"lungs","keywords":["lungs","smiley","emotion","face"]},{"emoji":"๐Ÿฉธ","name":"drop of blood","keywords":["drop","blood","smiley","emotion","face"]},{"emoji":"๐Ÿฆ ","name":"microbe","keywords":["microbe","smiley","emotion","face"]},{"emoji":"๐Ÿฆท","name":"tooth","keywords":["tooth","smiley","emotion","face"]},{"emoji":"๐Ÿฆด","name":"bone","keywords":["bone","smiley","emotion","face"]},{"emoji":"๐Ÿ‘€","name":"eyes","keywords":["eyes","smiley","emotion","face"]},{"emoji":"๐Ÿ‘๏ธ","name":"eye","keywords":["eye","smiley","emotion","face"]},{"emoji":"๐Ÿ‘„","name":"mouth","keywords":["mouth","smiley","emotion","face"]},{"emoji":"๐Ÿซฆ","name":"biting lip","keywords":["biting","lip","smiley","emotion","face"]},{"emoji":"๐Ÿ‘…","name":"tongue","keywords":["tongue","smiley","emotion","face"]},{"emoji":"๐Ÿ‘ƒ","name":"nose","keywords":["nose","smiley","emotion","face"]},{"emoji":"๐Ÿ‘‚","name":"ear","keywords":["ear","smiley","emotion","face"]},{"emoji":"๐Ÿฆป","name":"ear with hearing aid","keywords":["ear","hearing","aid","smiley","emotion","face"]},{"emoji":"๐Ÿฆถ","name":"foot","keywords":["foot","smiley","emotion","face"]},{"emoji":"๐Ÿฆต","name":"leg","keywords":["leg","smiley","emotion","face"]},{"emoji":"๐Ÿฆฟ","name":"mechanical leg","keywords":["mechanical","leg","smiley","emotion","face"]},{"emoji":"๐Ÿฆพ","name":"mechanical arm","keywords":["mechanical","arm","smiley","emotion","face"]},{"emoji":"๐Ÿ’ช","name":"flexed biceps","keywords":["flexed","biceps","smiley","emotion","face"]},{"emoji":"๐Ÿ‘","name":"clapping hands","keywords":["clapping","hands","smiley","emotion","face"]},{"emoji":"๐Ÿ‘","name":"thumbs up","keywords":["thumbs","up","smiley","emotion","face"]},{"emoji":"๐Ÿ‘Ž","name":"thumbs down","keywords":["thumbs","down","smiley","emotion","face"]},{"emoji":"๐Ÿซถ","name":"heart hands","keywords":["heart","hands","smiley","emotion","face"]},{"emoji":"๐Ÿ™Œ","name":"raising hands","keywords":["raising","hands","smiley","emotion","face"]},{"emoji":"๐Ÿ‘","name":"open hands","keywords":["open","hands","smiley","emotion","face"]},{"emoji":"๐Ÿคฒ","name":"palms up together","keywords":["palms","up","together","smiley","emotion","face"]},{"emoji":"๐Ÿคœ","name":"right-facing fist","keywords":["right","facing","fist","smiley","emotion","face"]},{"emoji":"๐Ÿค›","name":"left-facing fist","keywords":["left","facing","fist","smiley","emotion","face"]},{"emoji":"โœŠ","name":"raised fist","keywords":["raised","fist","smiley","emotion","face"]},{"emoji":"๐Ÿ‘Š","name":"oncoming fist","keywords":["oncoming","fist","smiley","emotion","face"]},{"emoji":"๐Ÿซณ","name":"palm down hand","keywords":["palm","down","hand","smiley","emotion","face"]},{"emoji":"๐Ÿซด","name":"palm up hand","keywords":["palm","up","hand","smiley","emotion","face"]},{"emoji":"๐Ÿซฑ","name":"rightwards hand","keywords":["rightwards","hand","smiley","emotion","face"]},{"emoji":"๐Ÿซฒ","name":"leftwards hand","keywords":["leftwards","hand","smiley","emotion","face"]},{"emoji":"๐Ÿซธ","name":"rightwards pushing hand","keywords":["rightwards","pushing","hand","smiley","emotion","face"]},{"emoji":"๐Ÿซท","name":"leftwards pushing hand","keywords":["leftwards","pushing","hand","smiley","emotion","face"]},{"emoji":"๐Ÿ‘‹","name":"waving hand","keywords":["waving","hand","smiley","emotion","face"]},{"emoji":"๐Ÿคš","name":"raised back of hand","keywords":["raised","back","hand","smiley","emotion","face"]},{"emoji":"๐Ÿ–๏ธ","name":"hand with fingers splayed","keywords":["hand","fingers","splayed","smiley","emotion","face"]},{"emoji":"โœ‹","name":"raised hand","keywords":["raised","hand","smiley","emotion","face"]},{"emoji":"๐Ÿ––","name":"vulcan salute","keywords":["vulcan","salute","smiley","emotion","face"]},{"emoji":"๐ŸคŸ","name":"love-you gesture","keywords":["love","you","gesture","smiley","emotion","face"]},{"emoji":"๐Ÿค˜","name":"sign of the horns","keywords":["sign","horns","smiley","emotion","face"]},{"emoji":"โœŒ๏ธ","name":"victory hand","keywords":["victory","hand","smiley","emotion","face"]},{"emoji":"๐Ÿคž","name":"crossed fingers","keywords":["crossed","fingers","smiley","emotion","face"]},{"emoji":"๐Ÿซฐ","name":"hand with index finger and thumb crossed","keywords":["hand","index","finger","thumb","crossed","smiley","emotion","face"]},{"emoji":"๐Ÿค™","name":"call me hand","keywords":["call","me","hand","smiley","emotion","face"]},{"emoji":"๐ŸคŒ","name":"pinched fingers","keywords":["pinched","fingers","smiley","emotion","face"]},{"emoji":"๐Ÿค","name":"pinching hand","keywords":["pinching","hand","smiley","emotion","face"]},{"emoji":"๐Ÿ‘Œ","name":"OK hand","keywords":["ok","hand","smiley","emotion","face"]},{"emoji":"๐Ÿซต","name":"index pointing at the viewer","keywords":["index","pointing","at","viewer","smiley","emotion","face"]},{"emoji":"๐Ÿ‘‰","name":"backhand index pointing right","keywords":["backhand","index","pointing","right","smiley","emotion","face"]},{"emoji":"๐Ÿ‘ˆ","name":"backhand index pointing left","keywords":["backhand","index","pointing","left","smiley","emotion","face"]},{"emoji":"โ˜๏ธ","name":"index pointing up","keywords":["index","pointing","up","smiley","emotion","face"]},{"emoji":"๐Ÿ‘†","name":"backhand index pointing up","keywords":["backhand","index","pointing","up","smiley","emotion","face"]},{"emoji":"๐Ÿ‘‡","name":"backhand index pointing down","keywords":["backhand","index","pointing","down","smiley","emotion","face"]},{"emoji":"๐Ÿ–•","name":"middle finger","keywords":["middle","finger","smiley","emotion","face"]},{"emoji":"โœ๏ธ","name":"writing hand","keywords":["writing","hand","smiley","emotion","face"]},{"emoji":"๐Ÿคณ","name":"selfie","keywords":["selfie","smiley","emotion","face"]},{"emoji":"๐Ÿ™","name":"folded hands","keywords":["folded","hands","smiley","emotion","face"]},{"emoji":"๐Ÿ’…","name":"nail polish","keywords":["nail","polish","smiley","emotion","face"]},{"emoji":"๐Ÿค","name":"handshake","keywords":["handshake","smiley","emotion","face"]},{"emoji":"๐Ÿ™‡","name":"person bowing","keywords":["person","bowing","people","body"]},{"emoji":"๐Ÿ™‹","name":"person raising hand","keywords":["person","raising","hand","people","body"]},{"emoji":"๐Ÿ’","name":"person tipping hand","keywords":["person","tipping","hand","people","body"]},{"emoji":"๐Ÿ™†","name":"person gesturing OK","keywords":["person","gesturing","ok","people","body"]},{"emoji":"๐Ÿ™…","name":"person gesturing NO","keywords":["person","gesturing","no","people","body"]},{"emoji":"๐Ÿคท","name":"person shrugging","keywords":["person","shrugging","people","body"]},{"emoji":"๐Ÿคฆ","name":"person facepalming","keywords":["person","facepalming","people","body"]},{"emoji":"๐Ÿ™","name":"person frowning","keywords":["person","frowning","people","body"]},{"emoji":"๐Ÿ™Ž","name":"person pouting","keywords":["person","pouting","people","body"]},{"emoji":"๐Ÿง","name":"deaf person","keywords":["deaf","person","people","body"]},{"emoji":"๐Ÿ’†","name":"person getting massage","keywords":["person","getting","massage","people","body"]},{"emoji":"๐Ÿ’‡","name":"person getting haircut","keywords":["person","getting","haircut","people","body"]},{"emoji":"๐Ÿง–","name":"person in steamy room","keywords":["person","steamy","room","people","body"]},{"emoji":"๐Ÿ›€","name":"person taking bath","keywords":["person","taking","bath","people","body"]},{"emoji":"๐Ÿ›Œ","name":"person in bed","keywords":["person","bed","people","body"]},{"emoji":"๐Ÿง˜","name":"person in lotus position","keywords":["person","lotus","position","people","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฏ","name":"man with white cane","keywords":["man","white","cane","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฏ","name":"woman with white cane","keywords":["woman","white","cane","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿฆผ","name":"man in motorized wheelchair","keywords":["man","motorized","wheelchair","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆผ","name":"woman in motorized wheelchair","keywords":["woman","motorized","wheelchair","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฝ","name":"man in manual wheelchair","keywords":["man","manual","wheelchair","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฝ","name":"woman in manual wheelchair","keywords":["woman","manual","wheelchair","people","person","body"]},{"emoji":"๐ŸงŽ","name":"person kneeling","keywords":["person","kneeling","people","body"]},{"emoji":"๐Ÿง","name":"person standing","keywords":["person","standing","people","body"]},{"emoji":"๐Ÿšถ","name":"person walking","keywords":["person","walking","people","body"]},{"emoji":"๐Ÿƒ","name":"person running","keywords":["person","running","people","body"]},{"emoji":"๐Ÿคธ","name":"person cartwheeling","keywords":["person","cartwheeling","people","body"]},{"emoji":"๐Ÿ‹๏ธ","name":"person lifting weights","keywords":["person","lifting","weights","people","body"]},{"emoji":"โ›น๏ธ","name":"person bouncing ball","keywords":["person","bouncing","ball","people","body"]},{"emoji":"๐Ÿคพ","name":"person playing handball","keywords":["person","playing","handball","people","body"]},{"emoji":"๐Ÿšด","name":"person biking","keywords":["person","biking","people","body"]},{"emoji":"๐Ÿšต","name":"person mountain biking","keywords":["person","mountain","biking","people","body"]},{"emoji":"๐Ÿง—","name":"person climbing","keywords":["person","climbing","people","body"]},{"emoji":"๐Ÿคผ","name":"people wrestling","keywords":["people","wrestling","person","body"]},{"emoji":"๐Ÿคน","name":"person juggling","keywords":["person","juggling","people","body"]},{"emoji":"๐ŸŒ๏ธ","name":"person golfing","keywords":["person","golfing","people","body"]},{"emoji":"๐Ÿ‡","name":"horse racing","keywords":["horse","racing","people","person","body"]},{"emoji":"๐Ÿคบ","name":"person fencing","keywords":["person","fencing","people","body"]},{"emoji":"โ›ท๏ธ","name":"skier","keywords":["skier","people","person","body"]},{"emoji":"๐Ÿ‚","name":"snowboarder","keywords":["snowboarder","people","person","body"]},{"emoji":"๐Ÿช‚","name":"parachute","keywords":["parachute","people","person","body"]},{"emoji":"๐Ÿ„","name":"person surfing","keywords":["person","surfing","people","body"]},{"emoji":"๐Ÿšฃ","name":"person rowing boat","keywords":["person","rowing","boat","people","body"]},{"emoji":"๐ŸŠ","name":"person swimming","keywords":["person","swimming","people","body"]},{"emoji":"๐Ÿคฝ","name":"person playing water polo","keywords":["person","playing","water","polo","people","body"]},{"emoji":"๐Ÿงœ","name":"merperson","keywords":["merperson","people","person","body"]},{"emoji":"๐Ÿงš","name":"fairy","keywords":["fairy","people","person","body"]},{"emoji":"๐Ÿงž","name":"genie","keywords":["genie","people","person","body"]},{"emoji":"๐Ÿฆธ","name":"superhero","keywords":["superhero","people","person","body"]},{"emoji":"๐Ÿฆน","name":"supervillain","keywords":["supervillain","people","person","body"]},{"emoji":"๐Ÿง","name":"elf","keywords":["elf","people","person","body"]},{"emoji":"๐Ÿง™","name":"mage","keywords":["mage","people","person","body"]},{"emoji":"๐ŸงŸ","name":"zombie","keywords":["zombie","people","person","body"]},{"emoji":"๐Ÿง›","name":"vampire","keywords":["vampire","people","person","body"]},{"emoji":"๐Ÿ‘ผ","name":"baby angel","keywords":["baby","angel","people","person","body"]},{"emoji":"๐ŸŽ…","name":"Santa Claus","keywords":["santa","claus","people","person","body"]},{"emoji":"๐Ÿคถ","name":"Mrs. Claus","keywords":["mrs","claus","people","person","body"]},{"emoji":"๐Ÿ’‚","name":"guard","keywords":["guard","people","person","body"]},{"emoji":"๐Ÿคด","name":"prince","keywords":["prince","people","person","body"]},{"emoji":"๐Ÿ‘ธ","name":"princess","keywords":["princess","people","person","body"]},{"emoji":"๐Ÿคต","name":"person in tuxedo","keywords":["person","tuxedo","people","body"]},{"emoji":"๐Ÿ‘ฐ","name":"person with veil","keywords":["person","veil","people","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿš€","name":"woman astronaut","keywords":["woman","astronaut","people","person","body"]},{"emoji":"๐Ÿ‘ท","name":"construction worker","keywords":["construction","worker","people","person","body"]},{"emoji":"๐Ÿ‘ฎ","name":"police officer","keywords":["police","officer","people","person","body"]},{"emoji":"๐Ÿ•ต๏ธ","name":"detective","keywords":["detective","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€โœˆ๏ธ","name":"woman pilot","keywords":["woman","pilot","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ”ฌ","name":"woman scientist","keywords":["woman","scientist","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€โš•๏ธ","name":"woman health worker","keywords":["woman","health","worker","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ”ง","name":"woman mechanic","keywords":["woman","mechanic","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿญ","name":"woman factory worker","keywords":["woman","factory","worker","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿš’","name":"woman firefighter","keywords":["woman","firefighter","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐ŸŒพ","name":"woman farmer","keywords":["woman","farmer","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿซ","name":"woman teacher","keywords":["woman","teacher","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐ŸŽ“","name":"woman student","keywords":["woman","student","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ’ผ","name":"woman office worker","keywords":["woman","office","worker","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€โš–๏ธ","name":"woman judge","keywords":["woman","judge","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ’ป","name":"woman technologist","keywords":["woman","technologist","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐ŸŽค","name":"woman singer","keywords":["woman","singer","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐ŸŽจ","name":"woman artist","keywords":["woman","artist","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿณ","name":"woman cook","keywords":["woman","cook","people","person","body"]},{"emoji":"๐Ÿ‘ณ","name":"person wearing turban","keywords":["person","wearing","turban","people","body"]},{"emoji":"๐Ÿง•","name":"woman with headscarf","keywords":["woman","headscarf","people","person","body"]},{"emoji":"๐Ÿ‘ฒ","name":"person with skullcap","keywords":["person","skullcap","people","body"]},{"emoji":"๐Ÿ‘ถ","name":"baby","keywords":["baby","people","person","body"]},{"emoji":"๐Ÿง’","name":"child","keywords":["child","people","person","body"]},{"emoji":"๐Ÿ‘ฆ","name":"boy","keywords":["boy","people","person","body"]},{"emoji":"๐Ÿ‘ง","name":"girl","keywords":["girl","people","person","body"]},{"emoji":"๐Ÿง‘","name":"person","keywords":["person","people","body"]},{"emoji":"๐Ÿ‘จ","name":"man","keywords":["man","people","person","body"]},{"emoji":"๐Ÿ‘ฉ","name":"woman","keywords":["woman","people","person","body"]},{"emoji":"๐Ÿง“","name":"older person","keywords":["older","person","people","body"]},{"emoji":"๐Ÿ‘ด","name":"old man","keywords":["old","man","people","person","body"]},{"emoji":"๐Ÿ‘ต","name":"old woman","keywords":["old","woman","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿฆณ","name":"man: white hair","keywords":["man","white","hair","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆณ","name":"woman: white hair","keywords":["woman","white","hair","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฐ","name":"man: red hair","keywords":["man","red","hair","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฐ","name":"woman: red hair","keywords":["woman","red","hair","people","person","body"]},{"emoji":"๐Ÿ‘ฑ","name":"person: blond hair","keywords":["person","blond","hair","people","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฑ","name":"man: curly hair","keywords":["man","curly","hair","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฑ","name":"woman: curly hair","keywords":["woman","curly","hair","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฒ","name":"man: bald","keywords":["man","bald","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฒ","name":"woman: bald","keywords":["woman","bald","people","person","body"]},{"emoji":"๐Ÿง”","name":"person: beard","keywords":["person","beard","people","body"]},{"emoji":"๐Ÿ•ด๏ธ","name":"person in suit levitating","keywords":["person","suit","levitating","people","body"]},{"emoji":"๐Ÿ’ƒ","name":"woman dancing","keywords":["woman","dancing","people","person","body"]},{"emoji":"๐Ÿ•บ","name":"man dancing","keywords":["man","dancing","people","person","body"]},{"emoji":"๐Ÿ‘ฏ","name":"people with bunny ears","keywords":["people","bunny","ears","person","body"]},{"emoji":"๐Ÿ‘ญ","name":"women holding hands","keywords":["women","holding","hands","people","person","body"]},{"emoji":"๐Ÿ‘ซ","name":"woman and man holding hands","keywords":["woman","man","holding","hands","people","person","body"]},{"emoji":"๐Ÿ‘ฌ","name":"men holding hands","keywords":["men","holding","hands","people","person","body"]},{"emoji":"๐Ÿ’","name":"kiss","keywords":["kiss","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","name":"kiss: woman, man","keywords":["kiss","woman","man","people","person","body"]},{"emoji":"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","name":"kiss: man, man","keywords":["kiss","man","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","name":"kiss: woman, woman","keywords":["kiss","woman","people","person","body"]},{"emoji":"๐Ÿ’‘","name":"couple with heart","keywords":["couple","heart","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","name":"couple with heart: woman, man","keywords":["couple","heart","woman","man","people","person","body"]},{"emoji":"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","name":"couple with heart: man, man","keywords":["couple","heart","man","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","name":"couple with heart: woman, woman","keywords":["couple","heart","woman","people","person","body"]},{"emoji":"๐Ÿ‘ช","name":"family","keywords":["family","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","name":"family: man, woman, boy","keywords":["family","man","woman","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","name":"family: man, woman, girl","keywords":["family","man","woman","girl","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","name":"family: man, woman, girl, boy","keywords":["family","man","woman","girl","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","name":"family: man, woman, boy, boy","keywords":["family","man","woman","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","name":"family: man, woman, girl, girl","keywords":["family","man","woman","girl","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ","name":"family: man, man, boy","keywords":["family","man","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง","name":"family: man, man, girl","keywords":["family","man","girl","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","name":"family: man, man, girl, boy","keywords":["family","man","girl","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","name":"family: man, man, boy, boy","keywords":["family","man","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","name":"family: man, man, girl, girl","keywords":["family","man","girl","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","name":"family: woman, woman, boy","keywords":["family","woman","boy","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","name":"family: woman, woman, girl","keywords":["family","woman","girl","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","name":"family: woman, woman, girl, boy","keywords":["family","woman","girl","boy","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","name":"family: woman, woman, boy, boy","keywords":["family","woman","boy","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","name":"family: woman, woman, girl, girl","keywords":["family","woman","girl","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฆ","name":"family: man, boy","keywords":["family","man","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","name":"family: man, boy, boy","keywords":["family","man","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ง","name":"family: man, girl","keywords":["family","man","girl","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","name":"family: man, girl, boy","keywords":["family","man","girl","boy","people","person","body"]},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","name":"family: man, girl, girl","keywords":["family","man","girl","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฆ","name":"family: woman, boy","keywords":["family","woman","boy","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","name":"family: woman, boy, boy","keywords":["family","woman","boy","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ง","name":"family: woman, girl","keywords":["family","woman","girl","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","name":"family: woman, girl, boy","keywords":["family","woman","girl","boy","people","person","body"]},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","name":"family: woman, girl, girl","keywords":["family","woman","girl","people","person","body"]},{"emoji":"๐Ÿคฐ","name":"pregnant woman","keywords":["pregnant","woman","people","person","body"]},{"emoji":"๐Ÿคฑ","name":"breast-feeding","keywords":["breast","feeding","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿฆผ","name":"person in motorized wheelchair","keywords":["person","motorized","wheelchair","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿฆฝ","name":"person in manual wheelchair","keywords":["person","manual","wheelchair","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿฆฏ","name":"person with white cane","keywords":["person","white","cane","people","body"]},{"emoji":"๐ŸงŒ","name":"troll","keywords":["troll","people","person","body"]},{"emoji":"๐Ÿฅท","name":"ninja","keywords":["ninja","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐ŸŽ„","name":"Mx Claus","keywords":["mx","claus","people","person","body"]},{"emoji":"๐Ÿซ…","name":"person with crown","keywords":["person","crown","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿš€","name":"astronaut","keywords":["astronaut","people","person","body"]},{"emoji":"๐Ÿง‘โ€โœˆ๏ธ","name":"pilot","keywords":["pilot","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿ”ฌ","name":"scientist","keywords":["scientist","people","person","body"]},{"emoji":"๐Ÿง‘โ€โš•๏ธ","name":"health worker","keywords":["health","worker","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿ”ง","name":"mechanic","keywords":["mechanic","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿญ","name":"factory worker","keywords":["factory","worker","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿš’","name":"firefighter","keywords":["firefighter","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐ŸŒพ","name":"farmer","keywords":["farmer","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿซ","name":"teacher","keywords":["teacher","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐ŸŽ“","name":"student","keywords":["student","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿ’ผ","name":"office worker","keywords":["office","worker","people","person","body"]},{"emoji":"๐Ÿง‘โ€โš–๏ธ","name":"judge","keywords":["judge","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿ’ป","name":"technologist","keywords":["technologist","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐ŸŽค","name":"singer","keywords":["singer","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐ŸŽจ","name":"artist","keywords":["artist","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿณ","name":"cook","keywords":["cook","people","person","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿฆณ","name":"person: white hair","keywords":["person","white","hair","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿฆฐ","name":"person: red hair","keywords":["person","red","hair","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿฆฑ","name":"person: curly hair","keywords":["person","curly","hair","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿฆฒ","name":"person: bald","keywords":["person","bald","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘","name":"people holding hands","keywords":["people","holding","hands","person","body"]},{"emoji":"๐Ÿซ„","name":"pregnant person","keywords":["pregnant","person","people","body"]},{"emoji":"๐Ÿง‘โ€๐Ÿผ","name":"person feeding baby","keywords":["person","feeding","baby","people","body"]},{"emoji":"๐Ÿ’","name":"bouquet","keywords":["bouquet","animal","nature"]},{"emoji":"๐ŸŒน","name":"rose","keywords":["rose","animal","nature"]},{"emoji":"๐Ÿฅ€","name":"wilted flower","keywords":["wilted","flower","animal","nature"]},{"emoji":"๐ŸŒบ","name":"hibiscus","keywords":["hibiscus","animal","nature"]},{"emoji":"๐ŸŒท","name":"tulip","keywords":["tulip","animal","nature"]},{"emoji":"๐Ÿชท","name":"lotus","keywords":["lotus","animal","nature"]},{"emoji":"๐ŸŒธ","name":"cherry blossom","keywords":["cherry","blossom","animal","nature"]},{"emoji":"๐Ÿ’ฎ","name":"white flower","keywords":["white","flower","animal","nature"]},{"emoji":"๐Ÿต๏ธ","name":"rosette","keywords":["rosette","animal","nature"]},{"emoji":"๐Ÿชป","name":"hyacinth","keywords":["hyacinth","animal","nature"]},{"emoji":"๐ŸŒป","name":"sunflower","keywords":["sunflower","animal","nature"]},{"emoji":"๐ŸŒผ","name":"blossom","keywords":["blossom","animal","nature"]},{"emoji":"๐Ÿ‚","name":"fallen leaf","keywords":["fallen","leaf","animal","nature"]},{"emoji":"๐Ÿ","name":"maple leaf","keywords":["maple","leaf","animal","nature"]},{"emoji":"๐Ÿ„","name":"mushroom","keywords":["mushroom","animal","nature"]},{"emoji":"๐ŸŒพ","name":"sheaf of rice","keywords":["sheaf","rice","animal","nature"]},{"emoji":"๐ŸŒฑ","name":"seedling","keywords":["seedling","animal","nature"]},{"emoji":"๐ŸŒฟ","name":"herb","keywords":["herb","animal","nature"]},{"emoji":"๐Ÿƒ","name":"leaf fluttering in wind","keywords":["leaf","fluttering","wind","animal","nature"]},{"emoji":"โ˜˜๏ธ","name":"shamrock","keywords":["shamrock","animal","nature"]},{"emoji":"๐Ÿ€","name":"four leaf clover","keywords":["four","leaf","clover","animal","nature"]},{"emoji":"๐Ÿชด","name":"potted plant","keywords":["potted","plant","animal","nature"]},{"emoji":"๐ŸŒต","name":"cactus","keywords":["cactus","animal","nature"]},{"emoji":"๐ŸŒด","name":"palm tree","keywords":["palm","tree","animal","nature"]},{"emoji":"๐Ÿชพ","name":"leafless tree","keywords":["leafless","tree","animal","nature"]},{"emoji":"๐ŸŒณ","name":"deciduous tree","keywords":["deciduous","tree","animal","nature"]},{"emoji":"๐ŸŒฒ","name":"evergreen tree","keywords":["evergreen","tree","animal","nature"]},{"emoji":"๐Ÿชต","name":"wood","keywords":["wood","animal","nature"]},{"emoji":"๐Ÿชน","name":"empty nest","keywords":["empty","nest","animal","nature"]},{"emoji":"๐Ÿชบ","name":"nest with eggs","keywords":["nest","eggs","animal","nature"]},{"emoji":"๐Ÿชจ","name":"rock","keywords":["rock","animal","nature"]},{"emoji":"โ›ฐ๏ธ","name":"mountain","keywords":["mountain","animal","nature"]},{"emoji":"๐Ÿ”๏ธ","name":"snow-capped mountain","keywords":["snow","capped","mountain","animal","nature"]},{"emoji":"โ„๏ธ","name":"snowflake","keywords":["snowflake","animal","nature"]},{"emoji":"๐ŸŒก๏ธ","name":"thermometer","keywords":["thermometer","animal","nature"]},{"emoji":"๐ŸŒ‹","name":"volcano","keywords":["volcano","animal","nature"]},{"emoji":"๐Ÿœ๏ธ","name":"desert","keywords":["desert","animal","nature"]},{"emoji":"๐Ÿž๏ธ","name":"national park","keywords":["national","park","animal","nature"]},{"emoji":"๐ŸŒ…","name":"sunrise","keywords":["sunrise","animal","nature"]},{"emoji":"๐ŸŒ„","name":"sunrise over mountains","keywords":["sunrise","over","mountains","animal","nature"]},{"emoji":"๐Ÿ๏ธ","name":"desert island","keywords":["desert","island","animal","nature"]},{"emoji":"๐Ÿ–๏ธ","name":"beach with umbrella","keywords":["beach","umbrella","animal","nature"]},{"emoji":"๐ŸŒˆ","name":"rainbow","keywords":["rainbow","animal","nature"]},{"emoji":"๐Ÿซง","name":"bubbles","keywords":["bubbles","animal","nature"]},{"emoji":"๐ŸŒŠ","name":"water wave","keywords":["water","wave","animal","nature"]},{"emoji":"๐ŸŒฌ๏ธ","name":"wind face","keywords":["wind","face","animal","nature"]},{"emoji":"๐ŸŒ€","name":"cyclone","keywords":["cyclone","animal","nature"]},{"emoji":"๐ŸŒช๏ธ","name":"tornado","keywords":["tornado","animal","nature"]},{"emoji":"โ˜”","name":"umbrella with rain drops","keywords":["umbrella","rain","drops","animal","nature"]},{"emoji":"๐Ÿ’ง","name":"droplet","keywords":["droplet","animal","nature"]},{"emoji":"โ˜๏ธ","name":"cloud","keywords":["cloud","animal","nature"]},{"emoji":"๐ŸŒจ๏ธ","name":"cloud with snow","keywords":["cloud","snow","animal","nature"]},{"emoji":"๐ŸŒง๏ธ","name":"cloud with rain","keywords":["cloud","rain","animal","nature"]},{"emoji":"๐ŸŒฉ๏ธ","name":"cloud with lightning","keywords":["cloud","lightning","animal","nature"]},{"emoji":"โ›ˆ๏ธ","name":"cloud with lightning and rain","keywords":["cloud","lightning","rain","animal","nature"]},{"emoji":"๐ŸŒฆ๏ธ","name":"sun behind rain cloud","keywords":["sun","behind","rain","cloud","animal","nature"]},{"emoji":"๐ŸŒฅ๏ธ","name":"sun behind large cloud","keywords":["sun","behind","large","cloud","animal","nature"]},{"emoji":"โ›…","name":"sun behind cloud","keywords":["sun","behind","cloud","animal","nature"]},{"emoji":"๐ŸŒค๏ธ","name":"sun behind small cloud","keywords":["sun","behind","small","cloud","animal","nature"]},{"emoji":"โ˜€๏ธ","name":"sun","keywords":["sun","animal","nature"]},{"emoji":"๐ŸŒ™","name":"crescent moon","keywords":["crescent","moon","animal","nature"]},{"emoji":"๐Ÿช","name":"ringed planet","keywords":["ringed","planet","animal","nature"]},{"emoji":"๐ŸŒ","name":"globe showing Europe-Africa","keywords":["globe","showing","europe","africa","animal","nature"]},{"emoji":"๐ŸŒŽ","name":"globe showing Americas","keywords":["globe","showing","americas","animal","nature"]},{"emoji":"๐ŸŒ","name":"globe showing Asia-Australia","keywords":["globe","showing","asia","australia","animal","nature"]},{"emoji":"๐ŸŒซ๏ธ","name":"fog","keywords":["fog","animal","nature"]},{"emoji":"๐ŸŒ ","name":"shooting star","keywords":["shooting","star","animal","nature"]},{"emoji":"๐ŸŒŒ","name":"milky way","keywords":["milky","way","animal","nature"]},{"emoji":"โ˜„๏ธ","name":"comet","keywords":["comet","animal","nature"]},{"emoji":"๐ŸŒ‘","name":"new moon","keywords":["new","moon","animal","nature"]},{"emoji":"๐ŸŒ’","name":"waxing crescent moon","keywords":["waxing","crescent","moon","animal","nature"]},{"emoji":"๐ŸŒ“","name":"first quarter moon","keywords":["first","quarter","moon","animal","nature"]},{"emoji":"๐ŸŒ”","name":"waxing gibbous moon","keywords":["waxing","gibbous","moon","animal","nature"]},{"emoji":"๐ŸŒ•","name":"full moon","keywords":["full","moon","animal","nature"]},{"emoji":"๐ŸŒ–","name":"waning gibbous moon","keywords":["waning","gibbous","moon","animal","nature"]},{"emoji":"๐ŸŒ—","name":"last quarter moon","keywords":["last","quarter","moon","animal","nature"]},{"emoji":"๐ŸŒ˜","name":"waning crescent moon","keywords":["waning","crescent","moon","animal","nature"]},{"emoji":"๐Ÿต","name":"monkey face","keywords":["monkey","face","animal","nature"]},{"emoji":"๐Ÿฆ","name":"lion","keywords":["lion","animal","nature"]},{"emoji":"๐Ÿฏ","name":"tiger face","keywords":["tiger","face","animal","nature"]},{"emoji":"๐Ÿฑ","name":"cat face","keywords":["cat","face","animal","nature"]},{"emoji":"๐Ÿถ","name":"dog face","keywords":["dog","face","animal","nature"]},{"emoji":"๐Ÿบ","name":"wolf","keywords":["wolf","animal","nature"]},{"emoji":"๐Ÿป","name":"bear","keywords":["bear","animal","nature"]},{"emoji":"๐Ÿปโ€โ„๏ธ","name":"polar bear","keywords":["polar","bear","animal","nature"]},{"emoji":"๐Ÿจ","name":"koala","keywords":["koala","animal","nature"]},{"emoji":"๐Ÿผ","name":"panda","keywords":["panda","animal","nature"]},{"emoji":"๐Ÿน","name":"hamster","keywords":["hamster","animal","nature"]},{"emoji":"๐Ÿญ","name":"mouse face","keywords":["mouse","face","animal","nature"]},{"emoji":"๐Ÿฐ","name":"rabbit face","keywords":["rabbit","face","animal","nature"]},{"emoji":"๐ŸฆŠ","name":"fox","keywords":["fox","animal","nature"]},{"emoji":"๐Ÿฆ","name":"raccoon","keywords":["raccoon","animal","nature"]},{"emoji":"๐Ÿฎ","name":"cow face","keywords":["cow","face","animal","nature"]},{"emoji":"๐Ÿท","name":"pig face","keywords":["pig","face","animal","nature"]},{"emoji":"๐Ÿฝ","name":"pig nose","keywords":["pig","nose","animal","nature"]},{"emoji":"๐Ÿ—","name":"boar","keywords":["boar","animal","nature"]},{"emoji":"๐Ÿฆ“","name":"zebra","keywords":["zebra","animal","nature"]},{"emoji":"๐Ÿฆ„","name":"unicorn","keywords":["unicorn","animal","nature"]},{"emoji":"๐Ÿด","name":"horse face","keywords":["horse","face","animal","nature"]},{"emoji":"๐ŸซŽ","name":"moose","keywords":["moose","animal","nature"]},{"emoji":"๐Ÿฒ","name":"dragon face","keywords":["dragon","face","animal","nature"]},{"emoji":"๐ŸฆŽ","name":"lizard","keywords":["lizard","animal","nature"]},{"emoji":"๐Ÿ‰","name":"dragon","keywords":["dragon","animal","nature"]},{"emoji":"๐Ÿฆ–","name":"T-Rex","keywords":["rex","animal","nature"]},{"emoji":"๐Ÿฆ•","name":"sauropod","keywords":["sauropod","animal","nature"]},{"emoji":"๐Ÿข","name":"turtle","keywords":["turtle","animal","nature"]},{"emoji":"๐ŸŠ","name":"crocodile","keywords":["crocodile","animal","nature"]},{"emoji":"๐Ÿ","name":"snake","keywords":["snake","animal","nature"]},{"emoji":"๐Ÿธ","name":"frog","keywords":["frog","animal","nature"]},{"emoji":"๐Ÿ‡","name":"rabbit","keywords":["rabbit","animal","nature"]},{"emoji":"๐Ÿ","name":"mouse","keywords":["mouse","animal","nature"]},{"emoji":"๐Ÿ€","name":"rat","keywords":["rat","animal","nature"]},{"emoji":"๐Ÿˆ","name":"cat","keywords":["cat","animal","nature"]},{"emoji":"๐Ÿˆโ€โฌ›","name":"black cat","keywords":["black","cat","animal","nature"]},{"emoji":"๐Ÿฉ","name":"poodle","keywords":["poodle","animal","nature"]},{"emoji":"๐Ÿ•","name":"dog","keywords":["dog","animal","nature"]},{"emoji":"๐Ÿฆฎ","name":"guide dog","keywords":["guide","dog","animal","nature"]},{"emoji":"๐Ÿ•โ€๐Ÿฆบ","name":"service dog","keywords":["service","dog","animal","nature"]},{"emoji":"๐Ÿ–","name":"pig","keywords":["pig","animal","nature"]},{"emoji":"๐ŸŽ","name":"horse","keywords":["horse","animal","nature"]},{"emoji":"๐Ÿซ","name":"donkey","keywords":["donkey","animal","nature"]},{"emoji":"๐Ÿ„","name":"cow","keywords":["cow","animal","nature"]},{"emoji":"๐Ÿ‚","name":"ox","keywords":["ox","animal","nature"]},{"emoji":"๐Ÿƒ","name":"water buffalo","keywords":["water","buffalo","animal","nature"]},{"emoji":"๐Ÿฆฌ","name":"bison","keywords":["bison","animal","nature"]},{"emoji":"๐Ÿ","name":"ram","keywords":["ram","animal","nature"]},{"emoji":"๐Ÿ‘","name":"ewe","keywords":["ewe","animal","nature"]},{"emoji":"๐Ÿ","name":"goat","keywords":["goat","animal","nature"]},{"emoji":"๐ŸฆŒ","name":"deer","keywords":["deer","animal","nature"]},{"emoji":"๐Ÿฆ™","name":"llama","keywords":["llama","animal","nature"]},{"emoji":"๐Ÿฆฅ","name":"sloth","keywords":["sloth","animal","nature"]},{"emoji":"๐Ÿฆ˜","name":"kangaroo","keywords":["kangaroo","animal","nature"]},{"emoji":"๐Ÿ˜","name":"elephant","keywords":["elephant","animal","nature"]},{"emoji":"๐Ÿฆฃ","name":"mammoth","keywords":["mammoth","animal","nature"]},{"emoji":"๐Ÿฆ","name":"rhinoceros","keywords":["rhinoceros","animal","nature"]},{"emoji":"๐Ÿฆ›","name":"hippopotamus","keywords":["hippopotamus","animal","nature"]},{"emoji":"๐Ÿฆ’","name":"giraffe","keywords":["giraffe","animal","nature"]},{"emoji":"๐Ÿ†","name":"leopard","keywords":["leopard","animal","nature"]},{"emoji":"๐Ÿ…","name":"tiger","keywords":["tiger","animal","nature"]},{"emoji":"๐Ÿ’","name":"monkey","keywords":["monkey","animal","nature"]},{"emoji":"๐Ÿฆ","name":"gorilla","keywords":["gorilla","animal","nature"]},{"emoji":"๐Ÿฆง","name":"orangutan","keywords":["orangutan","animal","nature"]},{"emoji":"๐Ÿช","name":"camel","keywords":["camel","animal","nature"]},{"emoji":"๐Ÿซ","name":"two-hump camel","keywords":["two","hump","camel","animal","nature"]},{"emoji":"๐Ÿฟ๏ธ","name":"chipmunk","keywords":["chipmunk","animal","nature"]},{"emoji":"๐Ÿฆซ","name":"beaver","keywords":["beaver","animal","nature"]},{"emoji":"๐Ÿฆจ","name":"skunk","keywords":["skunk","animal","nature"]},{"emoji":"๐Ÿฆก","name":"badger","keywords":["badger","animal","nature"]},{"emoji":"๐Ÿฆ”","name":"hedgehog","keywords":["hedgehog","animal","nature"]},{"emoji":"๐Ÿฆฆ","name":"otter","keywords":["otter","animal","nature"]},{"emoji":"๐Ÿฆ‡","name":"bat","keywords":["bat","animal","nature"]},{"emoji":"๐Ÿชฝ","name":"wing","keywords":["wing","animal","nature"]},{"emoji":"๐Ÿชถ","name":"feather","keywords":["feather","animal","nature"]},{"emoji":"๐Ÿฆ","name":"bird","keywords":["bird","animal","nature"]},{"emoji":"๐Ÿฆโ€โฌ›","name":"black bird","keywords":["black","bird","animal","nature"]},{"emoji":"๐Ÿ“","name":"rooster","keywords":["rooster","animal","nature"]},{"emoji":"๐Ÿ”","name":"chicken","keywords":["chicken","animal","nature"]},{"emoji":"๐Ÿฃ","name":"hatching chick","keywords":["hatching","chick","animal","nature"]},{"emoji":"๐Ÿค","name":"baby chick","keywords":["baby","chick","animal","nature"]},{"emoji":"๐Ÿฅ","name":"front-facing baby chick","keywords":["front","facing","baby","chick","animal","nature"]},{"emoji":"๐Ÿฆ…","name":"eagle","keywords":["eagle","animal","nature"]},{"emoji":"๐Ÿฆ‰","name":"owl","keywords":["owl","animal","nature"]},{"emoji":"๐Ÿฆœ","name":"parrot","keywords":["parrot","animal","nature"]},{"emoji":"๐Ÿ•Š๏ธ","name":"dove","keywords":["dove","animal","nature"]},{"emoji":"๐Ÿฆค","name":"dodo","keywords":["dodo","animal","nature"]},{"emoji":"๐Ÿฆข","name":"swan","keywords":["swan","animal","nature"]},{"emoji":"๐Ÿฆ†","name":"duck","keywords":["duck","animal","nature"]},{"emoji":"๐Ÿชฟ","name":"goose","keywords":["goose","animal","nature"]},{"emoji":"๐Ÿฆฉ","name":"flamingo","keywords":["flamingo","animal","nature"]},{"emoji":"๐Ÿฆš","name":"peacock","keywords":["peacock","animal","nature"]},{"emoji":"๐Ÿฆโ€๐Ÿ”ฅ","name":"phoenix","keywords":["phoenix","animal","nature"]},{"emoji":"๐Ÿฆƒ","name":"turkey","keywords":["turkey","animal","nature"]},{"emoji":"๐Ÿง","name":"penguin","keywords":["penguin","animal","nature"]},{"emoji":"๐Ÿฆญ","name":"seal","keywords":["seal","animal","nature"]},{"emoji":"๐Ÿฆˆ","name":"shark","keywords":["shark","animal","nature"]},{"emoji":"๐Ÿฌ","name":"dolphin","keywords":["dolphin","animal","nature"]},{"emoji":"๐Ÿ‹","name":"whale","keywords":["whale","animal","nature"]},{"emoji":"๐Ÿณ","name":"spouting whale","keywords":["spouting","whale","animal","nature"]},{"emoji":"๐ŸŸ","name":"fish","keywords":["fish","animal","nature"]},{"emoji":"๐Ÿ ","name":"tropical fish","keywords":["tropical","fish","animal","nature"]},{"emoji":"๐Ÿก","name":"blowfish","keywords":["blowfish","animal","nature"]},{"emoji":"๐Ÿฆ","name":"shrimp","keywords":["shrimp","animal","nature"]},{"emoji":"๐Ÿฆž","name":"lobster","keywords":["lobster","animal","nature"]},{"emoji":"๐Ÿฆ€","name":"crab","keywords":["crab","animal","nature"]},{"emoji":"๐Ÿฆ‘","name":"squid","keywords":["squid","animal","nature"]},{"emoji":"๐Ÿ™","name":"octopus","keywords":["octopus","animal","nature"]},{"emoji":"๐Ÿชผ","name":"jellyfish","keywords":["jellyfish","animal","nature"]},{"emoji":"๐Ÿฆช","name":"oyster","keywords":["oyster","animal","nature"]},{"emoji":"๐Ÿชธ","name":"coral","keywords":["coral","animal","nature"]},{"emoji":"๐Ÿฆ‚","name":"scorpion","keywords":["scorpion","animal","nature"]},{"emoji":"๐Ÿ•ท๏ธ","name":"spider","keywords":["spider","animal","nature"]},{"emoji":"๐Ÿ•ธ๏ธ","name":"spider web","keywords":["spider","web","animal","nature"]},{"emoji":"๐Ÿš","name":"spiral shell","keywords":["spiral","shell","animal","nature"]},{"emoji":"๐ŸŒ","name":"snail","keywords":["snail","animal","nature"]},{"emoji":"๐Ÿœ","name":"ant","keywords":["ant","animal","nature"]},{"emoji":"๐Ÿฆ—","name":"cricket","keywords":["cricket","animal","nature"]},{"emoji":"๐Ÿชฒ","name":"beetle","keywords":["beetle","animal","nature"]},{"emoji":"๐ŸฆŸ","name":"mosquito","keywords":["mosquito","animal","nature"]},{"emoji":"๐Ÿชณ","name":"cockroach","keywords":["cockroach","animal","nature"]},{"emoji":"๐Ÿชฐ","name":"fly","keywords":["fly","animal","nature"]},{"emoji":"๐Ÿ","name":"honeybee","keywords":["honeybee","animal","nature"]},{"emoji":"๐Ÿž","name":"lady beetle","keywords":["lady","beetle","animal","nature"]},{"emoji":"๐Ÿฆ‹","name":"butterfly","keywords":["butterfly","animal","nature"]},{"emoji":"๐Ÿ›","name":"bug","keywords":["bug","animal","nature"]},{"emoji":"๐Ÿชฑ","name":"worm","keywords":["worm","animal","nature"]},{"emoji":"๐Ÿพ","name":"paw prints","keywords":["paw","prints","animal","nature"]},{"emoji":"๐Ÿ“","name":"strawberry","keywords":["strawberry","food","drink"]},{"emoji":"๐Ÿ’","name":"cherries","keywords":["cherries","food","drink"]},{"emoji":"๐ŸŽ","name":"red apple","keywords":["red","apple","food","drink"]},{"emoji":"๐Ÿ…","name":"tomato","keywords":["tomato","food","drink"]},{"emoji":"๐ŸŒถ๏ธ","name":"hot pepper","keywords":["hot","pepper","food","drink"]},{"emoji":"๐Ÿ‰","name":"watermelon","keywords":["watermelon","food","drink"]},{"emoji":"๐Ÿ‘","name":"peach","keywords":["peach","food","drink"]},{"emoji":"๐ŸŠ","name":"tangerine","keywords":["tangerine","food","drink"]},{"emoji":"๐Ÿฅ•","name":"carrot","keywords":["carrot","food","drink"]},{"emoji":"๐Ÿฅญ","name":"mango","keywords":["mango","food","drink"]},{"emoji":"๐Ÿ","name":"pineapple","keywords":["pineapple","food","drink"]},{"emoji":"๐ŸŒ","name":"banana","keywords":["banana","food","drink"]},{"emoji":"๐ŸŒฝ","name":"ear of corn","keywords":["ear","corn","food","drink"]},{"emoji":"๐Ÿ‹","name":"lemon","keywords":["lemon","food","drink"]},{"emoji":"๐Ÿ‹โ€๐ŸŸฉ","name":"lime","keywords":["lime","food","drink"]},{"emoji":"๐Ÿˆ","name":"melon","keywords":["melon","food","drink"]},{"emoji":"๐Ÿ","name":"pear","keywords":["pear","food","drink"]},{"emoji":"๐Ÿซ›","name":"pea pod","keywords":["pea","pod","food","drink"]},{"emoji":"๐Ÿฅฌ","name":"leafy green","keywords":["leafy","green","food","drink"]},{"emoji":"๐Ÿซ‘","name":"bell pepper","keywords":["bell","pepper","food","drink"]},{"emoji":"๐Ÿ","name":"green apple","keywords":["green","apple","food","drink"]},{"emoji":"๐Ÿฅ","name":"kiwi fruit","keywords":["kiwi","fruit","food","drink"]},{"emoji":"๐Ÿฅ‘","name":"avocado","keywords":["avocado","food","drink"]},{"emoji":"๐Ÿซ’","name":"olive","keywords":["olive","food","drink"]},{"emoji":"๐Ÿฅฆ","name":"broccoli","keywords":["broccoli","food","drink"]},{"emoji":"๐Ÿฅ’","name":"cucumber","keywords":["cucumber","food","drink"]},{"emoji":"๐Ÿซ","name":"blueberries","keywords":["blueberries","food","drink"]},{"emoji":"๐Ÿ‡","name":"grapes","keywords":["grapes","food","drink"]},{"emoji":"๐Ÿ†","name":"eggplant","keywords":["eggplant","food","drink"]},{"emoji":"๐Ÿ ","name":"roasted sweet potato","keywords":["roasted","sweet","potato","food","drink"]},{"emoji":"๐Ÿซœ","name":"root vegetable","keywords":["root","vegetable","food","drink"]},{"emoji":"๐Ÿฅฅ","name":"coconut","keywords":["coconut","food","drink"]},{"emoji":"๐Ÿฅ”","name":"potato","keywords":["potato","food","drink"]},{"emoji":"๐Ÿ„โ€๐ŸŸซ","name":"brown mushroom","keywords":["brown","mushroom","food","drink"]},{"emoji":"๐Ÿง…","name":"onion","keywords":["onion","food","drink"]},{"emoji":"๐Ÿซš","name":"ginger root","keywords":["ginger","root","food","drink"]},{"emoji":"๐Ÿง„","name":"garlic","keywords":["garlic","food","drink"]},{"emoji":"๐Ÿซ˜","name":"beans","keywords":["beans","food","drink"]},{"emoji":"๐ŸŒฐ","name":"chestnut","keywords":["chestnut","food","drink"]},{"emoji":"๐Ÿฅœ","name":"peanuts","keywords":["peanuts","food","drink"]},{"emoji":"๐Ÿž","name":"bread","keywords":["bread","food","drink"]},{"emoji":"๐Ÿซ“","name":"flatbread","keywords":["flatbread","food","drink"]},{"emoji":"๐Ÿฅ","name":"croissant","keywords":["croissant","food","drink"]},{"emoji":"๐Ÿฅ–","name":"baguette bread","keywords":["baguette","bread","food","drink"]},{"emoji":"๐Ÿฅฏ","name":"bagel","keywords":["bagel","food","drink"]},{"emoji":"๐Ÿง‡","name":"waffle","keywords":["waffle","food","drink"]},{"emoji":"๐Ÿฅž","name":"pancakes","keywords":["pancakes","food","drink"]},{"emoji":"๐Ÿณ","name":"cooking","keywords":["cooking","food","drink"]},{"emoji":"๐Ÿฅš","name":"egg","keywords":["egg","food","drink"]},{"emoji":"๐Ÿง€","name":"cheese wedge","keywords":["cheese","wedge","food","drink"]},{"emoji":"๐Ÿฅ“","name":"bacon","keywords":["bacon","food","drink"]},{"emoji":"๐Ÿฅฉ","name":"cut of meat","keywords":["cut","meat","food","drink"]},{"emoji":"๐Ÿ—","name":"poultry leg","keywords":["poultry","leg","food","drink"]},{"emoji":"๐Ÿ–","name":"meat on bone","keywords":["meat","bone","food","drink"]},{"emoji":"๐Ÿ”","name":"hamburger","keywords":["hamburger","food","drink"]},{"emoji":"๐ŸŒญ","name":"hot dog","keywords":["hot","dog","food","drink"]},{"emoji":"๐Ÿฅช","name":"sandwich","keywords":["sandwich","food","drink"]},{"emoji":"๐Ÿฅจ","name":"pretzel","keywords":["pretzel","food","drink"]},{"emoji":"๐ŸŸ","name":"french fries","keywords":["french","fries","food","drink"]},{"emoji":"๐Ÿ•","name":"pizza","keywords":["pizza","food","drink"]},{"emoji":"๐Ÿซ”","name":"tamale","keywords":["tamale","food","drink"]},{"emoji":"๐ŸŒฎ","name":"taco","keywords":["taco","food","drink"]},{"emoji":"๐ŸŒฏ","name":"burrito","keywords":["burrito","food","drink"]},{"emoji":"๐Ÿฅ™","name":"stuffed flatbread","keywords":["stuffed","flatbread","food","drink"]},{"emoji":"๐Ÿง†","name":"falafel","keywords":["falafel","food","drink"]},{"emoji":"๐Ÿฅ˜","name":"shallow pan of food","keywords":["shallow","pan","food","drink"]},{"emoji":"๐Ÿ","name":"spaghetti","keywords":["spaghetti","food","drink"]},{"emoji":"๐Ÿฅซ","name":"canned food","keywords":["canned","food","drink"]},{"emoji":"๐Ÿซ•","name":"fondue","keywords":["fondue","food","drink"]},{"emoji":"๐Ÿฅฃ","name":"bowl with spoon","keywords":["bowl","spoon","food","drink"]},{"emoji":"๐Ÿฅ—","name":"green salad","keywords":["green","salad","food","drink"]},{"emoji":"๐Ÿฒ","name":"pot of food","keywords":["pot","food","drink"]},{"emoji":"๐Ÿ›","name":"curry rice","keywords":["curry","rice","food","drink"]},{"emoji":"๐Ÿœ","name":"steaming bowl","keywords":["steaming","bowl","food","drink"]},{"emoji":"๐Ÿฃ","name":"sushi","keywords":["sushi","food","drink"]},{"emoji":"๐Ÿค","name":"fried shrimp","keywords":["fried","shrimp","food","drink"]},{"emoji":"๐Ÿฅก","name":"takeout box","keywords":["takeout","box","food","drink"]},{"emoji":"๐Ÿš","name":"cooked rice","keywords":["cooked","rice","food","drink"]},{"emoji":"๐Ÿฑ","name":"bento box","keywords":["bento","box","food","drink"]},{"emoji":"๐ŸฅŸ","name":"dumpling","keywords":["dumpling","food","drink"]},{"emoji":"๐Ÿข","name":"oden","keywords":["oden","food","drink"]},{"emoji":"๐Ÿ™","name":"rice ball","keywords":["rice","ball","food","drink"]},{"emoji":"๐Ÿ˜","name":"rice cracker","keywords":["rice","cracker","food","drink"]},{"emoji":"๐Ÿฅ","name":"fish cake with swirl","keywords":["fish","cake","swirl","food","drink"]},{"emoji":"๐Ÿก","name":"dango","keywords":["dango","food","drink"]},{"emoji":"๐Ÿฅ ","name":"fortune cookie","keywords":["fortune","cookie","food","drink"]},{"emoji":"๐Ÿฅฎ","name":"moon cake","keywords":["moon","cake","food","drink"]},{"emoji":"๐Ÿง","name":"shaved ice","keywords":["shaved","ice","food","drink"]},{"emoji":"๐Ÿจ","name":"ice cream","keywords":["ice","cream","food","drink"]},{"emoji":"๐Ÿฆ","name":"soft ice cream","keywords":["soft","ice","cream","food","drink"]},{"emoji":"๐Ÿฅง","name":"pie","keywords":["pie","food","drink"]},{"emoji":"๐Ÿฐ","name":"shortcake","keywords":["shortcake","food","drink"]},{"emoji":"๐Ÿฎ","name":"custard","keywords":["custard","food","drink"]},{"emoji":"๐ŸŽ‚","name":"birthday cake","keywords":["birthday","cake","food","drink"]},{"emoji":"๐Ÿง","name":"cupcake","keywords":["cupcake","food","drink"]},{"emoji":"๐Ÿญ","name":"lollipop","keywords":["lollipop","food","drink"]},{"emoji":"๐Ÿฌ","name":"candy","keywords":["candy","food","drink"]},{"emoji":"๐Ÿซ","name":"chocolate bar","keywords":["chocolate","bar","food","drink"]},{"emoji":"๐Ÿฉ","name":"doughnut","keywords":["doughnut","food","drink"]},{"emoji":"๐Ÿช","name":"cookie","keywords":["cookie","food","drink"]},{"emoji":"๐Ÿฏ","name":"honey pot","keywords":["honey","pot","food","drink"]},{"emoji":"๐Ÿง‚","name":"salt","keywords":["salt","food","drink"]},{"emoji":"๐Ÿงˆ","name":"butter","keywords":["butter","food","drink"]},{"emoji":"๐Ÿฟ","name":"popcorn","keywords":["popcorn","food","drink"]},{"emoji":"๐ŸงŠ","name":"ice","keywords":["ice","food","drink"]},{"emoji":"๐Ÿซ™","name":"jar","keywords":["jar","food","drink"]},{"emoji":"๐Ÿฅค","name":"cup with straw","keywords":["cup","straw","food","drink"]},{"emoji":"๐Ÿง‹","name":"bubble tea","keywords":["bubble","tea","food","drink"]},{"emoji":"๐Ÿงƒ","name":"beverage box","keywords":["beverage","box","food","drink"]},{"emoji":"๐Ÿฅ›","name":"glass of milk","keywords":["glass","milk","food","drink"]},{"emoji":"๐Ÿผ","name":"baby bottle","keywords":["baby","bottle","food","drink"]},{"emoji":"๐Ÿต","name":"teacup without handle","keywords":["teacup","without","handle","food","drink"]},{"emoji":"โ˜•","name":"hot beverage","keywords":["hot","beverage","food","drink"]},{"emoji":"๐Ÿซ–","name":"teapot","keywords":["teapot","food","drink"]},{"emoji":"๐Ÿง‰","name":"mate","keywords":["mate","food","drink"]},{"emoji":"๐Ÿบ","name":"beer mug","keywords":["beer","mug","food","drink"]},{"emoji":"๐Ÿป","name":"clinking beer mugs","keywords":["clinking","beer","mugs","food","drink"]},{"emoji":"๐Ÿฅ‚","name":"clinking glasses","keywords":["clinking","glasses","food","drink"]},{"emoji":"๐Ÿพ","name":"bottle with popping cork","keywords":["bottle","popping","cork","food","drink"]},{"emoji":"๐Ÿท","name":"wine glass","keywords":["wine","glass","food","drink"]},{"emoji":"๐Ÿฅƒ","name":"tumbler glass","keywords":["tumbler","glass","food","drink"]},{"emoji":"๐Ÿซ—","name":"pouring liquid","keywords":["pouring","liquid","food","drink"]},{"emoji":"๐Ÿธ","name":"cocktail glass","keywords":["cocktail","glass","food","drink"]},{"emoji":"๐Ÿน","name":"tropical drink","keywords":["tropical","drink","food"]},{"emoji":"๐Ÿถ","name":"sake","keywords":["sake","food","drink"]},{"emoji":"๐Ÿฅข","name":"chopsticks","keywords":["chopsticks","food","drink"]},{"emoji":"๐Ÿด","name":"fork and knife","keywords":["fork","knife","food","drink"]},{"emoji":"๐Ÿฅ„","name":"spoon","keywords":["spoon","food","drink"]},{"emoji":"๐Ÿ”ช","name":"kitchen knife","keywords":["kitchen","knife","food","drink"]},{"emoji":"๐Ÿฝ๏ธ","name":"fork and knife with plate","keywords":["fork","knife","plate","food","drink"]},{"emoji":"๐ŸŽˆ","name":"balloon","keywords":["balloon","activity","sport"]},{"emoji":"๐ŸŽ€","name":"ribbon","keywords":["ribbon","activity","sport"]},{"emoji":"๐ŸŽ","name":"wrapped gift","keywords":["wrapped","gift","activity","sport"]},{"emoji":"๐ŸŽ‡","name":"sparkler","keywords":["sparkler","activity","sport"]},{"emoji":"๐ŸŽ†","name":"fireworks","keywords":["fireworks","activity","sport"]},{"emoji":"๐Ÿงจ","name":"firecracker","keywords":["firecracker","activity","sport"]},{"emoji":"๐Ÿงง","name":"red envelope","keywords":["red","envelope","activity","sport"]},{"emoji":"๐Ÿช”","name":"diya lamp","keywords":["diya","lamp","activity","sport"]},{"emoji":"๐Ÿช…","name":"piรฑata","keywords":["pi","ata","activity","sport"]},{"emoji":"๐Ÿชฉ","name":"mirror ball","keywords":["mirror","ball","activity","sport"]},{"emoji":"๐ŸŽ","name":"wind chime","keywords":["wind","chime","activity","sport"]},{"emoji":"๐ŸŽ","name":"carp streamer","keywords":["carp","streamer","activity","sport"]},{"emoji":"๐ŸŽŽ","name":"Japanese dolls","keywords":["japanese","dolls","activity","sport"]},{"emoji":"๐ŸŽ‘","name":"moon viewing ceremony","keywords":["moon","viewing","ceremony","activity","sport"]},{"emoji":"๐ŸŽ","name":"pine decoration","keywords":["pine","decoration","activity","sport"]},{"emoji":"๐ŸŽ‹","name":"tanabata tree","keywords":["tanabata","tree","activity","sport"]},{"emoji":"๐ŸŽ„","name":"Christmas tree","keywords":["christmas","tree","activity","sport"]},{"emoji":"๐ŸŽ—๏ธ","name":"reminder ribbon","keywords":["reminder","ribbon","activity","sport"]},{"emoji":"๐Ÿฅ‡","name":"1st place medal","keywords":["1st","place","medal","activity","sport"]},{"emoji":"๐Ÿฅˆ","name":"2nd place medal","keywords":["2nd","place","medal","activity","sport"]},{"emoji":"๐Ÿฅ‰","name":"3rd place medal","keywords":["3rd","place","medal","activity","sport"]},{"emoji":"๐Ÿ…","name":"sports medal","keywords":["sports","medal","activity","sport"]},{"emoji":"๐ŸŽ–๏ธ","name":"military medal","keywords":["military","medal","activity","sport"]},{"emoji":"๐Ÿ†","name":"trophy","keywords":["trophy","activity","sport"]},{"emoji":"๐Ÿ“ข","name":"loudspeaker","keywords":["loudspeaker","activity","sport"]},{"emoji":"โšฝ","name":"soccer ball","keywords":["soccer","ball","activity","sport"]},{"emoji":"โšพ","name":"baseball","keywords":["baseball","activity","sport"]},{"emoji":"๐ŸฅŽ","name":"softball","keywords":["softball","activity","sport"]},{"emoji":"๐Ÿ€","name":"basketball","keywords":["basketball","activity","sport"]},{"emoji":"๐Ÿ","name":"volleyball","keywords":["volleyball","activity","sport"]},{"emoji":"๐Ÿˆ","name":"american football","keywords":["american","football","activity","sport"]},{"emoji":"๐Ÿ‰","name":"rugby football","keywords":["rugby","football","activity","sport"]},{"emoji":"๐Ÿฅ…","name":"goal net","keywords":["goal","net","activity","sport"]},{"emoji":"๐ŸŽพ","name":"tennis","keywords":["tennis","activity","sport"]},{"emoji":"๐Ÿธ","name":"badminton","keywords":["badminton","activity","sport"]},{"emoji":"๐Ÿฅ","name":"lacrosse","keywords":["lacrosse","activity","sport"]},{"emoji":"๐Ÿ","name":"cricket game","keywords":["cricket","game","activity","sport"]},{"emoji":"๐Ÿ‘","name":"field hockey","keywords":["field","hockey","activity","sport"]},{"emoji":"๐Ÿ’","name":"ice hockey","keywords":["ice","hockey","activity","sport"]},{"emoji":"๐ŸฅŒ","name":"curling stone","keywords":["curling","stone","activity","sport"]},{"emoji":"๐Ÿ›ท","name":"sled","keywords":["sled","activity","sport"]},{"emoji":"๐ŸŽฟ","name":"skis","keywords":["skis","activity","sport"]},{"emoji":"โ›ธ๏ธ","name":"ice skate","keywords":["ice","skate","activity","sport"]},{"emoji":"๐Ÿ›ผ","name":"roller skate","keywords":["roller","skate","activity","sport"]},{"emoji":"๐Ÿฉฐ","name":"ballet shoes","keywords":["ballet","shoes","activity","sport"]},{"emoji":"๐Ÿ›น","name":"skateboard","keywords":["skateboard","activity","sport"]},{"emoji":"โ›ณ","name":"flag in hole","keywords":["flag","hole","activity","sport"]},{"emoji":"๐ŸŽฏ","name":"bullseye","keywords":["bullseye","activity","sport"]},{"emoji":"๐Ÿน","name":"bow and arrow","keywords":["bow","arrow","activity","sport"]},{"emoji":"๐Ÿฅ","name":"flying disc","keywords":["flying","disc","activity","sport"]},{"emoji":"๐Ÿชƒ","name":"boomerang","keywords":["boomerang","activity","sport"]},{"emoji":"๐Ÿช","name":"kite","keywords":["kite","activity","sport"]},{"emoji":"๐ŸŽฃ","name":"fishing pole","keywords":["fishing","pole","activity","sport"]},{"emoji":"๐Ÿคฟ","name":"diving mask","keywords":["diving","mask","activity","sport"]},{"emoji":"๐Ÿฉฑ","name":"one-piece swimsuit","keywords":["one","piece","swimsuit","activity","sport"]},{"emoji":"๐ŸŽฝ","name":"running shirt","keywords":["running","shirt","activity","sport"]},{"emoji":"๐Ÿฅ‹","name":"martial arts uniform","keywords":["martial","arts","uniform","activity","sport"]},{"emoji":"๐ŸฅŠ","name":"boxing glove","keywords":["boxing","glove","activity","sport"]},{"emoji":"๐ŸŽฑ","name":"pool 8 ball","keywords":["pool","ball","activity","sport"]},{"emoji":"๐Ÿ“","name":"ping pong","keywords":["ping","pong","activity","sport"]},{"emoji":"๐ŸŽณ","name":"bowling","keywords":["bowling","activity","sport"]},{"emoji":"โ™Ÿ๏ธ","name":"chess pawn","keywords":["chess","pawn","activity","sport"]},{"emoji":"๐Ÿช€","name":"yo-yo","keywords":["yo","activity","sport"]},{"emoji":"๐Ÿงฉ","name":"puzzle piece","keywords":["puzzle","piece","activity","sport"]},{"emoji":"๐ŸŽฎ","name":"video game","keywords":["video","game","activity","sport"]},{"emoji":"๐Ÿ•น๏ธ","name":"joystick","keywords":["joystick","activity","sport"]},{"emoji":"๐Ÿ”ซ","name":"water pistol","keywords":["water","pistol","activity","sport"]},{"emoji":"๐ŸŽฒ","name":"game die","keywords":["game","die","activity","sport"]},{"emoji":"๐ŸŽฐ","name":"slot machine","keywords":["slot","machine","activity","sport"]},{"emoji":"๐ŸŽด","name":"flower playing cards","keywords":["flower","playing","cards","activity","sport"]},{"emoji":"๐Ÿ€„","name":"mahjong red dragon","keywords":["mahjong","red","dragon","activity","sport"]},{"emoji":"๐Ÿƒ","name":"joker","keywords":["joker","activity","sport"]},{"emoji":"๐Ÿช„","name":"magic wand","keywords":["magic","wand","activity","sport"]},{"emoji":"๐ŸŽฉ","name":"top hat","keywords":["top","hat","activity","sport"]},{"emoji":"๐Ÿ“ท","name":"camera","keywords":["camera","activity","sport"]},{"emoji":"๐Ÿ“ธ","name":"camera with flash","keywords":["camera","flash","activity","sport"]},{"emoji":"๐Ÿ–ผ๏ธ","name":"framed picture","keywords":["framed","picture","activity","sport"]},{"emoji":"๐ŸŽจ","name":"artist palette","keywords":["artist","palette","activity","sport"]},{"emoji":"๐ŸซŸ","name":"splatter","keywords":["splatter","activity","sport"]},{"emoji":"๐Ÿ–Œ๏ธ","name":"paintbrush","keywords":["paintbrush","activity","sport"]},{"emoji":"๐Ÿ–๏ธ","name":"crayon","keywords":["crayon","activity","sport"]},{"emoji":"๐Ÿชก","name":"sewing needle","keywords":["sewing","needle","activity","sport"]},{"emoji":"๐Ÿงต","name":"thread","keywords":["thread","activity","sport"]},{"emoji":"๐Ÿงถ","name":"yarn","keywords":["yarn","activity","sport"]},{"emoji":"๐ŸŽน","name":"musical keyboard","keywords":["musical","keyboard","activity","sport"]},{"emoji":"๐ŸŽท","name":"saxophone","keywords":["saxophone","activity","sport"]},{"emoji":"๐ŸŽบ","name":"trumpet","keywords":["trumpet","activity","sport"]},{"emoji":"๐ŸŽธ","name":"guitar","keywords":["guitar","activity","sport"]},{"emoji":"๐Ÿช•","name":"banjo","keywords":["banjo","activity","sport"]},{"emoji":"๐ŸŽป","name":"violin","keywords":["violin","activity","sport"]},{"emoji":"๐Ÿช‰","name":"harp","keywords":["harp","activity","sport"]},{"emoji":"๐Ÿช˜","name":"long drum","keywords":["long","drum","activity","sport"]},{"emoji":"๐Ÿฅ","name":"drum","keywords":["drum","activity","sport"]},{"emoji":"๐Ÿช‡","name":"maracas","keywords":["maracas","activity","sport"]},{"emoji":"๐Ÿชˆ","name":"flute","keywords":["flute","activity","sport"]},{"emoji":"๐Ÿช—","name":"accordion","keywords":["accordion","activity","sport"]},{"emoji":"๐ŸŽค","name":"microphone","keywords":["microphone","activity","sport"]},{"emoji":"๐ŸŽง","name":"headphone","keywords":["headphone","activity","sport"]},{"emoji":"๐ŸŽš๏ธ","name":"level slider","keywords":["level","slider","activity","sport"]},{"emoji":"๐ŸŽ›๏ธ","name":"control knobs","keywords":["control","knobs","activity","sport"]},{"emoji":"๐ŸŽ™๏ธ","name":"studio microphone","keywords":["studio","microphone","activity","sport"]},{"emoji":"๐Ÿ“ป","name":"radio","keywords":["radio","activity","sport"]},{"emoji":"๐Ÿ“บ","name":"television","keywords":["television","activity","sport"]},{"emoji":"๐Ÿ“ผ","name":"videocassette","keywords":["videocassette","activity","sport"]},{"emoji":"๐Ÿ“น","name":"video camera","keywords":["video","camera","activity","sport"]},{"emoji":"๐Ÿ“ฝ๏ธ","name":"film projector","keywords":["film","projector","activity","sport"]},{"emoji":"๐ŸŽฅ","name":"movie camera","keywords":["movie","camera","activity","sport"]},{"emoji":"๐ŸŽž๏ธ","name":"film frames","keywords":["film","frames","activity","sport"]},{"emoji":"๐ŸŽฌ","name":"clapper board","keywords":["clapper","board","activity","sport"]},{"emoji":"๐ŸŽญ","name":"performing arts","keywords":["performing","arts","activity","sport"]},{"emoji":"๐ŸŽซ","name":"ticket","keywords":["ticket","activity","sport"]},{"emoji":"๐ŸŽŸ๏ธ","name":"admission tickets","keywords":["admission","tickets","activity","sport"]},{"emoji":"๐Ÿ›‘","name":"stop sign","keywords":["stop","sign","travel","place"]},{"emoji":"๐Ÿšง","name":"construction","keywords":["construction","travel","place"]},{"emoji":"๐Ÿšจ","name":"police car light","keywords":["police","car","light","travel","place"]},{"emoji":"โ›ฝ","name":"fuel pump","keywords":["fuel","pump","travel","place"]},{"emoji":"๐Ÿ›ข๏ธ","name":"oil drum","keywords":["oil","drum","travel","place"]},{"emoji":"๐Ÿงญ","name":"compass","keywords":["compass","travel","place"]},{"emoji":"๐Ÿ›ž","name":"wheel","keywords":["wheel","travel","place"]},{"emoji":"๐Ÿ›Ÿ","name":"ring buoy","keywords":["ring","buoy","travel","place"]},{"emoji":"โš“","name":"anchor","keywords":["anchor","travel","place"]},{"emoji":"๐Ÿš","name":"bus stop","keywords":["bus","stop","travel","place"]},{"emoji":"๐Ÿš‡","name":"metro","keywords":["metro","travel","place"]},{"emoji":"๐Ÿšฅ","name":"horizontal traffic light","keywords":["horizontal","traffic","light","travel","place"]},{"emoji":"๐Ÿšฆ","name":"vertical traffic light","keywords":["vertical","traffic","light","travel","place"]},{"emoji":"๐Ÿ›ด","name":"kick scooter","keywords":["kick","scooter","travel","place"]},{"emoji":"๐Ÿฆฝ","name":"manual wheelchair","keywords":["manual","wheelchair","travel","place"]},{"emoji":"๐Ÿฆผ","name":"motorized wheelchair","keywords":["motorized","wheelchair","travel","place"]},{"emoji":"๐Ÿฉผ","name":"crutch","keywords":["crutch","travel","place"]},{"emoji":"๐Ÿšฒ","name":"bicycle","keywords":["bicycle","travel","place"]},{"emoji":"๐Ÿ›ต","name":"motor scooter","keywords":["motor","scooter","travel","place"]},{"emoji":"๐Ÿ๏ธ","name":"motorcycle","keywords":["motorcycle","travel","place"]},{"emoji":"๐Ÿš™","name":"sport utility vehicle","keywords":["sport","utility","vehicle","travel","place"]},{"emoji":"๐Ÿš—","name":"automobile","keywords":["automobile","travel","place"]},{"emoji":"๐Ÿ›ป","name":"pickup truck","keywords":["pickup","truck","travel","place"]},{"emoji":"๐Ÿš","name":"minibus","keywords":["minibus","travel","place"]},{"emoji":"๐Ÿšš","name":"delivery truck","keywords":["delivery","truck","travel","place"]},{"emoji":"๐Ÿš›","name":"articulated lorry","keywords":["articulated","lorry","travel","place"]},{"emoji":"๐Ÿšœ","name":"tractor","keywords":["tractor","travel","place"]},{"emoji":"๐ŸŽ๏ธ","name":"racing car","keywords":["racing","car","travel","place"]},{"emoji":"๐Ÿš’","name":"fire engine","keywords":["fire","engine","travel","place"]},{"emoji":"๐Ÿš‘","name":"ambulance","keywords":["ambulance","travel","place"]},{"emoji":"๐Ÿš“","name":"police car","keywords":["police","car","travel","place"]},{"emoji":"๐Ÿš•","name":"taxi","keywords":["taxi","travel","place"]},{"emoji":"๐Ÿ›บ","name":"auto rickshaw","keywords":["auto","rickshaw","travel","place"]},{"emoji":"๐ŸšŒ","name":"bus","keywords":["bus","travel","place"]},{"emoji":"๐Ÿšˆ","name":"light rail","keywords":["light","rail","travel","place"]},{"emoji":"๐Ÿš","name":"monorail","keywords":["monorail","travel","place"]},{"emoji":"๐Ÿš…","name":"bullet train","keywords":["bullet","train","travel","place"]},{"emoji":"๐Ÿš„","name":"high-speed train","keywords":["high","speed","train","travel","place"]},{"emoji":"๐Ÿš‚","name":"locomotive","keywords":["locomotive","travel","place"]},{"emoji":"๐Ÿšƒ","name":"railway car","keywords":["railway","car","travel","place"]},{"emoji":"๐Ÿš‹","name":"tram car","keywords":["tram","car","travel","place"]},{"emoji":"๐ŸšŽ","name":"trolleybus","keywords":["trolleybus","travel","place"]},{"emoji":"๐Ÿšž","name":"mountain railway","keywords":["mountain","railway","travel","place"]},{"emoji":"๐ŸšŠ","name":"tram","keywords":["tram","travel","place"]},{"emoji":"๐Ÿš‰","name":"station","keywords":["station","travel","place"]},{"emoji":"๐Ÿš","name":"oncoming bus","keywords":["oncoming","bus","travel","place"]},{"emoji":"๐Ÿš”","name":"oncoming police car","keywords":["oncoming","police","car","travel","place"]},{"emoji":"๐Ÿš˜","name":"oncoming automobile","keywords":["oncoming","automobile","travel","place"]},{"emoji":"๐Ÿš–","name":"oncoming taxi","keywords":["oncoming","taxi","travel","place"]},{"emoji":"๐Ÿš†","name":"train","keywords":["train","travel","place"]},{"emoji":"๐Ÿšข","name":"ship","keywords":["ship","travel","place"]},{"emoji":"๐Ÿ›ณ๏ธ","name":"passenger ship","keywords":["passenger","ship","travel","place"]},{"emoji":"๐Ÿ›ฅ๏ธ","name":"motor boat","keywords":["motor","boat","travel","place"]},{"emoji":"๐Ÿšค","name":"speedboat","keywords":["speedboat","travel","place"]},{"emoji":"โ›ด๏ธ","name":"ferry","keywords":["ferry","travel","place"]},{"emoji":"โ›ต","name":"sailboat","keywords":["sailboat","travel","place"]},{"emoji":"๐Ÿ›ถ","name":"canoe","keywords":["canoe","travel","place"]},{"emoji":"๐ŸšŸ","name":"suspension railway","keywords":["suspension","railway","travel","place"]},{"emoji":"๐Ÿš ","name":"mountain cableway","keywords":["mountain","cableway","travel","place"]},{"emoji":"๐Ÿšก","name":"aerial tramway","keywords":["aerial","tramway","travel","place"]},{"emoji":"๐Ÿš","name":"helicopter","keywords":["helicopter","travel","place"]},{"emoji":"๐Ÿ›ธ","name":"flying saucer","keywords":["flying","saucer","travel","place"]},{"emoji":"๐Ÿš€","name":"rocket","keywords":["rocket","travel","place"]},{"emoji":"โœˆ๏ธ","name":"airplane","keywords":["airplane","travel","place"]},{"emoji":"๐Ÿ›ซ","name":"airplane departure","keywords":["airplane","departure","travel","place"]},{"emoji":"๐Ÿ›ฌ","name":"airplane arrival","keywords":["airplane","arrival","travel","place"]},{"emoji":"๐Ÿ›ฉ๏ธ","name":"small airplane","keywords":["small","airplane","travel","place"]},{"emoji":"๐Ÿ›","name":"playground slide","keywords":["playground","slide","travel","place"]},{"emoji":"๐ŸŽข","name":"roller coaster","keywords":["roller","coaster","travel","place"]},{"emoji":"๐ŸŽก","name":"ferris wheel","keywords":["ferris","wheel","travel","place"]},{"emoji":"๐ŸŽ ","name":"carousel horse","keywords":["carousel","horse","travel","place"]},{"emoji":"๐ŸŽช","name":"circus tent","keywords":["circus","tent","travel","place"]},{"emoji":"๐Ÿ—ผ","name":"Tokyo tower","keywords":["tokyo","tower","travel","place"]},{"emoji":"๐Ÿ—ฝ","name":"Statue of Liberty","keywords":["statue","liberty","travel","place"]},{"emoji":"๐Ÿ—ฟ","name":"moai","keywords":["moai","travel","place"]},{"emoji":"๐Ÿ—ป","name":"mount fuji","keywords":["mount","fuji","travel","place"]},{"emoji":"๐Ÿ›๏ธ","name":"classical building","keywords":["classical","building","travel","place"]},{"emoji":"๐Ÿ’ˆ","name":"barber pole","keywords":["barber","pole","travel","place"]},{"emoji":"โ›ฒ","name":"fountain","keywords":["fountain","travel","place"]},{"emoji":"โ›ฉ๏ธ","name":"shinto shrine","keywords":["shinto","shrine","travel","place"]},{"emoji":"๐Ÿ•","name":"synagogue","keywords":["synagogue","travel","place"]},{"emoji":"๐Ÿ•Œ","name":"mosque","keywords":["mosque","travel","place"]},{"emoji":"๐Ÿ•‹","name":"kaaba","keywords":["kaaba","travel","place"]},{"emoji":"๐Ÿ›•","name":"hindu temple","keywords":["hindu","temple","travel","place"]},{"emoji":"โ›ช","name":"church","keywords":["church","travel","place"]},{"emoji":"๐Ÿ’’","name":"wedding","keywords":["wedding","travel","place"]},{"emoji":"๐Ÿฉ","name":"love hotel","keywords":["love","hotel","travel","place"]},{"emoji":"๐Ÿฏ","name":"Japanese castle","keywords":["japanese","castle","travel","place"]},{"emoji":"๐Ÿฐ","name":"castle","keywords":["castle","travel","place"]},{"emoji":"๐Ÿ—๏ธ","name":"building construction","keywords":["building","construction","travel","place"]},{"emoji":"๐Ÿข","name":"office building","keywords":["office","building","travel","place"]},{"emoji":"๐Ÿญ","name":"factory","keywords":["factory","travel","place"]},{"emoji":"๐Ÿฌ","name":"department store","keywords":["department","store","travel","place"]},{"emoji":"๐Ÿช","name":"convenience store","keywords":["convenience","store","travel","place"]},{"emoji":"๐ŸŸ๏ธ","name":"stadium","keywords":["stadium","travel","place"]},{"emoji":"๐Ÿฆ","name":"bank","keywords":["bank","travel","place"]},{"emoji":"๐Ÿซ","name":"school","keywords":["school","travel","place"]},{"emoji":"๐Ÿจ","name":"hotel","keywords":["hotel","travel","place"]},{"emoji":"๐Ÿฃ","name":"Japanese post office","keywords":["japanese","post","office","travel","place"]},{"emoji":"๐Ÿค","name":"post office","keywords":["post","office","travel","place"]},{"emoji":"๐Ÿฅ","name":"hospital","keywords":["hospital","travel","place"]},{"emoji":"๐Ÿš๏ธ","name":"derelict house","keywords":["derelict","house","travel","place"]},{"emoji":"๐Ÿ ","name":"house","keywords":["house","travel","place"]},{"emoji":"๐Ÿก","name":"house with garden","keywords":["house","garden","travel","place"]},{"emoji":"๐Ÿ˜๏ธ","name":"houses","keywords":["houses","travel","place"]},{"emoji":"๐Ÿ›–","name":"hut","keywords":["hut","travel","place"]},{"emoji":"โ›บ","name":"tent","keywords":["tent","travel","place"]},{"emoji":"๐Ÿ•๏ธ","name":"camping","keywords":["camping","travel","place"]},{"emoji":"โ›ฑ๏ธ","name":"umbrella on ground","keywords":["umbrella","ground","travel","place"]},{"emoji":"๐Ÿ™๏ธ","name":"cityscape","keywords":["cityscape","travel","place"]},{"emoji":"๐ŸŒ†","name":"cityscape at dusk","keywords":["cityscape","at","dusk","travel","place"]},{"emoji":"๐ŸŒ‡","name":"sunset","keywords":["sunset","travel","place"]},{"emoji":"๐ŸŒƒ","name":"night with stars","keywords":["night","stars","travel","place"]},{"emoji":"๐ŸŒ‰","name":"bridge at night","keywords":["bridge","at","night","travel","place"]},{"emoji":"๐ŸŒ","name":"foggy","keywords":["foggy","travel","place"]},{"emoji":"๐Ÿ›ค๏ธ","name":"railway track","keywords":["railway","track","travel","place"]},{"emoji":"๐Ÿ›ฃ๏ธ","name":"motorway","keywords":["motorway","travel","place"]},{"emoji":"๐Ÿ—พ","name":"map of Japan","keywords":["map","japan","travel","place"]},{"emoji":"๐Ÿ—บ๏ธ","name":"world map","keywords":["world","map","travel","place"]},{"emoji":"๐ŸŒ","name":"globe with meridians","keywords":["globe","meridians","travel","place"]},{"emoji":"๐Ÿ’บ","name":"seat","keywords":["seat","travel","place"]},{"emoji":"๐Ÿงณ","name":"luggage","keywords":["luggage","travel","place"]},{"emoji":"๐Ÿ“ฑ","name":"mobile phone","keywords":["mobile","phone","object"]},{"emoji":"โ˜Ž๏ธ","name":"telephone","keywords":["telephone","object"]},{"emoji":"๐Ÿ“ž","name":"telephone receiver","keywords":["telephone","receiver","object"]},{"emoji":"๐Ÿ“Ÿ","name":"pager","keywords":["pager","object"]},{"emoji":"๐Ÿ“ ","name":"fax machine","keywords":["fax","machine","object"]},{"emoji":"๐Ÿ”Œ","name":"electric plug","keywords":["electric","plug","object"]},{"emoji":"๐Ÿ”‹","name":"battery","keywords":["battery","object"]},{"emoji":"๐Ÿชซ","name":"low battery","keywords":["low","battery","object"]},{"emoji":"๐Ÿ–ฒ๏ธ","name":"trackball","keywords":["trackball","object"]},{"emoji":"๐Ÿ’ฝ","name":"computer disk","keywords":["computer","disk","object"]},{"emoji":"๐Ÿ’พ","name":"floppy disk","keywords":["floppy","disk","object"]},{"emoji":"๐Ÿ’ฟ","name":"optical disk","keywords":["optical","disk","object"]},{"emoji":"๐Ÿ“€","name":"dvd","keywords":["dvd","object"]},{"emoji":"๐Ÿ–ฅ๏ธ","name":"desktop computer","keywords":["desktop","computer","object"]},{"emoji":"๐Ÿ’ป","name":"laptop","keywords":["laptop","object"]},{"emoji":"โŒจ๏ธ","name":"keyboard","keywords":["keyboard","object"]},{"emoji":"๐Ÿ–จ๏ธ","name":"printer","keywords":["printer","object"]},{"emoji":"๐Ÿ–ฑ๏ธ","name":"computer mouse","keywords":["computer","mouse","object"]},{"emoji":"๐Ÿช™","name":"coin","keywords":["coin","object"]},{"emoji":"๐Ÿ’ธ","name":"money with wings","keywords":["money","wings","object"]},{"emoji":"๐Ÿ’ต","name":"dollar banknote","keywords":["dollar","banknote","object"]},{"emoji":"๐Ÿ’ด","name":"yen banknote","keywords":["yen","banknote","object"]},{"emoji":"๐Ÿ’ถ","name":"euro banknote","keywords":["euro","banknote","object"]},{"emoji":"๐Ÿ’ท","name":"pound banknote","keywords":["pound","banknote","object"]},{"emoji":"๐Ÿ’ณ","name":"credit card","keywords":["credit","card","object"]},{"emoji":"๐Ÿ’ฐ","name":"money bag","keywords":["money","bag","object"]},{"emoji":"๐Ÿ’Ž","name":"gem stone","keywords":["gem","stone","object"]},{"emoji":"๐Ÿงพ","name":"receipt","keywords":["receipt","object"]},{"emoji":"๐Ÿงฎ","name":"abacus","keywords":["abacus","object"]},{"emoji":"โš–๏ธ","name":"balance scale","keywords":["balance","scale","object"]},{"emoji":"๐Ÿ›’","name":"shopping cart","keywords":["shopping","cart","object"]},{"emoji":"๐Ÿ›๏ธ","name":"shopping bags","keywords":["shopping","bags","object"]},{"emoji":"๐Ÿ•ฏ๏ธ","name":"candle","keywords":["candle","object"]},{"emoji":"๐Ÿ’ก","name":"light bulb","keywords":["light","bulb","object"]},{"emoji":"๐Ÿ”ฆ","name":"flashlight","keywords":["flashlight","object"]},{"emoji":"๐Ÿฎ","name":"red paper lantern","keywords":["red","paper","lantern","object"]},{"emoji":"๐Ÿงฑ","name":"brick","keywords":["brick","object"]},{"emoji":"๐ŸชŸ","name":"window","keywords":["window","object"]},{"emoji":"๐Ÿชž","name":"mirror","keywords":["mirror","object"]},{"emoji":"๐Ÿšช","name":"door","keywords":["door","object"]},{"emoji":"๐Ÿช‘","name":"chair","keywords":["chair","object"]},{"emoji":"๐Ÿ›๏ธ","name":"bed","keywords":["bed","object"]},{"emoji":"๐Ÿ›‹๏ธ","name":"couch and lamp","keywords":["couch","lamp","object"]},{"emoji":"๐Ÿšฟ","name":"shower","keywords":["shower","object"]},{"emoji":"๐Ÿ›","name":"bathtub","keywords":["bathtub","object"]},{"emoji":"๐Ÿšฝ","name":"toilet","keywords":["toilet","object"]},{"emoji":"๐Ÿงป","name":"roll of paper","keywords":["roll","paper","object"]},{"emoji":"๐Ÿช ","name":"plunger","keywords":["plunger","object"]},{"emoji":"๐Ÿงธ","name":"teddy bear","keywords":["teddy","bear","object"]},{"emoji":"๐Ÿช†","name":"nesting dolls","keywords":["nesting","dolls","object"]},{"emoji":"๐Ÿงท","name":"safety pin","keywords":["safety","pin","object"]},{"emoji":"๐Ÿชข","name":"knot","keywords":["knot","object"]},{"emoji":"๐Ÿงน","name":"broom","keywords":["broom","object"]},{"emoji":"๐Ÿงด","name":"lotion bottle","keywords":["lotion","bottle","object"]},{"emoji":"๐Ÿงฝ","name":"sponge","keywords":["sponge","object"]},{"emoji":"๐Ÿงผ","name":"soap","keywords":["soap","object"]},{"emoji":"๐Ÿชฅ","name":"toothbrush","keywords":["toothbrush","object"]},{"emoji":"๐Ÿช’","name":"razor","keywords":["razor","object"]},{"emoji":"๐Ÿชฎ","name":"hair pick","keywords":["hair","pick","object"]},{"emoji":"๐Ÿงบ","name":"basket","keywords":["basket","object"]},{"emoji":"๐Ÿงฆ","name":"socks","keywords":["socks","object"]},{"emoji":"๐Ÿงค","name":"gloves","keywords":["gloves","object"]},{"emoji":"๐Ÿงฃ","name":"scarf","keywords":["scarf","object"]},{"emoji":"๐Ÿ‘–","name":"jeans","keywords":["jeans","object"]},{"emoji":"๐Ÿ‘•","name":"t-shirt","keywords":["shirt","object"]},{"emoji":"๐Ÿ‘š","name":"womanโ€™s clothes","keywords":["woman","clothes","object"]},{"emoji":"๐Ÿ‘”","name":"necktie","keywords":["necktie","object"]},{"emoji":"๐Ÿ‘—","name":"dress","keywords":["dress","object"]},{"emoji":"๐Ÿ‘˜","name":"kimono","keywords":["kimono","object"]},{"emoji":"๐Ÿฅป","name":"sari","keywords":["sari","object"]},{"emoji":"๐Ÿ‘™","name":"bikini","keywords":["bikini","object"]},{"emoji":"๐Ÿฉณ","name":"shorts","keywords":["shorts","object"]},{"emoji":"๐Ÿฉฒ","name":"briefs","keywords":["briefs","object"]},{"emoji":"๐Ÿงฅ","name":"coat","keywords":["coat","object"]},{"emoji":"๐Ÿฅผ","name":"lab coat","keywords":["lab","coat","object"]},{"emoji":"๐Ÿฆบ","name":"safety vest","keywords":["safety","vest","object"]},{"emoji":"โ›‘๏ธ","name":"rescue workerโ€™s helmet","keywords":["rescue","worker","helmet","object"]},{"emoji":"๐Ÿช–","name":"military helmet","keywords":["military","helmet","object"]},{"emoji":"๐ŸŽ“","name":"graduation cap","keywords":["graduation","cap","object"]},{"emoji":"๐Ÿ‘’","name":"womanโ€™s hat","keywords":["woman","hat","object"]},{"emoji":"๐Ÿงข","name":"billed cap","keywords":["billed","cap","object"]},{"emoji":"๐Ÿ‘‘","name":"crown","keywords":["crown","object"]},{"emoji":"๐Ÿ’","name":"ring","keywords":["ring","object"]},{"emoji":"๐Ÿ’„","name":"lipstick","keywords":["lipstick","object"]},{"emoji":"๐Ÿชญ","name":"folding hand fan","keywords":["folding","hand","fan","object"]},{"emoji":"๐ŸŽ’","name":"backpack","keywords":["backpack","object"]},{"emoji":"๐Ÿ‘","name":"clutch bag","keywords":["clutch","bag","object"]},{"emoji":"๐Ÿ‘›","name":"purse","keywords":["purse","object"]},{"emoji":"๐Ÿ‘œ","name":"handbag","keywords":["handbag","object"]},{"emoji":"๐Ÿ’ผ","name":"briefcase","keywords":["briefcase","object"]},{"emoji":"โ˜‚๏ธ","name":"umbrella","keywords":["umbrella","object"]},{"emoji":"๐ŸŒ‚","name":"closed umbrella","keywords":["closed","umbrella","object"]},{"emoji":"๐Ÿฅพ","name":"hiking boot","keywords":["hiking","boot","object"]},{"emoji":"๐Ÿ‘ข","name":"womanโ€™s boot","keywords":["woman","boot","object"]},{"emoji":"๐Ÿฉด","name":"thong sandal","keywords":["thong","sandal","object"]},{"emoji":"๐Ÿ‘ ","name":"high-heeled shoe","keywords":["high","heeled","shoe","object"]},{"emoji":"๐Ÿ‘Ÿ","name":"running shoe","keywords":["running","shoe","object"]},{"emoji":"๐Ÿ‘ž","name":"manโ€™s shoe","keywords":["man","shoe","object"]},{"emoji":"๐Ÿฅฟ","name":"flat shoe","keywords":["flat","shoe","object"]},{"emoji":"๐Ÿ‘ก","name":"womanโ€™s sandal","keywords":["woman","sandal","object"]},{"emoji":"๐Ÿฆฏ","name":"white cane","keywords":["white","cane","object"]},{"emoji":"๐Ÿ•ถ๏ธ","name":"sunglasses","keywords":["sunglasses","object"]},{"emoji":"๐Ÿ‘“","name":"glasses","keywords":["glasses","object"]},{"emoji":"๐Ÿฅฝ","name":"goggles","keywords":["goggles","object"]},{"emoji":"โš—๏ธ","name":"alembic","keywords":["alembic","object"]},{"emoji":"๐Ÿงซ","name":"petri dish","keywords":["petri","dish","object"]},{"emoji":"๐Ÿงช","name":"test tube","keywords":["test","tube","object"]},{"emoji":"๐Ÿ’‰","name":"syringe","keywords":["syringe","object"]},{"emoji":"๐Ÿ’Š","name":"pill","keywords":["pill","object"]},{"emoji":"๐Ÿฉน","name":"adhesive bandage","keywords":["adhesive","bandage","object"]},{"emoji":"๐Ÿฉบ","name":"stethoscope","keywords":["stethoscope","object"]},{"emoji":"๐Ÿฉป","name":"x-ray","keywords":["ray","object"]},{"emoji":"๐Ÿงฌ","name":"dna","keywords":["dna","object"]},{"emoji":"๐Ÿ”ญ","name":"telescope","keywords":["telescope","object"]},{"emoji":"๐Ÿ”ฌ","name":"microscope","keywords":["microscope","object"]},{"emoji":"๐Ÿ“ก","name":"satellite antenna","keywords":["satellite","antenna","object"]},{"emoji":"๐Ÿ›ฐ๏ธ","name":"satellite","keywords":["satellite","object"]},{"emoji":"๐Ÿงฏ","name":"fire extinguisher","keywords":["fire","extinguisher","object"]},{"emoji":"๐Ÿช“","name":"axe","keywords":["axe","object"]},{"emoji":"๐Ÿชœ","name":"ladder","keywords":["ladder","object"]},{"emoji":"๐Ÿชฃ","name":"bucket","keywords":["bucket","object"]},{"emoji":"๐Ÿช","name":"hook","keywords":["hook","object"]},{"emoji":"๐Ÿงฒ","name":"magnet","keywords":["magnet","object"]},{"emoji":"๐Ÿงฐ","name":"toolbox","keywords":["toolbox","object"]},{"emoji":"๐Ÿ—œ๏ธ","name":"clamp","keywords":["clamp","object"]},{"emoji":"๐Ÿ”ฉ","name":"nut and bolt","keywords":["nut","bolt","object"]},{"emoji":"๐Ÿช›","name":"screwdriver","keywords":["screwdriver","object"]},{"emoji":"๐Ÿชš","name":"carpentry saw","keywords":["carpentry","saw","object"]},{"emoji":"๐Ÿ”ง","name":"wrench","keywords":["wrench","object"]},{"emoji":"๐Ÿ”จ","name":"hammer","keywords":["hammer","object"]},{"emoji":"๐Ÿ› ๏ธ","name":"hammer and wrench","keywords":["hammer","wrench","object"]},{"emoji":"โš’๏ธ","name":"hammer and pick","keywords":["hammer","pick","object"]},{"emoji":"โ›๏ธ","name":"pick","keywords":["pick","object"]},{"emoji":"๐Ÿช","name":"shovel","keywords":["shovel","object"]},{"emoji":"โš™๏ธ","name":"gear","keywords":["gear","object"]},{"emoji":"โ›“๏ธโ€๐Ÿ’ฅ","name":"broken chain","keywords":["broken","chain","object"]},{"emoji":"๐Ÿ”—","name":"link","keywords":["link","object"]},{"emoji":"โ›“๏ธ","name":"chains","keywords":["chains","object"]},{"emoji":"๐Ÿ“Ž","name":"paperclip","keywords":["paperclip","object"]},{"emoji":"๐Ÿ–‡๏ธ","name":"linked paperclips","keywords":["linked","paperclips","object"]},{"emoji":"โœ‚๏ธ","name":"scissors","keywords":["scissors","object"]},{"emoji":"๐Ÿ“","name":"straight ruler","keywords":["straight","ruler","object"]},{"emoji":"๐Ÿ“","name":"triangular ruler","keywords":["triangular","ruler","object"]},{"emoji":"๐Ÿ–Š๏ธ","name":"pen","keywords":["pen","object"]},{"emoji":"๐Ÿ–‹๏ธ","name":"fountain pen","keywords":["fountain","pen","object"]},{"emoji":"โœ’๏ธ","name":"black nib","keywords":["black","nib","object"]},{"emoji":"โœ๏ธ","name":"pencil","keywords":["pencil","object"]},{"emoji":"๐Ÿ“","name":"memo","keywords":["memo","object"]},{"emoji":"๐Ÿ—’๏ธ","name":"spiral notepad","keywords":["spiral","notepad","object"]},{"emoji":"๐Ÿ“„","name":"page facing up","keywords":["page","facing","up","object"]},{"emoji":"๐Ÿ“ƒ","name":"page with curl","keywords":["page","curl","object"]},{"emoji":"๐Ÿ“‘","name":"bookmark tabs","keywords":["bookmark","tabs","object"]},{"emoji":"๐Ÿ“‹","name":"clipboard","keywords":["clipboard","object"]},{"emoji":"๐Ÿ—ƒ๏ธ","name":"card file box","keywords":["card","file","box","object"]},{"emoji":"๐Ÿ—„๏ธ","name":"file cabinet","keywords":["file","cabinet","object"]},{"emoji":"๐Ÿ“’","name":"ledger","keywords":["ledger","object"]},{"emoji":"๐Ÿ“”","name":"notebook with decorative cover","keywords":["notebook","decorative","cover","object"]},{"emoji":"๐Ÿ“•","name":"closed book","keywords":["closed","book","object"]},{"emoji":"๐Ÿ““","name":"notebook","keywords":["notebook","object"]},{"emoji":"๐Ÿ“—","name":"green book","keywords":["green","book","object"]},{"emoji":"๐Ÿ“˜","name":"blue book","keywords":["blue","book","object"]},{"emoji":"๐Ÿ“™","name":"orange book","keywords":["orange","book","object"]},{"emoji":"๐Ÿ“š","name":"books","keywords":["books","object"]},{"emoji":"๐Ÿ“–","name":"open book","keywords":["open","book","object"]},{"emoji":"๐Ÿ”–","name":"bookmark","keywords":["bookmark","object"]},{"emoji":"๐Ÿ“‚","name":"open file folder","keywords":["open","file","folder","object"]},{"emoji":"๐Ÿ“","name":"file folder","keywords":["file","folder","object"]},{"emoji":"๐Ÿ—‚๏ธ","name":"card index dividers","keywords":["card","index","dividers","object"]},{"emoji":"๐Ÿ“Š","name":"bar chart","keywords":["bar","chart","object"]},{"emoji":"๐Ÿ“ˆ","name":"chart increasing","keywords":["chart","increasing","object"]},{"emoji":"๐Ÿ“‰","name":"chart decreasing","keywords":["chart","decreasing","object"]},{"emoji":"๐Ÿ“‡","name":"card index","keywords":["card","index","object"]},{"emoji":"๐Ÿชช","name":"identification card","keywords":["identification","card","object"]},{"emoji":"๐Ÿ“Œ","name":"pushpin","keywords":["pushpin","object"]},{"emoji":"๐Ÿ“","name":"round pushpin","keywords":["round","pushpin","object"]},{"emoji":"๐Ÿ—‘๏ธ","name":"wastebasket","keywords":["wastebasket","object"]},{"emoji":"๐Ÿ“ฐ","name":"newspaper","keywords":["newspaper","object"]},{"emoji":"๐Ÿ—ž๏ธ","name":"rolled-up newspaper","keywords":["rolled","up","newspaper","object"]},{"emoji":"๐Ÿท๏ธ","name":"label","keywords":["label","object"]},{"emoji":"๐Ÿ“ฆ","name":"package","keywords":["package","object"]},{"emoji":"๐Ÿ“ค","name":"outbox tray","keywords":["outbox","tray","object"]},{"emoji":"๐Ÿ“ฅ","name":"inbox tray","keywords":["inbox","tray","object"]},{"emoji":"๐Ÿ“จ","name":"incoming envelope","keywords":["incoming","envelope","object"]},{"emoji":"๐Ÿ“ฉ","name":"envelope with arrow","keywords":["envelope","arrow","object"]},{"emoji":"โœ‰๏ธ","name":"envelope","keywords":["envelope","object"]},{"emoji":"๐Ÿ“ง","name":"e-mail","keywords":["mail","object"]},{"emoji":"๐Ÿ“ซ","name":"closed mailbox with raised flag","keywords":["closed","mailbox","raised","flag","object"]},{"emoji":"๐Ÿ“ช","name":"closed mailbox with lowered flag","keywords":["closed","mailbox","lowered","flag","object"]},{"emoji":"๐Ÿ“ฌ","name":"open mailbox with raised flag","keywords":["open","mailbox","raised","flag","object"]},{"emoji":"๐Ÿ“ญ","name":"open mailbox with lowered flag","keywords":["open","mailbox","lowered","flag","object"]},{"emoji":"๐Ÿ“ฎ","name":"postbox","keywords":["postbox","object"]},{"emoji":"๐Ÿ—ณ๏ธ","name":"ballot box with ballot","keywords":["ballot","box","object"]},{"emoji":"โŒš","name":"watch","keywords":["watch","object"]},{"emoji":"๐Ÿ•ฐ๏ธ","name":"mantelpiece clock","keywords":["mantelpiece","clock","object"]},{"emoji":"โŒ›","name":"hourglass done","keywords":["hourglass","done","object"]},{"emoji":"โณ","name":"hourglass not done","keywords":["hourglass","not","done","object"]},{"emoji":"โฒ๏ธ","name":"timer clock","keywords":["timer","clock","object"]},{"emoji":"โฐ","name":"alarm clock","keywords":["alarm","clock","object"]},{"emoji":"โฑ๏ธ","name":"stopwatch","keywords":["stopwatch","object"]},{"emoji":"๐Ÿ•›","name":"twelve oโ€™clock","keywords":["twelve","clock","object"]},{"emoji":"๐Ÿ•ง","name":"twelve-thirty","keywords":["twelve","thirty","object"]},{"emoji":"๐Ÿ•","name":"one oโ€™clock","keywords":["one","clock","object"]},{"emoji":"๐Ÿ•œ","name":"one-thirty","keywords":["one","thirty","object"]},{"emoji":"๐Ÿ•‘","name":"two oโ€™clock","keywords":["two","clock","object"]},{"emoji":"๐Ÿ•","name":"two-thirty","keywords":["two","thirty","object"]},{"emoji":"๐Ÿ•’","name":"three oโ€™clock","keywords":["three","clock","object"]},{"emoji":"๐Ÿ•ž","name":"three-thirty","keywords":["three","thirty","object"]},{"emoji":"๐Ÿ•“","name":"four oโ€™clock","keywords":["four","clock","object"]},{"emoji":"๐Ÿ•Ÿ","name":"four-thirty","keywords":["four","thirty","object"]},{"emoji":"๐Ÿ•”","name":"five oโ€™clock","keywords":["five","clock","object"]},{"emoji":"๐Ÿ• ","name":"five-thirty","keywords":["five","thirty","object"]},{"emoji":"๐Ÿ••","name":"six oโ€™clock","keywords":["six","clock","object"]},{"emoji":"๐Ÿ•ก","name":"six-thirty","keywords":["six","thirty","object"]},{"emoji":"๐Ÿ•–","name":"seven oโ€™clock","keywords":["seven","clock","object"]},{"emoji":"๐Ÿ•ข","name":"seven-thirty","keywords":["seven","thirty","object"]},{"emoji":"๐Ÿ•—","name":"eight oโ€™clock","keywords":["eight","clock","object"]},{"emoji":"๐Ÿ•ฃ","name":"eight-thirty","keywords":["eight","thirty","object"]},{"emoji":"๐Ÿ•˜","name":"nine oโ€™clock","keywords":["nine","clock","object"]},{"emoji":"๐Ÿ•ค","name":"nine-thirty","keywords":["nine","thirty","object"]},{"emoji":"๐Ÿ•™","name":"ten oโ€™clock","keywords":["ten","clock","object"]},{"emoji":"๐Ÿ•ฅ","name":"ten-thirty","keywords":["ten","thirty","object"]},{"emoji":"๐Ÿ•š","name":"eleven oโ€™clock","keywords":["eleven","clock","object"]},{"emoji":"๐Ÿ•ฆ","name":"eleven-thirty","keywords":["eleven","thirty","object"]},{"emoji":"๐Ÿ“…","name":"calendar","keywords":["calendar","object"]},{"emoji":"๐Ÿ“†","name":"tear-off calendar","keywords":["tear","off","calendar","object"]},{"emoji":"๐Ÿ—“๏ธ","name":"spiral calendar","keywords":["spiral","calendar","object"]},{"emoji":"๐Ÿชง","name":"placard","keywords":["placard","object"]},{"emoji":"๐Ÿ›Ž๏ธ","name":"bellhop bell","keywords":["bellhop","bell","object"]},{"emoji":"๐Ÿ””","name":"bell","keywords":["bell","object"]},{"emoji":"๐Ÿ“ฏ","name":"postal horn","keywords":["postal","horn","object"]},{"emoji":"๐Ÿ“ฃ","name":"megaphone","keywords":["megaphone","object"]},{"emoji":"๐Ÿ”ˆ","name":"speaker low volume","keywords":["speaker","low","volume","object"]},{"emoji":"๐Ÿ”‰","name":"speaker medium volume","keywords":["speaker","medium","volume","object"]},{"emoji":"๐Ÿ”Š","name":"speaker high volume","keywords":["speaker","high","volume","object"]},{"emoji":"๐Ÿ”","name":"magnifying glass tilted left","keywords":["magnifying","glass","tilted","left","object"]},{"emoji":"๐Ÿ”Ž","name":"magnifying glass tilted right","keywords":["magnifying","glass","tilted","right","object"]},{"emoji":"๐Ÿ”ฎ","name":"crystal ball","keywords":["crystal","ball","object"]},{"emoji":"๐Ÿงฟ","name":"nazar amulet","keywords":["nazar","amulet","object"]},{"emoji":"๐Ÿชฌ","name":"hamsa","keywords":["hamsa","object"]},{"emoji":"๐Ÿ“ฟ","name":"prayer beads","keywords":["prayer","beads","object"]},{"emoji":"๐Ÿบ","name":"amphora","keywords":["amphora","object"]},{"emoji":"โšฑ๏ธ","name":"funeral urn","keywords":["funeral","urn","object"]},{"emoji":"โšฐ๏ธ","name":"coffin","keywords":["coffin","object"]},{"emoji":"๐Ÿชฆ","name":"headstone","keywords":["headstone","object"]},{"emoji":"๐Ÿšฌ","name":"cigarette","keywords":["cigarette","object"]},{"emoji":"๐Ÿ’ฃ","name":"bomb","keywords":["bomb","object"]},{"emoji":"๐Ÿชค","name":"mouse trap","keywords":["mouse","trap","object"]},{"emoji":"๐Ÿ“œ","name":"scroll","keywords":["scroll","object"]},{"emoji":"โš”๏ธ","name":"crossed swords","keywords":["crossed","swords","object"]},{"emoji":"๐Ÿ—ก๏ธ","name":"dagger","keywords":["dagger","object"]},{"emoji":"๐Ÿ›ก๏ธ","name":"shield","keywords":["shield","object"]},{"emoji":"๐Ÿ—๏ธ","name":"old key","keywords":["old","key","object"]},{"emoji":"๐Ÿ”‘","name":"key","keywords":["key","object"]},{"emoji":"๐Ÿ”","name":"locked with key","keywords":["locked","key","object"]},{"emoji":"๐Ÿ”","name":"locked with pen","keywords":["locked","pen","object"]},{"emoji":"๐Ÿ”’","name":"locked","keywords":["locked","object"]},{"emoji":"๐Ÿ”“","name":"unlocked","keywords":["unlocked","object"]},{"emoji":"๐Ÿ”ด","name":"red circle","keywords":["red","circle","symbol"]},{"emoji":"๐ŸŸ ","name":"orange circle","keywords":["orange","circle","symbol"]},{"emoji":"๐ŸŸก","name":"yellow circle","keywords":["yellow","circle","symbol"]},{"emoji":"๐ŸŸข","name":"green circle","keywords":["green","circle","symbol"]},{"emoji":"๐Ÿ”ต","name":"blue circle","keywords":["blue","circle","symbol"]},{"emoji":"๐ŸŸฃ","name":"purple circle","keywords":["purple","circle","symbol"]},{"emoji":"๐ŸŸค","name":"brown circle","keywords":["brown","circle","symbol"]},{"emoji":"โšซ","name":"black circle","keywords":["black","circle","symbol"]},{"emoji":"โšช","name":"white circle","keywords":["white","circle","symbol"]},{"emoji":"๐ŸŸฅ","name":"red square","keywords":["red","square","symbol"]},{"emoji":"๐ŸŸง","name":"orange square","keywords":["orange","square","symbol"]},{"emoji":"๐ŸŸจ","name":"yellow square","keywords":["yellow","square","symbol"]},{"emoji":"๐ŸŸฉ","name":"green square","keywords":["green","square","symbol"]},{"emoji":"๐ŸŸฆ","name":"blue square","keywords":["blue","square","symbol"]},{"emoji":"๐ŸŸช","name":"purple square","keywords":["purple","square","symbol"]},{"emoji":"๐ŸŸซ","name":"brown square","keywords":["brown","square","symbol"]},{"emoji":"โฌ›","name":"black large square","keywords":["black","large","square","symbol"]},{"emoji":"โฌœ","name":"white large square","keywords":["white","large","square","symbol"]},{"emoji":"โ™ฆ๏ธ","name":"diamond suit","keywords":["diamond","suit","symbol"]},{"emoji":"โ™ฃ๏ธ","name":"club suit","keywords":["club","suit","symbol"]},{"emoji":"โ™ ๏ธ","name":"spade suit","keywords":["spade","suit","symbol"]},{"emoji":"โ™ˆ","name":"Aries","keywords":["aries","symbol"]},{"emoji":"โ™‰","name":"Taurus","keywords":["taurus","symbol"]},{"emoji":"โ™Š","name":"Gemini","keywords":["gemini","symbol"]},{"emoji":"โ™‹","name":"Cancer","keywords":["cancer","symbol"]},{"emoji":"โ™Œ","name":"Leo","keywords":["leo","symbol"]},{"emoji":"โ™","name":"Virgo","keywords":["virgo","symbol"]},{"emoji":"โ™Ž","name":"Libra","keywords":["libra","symbol"]},{"emoji":"โ™","name":"Scorpio","keywords":["scorpio","symbol"]},{"emoji":"โ™","name":"Sagittarius","keywords":["sagittarius","symbol"]},{"emoji":"โ™‘","name":"Capricorn","keywords":["capricorn","symbol"]},{"emoji":"โ™’","name":"Aquarius","keywords":["aquarius","symbol"]},{"emoji":"โ™“","name":"Pisces","keywords":["pisces","symbol"]},{"emoji":"โ›Ž","name":"Ophiuchus","keywords":["ophiuchus","symbol"]},{"emoji":"โ™€๏ธ","name":"female sign","keywords":["female","sign","symbol"]},{"emoji":"โ™‚๏ธ","name":"male sign","keywords":["male","sign","symbol"]},{"emoji":"โšง๏ธ","name":"transgender symbol","keywords":["transgender","symbol"]},{"emoji":"๐Ÿ’ญ","name":"thought balloon","keywords":["thought","balloon","symbol"]},{"emoji":"๐Ÿ—ฏ๏ธ","name":"right anger bubble","keywords":["right","anger","bubble","symbol"]},{"emoji":"๐Ÿ’ฌ","name":"speech balloon","keywords":["speech","balloon","symbol"]},{"emoji":"๐Ÿ—จ๏ธ","name":"left speech bubble","keywords":["left","speech","bubble","symbol"]},{"emoji":"โ•","name":"white exclamation mark","keywords":["white","exclamation","mark","symbol"]},{"emoji":"โ”","name":"white question mark","keywords":["white","question","mark","symbol"]},{"emoji":"โ—","name":"red exclamation mark","keywords":["red","exclamation","mark","symbol"]},{"emoji":"โ“","name":"red question mark","keywords":["red","question","mark","symbol"]},{"emoji":"โ‰๏ธ","name":"exclamation question mark","keywords":["exclamation","question","mark","symbol"]},{"emoji":"โ€ผ๏ธ","name":"double exclamation mark","keywords":["double","exclamation","mark","symbol"]},{"emoji":"โญ•","name":"hollow red circle","keywords":["hollow","red","circle","symbol"]},{"emoji":"โŒ","name":"cross mark","keywords":["cross","mark","symbol"]},{"emoji":"๐Ÿšซ","name":"prohibited","keywords":["prohibited","symbol"]},{"emoji":"๐Ÿšณ","name":"no bicycles","keywords":["no","bicycles","symbol"]},{"emoji":"๐Ÿšญ","name":"no smoking","keywords":["no","smoking","symbol"]},{"emoji":"๐Ÿšฏ","name":"no littering","keywords":["no","littering","symbol"]},{"emoji":"๐Ÿšฑ","name":"non-potable water","keywords":["non","potable","water","symbol"]},{"emoji":"๐Ÿšท","name":"no pedestrians","keywords":["no","pedestrians","symbol"]},{"emoji":"๐Ÿ“ต","name":"no mobile phones","keywords":["no","mobile","phones","symbol"]},{"emoji":"๐Ÿ”ž","name":"no one under eighteen","keywords":["no","one","under","eighteen","symbol"]},{"emoji":"๐Ÿ”•","name":"bell with slash","keywords":["bell","slash","symbol"]},{"emoji":"๐Ÿ”‡","name":"muted speaker","keywords":["muted","speaker","symbol"]},{"emoji":"๐Ÿ…ฐ๏ธ","name":"A button (blood type)","keywords":["button","blood","type","symbol"]},{"emoji":"๐Ÿ†Ž","name":"AB button (blood type)","keywords":["ab","button","blood","type","symbol"]},{"emoji":"๐Ÿ…ฑ๏ธ","name":"B button (blood type)","keywords":["button","blood","type","symbol"]},{"emoji":"๐Ÿ…พ๏ธ","name":"O button (blood type)","keywords":["button","blood","type","symbol"]},{"emoji":"๐Ÿ†‘","name":"CL button","keywords":["cl","button","symbol"]},{"emoji":"๐Ÿ†˜","name":"SOS button","keywords":["sos","button","symbol"]},{"emoji":"โ›”","name":"no entry","keywords":["no","entry","symbol"]},{"emoji":"๐Ÿ“›","name":"name badge","keywords":["name","badge","symbol"]},{"emoji":"โ™จ๏ธ","name":"hot springs","keywords":["hot","springs","symbol"]},{"emoji":"๐Ÿ”ป","name":"red triangle pointed down","keywords":["red","triangle","pointed","down","symbol"]},{"emoji":"๐Ÿ”บ","name":"red triangle pointed up","keywords":["red","triangle","pointed","up","symbol"]},{"emoji":"๐Ÿ‰","name":"Japanese โ€œbargainโ€ button","keywords":["japanese","bargain","button","symbol"]},{"emoji":"ใŠ™๏ธ","name":"Japanese โ€œsecretโ€ button","keywords":["japanese","secret","button","symbol"]},{"emoji":"ใŠ—๏ธ","name":"Japanese โ€œcongratulationsโ€ button","keywords":["japanese","congratulations","button","symbol"]},{"emoji":"๐Ÿˆด","name":"Japanese โ€œpassing gradeโ€ button","keywords":["japanese","passing","grade","button","symbol"]},{"emoji":"๐Ÿˆต","name":"Japanese โ€œno vacancyโ€ button","keywords":["japanese","no","vacancy","button","symbol"]},{"emoji":"๐Ÿˆน","name":"Japanese โ€œdiscountโ€ button","keywords":["japanese","discount","button","symbol"]},{"emoji":"๐Ÿˆฒ","name":"Japanese โ€œprohibitedโ€ button","keywords":["japanese","prohibited","button","symbol"]},{"emoji":"๐Ÿ‰‘","name":"Japanese โ€œacceptableโ€ button","keywords":["japanese","acceptable","button","symbol"]},{"emoji":"๐Ÿˆถ","name":"Japanese โ€œnot free of chargeโ€ button","keywords":["japanese","not","free","charge","button","symbol"]},{"emoji":"๐Ÿˆš","name":"Japanese โ€œfree of chargeโ€ button","keywords":["japanese","free","charge","button","symbol"]},{"emoji":"๐Ÿˆธ","name":"Japanese โ€œapplicationโ€ button","keywords":["japanese","application","button","symbol"]},{"emoji":"๐Ÿˆบ","name":"Japanese โ€œopen for businessโ€ button","keywords":["japanese","open","business","button","symbol"]},{"emoji":"๐Ÿˆท๏ธ","name":"Japanese โ€œmonthly amountโ€ button","keywords":["japanese","monthly","amount","button","symbol"]},{"emoji":"โœด๏ธ","name":"eight-pointed star","keywords":["eight","pointed","star","symbol"]},{"emoji":"๐Ÿ”ถ","name":"large orange diamond","keywords":["large","orange","diamond","symbol"]},{"emoji":"๐Ÿ”ธ","name":"small orange diamond","keywords":["small","orange","diamond","symbol"]},{"emoji":"๐Ÿ”†","name":"bright button","keywords":["bright","button","symbol"]},{"emoji":"๐Ÿ”…","name":"dim button","keywords":["dim","button","symbol"]},{"emoji":"๐Ÿ†š","name":"VS button","keywords":["vs","button","symbol"]},{"emoji":"๐ŸŽฆ","name":"cinema","keywords":["cinema","symbol"]},{"emoji":"๐Ÿ“ถ","name":"antenna bars","keywords":["antenna","bars","symbol"]},{"emoji":"๐Ÿ”","name":"repeat button","keywords":["repeat","button","symbol"]},{"emoji":"๐Ÿ”‚","name":"repeat single button","keywords":["repeat","single","button","symbol"]},{"emoji":"๐Ÿ”€","name":"shuffle tracks button","keywords":["shuffle","tracks","button","symbol"]},{"emoji":"โ–ถ๏ธ","name":"play button","keywords":["play","button","symbol"]},{"emoji":"โฉ","name":"fast-forward button","keywords":["fast","forward","button","symbol"]},{"emoji":"โญ๏ธ","name":"next track button","keywords":["next","track","button","symbol"]},{"emoji":"โฏ๏ธ","name":"play or pause button","keywords":["play","or","pause","button","symbol"]},{"emoji":"โ—€๏ธ","name":"reverse button","keywords":["reverse","button","symbol"]},{"emoji":"โช","name":"fast reverse button","keywords":["fast","reverse","button","symbol"]},{"emoji":"โฎ๏ธ","name":"last track button","keywords":["last","track","button","symbol"]},{"emoji":"๐Ÿ”ผ","name":"upwards button","keywords":["upwards","button","symbol"]},{"emoji":"โซ","name":"fast up button","keywords":["fast","up","button","symbol"]},{"emoji":"๐Ÿ”ฝ","name":"downwards button","keywords":["downwards","button","symbol"]},{"emoji":"โฌ","name":"fast down button","keywords":["fast","down","button","symbol"]},{"emoji":"โธ๏ธ","name":"pause button","keywords":["pause","button","symbol"]},{"emoji":"โน๏ธ","name":"stop button","keywords":["stop","button","symbol"]},{"emoji":"โบ๏ธ","name":"record button","keywords":["record","button","symbol"]},{"emoji":"โ๏ธ","name":"eject button","keywords":["eject","button","symbol"]},{"emoji":"๐Ÿ“ด","name":"mobile phone off","keywords":["mobile","phone","off","symbol"]},{"emoji":"๐Ÿ›œ","name":"wireless","keywords":["wireless","symbol"]},{"emoji":"๐Ÿ“ณ","name":"vibration mode","keywords":["vibration","mode","symbol"]},{"emoji":"๐Ÿ“ฒ","name":"mobile phone with arrow","keywords":["mobile","phone","arrow","symbol"]},{"emoji":"โ˜ข๏ธ","name":"radioactive","keywords":["radioactive","symbol"]},{"emoji":"โ˜ฃ๏ธ","name":"biohazard","keywords":["biohazard","symbol"]},{"emoji":"โš ๏ธ","name":"warning","keywords":["warning","symbol"]},{"emoji":"๐Ÿšธ","name":"children crossing","keywords":["children","crossing","symbol"]},{"emoji":"โšœ๏ธ","name":"fleur-de-lis","keywords":["fleur","de","lis","symbol"]},{"emoji":"๐Ÿ”ฑ","name":"trident emblem","keywords":["trident","emblem","symbol"]},{"emoji":"ใ€ฝ๏ธ","name":"part alternation mark","keywords":["part","alternation","mark","symbol"]},{"emoji":"๐Ÿ”ฐ","name":"Japanese symbol for beginner","keywords":["japanese","symbol","beginner"]},{"emoji":"โœณ๏ธ","name":"eight-spoked asterisk","keywords":["eight","spoked","asterisk","symbol"]},{"emoji":"โ‡๏ธ","name":"sparkle","keywords":["sparkle","symbol"]},{"emoji":"โ™ป๏ธ","name":"recycling symbol","keywords":["recycling","symbol"]},{"emoji":"๐Ÿ’ฑ","name":"currency exchange","keywords":["currency","exchange","symbol"]},{"emoji":"๐Ÿ’ฒ","name":"heavy dollar sign","keywords":["heavy","dollar","sign","symbol"]},{"emoji":"๐Ÿ’น","name":"chart increasing with yen","keywords":["chart","increasing","yen","symbol"]},{"emoji":"๐Ÿˆฏ","name":"Japanese โ€œreservedโ€ button","keywords":["japanese","reserved","button","symbol"]},{"emoji":"โŽ","name":"cross mark button","keywords":["cross","mark","button","symbol"]},{"emoji":"โœ…","name":"check mark button","keywords":["check","mark","button","symbol"]},{"emoji":"โœ”๏ธ","name":"check mark","keywords":["check","mark","symbol"]},{"emoji":"โ˜‘๏ธ","name":"check box with check","keywords":["check","box","symbol"]},{"emoji":"โฌ†๏ธ","name":"up arrow","keywords":["up","arrow","symbol"]},{"emoji":"โ†—๏ธ","name":"up-right arrow","keywords":["up","right","arrow","symbol"]},{"emoji":"โžก๏ธ","name":"right arrow","keywords":["right","arrow","symbol"]},{"emoji":"โ†˜๏ธ","name":"down-right arrow","keywords":["down","right","arrow","symbol"]},{"emoji":"โฌ‡๏ธ","name":"down arrow","keywords":["down","arrow","symbol"]},{"emoji":"โ†™๏ธ","name":"down-left arrow","keywords":["down","left","arrow","symbol"]},{"emoji":"โฌ…๏ธ","name":"left arrow","keywords":["left","arrow","symbol"]},{"emoji":"โ†–๏ธ","name":"up-left arrow","keywords":["up","left","arrow","symbol"]},{"emoji":"โ†•๏ธ","name":"up-down arrow","keywords":["up","down","arrow","symbol"]},{"emoji":"โ†”๏ธ","name":"left-right arrow","keywords":["left","right","arrow","symbol"]},{"emoji":"โ†ฉ๏ธ","name":"right arrow curving left","keywords":["right","arrow","curving","left","symbol"]},{"emoji":"โ†ช๏ธ","name":"left arrow curving right","keywords":["left","arrow","curving","right","symbol"]},{"emoji":"โคด๏ธ","name":"right arrow curving up","keywords":["right","arrow","curving","up","symbol"]},{"emoji":"โคต๏ธ","name":"right arrow curving down","keywords":["right","arrow","curving","down","symbol"]},{"emoji":"๐Ÿ”ƒ","name":"clockwise vertical arrows","keywords":["clockwise","vertical","arrows","symbol"]},{"emoji":"๐Ÿ”„","name":"counterclockwise arrows button","keywords":["counterclockwise","arrows","button","symbol"]},{"emoji":"๐Ÿ”™","name":"BACK arrow","keywords":["back","arrow","symbol"]},{"emoji":"๐Ÿ”›","name":"ON! arrow","keywords":["arrow","symbol"]},{"emoji":"๐Ÿ”","name":"TOP arrow","keywords":["top","arrow","symbol"]},{"emoji":"๐Ÿ”š","name":"END arrow","keywords":["end","arrow","symbol"]},{"emoji":"๐Ÿ”œ","name":"SOON arrow","keywords":["soon","arrow","symbol"]},{"emoji":"๐Ÿ†•","name":"NEW button","keywords":["new","button","symbol"]},{"emoji":"๐Ÿ†“","name":"FREE button","keywords":["free","button","symbol"]},{"emoji":"๐Ÿ†™","name":"UP! button","keywords":["up","button","symbol"]},{"emoji":"๐Ÿ†—","name":"OK button","keywords":["ok","button","symbol"]},{"emoji":"๐Ÿ†’","name":"COOL button","keywords":["cool","button","symbol"]},{"emoji":"๐Ÿ†–","name":"NG button","keywords":["ng","button","symbol"]},{"emoji":"โ„น๏ธ","name":"information","keywords":["information","symbol"]},{"emoji":"๐Ÿ…ฟ๏ธ","name":"P button","keywords":["button","symbol"]},{"emoji":"๐Ÿˆ","name":"Japanese โ€œhereโ€ button","keywords":["japanese","here","button","symbol"]},{"emoji":"๐Ÿˆ‚๏ธ","name":"Japanese โ€œservice chargeโ€ button","keywords":["japanese","service","charge","button","symbol"]},{"emoji":"๐Ÿˆณ","name":"Japanese โ€œvacancyโ€ button","keywords":["japanese","vacancy","button","symbol"]},{"emoji":"๐Ÿ”ฃ","name":"input symbols","keywords":["input","symbols","symbol"]},{"emoji":"๐Ÿ”ค","name":"input latin letters","keywords":["input","latin","letters","symbol"]},{"emoji":"๐Ÿ” ","name":"input latin uppercase","keywords":["input","latin","uppercase","symbol"]},{"emoji":"๐Ÿ”ก","name":"input latin lowercase","keywords":["input","latin","lowercase","symbol"]},{"emoji":"๐Ÿ”ข","name":"input numbers","keywords":["input","numbers","symbol"]},{"emoji":"#๏ธโƒฃ","name":"keycap: #","keywords":["keycap","symbol"]},{"emoji":"*๏ธโƒฃ","name":"keycap: *","keywords":["keycap","symbol"]},{"emoji":"0๏ธโƒฃ","name":"keycap: 0","keywords":["keycap","symbol"]},{"emoji":"1๏ธโƒฃ","name":"keycap: 1","keywords":["keycap","symbol"]},{"emoji":"2๏ธโƒฃ","name":"keycap: 2","keywords":["keycap","symbol"]},{"emoji":"3๏ธโƒฃ","name":"keycap: 3","keywords":["keycap","symbol"]},{"emoji":"4๏ธโƒฃ","name":"keycap: 4","keywords":["keycap","symbol"]},{"emoji":"5๏ธโƒฃ","name":"keycap: 5","keywords":["keycap","symbol"]},{"emoji":"6๏ธโƒฃ","name":"keycap: 6","keywords":["keycap","symbol"]},{"emoji":"7๏ธโƒฃ","name":"keycap: 7","keywords":["keycap","symbol"]},{"emoji":"8๏ธโƒฃ","name":"keycap: 8","keywords":["keycap","symbol"]},{"emoji":"9๏ธโƒฃ","name":"keycap: 9","keywords":["keycap","symbol"]},{"emoji":"๐Ÿ”Ÿ","name":"keycap: 10","keywords":["keycap","10","symbol"]},{"emoji":"๐Ÿ’ ","name":"diamond with a dot","keywords":["diamond","dot","symbol"]},{"emoji":"๐Ÿ”ท","name":"large blue diamond","keywords":["large","blue","diamond","symbol"]},{"emoji":"๐Ÿ”น","name":"small blue diamond","keywords":["small","blue","diamond","symbol"]},{"emoji":"๐Ÿง","name":"ATM sign","keywords":["atm","sign","symbol"]},{"emoji":"โ“‚๏ธ","name":"circled M","keywords":["circled","symbol"]},{"emoji":"๐Ÿšพ","name":"water closet","keywords":["water","closet","symbol"]},{"emoji":"๐Ÿšป","name":"restroom","keywords":["restroom","symbol"]},{"emoji":"๐Ÿšน","name":"menโ€™s room","keywords":["men","room","symbol"]},{"emoji":"๐Ÿšบ","name":"womenโ€™s room","keywords":["women","room","symbol"]},{"emoji":"โ™ฟ","name":"wheelchair symbol","keywords":["wheelchair","symbol"]},{"emoji":"๐Ÿšผ","name":"baby symbol","keywords":["baby","symbol"]},{"emoji":"๐Ÿ›—","name":"elevator","keywords":["elevator","symbol"]},{"emoji":"๐Ÿšฎ","name":"litter in bin sign","keywords":["litter","bin","sign","symbol"]},{"emoji":"๐Ÿšฐ","name":"potable water","keywords":["potable","water","symbol"]},{"emoji":"๐Ÿ›‚","name":"passport control","keywords":["passport","control","symbol"]},{"emoji":"๐Ÿ›ƒ","name":"customs","keywords":["customs","symbol"]},{"emoji":"๐Ÿ›„","name":"baggage claim","keywords":["baggage","claim","symbol"]},{"emoji":"๐Ÿ›…","name":"left luggage","keywords":["left","luggage","symbol"]},{"emoji":"โš›๏ธ","name":"atom symbol","keywords":["atom","symbol"]},{"emoji":"๐Ÿ›","name":"place of worship","keywords":["place","worship","symbol"]},{"emoji":"๐Ÿ•‰๏ธ","name":"om","keywords":["om","symbol"]},{"emoji":"โ˜ธ๏ธ","name":"wheel of dharma","keywords":["wheel","dharma","symbol"]},{"emoji":"โ˜ฎ๏ธ","name":"peace symbol","keywords":["peace","symbol"]},{"emoji":"โ˜ฏ๏ธ","name":"yin yang","keywords":["yin","yang","symbol"]},{"emoji":"โ˜ช๏ธ","name":"star and crescent","keywords":["star","crescent","symbol"]},{"emoji":"๐Ÿชฏ","name":"khanda","keywords":["khanda","symbol"]},{"emoji":"โœ๏ธ","name":"latin cross","keywords":["latin","cross","symbol"]},{"emoji":"โ˜ฆ๏ธ","name":"orthodox cross","keywords":["orthodox","cross","symbol"]},{"emoji":"โœก๏ธ","name":"star of David","keywords":["star","david","symbol"]},{"emoji":"๐Ÿ”ฏ","name":"dotted six-pointed star","keywords":["dotted","six","pointed","star","symbol"]},{"emoji":"๐Ÿ•Ž","name":"menorah","keywords":["menorah","symbol"]},{"emoji":"โ™พ๏ธ","name":"infinity","keywords":["infinity","symbol"]},{"emoji":"๐Ÿ†”","name":"ID button","keywords":["id","button","symbol"]},{"emoji":"๐Ÿง‘โ€๐Ÿง‘โ€๐Ÿง’","name":"family: adult, adult, child","keywords":["family","adult","child","symbol"]},{"emoji":"๐Ÿง‘โ€๐Ÿง‘โ€๐Ÿง’โ€๐Ÿง’","name":"family: adult, adult, child, child","keywords":["family","adult","child","symbol"]},{"emoji":"๐Ÿง‘โ€๐Ÿง’","name":"family: adult, child","keywords":["family","adult","child","symbol"]},{"emoji":"๐Ÿง‘โ€๐Ÿง’โ€๐Ÿง’","name":"family: adult, child, child","keywords":["family","adult","child","symbol"]},{"emoji":"โš•๏ธ","name":"medical symbol","keywords":["medical","symbol"]},{"emoji":"๐ŸŽผ","name":"musical score","keywords":["musical","score","symbol"]},{"emoji":"๐ŸŽต","name":"musical note","keywords":["musical","note","symbol"]},{"emoji":"๐ŸŽถ","name":"musical notes","keywords":["musical","notes","symbol"]},{"emoji":"โœ–๏ธ","name":"multiply","keywords":["multiply","symbol"]},{"emoji":"โž•","name":"plus","keywords":["plus","symbol"]},{"emoji":"โž–","name":"minus","keywords":["minus","symbol"]},{"emoji":"โž—","name":"divide","keywords":["divide","symbol"]},{"emoji":"๐ŸŸฐ","name":"heavy equals sign","keywords":["heavy","equals","sign","symbol"]},{"emoji":"โžฐ","name":"curly loop","keywords":["curly","loop","symbol"]},{"emoji":"โžฟ","name":"double curly loop","keywords":["double","curly","loop","symbol"]},{"emoji":"ใ€ฐ๏ธ","name":"wavy dash","keywords":["wavy","dash","symbol"]},{"emoji":"ยฉ๏ธ","name":"copyright","keywords":["copyright","symbol"]},{"emoji":"ยฎ๏ธ","name":"registered","keywords":["registered","symbol"]},{"emoji":"โ„ข๏ธ","name":"trade mark","keywords":["trade","mark","symbol"]},{"emoji":"๐Ÿ”˜","name":"radio button","keywords":["radio","button","symbol"]},{"emoji":"๐Ÿ”ณ","name":"white square button","keywords":["white","square","button","symbol"]},{"emoji":"โ—ผ๏ธ","name":"black medium square","keywords":["black","medium","square","symbol"]},{"emoji":"โ—พ","name":"black medium-small square","keywords":["black","medium","small","square","symbol"]},{"emoji":"โ–ช๏ธ","name":"black small square","keywords":["black","small","square","symbol"]},{"emoji":"๐Ÿ”ฒ","name":"black square button","keywords":["black","square","button","symbol"]},{"emoji":"โ—ป๏ธ","name":"white medium square","keywords":["white","medium","square","symbol"]},{"emoji":"โ—ฝ","name":"white medium-small square","keywords":["white","medium","small","square","symbol"]},{"emoji":"โ–ซ๏ธ","name":"white small square","keywords":["white","small","square","symbol"]},{"emoji":"๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ","name":"eye in speech bubble","keywords":["eye","speech","bubble","symbol"]},{"emoji":"๐Ÿ","name":"chequered flag","keywords":["chequered","flag"]},{"emoji":"๐Ÿšฉ","name":"triangular flag","keywords":["triangular","flag"]},{"emoji":"๐ŸŽŒ","name":"crossed flags","keywords":["crossed","flags","flag"]},{"emoji":"๐Ÿด","name":"black flag","keywords":["black","flag"]},{"emoji":"๐Ÿณ๏ธ","name":"white flag","keywords":["white","flag"]},{"emoji":"๐Ÿณ๏ธโ€๐ŸŒˆ","name":"rainbow flag","keywords":["rainbow","flag"]},{"emoji":"๐Ÿณ๏ธโ€โšง๏ธ","name":"transgender flag","keywords":["transgender","flag"]},{"emoji":"๐Ÿดโ€โ˜ ๏ธ","name":"pirate flag","keywords":["pirate","flag"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡จ","name":"flag: Ascension Island","keywords":["flag","ascension","island"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฉ","name":"flag: Andorra","keywords":["flag","andorra"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ช","name":"flag: United Arab Emirates","keywords":["flag","united","arab","emirates"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ซ","name":"flag: Afghanistan","keywords":["flag","afghanistan"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฌ","name":"flag: Antigua & Barbuda","keywords":["flag","antigua","barbuda"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฎ","name":"flag: Anguilla","keywords":["flag","anguilla"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฑ","name":"flag: Albania","keywords":["flag","albania"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฒ","name":"flag: Armenia","keywords":["flag","armenia"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ด","name":"flag: Angola","keywords":["flag","angola"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ถ","name":"flag: Antarctica","keywords":["flag","antarctica"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ท","name":"flag: Argentina","keywords":["flag","argentina"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ธ","name":"flag: American Samoa","keywords":["flag","american","samoa"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡น","name":"flag: Austria","keywords":["flag","austria"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡บ","name":"flag: Australia","keywords":["flag","australia"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ผ","name":"flag: Aruba","keywords":["flag","aruba"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฝ","name":"flag: ร…land Islands","keywords":["flag","land","islands"]},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฟ","name":"flag: Azerbaijan","keywords":["flag","azerbaijan"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฆ","name":"flag: Bosnia & Herzegovina","keywords":["flag","bosnia","herzegovina"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ง","name":"flag: Barbados","keywords":["flag","barbados"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฉ","name":"flag: Bangladesh","keywords":["flag","bangladesh"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ช","name":"flag: Belgium","keywords":["flag","belgium"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ซ","name":"flag: Burkina Faso","keywords":["flag","burkina","faso"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฌ","name":"flag: Bulgaria","keywords":["flag","bulgaria"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ญ","name":"flag: Bahrain","keywords":["flag","bahrain"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฎ","name":"flag: Burundi","keywords":["flag","burundi"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฏ","name":"flag: Benin","keywords":["flag","benin"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฑ","name":"flag: St. Barthรฉlemy","keywords":["flag","st","barth","lemy"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฒ","name":"flag: Bermuda","keywords":["flag","bermuda"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ณ","name":"flag: Brunei","keywords":["flag","brunei"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ด","name":"flag: Bolivia","keywords":["flag","bolivia"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ถ","name":"flag: Caribbean Netherlands","keywords":["flag","caribbean","netherlands"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ท","name":"flag: Brazil","keywords":["flag","brazil"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ธ","name":"flag: Bahamas","keywords":["flag","bahamas"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡น","name":"flag: Bhutan","keywords":["flag","bhutan"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ป","name":"flag: Bouvet Island","keywords":["flag","bouvet","island"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ผ","name":"flag: Botswana","keywords":["flag","botswana"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡พ","name":"flag: Belarus","keywords":["flag","belarus"]},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฟ","name":"flag: Belize","keywords":["flag","belize"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฆ","name":"flag: Canada","keywords":["flag","canada"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡จ","name":"flag: Cocos (Keeling) Islands","keywords":["flag","cocos","keeling","islands"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฉ","name":"flag: Congo - Kinshasa","keywords":["flag","congo","kinshasa"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ซ","name":"flag: Central African Republic","keywords":["flag","central","african","republic"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฌ","name":"flag: Congo - Brazzaville","keywords":["flag","congo","brazzaville"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ญ","name":"flag: Switzerland","keywords":["flag","switzerland"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฎ","name":"flag: Cรดte dโ€™Ivoire","keywords":["flag","te","ivoire"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฐ","name":"flag: Cook Islands","keywords":["flag","cook","islands"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฑ","name":"flag: Chile","keywords":["flag","chile"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฒ","name":"flag: Cameroon","keywords":["flag","cameroon"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ณ","name":"flag: China","keywords":["flag","china"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ด","name":"flag: Colombia","keywords":["flag","colombia"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ต","name":"flag: Clipperton Island","keywords":["flag","clipperton","island"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ถ","name":"flag: Sark","keywords":["flag","sark"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ท","name":"flag: Costa Rica","keywords":["flag","costa","rica"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡บ","name":"flag: Cuba","keywords":["flag","cuba"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ป","name":"flag: Cape Verde","keywords":["flag","cape","verde"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ผ","name":"flag: Curaรงao","keywords":["flag","cura","ao"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฝ","name":"flag: Christmas Island","keywords":["flag","christmas","island"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡พ","name":"flag: Cyprus","keywords":["flag","cyprus"]},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฟ","name":"flag: Czechia","keywords":["flag","czechia"]},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ช","name":"flag: Germany","keywords":["flag","germany"]},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฌ","name":"flag: Diego Garcia","keywords":["flag","diego","garcia"]},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฏ","name":"flag: Djibouti","keywords":["flag","djibouti"]},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฐ","name":"flag: Denmark","keywords":["flag","denmark"]},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฒ","name":"flag: Dominica","keywords":["flag","dominica"]},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ด","name":"flag: Dominican Republic","keywords":["flag","dominican","republic"]},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฟ","name":"flag: Algeria","keywords":["flag","algeria"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡ฆ","name":"flag: Ceuta & Melilla","keywords":["flag","ceuta","melilla"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡จ","name":"flag: Ecuador","keywords":["flag","ecuador"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡ช","name":"flag: Estonia","keywords":["flag","estonia"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡ฌ","name":"flag: Egypt","keywords":["flag","egypt"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡ญ","name":"flag: Western Sahara","keywords":["flag","western","sahara"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡ท","name":"flag: Eritrea","keywords":["flag","eritrea"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡ธ","name":"flag: Spain","keywords":["flag","spain"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡น","name":"flag: Ethiopia","keywords":["flag","ethiopia"]},{"emoji":"๐Ÿ‡ช๐Ÿ‡บ","name":"flag: European Union","keywords":["flag","european","union"]},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฎ","name":"flag: Finland","keywords":["flag","finland"]},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฏ","name":"flag: Fiji","keywords":["flag","fiji"]},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฐ","name":"flag: Falkland Islands","keywords":["flag","falkland","islands"]},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฒ","name":"flag: Micronesia","keywords":["flag","micronesia"]},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ด","name":"flag: Faroe Islands","keywords":["flag","faroe","islands"]},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ท","name":"flag: France","keywords":["flag","france"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฆ","name":"flag: Gabon","keywords":["flag","gabon"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ง","name":"flag: United Kingdom","keywords":["flag","united","kingdom"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฉ","name":"flag: Grenada","keywords":["flag","grenada"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ช","name":"flag: Georgia","keywords":["flag","georgia"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ซ","name":"flag: French Guiana","keywords":["flag","french","guiana"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฌ","name":"flag: Guernsey","keywords":["flag","guernsey"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ญ","name":"flag: Ghana","keywords":["flag","ghana"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฎ","name":"flag: Gibraltar","keywords":["flag","gibraltar"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฑ","name":"flag: Greenland","keywords":["flag","greenland"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฒ","name":"flag: Gambia","keywords":["flag","gambia"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ณ","name":"flag: Guinea","keywords":["flag","guinea"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ต","name":"flag: Guadeloupe","keywords":["flag","guadeloupe"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ถ","name":"flag: Equatorial Guinea","keywords":["flag","equatorial","guinea"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ท","name":"flag: Greece","keywords":["flag","greece"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ธ","name":"flag: South Georgia & South Sandwich Islands","keywords":["flag","south","georgia","sandwich","islands"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡น","name":"flag: Guatemala","keywords":["flag","guatemala"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡บ","name":"flag: Guam","keywords":["flag","guam"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ผ","name":"flag: Guinea-Bissau","keywords":["flag","guinea","bissau"]},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡พ","name":"flag: Guyana","keywords":["flag","guyana"]},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ฐ","name":"flag: Hong Kong SAR China","keywords":["flag","hong","kong","sar","china"]},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ฒ","name":"flag: Heard & McDonald Islands","keywords":["flag","heard","mcdonald","islands"]},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ณ","name":"flag: Honduras","keywords":["flag","honduras"]},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ท","name":"flag: Croatia","keywords":["flag","croatia"]},{"emoji":"๐Ÿ‡ญ๐Ÿ‡น","name":"flag: Haiti","keywords":["flag","haiti"]},{"emoji":"๐Ÿ‡ญ๐Ÿ‡บ","name":"flag: Hungary","keywords":["flag","hungary"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡จ","name":"flag: Canary Islands","keywords":["flag","canary","islands"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ฉ","name":"flag: Indonesia","keywords":["flag","indonesia"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ช","name":"flag: Ireland","keywords":["flag","ireland"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ฑ","name":"flag: Israel","keywords":["flag","israel"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ฒ","name":"flag: Isle of Man","keywords":["flag","isle","man"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ณ","name":"flag: India","keywords":["flag","india"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ด","name":"flag: British Indian Ocean Territory","keywords":["flag","british","indian","ocean","territory"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ถ","name":"flag: Iraq","keywords":["flag","iraq"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ท","name":"flag: Iran","keywords":["flag","iran"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ธ","name":"flag: Iceland","keywords":["flag","iceland"]},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡น","name":"flag: Italy","keywords":["flag","italy"]},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ช","name":"flag: Jersey","keywords":["flag","jersey"]},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ฒ","name":"flag: Jamaica","keywords":["flag","jamaica"]},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ด","name":"flag: Jordan","keywords":["flag","jordan"]},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ต","name":"flag: Japan","keywords":["flag","japan"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ช","name":"flag: Kenya","keywords":["flag","kenya"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฌ","name":"flag: Kyrgyzstan","keywords":["flag","kyrgyzstan"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ญ","name":"flag: Cambodia","keywords":["flag","cambodia"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฎ","name":"flag: Kiribati","keywords":["flag","kiribati"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฒ","name":"flag: Comoros","keywords":["flag","comoros"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ณ","name":"flag: St. Kitts & Nevis","keywords":["flag","st","kitts","nevis"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ต","name":"flag: North Korea","keywords":["flag","north","korea"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ท","name":"flag: South Korea","keywords":["flag","south","korea"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ผ","name":"flag: Kuwait","keywords":["flag","kuwait"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡พ","name":"flag: Cayman Islands","keywords":["flag","cayman","islands"]},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฟ","name":"flag: Kazakhstan","keywords":["flag","kazakhstan"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ฆ","name":"flag: Laos","keywords":["flag","laos"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ง","name":"flag: Lebanon","keywords":["flag","lebanon"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡จ","name":"flag: St. Lucia","keywords":["flag","st","lucia"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ฎ","name":"flag: Liechtenstein","keywords":["flag","liechtenstein"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ฐ","name":"flag: Sri Lanka","keywords":["flag","sri","lanka"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ท","name":"flag: Liberia","keywords":["flag","liberia"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ธ","name":"flag: Lesotho","keywords":["flag","lesotho"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡น","name":"flag: Lithuania","keywords":["flag","lithuania"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡บ","name":"flag: Luxembourg","keywords":["flag","luxembourg"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ป","name":"flag: Latvia","keywords":["flag","latvia"]},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡พ","name":"flag: Libya","keywords":["flag","libya"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฆ","name":"flag: Morocco","keywords":["flag","morocco"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡จ","name":"flag: Monaco","keywords":["flag","monaco"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฉ","name":"flag: Moldova","keywords":["flag","moldova"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ช","name":"flag: Montenegro","keywords":["flag","montenegro"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ซ","name":"flag: St. Martin","keywords":["flag","st","martin"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฌ","name":"flag: Madagascar","keywords":["flag","madagascar"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ญ","name":"flag: Marshall Islands","keywords":["flag","marshall","islands"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฐ","name":"flag: North Macedonia","keywords":["flag","north","macedonia"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฑ","name":"flag: Mali","keywords":["flag","mali"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฒ","name":"flag: Myanmar (Burma)","keywords":["flag","myanmar","burma"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ณ","name":"flag: Mongolia","keywords":["flag","mongolia"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ด","name":"flag: Macao SAR China","keywords":["flag","macao","sar","china"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ต","name":"flag: Northern Mariana Islands","keywords":["flag","northern","mariana","islands"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ถ","name":"flag: Martinique","keywords":["flag","martinique"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ท","name":"flag: Mauritania","keywords":["flag","mauritania"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ธ","name":"flag: Montserrat","keywords":["flag","montserrat"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡น","name":"flag: Malta","keywords":["flag","malta"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡บ","name":"flag: Mauritius","keywords":["flag","mauritius"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ป","name":"flag: Maldives","keywords":["flag","maldives"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ผ","name":"flag: Malawi","keywords":["flag","malawi"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฝ","name":"flag: Mexico","keywords":["flag","mexico"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡พ","name":"flag: Malaysia","keywords":["flag","malaysia"]},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฟ","name":"flag: Mozambique","keywords":["flag","mozambique"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฆ","name":"flag: Namibia","keywords":["flag","namibia"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡จ","name":"flag: New Caledonia","keywords":["flag","new","caledonia"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ช","name":"flag: Niger","keywords":["flag","niger"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ซ","name":"flag: Norfolk Island","keywords":["flag","norfolk","island"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฌ","name":"flag: Nigeria","keywords":["flag","nigeria"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฎ","name":"flag: Nicaragua","keywords":["flag","nicaragua"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฑ","name":"flag: Netherlands","keywords":["flag","netherlands"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ด","name":"flag: Norway","keywords":["flag","norway"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ต","name":"flag: Nepal","keywords":["flag","nepal"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ท","name":"flag: Nauru","keywords":["flag","nauru"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡บ","name":"flag: Niue","keywords":["flag","niue"]},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฟ","name":"flag: New Zealand","keywords":["flag","new","zealand"]},{"emoji":"๐Ÿ‡ด๐Ÿ‡ฒ","name":"flag: Oman","keywords":["flag","oman"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฆ","name":"flag: Panama","keywords":["flag","panama"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ช","name":"flag: Peru","keywords":["flag","peru"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ซ","name":"flag: French Polynesia","keywords":["flag","french","polynesia"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฌ","name":"flag: Papua New Guinea","keywords":["flag","papua","new","guinea"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ญ","name":"flag: Philippines","keywords":["flag","philippines"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฐ","name":"flag: Pakistan","keywords":["flag","pakistan"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฑ","name":"flag: Poland","keywords":["flag","poland"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฒ","name":"flag: St. Pierre & Miquelon","keywords":["flag","st","pierre","miquelon"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ณ","name":"flag: Pitcairn Islands","keywords":["flag","pitcairn","islands"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ท","name":"flag: Puerto Rico","keywords":["flag","puerto","rico"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ธ","name":"flag: Palestinian Territories","keywords":["flag","palestinian","territories"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡น","name":"flag: Portugal","keywords":["flag","portugal"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡ผ","name":"flag: Palau","keywords":["flag","palau"]},{"emoji":"๐Ÿ‡ต๐Ÿ‡พ","name":"flag: Paraguay","keywords":["flag","paraguay"]},{"emoji":"๐Ÿ‡ถ๐Ÿ‡ฆ","name":"flag: Qatar","keywords":["flag","qatar"]},{"emoji":"๐Ÿ‡ท๐Ÿ‡ช","name":"flag: Rรฉunion","keywords":["flag","union"]},{"emoji":"๐Ÿ‡ท๐Ÿ‡ด","name":"flag: Romania","keywords":["flag","romania"]},{"emoji":"๐Ÿ‡ท๐Ÿ‡ธ","name":"flag: Serbia","keywords":["flag","serbia"]},{"emoji":"๐Ÿ‡ท๐Ÿ‡บ","name":"flag: Russia","keywords":["flag","russia"]},{"emoji":"๐Ÿ‡ท๐Ÿ‡ผ","name":"flag: Rwanda","keywords":["flag","rwanda"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฆ","name":"flag: Saudi Arabia","keywords":["flag","saudi","arabia"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ง","name":"flag: Solomon Islands","keywords":["flag","solomon","islands"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡จ","name":"flag: Seychelles","keywords":["flag","seychelles"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฉ","name":"flag: Sudan","keywords":["flag","sudan"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ช","name":"flag: Sweden","keywords":["flag","sweden"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฌ","name":"flag: Singapore","keywords":["flag","singapore"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ญ","name":"flag: St. Helena","keywords":["flag","st","helena"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฎ","name":"flag: Slovenia","keywords":["flag","slovenia"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฏ","name":"flag: Svalbard & Jan Mayen","keywords":["flag","svalbard","jan","mayen"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฐ","name":"flag: Slovakia","keywords":["flag","slovakia"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฑ","name":"flag: Sierra Leone","keywords":["flag","sierra","leone"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฒ","name":"flag: San Marino","keywords":["flag","san","marino"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ณ","name":"flag: Senegal","keywords":["flag","senegal"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ด","name":"flag: Somalia","keywords":["flag","somalia"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ท","name":"flag: Suriname","keywords":["flag","suriname"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ธ","name":"flag: South Sudan","keywords":["flag","south","sudan"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡น","name":"flag: Sรฃo Tomรฉ & Prรญncipe","keywords":["flag","tom","pr","ncipe"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ป","name":"flag: El Salvador","keywords":["flag","el","salvador"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฝ","name":"flag: Sint Maarten","keywords":["flag","sint","maarten"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡พ","name":"flag: Syria","keywords":["flag","syria"]},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฟ","name":"flag: Eswatini","keywords":["flag","eswatini"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฆ","name":"flag: Tristan da Cunha","keywords":["flag","tristan","da","cunha"]},{"emoji":"๐Ÿ‡น๐Ÿ‡จ","name":"flag: Turks & Caicos Islands","keywords":["flag","turks","caicos","islands"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฉ","name":"flag: Chad","keywords":["flag","chad"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ซ","name":"flag: French Southern Territories","keywords":["flag","french","southern","territories"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฌ","name":"flag: Togo","keywords":["flag","togo"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ญ","name":"flag: Thailand","keywords":["flag","thailand"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฏ","name":"flag: Tajikistan","keywords":["flag","tajikistan"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฐ","name":"flag: Tokelau","keywords":["flag","tokelau"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฑ","name":"flag: Timor-Leste","keywords":["flag","timor","leste"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฒ","name":"flag: Turkmenistan","keywords":["flag","turkmenistan"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ณ","name":"flag: Tunisia","keywords":["flag","tunisia"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ด","name":"flag: Tonga","keywords":["flag","tonga"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ท","name":"flag: Tรผrkiye","keywords":["flag","rkiye"]},{"emoji":"๐Ÿ‡น๐Ÿ‡น","name":"flag: Trinidad & Tobago","keywords":["flag","trinidad","tobago"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ป","name":"flag: Tuvalu","keywords":["flag","tuvalu"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ผ","name":"flag: Taiwan","keywords":["flag","taiwan"]},{"emoji":"๐Ÿ‡น๐Ÿ‡ฟ","name":"flag: Tanzania","keywords":["flag","tanzania"]},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฆ","name":"flag: Ukraine","keywords":["flag","ukraine"]},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฌ","name":"flag: Uganda","keywords":["flag","uganda"]},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฒ","name":"flag: U.S. Outlying Islands","keywords":["flag","outlying","islands"]},{"emoji":"๐Ÿ‡บ๐Ÿ‡ณ","name":"flag: United Nations","keywords":["flag","united","nations"]},{"emoji":"๐Ÿ‡บ๐Ÿ‡ธ","name":"flag: United States","keywords":["flag","united","states"]},{"emoji":"๐Ÿ‡บ๐Ÿ‡พ","name":"flag: Uruguay","keywords":["flag","uruguay"]},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฟ","name":"flag: Uzbekistan","keywords":["flag","uzbekistan"]},{"emoji":"๐Ÿ‡ป๐Ÿ‡ฆ","name":"flag: Vatican City","keywords":["flag","vatican","city"]},{"emoji":"๐Ÿ‡ป๐Ÿ‡จ","name":"flag: St. Vincent & Grenadines","keywords":["flag","st","vincent","grenadines"]},{"emoji":"๐Ÿ‡ป๐Ÿ‡ช","name":"flag: Venezuela","keywords":["flag","venezuela"]},{"emoji":"๐Ÿ‡ป๐Ÿ‡ฌ","name":"flag: British Virgin Islands","keywords":["flag","british","virgin","islands"]},{"emoji":"๐Ÿ‡ป๐Ÿ‡ฎ","name":"flag: U.S. Virgin Islands","keywords":["flag","virgin","islands"]},{"emoji":"๐Ÿ‡ป๐Ÿ‡ณ","name":"flag: Vietnam","keywords":["flag","vietnam"]},{"emoji":"๐Ÿ‡ป๐Ÿ‡บ","name":"flag: Vanuatu","keywords":["flag","vanuatu"]},{"emoji":"๐Ÿ‡ผ๐Ÿ‡ซ","name":"flag: Wallis & Futuna","keywords":["flag","wallis","futuna"]},{"emoji":"๐Ÿ‡ผ๐Ÿ‡ธ","name":"flag: Samoa","keywords":["flag","samoa"]},{"emoji":"๐Ÿ‡ฝ๐Ÿ‡ฐ","name":"flag: Kosovo","keywords":["flag","kosovo"]},{"emoji":"๐Ÿ‡พ๐Ÿ‡ช","name":"flag: Yemen","keywords":["flag","yemen"]},{"emoji":"๐Ÿ‡พ๐Ÿ‡น","name":"flag: Mayotte","keywords":["flag","mayotte"]},{"emoji":"๐Ÿ‡ฟ๐Ÿ‡ฆ","name":"flag: South Africa","keywords":["flag","south","africa"]},{"emoji":"๐Ÿ‡ฟ๐Ÿ‡ฒ","name":"flag: Zambia","keywords":["flag","zambia"]},{"emoji":"๐Ÿ‡ฟ๐Ÿ‡ผ","name":"flag: Zimbabwe","keywords":["flag","zimbabwe"]},{"emoji":"๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ","name":"flag: England","keywords":["flag","england"]},{"emoji":"๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ","name":"flag: Scotland","keywords":["flag","scotland"]},{"emoji":"๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ","name":"flag: Wales","keywords":["flag","wales"]}] \ No newline at end of file diff --git a/app/src/main/assets/emoji_keywords.json.license b/app/src/main/assets/emoji_keywords.json.license new file mode 100644 index 00000000000..b6fc7379fab --- /dev/null +++ b/app/src/main/assets/emoji_keywords.json.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +SPDX-License-Identifier: GPL-3.0-or-later diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index b542b984499..74ebfbdcc69 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -9,6 +9,7 @@ package com.nextcloud.talk.chat import android.content.Context import android.content.res.Resources +import android.icu.text.BreakIterator import android.os.Build import android.os.Bundle import android.os.CountDownTimer @@ -37,6 +38,7 @@ import android.widget.LinearLayout import android.widget.PopupMenu import android.widget.RelativeLayout import android.widget.SeekBar +import android.widget.TextView import androidx.appcompat.view.ContextThemeWrapper import androidx.compose.material3.MaterialTheme import androidx.core.content.ContextCompat @@ -81,6 +83,7 @@ import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.CharPolicy import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DateUtils +import com.nextcloud.talk.utils.EmojiKeywordProvider import com.nextcloud.talk.utils.EmojiTextInputEditText import com.nextcloud.talk.utils.ImageEmojiEditText import com.nextcloud.talk.utils.SpreedFeatures @@ -89,6 +92,8 @@ import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.text.Spans import com.otaliastudios.autocomplete.Autocomplete import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -128,6 +133,9 @@ class MessageInputFragment : Fragment() { private var hasScheduledMessages = false private lateinit var spreedCapabilities: SpreedCapability private var hasSharedText = false + private val emojiKeywordProvider: EmojiKeywordProvider by lazy { EmojiKeywordProvider(requireContext()) } + private lateinit var recentEmojiProvider: MessageInputRecentEmojiProvider + private var emojiSearchJob: Job? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -782,7 +790,7 @@ class MessageInputFragment : Fragment() { private fun showRecordAudioUi(show: Boolean) { if (show) { restoreKeyboardOnEmojiDismiss = false - binding.emojiPicker.isVisible = false + hideEmojiKeyboardArea() val animation: Animation = AlphaAnimation(FULLY_OPAQUE, FULLY_TRANSPARENT) animation.duration = ANIMATION_DURATION animation.interpolator = LinearInterpolator() @@ -815,7 +823,7 @@ class MessageInputFragment : Fragment() { } private fun updateSmileyButtonIcon() { - val icon = if (binding.emojiPicker.isVisible) { + val icon = if (isEmojiAreaVisible()) { R.drawable.ic_baseline_keyboard_24 } else { R.drawable.ic_insert_emoticon_black_24dp @@ -824,6 +832,137 @@ class MessageInputFragment : Fragment() { binding.fragmentMessageInputView.smileyButton.setImageDrawable(drawable) } + private fun isEmojiAreaVisible(): Boolean = binding.emojiSearchPanel.emojiSearchPanel.isVisible + + private fun showEmojiKeyboardArea() { + binding.emojiSearchPanel.emojiSearchPanel.isVisible = true + binding.emojiSearchPanel.emojiSearchInput.setText("") + binding.emojiPicker.isVisible = true + binding.emojiSearchPanel.emojiSearchResultsScroll.isVisible = false + binding.emojiSearchPanel.emojiSearchNoResults.isVisible = false + } + + private fun hideEmojiKeyboardArea() { + emojiSearchJob?.cancel() + binding.emojiSearchPanel.emojiSearchPanel.isVisible = false + binding.emojiPicker.isVisible = false + binding.emojiSearchPanel.emojiSearchResultsScroll.isVisible = false + binding.emojiSearchPanel.emojiSearchNoResults.isVisible = false + } + + private fun insertEmoji(emoji: String) { + val inputEditText = binding.fragmentMessageInputView.inputEditText + val start = inputEditText.selectionStart + val end = inputEditText.selectionEnd + inputEditText.editableText.replace(start, end, emoji) + } + + private fun onEmojiSearchResultSelected(emoji: String) { + insertEmoji(emoji) + recentEmojiProvider.recordSelection(emoji) + } + + private fun deleteEmojiOrCharacterBeforeCursor() { + val inputEditText = binding.fragmentMessageInputView.inputEditText + val text = inputEditText.text ?: return + + fun rangeToDelete(): Pair? { + val start = inputEditText.selectionStart + val end = inputEditText.selectionEnd + return when { + start < 0 || end < 0 -> null + start != end -> minOf(start, end) to maxOf(start, end) + start == 0 -> null + else -> { + val breakIterator = BreakIterator.getCharacterInstance() + breakIterator.setText(text.toString()) + val deleteStart = breakIterator.preceding(start) + if (deleteStart == BreakIterator.DONE) null else deleteStart to start + } + } + } + + rangeToDelete()?.let { (deleteStart, deleteEnd) -> text.delete(deleteStart, deleteEnd) } + } + + private fun initEmojiSearchPanel() { + val searchPanel = binding.emojiSearchPanel + + searchPanel.emojiSearchInput.doAfterTextChanged { editable -> + onEmojiSearchTextChanged(editable?.toString().orEmpty()) + } + + searchPanel.emojiSearchClear.setOnClickListener { + searchPanel.emojiSearchInput.setText("") + } + + searchPanel.emojiBackspaceButton.setOnClickListener { + deleteEmojiOrCharacterBeforeCursor() + } + } + + private fun onEmojiSearchTextChanged(query: String) { + val searchPanel = binding.emojiSearchPanel + searchPanel.emojiSearchClear.isVisible = query.isNotEmpty() + + emojiSearchJob?.cancel() + + if (query.isBlank()) { + binding.emojiPicker.isVisible = true + searchPanel.emojiSearchResultsScroll.isVisible = false + searchPanel.emojiSearchNoResults.isVisible = false + return + } + + emojiSearchJob = viewLifecycleOwner.lifecycleScope.launch { + delay(EMOJI_SEARCH_DEBOUNCE_MS) + val results = emojiKeywordProvider.search(query) + binding.emojiPicker.isVisible = false + populateEmojiSearchResults(results) + } + } + + private fun populateEmojiSearchResults(results: List) { + val searchPanel = binding.emojiSearchPanel + searchPanel.emojiSearchResultsFlexbox.removeAllViews() + + if (results.isEmpty()) { + searchPanel.emojiSearchResultsScroll.isVisible = false + searchPanel.emojiSearchNoResults.isVisible = true + return + } + + searchPanel.emojiSearchNoResults.isVisible = false + searchPanel.emojiSearchResultsScroll.isVisible = true + + val rippleBackground = TypedValue() + requireContext().theme.resolveAttribute( + android.R.attr.selectableItemBackgroundBorderless, + rippleBackground, + true + ) + val paddingPx = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + EMOJI_SEARCH_RESULT_PADDING_DP.toFloat(), + resources.displayMetrics + ).toInt() + + results.forEach { emoji -> + val emojiView = TextView(requireContext()).apply { + text = emoji + textSize = EMOJI_SEARCH_RESULT_TEXT_SIZE_SP + setPadding(paddingPx, paddingPx, paddingPx, paddingPx) + setBackgroundResource(rippleBackground.resourceId) + isClickable = true + isFocusable = true + setOnClickListener { + onEmojiSearchResultSelected(emoji) + } + } + searchPanel.emojiSearchResultsFlexbox.addView(emojiView) + } + } + private fun showKeyboard() { val editText = binding.fragmentMessageInputView.inputEditText editText.requestFocus() @@ -844,30 +983,30 @@ class MessageInputFragment : Fragment() { val inputEditText = binding.fragmentMessageInputView.inputEditText val emojiPicker = binding.emojiPicker - emojiPicker.setRecentEmojiProvider(MessageInputRecentEmojiProvider(requireContext())) + recentEmojiProvider = MessageInputRecentEmojiProvider(requireContext()) + emojiPicker.setRecentEmojiProvider(recentEmojiProvider) emojiPicker.setOnEmojiPickedListener { item -> - val start = inputEditText.selectionStart - val end = inputEditText.selectionEnd - inputEditText.editableText.replace(start, end, item.emoji) + insertEmoji(item.emoji) } viewThemeUtils.talk.themeEmojiPicker(emojiPicker) + initEmojiSearchPanel() updateSmileyButtonIcon() binding.fragmentMessageInputView.smileyButton.setOnClickListener { - if (emojiPicker.isVisible) { + if (isEmojiAreaVisible()) { showKeyboard() - emojiPicker.isVisible = false + hideEmojiKeyboardArea() } else { hideKeyboard() - emojiPicker.isVisible = true + showEmojiKeyboardArea() } updateSmileyButtonIcon() } inputEditText.setOnClickListener { - if (emojiPicker.isVisible) { - emojiPicker.isVisible = false + if (isEmojiAreaVisible()) { + hideEmojiKeyboardArea() updateSmileyButtonIcon() } } @@ -1280,5 +1419,8 @@ class MessageInputFragment : Fragment() { private const val FULLY_OPAQUE: Float = 1.0f private const val FULLY_TRANSPARENT: Float = 0.0f private const val OPACITY_DISABLED = 0.7f + private const val EMOJI_SEARCH_DEBOUNCE_MS = 150L + private const val EMOJI_SEARCH_RESULT_TEXT_SIZE_SP = 28f + private const val EMOJI_SEARCH_RESULT_PADDING_DP = 8 } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/EmojiKeywordProvider.kt b/app/src/main/java/com/nextcloud/talk/utils/EmojiKeywordProvider.kt new file mode 100644 index 00000000000..7061528e191 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/EmojiKeywordProvider.kt @@ -0,0 +1,69 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Marcel Hibbe + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.utils + +import android.content.Context +import android.util.Log +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.SerializationException +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import java.io.IOException + +@Serializable +data class EmojiKeywordEntry(val emoji: String, val name: String, val keywords: List) + +/** + * Looks up emoji by keyword against a dataset bundled in assets/emoji_keywords.json. + * The androidx emoji2-emojipicker library used for the chat emoji panel has no search + * API and its own emoji dataset is not accessible from app code, so this ships its own + * keyword list (derived from the Unicode CLDR emoji short names). + */ +class EmojiKeywordProvider(private val context: Context) { + + private var cachedEntries: List? = null + + suspend fun search(query: String, limit: Int = MAX_RESULTS): List { + val terms = query.trim().lowercase().split(WHITESPACE_REGEX).filter { it.isNotEmpty() } + if (terms.isEmpty()) { + return emptyList() + } + + val entries = getEntries() + return entries.asSequence() + .filter { entry -> terms.all { term -> entry.keywords.any { it.startsWith(term) } } } + .map { it.emoji } + .take(limit) + .toList() + } + + private suspend fun getEntries(): List = + cachedEntries ?: withContext(Dispatchers.IO) { + cachedEntries ?: loadEntries().also { cachedEntries = it } + } + + private fun loadEntries(): List = + try { + val json = context.assets.open(ASSET_FILE_NAME).bufferedReader(Charsets.UTF_8).use { it.readText() } + Json.decodeFromString>(json) + } catch (e: IOException) { + Log.e(TAG, "Failed to read emoji keyword dataset", e) + emptyList() + } catch (e: SerializationException) { + Log.e(TAG, "Failed to parse emoji keyword dataset", e) + emptyList() + } + + companion object { + private const val TAG = "EmojiKeywordProvider" + private const val ASSET_FILE_NAME = "emoji_keywords.json" + private const val MAX_RESULTS = 100 + private val WHITESPACE_REGEX = Regex("\\s+") + } +} diff --git a/app/src/main/res/drawable/ic_baseline_backspace_24.xml b/app/src/main/res/drawable/ic_baseline_backspace_24.xml new file mode 100644 index 00000000000..1b62d0e233e --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_backspace_24.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/emoji_search_panel.xml b/app/src/main/res/layout/emoji_search_panel.xml new file mode 100644 index 00000000000..d0d0875c1f9 --- /dev/null +++ b/app/src/main/res/layout/emoji_search_panel.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_message_input.xml b/app/src/main/res/layout/fragment_message_input.xml index aec5fc67534..c09afdde985 100644 --- a/app/src/main/res/layout/fragment_message_input.xml +++ b/app/src/main/res/layout/fragment_message_input.xml @@ -82,6 +82,12 @@ android:visibility="gone" tools:visibility="visible" /> + + Conversation name Create conversation Add emojis + Search emoji + Clear search + Delete last emoji + No emoji found Select authentication certificate Change authentication certificate From 11337a11092088a4c9768c4b458eb6b761ffb274 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 3 Sep 2026 16:03:23 +0200 Subject: [PATCH 2/6] refactor(emoji): move emoji picker into its own package with configurable search/backspace Consolidates all emoji-picker code (keyword search, category-tab theming, recent-emoji persistence) under com.nextcloud.talk.emojipicker and wraps the androidx EmojiPickerView plus the search/backspace UI in a single EmojiPickerPanel view. Search and backspace are now toggleable per call site via searchEnabled/backspaceEnabled and wired through callbacks (onEmojiPicked/onBackspaceClicked), so the panel has no knowledge of how a pick or backspace is applied by the host. Search is now available everywhere the picker is used - message input, message reactions, status message, and avatar emoji picker - not just the chat message input. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: Marcel Hibbe --- .../talk/chat/MessageInputFragment.kt | 151 ++-------------- .../talk/chat/ui/MessageActionsBottomSheet.kt | 65 +++---- .../chooseaccount/ui/StatusMessageSheet.kt | 23 ++- .../talk/components/EmojiColorPickers.kt | 17 +- .../EmojiKeywordProvider.kt | 8 +- .../talk/emojipicker/EmojiPickerPanel.kt | 164 ++++++++++++++++++ .../EmojiPickerTheming.kt} | 2 +- .../SharedPreferencesRecentEmojiProvider.kt | 38 ++++ .../ui/theme/TalkSpecificViewThemeUtils.kt | 2 + .../main/res/layout/emoji_picker_panel.xml | 100 +++++++++++ .../main/res/layout/emoji_search_panel.xml | 89 ---------- .../res/layout/fragment_message_input.xml | 15 +- 12 files changed, 374 insertions(+), 300 deletions(-) rename app/src/main/java/com/nextcloud/talk/{utils => emojipicker}/EmojiKeywordProvider.kt (88%) create mode 100644 app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt rename app/src/main/java/com/nextcloud/talk/{ui/theme/EmojiPickerCategoryTabs.kt => emojipicker/EmojiPickerTheming.kt} (99%) create mode 100644 app/src/main/java/com/nextcloud/talk/emojipicker/SharedPreferencesRecentEmojiProvider.kt create mode 100644 app/src/main/res/layout/emoji_picker_panel.xml delete mode 100644 app/src/main/res/layout/emoji_search_panel.xml diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index 74ebfbdcc69..278768e6207 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -38,14 +38,12 @@ import android.widget.LinearLayout import android.widget.PopupMenu import android.widget.RelativeLayout import android.widget.SeekBar -import android.widget.TextView import androidx.appcompat.view.ContextThemeWrapper import androidx.compose.material3.MaterialTheme import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toDrawable import androidx.core.view.isVisible import androidx.core.widget.doAfterTextChanged -import androidx.emoji2.emojipicker.RecentEmojiProvider import androidx.emoji2.widget.EmojiTextView import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -67,6 +65,7 @@ import com.nextcloud.talk.chat.viewmodels.ChatViewModel import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel import com.nextcloud.talk.data.network.NetworkMonitor import com.nextcloud.talk.databinding.FragmentMessageInputBinding +import com.nextcloud.talk.emojipicker.SharedPreferencesRecentEmojiProvider import com.nextcloud.talk.jobs.UploadAndShareFilesWorker import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.chat.ChatUtils @@ -83,7 +82,6 @@ import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.CharPolicy import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DateUtils -import com.nextcloud.talk.utils.EmojiKeywordProvider import com.nextcloud.talk.utils.EmojiTextInputEditText import com.nextcloud.talk.utils.ImageEmojiEditText import com.nextcloud.talk.utils.SpreedFeatures @@ -92,8 +90,6 @@ import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.text.Spans import com.otaliastudios.autocomplete.Autocomplete import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -133,9 +129,7 @@ class MessageInputFragment : Fragment() { private var hasScheduledMessages = false private lateinit var spreedCapabilities: SpreedCapability private var hasSharedText = false - private val emojiKeywordProvider: EmojiKeywordProvider by lazy { EmojiKeywordProvider(requireContext()) } - private lateinit var recentEmojiProvider: MessageInputRecentEmojiProvider - private var emojiSearchJob: Job? = null + private lateinit var recentEmojiProvider: SharedPreferencesRecentEmojiProvider override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -832,22 +826,15 @@ class MessageInputFragment : Fragment() { binding.fragmentMessageInputView.smileyButton.setImageDrawable(drawable) } - private fun isEmojiAreaVisible(): Boolean = binding.emojiSearchPanel.emojiSearchPanel.isVisible + private fun isEmojiAreaVisible(): Boolean = binding.emojiPickerPanel.isVisible private fun showEmojiKeyboardArea() { - binding.emojiSearchPanel.emojiSearchPanel.isVisible = true - binding.emojiSearchPanel.emojiSearchInput.setText("") - binding.emojiPicker.isVisible = true - binding.emojiSearchPanel.emojiSearchResultsScroll.isVisible = false - binding.emojiSearchPanel.emojiSearchNoResults.isVisible = false + binding.emojiPickerPanel.isVisible = true + binding.emojiPickerPanel.reset() } private fun hideEmojiKeyboardArea() { - emojiSearchJob?.cancel() - binding.emojiSearchPanel.emojiSearchPanel.isVisible = false - binding.emojiPicker.isVisible = false - binding.emojiSearchPanel.emojiSearchResultsScroll.isVisible = false - binding.emojiSearchPanel.emojiSearchNoResults.isVisible = false + binding.emojiPickerPanel.isVisible = false } private fun insertEmoji(emoji: String) { @@ -857,11 +844,6 @@ class MessageInputFragment : Fragment() { inputEditText.editableText.replace(start, end, emoji) } - private fun onEmojiSearchResultSelected(emoji: String) { - insertEmoji(emoji) - recentEmojiProvider.recordSelection(emoji) - } - private fun deleteEmojiOrCharacterBeforeCursor() { val inputEditText = binding.fragmentMessageInputView.inputEditText val text = inputEditText.text ?: return @@ -885,84 +867,6 @@ class MessageInputFragment : Fragment() { rangeToDelete()?.let { (deleteStart, deleteEnd) -> text.delete(deleteStart, deleteEnd) } } - private fun initEmojiSearchPanel() { - val searchPanel = binding.emojiSearchPanel - - searchPanel.emojiSearchInput.doAfterTextChanged { editable -> - onEmojiSearchTextChanged(editable?.toString().orEmpty()) - } - - searchPanel.emojiSearchClear.setOnClickListener { - searchPanel.emojiSearchInput.setText("") - } - - searchPanel.emojiBackspaceButton.setOnClickListener { - deleteEmojiOrCharacterBeforeCursor() - } - } - - private fun onEmojiSearchTextChanged(query: String) { - val searchPanel = binding.emojiSearchPanel - searchPanel.emojiSearchClear.isVisible = query.isNotEmpty() - - emojiSearchJob?.cancel() - - if (query.isBlank()) { - binding.emojiPicker.isVisible = true - searchPanel.emojiSearchResultsScroll.isVisible = false - searchPanel.emojiSearchNoResults.isVisible = false - return - } - - emojiSearchJob = viewLifecycleOwner.lifecycleScope.launch { - delay(EMOJI_SEARCH_DEBOUNCE_MS) - val results = emojiKeywordProvider.search(query) - binding.emojiPicker.isVisible = false - populateEmojiSearchResults(results) - } - } - - private fun populateEmojiSearchResults(results: List) { - val searchPanel = binding.emojiSearchPanel - searchPanel.emojiSearchResultsFlexbox.removeAllViews() - - if (results.isEmpty()) { - searchPanel.emojiSearchResultsScroll.isVisible = false - searchPanel.emojiSearchNoResults.isVisible = true - return - } - - searchPanel.emojiSearchNoResults.isVisible = false - searchPanel.emojiSearchResultsScroll.isVisible = true - - val rippleBackground = TypedValue() - requireContext().theme.resolveAttribute( - android.R.attr.selectableItemBackgroundBorderless, - rippleBackground, - true - ) - val paddingPx = TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - EMOJI_SEARCH_RESULT_PADDING_DP.toFloat(), - resources.displayMetrics - ).toInt() - - results.forEach { emoji -> - val emojiView = TextView(requireContext()).apply { - text = emoji - textSize = EMOJI_SEARCH_RESULT_TEXT_SIZE_SP - setPadding(paddingPx, paddingPx, paddingPx, paddingPx) - setBackgroundResource(rippleBackground.resourceId) - isClickable = true - isFocusable = true - setOnClickListener { - onEmojiSearchResultSelected(emoji) - } - } - searchPanel.emojiSearchResultsFlexbox.addView(emojiView) - } - } - private fun showKeyboard() { val editText = binding.fragmentMessageInputView.inputEditText editText.requestFocus() @@ -981,16 +885,16 @@ class MessageInputFragment : Fragment() { private fun initSmileyKeyboardToggler() { val inputEditText = binding.fragmentMessageInputView.inputEditText - val emojiPicker = binding.emojiPicker + val emojiPickerPanel = binding.emojiPickerPanel - recentEmojiProvider = MessageInputRecentEmojiProvider(requireContext()) - emojiPicker.setRecentEmojiProvider(recentEmojiProvider) - emojiPicker.setOnEmojiPickedListener { item -> - insertEmoji(item.emoji) - } + recentEmojiProvider = SharedPreferencesRecentEmojiProvider(requireContext(), RECENT_EMOJIS_PREFS) + emojiPickerPanel.searchEnabled = true + emojiPickerPanel.backspaceEnabled = true + emojiPickerPanel.setRecentEmojiProvider(recentEmojiProvider) + emojiPickerPanel.onEmojiPicked = { emoji -> insertEmoji(emoji) } + emojiPickerPanel.onBackspaceClicked = { deleteEmojiOrCharacterBeforeCursor() } - viewThemeUtils.talk.themeEmojiPicker(emojiPicker) - initEmojiSearchPanel() + viewThemeUtils.talk.themeEmojiPicker(emojiPickerPanel.emojiPickerView) updateSmileyButtonIcon() binding.fragmentMessageInputView.smileyButton.setOnClickListener { @@ -1012,29 +916,6 @@ class MessageInputFragment : Fragment() { } } - private class MessageInputRecentEmojiProvider(context: Context) : RecentEmojiProvider { - private val prefs = context.getSharedPreferences("recent_emojis", Context.MODE_PRIVATE) - - override fun recordSelection(emoji: String) { - val updated = listOf(emoji) + getStoredList().filterNot { it == emoji } - prefs.edit() - .putString("recent", updated.take(MAX_STORED_RECENT_EMOJIS).joinToString(",")) - .apply() - } - - override suspend fun getRecentEmojiList(): List = getStoredList() - - private fun getStoredList(): List = - prefs.getString("recent", null) - ?.split(",") - ?.filter { it.isNotBlank() } - ?: emptyList() - - companion object { - private const val MAX_STORED_RECENT_EMOJIS = 20 - } - } - private fun replyToMessage(quotedMessageText: String?, quotedActorDisplayName: String?, quotedImageUrl: String?) { Log.d(TAG, "Reply") val view = binding.fragmentMessageInputView @@ -1419,8 +1300,6 @@ class MessageInputFragment : Fragment() { private const val FULLY_OPAQUE: Float = 1.0f private const val FULLY_TRANSPARENT: Float = 0.0f private const val OPACITY_DISABLED = 0.7f - private const val EMOJI_SEARCH_DEBOUNCE_MS = 150L - private const val EMOJI_SEARCH_RESULT_TEXT_SIZE_SP = 28f - private const val EMOJI_SEARCH_RESULT_PADDING_DP = 8 + private const val RECENT_EMOJIS_PREFS = "recent_emojis" } } diff --git a/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt index c28bb2cf29c..3bfe6ad889c 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt @@ -7,7 +7,6 @@ package com.nextcloud.talk.chat.ui -import android.content.Context import android.content.res.Configuration import android.view.ContextThemeWrapper import androidx.activity.compose.BackHandler @@ -61,20 +60,19 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.util.Consumer -import androidx.emoji2.emojipicker.EmojiPickerView import androidx.emoji2.emojipicker.RecentEmojiProvider import com.nextcloud.talk.R import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.emojipicker.EmojiPickerPanel +import com.nextcloud.talk.emojipicker.SharedPreferencesRecentEmojiProvider +import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture +import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.conversations.ConversationEnums -import com.nextcloud.talk.ui.theme.protectEmojiPickerScrollGesture -import com.nextcloud.talk.ui.theme.themeEmojiPickerCategoryTabs import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability import com.nextcloud.talk.utils.ConversationUtils @@ -90,30 +88,8 @@ private const val AGE_THRESHOLD_FOR_DELETE_MESSAGE = 21600000L private const val MAX_RECENTS = 8 private const val ACTOR_BOTS = "bots" private const val RECENT_REACTIONS_PREFS = "recent_reaction_emojis" -private const val RECENT_REACTIONS_KEY = "recent" -private const val MAX_STORED_RECENT_REACTIONS = 20 private val defaultReactionEmojis = listOf("๐Ÿ‘", "๐Ÿ‘Ž", "โค๏ธ", "๐Ÿ˜‚", "๐Ÿ˜•", "๐Ÿ˜ข", "๐Ÿ™", "๐Ÿ”ฅ") -private val emojiPickerHeight = 360.dp - -private class ReactionRecentEmojiProvider(context: Context) : RecentEmojiProvider { - private val prefs = context.getSharedPreferences(RECENT_REACTIONS_PREFS, Context.MODE_PRIVATE) - - override fun recordSelection(emoji: String) { - val updated = listOf(emoji) + getStoredList().filterNot { it == emoji } - prefs.edit() - .putString(RECENT_REACTIONS_KEY, updated.take(MAX_STORED_RECENT_REACTIONS).joinToString(",")) - .apply() - } - - override suspend fun getRecentEmojiList(): List = getStoredList() - - private fun getStoredList(): List = - prefs.getString(RECENT_REACTIONS_KEY, null) - ?.split(",") - ?.filter { it.isNotBlank() } - ?: emptyList() -} data class MessageActionsState( val showEmojiBar: Boolean, @@ -300,7 +276,9 @@ fun MessageActionsBottomSheet( onDismiss: () -> Unit ) { val context = LocalContext.current - val recentEmojiProvider = remember(context) { ReactionRecentEmojiProvider(context) } + val recentEmojiProvider = remember(context) { + SharedPreferencesRecentEmojiProvider(context, RECENT_REACTIONS_PREFS) + } var showEmojiPicker by rememberSaveable { mutableStateOf(false) } val scope = rememberCoroutineScope() @@ -705,16 +683,16 @@ private fun EmojiPickerSheetContent( Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.back_button)) } AndroidView( - modifier = Modifier - .fillMaxWidth() - .height(emojiPickerHeight), + modifier = Modifier.fillMaxWidth(), factory = { ctx -> - EmojiPickerView(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { + EmojiPickerPanel(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { setBackgroundColor(backgroundColor.toArgb()) + searchEnabled = true + backspaceEnabled = false setRecentEmojiProvider(recentEmojiProvider) - setOnEmojiPickedListener(Consumer { item -> onEmojiSelected(item.emoji) }) - themeEmojiPickerCategoryTabs(this, selectedTabColor, unselectedTabColor) - protectEmojiPickerScrollGesture(this) + onEmojiPicked = onEmojiSelected + themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) + protectEmojiPickerScrollGesture(emojiPickerView) } } ) @@ -809,7 +787,10 @@ private fun PreviewEmojiBar() { Surface(color = MaterialTheme.colorScheme.surfaceContainerLow) { EmojiBar( selfReactions = setOf("๐Ÿ‘", "โค๏ธ"), - recentEmojiProvider = ReactionRecentEmojiProvider(LocalContext.current), + recentEmojiProvider = SharedPreferencesRecentEmojiProvider( + LocalContext.current, + RECENT_REACTIONS_PREFS + ), onEmojiClick = {}, onMoreEmojiClick = {} ) @@ -851,7 +832,10 @@ private fun PreviewMessageActionsSheetContent() { Surface(color = MaterialTheme.colorScheme.surfaceContainerLow) { MessageActionsSheetContent( actionsState = previewState, - recentEmojiProvider = ReactionRecentEmojiProvider(LocalContext.current), + recentEmojiProvider = SharedPreferencesRecentEmojiProvider( + LocalContext.current, + RECENT_REACTIONS_PREFS + ), onEmojiClick = {}, onMoreEmojiClick = {}, onReply = {}, @@ -907,7 +891,10 @@ private fun PreviewMessageActionsSheetPinned() { showOpenInFiles = false, showDelete = false ), - recentEmojiProvider = ReactionRecentEmojiProvider(LocalContext.current), + recentEmojiProvider = SharedPreferencesRecentEmojiProvider( + LocalContext.current, + RECENT_REACTIONS_PREFS + ), onEmojiClick = {}, onMoreEmojiClick = {}, onReply = {}, diff --git a/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt b/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt index e7d4b785854..658cbcaff49 100644 --- a/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt +++ b/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt @@ -41,16 +41,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.util.Consumer -import androidx.emoji2.emojipicker.EmojiPickerView import com.nextcloud.talk.R import com.nextcloud.talk.chooseaccount.viewmodel.StatusMessageViewModel +import com.nextcloud.talk.emojipicker.EmojiPickerPanel +import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture +import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs import com.nextcloud.talk.models.json.status.Status import com.nextcloud.talk.models.json.status.predefined.PredefinedStatus -import com.nextcloud.talk.ui.theme.protectEmojiPickerScrollGesture -import com.nextcloud.talk.ui.theme.themeEmojiPickerCategoryTabs - -private val emojiPickerHeight = 360.dp @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -107,15 +104,15 @@ private fun EmojiPickerSheetContent(onEmojiSelected: (String) -> Unit, onBack: ( Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.back_button)) } AndroidView( - modifier = Modifier - .fillMaxWidth() - .height(emojiPickerHeight), + modifier = Modifier.fillMaxWidth(), factory = { ctx -> - EmojiPickerView(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { + EmojiPickerPanel(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { setBackgroundColor(backgroundColor.toArgb()) - setOnEmojiPickedListener(Consumer { item -> onEmojiSelected(item.emoji) }) - themeEmojiPickerCategoryTabs(this, selectedTabColor, unselectedTabColor) - protectEmojiPickerScrollGesture(this) + searchEnabled = true + backspaceEnabled = false + onEmojiPicked = onEmojiSelected + themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) + protectEmojiPickerScrollGesture(emojiPickerView) } } ) diff --git a/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt b/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt index da3ba95cd7c..2a70fdca901 100644 --- a/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt +++ b/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt @@ -69,11 +69,10 @@ import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.util.Consumer -import androidx.emoji2.emojipicker.EmojiPickerView import com.nextcloud.talk.R -import com.nextcloud.talk.ui.theme.protectEmojiPickerScrollGesture -import com.nextcloud.talk.ui.theme.themeEmojiPickerCategoryTabs +import com.nextcloud.talk.emojipicker.EmojiPickerPanel +import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture +import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs import com.nextcloud.talk.utils.ColorGenerator import kotlin.math.roundToInt @@ -346,11 +345,13 @@ private fun EmojiGrid(onEmojiSelected: (String) -> Unit, modifier: Modifier = Mo AndroidView( modifier = modifier.fillMaxWidth(), factory = { ctx -> - EmojiPickerView(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { + EmojiPickerPanel(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { setBackgroundColor(backgroundColor.toArgb()) - setOnEmojiPickedListener(Consumer { item -> onEmojiSelected(item.emoji) }) - themeEmojiPickerCategoryTabs(this, selectedTabColor, unselectedTabColor) - protectEmojiPickerScrollGesture(this) + searchEnabled = true + backspaceEnabled = false + onEmojiPicked = onEmojiSelected + themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) + protectEmojiPickerScrollGesture(emojiPickerView) } } ) diff --git a/app/src/main/java/com/nextcloud/talk/utils/EmojiKeywordProvider.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiKeywordProvider.kt similarity index 88% rename from app/src/main/java/com/nextcloud/talk/utils/EmojiKeywordProvider.kt rename to app/src/main/java/com/nextcloud/talk/emojipicker/EmojiKeywordProvider.kt index 7061528e191..e9264911f7f 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/EmojiKeywordProvider.kt +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiKeywordProvider.kt @@ -4,7 +4,7 @@ * SPDX-FileCopyrightText: 2026 Marcel Hibbe * SPDX-License-Identifier: GPL-3.0-or-later */ -package com.nextcloud.talk.utils +package com.nextcloud.talk.emojipicker import android.content.Context import android.util.Log @@ -21,9 +21,9 @@ data class EmojiKeywordEntry(val emoji: String, val name: String, val keywords: /** * Looks up emoji by keyword against a dataset bundled in assets/emoji_keywords.json. - * The androidx emoji2-emojipicker library used for the chat emoji panel has no search - * API and its own emoji dataset is not accessible from app code, so this ships its own - * keyword list (derived from the Unicode CLDR emoji short names). + * The androidx emoji2-emojipicker library used for the emoji pickers throughout the app + * has no search API and its own emoji dataset is not accessible from app code, so this + * ships its own keyword list (derived from the Unicode CLDR emoji short names). */ class EmojiKeywordProvider(private val context: Context) { diff --git a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt new file mode 100644 index 00000000000..dc0d5b65ae3 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt @@ -0,0 +1,164 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.emojipicker + +import android.content.Context +import android.util.AttributeSet +import android.util.TypedValue +import android.view.LayoutInflater +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.core.widget.doAfterTextChanged +import androidx.emoji2.emojipicker.EmojiPickerView +import androidx.emoji2.emojipicker.RecentEmojiProvider +import com.nextcloud.talk.databinding.EmojiPickerPanelBinding +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +/** + * Self-contained emoji picker: the bundled androidx EmojiPickerView grid, plus an optional + * keyword search field (backed by [EmojiKeywordProvider]) and an optional backspace button, + * so every screen that embeds an emoji picker can opt into the same search/backspace behavior + * instead of reimplementing it. [searchEnabled] and [backspaceEnabled] control which of those + * are shown, and [onEmojiPicked]/[onBackspaceClicked] are how the host reacts to them - this + * view has no knowledge of where the emoji or the backspace action actually get applied. + */ +class EmojiPickerPanel @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : LinearLayout(context, attrs) { + + private val binding = EmojiPickerPanelBinding.inflate(LayoutInflater.from(context), this) + private val emojiKeywordProvider by lazy { EmojiKeywordProvider(context) } + private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) + private var searchJob: Job? = null + private var recentEmojiProvider: RecentEmojiProvider? = null + + var searchEnabled: Boolean = true + set(value) { + field = value + binding.emojiSearchFieldGroup.isVisible = value + updateSearchRowVisibility() + } + + var backspaceEnabled: Boolean = false + set(value) { + field = value + binding.emojiBackspaceButton.isVisible = value + updateSearchRowVisibility() + } + + var onEmojiPicked: ((String) -> Unit)? = null + var onBackspaceClicked: (() -> Unit)? = null + + val emojiPickerView: EmojiPickerView get() = binding.emojiPicker + + init { + orientation = VERTICAL + binding.emojiSearchFieldGroup.isVisible = searchEnabled + binding.emojiBackspaceButton.isVisible = backspaceEnabled + updateSearchRowVisibility() + + binding.emojiPicker.setOnEmojiPickedListener { item -> onEmojiPicked?.invoke(item.emoji) } + binding.emojiSearchInput.doAfterTextChanged { editable -> onSearchTextChanged(editable?.toString().orEmpty()) } + binding.emojiSearchClear.setOnClickListener { binding.emojiSearchInput.setText("") } + binding.emojiBackspaceButton.setOnClickListener { onBackspaceClicked?.invoke() } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + coroutineScope.cancel() + } + + fun setRecentEmojiProvider(provider: RecentEmojiProvider) { + recentEmojiProvider = provider + binding.emojiPicker.setRecentEmojiProvider(provider) + } + + /** Clears any search query and returns to showing the emoji grid. */ + fun reset() { + searchJob?.cancel() + binding.emojiSearchInput.setText("") + showGrid() + } + + private fun updateSearchRowVisibility() { + binding.emojiSearchRow.isVisible = searchEnabled || backspaceEnabled + } + + private fun onSearchTextChanged(query: String) { + binding.emojiSearchClear.isVisible = query.isNotEmpty() + searchJob?.cancel() + + if (query.isBlank()) { + showGrid() + return + } + + searchJob = coroutineScope.launch { + delay(SEARCH_DEBOUNCE_MS) + val results = emojiKeywordProvider.search(query) + binding.emojiPicker.isVisible = false + populateSearchResults(results) + } + } + + private fun showGrid() { + binding.emojiPicker.isVisible = true + binding.emojiSearchResultsScroll.isVisible = false + binding.emojiSearchNoResults.isVisible = false + } + + private fun populateSearchResults(results: List) { + binding.emojiSearchResultsFlexbox.removeAllViews() + + if (results.isEmpty()) { + binding.emojiSearchResultsScroll.isVisible = false + binding.emojiSearchNoResults.isVisible = true + return + } + + binding.emojiSearchNoResults.isVisible = false + binding.emojiSearchResultsScroll.isVisible = true + + val rippleBackground = TypedValue() + context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, rippleBackground, true) + val paddingPx = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + RESULT_PADDING_DP.toFloat(), + resources.displayMetrics + ).toInt() + + results.forEach { emoji -> + val emojiView = TextView(context).apply { + text = emoji + textSize = RESULT_TEXT_SIZE_SP + setPadding(paddingPx, paddingPx, paddingPx, paddingPx) + setBackgroundResource(rippleBackground.resourceId) + isClickable = true + isFocusable = true + setOnClickListener { + recentEmojiProvider?.recordSelection(emoji) + onEmojiPicked?.invoke(emoji) + } + } + binding.emojiSearchResultsFlexbox.addView(emojiView) + } + } + + companion object { + private const val SEARCH_DEBOUNCE_MS = 150L + private const val RESULT_TEXT_SIZE_SP = 28f + private const val RESULT_PADDING_DP = 8 + } +} diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/EmojiPickerCategoryTabs.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerTheming.kt similarity index 99% rename from app/src/main/java/com/nextcloud/talk/ui/theme/EmojiPickerCategoryTabs.kt rename to app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerTheming.kt index 1c2d3804fbb..f5a5df440e1 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/EmojiPickerCategoryTabs.kt +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerTheming.kt @@ -4,7 +4,7 @@ * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ -package com.nextcloud.talk.ui.theme +package com.nextcloud.talk.emojipicker import android.content.res.ColorStateList import android.view.MotionEvent diff --git a/app/src/main/java/com/nextcloud/talk/emojipicker/SharedPreferencesRecentEmojiProvider.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/SharedPreferencesRecentEmojiProvider.kt new file mode 100644 index 00000000000..69700ac7204 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/SharedPreferencesRecentEmojiProvider.kt @@ -0,0 +1,38 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.emojipicker + +import android.content.Context +import androidx.emoji2.emojipicker.RecentEmojiProvider + +class SharedPreferencesRecentEmojiProvider( + context: Context, + prefsName: String, + private val maxStored: Int = MAX_STORED_RECENT_EMOJIS +) : RecentEmojiProvider { + private val prefs = context.getSharedPreferences(prefsName, Context.MODE_PRIVATE) + + override fun recordSelection(emoji: String) { + val updated = listOf(emoji) + getStoredList().filterNot { it == emoji } + prefs.edit() + .putString(KEY_RECENT, updated.take(maxStored).joinToString(",")) + .apply() + } + + override suspend fun getRecentEmojiList(): List = getStoredList() + + private fun getStoredList(): List = + prefs.getString(KEY_RECENT, null) + ?.split(",") + ?.filter { it.isNotBlank() } + ?: emptyList() + + companion object { + private const val KEY_RECENT = "recent" + private const val MAX_STORED_RECENT_EMOJIS = 20 + } +} diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt index edcda2624f8..bf6ddb66096 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt @@ -47,6 +47,8 @@ import com.nextcloud.android.common.ui.util.buildColorStateList import com.nextcloud.talk.R import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding +import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture +import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs import com.nextcloud.talk.ui.MicInputCloud import com.nextcloud.talk.ui.StatusDrawable import com.nextcloud.talk.ui.WaveformSeekBar diff --git a/app/src/main/res/layout/emoji_picker_panel.xml b/app/src/main/res/layout/emoji_picker_panel.xml new file mode 100644 index 00000000000..2e4c5ca8983 --- /dev/null +++ b/app/src/main/res/layout/emoji_picker_panel.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/emoji_search_panel.xml b/app/src/main/res/layout/emoji_search_panel.xml deleted file mode 100644 index d0d0875c1f9..00000000000 --- a/app/src/main/res/layout/emoji_search_panel.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_message_input.xml b/app/src/main/res/layout/fragment_message_input.xml index c09afdde985..4700e46fb5b 100644 --- a/app/src/main/res/layout/fragment_message_input.xml +++ b/app/src/main/res/layout/fragment_message_input.xml @@ -82,17 +82,12 @@ android:visibility="gone" tools:visibility="visible" /> - - - + android:layout_height="wrap_content" + android:visibility="gone" + tools:visibility="visible" /> From 489a3c5700f6b4637849169f61513b642e460c69 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 3 Sep 2026 16:09:53 +0200 Subject: [PATCH 3/6] fix(emoji): theme the emoji search field's hint and text color EmojiPickerPanel's search EditText was left at its static default colors, so the "Search emoji" hint didn't follow the app's dynamic per-server branding the way the rest of the picker already does. EmojiPickerPanel.applyTheme() now sets hint/text colors alongside the existing background/tab/scroll-gesture theming, and every call site (chat input, reactions, status message, avatar picker) routes through it instead of theming pieces individually. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: Marcel Hibbe --- .../talk/chat/MessageInputFragment.kt | 2 +- .../talk/chat/ui/MessageActionsBottomSheet.kt | 10 ++++----- .../chooseaccount/ui/StatusMessageSheet.kt | 10 ++++----- .../talk/components/EmojiColorPickers.kt | 10 ++++----- .../talk/emojipicker/EmojiPickerPanel.kt | 21 +++++++++++++++++++ .../ui/theme/TalkSpecificViewThemeUtils.kt | 20 ++++++++---------- 6 files changed, 43 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index 278768e6207..c8a5f89910c 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -894,7 +894,7 @@ class MessageInputFragment : Fragment() { emojiPickerPanel.onEmojiPicked = { emoji -> insertEmoji(emoji) } emojiPickerPanel.onBackspaceClicked = { deleteEmojiOrCharacterBeforeCursor() } - viewThemeUtils.talk.themeEmojiPicker(emojiPickerPanel.emojiPickerView) + viewThemeUtils.talk.themeEmojiPicker(emojiPickerPanel) updateSmileyButtonIcon() binding.fragmentMessageInputView.smileyButton.setOnClickListener { diff --git a/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt index 3bfe6ad889c..5c3bcd942fb 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ui/MessageActionsBottomSheet.kt @@ -68,8 +68,6 @@ import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.emojipicker.EmojiPickerPanel import com.nextcloud.talk.emojipicker.SharedPreferencesRecentEmojiProvider -import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture -import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.conversations.ConversationEnums @@ -670,9 +668,11 @@ private fun EmojiPickerSheetContent( onEmojiSelected: (String) -> Unit, onBack: () -> Unit ) { - val backgroundColor = MaterialTheme.colorScheme.surfaceContainerLow + val backgroundColor = MaterialTheme.colorScheme.surfaceContainerLow.toArgb() val selectedTabColor = MaterialTheme.colorScheme.primary.toArgb() val unselectedTabColor = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() + val hintTextColor = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() + val textColor = MaterialTheme.colorScheme.onSurface.toArgb() Column( modifier = Modifier @@ -686,13 +686,11 @@ private fun EmojiPickerSheetContent( modifier = Modifier.fillMaxWidth(), factory = { ctx -> EmojiPickerPanel(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { - setBackgroundColor(backgroundColor.toArgb()) searchEnabled = true backspaceEnabled = false setRecentEmojiProvider(recentEmojiProvider) onEmojiPicked = onEmojiSelected - themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) - protectEmojiPickerScrollGesture(emojiPickerView) + applyTheme(backgroundColor, selectedTabColor, unselectedTabColor, hintTextColor, textColor) } } ) diff --git a/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt b/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt index 658cbcaff49..2d794237a8d 100644 --- a/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt +++ b/app/src/main/java/com/nextcloud/talk/chooseaccount/ui/StatusMessageSheet.kt @@ -44,8 +44,6 @@ import androidx.compose.ui.viewinterop.AndroidView import com.nextcloud.talk.R import com.nextcloud.talk.chooseaccount.viewmodel.StatusMessageViewModel import com.nextcloud.talk.emojipicker.EmojiPickerPanel -import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture -import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs import com.nextcloud.talk.models.json.status.Status import com.nextcloud.talk.models.json.status.predefined.PredefinedStatus @@ -91,9 +89,11 @@ fun StatusMessageModalBottomSheet(currentStatus: Status, viewModel: StatusMessag @Composable private fun EmojiPickerSheetContent(onEmojiSelected: (String) -> Unit, onBack: () -> Unit) { - val backgroundColor = MaterialTheme.colorScheme.surfaceContainerLow + val backgroundColor = MaterialTheme.colorScheme.surfaceContainerLow.toArgb() val selectedTabColor = MaterialTheme.colorScheme.primary.toArgb() val unselectedTabColor = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() + val hintTextColor = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() + val textColor = MaterialTheme.colorScheme.onSurface.toArgb() Column( modifier = Modifier @@ -107,12 +107,10 @@ private fun EmojiPickerSheetContent(onEmojiSelected: (String) -> Unit, onBack: ( modifier = Modifier.fillMaxWidth(), factory = { ctx -> EmojiPickerPanel(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { - setBackgroundColor(backgroundColor.toArgb()) searchEnabled = true backspaceEnabled = false onEmojiPicked = onEmojiSelected - themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) - protectEmojiPickerScrollGesture(emojiPickerView) + applyTheme(backgroundColor, selectedTabColor, unselectedTabColor, hintTextColor, textColor) } } ) diff --git a/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt b/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt index 2a70fdca901..00b7a729990 100644 --- a/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt +++ b/app/src/main/java/com/nextcloud/talk/components/EmojiColorPickers.kt @@ -71,8 +71,6 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView import com.nextcloud.talk.R import com.nextcloud.talk.emojipicker.EmojiPickerPanel -import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture -import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs import com.nextcloud.talk.utils.ColorGenerator import kotlin.math.roundToInt @@ -338,20 +336,20 @@ private fun CustomColorSwatch(onClick: () -> Unit) { @Composable private fun EmojiGrid(onEmojiSelected: (String) -> Unit, modifier: Modifier = Modifier) { - val backgroundColor = MaterialTheme.colorScheme.surfaceContainerLow + val backgroundColor = MaterialTheme.colorScheme.surfaceContainerLow.toArgb() val selectedTabColor = MaterialTheme.colorScheme.primary.toArgb() val unselectedTabColor = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() + val hintTextColor = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() + val textColor = MaterialTheme.colorScheme.onSurface.toArgb() AndroidView( modifier = modifier.fillMaxWidth(), factory = { ctx -> EmojiPickerPanel(ContextThemeWrapper(ctx, R.style.ThemeOverlay_App_EmojiPicker)).apply { - setBackgroundColor(backgroundColor.toArgb()) searchEnabled = true backspaceEnabled = false onEmojiPicked = onEmojiSelected - themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) - protectEmojiPickerScrollGesture(emojiPickerView) + applyTheme(backgroundColor, selectedTabColor, unselectedTabColor, hintTextColor, textColor) } } ) diff --git a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt index dc0d5b65ae3..b4e85d97400 100644 --- a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt @@ -92,6 +92,27 @@ class EmojiPickerPanel @JvmOverloads constructor( showGrid() } + /** + * Applies the host's dynamic per-server branding to every themeable part of the panel: + * the picker's background and selected-category tab (see [themeEmojiPickerCategoryTabs]), + * its scroll-gesture fix (see [protectEmojiPickerScrollGesture]), and the search field's + * hint/text colors, which otherwise fall back to the static app theme instead of following + * that branding. + */ + fun applyTheme( + backgroundColor: Int, + selectedTabColor: Int, + unselectedTabColor: Int, + hintTextColor: Int, + textColor: Int + ) { + setBackgroundColor(backgroundColor) + binding.emojiSearchInput.setHintTextColor(hintTextColor) + binding.emojiSearchInput.setTextColor(textColor) + themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) + protectEmojiPickerScrollGesture(emojiPickerView) + } + private fun updateSearchRowVisibility() { binding.emojiSearchRow.isVisible = searchEnabled || backspaceEnabled } diff --git a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt index bf6ddb66096..bb39f4165ad 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt @@ -35,7 +35,6 @@ import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.ColorUtils import androidx.core.graphics.drawable.DrawableCompat import androidx.core.view.ViewCompat -import androidx.emoji2.emojipicker.EmojiPickerView import com.google.android.material.button.MaterialButton import com.google.android.material.card.MaterialCardView import com.google.android.material.chip.Chip @@ -47,8 +46,7 @@ import com.nextcloud.android.common.ui.util.buildColorStateList import com.nextcloud.talk.R import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding -import com.nextcloud.talk.emojipicker.protectEmojiPickerScrollGesture -import com.nextcloud.talk.emojipicker.themeEmojiPickerCategoryTabs +import com.nextcloud.talk.emojipicker.EmojiPickerPanel import com.nextcloud.talk.ui.MicInputCloud import com.nextcloud.talk.ui.StatusDrawable import com.nextcloud.talk.ui.WaveformSeekBar @@ -495,15 +493,15 @@ class TalkSpecificViewThemeUtils @Inject constructor( } } - fun themeEmojiPicker(emojiPickerView: EmojiPickerView) { - withScheme(emojiPickerView.context) { scheme -> - emojiPickerView.setBackgroundColor(dynamicColor.surfaceContainerLow().getArgb(scheme)) - themeEmojiPickerCategoryTabs( - emojiPickerView, - dynamicColor.primary().getArgb(scheme), - dynamicColor.onSurfaceVariant().getArgb(scheme) + fun themeEmojiPicker(emojiPickerPanel: EmojiPickerPanel) { + withScheme(emojiPickerPanel.context) { scheme -> + emojiPickerPanel.applyTheme( + backgroundColor = dynamicColor.surfaceContainerLow().getArgb(scheme), + selectedTabColor = dynamicColor.primary().getArgb(scheme), + unselectedTabColor = dynamicColor.onSurfaceVariant().getArgb(scheme), + hintTextColor = dynamicColor.onSurfaceVariant().getArgb(scheme), + textColor = dynamicColor.onSurface().getArgb(scheme) ) - protectEmojiPickerScrollGesture(emojiPickerView) } } From 0df5368731ca4e4a24bdba8755c79cf9b4d0893c Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 3 Sep 2026 16:15:30 +0200 Subject: [PATCH 4/6] fix(emoji): theme the search icon, clear, and backspace buttons These icons were left at their static drawable tint, so they didn't follow the app's dynamic per-server branding like the rest of the picker. EmojiPickerPanel.applyTheme() now tints all three with the same color used for the search hint text. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt | 9 +++++++-- app/src/main/res/layout/emoji_picker_panel.xml | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt index b4e85d97400..e4c68712e59 100644 --- a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt @@ -7,6 +7,7 @@ package com.nextcloud.talk.emojipicker import android.content.Context +import android.content.res.ColorStateList import android.util.AttributeSet import android.util.TypedValue import android.view.LayoutInflater @@ -96,8 +97,8 @@ class EmojiPickerPanel @JvmOverloads constructor( * Applies the host's dynamic per-server branding to every themeable part of the panel: * the picker's background and selected-category tab (see [themeEmojiPickerCategoryTabs]), * its scroll-gesture fix (see [protectEmojiPickerScrollGesture]), and the search field's - * hint/text colors, which otherwise fall back to the static app theme instead of following - * that branding. + * hint/text/icon colors, which otherwise fall back to the static app theme instead of + * following that branding. */ fun applyTheme( backgroundColor: Int, @@ -109,6 +110,10 @@ class EmojiPickerPanel @JvmOverloads constructor( setBackgroundColor(backgroundColor) binding.emojiSearchInput.setHintTextColor(hintTextColor) binding.emojiSearchInput.setTextColor(textColor) + val iconTint = ColorStateList.valueOf(hintTextColor) + binding.emojiSearchIcon.imageTintList = iconTint + binding.emojiSearchClear.imageTintList = iconTint + binding.emojiBackspaceButton.imageTintList = iconTint themeEmojiPickerCategoryTabs(emojiPickerView, selectedTabColor, unselectedTabColor) protectEmojiPickerScrollGesture(emojiPickerView) } diff --git a/app/src/main/res/layout/emoji_picker_panel.xml b/app/src/main/res/layout/emoji_picker_panel.xml index 2e4c5ca8983..5a316a47215 100644 --- a/app/src/main/res/layout/emoji_picker_panel.xml +++ b/app/src/main/res/layout/emoji_picker_panel.xml @@ -25,6 +25,7 @@ android:orientation="horizontal"> Date: Thu, 3 Sep 2026 16:21:18 +0200 Subject: [PATCH 5/6] fix(emoji): hide the backspace button while the search field is focused With the keyboard open for typing a search term, a backspace button right next to the field read as if it deleted from the search term itself rather than from the host's own text field. EmojiPickerPanel now hides it on search-field focus and restores it once focus leaves (or the panel is reset). Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: Marcel Hibbe --- .../talk/emojipicker/EmojiPickerPanel.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt index e4c68712e59..3f657702120 100644 --- a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt @@ -44,6 +44,7 @@ class EmojiPickerPanel @JvmOverloads constructor( private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private var searchJob: Job? = null private var recentEmojiProvider: RecentEmojiProvider? = null + private var searchFieldFocused = false var searchEnabled: Boolean = true set(value) { @@ -55,7 +56,7 @@ class EmojiPickerPanel @JvmOverloads constructor( var backspaceEnabled: Boolean = false set(value) { field = value - binding.emojiBackspaceButton.isVisible = value + updateBackspaceVisibility() updateSearchRowVisibility() } @@ -67,11 +68,15 @@ class EmojiPickerPanel @JvmOverloads constructor( init { orientation = VERTICAL binding.emojiSearchFieldGroup.isVisible = searchEnabled - binding.emojiBackspaceButton.isVisible = backspaceEnabled + updateBackspaceVisibility() updateSearchRowVisibility() binding.emojiPicker.setOnEmojiPickedListener { item -> onEmojiPicked?.invoke(item.emoji) } binding.emojiSearchInput.doAfterTextChanged { editable -> onSearchTextChanged(editable?.toString().orEmpty()) } + binding.emojiSearchInput.setOnFocusChangeListener { _, hasFocus -> + searchFieldFocused = hasFocus + updateBackspaceVisibility() + } binding.emojiSearchClear.setOnClickListener { binding.emojiSearchInput.setText("") } binding.emojiBackspaceButton.setOnClickListener { onBackspaceClicked?.invoke() } } @@ -90,6 +95,7 @@ class EmojiPickerPanel @JvmOverloads constructor( fun reset() { searchJob?.cancel() binding.emojiSearchInput.setText("") + binding.emojiSearchInput.clearFocus() showGrid() } @@ -122,6 +128,15 @@ class EmojiPickerPanel @JvmOverloads constructor( binding.emojiSearchRow.isVisible = searchEnabled || backspaceEnabled } + /** + * Hidden while the search field has focus - with the keyboard open for typing a search + * term, a backspace button right next to it reads as belonging to the search field rather + * than to whatever text field the host's own [onBackspaceClicked] actually edits. + */ + private fun updateBackspaceVisibility() { + binding.emojiBackspaceButton.isVisible = backspaceEnabled && !searchFieldFocused + } + private fun onSearchTextChanged(query: String) { binding.emojiSearchClear.isVisible = query.isNotEmpty() searchJob?.cancel() From 65d2e65ef153e5b6f64965fb555ee8b29f4ccfaa Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 3 Sep 2026 16:28:32 +0200 Subject: [PATCH 6/6] fix(emoji): grey out the backspace button when there is nothing to delete EmojiPickerPanel gains backspaceActionAvailable, which the host toggles independently of backspaceEnabled (which only controls whether the button shows at all). MessageInputFragment now keeps it in sync with whether the message input actually has text, since the panel itself has no knowledge of the host's text field content. Assisted-by: Claude Code:claude-sonnet-5 Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/chat/MessageInputFragment.kt | 2 ++ .../nextcloud/talk/emojipicker/EmojiPickerPanel.kt | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index c8a5f89910c..45f2f6acec4 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -468,6 +468,7 @@ class MessageInputFragment : Fragment() { val text = binding.fragmentMessageInputView.messageInput.text.toString() chatActivity.chatViewModel.messageDraft.messageCursor = cursor chatActivity.chatViewModel.messageDraft.messageText = text + binding.emojiPickerPanel.backspaceActionAvailable = s.isNotEmpty() handleButtonsVisibility() } }) @@ -893,6 +894,7 @@ class MessageInputFragment : Fragment() { emojiPickerPanel.setRecentEmojiProvider(recentEmojiProvider) emojiPickerPanel.onEmojiPicked = { emoji -> insertEmoji(emoji) } emojiPickerPanel.onBackspaceClicked = { deleteEmojiOrCharacterBeforeCursor() } + emojiPickerPanel.backspaceActionAvailable = inputEditText.text?.isNotEmpty() == true viewThemeUtils.talk.themeEmojiPicker(emojiPickerPanel) updateSmileyButtonIcon() diff --git a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt index 3f657702120..3a88f4f7142 100644 --- a/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt +++ b/app/src/main/java/com/nextcloud/talk/emojipicker/EmojiPickerPanel.kt @@ -60,6 +60,14 @@ class EmojiPickerPanel @JvmOverloads constructor( updateSearchRowVisibility() } + /** Whether the host's target text actually has something for the backspace button to delete. */ + var backspaceActionAvailable: Boolean = true + set(value) { + field = value + binding.emojiBackspaceButton.isEnabled = value + binding.emojiBackspaceButton.alpha = if (value) ENABLED_ALPHA else DISABLED_ALPHA + } + var onEmojiPicked: ((String) -> Unit)? = null var onBackspaceClicked: (() -> Unit)? = null @@ -70,6 +78,7 @@ class EmojiPickerPanel @JvmOverloads constructor( binding.emojiSearchFieldGroup.isVisible = searchEnabled updateBackspaceVisibility() updateSearchRowVisibility() + binding.emojiBackspaceButton.alpha = ENABLED_ALPHA binding.emojiPicker.setOnEmojiPickedListener { item -> onEmojiPicked?.invoke(item.emoji) } binding.emojiSearchInput.doAfterTextChanged { editable -> onSearchTextChanged(editable?.toString().orEmpty()) } @@ -201,5 +210,7 @@ class EmojiPickerPanel @JvmOverloads constructor( private const val SEARCH_DEBOUNCE_MS = 150L private const val RESULT_TEXT_SIZE_SP = 28f private const val RESULT_PADDING_DP = 8 + private const val ENABLED_ALPHA = 1f + private const val DISABLED_ALPHA = 0.38f } }