diff --git a/electron/ipc/handlers.ts b/electron/ipc/handlers.ts index 0942dc1f..07ee1d5d 100644 --- a/electron/ipc/handlers.ts +++ b/electron/ipc/handlers.ts @@ -81,6 +81,7 @@ let cachedSystemCursorAssets: Record | null = null let cachedSystemCursorAssetsSourceMtimeMs: number | null = null let countdownTimer: ReturnType | null = null let countdownCancelled = false +let countdownInProgress = false type SystemCursorAsset = { dataUrl: string @@ -2767,6 +2768,11 @@ export function registerIpcHandlers( }) ipcMain.handle('start-countdown', async (_, seconds: number) => { + if (countdownInProgress) { + return { success: false, error: 'Countdown already in progress' } + } + + countdownInProgress = true countdownCancelled = false const countdownWin = createCountdownWindow() @@ -2789,6 +2795,7 @@ export function registerIpcHandlers( countdownTimer = null } closeCountdownWindow() + countdownInProgress = false resolve({ success: false, cancelled: true }) return } @@ -2801,6 +2808,7 @@ export function registerIpcHandlers( countdownTimer = null } closeCountdownWindow() + countdownInProgress = false resolve({ success: true }) } else { const win = getCountdownWindow() @@ -2814,6 +2822,7 @@ export function registerIpcHandlers( ipcMain.handle('cancel-countdown', () => { countdownCancelled = true + countdownInProgress = false if (countdownTimer) { clearInterval(countdownTimer) countdownTimer = null diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index f0489abc..06c48067 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -31,6 +31,7 @@ export function LaunchWindow() { const LOCALE_LABELS: Record = { en: "EN", es: "ES", "zh-CN": "中文" }; const { recording, + countdownActive, toggleRecording, microphoneEnabled, setMicrophoneEnabled, @@ -283,7 +284,7 @@ export function LaunchWindow() { variant="link" size="sm" onClick={hasSelectedSource ? toggleRecording : openSourceSelector} - disabled={!hasSelectedSource && !recording} + disabled={countdownActive || (!hasSelectedSource && !recording)} className={`gap-1 text-white bg-transparent hover:bg-transparent px-0 text-xs ${styles.electronNoDrag}`} > {recording ? ( diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index 6222518c..4765bd40 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -28,6 +28,7 @@ const MIC_GAIN_BOOST = 1.4; type UseScreenRecorderReturn = { recording: boolean; + countdownActive: boolean; toggleRecording: () => void; preparePermissions: (options?: { startup?: boolean }) => Promise; isMacOS: boolean; @@ -44,6 +45,7 @@ type UseScreenRecorderReturn = { export function useScreenRecorder(): UseScreenRecorderReturn { const [recording, setRecording] = useState(false); const [starting, setStarting] = useState(false); + const [countdownActive, setCountdownActive] = useState(false); const [isMacOS, setIsMacOS] = useState(false); const [microphoneEnabled, setMicrophoneEnabled] = useState(false); const [microphoneDeviceId, setMicrophoneDeviceId] = useState(undefined); @@ -570,7 +572,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { }; const toggleRecording = async () => { - if (starting) { + if (starting || countdownActive) { return; } @@ -581,9 +583,14 @@ export function useScreenRecorder(): UseScreenRecorderReturn { // Start recording with optional countdown if (countdownDelay > 0) { - const result = await window.electronAPI.startCountdown(countdownDelay); - if (!result.success || result.cancelled) { - return; + setCountdownActive(true); + try { + const result = await window.electronAPI.startCountdown(countdownDelay); + if (!result.success || result.cancelled) { + return; + } + } finally { + setCountdownActive(false); } } @@ -592,6 +599,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { return { recording, + countdownActive, toggleRecording, preparePermissions, isMacOS,