file dialog choose location
This commit is contained in:
+18
-5
@@ -1,4 +1,4 @@
|
||||
import { BrowserWindow, screen, ipcMain, desktopCapturer, shell, app, nativeImage, Tray, Menu } from "electron";
|
||||
import { BrowserWindow, screen, ipcMain, desktopCapturer, shell, app, dialog, nativeImage, Tray, Menu } from "electron";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs/promises";
|
||||
@@ -202,12 +202,25 @@ function registerIpcHandlers(createEditorWindow2, createSourceSelectorWindow2, g
|
||||
});
|
||||
ipcMain.handle("save-exported-video", async (_, videoData, fileName) => {
|
||||
try {
|
||||
const downloadsPath = app.getPath("downloads");
|
||||
const videoPath = path.join(downloadsPath, fileName);
|
||||
await fs.writeFile(videoPath, Buffer.from(videoData));
|
||||
const result = await dialog.showSaveDialog({
|
||||
title: "Save Exported Video",
|
||||
defaultPath: path.join(app.getPath("downloads"), fileName),
|
||||
filters: [
|
||||
{ name: "MP4 Video", extensions: ["mp4"] }
|
||||
],
|
||||
properties: ["createDirectory", "showOverwriteConfirmation"]
|
||||
});
|
||||
if (result.canceled || !result.filePath) {
|
||||
return {
|
||||
success: false,
|
||||
cancelled: true,
|
||||
message: "Export cancelled"
|
||||
};
|
||||
}
|
||||
await fs.writeFile(result.filePath, Buffer.from(videoData));
|
||||
return {
|
||||
success: true,
|
||||
path: videoPath,
|
||||
path: result.filePath,
|
||||
message: "Video exported successfully"
|
||||
};
|
||||
} catch (error) {
|
||||
|
||||
Vendored
+1
-1
@@ -35,7 +35,7 @@ interface Window {
|
||||
setRecordingState: (recording: boolean) => Promise<void>
|
||||
onStopRecordingFromTray: (callback: () => void) => () => void
|
||||
openExternalUrl: (url: string) => Promise<{ success: boolean; error?: string }>
|
||||
saveExportedVideo: (videoData: ArrayBuffer, fileName: string) => Promise<{ success: boolean; path?: string; message?: string }>
|
||||
saveExportedVideo: (videoData: ArrayBuffer, fileName: string) => Promise<{ success: boolean; path?: string; message?: string; cancelled?: boolean }>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ipcMain, desktopCapturer, BrowserWindow, shell, app } from 'electron'
|
||||
import { ipcMain, desktopCapturer, BrowserWindow, shell, app, dialog } from 'electron'
|
||||
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
@@ -128,22 +128,40 @@ export function registerIpcHandlers(
|
||||
|
||||
ipcMain.handle('save-exported-video', async (_, videoData: ArrayBuffer, fileName: string) => {
|
||||
try {
|
||||
const downloadsPath = app.getPath('downloads')
|
||||
const videoPath = path.join(downloadsPath, fileName)
|
||||
await fs.writeFile(videoPath, Buffer.from(videoData))
|
||||
// Show save dialog to let user choose location and filename
|
||||
const result = await dialog.showSaveDialog({
|
||||
title: 'Save Exported Video',
|
||||
defaultPath: path.join(app.getPath('downloads'), fileName),
|
||||
filters: [
|
||||
{ name: 'MP4 Video', extensions: ['mp4'] }
|
||||
],
|
||||
properties: ['createDirectory', 'showOverwriteConfirmation']
|
||||
});
|
||||
|
||||
// User cancelled the dialog
|
||||
if (result.canceled || !result.filePath) {
|
||||
return {
|
||||
success: false,
|
||||
cancelled: true,
|
||||
message: 'Export cancelled'
|
||||
};
|
||||
}
|
||||
|
||||
// Write the file to the chosen location
|
||||
await fs.writeFile(result.filePath, Buffer.from(videoData));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
path: videoPath,
|
||||
path: result.filePath,
|
||||
message: 'Video exported successfully'
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Failed to save exported video:', error)
|
||||
console.error('Failed to save exported video:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: 'Failed to save exported video',
|
||||
error: String(error)
|
||||
}
|
||||
};
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -248,8 +248,10 @@ export default function VideoEditor() {
|
||||
|
||||
const saveResult = await window.electronAPI.saveExportedVideo(arrayBuffer, fileName);
|
||||
|
||||
if (saveResult.success) {
|
||||
toast.success('Video exported successfully!');
|
||||
if (saveResult.cancelled) {
|
||||
toast.info('Export cancelled');
|
||||
} else if (saveResult.success) {
|
||||
toast.success(`Video exported successfully to ${saveResult.path}`);
|
||||
} else {
|
||||
setExportError(saveResult.message || 'Failed to save video');
|
||||
toast.error(saveResult.message || 'Failed to save video');
|
||||
|
||||
@@ -724,7 +724,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
|
||||
className="absolute inset-0 bg-cover bg-center"
|
||||
style={{
|
||||
...backgroundStyle,
|
||||
filter: showBlur ? 'blur(3px)' : 'none',
|
||||
filter: showBlur ? 'blur(2px)' : 'none',
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
|
||||
@@ -435,7 +435,7 @@ export class FrameRenderer {
|
||||
|
||||
if (this.config.showBlur) {
|
||||
ctx.save();
|
||||
ctx.filter = 'blur(3px)';
|
||||
ctx.filter = 'blur(6px)'; // Canvas blur is weaker than CSS
|
||||
ctx.drawImage(bgCanvas, 0, 0, w, h);
|
||||
ctx.restore();
|
||||
} else {
|
||||
|
||||
Vendored
+1
@@ -36,6 +36,7 @@ interface Window {
|
||||
success: boolean
|
||||
path?: string
|
||||
message?: string
|
||||
cancelled?: boolean
|
||||
}>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user