Skip to content

Commit 231a6bc

Browse files
Merge pull request #1496 from CapSoftware/misc-fixes
Refactor pause tracking and improve configuration defaults
2 parents dcaccb6 + 9e8459d commit 231a6bc

File tree

15 files changed

+347
-545
lines changed

15 files changed

+347
-545
lines changed

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ jobs:
143143
- target: aarch64-apple-darwin
144144
runner: macos-latest-xlarge
145145
- target: x86_64-pc-windows-msvc
146-
runner: windows-latest
146+
runner: windows-latest-8-cores
147147
env:
148148
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
149149
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}

apps/desktop/src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cap-desktop"
3-
version = "0.4.1"
3+
version = "0.4.2"
44
description = "Beautiful screen recordings, owned by you."
55
authors = ["you"]
66
edition = "2024"

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,6 +2223,13 @@ async fn reset_microphone_permissions(_app: AppHandle) -> Result<(), ()> {
22232223
Ok(())
22242224
}
22252225

2226+
#[tauri::command]
2227+
#[specta::specta]
2228+
#[instrument(skip(app))]
2229+
async fn clear_presets(app: AppHandle) -> Result<(), String> {
2230+
presets::PresetsStore::clear(&app)
2231+
}
2232+
22262233
#[tauri::command]
22272234
#[specta::specta]
22282235
#[instrument(skip(app))]
@@ -2604,6 +2611,7 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
26042611
hotkeys::set_hotkey,
26052612
reset_camera_permissions,
26062613
reset_microphone_permissions,
2614+
clear_presets,
26072615
is_camera_window_open,
26082616
seek_to,
26092617
get_display_frame_for_cropping,

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,28 @@ pub struct Preset {
2323
impl PresetsStore {
2424
fn get(app: &AppHandle<Wry>) -> Result<Option<Self>, String> {
2525
match app.store("store").map(|s| s.get("presets")) {
26-
Ok(Some(store)) => {
27-
// Handle potential deserialization errors gracefully
28-
match serde_json::from_value(store) {
29-
Ok(settings) => Ok(Some(settings)),
30-
Err(_) => {
31-
error!("Failed to deserialize presets store");
32-
Ok(None)
33-
}
26+
Ok(Some(store)) => match serde_json::from_value(store.clone()) {
27+
Ok(settings) => Ok(Some(settings)),
28+
Err(e) => {
29+
error!(
30+
"Failed to deserialize presets store: {}. Raw value: {}",
31+
e,
32+
serde_json::to_string_pretty(&store).unwrap_or_default()
33+
);
34+
Ok(None)
3435
}
35-
}
36+
},
3637
_ => Ok(None),
3738
}
3839
}
3940

41+
pub fn clear(app: &AppHandle<Wry>) -> Result<(), String> {
42+
let store = app.store("store").map_err(|e| e.to_string())?;
43+
store.delete("presets");
44+
store.save().map_err(|e| e.to_string())?;
45+
Ok(())
46+
}
47+
4048
pub fn get_default_preset(app: &AppHandle<Wry>) -> Result<Option<Preset>, String> {
4149
let Some(this) = Self::get(app)? else {
4250
return Ok(None);

apps/desktop/src/routes/editor/ConfigSidebar.tsx

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,7 @@ function BackgroundConfig(props: { scrollRef: HTMLDivElement }) {
12621262
photoUrl.replace("file://", ""),
12631263
);
12641264

1265-
debouncedSetProject(rawPath);
1265+
setWallpaperSource(rawPath);
12661266
} catch (_err) {
12671267
toast.error("Failed to set wallpaper");
12681268
}
@@ -1324,17 +1324,14 @@ function BackgroundConfig(props: { scrollRef: HTMLDivElement }) {
13241324

13251325
let fileInput!: HTMLInputElement;
13261326

1327-
// Optimize the debounced set project function
1328-
const debouncedSetProject = (wallpaperPath: string) => {
1327+
const setWallpaperSource = (wallpaperPath: string) => {
13291328
const resumeHistory = projectHistory.pause();
1330-
queueMicrotask(() => {
1331-
batch(() => {
1332-
setProject("background", "source", {
1333-
type: "wallpaper",
1334-
path: wallpaperPath,
1335-
} as const);
1336-
resumeHistory();
1337-
});
1329+
batch(() => {
1330+
setProject("background", "source", {
1331+
type: "wallpaper",
1332+
path: wallpaperPath,
1333+
} as const);
1334+
resumeHistory();
13381335
});
13391336
};
13401337

@@ -1600,7 +1597,7 @@ function BackgroundConfig(props: { scrollRef: HTMLDivElement }) {
16001597

16011598
// Get the raw path without any URL prefixes
16021599

1603-
debouncedSetProject(wallpaper.rawPath);
1600+
setWallpaperSource(wallpaper.rawPath);
16041601

16051602
ensurePaddingForBackground();
16061603
} catch (_err) {

apps/desktop/src/routes/editor/Player.tsx

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,7 @@ export function PlayerContent() {
7373
end: segment.end,
7474
text: segment.text,
7575
})),
76-
settings: {
77-
enabled: captionsStore.state.settings.enabled,
78-
font: captionsStore.state.settings.font,
79-
size: captionsStore.state.settings.size,
80-
color: captionsStore.state.settings.color,
81-
backgroundColor: captionsStore.state.settings.backgroundColor,
82-
backgroundOpacity: captionsStore.state.settings.backgroundOpacity,
83-
position: captionsStore.state.settings.position,
84-
italic: captionsStore.state.settings.italic,
85-
outline: captionsStore.state.settings.outline,
86-
outlineColor: captionsStore.state.settings.outlineColor,
87-
exportWithSubtitles:
88-
captionsStore.state.settings.exportWithSubtitles,
89-
highlightColor: captionsStore.state.settings.highlightColor,
90-
fadeDuration: captionsStore.state.settings.fadeDuration,
91-
},
76+
settings: { ...captionsStore.state.settings },
9277
};
9378

9479
// Update the project with captions data

apps/desktop/src/routes/editor/PresetsDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function PresetsDropdown() {
4949
setShowSettings(false);
5050
const normalizedConfig = normalizeProject({
5151
...preset.config,
52-
timeline: project.timeline,
52+
timeline: project.timeline ?? null,
5353
clips: project.clips,
5454
});
5555
setProject(reconcile(normalizedConfig));

apps/desktop/src/routes/screenshot-editor/popovers/BackgroundSettingsPopover.tsx

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,17 +170,14 @@ export function BackgroundSettingsPopover() {
170170
setProject("background", "source", source);
171171
};
172172

173-
// Debounced set project for history
174-
const debouncedSetProject = (wallpaperPath: string) => {
173+
const setWallpaperSource = (wallpaperPath: string) => {
175174
const resumeHistory = projectHistory.pause();
176-
queueMicrotask(() => {
177-
batch(() => {
178-
setProject("background", "source", {
179-
type: "wallpaper",
180-
path: wallpaperPath,
181-
} as const);
182-
resumeHistory();
183-
});
175+
batch(() => {
176+
setProject("background", "source", {
177+
type: "wallpaper",
178+
path: wallpaperPath,
179+
} as const);
180+
resumeHistory();
184181
});
185182
};
186183

@@ -319,7 +316,7 @@ export function BackgroundSettingsPopover() {
319316
(w) => w.url === photoUrl,
320317
);
321318
if (wallpaper) {
322-
debouncedSetProject(wallpaper.rawPath);
319+
setWallpaperSource(wallpaper.rawPath);
323320
ensurePaddingForBackground();
324321
}
325322
}}

apps/desktop/src/utils/createPresets.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,28 @@ export function createPresets() {
2525
return {
2626
query,
2727
createPreset: async (preset: CreatePreset) => {
28-
const config = { ...preset.config };
29-
// @ts-expect-error we reeeally don't want the timeline in the preset
30-
config.timeline = undefined;
31-
config.clips = undefined;
28+
const config = {
29+
...preset.config,
30+
timeline: null,
31+
clips: [],
32+
};
3233

3334
await updatePresets((store) => {
3435
store.presets.push({ name: preset.name, config });
35-
store.default = preset.default ? store.presets.length : store.default;
36+
store.default = preset.default
37+
? store.presets.length - 1
38+
: store.default;
3639
});
3740
},
3841
deletePreset: (index: number) =>
3942
updatePresets((store) => {
4043
store.presets.splice(index, 1);
41-
store.default =
42-
index > store.presets.length - 1
43-
? store.presets.length - 1
44-
: store.default;
44+
if (store.default === null) return;
45+
if (index === store.default) {
46+
store.default = store.presets.length > 0 ? 0 : null;
47+
} else if (index < store.default) {
48+
store.default = store.default - 1;
49+
}
4550
}),
4651
setDefault: (index: number) =>
4752
updatePresets((store) => {

apps/desktop/src/utils/tauri.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ async resetCameraPermissions() : Promise<null> {
194194
async resetMicrophonePermissions() : Promise<null> {
195195
return await TAURI_INVOKE("reset_microphone_permissions");
196196
},
197+
async clearPresets() : Promise<null> {
198+
return await TAURI_INVOKE("clear_presets");
199+
},
197200
async isCameraWindowOpen() : Promise<boolean> {
198201
return await TAURI_INVOKE("is_camera_window_open");
199202
},
@@ -380,15 +383,15 @@ export type AnnotationType = "arrow" | "circle" | "rectangle" | "text" | "mask"
380383
export type AppTheme = "system" | "light" | "dark"
381384
export type AspectRatio = "wide" | "vertical" | "square" | "classic" | "tall"
382385
export type Audio = { duration: number; sample_rate: number; channels: number; start_time: number }
383-
export type AudioConfiguration = { mute: boolean; improve: boolean; micVolumeDb?: number; micStereoMode?: StereoMode; systemVolumeDb?: number }
386+
export type AudioConfiguration = { mute: boolean; improve: boolean; micVolumeDb: number; micStereoMode: StereoMode; systemVolumeDb: number }
384387
export type AudioInputLevelChange = number
385388
export type AudioMeta = { path: string; start_time?: number | null; device_id?: string | null }
386389
export type AuthSecret = { api_key: string } | { token: string; expires: number }
387390
export type AuthStore = { secret: AuthSecret; user_id: string | null; plan: Plan | null; intercom_hash: string | null; organizations?: Organization[] }
388-
export type BackgroundConfiguration = { source: BackgroundSource; blur: number; padding: number; rounding: number; roundingType?: CornerStyle; inset: number; crop: Crop | null; shadow?: number; advancedShadow?: ShadowConfiguration | null; border?: BorderConfiguration | null }
391+
export type BackgroundConfiguration = { source: BackgroundSource; blur: number; padding: number; rounding: number; roundingType: CornerStyle; inset: number; crop: Crop | null; shadow: number; advancedShadow: ShadowConfiguration | null; border: BorderConfiguration | null }
389392
export type BackgroundSource = { type: "wallpaper"; path: string | null } | { type: "image"; path: string | null } | { type: "color"; value: [number, number, number]; alpha?: number } | { type: "gradient"; from: [number, number, number]; to: [number, number, number]; angle?: number }
390393
export type BorderConfiguration = { enabled: boolean; width: number; color: [number, number, number]; opacity: number }
391-
export type Camera = { hide: boolean; mirror: boolean; position: CameraPosition; size: number; zoomSize: number | null; rounding?: number; shadow?: number; advancedShadow?: ShadowConfiguration | null; shape?: CameraShape; roundingType?: CornerStyle }
394+
export type Camera = { hide: boolean; mirror: boolean; position: CameraPosition; size: number; zoomSize: number | null; rounding: number; shadow: number; advancedShadow: ShadowConfiguration | null; shape: CameraShape; roundingType: CornerStyle }
392395
export type CameraInfo = { device_id: string; model_id: ModelIDType | null; display_name: string }
393396
export type CameraPosition = { x: CameraXPosition; y: CameraYPosition }
394397
export type CameraPreviewShape = "round" | "square" | "full"
@@ -398,7 +401,7 @@ export type CameraXPosition = "left" | "center" | "right"
398401
export type CameraYPosition = "top" | "bottom"
399402
export type CaptionData = { segments: CaptionSegment[]; settings: CaptionSettings | null }
400403
export type CaptionSegment = { id: string; start: number; end: number; text: string; words?: CaptionWord[] }
401-
export type CaptionSettings = { enabled: boolean; font: string; size: number; color: string; backgroundColor: string; backgroundOpacity: number; position?: string; italic: boolean; fontWeight?: number; outline: boolean; outlineColor: string; exportWithSubtitles: boolean; highlightColor?: string; fadeDuration?: number; lingerDuration?: number; wordTransitionDuration?: number; activeWordHighlight?: boolean }
404+
export type CaptionSettings = { enabled: boolean; font: string; size: number; color: string; backgroundColor: string; backgroundOpacity: number; position: string; italic: boolean; fontWeight: number; outline: boolean; outlineColor: string; exportWithSubtitles: boolean; highlightColor: string; fadeDuration: number; lingerDuration: number; wordTransitionDuration: number; activeWordHighlight: boolean }
402405
export type CaptionWord = { text: string; start: number; end: number }
403406
export type CaptionsData = { segments: CaptionSegment[]; settings: CaptionSettings }
404407
export type CaptureDisplay = { id: DisplayId; name: string; refresh_rate: number }
@@ -414,7 +417,7 @@ export type CurrentRecording = { target: CurrentRecordingTarget; mode: Recording
414417
export type CurrentRecordingChanged = null
415418
export type CurrentRecordingTarget = { window: { id: WindowId; bounds: LogicalBounds | null } } | { screen: { id: DisplayId } } | { area: { screen: DisplayId; bounds: LogicalBounds } }
416419
export type CursorAnimationStyle = "slow" | "mellow" | "custom"
417-
export type CursorConfiguration = { hide?: boolean; hideWhenIdle?: boolean; hideWhenIdleDelay?: number; size: number; type: CursorType; animationStyle: CursorAnimationStyle; tension: number; mass: number; friction: number; raw?: boolean; motionBlur?: number; useSvg?: boolean }
420+
export type CursorConfiguration = { hide: boolean; hideWhenIdle: boolean; hideWhenIdleDelay: number; size: number; type: CursorType; animationStyle: CursorAnimationStyle; tension: number; mass: number; friction: number; raw: boolean; motionBlur: number; useSvg: boolean }
418421
export type CursorMeta = { imagePath: string; hotspot: XY<number>; shape?: string | null }
419422
export type CursorType = "auto" | "pointer" | "circle"
420423
export type Cursors = { [key in string]: string } | { [key in string]: CursorMeta }
@@ -483,7 +486,7 @@ export type PostDeletionBehaviour = "doNothing" | "reopenRecordingWindow"
483486
export type PostStudioRecordingBehaviour = "openEditor" | "showOverlay"
484487
export type Preset = { name: string; config: ProjectConfiguration }
485488
export type PresetsStore = { presets: Preset[]; default: number | null }
486-
export type ProjectConfiguration = { aspectRatio: AspectRatio | null; background: BackgroundConfiguration; camera: Camera; audio: AudioConfiguration; cursor: CursorConfiguration; hotkeys: HotkeysConfiguration; timeline?: TimelineConfiguration | null; captions?: CaptionsData | null; clips?: ClipConfiguration[]; annotations?: Annotation[] }
489+
export type ProjectConfiguration = { aspectRatio: AspectRatio | null; background: BackgroundConfiguration; camera: Camera; audio: AudioConfiguration; cursor: CursorConfiguration; hotkeys: HotkeysConfiguration; timeline: TimelineConfiguration | null; captions: CaptionsData | null; clips: ClipConfiguration[]; annotations: Annotation[] }
487490
export type ProjectRecordingsMeta = { segments: SegmentRecordings[] }
488491
export type RecordingAction = "Started" | "InvalidAuthentication" | "UpgradeRequired"
489492
export type RecordingDeleted = { path: string }

0 commit comments

Comments
 (0)