Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions apps/desktop/src-tauri/src/general_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde_json::json;
use specta::Type;
use tauri::{AppHandle, Wry};
use tauri_plugin_store::StoreExt;
use tracing::error;
use uuid::Uuid;

#[derive(Default, Serialize, Deserialize, Type, Debug, Clone, Copy)]
Expand All @@ -21,6 +22,14 @@ pub enum MainWindowRecordingStartBehaviour {
Minimise,
}

#[derive(Default, Serialize, Deserialize, Type, Debug, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum PostDeletionBehaviour {
#[default]
DoNothing,
ReopenRecordingWindow,
}

impl MainWindowRecordingStartBehaviour {
pub fn perform(&self, window: &tauri::WebviewWindow) -> tauri::Result<()> {
match self {
Expand Down Expand Up @@ -79,6 +88,8 @@ pub struct GeneralSettingsStore {
pub enable_native_camera_preview: bool,
#[serde(default)]
pub auto_zoom_on_clicks: bool,
#[serde(default)]
pub post_deletion_behaviour: PostDeletionBehaviour,
}

fn default_server_url() -> String {
Expand Down Expand Up @@ -119,6 +130,7 @@ impl Default for GeneralSettingsStore {
_open_editor_after_recording: false,
enable_native_camera_preview: false,
auto_zoom_on_clicks: false,
post_deletion_behaviour: PostDeletionBehaviour::DoNothing,
}
}
}
Expand Down Expand Up @@ -178,9 +190,9 @@ pub fn init(app: &AppHandle) {
let store = match GeneralSettingsStore::get(app) {
Ok(Some(store)) => store,
Ok(None) => GeneralSettingsStore::default(),
e => {
e.unwrap();
return;
Err(e) => {
error!("Failed to deserialize general settings store: {}", e);
GeneralSettingsStore::default()
}
};

Expand Down
20 changes: 19 additions & 1 deletion apps/desktop/src-tauri/src/recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
audio::AppSounds,
auth::AuthStore,
create_screenshot,
general_settings::{GeneralSettingsStore, PostStudioRecordingBehaviour},
general_settings::{GeneralSettingsStore, PostDeletionBehaviour, PostStudioRecordingBehaviour},
open_external_link,
presets::PresetsStore,
upload::{
Expand Down Expand Up @@ -485,6 +485,7 @@ pub async fn start_recording(
// this clears the current recording for us
handle_recording_end(app, None, &mut state).await.ok();
}
// Actor hasn't errored, it's just finished
_ => {}
}
}
Expand Down Expand Up @@ -589,6 +590,23 @@ pub async fn delete_recording(app: AppHandle, state: MutableState<'_, App>) -> R
)
.await;
}

// Check user's post-deletion behavior setting
let settings = GeneralSettingsStore::get(&app)
.ok()
.flatten()
.unwrap_or_default();

if let Some(window) = CapWindowId::InProgressRecording.get(&app) {
let _ = window.close();
}

match settings.post_deletion_behaviour {
PostDeletionBehaviour::DoNothing => {}
PostDeletionBehaviour::ReopenRecordingWindow => {
let _ = ShowCapWindow::Main.show(&app).await;
}
}
}

Ok(())
Expand Down
47 changes: 46 additions & 1 deletion apps/desktop/src/routes/(window-chrome)/settings/general.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
type GeneralSettingsStore,
type MainWindowRecordingStartBehaviour,
type PostStudioRecordingBehaviour,
type PostDeletionBehaviour,
} from "~/utils/tauri";
import { CheckMenuItem, Menu } from "@tauri-apps/api/menu";
import { confirm } from "@tauri-apps/plugin-dialog";
Expand Down Expand Up @@ -148,9 +149,14 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
value:
| MainWindowRecordingStartBehaviour
| PostStudioRecordingBehaviour
| PostDeletionBehaviour
| number;
onChange: (
value: MainWindowRecordingStartBehaviour | PostStudioRecordingBehaviour
value:
| MainWindowRecordingStartBehaviour
| PostStudioRecordingBehaviour
| PostDeletionBehaviour
| number
) => void | Promise<void>;
};

