fix(hud): persist capture hiding review fixes

This commit is contained in:
KBCats
2026-03-15 20:36:27 -07:00
parent 43a9ec5701
commit acf796b074
3 changed files with 104 additions and 229 deletions
+43 -16
View File
@@ -85,7 +85,8 @@ export function LaunchWindow() {
const [selectedSource, setSelectedSource] = useState("Screen");
const [hasSelectedSource, setHasSelectedSource] = useState(false);
const [recordingsDirectory, setRecordingsDirectory] = useState<string | null>(null);
const [hideHudFromCapture, setHideHudFromCapture] = useState(false);
const [hideHudFromCapture, setHideHudFromCapture] = useState(true);
const [platform, setPlatform] = useState<string | null>(null);
useEffect(() => {
const checkSelectedSource = async () => {
@@ -106,6 +107,27 @@ export function LaunchWindow() {
return () => clearInterval(interval);
}, []);
useEffect(() => {
let cancelled = false;
const loadPlatform = async () => {
try {
const nextPlatform = await window.electronAPI.getPlatform();
if (!cancelled) {
setPlatform(nextPlatform);
}
} catch (error) {
console.error("Failed to load platform:", error);
}
};
void loadPlatform();
return () => {
cancelled = true;
};
}, []);
useEffect(() => {
let cancelled = false;
@@ -204,6 +226,7 @@ export function LaunchWindow() {
? recordingsDirectory.split(/[\\/]/).filter(Boolean).pop() || recordingsDirectory
: "recordings";
const dividerClass = "mx-1 h-5 w-px shrink-0 bg-white/35";
const supportsHudCaptureProtection = platform !== "linux";
const toggleMicrophone = () => {
if (!recording) {
@@ -266,21 +289,25 @@ export function LaunchWindow() {
<div className={dividerClass} />
<div className={`flex items-center gap-1 ${styles.electronNoDrag}`}>
<Button
variant="link"
size="icon"
onClick={() => void toggleHudCaptureProtection()}
title={
hideHudFromCapture ? t("recording.showHudInVideo") : t("recording.hideHudFromVideo")
}
className="text-white/80 hover:bg-transparent"
>
{hideHudFromCapture ? (
<EyeOff size={16} className="text-[#2563EB]" />
) : (
<Eye size={16} className="text-white/35" />
)}
</Button>
{supportsHudCaptureProtection && (
<Button
variant="link"
size="icon"
onClick={() => void toggleHudCaptureProtection()}
title={
hideHudFromCapture
? t("recording.showHudInVideo")
: t("recording.hideHudFromVideo")
}
className="text-white/80 hover:bg-transparent"
>
{hideHudFromCapture ? (
<EyeOff size={16} className="text-white/35" />
) : (
<Eye size={16} className="text-[#2563EB]" />
)}
</Button>
)}
<Button
variant="link"
size="icon"
-208
View File
@@ -1,210 +1,2 @@
/// <reference types="vite/client" />
/// <reference types="../electron/electron-env" />
interface ProcessedDesktopSource {
id: string;
name: string;
display_id: string;
thumbnail: string | null;
appIcon: string | null;
originalName?: string;
sourceType?: "screen" | "window";
appName?: string;
windowTitle?: string;
}
interface CursorTelemetryPoint {
timeMs: number;
cx: number;
cy: number;
interactionType?: "move" | "click" | "double-click" | "right-click" | "middle-click" | "mouseup";
cursorType?:
| "arrow"
| "text"
| "pointer"
| "crosshair"
| "open-hand"
| "closed-hand"
| "resize-ew"
| "resize-ns"
| "not-allowed";
}
interface SystemCursorAsset {
dataUrl: string;
hotspotX: number;
hotspotY: number;
width: number;
height: number;
}
interface Window {
electronAPI: {
hudOverlayHide: () => void;
hudOverlayClose: () => void;
getHudOverlayCaptureProtection: () => Promise<{ success: boolean; enabled: boolean }>;
setHudOverlayCaptureProtection: (
enabled: boolean,
) => Promise<{ success: boolean; enabled: boolean }>;
getSources: (opts: Electron.SourcesOptions) => Promise<ProcessedDesktopSource[]>;
switchToEditor: () => Promise<void>;
openSourceSelector: () => Promise<void>;
selectSource: (source: any) => Promise<any>;
getSelectedSource: () => Promise<any>;
startNativeScreenRecording: (
source: any,
options?: {
capturesSystemAudio?: boolean;
capturesMicrophone?: boolean;
microphoneDeviceId?: string;
microphoneLabel?: string;
},
) => Promise<{
success: boolean;
path?: string;
message?: string;
error?: string;
}>;
stopNativeScreenRecording: () => Promise<{
success: boolean;
path?: string;
message?: string;
error?: string;
}>;
startFfmpegRecording: (source: any) => Promise<{
success: boolean;
path?: string;
message?: string;
error?: string;
}>;
stopFfmpegRecording: () => Promise<{
success: boolean;
path?: string;
message?: string;
error?: string;
}>;
storeRecordedVideo: (
videoData: ArrayBuffer,
fileName: string,
) => Promise<{
success: boolean;
path?: string;
message: string;
error?: string;
}>;
getRecordedVideoPath: () => Promise<{
success: boolean;
path?: string;
message?: string;
error?: string;
}>;
readLocalFile: (filePath: string) => Promise<{
success: boolean;
data?: Uint8Array;
error?: string;
}>;
getAssetBasePath: () => Promise<string | null>;
setRecordingState: (recording: boolean) => Promise<void>;
getCursorTelemetry: (videoPath?: string) => Promise<{
success: boolean;
samples: CursorTelemetryPoint[];
message?: string;
error?: string;
}>;
getSystemCursorAssets: () => Promise<{
success: boolean;
cursors: Record<string, SystemCursorAsset>;
error?: string;
}>;
onStopRecordingFromTray: (callback: () => void) => () => void;
onRecordingStateChanged: (
callback: (state: { recording: boolean; sourceName: string }) => void,
) => () => void;
onRecordingInterrupted: (
callback: (state: { reason: string; message: string }) => void,
) => () => void;
onCursorStateChanged: (
callback: (state: { cursorType: CursorTelemetryPoint["cursorType"] }) => void,
) => () => void;
openExternalUrl: (url: string) => Promise<{ success: boolean; error?: string }>;
getAccessibilityPermissionStatus: () => Promise<{
success: boolean;
trusted: boolean;
prompted: boolean;
error?: string;
}>;
requestAccessibilityPermission: () => Promise<{
success: boolean;
trusted: boolean;
prompted: boolean;
error?: string;
}>;
getScreenRecordingPermissionStatus: () => Promise<{
success: boolean;
status: string;
error?: string;
}>;
openScreenRecordingPreferences: () => Promise<{ success: boolean; error?: string }>;
openAccessibilityPreferences: () => Promise<{ success: boolean; error?: string }>;
saveExportedVideo: (
videoData: ArrayBuffer,
fileName: string,
) => Promise<{
success: boolean;
path?: string;
message?: string;
canceled?: boolean;
}>;
openVideoFilePicker: () => Promise<{ success: boolean; path?: string; canceled?: boolean }>;
setCurrentVideoPath: (path: string) => Promise<{ success: boolean }>;
getCurrentVideoPath: () => Promise<{ success: boolean; path?: string }>;
clearCurrentVideoPath: () => Promise<{ success: boolean }>;
saveProjectFile: (
projectData: unknown,
suggestedName?: string,
existingProjectPath?: string,
) => Promise<{
success: boolean;
path?: string;
message?: string;
canceled?: boolean;
error?: string;
}>;
loadProjectFile: () => Promise<{
success: boolean;
path?: string;
project?: unknown;
message?: string;
canceled?: boolean;
error?: string;
}>;
loadCurrentProjectFile: () => Promise<{
success: boolean;
path?: string;
project?: unknown;
message?: string;
canceled?: boolean;
error?: string;
}>;
onMenuLoadProject: (callback: () => void) => () => void;
onMenuSaveProject: (callback: () => void) => () => void;
onMenuSaveProjectAs: (callback: () => void) => () => void;
hideOsCursor: () => Promise<{ success: boolean }>;
setHasUnsavedChanges: (hasChanges: boolean) => void;
onRequestSaveBeforeClose: (callback: () => Promise<void>) => () => void;
getRecordingsDirectory: () => Promise<{
success: boolean;
path: string;
isDefault: boolean;
error?: string;
}>;
chooseRecordingsDirectory: () => Promise<{
success: boolean;
canceled?: boolean;
path?: string;
isDefault?: boolean;
message?: string;
error?: string;
}>;
};
}