diff --git a/electron/windows.ts b/electron/windows.ts index 240d89f1..960fd6f4 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -609,13 +609,37 @@ export function createEditorWindow(): BrowserWindow { }, }); + const showEditorWindow = () => { + if (win.isDestroyed()) { + return; + } + + if (win.isMinimized()) { + win.restore(); + } + + if (!win.isVisible()) { + win.show(); + } + + win.moveTop(); + win.focus(); + }; + win.once("ready-to-show", () => { console.log("[editor-window] ready-to-show"); - win.show(); + showEditorWindow(); }); win.webContents.on("did-finish-load", () => { console.log("[editor-window] did-finish-load", win.webContents.getURL()); + if (!win.isVisible()) { + setTimeout(() => { + if (!win.isDestroyed() && !win.isVisible()) { + showEditorWindow(); + } + }, process.platform === "linux" ? 50 : 0); + } win?.webContents.send("main-process-message", new Date().toLocaleString()); }); diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index bd06d4bb..074c5b6e 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -101,6 +101,32 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const accumulatedPausedDurationMs = useRef(0); const pauseStartedAtMs = useRef(null); const pauseSegmentsRef = useRef([]); + const recordingFinalizationToastId = useRef(null); + + const showRecordingFinalizationToast = useCallback((message = "Preparing recording...") => { + recordingFinalizationToastId.current = toast.loading(message, { + id: recordingFinalizationToastId.current ?? undefined, + duration: Number.POSITIVE_INFINITY, + }); + }, []); + + const clearRecordingFinalizationToast = useCallback(() => { + const toastId = recordingFinalizationToastId.current; + if (toastId === null) { + return; + } + + toast.dismiss(toastId); + recordingFinalizationToastId.current = null; + }, []); + + const notifyRecordingFinalizationFailure = useCallback( + async (message: string) => { + clearRecordingFinalizationToast(); + toast.error(message, { duration: 10000 }); + }, + [clearRecordingFinalizationToast], + ); const logNativeCaptureDiagnostics = useCallback(async (context: string) => { if (typeof window.electronAPI?.getLastNativeCaptureDiagnostics !== "function") { @@ -344,8 +370,9 @@ export function useScreenRecorder(): UseScreenRecorderReturn { } } + clearRecordingFinalizationToast(); await window.electronAPI.notifyRecordingFinalized(); - }, []); + }, [clearRecordingFinalizationToast]); const stopWebcamRecorder = useCallback(async () => { const recorder = webcamRecorder.current; @@ -500,6 +527,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { setRecording(false); void (async () => { + showRecordingFinalizationToast(); const webcamPath = await stopWebcamRecorder(); const isNativeWindows = nativeWindowsRecording.current; markRecordingResumed(Date.now()); @@ -527,7 +555,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { ? "Failed to finish the macOS recording, so the editor was not opened." : "Failed to finish the recording, so the editor was not opened.", ); - toast.error(failureMessage, { duration: 10000 }); + await notifyRecordingFinalizationFailure(failureMessage); return; } @@ -989,6 +1017,8 @@ export function useScreenRecorder(): UseScreenRecorderReturn { cleanupCapturedMedia(); if (chunks.current.length === 0) return; + showRecordingFinalizationToast(); + // Open editor window immediately while we process the recording await window.electronAPI.openEditorEarly?.(); @@ -1005,6 +1035,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const videoResult = await window.electronAPI.storeRecordedVideo(arrayBuffer, videoFileName); if (!videoResult.success) { console.error("Failed to store video:", videoResult.message); + await notifyRecordingFinalizationFailure(videoResult.message || "Failed to store the recording."); return; } @@ -1013,9 +1044,13 @@ export function useScreenRecorder(): UseScreenRecorderReturn { ? await pendingWebcamPathPromise.current : resolvedWebcamPath.current; await finalizeRecordingSession(videoResult.path, webcamPath); + } else { + await notifyRecordingFinalizationFailure("Failed to save the recording."); } } catch (error) { console.error("Error saving recording:", error); + const message = error instanceof Error ? error.message : String(error); + await notifyRecordingFinalizationFailure(`Failed to finalize the recording. ${message}`); } }; recorder.onerror = () => {