- Matrix: interactive device verification (SAS emoji flow), recovery-key
backup/restore, membership announcement moderation, member/room avatars,
power-level-aware moderation menu, and an encryption lock indicator on
the composer - verified live with two independent devices.
- Replace the single combined join panel with a dedicated page per
protocol (IrcJoinPanel/MatrixJoinPanel/DiscordJoinPanel), routed by
whichever account the "+" button was clicked for rather than listing
every account in one expandable page.
- Discord: friends list (Online/All, click-to-DM, add-friend, matches
READY's relationships + live PRESENCE_UPDATE), create-a-server, and
join-by-invite alongside the existing DM-by-ID flow.
- Discord: an expired attachment-link fallback ("Open in Discord") for
scrollback media whose signed cdn.discordapp.com URL has lapsed -
Discord's own /attachments/refresh-urls re-sign endpoint hard-rejects
this backend's user-token requests, confirmed live, so this opens the
real message instead of showing a broken embed.
- Discord: detect gateway close code 4004 (revoked token) as a distinct
ConnState::AuthFailed instead of retrying a dead credential forever;
the Accounts pane shows a clear "needs login" state that routes
straight to a fresh QR login, which upserts the same account id in
place (no lost buffers/scrollback).
- Fix the unread-DM pinned-buffer flash never reliably triggering: an
implicit property binding computed via nested closures over two
separate properties wasn't consistently re-evaluated by QML's
dependency tracker; replaced with an explicit recompute function called
at every actual mutation point.
- Fix ChatBarWidget.qml's pill double-padding against BasePill's own
padding.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- New chatd-rs backend/matrix module: m.login.password auth, /sync-based
multi-room connect loop, and full E2EE via matrix-sdk-crypto (device key
upload, Megolm session establishment, encrypt/decrypt) - verified live
against real homeservers with two independent devices exchanging an
encrypted message neither one decrypted itself.
- Reactions, edits, redactions, replies, and media upload/download, mapped
onto the existing Reaction/Embed/ReplyPreview model.
- Frontend wiring: MatrixConnectForm.qml, AccountsPanel/ChatView hookup,
and the real addMatrixAccount RPC handler (replacing the stub).
- Fix messages doubling in the UI: the Matrix backend never called
Runtime::set_own_identity, so every message - including the account's
own - was stored with is_own=false, defeating the frontend's optimistic-
send reconciliation.
- Fix accounts getting stuck showing "connecting" forever: the Connected
state transition was gated on this being the account's very first-ever
sync (next_batch.is_none()), which is never true again once a cursor is
persisted across a restart - a real account could sync successfully
forever and never have its state announced as connected.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Bundle Sneedchat's 175 site smilies as local assets instead of fetching
live over Tor; render them full-size in the chat buffer and emoji picker,
with animated (gif/webp) smilies looping via a separate AnimatedImage row
since Qt rich-text <img> can only render a static first frame.
- Add Discord message reactions: toggleReaction RPC, per-message reaction
pills sized to match Discord's own client, a shared reaction/emoji-picker
popup anchored and edge-clamped to the message row, and a row-wide hover
toolbar (reactions/reply/more) gated to Discord only.
- Extend the row hover highlight to every protocol, not just Discord, since
it's generic UX polish with nothing protocol-specific about it.
- Restyle the message context menu with per-item icons and Discord-style
colored entries (e.g. red Delete), using anchored icon+text layout instead
of RowLayout/MenuItem auto-sizing for reliable alignment across items.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Sneedchat: detect a reconnect that silently lands as a guest (server's
own can_send permission flag) and force a session refresh + relogin;
add an idle-read timeout so a dead websocket is actually noticed
- Sneedchat: multipart file upload support in http.rs, wired into
sendMessage's attachment path (qu.ax-hosted images/video)
- Discord-style optimistic message sends: dim pending messages, resolve
to the real server echo, turn red and offer Retry on failure/timeout
- MessageList: fix scroll-to-end/New-divider landing, anchored-scroll
reliability during scrollbar drags, and BBCode [img][/img] tags
merging into one URL when posted back-to-back
- MediaEmbed: real audio output device, working scrub-bar seek/pan,
restart-from-start on a finished video
- DaemonStatusSettings: chatd connection indicator + build (git branch)
badge for DMS's plugin manager pane
- BufferList: scope the "+" join-channel affordance to IRC accounts only
- DisplaySettingsPanel: new toggle for content-sniffing unrecognized
media links
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Persist the last-viewed channel and collapsed sidebar groups (accounts,
Discord guilds/DMs, pinned) across closing and reopening the chat
window, which recreates these views from scratch rather than just
hiding them.
- Add one line of breathing room between the last message and the
composer bar.
- Fix BBCode-wrapped image links (Sneedchat's own "[url=X][img]X[/img]
[/url]" convention) not embedding: the wrapper wasn't being collapsed
before extraction, so the bare-URL scan swallowed the trailing [/url]
into the "URL" and broke the extension check. Also harden that scan
against any other bracket-adjacent markup, and recognize known
extensionless image hosts (e.g. ShareX-style upload hosts).
- Resolve Kiwi Farms attachment links (which encode their extension in
the slug, not as a real URL suffix) by fetching them through the
account's Tor transport - using the onion address specifically, since
kiwifarms.st's clearnet edge is both unstable and tends to mishandle
Tor exit traffic - caching to /tmp, and patching the message body with
the local path once ready. Required teaching the frontend's URL
detection about file:// links and giving message-body rewrites a way
to update in place without showing a spurious "(edited)" label.
- Fix Sneedchat messages failing to send (while still receiving fine) on
a room whose connection had recently been re-established: the old
connection's delayed cleanup could remove a newer, live sender for the
same room out from under it. Sender removal now checks it's still the
same channel before removing it.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Move the ~17 top-level QML files into views/, settings/, and forms/
subdirectories, grouped so cross-directory type references stay minimal
(only 3 files need an added `import` line). Root now only holds the
four surfaces plugin.json points at directly.
- Add a `dms ipc call dankChat popout` IPC target to open the floating
window directly, alongside the existing `toggle`, and document both in
the README along with the new directory layout.
- Add one line of breathing room between the last message and the
composer bar via the message ListView's bottomMargin (measured with
FontMetrics rather than a guessed pixel value).
Co-Authored-By: Claude Sonnet 5 <[email protected]>