diff --git a/apps/desktop/src-tauri/src/permissions.rs b/apps/desktop/src-tauri/src/permissions.rs index 17b9e7153e..345946d40c 100644 --- a/apps/desktop/src-tauri/src/permissions.rs +++ b/apps/desktop/src-tauri/src/permissions.rs @@ -156,6 +156,14 @@ pub(crate) fn sync_macos_dock_visibility(app: &tauri::AppHandle) { #[cfg(target_os = "macos")] fn macos_permission_status(permission: &OSPermission, initial_check: bool) -> OSPermissionStatus { + #[cfg(debug_assertions)] + if matches!( + permission, + OSPermission::ScreenRecording | OSPermission::Accessibility + ) { + return OSPermissionStatus::Granted; + } + match permission { OSPermission::ScreenRecording => { let granted = scap_screencapturekit::has_permission(); diff --git a/apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx b/apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx index c7f67ca76a..9093e24e4f 100644 --- a/apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx +++ b/apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx @@ -34,7 +34,11 @@ export function CaptionsTrack(props: { const minDuration = () => Math.max(MIN_SEGMENT_SECS, secsPerPixel() * MIN_SEGMENT_PIXELS); - const captionSegments = () => project.timeline?.captionSegments ?? []; + const captionSegments = createMemo(() => + (project.timeline?.captionSegments ?? []).filter( + (s) => s.start < totalDuration(), + ), + ); const selectedCaptionIndices = createMemo(() => { const selection = editorState.timeline.selection; if (!selection || selection.type !== "caption") return null; @@ -157,7 +161,8 @@ export function CaptionsTrack(props: { return indices.has(i()); }); - const segmentWidth = () => segment.end - segment.start; + const segmentWidth = () => + Math.min(segment.end, totalDuration()) - segment.start; return ( { e.stopPropagation(); if (editorState.timeline.interactMode === "split") { diff --git a/apps/desktop/src/routes/editor/Timeline/KeyboardTrack.tsx b/apps/desktop/src/routes/editor/Timeline/KeyboardTrack.tsx index 52c3d6feb2..9cefb84bfe 100644 --- a/apps/desktop/src/routes/editor/Timeline/KeyboardTrack.tsx +++ b/apps/desktop/src/routes/editor/Timeline/KeyboardTrack.tsx @@ -32,7 +32,11 @@ export function KeyboardTrack(props: { const minDuration = () => Math.max(MIN_SEGMENT_SECS, secsPerPixel() * MIN_SEGMENT_PIXELS); - const keyboardSegments = () => project.timeline?.keyboardSegments ?? []; + const keyboardSegments = createMemo(() => + (project.timeline?.keyboardSegments ?? []).filter( + (s) => s.start < totalDuration(), + ), + ); const selectedKeyboardIndices = createMemo(() => { const selection = editorState.timeline.selection; if (!selection || selection.type !== "keyboard") return null; @@ -149,7 +153,8 @@ export function KeyboardTrack(props: { return indices.has(i()); }); - const segmentWidth = () => segment.end - segment.start; + const segmentWidth = () => + Math.min(segment.end, totalDuration()) - segment.start; return ( { e.stopPropagation(); if (editorState.timeline.interactMode === "split") { diff --git a/crates/audio/src/latency.rs b/crates/audio/src/latency.rs index 364c5d3faf..2a7804566e 100644 --- a/crates/audio/src/latency.rs +++ b/crates/audio/src/latency.rs @@ -685,15 +685,13 @@ mod macos { let mut latency_secs = total_frames as f64 / effective_rate; match transport_kind { - OutputTransportKind::Airplay => { - if latency_secs < AIRPLAY_MIN_LATENCY_SECS { - latency_secs = AIRPLAY_MIN_LATENCY_SECS; - } + OutputTransportKind::Airplay if latency_secs < AIRPLAY_MIN_LATENCY_SECS => { + latency_secs = AIRPLAY_MIN_LATENCY_SECS; } - OutputTransportKind::Wireless | OutputTransportKind::ContinuityWireless => { - if latency_secs < WIRELESS_MIN_LATENCY_SECS { - latency_secs = WIRELESS_MIN_LATENCY_SECS; - } + OutputTransportKind::Wireless | OutputTransportKind::ContinuityWireless + if latency_secs < WIRELESS_MIN_LATENCY_SECS => + { + latency_secs = WIRELESS_MIN_LATENCY_SECS; } _ => {} } diff --git a/crates/rendering-skia/src/layers/background.rs b/crates/rendering-skia/src/layers/background.rs index 90fd81b09b..71e187695a 100644 --- a/crates/rendering-skia/src/layers/background.rs +++ b/crates/rendering-skia/src/layers/background.rs @@ -277,31 +277,29 @@ impl RecordableLayer for BackgroundLayer { // Handle image loading if needed match &new_background { - Background::Image { path } | Background::Wallpaper { path } => { - if self.image_path.as_ref() != Some(path) || self.loaded_image.is_none() { - // For now, we'll do synchronous loading. In a real implementation, - // this should be async or cached at a higher level - match std::fs::read(path) { - Ok(image_data) => { - let data = skia_safe::Data::new_copy(&image_data); - if let Some(image) = Image::from_encoded(&data) { - self.loaded_image = Some(image); - self.image_path = Some(path.clone()); - } else { - tracing::error!("Failed to decode image: {:?}", path); - return Err(SkiaRenderingError::Other(anyhow::anyhow!( - "Failed to decode image" - ))); - } - } - Err(e) => { - tracing::error!("Failed to load image: {:?}, error: {}", path, e); + Background::Image { path } | Background::Wallpaper { path } + if self.image_path.as_ref() != Some(path) || self.loaded_image.is_none() => + { + match std::fs::read(path) { + Ok(image_data) => { + let data = skia_safe::Data::new_copy(&image_data); + if let Some(image) = Image::from_encoded(&data) { + self.loaded_image = Some(image); + self.image_path = Some(path.clone()); + } else { + tracing::error!("Failed to decode image: {:?}", path); return Err(SkiaRenderingError::Other(anyhow::anyhow!( - "Failed to load image: {}", - e + "Failed to decode image" ))); } } + Err(e) => { + tracing::error!("Failed to load image: {:?}, error: {}", path, e); + return Err(SkiaRenderingError::Other(anyhow::anyhow!( + "Failed to load image: {}", + e + ))); + } } } _ => {} diff --git a/crates/rendering/src/decoder/multi_position.rs b/crates/rendering/src/decoder/multi_position.rs index 318c0d4d8f..98e7cd97eb 100644 --- a/crates/rendering/src/decoder/multi_position.rs +++ b/crates/rendering/src/decoder/multi_position.rs @@ -204,7 +204,7 @@ impl DecoderPoolManager { .iter() .map(|(&frame, &count)| (frame, count)) .collect(); - hotspots.sort_by(|a, b| b.1.cmp(&a.1)); + hotspots.sort_by_key(|b| std::cmp::Reverse(b.1)); let top_hotspots: Vec = hotspots .into_iter() diff --git a/crates/scap-targets/src/main.rs b/crates/scap-targets/src/main.rs index 8a836ddb53..d24f8f022d 100644 --- a/crates/scap-targets/src/main.rs +++ b/crates/scap-targets/src/main.rs @@ -128,7 +128,7 @@ fn main() { }) .collect::>(); - relevant_windows.sort_by(|a, b| b.1.cmp(&a.1)); + relevant_windows.sort_by_key(|b| std::cmp::Reverse(b.1)); // Print current topmost window info if let Some((topmost_window, level)) = relevant_windows.first() diff --git a/crates/scap-targets/src/platform/macos.rs b/crates/scap-targets/src/platform/macos.rs index 7436b01e59..3b7b139632 100644 --- a/crates/scap-targets/src/platform/macos.rs +++ b/crates/scap-targets/src/platform/macos.rs @@ -290,7 +290,7 @@ impl WindowImpl { }) .collect::>(); - windows_with_level.sort_by(|a, b| b.1.cmp(&a.1)); + windows_with_level.sort_by_key(|b| std::cmp::Reverse(b.1)); windows_with_level.first().map(|(window, _)| *window) }