@@ -115,6 +115,21 @@ impl PreviewCursorCache {
115115 }
116116}
117117
118+ fn refresh_project_snapshot (
119+ project_rx : & mut watch:: Receiver < ProjectConfiguration > ,
120+ snapshot : & mut Arc < ProjectConfiguration > ,
121+ ) -> bool {
122+ let refreshed = {
123+ let project = project_rx. borrow_and_update ( ) ;
124+ if !project. has_changed ( ) {
125+ return false ;
126+ }
127+ Arc :: new ( project. clone ( ) )
128+ } ;
129+ * snapshot = refreshed;
130+ true
131+ }
132+
118133fn get_video_duration_fallback ( path : & Path ) -> Option < f64 > {
119134 tracing:: debug!( "get_video_duration_fallback called for: {:?}" , path) ;
120135 let input = match ffmpeg:: format:: input ( path) {
@@ -985,6 +1000,7 @@ impl EditorInstance {
9851000 let mut prefetch_cancel_token: Option < CancellationToken > = None ;
9861001 let mut cursor_cache = PreviewCursorCache :: default ( ) ;
9871002 let mut project_rx = self . project_config . 1 . clone ( ) ;
1003+ let mut project = Arc :: new ( project_rx. borrow_and_update ( ) . clone ( ) ) ;
9881004 let mut zoom_timelines = HashMap :: < u32 , ZoomTransformTimeline > :: new ( ) ;
9891005 let mut outgoing_zoom_timelines = HashMap :: < u32 , ZoomTransformTimeline > :: new ( ) ;
9901006
@@ -1011,14 +1027,10 @@ impl EditorInstance {
10111027 break ;
10121028 }
10131029
1014- let project = {
1015- let project = project_rx. borrow_and_update ( ) ;
1016- if project. has_changed ( ) {
1017- zoom_timelines. clear ( ) ;
1018- outgoing_zoom_timelines. clear ( ) ;
1019- }
1020- project. clone ( )
1021- } ;
1030+ if refresh_project_snapshot ( & mut project_rx, & mut project) {
1031+ zoom_timelines. clear ( ) ;
1032+ outgoing_zoom_timelines. clear ( ) ;
1033+ }
10221034 let frame_time = frame_number as f64 / fps as f64 ;
10231035 let transition_mapping = project. timeline . as_ref ( ) . and_then ( |timeline| {
10241036 if timeline. transitions . is_empty ( ) {
@@ -2250,6 +2262,43 @@ mod tests {
22502262 }
22512263 }
22522264
2265+ #[ test]
2266+ fn preview_project_snapshot_is_shared_until_the_project_changes ( ) {
2267+ let ( _untouched_tx, untouched_rx) = watch:: channel ( ProjectConfiguration :: default ( ) ) ;
2268+ let ( edited_tx, edited_rx) = watch:: channel ( ProjectConfiguration :: default ( ) ) ;
2269+ edited_tx. send_modify ( |project| project. background . padding = 12.0 ) ;
2270+
2271+ for ( mut project_rx, padding) in [ ( untouched_rx, 0.0 ) , ( edited_rx, 12.0 ) ] {
2272+ let mut snapshot = Arc :: new ( project_rx. borrow_and_update ( ) . clone ( ) ) ;
2273+ let initial = Arc :: clone ( & snapshot) ;
2274+ for _ in 0 ..3 {
2275+ assert ! ( !refresh_project_snapshot( & mut project_rx, & mut snapshot) ) ;
2276+ assert ! ( Arc :: ptr_eq( & snapshot, & initial) ) ;
2277+ }
2278+ assert_eq ! ( snapshot. background. padding, padding) ;
2279+ }
2280+ }
2281+
2282+ #[ test]
2283+ fn preview_project_snapshot_refreshes_once_to_the_latest_project ( ) {
2284+ let ( project_tx, mut project_rx) = watch:: channel ( ProjectConfiguration :: default ( ) ) ;
2285+ let mut snapshot = Arc :: new ( project_rx. borrow_and_update ( ) . clone ( ) ) ;
2286+ let initial = Arc :: clone ( & snapshot) ;
2287+
2288+ for padding in [ 4.0 , 8.0 , 16.0 ] {
2289+ project_tx. send_modify ( |project| project. background . padding = padding) ;
2290+ }
2291+
2292+ assert ! ( refresh_project_snapshot( & mut project_rx, & mut snapshot) ) ;
2293+ assert ! ( !Arc :: ptr_eq( & snapshot, & initial) ) ;
2294+ assert_eq ! ( snapshot. background. padding, 16.0 ) ;
2295+ assert_eq ! ( initial. background. padding, 0.0 ) ;
2296+
2297+ let refreshed = Arc :: clone ( & snapshot) ;
2298+ assert ! ( !refresh_project_snapshot( & mut project_rx, & mut snapshot) ) ;
2299+ assert ! ( Arc :: ptr_eq( & snapshot, & refreshed) ) ;
2300+ }
2301+
22532302 #[ test]
22542303 fn audio_timing_repair_uses_startup_trimmed_overlap ( ) {
22552304 let summary = AudioGapSummary {
0 commit comments