import { useAtomValue } from "@effect/atom-react";import { isModifierPairShortcut, type ClientSettingsPatch, type DesktopSnapShotShortcutAvailability, type DesktopSnapShotState, type DesktopSnapShotSetupAction, type SnapShotShortcut,} from "@t3tools/contracts";import { ChevronDownIcon, PlayIcon } from "lucide-react";import { useCallback, useEffect, useRef, useState } from "react"; import { cn } from "~/lib/utils"; import { useClientSettings, useUpdateClientSettings } from "../../hooks/useSettings";import { getDesktopSnapShotBridge } from "../../lib/desktopSnapShot";import { readSnapShotSetupResume, saveSnapShotSetupResume, clearSnapShotSetupResume,} from "../../lib/snapShotSetupResume";import { sameSnapShotShortcut, snapShotKeybindingConflict } from "../../lib/snapShotShortcut";import { playSnapShotSound } from "../../lib/snapShotSound";import { primaryServerKeybindingsAtom } from "../../state/server";import { commandLabel } from "./KeybindingsSettings.logic";import { snapShotStatus, snapShotShortcutStatus, snapShotSetupButtonLabel, snapShotUnavailableMessage, snapShotSoundPatch, snapShotFeedbackUnavailableMessage, snapShotDescription, snapShotAccessibilityUnavailableMessage, snapShotSetupComplete, type SnapShotSoundSelection,} from "./SnapShotSettings.logic";import { SettingsUnavailableGroup, SettingsPageContainer, SettingsRow, SettingsSection,} from "./settingsLayout";import { searchableSetting } from "./settingsSearch";import { Button } from "../ui/button";import { Menu, MenuItem, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuTrigger } from "../ui/menu";import { selectTriggerVariants } from "../ui/select";import { Switch } from "../ui/switch";import { toastManager } from "../ui/toast";import { SnapShotSetupDialog } from "./SnapShotSetupDialog";import { useSnapShotShortcutRecorder } from "./useSnapShotShortcutRecorder";import { captureSetupAccessReady, captureSetupInitialStep, captureSetupShouldDisableOnClose, type CaptureSetupStep,} from "./SnapShotSetupDialog.logic"; const soundOptionRowClassName = "grid grid-cols-[1fr_auto] rounded-sm has-data-checked:bg-foreground/[0.08]";const soundOptionItemClassName = "data-checked:bg-transparent";const soundPreviewClassName = "min-h-7 w-7 justify-center px-0"; function captureSettingsError(title: string, error: unknown) { return { title, message: error instanceof Error ? error.message : "Try again." };} type ShortcutCheck = | { readonly status: "idle"; readonly availability: null } | { readonly status: "checking"; readonly availability: null } | { readonly status: "checked"; readonly availability: DesktopSnapShotShortcutAvailability; }; export function SnapShotSettings() { const settings = useClientSettings(); const updateSettings = useUpdateClientSettings(); const keybindings = useAtomValue(primaryServerKeybindingsAtom); const bridge = getDesktopSnapShotBridge(); const [state, setState] = useState<DesktopSnapShotState | null>(null); const [setupBusy, setSetupBusy] = useState(false); const [setupError, setSetupError] = useState<ReturnType<typeof captureSettingsError> | null>( null, ); const [wizard, setWizard] = useState<{ initialStep: CaptureSetupStep; wasEnabled: boolean; } | null>(null); const [candidate, setCandidate] = useState<SnapShotShortcut>(settings.snapShotShortcut); const [shortcutCheck, setShortcutCheck] = useState<ShortcutCheck>({ status: "idle", availability: null, }); const shortcutCheckIdRef = useRef(0); const stateRequestIdRef = useRef(0); const unavailableMessage = snapShotUnavailableMessage(Boolean(bridge)); const captureAvailable = Boolean(bridge) && state !== null && state.mode !== "unavailable"; const feedbackUnavailable = snapShotFeedbackUnavailableMessage(state); const savedShortcut = settings.snapShotShortcut; const managedShortcut = state?.linuxBackend === "niri" || state?.linuxBackend === "hyprland"; const shortcutChanged = !managedShortcut && !sameSnapShotShortcut(candidate, savedShortcut); const displayShortcut = shortcutChanged ? candidate : (state?.shortcut ?? savedShortcut); const candidateConflict = shortcutChanged ? snapShotKeybindingConflict(candidate, keybindings) : null; const canSaveShortcut = shortcutChanged && candidateConflict === null && shortcutCheck.availability?.available === true; const soundSelection = settings.snapShotPlaySound ? settings.snapShotSound : "off"; const soundLabel = soundSelection === "off" ? "Off" : soundSelection === "soft-pop" ? "Whoosh (Default)" : "Click"; const refreshState = useCallback(async () => { const requestId = ++stateRequestIdRef.current; try { if (bridge) { const nextState = await bridge.getSnapShotState(); if (requestId === stateRequestIdRef.current) setState(nextState); return nextState; } } catch (error) { if (requestId === stateRequestIdRef.current) setSetupError(captureSettingsError("Couldn't check capture setup", error)); } }, [bridge]); const setup = useCallback( async (action: DesktopSnapShotSetupAction) => { if (!bridge?.setupSnapShot || setupBusy) return; setSetupBusy(true); setSetupError(null); try { if ( state?.macPermissions && wizard && (action === "allow-screen-recording" || action === "allow-accessibility") ) { // macOS can quit the app from its permission prompt. saveSnapShotSetupResume(wizard.wasEnabled); } await bridge.setupSnapShot(action); await refreshState(); } catch (error) { setSetupError( captureSettingsError( action === "retry-shortcut" ? "Couldn't open shortcut permissions" : "Couldn't complete capture setup", error, ), ); } finally { setSetupBusy(false); } }, [bridge, refreshState, setupBusy, state, wizard], ); useEffect(() => { if (!setupError || wizard) return; toastManager.add({ type: "error", title: setupError.title, description: setupError.message, }); setSetupError(null); }, [setupError, wizard]); useEffect(() => { let cancelled = false; void refreshState().then((current) => { const resume = readSnapShotSetupResume(); if (!cancelled && current?.macPermissions && resume) { setWizard({ initialStep: "access", wasEnabled: resume.wasEnabled }); } }); window.addEventListener("focus", refreshState); return () => { cancelled = true; window.removeEventListener("focus", refreshState); }; }, [refreshState]); useEffect( () => bridge?.onSnapShotEvent((event) => { if (event.type === "shortcut-changed") void refreshState(); }), [bridge, refreshState], ); useEffect(() => { shortcutCheckIdRef.current++; setCandidate(savedShortcut); setShortcutCheck({ status: "idle", availability: null }); }, [savedShortcut]); const save = useCallback( async (patch: ClientSettingsPatch) => { setSetupError(null); try { await updateSettings(patch); return await refreshState(); } catch (error) { setSetupError(captureSettingsError("Couldn't save capture settings", error)); } }, [refreshState, updateSettings], ); const saveIncludeAccessibility = useCallback( async (includeAccessibility: boolean) => { try { if (includeAccessibility && settings.snapShotEnabled) await bridge?.requestSnapShotPermissions(true); await save({ snapShotIncludeAccessibility: includeAccessibility }); } catch (error) { setSetupError(captureSettingsError("Couldn't allow app text capture", error)); } }, [bridge, save, settings.snapShotEnabled], ); const checkShortcut = useCallback( async (shortcut: SnapShotShortcut) => { const checkId = ++shortcutCheckIdRef.current; setCandidate(shortcut); const conflict = snapShotKeybindingConflict(shortcut, keybindings); if (conflict || !bridge) return; setShortcutCheck({ status: "checking", availability: null }); try { const availability = await bridge.checkSnapShotShortcut(shortcut); if (checkId === shortcutCheckIdRef.current) { setShortcutCheck({ status: "checked", availability }); } } catch (error) { if (checkId !== shortcutCheckIdRef.current) return; setShortcutCheck({ status: "checked", availability: { available: false, message: error instanceof Error ? error.message : "Could not check this shortcut.", }, }); } }, [bridge, keybindings], ); const { recording, stopRecording, input: shortcutInput, } = useSnapShotShortcutRecorder({ shortcut: displayShortcut, shortcutLabel: !shortcutChanged ? state?.shortcutLabel : undefined, disabled: setupBusy, allowModifierPairs: state?.mode !== "portal", onRecord: (shortcut) => void checkShortcut(shortcut), onStart: () => { shortcutCheckIdRef.current++; setShortcutCheck({ status: "idle", availability: null }); }, onError: (message) => setShortcutCheck({ status: "checked", availability: { available: false, message } }), }); const shortcutStatus = recording ? "Press your shortcut. Esc cancels." : candidateConflict ? `T3 Code already uses this for "${commandLabel(candidateConflict)}".` : shortcutCheck.status === "checking" ? "Checking shortcut…" : shortcutCheck.availability ? shortcutCheck.availability.available ? "Ready to save." : shortcutCheck.availability.message : state?.mode === "portal" && !state.shortcutLabel && isModifierPairShortcut(displayShortcut) ? "Try a shortcut such as Ctrl+Shift+2." : snapShotShortcutStatus(state); const openSetup = async (requested: CaptureSetupStep | "resume" = "resume") => { if (!state || setupBusy) return; stopRecording(); shortcutCheckIdRef.current++; setCandidate(savedShortcut); setShortcutCheck({ status: "idle", availability: null }); setSetupError(null); setSetupBusy(true); try { let current = await refreshState(); if (!current) return; if (current.macPermissions) requested = "access"; if (!settings.snapShotEnabled && captureSetupInitialStep(current, requested) !== "access") { // Opening setup is the opt-in. Restore registration before resuming a // later step, just as Continue does on the access step. current = await save({ snapShotEnabled: true }); if (!current) { // A settings write can succeed even if the following status check // fails. Keep Finish later available to turn capture back off. setWizard({ initialStep: "access", wasEnabled: false }); return; } } setWizard({ initialStep: captureSetupInitialStep(current, requested), wasEnabled: settings.snapShotEnabled, }); } finally { setSetupBusy(false); } }; const enableForSetup = async () => { if (setupBusy) return false; setSetupBusy(true); setSetupError(null); try { if (state?.macPermissions) { saveSnapShotSetupResume(wizard?.wasEnabled ?? settings.snapShotEnabled); if (!bridge?.setupSnapShot) throw new Error("Restart T3 Code to finish capture setup."); await bridge.setupSnapShot("test-mac-capture"); } if (state?.mode === "direct") await bridge?.requestSnapShotPermissions(settings.snapShotIncludeAccessibility); const nextState = settings.snapShotEnabled && !state?.message ? await refreshState() : await save({ snapShotEnabled: true }); return nextState !== undefined && captureSetupAccessReady(nextState); } catch (error) { setSetupError(captureSettingsError("Couldn't verify capture access", error)); return false; } finally { setSetupBusy(false); } }; const refreshSetup = useCallback(() => { setSetupError(null); return refreshState(); }, [refreshState]); const closeSetup = async (completed: boolean) => { if (!wizard || setupBusy) return; setSetupBusy(true); try { if ( settings.snapShotEnabled && captureSetupShouldDisableOnClose(wizard.wasEnabled, completed) ) { if (!(await save({ snapShotEnabled: false }))) return; } stopRecording(); setSetupError(null); clearSnapShotSetupResume(); setWizard(null); } catch (error) { setSetupError(captureSettingsError("Couldn't close capture setup", error)); } finally { setSetupBusy(false); } }; const saveShortcut = async () => { if (!canSaveShortcut || setupBusy) return false; setSetupBusy(true); try { const saved = await save({ snapShotShortcut: candidate }); return Boolean(saved?.shortcutRegistered || saved?.shortcutPending); } finally { setSetupBusy(false); } }; return ( <SettingsPageContainer> <SettingsSection id="snap-shot" title="SnapShots"> <SettingsUnavailableGroup message={unavailableMessage}> <SettingsRow {...searchableSetting("snap-shot-enabled")} description={snapShotDescription(state)} status={ bridge ? setupBusy && !wizard ? "Updating capture settings…" : snapShotStatus(state, settings.snapShotEnabled) : undefined } control={ <> {settings.snapShotEnabled && !snapShotSetupComplete(state, settings.snapShotIncludeAccessibility) ? ( <Button size="xs" variant="outline" disabled={setupBusy} onClick={() => void openSetup()} > {snapShotSetupButtonLabel(state)} </Button> ) : null} <Switch checked={settings.snapShotEnabled || Boolean(wizard)} disabled={!captureAvailable || setupBusy} aria-label="Enable snapshots" onCheckedChange={(checked) => { if (!checked) void save({ snapShotEnabled: false }); else if (state?.windows) void save({ snapShotEnabled: true }); else void openSetup(); }} /> </> } /> {settings.snapShotEnabled && captureAvailable ? ( <> <SettingsRow {...searchableSetting("snap-shot-accessibility")} description="Include text and controls when the app makes them available." status={snapShotAccessibilityUnavailableMessage(state)} control={ <Switch checked={ !snapShotAccessibilityUnavailableMessage(state) && settings.snapShotIncludeAccessibility } disabled={ !captureAvailable || Boolean(snapShotAccessibilityUnavailableMessage(state)) } aria-label="Include app text in snapshots" onCheckedChange={(checked) => void saveIncludeAccessibility(checked)} /> } /> <SettingsRow {...searchableSetting("snap-shot-shortcut")} description={ state?.linuxBackend === "picker" ? "Choose a window to capture from any app." : "Capture the window you're using without switching apps." } status={managedShortcut ? undefined : shortcutStatus} control={ managedShortcut ? ( <Button size="xs" variant="outline" disabled={setupBusy} onClick={() => void openSetup("shortcut")} > Change shortcut </Button> ) : ( <> {shortcutInput} {shortcutChanged ? ( <> <Button size="xs" disabled={!canSaveShortcut || setupBusy} onClick={() => void saveShortcut()} > {setupBusy ? "Saving…" : "Save"} </Button> <Button size="xs" variant="ghost" disabled={setupBusy} onClick={() => { stopRecording(); shortcutCheckIdRef.current++; setCandidate(savedShortcut); setShortcutCheck({ status: "idle", availability: null }); }} > Cancel </Button> </> ) : state?.mode === "portal" && state.shortcutCanRetry !== false && !isModifierPairShortcut(savedShortcut) ? ( <Button size="xs" variant="ghost" disabled={setupBusy || state.shortcutPending} onClick={() => void setup("retry-shortcut")} > Shortcut permissions </Button> ) : null} </> ) } /> <SettingsRow {...searchableSetting("snap-shot-sound")} description="Choose the sound played when capture starts."Lines 1–500 of 622. Load more
import { useAtomValue } from "@effect/atom-react"; import { isModifierPairShortcut, type ClientSettingsPatch, type DesktopSnapShotShortcutAvailability, type DesktopSnapShotState, type DesktopSnapShotSetupAction, type SnapShotShortcut, } from "@t3tools/contracts"; import { ChevronDownIcon, PlayIcon } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { cn } from "~/lib/utils"; import { useClientSettings, useUpdateClientSettings } from "../../hooks/useSettings"; import { getDesktopSnapShotBridge } from "../../lib/desktopSnapShot"; import { readSnapShotSetupResume, saveSnapShotSetupResume, clearSnapShotSetupResume, } from "../../lib/snapShotSetupResume"; import { sameSnapShotShortcut, snapShotKeybindingConflict } from "../../lib/snapShotShortcut"; import { playSnapShotSound } from "../../lib/snapShotSound"; import { primaryServerKeybindingsAtom } from "../../state/server"; import { commandLabel } from "./KeybindingsSettings.logic"; import { snapShotStatus, snapShotShortcutStatus, snapShotSetupButtonLabel, snapShotUnavailableMessage, snapShotSoundPatch, snapShotFeedbackUnavailableMessage, snapShotDescription, snapShotAccessibilityUnavailableMessage, snapShotSetupComplete, type SnapShotSoundSelection, } from "./SnapShotSettings.logic"; import { SettingsUnavailableGroup, SettingsPageContainer, SettingsRow, SettingsSection, } from "./settingsLayout"; import { searchableSetting } from "./settingsSearch"; import { Button } from "../ui/button"; import { Menu, MenuItem, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuTrigger } from "../ui/menu"; import { selectTriggerVariants } from "../ui/select"; import { Switch } from "../ui/switch"; import { toastManager } from "../ui/toast"; import { SnapShotSetupDialog } from "./SnapShotSetupDialog"; import { useSnapShotShortcutRecorder } from "./useSnapShotShortcutRecorder"; import { captureSetupAccessReady, captureSetupInitialStep, captureSetupShouldDisableOnClose, type CaptureSetupStep, } from "./SnapShotSetupDialog.logic"; const soundOptionRowClassName = "grid grid-cols-[1fr_auto] rounded-sm has-data-checked:bg-foreground/[0.08]"; const soundOptionItemClassName = "data-checked:bg-transparent"; const soundPreviewClassName = "min-h-7 w-7 justify-center px-0"; function captureSettingsError(title: string, error: unknown) { return { title, message: error instanceof Error ? error.message : "Try again." }; } type ShortcutCheck = | { readonly status: "idle"; readonly availability: null } | { readonly status: "checking"; readonly availability: null } | { readonly status: "checked"; readonly availability: DesktopSnapShotShortcutAvailability; }; export function SnapShotSettings() { const settings = useClientSettings(); const updateSettings = useUpdateClientSettings(); const keybindings = useAtomValue(primaryServerKeybindingsAtom); const bridge = getDesktopSnapShotBridge(); const [state, setState] = useState<DesktopSnapShotState | null>(null); const [setupBusy, setSetupBusy] = useState(false); const [setupError, setSetupError] = useState<ReturnType<typeof captureSettingsError> | null>( null, ); const [wizard, setWizard] = useState<{ initialStep: CaptureSetupStep; wasEnabled: boolean; } | null>(null); const [candidate, setCandidate] = useState<SnapShotShortcut>(settings.snapShotShortcut); const [shortcutCheck, setShortcutCheck] = useState<ShortcutCheck>({ status: "idle", availability: null, }); const shortcutCheckIdRef = useRef(0); const stateRequestIdRef = useRef(0); const unavailableMessage = snapShotUnavailableMessage(Boolean(bridge)); const captureAvailable = Boolean(bridge) && state !== null && state.mode !== "unavailable"; const feedbackUnavailable = snapShotFeedbackUnavailableMessage(state); const savedShortcut = settings.snapShotShortcut; const managedShortcut = state?.linuxBackend === "niri" || state?.linuxBackend === "hyprland"; const shortcutChanged = !managedShortcut && !sameSnapShotShortcut(candidate, savedShortcut); const displayShortcut = shortcutChanged ? candidate : (state?.shortcut ?? savedShortcut); const candidateConflict = shortcutChanged ? snapShotKeybindingConflict(candidate, keybindings) : null; const canSaveShortcut = shortcutChanged && candidateConflict === null && shortcutCheck.availability?.available === true; const soundSelection = settings.snapShotPlaySound ? settings.snapShotSound : "off"; const soundLabel = soundSelection === "off" ? "Off" : soundSelection === "soft-pop" ? "Whoosh (Default)" : "Click"; const refreshState = useCallback(async () => { const requestId = ++stateRequestIdRef.current; try { if (bridge) { const nextState = await bridge.getSnapShotState(); if (requestId === stateRequestIdRef.current) setState(nextState); return nextState; } } catch (error) { if (requestId === stateRequestIdRef.current) setSetupError(captureSettingsError("Couldn't check capture setup", error)); } }, [bridge]); const setup = useCallback( async (action: DesktopSnapShotSetupAction) => { if (!bridge?.setupSnapShot || setupBusy) return; setSetupBusy(true); setSetupError(null); try { if ( state?.macPermissions && wizard && (action === "allow-screen-recording" || action === "allow-accessibility") ) { // macOS can quit the app from its permission prompt. saveSnapShotSetupResume(wizard.wasEnabled); } await bridge.setupSnapShot(action); await refreshState(); } catch (error) { setSetupError( captureSettingsError( action === "retry-shortcut" ? "Couldn't open shortcut permissions" : "Couldn't complete capture setup", error, ), ); } finally { setSetupBusy(false); } }, [bridge, refreshState, setupBusy, state, wizard], ); useEffect(() => { if (!setupError || wizard) return; toastManager.add({ type: "error", title: setupError.title, description: setupError.message, }); setSetupError(null); }, [setupError, wizard]); useEffect(() => { let cancelled = false; void refreshState().then((current) => { const resume = readSnapShotSetupResume(); if (!cancelled && current?.macPermissions && resume) { setWizard({ initialStep: "access", wasEnabled: resume.wasEnabled }); } }); window.addEventListener("focus", refreshState); return () => { cancelled = true; window.removeEventListener("focus", refreshState); }; }, [refreshState]); useEffect( () => bridge?.onSnapShotEvent((event) => { if (event.type === "shortcut-changed") void refreshState(); }), [bridge, refreshState], ); useEffect(() => { shortcutCheckIdRef.current++; setCandidate(savedShortcut); setShortcutCheck({ status: "idle", availability: null }); }, [savedShortcut]); const save = useCallback( async (patch: ClientSettingsPatch) => { setSetupError(null); try { await updateSettings(patch); return await refreshState(); } catch (error) { setSetupError(captureSettingsError("Couldn't save capture settings", error)); } }, [refreshState, updateSettings], ); const saveIncludeAccessibility = useCallback( async (includeAccessibility: boolean) => { try { if (includeAccessibility && settings.snapShotEnabled) await bridge?.requestSnapShotPermissions(true); await save({ snapShotIncludeAccessibility: includeAccessibility }); } catch (error) { setSetupError(captureSettingsError("Couldn't allow app text capture", error)); } }, [bridge, save, settings.snapShotEnabled], ); const checkShortcut = useCallback( async (shortcut: SnapShotShortcut) => { const checkId = ++shortcutCheckIdRef.current; setCandidate(shortcut); const conflict = snapShotKeybindingConflict(shortcut, keybindings); if (conflict || !bridge) return; setShortcutCheck({ status: "checking", availability: null }); try { const availability = await bridge.checkSnapShotShortcut(shortcut); if (checkId === shortcutCheckIdRef.current) { setShortcutCheck({ status: "checked", availability }); } } catch (error) { if (checkId !== shortcutCheckIdRef.current) return; setShortcutCheck({ status: "checked", availability: { available: false, message: error instanceof Error ? error.message : "Could not check this shortcut.", }, }); } }, [bridge, keybindings], ); const { recording, stopRecording, input: shortcutInput, } = useSnapShotShortcutRecorder({ shortcut: displayShortcut, shortcutLabel: !shortcutChanged ? state?.shortcutLabel : undefined, disabled: setupBusy, allowModifierPairs: state?.mode !== "portal", onRecord: (shortcut) => void checkShortcut(shortcut), onStart: () => { shortcutCheckIdRef.current++; setShortcutCheck({ status: "idle", availability: null }); }, onError: (message) => setShortcutCheck({ status: "checked", availability: { available: false, message } }), }); const shortcutStatus = recording ? "Press your shortcut. Esc cancels." : candidateConflict ? `T3 Code already uses this for "${commandLabel(candidateConflict)}".` : shortcutCheck.status === "checking" ? "Checking shortcut…" : shortcutCheck.availability ? shortcutCheck.availability.available ? "Ready to save." : shortcutCheck.availability.message : state?.mode === "portal" && !state.shortcutLabel && isModifierPairShortcut(displayShortcut) ? "Try a shortcut such as Ctrl+Shift+2." : snapShotShortcutStatus(state); const openSetup = async (requested: CaptureSetupStep | "resume" = "resume") => { if (!state || setupBusy) return; stopRecording(); shortcutCheckIdRef.current++; setCandidate(savedShortcut); setShortcutCheck({ status: "idle", availability: null }); setSetupError(null); setSetupBusy(true); try { let current = await refreshState(); if (!current) return; if (current.macPermissions) requested = "access"; if (!settings.snapShotEnabled && captureSetupInitialStep(current, requested) !== "access") { // Opening setup is the opt-in. Restore registration before resuming a // later step, just as Continue does on the access step. current = await save({ snapShotEnabled: true }); if (!current) { // A settings write can succeed even if the following status check // fails. Keep Finish later available to turn capture back off. setWizard({ initialStep: "access", wasEnabled: false }); return; } } setWizard({ initialStep: captureSetupInitialStep(current, requested), wasEnabled: settings.snapShotEnabled, }); } finally { setSetupBusy(false); } }; const enableForSetup = async () => { if (setupBusy) return false; setSetupBusy(true); setSetupError(null); try { if (state?.macPermissions) { saveSnapShotSetupResume(wizard?.wasEnabled ?? settings.snapShotEnabled); if (!bridge?.setupSnapShot) throw new Error("Restart T3 Code to finish capture setup."); await bridge.setupSnapShot("test-mac-capture"); } if (state?.mode === "direct") await bridge?.requestSnapShotPermissions(settings.snapShotIncludeAccessibility); const nextState = settings.snapShotEnabled && !state?.message ? await refreshState() : await save({ snapShotEnabled: true }); return nextState !== undefined && captureSetupAccessReady(nextState); } catch (error) { setSetupError(captureSettingsError("Couldn't verify capture access", error)); return false; } finally { setSetupBusy(false); } }; const refreshSetup = useCallback(() => { setSetupError(null); return refreshState(); }, [refreshState]); const closeSetup = async (completed: boolean) => { if (!wizard || setupBusy) return; setSetupBusy(true); try { if ( settings.snapShotEnabled && captureSetupShouldDisableOnClose(wizard.wasEnabled, completed) ) { if (!(await save({ snapShotEnabled: false }))) return; } stopRecording(); setSetupError(null); clearSnapShotSetupResume(); setWizard(null); } catch (error) { setSetupError(captureSettingsError("Couldn't close capture setup", error)); } finally { setSetupBusy(false); } }; const saveShortcut = async () => { if (!canSaveShortcut || setupBusy) return false; setSetupBusy(true); try { const saved = await save({ snapShotShortcut: candidate }); return Boolean(saved?.shortcutRegistered || saved?.shortcutPending); } finally { setSetupBusy(false); } }; return ( <SettingsPageContainer> <SettingsSection id="snap-shot" title="SnapShots"> <SettingsUnavailableGroup message={unavailableMessage}> <SettingsRow {...searchableSetting("snap-shot-enabled")} description={snapShotDescription(state)} status={ bridge ? setupBusy && !wizard ? "Updating capture settings…" : snapShotStatus(state, settings.snapShotEnabled) : undefined } control={ <> {settings.snapShotEnabled && !snapShotSetupComplete(state, settings.snapShotIncludeAccessibility) ? ( <Button size="xs" variant="outline" disabled={setupBusy} onClick={() => void openSetup()} > {snapShotSetupButtonLabel(state)} </Button> ) : null} <Switch checked={settings.snapShotEnabled || Boolean(wizard)} disabled={!captureAvailable || setupBusy} aria-label="Enable snapshots" onCheckedChange={(checked) => { if (!checked) void save({ snapShotEnabled: false }); else if (state?.windows) void save({ snapShotEnabled: true }); else void openSetup(); }} /> </> } /> {settings.snapShotEnabled && captureAvailable ? ( <> <SettingsRow {...searchableSetting("snap-shot-accessibility")} description="Include text and controls when the app makes them available." status={snapShotAccessibilityUnavailableMessage(state)} control={ <Switch checked={ !snapShotAccessibilityUnavailableMessage(state) && settings.snapShotIncludeAccessibility } disabled={ !captureAvailable || Boolean(snapShotAccessibilityUnavailableMessage(state)) } aria-label="Include app text in snapshots" onCheckedChange={(checked) => void saveIncludeAccessibility(checked)} /> } /> <SettingsRow {...searchableSetting("snap-shot-shortcut")} description={ state?.linuxBackend === "picker" ? "Choose a window to capture from any app." : "Capture the window you're using without switching apps." } status={managedShortcut ? undefined : shortcutStatus} control={ managedShortcut ? ( <Button size="xs" variant="outline" disabled={setupBusy} onClick={() => void openSetup("shortcut")} > Change shortcut </Button> ) : ( <> {shortcutInput} {shortcutChanged ? ( <> <Button size="xs" disabled={!canSaveShortcut || setupBusy} onClick={() => void saveShortcut()} > {setupBusy ? "Saving…" : "Save"} </Button> <Button size="xs" variant="ghost" disabled={setupBusy} onClick={() => { stopRecording(); shortcutCheckIdRef.current++; setCandidate(savedShortcut); setShortcutCheck({ status: "idle", availability: null }); }} > Cancel </Button> </> ) : state?.mode === "portal" && state.shortcutCanRetry !== false && !isModifierPairShortcut(savedShortcut) ? ( <Button size="xs" variant="ghost" disabled={setupBusy || state.shortcutPending} onClick={() => void setup("retry-shortcut")} > Shortcut permissions </Button> ) : null} </> ) } /> <SettingsRow {...searchableSetting("snap-shot-sound")} description="Choose the sound played when capture starts."