From db65b8b101b6d7d9138c4f61899edcb1003dd030 Mon Sep 17 00:00:00 2001 From: Salastil Date: Sun, 13 Sep 2026 13:30:11 -0400 Subject: [PATCH] The picker asks the account what it used last Where the account keeps the list itself - Matrix, in account data - that copy wins, because it is the one that has seen every client and the local one is only this machine's view of it. Everything else keeps the local list unchanged: nothing else here has anywhere to put it, and on the services whose emoji are guild- or channel-bound a travelling list would travel to places its entries cannot be sent. Writing back is fire and forget. The row on screen is already right, and one pick failing to reach another client is not worth interrupting somebody mid-sentence about. Co-Authored-By: Claude Opus 5 --- nobilis | 2 +- src/renderer/src/components/EmojiPicker.tsx | 33 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/nobilis b/nobilis index 3e522af..ae2e818 160000 --- a/nobilis +++ b/nobilis @@ -1 +1 @@ -Subproject commit 3e522afdc55be5650fc260675026dc89acca9e73 +Subproject commit ae2e8189b42596c57be39459c8c1114863f213ba diff --git a/src/renderer/src/components/EmojiPicker.tsx b/src/renderer/src/components/EmojiPicker.tsx index a677609..43407bb 100644 --- a/src/renderer/src/components/EmojiPicker.tsx +++ b/src/renderer/src/components/EmojiPicker.tsx @@ -100,6 +100,19 @@ function readRecent(accountId?: string): string[] { } } +/** + * Whether this account keeps its recent picks on the account rather than in + * this window. + * + * Matrix does, in account data, so the list follows the person to their + * phone and back. Nothing else here has anywhere to put it - and on the + * services whose emoji are guild- or channel-bound, a list that travelled + * would travel to places the emoji in it cannot be sent. + */ +function travels(accountId?: string): boolean { + return !!accountId?.startsWith('matrix:') +} + /** One image out of a Matrix sticker pack, as the daemon offers it. */ export interface StickerEntry { name: string @@ -195,6 +208,19 @@ export function EmojiPicker({ // point the list on screen belongs to somebody else. useEffect(() => { setRecent(readRecent(accountId)) + // Where the account keeps the list itself, that copy wins: it is the one + // that has seen every client, and the local one is only ever this + // machine's view of it. Asked each time the picker changes account + // rather than held, because the answer changes elsewhere. + if (!travels(accountId)) return + void window.moho + .rpc('matrixRecentEmoji', { accountId }) + // An older daemon does not answer this, and an account that has never + // picked one has nothing to say. Both leave the local list alone. + .then((list) => { + if (list.length > 0) setRecent(list) + }) + .catch(() => {}) }, [accountId]) // Anchored above and right-aligned to the button that opened it, and kept @@ -355,6 +381,13 @@ export function EmojiPicker({ } catch { /* a full or disabled store just means recents don't persist */ } + // And on the account, where it has somewhere to go. Fire and forget: the + // list on screen is already right, and a failed write means one pick is + // not carried to another client - not something to interrupt somebody + // mid-sentence about. + if (travels(accountId)) { + void window.moho.rpc('matrixEmojiUsed', { accountId, emoji: text }).catch(() => {}) + } onSelect(text) }