Expand Down Expand Up @@ -253,6 +259,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
value:
| MainWindowRecordingStartBehaviour
| PostStudioRecordingBehaviour
| PostDeletionBehaviour
| number
) => handleChange("recordingCountdown", value as number),
},
Expand All @@ -267,6 +274,8 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
value:
| MainWindowRecordingStartBehaviour
| PostStudioRecordingBehaviour
| PostDeletionBehaviour
| number
) =>
handleChange(
"mainWindowRecordingStartBehaviour",
Expand All @@ -284,12 +293,33 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
value:
| MainWindowRecordingStartBehaviour
| PostStudioRecordingBehaviour
| PostDeletionBehaviour
| number
) =>
handleChange(
"postStudioRecordingBehaviour",
value as PostStudioRecordingBehaviour
),
},
{
label: "After deleting recording",
description: "What happens to the window after deleting a recording",
type: "select",
get value() {
return settings.postDeletionBehaviour ?? "doNothing";
},
onChange: (
value:
| MainWindowRecordingStartBehaviour
| PostStudioRecordingBehaviour
| PostDeletionBehaviour
| number
) =>
handleChange(
"postDeletionBehaviour",
value as PostDeletionBehaviour
),
},
],
},
];
Expand All @@ -301,6 +331,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
getValue: () =>
| MainWindowRecordingStartBehaviour
| PostStudioRecordingBehaviour
| PostDeletionBehaviour
| number,
onChange: (value: any) => void,
options: { text: string; value: any }[]
Expand Down Expand Up @@ -421,6 +452,20 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
{ text: "10 seconds", value: 10 },
]
);
} else if (item.label === "After deleting recording") {
return renderRecordingSelect(
item.label,
item.description,
() => item.value,
item.onChange,
[
{ text: "Do Nothing", value: "exit" },
{
text: "Reopen Recording Window",
value: "reopenRecordingWindow",
},
]
);
}
}
return null;
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/src/utils/tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ openEditorAfterRecording?: boolean;
/**
* @deprecated can be removed when native camera preview is ready
*/
enableNativeCameraPreview?: boolean; autoZoomOnClicks?: boolean }
enableNativeCameraPreview?: boolean; autoZoomOnClicks?: boolean; postDeletionBehaviour?: PostDeletionBehaviour }
export type GifExportSettings = { fps: number; resolution_base: XY<number> }
export type HapticPattern = "Alignment" | "LevelChange" | "Generic"
export type HapticPerformanceTime = "Default" | "Now" | "DrawCompleted"
Expand All @@ -383,6 +383,7 @@ export type OSPermissionStatus = "notNeeded" | "empty" | "granted" | "denied"
export type OSPermissionsCheck = { screenRecording: OSPermissionStatus; microphone: OSPermissionStatus; camera: OSPermissionStatus; accessibility: OSPermissionStatus }
export type Plan = { upgraded: boolean; manual: boolean; last_checked: number }
export type Platform = "MacOS" | "Windows"
export type PostDeletionBehaviour = "doNothing" | "reopenRecordingWindow"
export type PostStudioRecordingBehaviour = "openEditor" | "showOverlay"
export type Preset = { name: string; config: ProjectConfiguration }
export type PresetsStore = { presets: Preset[]; default: number | null }
Expand Down
10 changes: 9 additions & 1 deletion crates/recording/src/studio_recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,15 @@ async fn run_actor_iteration(
// Cancel from any state
(Msg::Cancel(tx), state) => {
let result = match state {
State::Recording { mut pipeline, .. } => pipeline.inner.shutdown().await,
State::Recording { mut pipeline, .. } => {
if let Some(cursor) = &mut pipeline.cursor
&& let Some(actor) = cursor.actor.take()
{
actor.stop().await;
}

pipeline.inner.shutdown().await
}
State::Paused { .. } => Ok(()),
};

Expand Down
32 changes: 1 addition & 31 deletions packages/ui-solid/src/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,26 @@ export {}
declare global {
const IconCapArrows: typeof import('~icons/cap/arrows.jsx')['default']
const IconCapAudioOn: typeof import('~icons/cap/audio-on.jsx')['default']
const IconCapAuto: typeof import("~icons/cap/auto.jsx")["default"]
const IconCapBgBlur: typeof import('~icons/cap/bg-blur.jsx')['default']
const IconCapBlur: typeof import("~icons/cap/blur.jsx")["default"]
const IconCapCamera: typeof import('~icons/cap/camera.jsx')['default']
const IconCapCaptions: typeof import('~icons/cap/captions.jsx')['default']
const IconCapCheck: typeof import("~icons/cap/check.jsx")["default"]
const IconCapChevronDown: typeof import('~icons/cap/chevron-down.jsx')['default']
const IconCapCircle: typeof import('~icons/cap/circle.jsx')['default']
const IconCapCircleCheck: typeof import('~icons/cap/circle-check.jsx')['default']
const IconCapCirclePlus: typeof import('~icons/cap/circle-plus.jsx')['default']
const IconCapCircleX: typeof import('~icons/cap/circle-x.jsx')['default']
const IconCapClock: typeof import("~icons/cap/clock.jsx")["default"]
const IconCapCopy: typeof import('~icons/cap/copy.jsx')['default']
const IconCapCorners: typeof import('~icons/cap/corners.jsx')['default']
const IconCapCrop: typeof import('~icons/cap/crop.jsx')['default']
const IconCapCursor: typeof import('~icons/cap/cursor.jsx')['default']
const IconCapDownload: typeof import("~icons/cap/download.jsx")["default"]
const IconCapEditor: typeof import('~icons/cap/editor.jsx')['default']
const IconCapEnlarge: typeof import('~icons/cap/enlarge.jsx')['default']
const IconCapFile: typeof import('~icons/cap/file.jsx')['default']
const IconCapFilmCut: typeof import('~icons/cap/film-cut.jsx')['default']
const IconCapFrameFirst: typeof import("~icons/cap/frame-first.jsx")["default"]
const IconCapFrameLast: typeof import("~icons/cap/frame-last.jsx")["default"]
const IconCapGauge: typeof import('~icons/cap/gauge.jsx')['default']
const IconCapHotkeys: typeof import('~icons/cap/hotkeys.jsx')['default']
const IconCapImage: typeof import('~icons/cap/image.jsx')['default']
const IconCapInfo: typeof import('~icons/cap/info.jsx')['default']
const IconCapInset: typeof import("~icons/cap/inset.jsx")["default"]
const IconCapInstant: typeof import('~icons/cap/instant.jsx')['default']
const IconCapLayout: typeof import('~icons/cap/layout.jsx')['default']
const IconCapLink: typeof import('~icons/cap/link.jsx')['default']
Expand All @@ -45,8 +37,6 @@ declare global {
const IconCapMessageBubble: typeof import('~icons/cap/message-bubble.jsx')['default']
const IconCapMicrophone: typeof import('~icons/cap/microphone.jsx')['default']
const IconCapMoreVertical: typeof import('~icons/cap/more-vertical.jsx')['default']
const IconCapMoveLeft: typeof import("~icons/cap/move-left.jsx")["default"]
const IconCapMoveRight: typeof import("~icons/cap/move-right.jsx")["default"]
const IconCapNext: typeof import('~icons/cap/next.jsx')['default']
const IconCapPadding: typeof import('~icons/cap/padding.jsx')['default']
const IconCapPause: typeof import('~icons/cap/pause.jsx')['default']
Expand All @@ -56,58 +46,38 @@ declare global {
const IconCapPresets: typeof import('~icons/cap/presets.jsx')['default']
const IconCapPrev: typeof import('~icons/cap/prev.jsx')['default']
const IconCapRedo: typeof import('~icons/cap/redo.jsx')['default']
const IconCapRefresh: typeof import("~icons/cap/refresh.jsx")["default"]
const IconCapRestart: typeof import('~icons/cap/restart.jsx')['default']
const IconCapScissors: typeof import('~icons/cap/scissors.jsx')['default']
const IconCapSettings: typeof import('~icons/cap/settings.jsx')['default']
const IconCapShadow: typeof import('~icons/cap/shadow.jsx')['default']
const IconCapSize: typeof import("~icons/cap/size.jsx")["default"]
const IconCapSquare: typeof import('~icons/cap/square.jsx')['default']
const IconCapStop: typeof import("~icons/cap/stop.jsx")["default"]
const IconCapStopCircle: typeof import('~icons/cap/stop-circle.jsx')['default']
const IconCapTrash: typeof import('~icons/cap/trash.jsx')['default']
const IconCapUndo: typeof import('~icons/cap/undo.jsx')['default']
const IconCapUpload: typeof import("~icons/cap/upload.jsx")["default"]
const IconCapWindow: typeof import("~icons/cap/window.jsx")["default"]
const IconCapX: typeof import("~icons/cap/x.jsx")["default"]
const IconCapUpload: typeof import('~icons/cap/upload.jsx')['default']
const IconCapZoomIn: typeof import('~icons/cap/zoom-in.jsx')['default']
const IconCapZoomOut: typeof import('~icons/cap/zoom-out.jsx')['default']
const IconHugeiconsEaseCurveControlPoints: typeof import('~icons/hugeicons/ease-curve-control-points.jsx')['default']
const IconIcBaselineMonitor: typeof import("~icons/ic/baseline-monitor.jsx")["default"]
const IconIcRoundSearch: typeof import("~icons/ic/round-search.jsx")["default"]
const IconLucideAppWindowMac: typeof import('~icons/lucide/app-window-mac.jsx')['default']
const IconLucideBell: typeof import('~icons/lucide/bell.jsx')['default']
const IconLucideBug: typeof import('~icons/lucide/bug.jsx')['default']
const IconLucideCamera: typeof import("~icons/lucide/camera.jsx")["default"]
const IconLucideCheck: typeof import('~icons/lucide/check.jsx')['default']
const IconLucideChevronDown: typeof import("~icons/lucide/chevron-down.jsx")["default"]
const IconLucideClock: typeof import('~icons/lucide/clock.jsx')['default']
const IconLucideDatabase: typeof import('~icons/lucide/database.jsx')['default']
const IconLucideEdit: typeof import('~icons/lucide/edit.jsx')['default']
const IconLucideEye: typeof import('~icons/lucide/eye.jsx')['default']
const IconLucideFolder: typeof import('~icons/lucide/folder.jsx')['default']
const IconLucideGift: typeof import('~icons/lucide/gift.jsx')['default']
const IconLucideHardDrive: typeof import('~icons/lucide/hard-drive.jsx')['default']
const IconLucideLayoutGrid: typeof import("~icons/lucide/layout-grid.jsx")["default"]
const IconLucideLoaderCircle: typeof import('~icons/lucide/loader-circle.jsx')['default']
const IconLucideMessageCircle: typeof import("~icons/lucide/message-circle.jsx")["default"]
const IconLucideMessageSquare: typeof import("~icons/lucide/message-square.jsx")["default"]
const IconLucideMessageSquarePlus: typeof import('~icons/lucide/message-square-plus.jsx')['default']
const IconLucideMicOff: typeof import('~icons/lucide/mic-off.jsx')['default']
const IconLucideMonitor: typeof import('~icons/lucide/monitor.jsx')['default']
const IconLucideRabbit: typeof import("~icons/lucide/rabbit.jsx")["default"]
const IconLucideRectangle: typeof import("~icons/lucide/rectangle.jsx")["default"]
const IconLucideRectangleHorizontal: typeof import('~icons/lucide/rectangle-horizontal.jsx')['default']
const IconLucideRectangleSquare: typeof import("~icons/lucide/rectangle-square.jsx")["default"]
const IconLucideRotateCcw: typeof import('~icons/lucide/rotate-ccw.jsx')['default']
const IconLucideSearch: typeof import('~icons/lucide/search.jsx')['default']
const IconLucideSquarePlay: typeof import('~icons/lucide/square-play.jsx')['default']
const IconLucideUnplug: typeof import('~icons/lucide/unplug.jsx')['default']
const IconLucideVideo: typeof import("~icons/lucide/video.jsx")["default"]
const IconLucideVolume2: typeof import('~icons/lucide/volume2.jsx')['default']
const IconLucideVolumeX: typeof import('~icons/lucide/volume-x.jsx')['default']
const IconLucideX: typeof import("~icons/lucide/x.jsx")["default"]
const IconMaterialSymbolsScreenshotFrame2Rounded: typeof import('~icons/material-symbols/screenshot-frame2-rounded.jsx')['default']
const IconMdiMonitor: typeof import('~icons/mdi/monitor.jsx')['default']
const IconPhMonitorBold: typeof import('~icons/ph/monitor-bold.jsx')['default']
}
Loading