feat: full Discord-style presence tracking

- Announce online immediately on app startup
- Idle detection: unavailable after 10 min of no input, online on return
- Tab visibility: unavailable when hidden, online when focused again
- Page close: offline via fetch+keepalive (survives unload without bfcache penalty)
- hidePresence setting: broadcasts offline and stops all tracking
- Added 'Hide Online Status' toggle in General settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 19:28:52 -04:00
parent eb283c29ff
commit 08b1a5c2a3
4 changed files with 115 additions and 0 deletions
@@ -26,6 +26,7 @@ import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
import { useInboxNotificationsSelected } from '../../hooks/router/useInbox';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { usePresenceUpdater } from '../../hooks/usePresenceUpdater';
function SystemEmojiFeature() {
const [twitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');
@@ -127,6 +128,11 @@ function InviteNotifications() {
);
}
function PresenceUpdater() {
usePresenceUpdater();
return null;
}
function MessageNotifications() {
const audioRef = useRef<HTMLAudioElement>(null);
const notifRef = useRef<Notification | undefined>(undefined);
@@ -261,6 +267,7 @@ export function ClientNonUIFeatures({ children }: ClientNonUIFeaturesProps) {
<SystemEmojiFeature />
<PageZoomFeature />
<FaviconUpdater />
<PresenceUpdater />
<InviteNotifications />
<MessageNotifications />
{children}