Skip to content

Commit 7538bf3

Browse files
committed
[wip] feat: add delete prev recording feat in settings
1 parent 9842913 commit 7538bf3

File tree

3 files changed

+90
-30
lines changed

3 files changed

+90
-30
lines changed

apps/desktop/src-tauri/src/lib.rs

+25
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,11 @@ pub struct RecordingStopped {
244244
path: PathBuf,
245245
}
246246

247+
#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
248+
pub struct RecordingDeleted {
249+
path: PathBuf,
250+
}
251+
247252
#[derive(Deserialize, specta::Type, Serialize, tauri_specta::Event, Debug, Clone)]
248253
pub struct RequestStartRecording;
249254

@@ -664,6 +669,24 @@ async fn open_file_path(_app: AppHandle, path: PathBuf) -> Result<(), String> {
664669
Ok(())
665670
}
666671

672+
673+
#[tauri::command]
674+
#[specta::specta]
675+
async fn delete_file(_app: AppHandle, path: PathBuf) -> Result<(), String> {
676+
let path_str = path.to_str().ok_or("Invalid path")?;
677+
678+
#[cfg(target_os = "macos")]
679+
{
680+
Command::new("rm")
681+
.arg("-r")
682+
.arg(path_str)
683+
.spawn()
684+
.map_err(|e| format!("Failed to delete folder: {}", e))?;
685+
}
686+
687+
Ok(())
688+
}
689+
667690
#[derive(Deserialize, specta::Type, tauri_specta::Event, Debug, Clone)]
668691
struct RenderFrameEvent {
669692
frame_number: u32,
@@ -1671,6 +1694,7 @@ pub async fn run() {
16711694
copy_video_to_clipboard,
16721695
copy_screenshot_to_clipboard,
16731696
open_file_path,
1697+
delete_file,
16741698
get_video_metadata,
16751699
create_editor_instance,
16761700
start_playback,
@@ -1711,6 +1735,7 @@ pub async fn run() {
17111735
RecordingMetaChanged,
17121736
RecordingStarted,
17131737
RecordingStopped,
1738+
RecordingDeleted,
17141739
RequestStartRecording,
17151740
RequestRestartRecording,
17161741
RequestStopRecording,

apps/desktop/src/routes/(window-chrome)/settings/recordings.tsx

+59-30
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { For, Show, Suspense, createSignal } from "solid-js";
33
import { convertFileSrc } from "@tauri-apps/api/core";
44

55
import { commands, events } from "~/utils/tauri";
6+
import { createQueryInvalidate } from "~/utils/events";
67

78
type MediaEntry = {
89
id: string;
@@ -13,38 +14,52 @@ type MediaEntry = {
1314
};
1415

1516
export default function Recordings() {
16-
const fetchRecordings = createQuery(() => ({
17-
queryKey: ["recordings"],
18-
queryFn: async () => {
19-
const result = await commands
20-
.listRecordings()
21-
.catch(
22-
() =>
23-
Promise.resolve([]) as ReturnType<typeof commands.listRecordings>
17+
function fetchRecordingsQuery() {
18+
const fetchRecordings = createQuery(() => ({
19+
queryKey: ["recordings"],
20+
queryFn: async () => {
21+
const result = await commands
22+
.listRecordings()
23+
.catch(
24+
() =>
25+
Promise.resolve([]) as ReturnType<typeof commands.listRecordings>
26+
);
27+
28+
const recordings = await Promise.all(
29+
result.map(async (file) => {
30+
const [id, path, meta] = file;
31+
const thumbnailPath = `${path}/screenshots/display.jpg`;
32+
33+
return {
34+
id,
35+
path,
36+
prettyName: meta.pretty_name,
37+
isNew: false,
38+
thumbnailPath,
39+
};
40+
})
2441
);
42+
return recordings;
43+
},
44+
staleTime: 0,
45+
}));
2546

26-
const recordings = await Promise.all(
27-
result.map(async (file) => {
28-
const [id, path, meta] = file;
29-
const thumbnailPath = `${path}/screenshots/display.jpg`;
47+
createQueryInvalidate(fetchRecordings, "recordingDeleted");
3048

31-
return {
32-
id,
33-
path,
34-
prettyName: meta.pretty_name,
35-
isNew: false,
36-
thumbnailPath,
37-
};
38-
})
39-
);
40-
return recordings;
41-
},
42-
}));
49+
return fetchRecordings;
50+
}
4351

44-
const handleRecordingClick = (recording: MediaEntry) => {
52+
const recordings = fetchRecordingsQuery();
53+
54+
const handleOpenRecording = (recording: MediaEntry) => {
4555
events.newRecordingAdded.emit({ path: recording.path });
4656
};
4757

58+
const handleDeleteRecording = (path: string) => {
59+
commands.deleteFile(path);
60+
events.recordingDeleted.emit({ path });
61+
};
62+
4863
const handleOpenFolder = (path: string) => {
4964
commands.openFilePath(path);
5065
};
@@ -60,18 +75,21 @@ export default function Recordings() {
6075
<div class="flex-1 overflow-y-auto">
6176
<ul class="p-[0.625rem] flex flex-col gap-[0.5rem] w-full">
6277
<Show
63-
when={fetchRecordings.data && fetchRecordings.data.length > 0}
78+
when={recordings.data && recordings.data.length > 0}
6479
fallback={
6580
<p class="text-center text-gray-500">No recordings found</p>
6681
}
6782
>
68-
<For each={fetchRecordings.data}>
83+
<For each={recordings.data}>
6984
{(recording) => (
7085
<RecordingItem
7186
recording={recording}
72-
onClick={() => handleRecordingClick(recording)}
7387
onOpenFolder={() => handleOpenFolder(recording.path)}
7488
onOpenEditor={() => handleOpenEditor(recording.path)}
89+
onOpenRecording={() => handleOpenRecording(recording)}
90+
onDeleteRecording={() =>
91+
handleDeleteRecording(recording.path)
92+
}
7593
/>
7694
)}
7795
</For>
@@ -84,9 +102,10 @@ export default function Recordings() {
84102

85103
function RecordingItem(props: {
86104
recording: MediaEntry;
87-
onClick: () => void;
88105
onOpenFolder: () => void;
89106
onOpenEditor: () => void;
107+
onOpenRecording: () => void;
108+
onDeleteRecording: () => void;
90109
}) {
91110
const [imageExists, setImageExists] = createSignal(true);
92111

@@ -133,12 +152,22 @@ function RecordingItem(props: {
133152
type="button"
134153
onClick={(e) => {
135154
e.stopPropagation();
136-
props.onClick();
155+
props.onOpenRecording();
137156
}}
138157
class="p-2 hover:bg-gray-200 rounded-full"
139158
>
140159
<IconLucideEye class="size-5" />
141160
</button>
161+
<button
162+
type="button"
163+
onClick={(e) => {
164+
e.stopPropagation();
165+
props.onDeleteRecording();
166+
}}
167+
class="p-2 hover:bg-gray-200 rounded-full"
168+
>
169+
<IconCapTrash class="size-5" />
170+
</button>
142171
</div>
143172
</li>
144173
);

apps/desktop/src/utils/tauri.ts

+6
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ async copyScreenshotToClipboard(path: string) : Promise<null> {
6868
async openFilePath(path: string) : Promise<null> {
6969
return await TAURI_INVOKE("open_file_path", { path });
7070
},
71+
async deleteFile(path: string) : Promise<null> {
72+
return await TAURI_INVOKE("delete_file", { path });
73+
},
7174
async getVideoMetadata(videoId: string, videoType: VideoType | null) : Promise<[number, number]> {
7275
return await TAURI_INVOKE("get_video_metadata", { videoId, videoType });
7376
},
@@ -168,6 +171,7 @@ editorStateChanged: EditorStateChanged,
168171
newNotification: NewNotification,
169172
newRecordingAdded: NewRecordingAdded,
170173
newScreenshotAdded: NewScreenshotAdded,
174+
recordingDeleted: RecordingDeleted,
171175
recordingMetaChanged: RecordingMetaChanged,
172176
recordingOptionsChanged: RecordingOptionsChanged,
173177
recordingStarted: RecordingStarted,
@@ -187,6 +191,7 @@ editorStateChanged: "editor-state-changed",
187191
newNotification: "new-notification",
188192
newRecordingAdded: "new-recording-added",
189193
newScreenshotAdded: "new-screenshot-added",
194+
recordingDeleted: "recording-deleted",
190195
recordingMetaChanged: "recording-meta-changed",
191196
recordingOptionsChanged: "recording-options-changed",
192197
recordingStarted: "recording-started",
@@ -247,6 +252,7 @@ export type Plan = { upgraded: boolean; last_checked: number }
247252
export type PreCreatedVideo = { id: string; link: string; config: S3UploadMeta }
248253
export type ProjectConfiguration = { aspectRatio: AspectRatio | null; background: BackgroundConfiguration; camera: Camera; audio: AudioConfiguration; cursor: CursorConfiguration; hotkeys: HotkeysConfiguration; timeline?: TimelineConfiguration | null; motionBlur: number | null }
249254
export type ProjectRecordings = { display: Video; camera: Video | null; audio: Audio | null }
255+
export type RecordingDeleted = { path: string }
250256
export type RecordingInfo = { captureTarget: ScreenCaptureTarget }
251257
export type RecordingMeta = { pretty_name: string; sharing?: SharingMeta | null; display: Display; camera?: CameraMeta | null; audio?: AudioMeta | null; segments?: RecordingSegment[]; cursor: string | null }
252258
export type RecordingMetaChanged = { id: string }

0 commit comments

Comments
 (0)