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
7 changes: 7 additions & 0 deletions apps/desktop/src-tauri/src/general_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ pub struct GeneralSettingsStore {
pub excluded_windows: Vec<WindowExclusion>,
#[serde(default)]
pub delete_instant_recordings_after_upload: bool,
#[serde(default = "default_instant_mode_max_resolution")]
pub instant_mode_max_resolution: u32,
}

fn default_enable_native_camera_preview() -> bool {
Expand All @@ -139,6 +141,10 @@ fn default_true() -> bool {
true
}

fn default_instant_mode_max_resolution() -> u32 {
1920
}

fn default_server_url() -> String {
std::option_env!("VITE_SERVER_URL")
.unwrap_or("https://cap.so")
Expand Down Expand Up @@ -180,6 +186,7 @@ impl Default for GeneralSettingsStore {
post_deletion_behaviour: PostDeletionBehaviour::DoNothing,
excluded_windows: default_excluded_windows(),
delete_instant_recordings_after_upload: false,
instant_mode_max_resolution: 1920,
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion apps/desktop/src-tauri/src/recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ pub async fn start_recording(
Err(SendError::HandlerError(camera::LockFeedError::NoInput)) => None,
Err(e) => return Err(e.to_string()),
};

#[cfg(target_os = "macos")]
let shareable_content = crate::platform::get_shareable_content()
.await
Expand Down Expand Up @@ -537,7 +538,13 @@ pub async fn start_recording(
recording_dir.clone(),
inputs.capture_target.clone(),
)
.with_system_audio(inputs.capture_system_audio);
.with_system_audio(inputs.capture_system_audio)
.with_max_output_size(
general_settings
.as_ref()
.map(|settings| settings.instant_mode_max_resolution)
.unwrap_or_else(|| 1920),
);

#[cfg(target_os = "macos")]
{
Expand Down
52 changes: 32 additions & 20 deletions apps/desktop/src/routes/(window-chrome)/settings/general.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ const getWindowOptionLabel = (window: CaptureWindow) => {
return parts.join(" • ");
};

const createDefaultGeneralSettings = (): GeneralSettingsStore => ({
type ExtendedGeneralSettingsStore = GeneralSettingsStore;

const createDefaultGeneralSettings = (): ExtendedGeneralSettingsStore => ({
uploadIndividualFiles: false,
hideDockIcon: false,
autoCreateShareableLink: false,
Expand All @@ -71,11 +73,12 @@ const createDefaultGeneralSettings = (): GeneralSettingsStore => ({
autoZoomOnClicks: false,
custom_cursor_capture2: true,
excludedWindows: [],
instantModeMaxResolution: 1920,
});

const deriveInitialSettings = (
store: GeneralSettingsStore | null,
): GeneralSettingsStore => {
): ExtendedGeneralSettingsStore => {
const defaults = createDefaultGeneralSettings();
if (!store) return defaults;

Expand All @@ -85,6 +88,16 @@ const deriveInitialSettings = (
};
};

const INSTANT_MODE_RESOLUTION_OPTIONS = [
{ value: 1280, label: "720p" },
{ value: 1920, label: "1080p" },
{ value: 2560, label: "1440p" },
{ value: 3840, label: "4K" },
] satisfies {
value: number;
label: string;
}[];

export default function GeneralSettings() {
const [store] = createResource(() => generalSettingsStore.get());

Expand Down Expand Up @@ -167,7 +180,7 @@ function AppearanceSection(props: {
}

function Inner(props: { initialStore: GeneralSettingsStore | null }) {
const [settings, setSettings] = createStore<GeneralSettingsStore>(
const [settings, setSettings] = createStore<ExtendedGeneralSettingsStore>(
deriveInitialSettings(props.initialStore),
);

Expand Down Expand Up @@ -417,13 +430,23 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
)}

<SettingGroup title="Recording">
<SelectSettingItem
label="Instant mode max resolution"
description="Choose the maximum resolution for Instant Mode recordings."
value={settings.instantModeMaxResolution ?? 1920}
onChange={(value) =>
handleChange("instantModeMaxResolution", value)
}
options={INSTANT_MODE_RESOLUTION_OPTIONS.map((option) => ({
text: option.label,
value: option.value,
}))}
/>
<SelectSettingItem
label="Recording countdown"
description="Countdown before recording starts"
value={settings.recordingCountdown ?? 0}
onChange={(value) =>
handleChange("recordingCountdown", value as number)
}
onChange={(value) => handleChange("recordingCountdown", value)}
options={[
{ text: "Off", value: 0 },
{ text: "3 seconds", value: 3 },
Expand All @@ -436,10 +459,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
description="The main window recording start behaviour"
value={settings.mainWindowRecordingStartBehaviour ?? "close"}
onChange={(value) =>
handleChange(
"mainWindowRecordingStartBehaviour",
value as MainWindowRecordingStartBehaviour,
)
handleChange("mainWindowRecordingStartBehaviour", value)
}
options={[
{ text: "Close", value: "close" },
Expand All @@ -451,10 +471,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
description="The studio recording finish behaviour"
value={settings.postStudioRecordingBehaviour ?? "openEditor"}
onChange={(value) =>
handleChange(
"postStudioRecordingBehaviour",
value as PostStudioRecordingBehaviour,
)
handleChange("postStudioRecordingBehaviour", value)
}
options={[
{ text: "Open editor", value: "openEditor" },
Expand All @@ -468,12 +485,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
label="After deleting recording behaviour"
description="Should Cap reopen after deleting an in progress recording?"
value={settings.postDeletionBehaviour ?? "doNothing"}
onChange={(value) =>
handleChange(
"postDeletionBehaviour",
value as PostDeletionBehaviour,
)
}
onChange={(value) => handleChange("postDeletionBehaviour", value)}
options={[
{ text: "Do Nothing", value: "doNothing" },
{
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/utils/tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ export type ExportSettings = ({ format: "Mp4" } & Mp4ExportSettings) | ({ format
export type FileType = "recording" | "screenshot"
export type Flags = { captions: boolean }
export type FramesRendered = { renderedCount: number; totalFrames: number; type: "FramesRendered" }
export type GeneralSettingsStore = { instanceId?: string; uploadIndividualFiles?: boolean; hideDockIcon?: boolean; hapticsEnabled?: boolean; autoCreateShareableLink?: boolean; enableNotifications?: boolean; disableAutoOpenLinks?: boolean; hasCompletedStartup?: boolean; theme?: AppTheme; commercialLicense?: CommercialLicense | null; lastVersion?: string | null; windowTransparency?: boolean; postStudioRecordingBehaviour?: PostStudioRecordingBehaviour; mainWindowRecordingStartBehaviour?: MainWindowRecordingStartBehaviour; custom_cursor_capture2?: boolean; serverUrl?: string; recordingCountdown?: number | null; enableNativeCameraPreview: boolean; autoZoomOnClicks?: boolean; enableNewRecordingFlow: boolean; postDeletionBehaviour?: PostDeletionBehaviour; excludedWindows?: WindowExclusion[]; deleteInstantRecordingsAfterUpload?: boolean }
export type GeneralSettingsStore = { instanceId?: string; uploadIndividualFiles?: boolean; hideDockIcon?: boolean; hapticsEnabled?: boolean; autoCreateShareableLink?: boolean; enableNotifications?: boolean; disableAutoOpenLinks?: boolean; hasCompletedStartup?: boolean; theme?: AppTheme; commercialLicense?: CommercialLicense | null; lastVersion?: string | null; windowTransparency?: boolean; postStudioRecordingBehaviour?: PostStudioRecordingBehaviour; mainWindowRecordingStartBehaviour?: MainWindowRecordingStartBehaviour; custom_cursor_capture2?: boolean; serverUrl?: string; recordingCountdown?: number | null; enableNativeCameraPreview: boolean; autoZoomOnClicks?: boolean; enableNewRecordingFlow: boolean; postDeletionBehaviour?: PostDeletionBehaviour; excludedWindows?: WindowExclusion[]; deleteInstantRecordingsAfterUpload?: boolean; instantModeMaxResolution?: number }
export type GifExportSettings = { fps: number; resolution_base: XY<number>; quality: GifQuality | null }
export type GifQuality = {
/**
Expand Down
Loading
Loading