Add setting to hide unread activity dot indicators - #2923
Conversation
|
I have read the CLA Document and I hereby sign the CLA 1 out of 2 committers have signed the CLA. |
|
I have read the CLA Document and I hereby sign the CLA |
|
recheck |
|
Here's a netlify link, if you wanted to test: |
Rooms with unread activity but no notification count (muted rooms, push-rule-downgraded rooms) showed a small grey dot in the room list and kept appearing in the collapsed "unread only" nav section even though nothing actually needed attention. This adds a "Hide Unread Activity Dots" toggle (off by default) under Settings › Notifications › System with three coordinated effects: 1. UnreadBadge: when the setting is on, skip rendering the dot entirely for rooms where count=0 and highlight=false. 2. Nav collapse filter (Direct, Home, Space): reads the same setting reactively — when on, the collapsed category shows only rooms with total>0 or highlight>0; when off, it reverts to the original behaviour of showing all rooms that have any unread activity. Toggling the setting in Settings updates the nav instantly without a page reload. 3. Settings UI: adds the toggle under Settings › Notifications › System.
|
Uhm, maybe I'm misunderstanding the purpose of this PR, but your "After" screenshot just seems to hide all the rooms that had this Unread Indicator |
|
@CrazyNicc thx for answering so quickly! Yes that's exactly the point. A lot of irrelevant events trigger that unread marker and I think it makes sense to hide them for some users who get a lot of messages 🙈 Also it is shown when the room is muted I think and probably in other scenarios. There are also a lot of bugs that are related to them. |
|
@chagai95 Oh, afaik muting the room also removed all the read indicators.
But your screenshot completely hides the rooms themselves, not just the unread markers of these rooms. Or did I miss something? |
It hides them from the unread view, when the section is closed (arrow not down), maybe muting the room helps with that, didn't check but I don't want to start muting all my rooms just to avoid seeing this, on fluffy chat it's not shown by default in the unread tab. |
|
Hi everyone, just wondering if there is something missing here? |
|
See the notice in the Project README:
|
…message" Replying to a voice note (m.audio .ogg, e.g. a bridged WhatsApp "Voice message.ogg") — or any media without a text body — rendered the quoted preview as "Failed to load message" even though the replied-to event loaded fine. Root cause: Reply.tsx only used the event's `body`. When `body` was missing/empty (or was only the stripped reply-quote), it fell through to the generic MessageFailedContent fallback, which reads "Failed to load message". Fix: when a loaded reply target has no usable text body, derive a msgtype-based preview (🎤 Voice message / 🔊 Audio / 🖼️ Image / 🎬 Video / 📄 File / 📍 Location) instead of the failure fallback. Voice notes are detected via the MSC3245/MSC1767 voice extension on m.audio. Only genuinely un-renderable events (redacted → deleted notice; unknown/no content → failure) still hit the fallbacks. General across all media msgtypes, not a voice-only band-aid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPNRaVnHM9hmpwYyewbeVj
…e estimates The emoji board virtualizes at the group level but used a flat estimateSize of 40px per group. Before any group was measured, the virtualizer therefore believed all ~10 groups fit in the 400px viewport and eagerly mounted every group — ~1,900 emoji <button> nodes — on the very first paint, defeating the virtualization and making the popover slow to open. Estimate each group's real rendered height from its item count (48px emoji / 112px sticker buttons, ~6/3 per row + group chrome) so only the groups that actually fit the viewport mount on open (~700 nodes now, dominated by the first "People" category), and drop overscan 2 -> 1 so an off-screen 500+ item category isn't eagerly built. Scroll/search, categories, recents and custom emoji/stickers are unchanged.
…guage setting
Add an in-app, client-side transcription action for voice/audio messages
(m.audio / m.voice). A microphone button next to the audio player opens an
app-only popover that requests a transcript from the local Whisper backend
(POST /transcribe with { room_id, event_id, mxc, language? }) and shows the
returned text plus the detected language, with copy-to-clipboard. The
transcript is cached in component state and is NEVER posted to the chat or
forwarded anywhere — it is a purely client-side overlay. Transcript text is
rendered strictly as text (untrusted content).
Adds a per-user default transcription language setting (General settings) and
optional backend URL/secret overrides. The API base and shared secret are
configurable via Vite env vars VITE_TRANSCRIBE_API_BASE and
VITE_TRANSCRIBE_API_SECRET (with settings overrides taking precedence), so the
endpoint can be re-pointed without a code change; no secret is hardcoded.
New files live under src/app/features/transcription/ to avoid overlap with the
parallel in-app translation feature. Shared files touched additively:
settings.ts (new fields), RenderMessageContent/AudioContent (thread roomId/
eventId to the button), General.tsx (settings section), RoomTimeline.tsx (pass
identifiers at the two message render sites).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add per-message translate button + auto-translate-all toggle to Cinny, backed by Chagai's on-box argos/"Libre" translation API (offline, no cloud translator). New self-contained `translation` feature (kept separate from the voice-note transcription UI to minimize merge conflicts): - Per-message "Translate" trigger under each text message with a language picker; shows the translation inline. Result cached per event+target. - Global "auto-translate everywhere into <lang>" toggle + language in a new Settings > Translation page; per-chat override in room settings General. - Settings persist in Matrix account data (`in.cinny.translation`) so they sync across devices; room override beats the global setting. - Backend URL + shared token read from public/config.json (ClientConfig.translation); feature hides itself when unconfigured. - Message text is only translated, never interpreted (injection-safe). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPNRaVnHM9hmpwYyewbeVj
…lback to Settings) Ship the on-box transcription API base+secret in public/config.json (mirrors the translation block) so the 🎤 transcribe button works out of the box on the static Netlify site. TranscribeButton falls back to config.json when the per-user Settings overrides are empty (precedence: Settings > config.json > built-in default). Also fill the translation token in config.json. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPNRaVnHM9hmpwYyewbeVj
useRooms() excludes DM rooms (mDirects check), so WA portal room IDs were stripped from the URL filter — producing [] (not undefined) — causing Synapse to receive `rooms: []` and return zero results. Fix 1: replace useRooms with new useAllJoinedRooms (no mDirects exclusion) so WA portals resolve correctly in the URL param filter. Fix 2: harden the resolved list — return undefined when all requested rooms fail to resolve (silent-empty guard) so the search falls back to the default scope instead of sending an empty room list. Fix 3: pass the full allRooms list (rooms + DMs) to SearchFilters so the room picker shows WA chats as selectable options. Co-Authored-By: Claude <noreply@anthropic.com>
Include DM/WhatsApp rooms in message search room filter. Fix: useAllJoinedRooms hook to bypass mDirects exclusion, harden empty-room-list → undefined fallback so Synapse gets correct scope.
There was a problem hiding this comment.
Pull request overview
This PR introduces a new user setting to suppress “dot-only” unread indicators (keeping numeric unread counts), and also bundles several additional UI and feature changes (translation, transcription, search scoping, reply preview improvements, and emoji board virtualization tuning).
Changes:
- Add
hideUnreadActivityDotssetting and apply it to unread badge rendering and “show room anyway” filtering when categories are collapsed. - Add in-app translation (account-data backed config, per-message translation UI, global/per-room auto-translate controls) and local Whisper transcription UI/actions.
- Adjust message search room scoping and tune EmojiBoard virtualization/overscan behavior.
Reviewed changes
Copilot reviewed 33 out of 33 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/app/state/settings.ts |
Adds new settings keys (hideUnreadActivityDots, transcription overrides) and defaults. |
src/app/state/hooks/roomList.ts |
Adds useAllJoinedRooms hook for broader “joined rooms” selection. |
src/app/pages/client/space/Space.tsx |
Applies hideUnreadActivityDots when deciding whether unread rooms keep categories open/visible. |
src/app/pages/client/home/Home.tsx |
Applies hideUnreadActivityDots when filtering rooms shown under collapsed categories. |
src/app/pages/client/direct/Direct.tsx |
Applies hideUnreadActivityDots when filtering directs shown under collapsed categories. |
src/app/hooks/useClientConfig.ts |
Extends client config type with translation and transcription configuration blocks. |
src/app/features/translation/useTranslation.ts |
Adds translation hooks (account-data config + per-event translation state + auto-translate logic). |
src/app/features/translation/translationConfig.ts |
Adds account-data persistence/read/write + resolution logic for per-room overrides. |
src/app/features/translation/translateApi.ts |
Adds translation backend client and in-memory caching. |
src/app/features/translation/RoomAutoTranslate.tsx |
Adds per-room auto-translate controls in room settings. |
src/app/features/translation/MessageTranslation.tsx |
Adds per-message translation UI (toggle, language picker, result rendering). |
src/app/features/translation/MessageTranslation.css.ts |
Styles for translation UI elements. |
src/app/features/translation/languages.ts |
Static language list + helpers for translation feature. |
src/app/features/transcription/TranscriptionSettings.tsx |
Adds general settings section for transcription language and backend overrides. |
src/app/features/transcription/TranscribeLanguageSelect.tsx |
Adds dropdown selector for transcription default language. |
src/app/features/transcription/TranscribeButton.tsx |
Adds per-audio-message “Transcribe” popover action with copy/retry handling. |
src/app/features/transcription/transcribeApi.ts |
Adds transcription backend client and error handling. |
src/app/features/transcription/languages.ts |
Static language list + helper for transcription feature. |
src/app/features/settings/translation/Translation.tsx |
Adds a settings page for global translation/auto-translate configuration. |
src/app/features/settings/translation/index.ts |
Exports the translation settings page. |
src/app/features/settings/Settings.tsx |
Adds “Translation” to the settings navigation and routes it to a new page. |
src/app/features/settings/notifications/SystemNotification.tsx |
Adds toggle UI for hideUnreadActivityDots. |
src/app/features/settings/general/General.tsx |
Includes the new TranscriptionSettings section. |
src/app/features/room/RoomTimeline.tsx |
Passes roomId/eventId down to message content rendering for transcription actions. |
src/app/features/room/message/Message.tsx |
Injects per-message translation UI under non-edit message content. |
src/app/features/room-settings/general/General.tsx |
Adds per-room auto-translate controls to room settings. |
src/app/features/message-search/MessageSearch.tsx |
Switches room source for search scoping + tweaks URL-room resolution behavior and filter list. |
src/app/components/unread-badge/UnreadBadge.tsx |
Hides dot-only unread badges when hideUnreadActivityDots is enabled. |
src/app/components/RenderMessageContent.tsx |
Adds optional roomId/eventId props and forwards them into AudioContent. |
src/app/components/message/Reply.tsx |
Improves reply previews for media messages (voice/audio/image/file/etc.) when no body is present. |
src/app/components/message/content/AudioContent.tsx |
Adds transcription button next to audio playback controls when identifiers are available. |
src/app/components/emoji-board/EmojiBoard.tsx |
Adjusts virtualizer overscan and adds better height estimation for emoji/sticker groups. |
config.json |
Adds translation/transcription config defaults (including endpoint/token fields). |
| "translation": { | ||
| "endpoint": "https://mx.chagai.website/translate-api", | ||
| "token": "oMBdfX9qUcwBl2TZMTNjYkC9YHuSdI2Cfne-57h8Pks", | ||
| "defaultTargetLang": "en" | ||
| }, | ||
|
|
||
| "transcription": { | ||
| "endpoint": "https://mx.chagai.website/apptranscribe", | ||
| "token": "UwTuImsqajz9PTXg7dMQb839PEPMKsaTWMRmde4V1NQ" | ||
| } |
| "translation": { | ||
| "endpoint": "https://mx.chagai.website/translate-api", | ||
| "token": "oMBdfX9qUcwBl2TZMTNjYkC9YHuSdI2Cfne-57h8Pks", | ||
| "defaultTargetLang": "en" | ||
| }, |
| export const useRoomAutoTranslate = (roomId: string): { auto: boolean; targetLang: string } => { | ||
| const { config } = useTranslationConfig(); | ||
| return useMemo(() => resolveRoomAutoTranslate(config, roomId), [config, roomId]); | ||
| }; |
| {t.error && ( | ||
| <Text size="T200" style={{ color: config.color?.critical, marginTop: config.space.S100 }}> | ||
| {`Translation failed: ${t.error}`} | ||
| </Text> |
|
Sorry I accidently kept on using the same branch 🤦🏻 |
The idea is to get rid of showing those type of unread rooms and keep only the ones with the number which are a lot more reliable and important.
This is how it looks before:

and this is after:
