feat(desktop): port v0.11.4-v0.15.2 from Tauri to Electron + Discord-parity audio (v0.16.0)

Chronological port of every Tauri release commit (v0.11.4 -> v0.15.2)
into the Electron rebuild, plus Discord-style audio handling that goes
beyond the Tauri original.

Highlights:
  - All 17 Tauri release commits ported (audio fixes, custom notification
    sound, Discord-style chat UX, profile banner, changelog page,
    Discord-parity call UX, screen-share echo + re-watch UX, audio-loop
    fix).
  - Native napi-rs audio-loopback addon with WASAPI process-loopback:
      * EXCLUDE_TARGET_PROCESS_TREE for full-screen shares -> peers
        never hear themselves echoed back through the capture.
      * INCLUDE_TARGET_PROCESS_TREE for window shares -> only the
        picked window's audio is captured, not the whole OS mixer
        (Discord parity).
      * HWND -> PID resolution via Win32 GetWindowThreadProcessId.
  - Discord-style screen-source picker (thumbnail grid, screens vs
    apps tabs, live-refreshing thumbnails).
  - Hash routing fix for packaged builds (file:// can't resolve
    BrowserRouter paths).
  - Tauri sources removed (apps/desktop/src-tauri).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
byGalax
2026-05-06 23:35:01 +02:00
parent 72d02e385f
commit 825160ee46
504 changed files with 14217 additions and 14366 deletions
+42 -6
View File
@@ -3,6 +3,7 @@ import {
getOwnProfile,
signOut as supabaseSignOut,
type Profile,
touchDeviceLastSeen,
updateOwnProfile,
} from '@chat-app/shared/auth';
import { changeLocale, isSupportedLocale } from '@chat-app/shared/i18n';
@@ -14,11 +15,13 @@ import {
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import { findExistingDevice } from '../lib/device';
import { PRESENCE_HEARTBEAT_MS } from '../lib/presence';
import { setSecretStoreUser } from '../lib/secretStore';
import { supabase } from '../lib/supabase';
import { registerWebPush } from '../lib/webPush';
@@ -46,6 +49,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const [profile, setProfile] = useState<Profile | null>(null);
const [device, setDevice] = useState<DeviceRecord | null>(null);
const [deviceLookupDone, setDeviceLookupDone] = useState(false);
const autoOnlineUserRef = useRef<string | null>(null);
// Initial session + auth subscription. We verify the cached JWT against the
// server (via getUser) once on mount. Only purge the session on an
@@ -154,8 +158,14 @@ export function AuthProvider({ children }: { children: ReactNode }) {
// request usually slips through; the next page load corrects state if it
// didn't.
useEffect(() => {
if (!session || !profile) return;
if (profile.presenceState === 'offline') {
if (!session) {
autoOnlineUserRef.current = null;
return;
}
if (!profile) return;
const shouldApplyInitialAutoOnline = autoOnlineUserRef.current !== session.user.id;
autoOnlineUserRef.current = session.user.id;
if (profile.presenceState === 'offline' && shouldApplyInitialAutoOnline) {
void updateOwnProfile(supabase, { presenceState: 'online' })
.then(() => refreshProfile())
.catch((err: unknown) => {
@@ -165,10 +175,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const onLeave = () => {
// Skip if user explicitly chose a non-online state — they probably
// want to look unavailable on next reconnect too.
if (
profile.presenceState !== 'online' &&
profile.presenceState !== 'offline'
) {
if (profile.presenceState !== 'online' && profile.presenceState !== 'offline') {
return;
}
void updateOwnProfile(supabase, { presenceState: 'offline' }).catch(() => {});
@@ -181,7 +188,36 @@ export function AuthProvider({ children }: { children: ReactNode }) {
};
}, [session, profile, refreshProfile]);
useEffect(() => {
if (!session || !device?.id) return;
const touch = () => {
void touchDeviceLastSeen(supabase, device.id).catch((err: unknown) => {
console.warn('presence heartbeat failed', err);
});
};
const touchWhenVisible = () => {
if (document.visibilityState === 'visible') touch();
};
touch();
const heartbeat = window.setInterval(touch, PRESENCE_HEARTBEAT_MS);
window.addEventListener('focus', touch);
window.addEventListener('online', touch);
document.addEventListener('visibilitychange', touchWhenVisible);
return () => {
window.clearInterval(heartbeat);
window.removeEventListener('focus', touch);
window.removeEventListener('online', touch);
document.removeEventListener('visibilitychange', touchWhenVisible);
};
}, [session, device?.id]);
const signOut = useCallback(async () => {
await updateOwnProfile(supabase, { presenceState: 'offline' }).catch((err: unknown) => {
console.warn('offline update before sign-out failed', err);
});
await supabaseSignOut(supabase);
}, []);