Commit Graph
100 Commits
Author SHA1 Message Date
Jannis Braun 561c9bc4f3 feat: include width, height, duration in all attachment serialization 2026-03-21 17:20:04 +01:00
Jannis Braun 7c767b580a feat: extract media dimensions and video thumbnails on upload 2026-03-21 17:18:59 +01:00
Jannis Braun d0f33446de feat: add video thumbnail generation and media metadata extraction 2026-03-21 17:16:40 +01:00
Jannis Braun b74e33b349 feat: add width, height, duration columns to attachments schema 2026-03-21 17:15:09 +01:00
Jannis Braun 948fa6de5c feat(desktop): add remote dictionary sync engine to activity detector
Refactor loadDictionary to accept a file path and support both legacy
bare-array (version 0) and versioned object formats. Add background
sync that fetches the latest games.json from GitHub, uses ETag-based
conditional requests (304 support), atomic cache writes, and hot-swaps
processMap/gameEntries without resetting current detection state.
On startup, the best local source (cache vs bundled seed) is loaded
immediately for instant detection, then sync runs fire-and-forget.
2026-03-21 04:12:21 +01:00
Jannis Braun 228ffe4894 feat(desktop): expand game dictionary to 249 entries with versioned schema
Rewrite games.json from bare array (28 entries) to versioned format
{ version: 1, games: [...] } with 249 entries covering top Steam games,
competitive titles, AAA, indie, survival/craft, simulation, horror,
fighting, racing, MMOs, and media apps (Spotify, VLC, OBS, mpv).
Every process name is specific enough to avoid false-positive detection.
2026-03-21 04:12:15 +01:00
Jannis Braun 156189dfa2 fix: redesign activity cards with glass-pill material and accent borders
Replace bg-surface-elevated cards and inline text badges with glass-pill
rows featuring colored left borders (mint=playing, sky=listening,
lavender=watching, rose=streaming). Identical treatment in both
ActivityPanel and MemberSidebar — no more compact/full distinction.
Members with rich activities get the frosted glass row; others stay plain.
2026-03-21 03:50:09 +01:00
Jannis Braun 2c122d066e fix: add console warnings for invalid games.json entries 2026-03-21 03:00:14 +01:00
Jannis Braun 0f4f129337 feat(desktop): add automatic game/app activity detection
Add cross-platform process scanning that detects running games and apps,
then broadcasts them as Rich Presence activities via the existing Phase 1
pipeline (activityStore -> WS -> other users).

- games.json dictionary with 26 entries (games, Spotify, VLC, OBS)
- activityDetector module: polls OS process list every 15s via execFile,
  matches against dictionary, emits IPC on state change only
- IPC bridge in main.ts/preload.ts with cleanup on quit
- Frontend activityBridge subscribes to IPC and feeds activityStore
- Supports Windows (tasklist CSV), macOS (ps -c), Linux (ps)
2026-03-21 02:57:30 +01:00
Jannis Braun 568b049b22 ci: add GitHub Actions workflow for desktop release builds
Triggers on v* tag push, builds for Windows, macOS (arm64), and Linux.
Uses electron-builder --publish to upload artifacts to GitHub Releases.
2026-03-21 02:32:43 +01:00
Jannis Braun 2593f7075c feat(desktop): add version display and check-for-updates to account settings 2026-03-21 02:32:19 +01:00
Jannis Braun a9fcdb72a8 feat(desktop): add manual download fallback to UpdateToast
Extends UpdateToast to handle update-error events from the preload bridge,
showing a "Download" link to the GitHub release URL when auto-update fails.
2026-03-21 02:31:20 +01:00
Jannis Braun 6ebb124d25 feat(desktop): update preload bridge types for enhanced update-error and getVersion 2026-03-21 02:30:06 +01:00
Jannis Braun a7d5abfca9 feat(desktop): enhance update-error payload with release URL, add get-app-version IPC 2026-03-21 02:29:42 +01:00
Jannis Braun a234041210 feat(desktop): switch auto-update provider from generic to github 2026-03-21 02:29:28 +01:00
Jannis Braun 9e4878c48f fix: move showActivity toggle from Account to Privacy settings panel 2026-03-21 02:13:32 +01:00
Jannis Braun 1f4e149ee1 feat: add frontend Rich Presence — activityStore, ActivityCard, sidebar upgrades, settings toggle
- Task 7: Create activityStore (Zustand) with Map<userId, Activity[]>, showActivity toggle,
  debounced pushActivities, and reset on logout
