presets: replace emoji picker with categorized WhatsApp-style grid
Replaces the 60-emoji flat list with 8 standard Unicode categories (Smileys, People, Animals, Food, Travel, Activities, Objects, Symbols), each with 30–100 emojis. The picker now has a category tab bar at the top (emoji icons, highlighted active tab) and a scrollable emoji grid below — matching the layout used in WhatsApp and other messaging apps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cc589f254b
commit
d2c6d352a5
@ -34,20 +34,89 @@ RESP_SAVE = 1
|
|||||||
RESP_SAVE_RESTART = 2
|
RESP_SAVE_RESTART = 2
|
||||||
GREEN, RED, GREY = "#34c759", "#ff3b30", "#b8b8be"
|
GREEN, RED, GREY = "#34c759", "#ff3b30", "#b8b8be"
|
||||||
|
|
||||||
_PICKER_EMOJIS = (
|
# (cat_emoji, label, [emojis]) — standard Unicode categories, WhatsApp-style
|
||||||
# Lightning / common defaults
|
_EMOJI_CATEGORIES: list[tuple[str, str, list[str]]] = [
|
||||||
"⚡", "🎤", "📝", "✉️", "📋", "💬", "📢", "🔔", "💡", "🔍",
|
("😀", "Smileys", [
|
||||||
# Status / actions
|
"😀","😃","😄","😁","😆","😅","🤣","😂","🙂","🙃","😉","😊","😇",
|
||||||
"✅", "❌", "🔄", "▶️", "⏺️", "🚀", "⭐", "✨", "🎯", "🏆",
|
"🥰","😍","🤩","😘","😗","😚","😙","🥲","😋","😛","😜","🤪","😝",
|
||||||
# Tech / tools
|
"🤑","🤗","🤭","🤫","🤔","🤐","🤨","😐","😑","😶","😏","😒","🙄",
|
||||||
"💻", "⌨️", "🔧", "⚙️", "🛠️", "💾", "📱", "🌐", "📊", "📈",
|
"😬","🤥","😌","😔","😪","🤤","😴","😷","🤒","🤕","🤢","🤮","🤧",
|
||||||
# People / reactions
|
"🥵","🥶","🥴","😵","🤯","🤠","🥳","🥸","😎","🤓","🧐","😕","😟",
|
||||||
"😀", "😊", "👍", "🤖", "🙌", "👋", "🎓", "🎵", "📖", "🔐",
|
"🙁","😮","😯","😲","😳","🥺","😦","😧","😨","😰","😥","😢","😭",
|
||||||
# Writing / documents
|
"😱","😖","😣","😞","😓","😩","😫","🥱","😤","😡","😠","🤬","😈",
|
||||||
"📧", "🗨️", "📨", "🗒️", "✏️", "🖊️", "📑", "🖋️", "📃", "📄",
|
"👿","💀","☠️","💩","🤡","👹","👺","👻","👽","👾","🤖",
|
||||||
# Misc useful
|
]),
|
||||||
"🌟", "💫", "🔁", "🔀", "⏸️", "⏹️", "🏠", "💰", "🎶", "🌈",
|
("👋", "People", [
|
||||||
)
|
"👋","🤚","🖐️","✋","🖖","👌","🤌","🤏","✌️","🤞","🤟","🤘","🤙",
|
||||||
|
"👈","👉","👆","🖕","👇","☝️","👍","👎","✊","👊","🤛","🤜","👏",
|
||||||
|
"🙌","👐","🤲","🤝","🙏","✍️","💅","💪","🦾","👂","👃","👀","👅",
|
||||||
|
"👄","💋","👶","🧒","👦","👧","🧑","👱","👨","🧔","👩","🧓","👴",
|
||||||
|
"👵","🙍","🙎","🙅","🙆","💁","🙋","🧏","🙇","🤦","🤷","💆","💇",
|
||||||
|
"🚶","🏃","💃","🕺","🧖","🧗","🤸","⛹️","🏋️","🤼","🧘","🛀","🛌",
|
||||||
|
"👮","🕵️","💂","🥷","👷","🫅","🤴","👸","🧙","🧝","🧛","🧟","🧞",
|
||||||
|
"🧜","🧚","👼","🤶","🎅","🦸","🦹","🧑🍳","🧑🎓","🧑🏫","🧑⚕️","🧑💼","🧑🔧","🧑💻",
|
||||||
|
]),
|
||||||
|
("🐶", "Animals", [
|
||||||
|
"🐶","🐱","🐭","🐹","🐰","🦊","🐻","🐼","🐨","🐯","🦁","🐮","🐷",
|
||||||
|
"🐸","🐵","🙈","🙉","🙊","🐒","🐔","🐧","🐦","🐤","🦆","🦅","🦉",
|
||||||
|
"🦇","🐺","🐗","🐴","🦄","🐝","🐛","🦋","🐌","🐞","🐜","🦟","🦗",
|
||||||
|
"🕷️","🦂","🐢","🐍","🦎","🐙","🦑","🦐","🦀","🐡","🐠","🐟","🐬",
|
||||||
|
"🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🐘","🦏","🐪","🦒","🦘",
|
||||||
|
"🐃","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐈",
|
||||||
|
"🐓","🦃","🦚","🦜","🦢","🦩","🕊️","🐇","🦝","🦨","🦡","🦦","🦥",
|
||||||
|
"🐁","🐀","🐿️","🦔","🐉","🐲","🌵","🌲","🌳","🌴","🌿","☘️","🍀",
|
||||||
|
"🎋","🎍","🍃","🍂","🍁","🌾","🌺","🌸","🌼","🌻","🌹","🥀","🌷",
|
||||||
|
]),
|
||||||
|
("🍎", "Food", [
|
||||||
|
"🍏","🍎","🍐","🍊","🍋","🍌","🍉","🍇","🍓","🫐","🍒","🍑","🥭",
|
||||||
|
"🍍","🥥","🥝","🍅","🍆","🥑","🥦","🥬","🥒","🌶️","🧄","🧅","🥔",
|
||||||
|
"🌽","🥕","🍞","🥐","🥖","🥨","🧀","🥚","🍳","🧈","🥞","🥓","🥩",
|
||||||
|
"🍗","🍖","🌭","🍔","🍟","🍕","🌮","🌯","🥙","🥚","🍲","🥗","🍿",
|
||||||
|
"🧂","🍱","🍣","🍛","🍜","🍝","🍢","🥟","🥠","🥡","🍦","🍧","🍨",
|
||||||
|
"🍩","🍪","🎂","🍰","🧁","🍫","🍬","🍭","🍮","🍯","🥛","☕","🍵",
|
||||||
|
"🧃","🥤","🧋","🍺","🍻","🥂","🍷","🥃","🍸","🍹","🍾","🧊","🍴",
|
||||||
|
]),
|
||||||
|
("🏠", "Travel", [
|
||||||
|
"🚗","🚕","🚙","🚌","🏎️","🚓","🚑","🚒","🚐","🛻","🚚","🚛","🚜",
|
||||||
|
"🏍️","🛵","🚲","🛴","🛹","⚓","⛵","🚤","🛥️","🚢","✈️","🛩️","🚁",
|
||||||
|
"🚀","🛸","🪐","🌍","🌎","🌏","🗺️","🧭","🏔️","⛰️","🌋","🏕️","🏖️",
|
||||||
|
"🏜️","🏝️","🏟️","🏛️","🏗️","🏘️","🏠","🏡","🏢","🏣","🏤","🏥","🏦",
|
||||||
|
"🏨","🏪","🏫","🏬","🏭","🏯","🏰","💒","🗼","🗽","⛪","🕌","⛩️",
|
||||||
|
"🕋","⛲","⛺","🌁","🌃","🏙️","🌄","🌅","🌆","🌇","🌉","🌌","🌠",
|
||||||
|
"🎇","🎆","🎑","🗾",
|
||||||
|
]),
|
||||||
|
("⚽", "Activities", [
|
||||||
|
"⚽","🏀","🏈","⚾","🥎","🎾","🏐","🏉","🥏","🎱","🏓","🏸","🏒",
|
||||||
|
"🥍","🏑","🏏","⛳","🎣","🤿","🎽","🎿","🛷","🥌","🎯","🎮","🎰",
|
||||||
|
"🎲","♟️","🧩","🪄","🎭","🎨","🎪","🎤","🎧","🎼","🎹","🥁","🎷",
|
||||||
|
"🎺","🎸","🎻","🎬","🎥","📽️","🎞️","🎠","🎡","🎢","🎟️","🎫","🏆",
|
||||||
|
"🥇","🥈","🥉","🏅","🎖️","🎗️","🎀","🎁","🎊","🎉",
|
||||||
|
]),
|
||||||
|
("💡", "Objects", [
|
||||||
|
"📱","📲","💻","⌨️","🖥️","🖨️","🖱️","💾","💿","📀","🧮","🎥","📷",
|
||||||
|
"📹","📼","🔍","🔎","💡","🔦","🏮","🪔","📔","📒","📓","📕","📗",
|
||||||
|
"📘","📙","📚","📖","🔖","🏷️","💰","💳","🪙","📈","📉","📊","📋",
|
||||||
|
"📌","📍","✂️","🔒","🔓","🔏","🔐","🔑","🗝️","🔨","⛏️","⚒️","🛠️",
|
||||||
|
"🔧","🪛","🔩","⚙️","⚖️","🔗","🧲","🪜","🧪","🔭","🔬","💊","💉",
|
||||||
|
"🩹","🩺","🧴","🧷","🧹","🧺","🧻","🪣","🧼","🪒","🛒","🚪","🪞",
|
||||||
|
"🛏️","🛋️","🪑","🚽","🚿","🛁","🧸","🪆","👓","🕶️","🥽","👒","🎩",
|
||||||
|
"🧢","⛑️","📿","💍","💎","🌂","🧵","🧶","🪢","🎒","👜","👝","👛",
|
||||||
|
"💼","🧳","🌂","☂️","🛡️","🗡️","⚔️","🪃","🏹","🪤","🪬","🧿","🔮",
|
||||||
|
]),
|
||||||
|
("🔣", "Symbols", [
|
||||||
|
"❤️","🧡","💛","💚","💙","💜","🖤","🤍","🤎","💔","❣️","💕","💞",
|
||||||
|
"💓","💗","💖","💘","💝","☮️","✝️","☪️","🕉️","☸️","✡️","☯️","☦️","🛐",
|
||||||
|
"♈","♉","♊","♋","♌","♍","♎","♏","♐","♑","♒","♓","⛎",
|
||||||
|
"🔀","🔁","🔂","▶️","⏩","⏭️","⏯️","◀️","⏪","⏮️","🔼","⏫","🔽",
|
||||||
|
"⏬","⏸️","⏹️","⏺️","🎦","🔅","🔆","📶","🔇","🔈","🔉","🔊","📢",
|
||||||
|
"📣","🔔","🔕","⚠️","🚸","⛔","🚫","🚳","🚭","🚯","🚱","🚷","📵",
|
||||||
|
"🔞","💯","♻️","✅","❌","❎","➕","➖","➗","✖️","💲","™️","©️","®️",
|
||||||
|
"〰️","➰","➿","🔚","🔙","🔛","🔜","🔝","🔴","🟠","🟡","🟢","🔵",
|
||||||
|
"🟣","⚫","⚪","🟤","🔶","🔷","🔸","🔹","🔺","🔻","💠","🔘","⭕",
|
||||||
|
"⭐","🌟","💫","✨","🔥","💧","🌊","🌀","⚡","❄️","🌈","🎵","🎶",
|
||||||
|
"💬","💭","💤","❓","❗","⁉️","🔑","🎯","🏁","🚩","🎌","🏴","🏳️",
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _dot(color: str) -> str:
|
def _dot(color: str) -> str:
|
||||||
@ -520,22 +589,68 @@ class SettingsDialog:
|
|||||||
|
|
||||||
def _show_emoji_picker(self, anchor: Gtk.Widget, entry: Gtk.Entry) -> None:
|
def _show_emoji_picker(self, anchor: Gtk.Widget, entry: Gtk.Entry) -> None:
|
||||||
pop = Gtk.Popover(relative_to=anchor)
|
pop = Gtk.Popover(relative_to=anchor)
|
||||||
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
|
||||||
|
|
||||||
|
# -- category tab bar ------------------------------------------------
|
||||||
|
stack = Gtk.Stack()
|
||||||
|
stack.set_transition_type(Gtk.StackTransitionType.NONE)
|
||||||
|
stack.set_size_request(420, 230)
|
||||||
|
|
||||||
|
cat_bar = Gtk.Box(spacing=0)
|
||||||
|
cat_bar.set_margin_top(4); cat_bar.set_margin_bottom(4)
|
||||||
|
cat_bar.set_margin_start(4); cat_bar.set_margin_end(4)
|
||||||
|
|
||||||
|
first_name: str | None = None
|
||||||
|
active_btn: list[Gtk.Button] = [None] # mutable cell
|
||||||
|
|
||||||
|
def _select(name: str, btn: Gtk.Button) -> None:
|
||||||
|
stack.set_visible_child_name(name)
|
||||||
|
if active_btn[0]:
|
||||||
|
active_btn[0].get_style_context().remove_class("suggested-action")
|
||||||
|
btn.get_style_context().add_class("suggested-action")
|
||||||
|
active_btn[0] = btn
|
||||||
|
|
||||||
|
for cat_emoji, cat_name, emojis in _EMOJI_CATEGORIES:
|
||||||
|
# Build scrollable emoji grid for this category
|
||||||
flow = Gtk.FlowBox()
|
flow = Gtk.FlowBox()
|
||||||
flow.set_max_children_per_line(10)
|
flow.set_max_children_per_line(10)
|
||||||
flow.set_selection_mode(Gtk.SelectionMode.NONE)
|
flow.set_selection_mode(Gtk.SelectionMode.NONE)
|
||||||
flow.set_margin_top(6); flow.set_margin_bottom(6)
|
flow.set_margin_top(4); flow.set_margin_bottom(4)
|
||||||
flow.set_margin_start(6); flow.set_margin_end(6)
|
flow.set_margin_start(4); flow.set_margin_end(4)
|
||||||
for emoji in _PICKER_EMOJIS:
|
for emoji in emojis:
|
||||||
eb = Gtk.Button(label=emoji)
|
eb = Gtk.Button(label=emoji)
|
||||||
eb.set_relief(Gtk.ReliefStyle.NONE)
|
eb.set_relief(Gtk.ReliefStyle.NONE)
|
||||||
eb.connect("clicked", lambda _b, e=emoji: (entry.set_text(e), pop.popdown()))
|
eb.connect("clicked", lambda _b, e=emoji: (entry.set_text(e), pop.popdown()))
|
||||||
flow.add(eb)
|
flow.add(eb)
|
||||||
sw = Gtk.ScrolledWindow()
|
sw = Gtk.ScrolledWindow()
|
||||||
sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
||||||
sw.set_min_content_height(210)
|
|
||||||
sw.set_min_content_width(370)
|
|
||||||
sw.add(flow)
|
sw.add(flow)
|
||||||
pop.add(sw)
|
stack.add_named(sw, cat_name)
|
||||||
|
|
||||||
|
# Category tab button
|
||||||
|
cb = Gtk.Button(label=cat_emoji)
|
||||||
|
cb.set_relief(Gtk.ReliefStyle.NONE)
|
||||||
|
cb.set_tooltip_text(cat_name)
|
||||||
|
cb.connect("clicked", lambda _b, n=cat_name, b=cb: _select(n, b))
|
||||||
|
cat_bar.pack_start(cb, True, True, 0)
|
||||||
|
|
||||||
|
if first_name is None:
|
||||||
|
first_name = cat_name
|
||||||
|
active_btn[0] = cb
|
||||||
|
cb.get_style_context().add_class("suggested-action")
|
||||||
|
|
||||||
|
if first_name:
|
||||||
|
stack.set_visible_child_name(first_name)
|
||||||
|
|
||||||
|
cat_scroll = Gtk.ScrolledWindow()
|
||||||
|
cat_scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.NEVER)
|
||||||
|
cat_scroll.set_min_content_height(44)
|
||||||
|
cat_scroll.add(cat_bar)
|
||||||
|
|
||||||
|
vbox.pack_start(cat_scroll, False, False, 0)
|
||||||
|
vbox.pack_start(Gtk.Separator(), False, False, 0)
|
||||||
|
vbox.pack_start(stack, True, True, 0)
|
||||||
|
pop.add(vbox)
|
||||||
pop.show_all()
|
pop.show_all()
|
||||||
|
|
||||||
# ===== Engines ==========================================================
|
# ===== Engines ==========================================================
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user