import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { type DisplaySurfaceHint, getPresetParams, getScreenShareSettings, PRESET_ORDER, type ScreenSharePreset, updateScreenShareSettings, } from '../lib/screenShareSettings'; import { MonitorShareIcon, SpinnerIcon, XIcon, } from './icons'; interface Props { open: boolean; onClose: () => void; onStart: (opts: { preset: ScreenSharePreset; displaySurface: DisplaySurfaceHint; framerate: number | null; }) => Promise; } const FRAMERATE_OPTIONS: ReadonlyArray<{ value: number | null; label: string }> = [ { value: null, label: 'Preset-Standard' }, { value: 15, label: '15 fps' }, { value: 30, label: '30 fps' }, { value: 60, label: '60 fps' }, ]; // Discord-style pre-share dialog. The OS still owns the final source picker // (browser/OS limitation — only Chrome/Edge plus a native plugin can enumerate // windows from JS), but we pre-filter with the `displaySurface` hint and lock // in quality + framerate up-front so the user doesn't have to re-open the // system picker to adjust them mid-call. export function ScreenShareDialog({ open, onClose, onStart }: Props) { const { t } = useTranslation(['app']); const initial = getScreenShareSettings(); const [surface, setSurface] = useState(initial.displaySurface); const [preset, setPreset] = useState(initial.preset); const [framerate, setFramerate] = useState(initial.framerateOverride); const [includeAudio, setIncludeAudio] = useState(initial.includeSystemAudio); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); if (!open) return null; async function handleStart() { setBusy(true); setError(null); try { // Persist the audio choice alongside the other picker prefs so the // upstream startScreenShare picks it up on its settings read. updateScreenShareSettings({ includeSystemAudio: includeAudio }); await onStart({ preset, displaySurface: surface, framerate }); onClose(); } catch (err: unknown) { setError(err instanceof Error ? err.message : 'screenshare failed'); } finally { setBusy(false); } } const presetParams = getPresetParams(preset); const effectiveFps = framerate ?? presetParams.framerate; return (
e.stopPropagation()} className="flex w-full max-w-lg flex-col overflow-hidden rounded-2xl border border-line bg-surface-3 shadow-xl" >

{t('app:call.share_dialog_title', { defaultValue: 'Bildschirm teilen' })}

{t('app:call.share_surface', { defaultValue: 'Quelle' })}

setSurface(null)} label={t('app:call.share_any', { defaultValue: 'Alle anzeigen' })} sub={t('app:call.share_any_sub', { defaultValue: 'Bildschirm + Fenster' })} /> setSurface('monitor')} label={t('app:call.share_monitor', { defaultValue: 'Bildschirm' })} sub={t('app:call.share_monitor_sub', { defaultValue: 'Ganzer Monitor' })} /> setSurface('window')} label={t('app:call.share_window', { defaultValue: 'Fenster' })} sub={t('app:call.share_window_sub', { defaultValue: 'Einzelnes Fenster' })} />

{t('app:call.share_quality', { defaultValue: 'Qualität' })}

{t('app:call.share_fps', { defaultValue: 'Bildrate' })}

{FRAMERATE_OPTIONS.map((opt) => ( ))}

{t('app:call.share_fps_effective', { defaultValue: 'Effektiv: {{fps}} fps', fps: effectiveFps, })}

{error && (

{error}

)}

{t('app:call.share_hint', { defaultValue: 'Nach "Teilen starten" öffnet das Betriebssystem den Quellen-Picker. Qualität + Bildrate werden bereits angewendet.', })}

); } function SurfaceOption({ active, onClick, label, sub, }: { active: boolean; onClick: () => void; label: string; sub: string; }) { return ( ); }