From 14cd045e65a4ba5320b885568b6e94bf67f6d04f Mon Sep 17 00:00:00 2001 From: Ayush765-spec Date: Fri, 3 Apr 2026 18:57:05 +0530 Subject: [PATCH 1/3] [Feature]: Ability to start a new recording from the editor --- electron/electron-env.d.ts | 1 + electron/ipc/handlers.ts | 5 ++ electron/main.ts | 11 ++++ electron/preload.ts | 3 ++ package-lock.json | 4 +- src/components/video-editor/VideoEditor.tsx | 56 ++++++++++++++++++++- src/vite-env.d.ts | 1 + 7 files changed, 78 insertions(+), 3 deletions(-) diff --git a/electron/electron-env.d.ts b/electron/electron-env.d.ts index 573aee8..82c7e57 100644 --- a/electron/electron-env.d.ts +++ b/electron/electron-env.d.ts @@ -26,6 +26,7 @@ interface Window { electronAPI: { getSources: (opts: Electron.SourcesOptions) => Promise; switchToEditor: () => Promise; + switchToHud: () => Promise; openSourceSelector: () => Promise; selectSource: (source: ProcessedDesktopSource) => Promise; getSelectedSource: () => Promise; diff --git a/electron/ipc/handlers.ts b/electron/ipc/handlers.ts index 78d8344..eb9e96b 100644 --- a/electron/ipc/handlers.ts +++ b/electron/ipc/handlers.ts @@ -217,7 +217,12 @@ export function registerIpcHandlers( getMainWindow: () => BrowserWindow | null, getSourceSelectorWindow: () => BrowserWindow | null, onRecordingStateChange?: (recording: boolean, sourceName: string) => void, + switchToHud?: () => void, ) { + ipcMain.handle("switch-to-hud", () => { + if (switchToHud) switchToHud(); + }); + ipcMain.handle("get-sources", async (_, opts) => { const sources = await desktopCapturer.getSources(opts); return sources.map((source) => ({ diff --git a/electron/main.ts b/electron/main.ts index 7e19d46..0f06f9e 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -371,6 +371,16 @@ app.whenReady().then(async () => { // Ensure recordings directory exists await ensureRecordingsDir(); + function switchToHudWrapper() { + if (mainWindow) { + isForceClosing = true; + mainWindow.close(); + isForceClosing = false; + mainWindow = null; + } + showMainWindow(); + } + registerIpcHandlers( createEditorWindowWrapper, createSourceSelectorWindowWrapper, @@ -384,6 +394,7 @@ app.whenReady().then(async () => { showMainWindow(); } }, + switchToHudWrapper, ); createWindow(); }); diff --git a/electron/preload.ts b/electron/preload.ts index 8f1836b..34731e5 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -18,6 +18,9 @@ contextBridge.exposeInMainWorld("electronAPI", { switchToEditor: () => { return ipcRenderer.invoke("switch-to-editor"); }, + switchToHud: () => { + return ipcRenderer.invoke("switch-to-hud"); + }, openSourceSelector: () => { return ipcRenderer.invoke("open-source-selector"); }, diff --git a/package-lock.json b/package-lock.json index 58e37a3..5d07f2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openscreen", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openscreen", - "version": "1.2.0", + "version": "1.3.0", "dependencies": { "@fix-webm-duration/fix": "^1.0.1", "@pixi/filter-drop-shadow": "^5.2.0", diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index 304d10f..dae009a 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -1,8 +1,16 @@ import type { Span } from "dnd-timeline"; -import { FolderOpen, Languages, Save } from "lucide-react"; +import { FolderOpen, Languages, Save, Video } from "lucide-react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; import { toast } from "sonner"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; import { useI18n, useScopedT } from "@/contexts/I18nContext"; import { useShortcuts } from "@/contexts/ShortcutsContext"; import { INITIAL_EDITOR_STATE, useEditorHistory } from "@/hooks/useEditorHistory"; @@ -107,6 +115,7 @@ export default function VideoEditor() { const [exportProgress, setExportProgress] = useState(null); const [exportError, setExportError] = useState(null); const [showExportDialog, setShowExportDialog] = useState(false); + const [showNewRecordingDialog, setShowNewRecordingDialog] = useState(false); const [exportQuality, setExportQuality] = useState("good"); const [exportFormat, setExportFormat] = useState("mp4"); const [gifFrameRate, setGifFrameRate] = useState(15); @@ -464,6 +473,13 @@ export default function VideoEditor() { await saveProject(true); }, [saveProject]); + const handleNewRecordingConfirm = useCallback(async () => { + setShowNewRecordingDialog(false); + await window.electronAPI.clearCurrentVideoPath(); + await window.electronAPI.setCurrentRecordingSession(null); + await window.electronAPI.switchToHud(); + }, []); + const handleLoadProject = useCallback(async () => { const result = await window.electronAPI.loadProjectFile(); @@ -1393,6 +1409,36 @@ export default function VideoEditor() { return (
+ + + + New Recording + + Start a new recording? Your current recording will be discarded. + + + + + + + + +
+ @@ -1470,7 +1472,7 @@ export default function VideoEditor() { className="flex items-center gap-1 px-2 py-1 rounded-md text-white/50 hover:text-white/90 hover:bg-white/10 transition-all duration-150 text-[11px] font-medium" >