- Task 8: Wire WS integration — presence_update propagates activities to store,
  ready payload initializes userActivities and showActivity (via setState to avoid side effects)
- Task 9: Create ActivityCard component with compact/full modes, type-colored labels,
  elapsed time display, asset images, and fallback to customStatus
- Task 10: Upgrade ActivityPanel to three groups — active friends (full cards, no header),
  online friends (compact), offline friends — using getPrimaryActivity for grouping
- Task 11: Upgrade MemberSidebar to show compact ActivityCards instead of raw customStatus
- Task 12: Add showActivity toggle in AccountPanel settings (Activity Status section)
  with API persistence and store sync
2026-03-21 01:55:17 +01:00
Jannis Braun 9403ded8da feat: add showActivity toggle to PATCH @me with activity broadcast clear
- Accept showActivity boolean in PATCH /api/users/@me body
- Validate and persist as integer in DB
- Update ConnectionManager cache on toggle
- Broadcast empty activities via presence_update when toggled off
2026-03-21 01:49:41 +01:00
Jannis Braun ceb8894d58 feat: add WS activity_update handler and enhanced presence_update with activities
- Add validateActivities() with full field validation against ACTIVITY_LIMITS
- Add handleActivityUpdate() with showActivity gate and rate limiting
- Enhance handlePresenceUpdate() to include activities in broadcast payload
- Update status cache via connectionManager.setUserStatus() on presence change
- Wire activity_update case into event router switch statement
2026-03-21 01:48:57 +01:00
Jannis Braun d4366a2207 feat: add ConnectionManager in-memory activity state and ready payload
Add Rich Presence infrastructure to ConnectionManager:
- Four new Maps: userActivities, userShowActivity, userStatuses, lastActivityUpdate
- Public accessors: set/get/clear activities, showActivity, status, rate limit check
- Cleanup in finalizeDisconnect() and forceDisconnectUser()
- Cache showActivity and status from DB at auth time in buildReadyPayload()
- Assemble userActivities snapshot in ready payload with customStatus fallback
- Include activities: [] in offline presence_update broadcast
2026-03-21 01:44:36 +01:00
Jannis Braun bc408235c9 feat: add Activity type system, DB migration, and self-only showActivity in sanitizeUser
- Add Activity, ActivityType, ActivityTimestamps, ActivityAssets types to shared types
- Add activity_update client event and activities field on presence_update server event
- Add userActivities to ready payload and showActivity to User/UpdateUserRequest
- Create shared activities.ts with ACTIVITY_LIMITS, ACTIVITY_PRIORITY, getPrimaryActivity
- Add show_activity column to users table (schema + migration)
- Update sanitizeUser with isSelf parameter; only include showActivity for self
- Fix .map(sanitizeUser) calls to use arrow wrapper to prevent index-as-boolean bug
- Mark auth routes (register/login) as isSelf=true since they return own user data
2026-03-21 01:38:36 +01:00
Jannis Braun ce981ee5fc fix: prevent metadata fetch from overwriting fallback thumbnail with null
Use logical OR when merging fetched metadata so null values from
failed og: extraction don't destroy valid defaults (e.g. YouTube
thumbnail set before the fetch).
2026-03-21 00:35:44 +01:00
Jannis Braun 1c7d8557c6 fix: use predictable YouTube thumbnail URL as fallback for embed poster
YouTube may block og:image extraction via BackspaceBot user-agent.
Use img.youtube.com/vi/{ID}/hqdefault.jpg as a guaranteed thumbnail
that doesn't require metadata fetching. If og:image is successfully
fetched, it overwrites the fallback.
2026-03-21 00:31:59 +01:00
Jannis Braun a3db74c7f7 fix: resolve YouTube Error 153 by adding origin param and removing no-referrer
YouTube's embed API requires knowing the embedding origin to authorize
playback. The referrerPolicy="no-referrer" was stripping the Referer
header, and the missing origin param meant youtube-nocookie.com couldn't
verify the embed source, causing Error 153 (video player configuration
error). Fix: pass origin param explicitly and let the browser send the
default referrer.
2026-03-21 00:26:32 +01:00
Jannis Braun c0133397e3 fix: resolve 4 media embed bugs from testing
1. Video aspect ratio: remove container border/overflow-hidden, use
   preload="metadata" so browser knows dimensions before play
