diff --git a/apps/desktop/src-tauri/src/general_settings.rs b/apps/desktop/src-tauri/src/general_settings.rs index 546b4960a8..dd8fce6d26 100644 --- a/apps/desktop/src-tauri/src/general_settings.rs +++ b/apps/desktop/src-tauri/src/general_settings.rs @@ -91,6 +91,8 @@ pub struct GeneralSettingsStore { #[serde(default)] pub hide_dock_icon: bool, #[serde(default)] + pub disable_update_checks: bool, + #[serde(default)] pub auto_create_shareable_link: bool, #[serde(default = "default_true")] pub enable_notifications: bool, @@ -188,6 +190,7 @@ impl Default for GeneralSettingsStore { instance_id: uuid::Uuid::new_v4(), upload_individual_files: false, hide_dock_icon: false, + disable_update_checks: false, auto_create_shareable_link: false, enable_notifications: true, disable_auto_open_links: false, diff --git a/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx b/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx index bfd7e51126..bc2e76a9e0 100644 --- a/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx +++ b/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx @@ -35,7 +35,7 @@ import Mode from "~/components/Mode"; import { RecoveryToast } from "~/components/RecoveryToast"; import Tooltip from "~/components/Tooltip"; import { Input } from "~/routes/editor/ui"; -import { authStore } from "~/store"; +import { authStore, generalSettingsStore } from "~/store"; import { createSignInMutation } from "~/utils/auth"; import { createTauriEventListener } from "~/utils/createEventListener"; import { @@ -930,6 +930,10 @@ function createUpdateCheck() { let update: updater.Update | undefined; try { + const generalSettings = await generalSettingsStore.get(); + + if (generalSettings?.disableUpdateChecks ?? false) return; + const result = await updater.check(); if (result) update = result; } catch (e) { diff --git a/apps/desktop/src/routes/(window-chrome)/settings/general.tsx b/apps/desktop/src/routes/(window-chrome)/settings/general.tsx index 4ba8d8c8a5..17dce19e59 100644 --- a/apps/desktop/src/routes/(window-chrome)/settings/general.tsx +++ b/apps/desktop/src/routes/(window-chrome)/settings/general.tsx @@ -69,6 +69,7 @@ type ExtendedGeneralSettingsStore = GeneralSettingsStore; const createDefaultGeneralSettings = (): ExtendedGeneralSettingsStore => ({ uploadIndividualFiles: false, hideDockIcon: false, + disableUpdateChecks: false, autoCreateShareableLink: false, enableNotifications: true, enableNativeCameraPreview: false, @@ -592,6 +593,14 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) { handleChange("serverUrl", origin); }} /> + + handleChange("disableUpdateChecks", v)} + /> + ); diff --git a/apps/desktop/src/routes/(window-chrome)/update.tsx b/apps/desktop/src/routes/(window-chrome)/update.tsx index 41cee01e50..9c34abf515 100644 --- a/apps/desktop/src/routes/(window-chrome)/update.tsx +++ b/apps/desktop/src/routes/(window-chrome)/update.tsx @@ -4,13 +4,22 @@ import { getCurrentWindow, UserAttentionType } from "@tauri-apps/api/window"; import { relaunch } from "@tauri-apps/plugin-process"; import { check, type Update } from "@tauri-apps/plugin-updater"; import { createResource, createSignal, Match, Show, Switch } from "solid-js"; +import { generalSettingsStore } from "~/store"; export default function () { const navigate = useNavigate(); const [updateError, setUpdateError] = createSignal(null); + const [updatesDisabled, setUpdatesDisabled] = createSignal(false); const [update] = createResource(async () => { try { + const generalSettings = await generalSettingsStore.get(); + + if (generalSettings?.disableUpdateChecks ?? false) { + setUpdatesDisabled(true); + return; + } + const update = await check(); if (!update) return; return update; @@ -23,6 +32,15 @@ export default function () { return ( + + + Update checks are currently disabled. + + To enable updates, go to General Settings and disable "Disable Update Checks". + + navigate("/")}>Go Back + + {updateError()} @@ -39,7 +57,7 @@ export default function () { No update available ) } diff --git a/apps/desktop/src/utils/tauri.ts b/apps/desktop/src/utils/tauri.ts index 0fb6d0b503..82ba7e9497 100644 --- a/apps/desktop/src/utils/tauri.ts +++ b/apps/desktop/src/utils/tauri.ts @@ -403,6 +403,7 @@ videoImportProgress: "video-import-progress" /** user-defined types **/ +export type AllGpusInfo = { gpus: GpuInfoDiag[]; primaryGpuIndex: number | null; isMultiGpuSystem: boolean; hasDiscreteGpu: boolean } export type Annotation = { id: string; type: AnnotationType; x: number; y: number; width: number; height: number; strokeColor: string; strokeWidth: number; fillColor: string; opacity: number; rotation: number; text: string | null; maskType?: MaskType | null; maskLevel?: number | null } export type AnnotationType = "arrow" | "circle" | "rectangle" | "text" | "mask" export type AppTheme = "system" | "light" | "dark" @@ -464,7 +465,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; 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; postDeletionBehaviour?: PostDeletionBehaviour; excludedWindows?: WindowExclusion[]; deleteInstantRecordingsAfterUpload?: boolean; instantModeMaxResolution?: number; defaultProjectNameTemplate?: string | null; crashRecoveryRecording?: boolean; maxFps?: number; editorPreviewQuality?: EditorPreviewQuality; mainWindowPosition?: WindowPosition | null; cameraWindowPosition?: WindowPosition | null; cameraWindowPositionsByMonitorName?: { [key in string]: WindowPosition } } +export type GeneralSettingsStore = { instanceId?: string; uploadIndividualFiles?: boolean; hideDockIcon?: boolean; disableUpdateChecks?: 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; postDeletionBehaviour?: PostDeletionBehaviour; excludedWindows?: WindowExclusion[]; deleteInstantRecordingsAfterUpload?: boolean; instantModeMaxResolution?: number; defaultProjectNameTemplate?: string | null; crashRecoveryRecording?: boolean; maxFps?: number; editorPreviewQuality?: EditorPreviewQuality; mainWindowPosition?: WindowPosition | null; cameraWindowPosition?: WindowPosition | null; cameraWindowPositionsByMonitorName?: { [key in string]: WindowPosition } } export type GifExportSettings = { fps: number; resolution_base: XY; quality: GifQuality | null } export type GifQuality = { /** @@ -476,6 +477,7 @@ quality: number | null; */ fast: boolean | null } export type GlideDirection = "none" | "left" | "right" | "up" | "down" +export type GpuInfoDiag = { vendor: string; description: string; dedicatedVideoMemoryMb: number; adapterIndex: number; isSoftwareAdapter: boolean; isBasicRenderDriver: boolean; supportsHardwareEncoding: boolean } export type HapticPattern = "alignment" | "levelChange" | "generic" export type HapticPerformanceTime = "default" | "now" | "drawCompleted" export type Hotkey = { code: string; meta: boolean; ctrl: boolean; alt: boolean; shift: boolean } @@ -489,7 +491,6 @@ export type JsonValue = [T] export type LogicalBounds = { position: LogicalPosition; size: LogicalSize } export type LogicalPosition = { x: number; y: number } export type LogicalSize = { width: number; height: number } -export type MacOSVersionInfo = { major: number; minor: number; patch: number; displayName: string; buildNumber: string; isAppleSilicon: boolean } export type MainWindowRecordingStartBehaviour = "close" | "minimise" export type MaskKeyframes = { position?: MaskVectorKeyframe[]; size?: MaskVectorKeyframe[]; intensity?: MaskScalarKeyframe[] } export type MaskKind = "sensitive" | "highlight" @@ -533,6 +534,7 @@ export type RecordingStatus = "pending" | "recording" export type RecordingStopped = null export type RecordingTargetMode = "display" | "window" | "area" | "camera" export type RenderFrameEvent = { frame_number: number; fps: number; resolution_base: XY } +export type RenderingStatus = { isUsingSoftwareRendering: boolean; isUsingBasicRenderDriver: boolean; hardwareEncodingAvailable: boolean; warningMessage: string | null } export type RequestOpenRecordingPicker = { target_mode: RecordingTargetMode | null } export type RequestOpenSettings = { page: string } export type RequestScreenCapturePrewarm = { force?: boolean } @@ -555,7 +557,7 @@ export type StartRecordingInputs = { capture_target: ScreenCaptureTarget; captur export type StereoMode = "stereo" | "monoL" | "monoR" export type StudioRecordingMeta = { segment: SingleSegment } | { inner: MultipleSegments } export type StudioRecordingStatus = { status: "InProgress" } | { status: "NeedsRemux" } | { status: "Failed"; error: string } | { status: "Complete" } -export type SystemDiagnostics = { macosVersion: MacOSVersionInfo | null; availableEncoders: string[]; screenCaptureSupported: boolean; metalSupported: boolean; gpuName: string | null } +export type SystemDiagnostics = { windowsVersion: WindowsVersionInfo | null; gpuInfo: GpuInfoDiag | null; allGpus: AllGpusInfo | null; renderingStatus: RenderingStatus; availableEncoders: string[]; graphicsCaptureSupported: boolean; d3D11VideoProcessorAvailable: boolean } export type TargetUnderCursor = { display_id: DisplayId | null; window: WindowUnderCursor | null } export type TextSegment = { start: number; end: number; enabled?: boolean; content?: string; center?: XY; size?: XY; fontFamily?: string; fontSize?: number; fontWeight?: number; italic?: boolean; color?: string; fadeDuration?: number } export type TimelineConfiguration = { segments: TimelineSegment[]; zoomSegments: ZoomSegment[]; sceneSegments?: SceneSegment[]; maskSegments?: MaskSegment[]; textSegments?: TextSegment[] } @@ -574,6 +576,7 @@ export type WindowExclusion = { bundleIdentifier?: string | null; ownerName?: st export type WindowId = string export type WindowPosition = { x: number; y: number; displayId?: DisplayId | null } export type WindowUnderCursor = { id: WindowId; app_name: string; bounds: LogicalBounds } +export type WindowsVersionInfo = { major: number; minor: number; build: number; displayName: string; meetsRequirements: boolean; isWindows11: boolean } export type XY = { x: T; y: T } export type ZoomMode = "auto" | { manual: { x: number; y: number } } export type ZoomSegment = { start: number; end: number; amount: number; mode: ZoomMode; glideDirection?: GlideDirection; glideSpeed?: number; instantAnimation?: boolean; edgeSnapRatio?: number }
Update checks are currently disabled.
+ To enable updates, go to General Settings and disable "Disable Update Checks". +
{updateError()}