Open History to see the last commit
1import type { ClientSettingsPatch, DesktopSnapShotState, SnapShotSound } from "@t3tools/contracts";
2import {
3 captureSetupBackend,
4 captureSetupDesktopName,
5 captureSetupAccessReady,
6 captureSetupMacPermissionsReady,
7} from "./SnapShotSetupDialog.logic";
8
9export function snapShotStatus(state: DesktopSnapShotState | null, enabled: boolean): string {
10 if (!state) return "Checking snapshots…";
11 if (state.mode === "unavailable") return state.message ?? "Not supported on this platform.";
12 if (!enabled) return "Turn this on to set up snapshots.";
13 return snapShotSetupSummary(state, enabled);
14}
15
16export function snapShotSetupSummary(state: DesktopSnapShotState, enabled: boolean): string {
17 if (state.message) return "Capture needs attention";
18 if (state.linuxBackend === "hyprland" && state.hyprlandHelper?.status !== "ready")
19 return state.hyprlandHelper?.status === "error"
20 ? "Check capture access in setup"
21 : "Install the capture helper to continue";
22 if (captureSetupBackend(state) === "gnome" && state.gnomeExtension?.status !== "enabled")
23 return "Set up active-window snapshots";
24 if (captureSetupBackend(state) === "kde" && state.kdeHelper?.status !== "ready")
25 return state.kdeHelper?.status === "error"
26 ? "Check capture access in setup"
27 : "Install the capture helper to continue";
28 if (captureSetupBackend(state) === "picker")
29 return "Manual capture only. You'll choose a window each time";
30 if (!enabled) return "Enable capture to continue";
31 if (state.shortcutPending)
32 return state.linuxBackend === "hyprland"
33 ? "Connecting your shortcut…"
34 : "Waiting for shortcut permission";
35 if (state.shortcutVerified) return "Ready to capture";
36 if (state.linuxBackend === "niri" && state.shortcutBinding)
37 return "Use your shortcut from another app";
38 if (state.linuxBackend === "hyprland" && state.shortcutActionRegistered)
39 return "Use your shortcut from another app";
40 if (state.shortcutRegistered) return state.shortcutLabel ? "Ready to capture" : "Shortcut saved";
41 return "Finish shortcut setup";
42}
43
44export function snapShotShortcutStatus(state: DesktopSnapShotState | null): string | null {
45 if (!state) return null;
46 if (state.linuxBackend === "hyprland") return state.shortcutMessage;
47 if (state.shortcutPending) return "Approve the shortcut permission prompt to continue.";
48 if (state.shortcutRegistered) return state.mode === "portal" ? null : "Shortcut saved.";
49 return state.shortcutMessage;
50}
51
52export function snapShotSetupButtonLabel(state: DesktopSnapShotState | null): string {
53 if (!state) return "Continue setup";
54 if (captureSetupAccessReady(state)) return "Manage capture";
55 const desktop = captureSetupDesktopName(state);
56 return desktop ? `Set up ${desktop} capture` : "Continue setup";
57}
58
59export function snapShotSetupComplete(
60 state: DesktopSnapShotState | null,
61 includeAccessibility: boolean,
62): boolean {
63 if (state?.windows) return true;
64 return (
65 state?.macPermissions !== undefined &&
66 captureSetupAccessReady(state) &&
67 captureSetupMacPermissionsReady(state, includeAccessibility) &&
68 state.shortcutRegistered
69 );
70}
71
72export type SnapShotSoundSelection = SnapShotSound | "off";
73
74export function snapShotFeedbackUnavailableMessage(
75 state: DesktopSnapShotState | null,
76): string | undefined {
77 if (state?.mode !== "portal" || state.linuxFeedbackAvailable) return undefined;
78 if (state.linuxBackend === "hyprland")
79 return state.hyprlandHelper?.status === "ready"
80 ? "Capture effects aren't available on this desktop."
81 : "Install or update the capture helper to enable effects.";
82 if (state.linuxBackend === "niri") return "Capture effects aren't available on Niri.";
83 if (state.linuxBackend === "kde")
84 return state.kdeHelper?.status === "ready"
85 ? "Capture effects aren't available on this desktop."
86 : "Install or update the capture helper to enable effects.";
87 return state.linuxBackend === "gnome-extension"
88 ? "Update the GNOME extension, then sign out and back in to enable effects."
89 : captureSetupBackend(state) === "gnome"
90 ? "Finish extension setup to enable effects."
91 : "Capture effects aren't available on this desktop.";
92}
93
94export function snapShotDescription(state: DesktopSnapShotState | null): string {
95 return state?.mode === "portal" && captureSetupBackend(state) === "picker"
96 ? "Automatic capture isn't available here. Choose a window instead."
97 : "Capture a window and attach it to your current draft.";
98}
99
100export function snapShotAccessibilityUnavailableMessage(
101 state: DesktopSnapShotState | null,
102): string | undefined {
103 if (state?.mode !== "portal") return undefined;
104 if (state.linuxBackend === "picker" || state.linuxBackend === "screenshot-portal")
105 return "This desktop only provides a screenshot.";
106 return undefined;
107}
108
109export function snapShotUnavailableMessage(hasBridge: boolean): string | undefined {
110 if (hasBridge) return undefined;
111 return typeof window !== "undefined" && window.desktopBridge
112 ? "Update the desktop app to use snapshots."
113 : "Only available in the desktop app.";
114}
115
116export function snapShotSoundPatch(sound: SnapShotSoundSelection): ClientSettingsPatch {
117 return sound === "off"
118 ? { snapShotPlaySound: false }
119 : { snapShotPlaySound: true, snapShotSound: sound };
120}
121
122export function createRecordingRequestTracker() {
123 let currentRequest: symbol | null = null;
124
125 return {
126 tryBegin() {
127 if (currentRequest) return null;
128 currentRequest = Symbol();
129 return currentRequest;
130 },
131 clear() {
132 currentRequest = null;
133 },
134 owns(request: symbol) {
135 return currentRequest === request;
136 },
137 };
138}