2. YouTube Error 153: remove sandbox attr (too restrictive), add full
   allow permissions (encrypted-media, accelerometer, gyroscope, etc.)
3. Google Images not displaying: detect image Content-Type from HTTP
   response in metadataFetcher, override classifier to create image
   embed for URLs that serve image/* content
4. Audio seeking broken: add HTTP Range request support in uploads
   route (Accept-Ranges, Content-Range, 206 Partial Content)
2026-03-21 00:19:04 +01:00
Jannis Braun ff2decded5 fix: address code review issues for embeds implementation
- Fix ?? to || in metadataFetcher.ts to handle empty strings from Cheerio
- Fix stale embeds on message edit: delete old embeds synchronously before
  broadcast, then resolve new ones async (all 4 edit paths: REST+WS, msg+DM)
- Revert unrelated MessageList.tsx scroll threshold change (5000 not 150)
- Remove duplicate embed indexes from migrateAddIndexes (kept standalone ones)
2026-03-20 23:58:06 +01:00
Jannis Braun dcdf10c5de docs: update CLAUDE.md with embeds schema, WS events, and feature status 2026-03-20 23:50:48 +01:00
Jannis Braun 4486341007 feat: add embeds_resolved WS handlers and optimistic embeds:[] default
- chatStore: normalize embeds to [] in addMessage, addRealtimeMessage, and updateMessage to guard against missing field from older servers/federation
- useWebSocket: add embeds_resolved and dm_embeds_resolved cases that patch the in-memory message cache when the server broadcasts resolved embed data
- useWebSocket: normalize embed image URLs for remote origins in message_created, message_updated, dm_message_created, dm_message_updated, and the new embeds_resolved handlers
2026-03-20 23:49:15 +01:00
Jannis Braun 95762a1974 feat: replace Embed.tsx with AttachmentRenderer + EmbedRenderer in Message
Switches Message.tsx from client-side URL metadata fetching (old Embed.tsx)
to server-driven embed objects via message.embeds[]. Delegates attachment
rendering to AttachmentRenderer. Removes firstUrl extraction and urlRegex.
2026-03-20 23:47:16 +01:00
Jannis Braun 5a670bc6ad feat: add embed sub-components (Generic, Video, Image, Rich) and dispatcher 2026-03-20 23:45:32 +01:00
Jannis Braun a800d9ff25 feat: add AttachmentRenderer with video/audio inline playback 2026-03-20 23:43:31 +01:00
Jannis Braun 01ee7ab67a feat: wire embeds into all message query and creation paths
Integrate embed infrastructure into the complete message flow:
- messages.ts: batch-fetch embeds in GET, resolve on POST, re-resolve on PATCH
- dm.ts: same pattern for DM messages with isDm=true
- search.ts: include embeds in all 4 search/around endpoints
- events.ts: embed resolution in WS message create/edit for both space and DM
- Fix embedClassifier.ts type errors (regex match undefined → null)
- Add embeds: [] to all inline MessageWithUser/DmMessageWithUser constructions
- Add embeds: [] to chatStore optimistic message
2026-03-20 23:41:53 +01:00
Jannis Braun 5fe25fb077 feat: add embed resolver with async resolution and batch fetching 2026-03-20 23:33:21 +01:00
Jannis Braun 29cfd88a15 feat: add URL classifier for embed type detection 2026-03-20 23:30:13 +01:00
Jannis Braun de1c0b4ed8 refactor: extract metadata fetcher into reusable utility 2026-03-20 23:30:01 +01:00
Jannis Braun ebc1868dd1 feat: add embeds database table with schema and migration 2026-03-20 23:28:57 +01:00
Jannis Braun 009923a12f feat: add Embed types and extend MessageWithUser with embeds[] 2026-03-20 23:25:58 +01:00
Jannis Braun f7d388c9a8 fix: clean up redundant regex guard and differentiate copy icons 2026-03-20 22:23:15 +01:00
Jannis Braun 720a3c4553 feat: wire up enhanced message context menu with all actions 2026-03-20 22:19:12 +01:00
Jannis Braun 3aa7e93a4d feat: pass previousMessageId prop from MessageList to Message 2026-03-20 22:16:55 +01:00
Jannis Braun 8da412c0d4 feat: create message context menu builder function 2026-03-20 22:15:31 +01:00
Jannis Braun 896cb77b5c feat: add markUnread store action and WS handler 2026-03-20 22:13:47 +01:00
Jannis Braun 2e26f98246 feat: add mark_unread WebSocket event handler 2026-03-20 22:11:42 +01:00
Jannis Braun 3c23893549 feat: add mark_unread to WebSocket event types 2026-03-20 22:09:40 +01:00
Jannis Braun c90ba431e8 fix: resolve mentions in reply previews to display usernames
Reply preview was rendering raw <@userId> tokens as plain text instead
of resolving them to MentionBadge components with proper usernames.
2026-03-20 21:25:45 +01:00
Jannis Braun 9fe46ad19b fix: voice drop zone was swallowing channel reorder drops
handleVoiceDropZoneDrop called stopPropagation and clearState
unconditionally, preventing container's handleContainerDrop from
firing when dropping a channel onto a voice channel. Add early
return for non-voiceUser drags so channel/category drops bubble
through to the container handler correctly.
2026-03-20 21:15:13 +01:00
Jannis Braun 99e6f2f249 fix: normalize drop indicator to single line between channels
Port the SpaceSidebar normalization pattern: convert 'before B'
to 'after A' so only one drop indicator renders at any gap.
Fixes double-line visual glitch and unreliable drops when cursor
is between two channels. Also adjust indicator offsets from
top-0/bottom-0 to -top-[1px]/-bottom-[1px] to center in the gap.
2026-03-20 21:07:20 +01:00
Jannis Braun ebe34a710b refactor: update VoiceChannel to use useDragManager hook-provided handlers 2026-03-20 20:46:49 +01:00
Jannis Braun 439a71dc13 refactor: wire useDragManager handlers into ChannelSidebar JSX and ChannelItem 2026-03-20 20:45:30 +01:00
Jannis Braun 999c13cdab refactor: replace old drag state with useDragManager hook in ChannelSidebar 2026-03-20 20:43:41 +01:00
Jannis Braun eb6f4bf94e fix: stabilize useDragManager callback refs and containerHandlers memo
Remove activeDrag from drag-start dependency arrays to prevent
unnecessary re-renders during drag. Wrap containerHandlers in
useMemo for consistent reference stability.
2026-03-20 20:39:52 +01:00
Jannis Braun 2952799d00 feat: add auto-scroll during drag near sidebar edges 2026-03-20 20:35:47 +01:00
Jannis Braun a8befcc701 feat: add voice user and voice channel drop zone handler factories 2026-03-20 20:35:13 +01:00
Jannis Braun 23c102a3cb feat: add channel/category handler factories and container handlers 2026-03-20 20:34:37 +01:00
Jannis Braun 9670450eec feat: scaffold useDragManager hook with types and state 2026-03-20 20:34:05 +01:00
Jannis Braun eb835f7e22 docs: add system prompt and design system reference files 2026-03-20 19:06:10 +01:00
Jannis Braun 0dc3eb1884 fix: notify displaced tab when user joins voice from another session
When a user joins a voice channel while already connected from another
tab, the server now sends a 'displaced' reason on voice_disconnected.
The client tears down LiveKit and shows an informational toast.
2026-03-20 19:03:35 +01:00
Jannis Braun 68378c7d83 fix: deduplicate VolumeSliderItem and add missing stopPropagation
- Extract VolumeSliderItem to voiceMenuItems.tsx (was duplicated in
  VoiceUser.tsx and VoiceChannel.tsx)
- Add e.stopPropagation() to all imperative context menu handlers
  for consistency with useContextMenu hook behavior
2026-03-20 18:55:58 +01:00
Jannis Braun 443259a527 chore: delete old context menu components replaced by centralized system 2026-03-20 18:48:40 +01:00
Jannis Braun 8eb3fc84a5 refactor: migrate voice context menus to centralized store 2026-03-20 18:47:45 +01:00
Jannis Braun cba19e8b20 refactor: migrate SpaceSidebar context menus to centralized store 2026-03-20 18:41:17 +01:00
Jannis Braun 15af93b979 refactor: migrate ChannelSidebar context menus to centralized store 2026-03-20 18:35:55 +01:00
Jannis Braun 3ead68b3e7 refactor: migrate Message context menu to centralized store 2026-03-20 18:32:18 +01:00
Jannis Braun ba0243d88c feat: mount ContextMenuRenderer in AppLayout 2026-03-20 18:30:58 +01:00
Jannis Braun 9e93734719 feat: add centralized ContextMenuRenderer with submenu and mobile support 2026-03-20 18:28:10 +01:00
Jannis Braun 6fb8801960 feat: add useContextMenu consumer hook 2026-03-20 18:24:44 +01:00
Jannis Braun 9a1b266760 feat: add context menu Zustand store and types 2026-03-20 18:24:25 +01:00
Jannis Braun e3e3eb82ff fix: restore missing logo and fix mobile space icon URLs
Restore logo.png lost during fast-forward merge and replace broken
resolveAssetUrl pattern in MobileSpacesScreen with proven desktop logic.
2026-03-17 16:16:09 +01:00
Jannis Braun f505f6578b fix(mobile): add viewport-fit=cover for safe area insets on notched devices 2026-03-17 15:55:06 +01:00
Jannis Braun ed70099963 fix(mobile): resolve all TypeScript errors from integration
- Fix voiceStore method names (toggleMic, leaveVoice, setCurrentVoiceChannel)
- Fix MemberWithUser nested user property access
- Pass required channelId props to MessageList, TypingIndicator, MessageInput
- Fix ConfirmDialog props (isOpen, description, variant, onClose)
- Add mobileStyle prop to Modal component (fullscreen + sheet modes)
- Fix fromId/isAdmin camelCase property names
- Guard possibly undefined touch events and array accesses
- Fix notification channelId resolution
2026-03-17 15:54:39 +01:00
Jannis Braun 7619b091da feat(mobile): route user profile to pushed screen instead of popout 2026-03-17 15:49:36 +01:00
Jannis Braun 1e0e957824 feat(mobile): route notification taps through mobile screen stack 2026-03-17 15:48:23 +01:00
Jannis Braun 206a0491ea feat(mobile): add full-screen voice view with controls 2026-03-17 15:47:41 +01:00
Jannis Braun 913b4c7365 feat(mobile): add mobileStyle to all modals (sheet for forms, fullscreen for settings) 2026-03-17 15:46:28 +01:00
Jannis Braun a073613b43 feat(mobile): disable tooltips, render context menus as bottom sheets 2026-03-17 15:44:46 +01:00
Jannis Braun 183290ef07 fix(mobile): stacked Add Friend input, responsive tab bar, mobile header 2026-03-17 15:43:43 +01:00
Jannis Braun 2790e9e088 feat(mobile): add voice mini-bar with quick controls 2026-03-17 15:42:16 +01:00
Jannis Braun af84674963 feat(mobile): add MobileSettingsScreen with drill-down navigation 2026-03-17 15:41:19 +01:00
Jannis Braun 934a1b85a7 feat(mobile): add MobileYouScreen with profile card and action links 2026-03-17 15:40:23 +01:00
Jannis Braun 49e4402802 feat(mobile): add MobileDmsScreen with activity row and DM list 2026-03-17 15:39:19 +01:00
Jannis Braun 0222946f04 feat(mobile): add swipe-from-left-edge back gesture 2026-03-17 15:37:27 +01:00
Jannis Braun e45bf1927e feat(mobile): add MobileChatScreen with back nav and member list access 2026-03-17 15:36:50 +01:00
Jannis Braun eac4e5f5eb feat(mobile): add MobileSpacesScreen with space strip and channel list 2026-03-17 15:35:53 +01:00
Jannis Braun 8463ca9ba8 feat(mobile): add MobileShell and split AppLayout for mobile/desktop 2026-03-17 15:32:52 +01:00
Jannis Braun 2386f497aa feat(mobile): add 3-tab bottom nav with unread badges 2026-03-17 15:31:06 +01:00
Jannis Braun cbfff701ce feat(mobile): add MobileScreenStack transition manager 2026-03-17 15:30:10 +01:00
Jannis Braun b0647fccb6 feat(mobile): add slide-up-sheet animation and screen transition CSS 2026-03-17 15:29:41 +01:00
Jannis Braun 8bd74ec608 feat(mobile): add screen stack navigation state to uiStore 2026-03-17 15:28:36 +01:00
Jannis Braun 8dda8b0b83 chore: add .worktrees/ to .gitignore 2026-03-17 15:26:43 +01:00
Jannis Braun ac7d3cb71b feat: add start-at-boot setting and fix tray icon to use app logo
Add auto-launch settings (start at boot + start minimized) to the
Desktop section in Account settings, using Electron's built-in
setLoginItemSettings API across macOS, Windows, and Linux.

Replace the fallback colored-circle tray icon with proper B logo assets:
template images for macOS (adapts to light/dark menu bar) and colored
icons for Windows/Linux. Fix BGRA channel order bug in fallback generator
and move tray icons to resources/ so they're packaged into the app.
2026-03-17 02:28:38 +01:00
Jannis Braun e5f89d4c3f feat: persist scroll position per channel with Jump to Present button
- Save the top-visible message ID on channel leave, restore via
  scrollIntoView on return (immune to lazy-loaded image reflow)
- Add floating glass-bubble "Jump to Present" button when scrolled
  5000px+ from bottom
- Clear stale scroll anchors when user returns to bottom
- Evict scroll positions alongside channel cache eviction
2026-03-17 01:46:25 +01:00
Jannis Braun 42e765b877 fix: use capture-phase load listener to scroll chat after GIF/image load
ResizeObserver alone misses scroll adjustments when multiple images load
in quick succession due to browser layout-loop suppression. A capture-phase
load event listener on the content wrapper reliably catches all descendant
image loads and re-scrolls to bottom.
2026-03-17 00:53:41 +01:00
Jannis Braun cbef0fe0f8 fix: resolve federated avatar double-path URL that broke cross-instance profile pictures
profileSync stored avatar/banner paths with /api/uploads/ prefix on remote
instances, causing resolveAssetUrl to produce double-path URLs like
https://remote/api/uploads//api/uploads/file.jpg that 404'd. Store bare
filenames instead, strip prefix defensively in resolveAssetUrl and server-side
for existing data self-healing.
2026-03-17 00:36:45 +01:00
Jannis Braun bc4dd81632 fix: exclude voice channels from unread computation to eliminate ghost notifications
Voice channels rendered with VoiceChannel component have no text reading/acking
UI, so messages in them created phantom unread indicators on the space sidebar
that users could never clear. Root cause was a message in the counter-strike
voice channel with no read state.

Three-layer fix:
- spaceStore: track voiceChannelIds set, exclude voice channels from
  channelLastMessageIds so setReadStates never marks them unread
- useWebSocket: skip markChannelUnread for voice channels on message_created,
  prune orphaned unreads on every ready event
- chatStore: validate preserved unreads against channelToSpaceMap to drop
  orphans that don't map to any known channel
2026-03-16 23:57:24 +01:00
Jannis Braun bf64c4678b fix: prevent logout 401 and login double-attempt caused by LWW layout push race
resetUserStores() was abusing populateFromReady('', [], [], []) to clear the
space store. Its LWW timestamp logic fired an async pushLayoutToOrigin when
_layoutUpdatedAt > 0, which read a null token from localStorage (already
removed on logout, not yet set on login). The 401 response triggered
handleUnauthorized(), deleting the freshly-stored login token and forcing a
full page reload — requiring users to log in twice.

Replace with a proper reset() method that synchronously sets all state to
initial values with no LWW comparison or API side effects.
2026-03-16 22:52:32 +01:00
Jannis Braun 1c806be94f fix: clear message cache on reconnect to prevent stale scroll position
After a server restart, navigating to a previously-visited channel showed
messages at a stale middle position instead of scrolling to the bottom.
The in-memory message cache survived the reconnect, so loadMessages()
bailed (cache hit) and the scroll-to-bottom logic never fired.

Now the ready handler clears the messages and hasMore maps for all
channels belonging to the reconnecting origin (including DMs for home).
The currently open channel is force-reloaded immediately; other channels
get fresh-fetched on next visit, triggering proper scroll-to-bottom.

Also fixes voice channel settings gear icon placement to match text
channels (flex-1 pushes icon to right edge).
2026-03-16 22:34:21 +01:00
Jannis Braun bfecb41c66 fix: derive voice sidebar from LiveKit participants to eliminate desync
The channel sidebar voice user list was maintained by a separate
voiceUsers Map (fed by WS events + fragile hydration code) that diverged
from reality after server restarts — users shown in wrong channels,
duplicated across channels. The VoiceGrid was always correct because it
reads LiveKit participants directly.

Now VoiceChannel.tsx derives its user list from LiveKit participants for
the connected channel (single source of truth) and only falls back to
server-provided voiceUsers for channels the user is not connected to.

Removed all hydration band-aids that tried to sync the two systems:
- useLiveKit ParticipantDisconnected → removeVoiceUser
- useLiveKit ConnectionStateChanged → addVoiceUser hydration loop
- useWebSocket ready handler → dynamic import LiveKit hydration

Also includes: voice channel settings gear icon on hover, persist
per-user volume/mute prefs across sessions, default screen share
audio off on Electron (no system audio capture support).
2026-03-16 22:10:53 +01:00
Jannis Braun e809adff3e fix: sync channel sidebar voice users with LiveKit participant disconnects
The sidebar used voiceStore.voiceUsers (WebSocket-driven, 5s delay) while
voice panels used LiveKit's real-time participants. Now ParticipantDisconnected
also removes the user from voiceUsers for immediate sidebar updates.
2026-03-16 20:41:36 +01:00
Jannis Braun e9c43f21f1 fix: eliminate phantom notifications across the entire read-state pipeline
Root cause: own messages echoed by the server marked channels unread when
the user had already navigated away. Seven related bugs compounded the
problem — stale read states, missing cleanup on space/DM removal, REST
broadcast ignoring VIEW_CHANNEL, and no validation on channel_ack writes.

Frontend:
- Skip markChannelUnread for the user's own messages (federation-aware)
- Walk backward past temp_ IDs in ackChannel instead of bailing
- Re-fire ack timer when temp message is replaced by server-confirmed ID
- Add removeChannelStates to clean up unread/read/message caches
- Clean up chatStore on removeSpace, removeDmChannel, removeInstanceSpaces

Server:
- Use sendToChannel instead of sendToSpace for REST message creation
- Clean up read_states on space deletion, member kick/leave, and ban
- Validate channel membership before accepting channel_ack writes
- Clean up read_states on DM leave and DM channel deletion
2026-03-16 20:20:25 +01:00
Jannis Braun 0815963e1b fix: update screen share audio warning to recommend Chrome browser 2026-03-16 19:27:12 +01:00