11use super :: project:: PROJECT_STATE ;
22use crate :: {
3- global_logic, global_store ,
3+ global_logic,
44 logic:: { toast, tr:: tr} ,
55 logic_cb,
66 slint_generatedAppWindow:: {
@@ -131,15 +131,11 @@ fn video_editor_export_video(ui: &AppWindow, config: UIVideoEditorExportVideoCon
131131 toast:: async_toast_success ( ui_weak, "Video export completed" . to_string ( ) ) ;
132132 }
133133 Ok ( Err ( e) ) => toast:: async_toast_warn ( ui_weak, format ! ( "Video export failed: {}" , e) ) ,
134- Err ( _) => {
135- toast:: async_toast_warn ( ui_weak, "Video export was cancelled" . to_string ( ) ) ;
136- }
134+ Err ( _) => toast:: async_toast_warn ( ui_weak, "Video export was cancelled" . to_string ( ) ) ,
137135 }
138136 } ) ;
139137}
140138
141- // todo
142-
143139fn video_editor_export_audio ( ui : & AppWindow , config : UIVideoEditorExportAudioConfig ) {
144140 let ui_weak = ui. as_weak ( ) ;
145141
@@ -155,49 +151,36 @@ fn video_editor_export_audio(ui: &AppWindow, config: UIVideoEditorExportAudioCon
155151 . to_string ( )
156152 } ;
157153
158- let ext = match config. format {
159- crate :: slint_generatedAppWindow:: AudioFormat :: Aac => "aac" ,
160- crate :: slint_generatedAppWindow:: AudioFormat :: Mp3 => "mp3" ,
161- crate :: slint_generatedAppWindow:: AudioFormat :: Ogg => "ogg" ,
162- crate :: slint_generatedAppWindow:: AudioFormat :: Wav => "wav" ,
163- crate :: slint_generatedAppWindow:: AudioFormat :: Flac => "flac" ,
164- } ;
154+ let ext = global_logic ! ( ui)
155+ . invoke_audio_format_to_str ( config. format )
156+ . to_ascii_lowercase ( ) ;
157+ let format = config. format . into ( ) ;
158+ let channels = global_logic ! ( ui) . invoke_audio_channels_to_int ( config. channels ) as u16 ;
159+ let sample_rate = global_logic ! ( ui) . invoke_audio_sample_rate_to_int ( config. sample_rate ) as u32 ;
165160
166161 let Some ( output_path) = picker_save_file (
167162 ui_weak. clone ( ) ,
168163 & tr ( "Export Audio" ) ,
169164 & tr ( "Audio File" ) ,
170- & [ ext] ,
165+ & [ & ext] ,
171166 & format ! ( "{}.{}" , default_name, ext) ,
172167 ) else {
173168 return ;
174169 } ;
175170
171+ let file_name = output_path
172+ . file_name ( )
173+ . and_then ( |s| s. to_str ( ) )
174+ . unwrap_or ( "video.mp4" )
175+ . to_string ( ) ;
176+
176177 tokio:: spawn ( async move {
177178 let manager = {
178179 let state_guard = PROJECT_STATE . lock ( ) . unwrap ( ) ;
179180 let state = state_guard. as_ref ( ) . unwrap ( ) ;
180181 Arc :: new ( state. tracks_manager . clone ( ) )
181182 } ;
182183
183- let format = config. format . into ( ) ;
184-
185- let channels = match config. channels {
186- crate :: slint_generatedAppWindow:: AudioChannels :: Mono => 1 ,
187- crate :: slint_generatedAppWindow:: AudioChannels :: Stereo => 2 ,
188- } ;
189-
190- let sample_rate = match config. sample_rate {
191- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz8000 => 8000 ,
192- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz16000 => 16000 ,
193- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz24000 => 24000 ,
194- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz32000 => 32000 ,
195- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz44100 => 44100 ,
196- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz48000 => 48000 ,
197- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz96000 => 96000 ,
198- crate :: slint_generatedAppWindow:: AudioSampleRate :: Hz192000 => 192000 ,
199- } ;
200-
201184 let export_config = AudioExportConfig :: default ( )
202185 . with_output_path ( output_path. clone ( ) )
203186 . with_format ( format)
@@ -206,18 +189,19 @@ fn video_editor_export_audio(ui: &AppWindow, config: UIVideoEditorExportAudioCon
206189
207190 let task_id = NEXT_TASK_ID . fetch_add ( 1 , Ordering :: SeqCst ) ;
208191
209- let mut task = UIVideoEditorExportQueueItem :: default ( ) ;
210- task. name = format ! ( "Audio [{}]" , task_id) . into ( ) ;
211- task. media_type = UIMediaType :: Audio ;
212- task. progress = 0.0 ;
213- task. is_cancelled = false ;
192+ let task = UIVideoEditorExportQueueItem {
193+ id : format ! ( "Audio [{}]" , task_id) . into ( ) ,
194+ name : file_name. into ( ) ,
195+ media_type : UIMediaType :: Audio ,
196+ progress : 0.0 ,
197+ is_cancelled : false ,
198+ } ;
214199
215200 _ = ui_weak. upgrade_in_event_loop ( move |ui| {
216201 store_video_editor_export_queue ! ( ui) . push ( task) ;
217202 } ) ;
218203
219204 let ui_weak_for_progress = ui_weak. clone ( ) ;
220-
221205 let result = tokio:: task:: spawn_blocking ( move || {
222206 let exporter = AudioExporter :: new ( manager, export_config) ;
223207 exporter. export_with_progress ( move |progress| {
@@ -233,30 +217,10 @@ fn video_editor_export_audio(ui: &AppWindow, config: UIVideoEditorExportAudioCon
233217 match result {
234218 Ok ( Ok ( _) ) => {
235219 update_export_task_progress ( & ui_weak, task_id, 100.0 ) ;
236-
237- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
238- crate :: logic:: toast:: async_toast_success (
239- ui. as_weak ( ) ,
240- "Audio export completed" . to_string ( ) ,
241- ) ;
242- } ) ;
243- }
244- Ok ( Err ( e) ) => {
245- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
246- crate :: logic:: toast:: async_toast_warn (
247- ui. as_weak ( ) ,
248- format ! ( "Audio export failed: {}" , e) ,
249- ) ;
250- } ) ;
251- }
252- Err ( _) => {
253- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
254- crate :: logic:: toast:: async_toast_warn (
255- ui. as_weak ( ) ,
256- "Audio export was cancelled" . to_string ( ) ,
257- ) ;
258- } ) ;
220+ toast:: async_toast_success ( ui_weak, "Audio export completed" . to_string ( ) ) ;
259221 }
222+ Ok ( Err ( e) ) => toast:: async_toast_warn ( ui_weak, format ! ( "Audio export failed: {}" , e) ) ,
223+ Err ( _) => toast:: async_toast_warn ( ui_weak, "Audio export was cancelled" . to_string ( ) ) ,
260224 }
261225 } ) ;
262226}
@@ -276,142 +240,85 @@ fn video_editor_export_subtitle(ui: &AppWindow, ty: UISubtitleType) {
276240 . to_string ( )
277241 } ;
278242
279- let ext = match ty {
280- UISubtitleType :: Srt => "srt" ,
281- UISubtitleType :: Vtt => "vtt" ,
282- UISubtitleType :: Ass => "ass" ,
283- } ;
243+ let format = ty. into ( ) ;
244+ let ext = global_logic ! ( ui) . invoke_subtitle_to_str ( ty) ;
284245
285246 let Some ( output_path) = picker_save_file (
286247 ui_weak. clone ( ) ,
287248 & tr ( "Export Subtitle" ) ,
288249 & tr ( "Subtitle File" ) ,
289- & [ ext] ,
250+ & [ & ext] ,
290251 & format ! ( "{}.{}" , default_name, ext) ,
291252 ) else {
292253 return ;
293254 } ;
294255
256+ let file_name = output_path
257+ . file_name ( )
258+ . and_then ( |s| s. to_str ( ) )
259+ . unwrap_or ( "video.mp4" )
260+ . to_string ( ) ;
261+
295262 tokio:: spawn ( async move {
296263 let manager = {
297264 let state_guard = PROJECT_STATE . lock ( ) . unwrap ( ) ;
298265 let state = state_guard. as_ref ( ) . unwrap ( ) ;
299266 Arc :: new ( state. tracks_manager . clone ( ) )
300267 } ;
301268
302- let format = ty. into ( ) ;
303-
304269 let export_config = SubtitleExportConfig :: default ( )
305270 . with_output_base_path ( output_path. clone ( ) )
306271 . with_format ( format) ;
307272
308273 let task_id = NEXT_TASK_ID . fetch_add ( 1 , Ordering :: SeqCst ) ;
309274
310- let mut task = UIVideoEditorExportQueueItem :: default ( ) ;
311- task. name = format ! ( "Subtitle [{}]" , task_id) . into ( ) ;
312- task. media_type = UIMediaType :: Subtitle ;
313- task. progress = 0.0 ;
314- task. is_cancelled = false ;
275+ let task = UIVideoEditorExportQueueItem {
276+ name : file_name. into ( ) ,
277+ id : format ! ( "Subtitle [{}]" , task_id) . into ( ) ,
278+ media_type : UIMediaType :: Subtitle ,
279+ progress : 0.0 ,
280+ is_cancelled : false ,
281+ } ;
315282
316283 _ = ui_weak. upgrade_in_event_loop ( move |ui| {
317284 store_video_editor_export_queue ! ( ui) . push ( task) ;
318285 } ) ;
319286
320287 let ui_weak_for_progress = ui_weak. clone ( ) ;
321-
322288 let result = tokio:: task:: spawn_blocking ( move || {
323289 let exporter = SubtitleExporter :: new ( manager, export_config) ;
324-
325290 update_export_task_progress ( & ui_weak_for_progress, task_id, 50.0 ) ;
326-
327291 let result = exporter. export_all_tracks ( ) ;
328-
329292 update_export_task_progress ( & ui_weak_for_progress, task_id, 100.0 ) ;
330-
331293 result
332294 } )
333295 . await ;
334296
335297 match result {
336298 Ok ( Ok ( _) ) => {
337- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
338- crate :: logic:: toast:: async_toast_success (
339- ui. as_weak ( ) ,
340- "Subtitle export completed" . to_string ( ) ,
341- ) ;
342- } ) ;
299+ toast:: async_toast_success ( ui_weak, "Subtitle export completed" . to_string ( ) )
343300 }
344301 Ok ( Err ( e) ) => {
345- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
346- crate :: logic:: toast:: async_toast_warn (
347- ui. as_weak ( ) ,
348- format ! ( "Subtitle export failed: {}" , e) ,
349- ) ;
350- } ) ;
351- }
352- Err ( _) => {
353- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
354- crate :: logic:: toast:: async_toast_warn (
355- ui. as_weak ( ) ,
356- "Subtitle export was cancelled" . to_string ( ) ,
357- ) ;
358- } ) ;
302+ toast:: async_toast_warn ( ui_weak, format ! ( "Subtitle export failed: {}" , e) )
359303 }
304+ Err ( _) => toast:: async_toast_warn ( ui_weak, "Subtitle export was cancelled" . to_string ( ) ) ,
360305 }
361306 } ) ;
362307}
363308
364309fn video_editor_export_queue_cancel ( ui : & AppWindow , index : i32 ) {
365- if index < 0 {
366- crate :: logic:: toast:: async_toast_warn ( ui. as_weak ( ) , "Invalid export index" . to_string ( ) ) ;
367- return ;
310+ if let Some ( mut task) = store_video_editor_export_queue ! ( ui) . row_data ( index as usize ) {
311+ task. is_cancelled = true ;
312+ store_video_editor_export_queue ! ( ui) . set_row_data ( index as usize , task) ;
313+ crate :: toast_info!( ui, "Export marked for cancellation" . to_string( ) ) ;
368314 }
369-
370- let ui_weak = ui. as_weak ( ) ;
371- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
372- let queue = global_store ! ( ui) . get_video_editor_export_queue ( ) ;
373- let model = queue
374- . as_any ( )
375- . downcast_ref :: < VecModel < UIVideoEditorExportQueueItem > > ( )
376- . expect ( "We know we set a VecModel<UIVideoEditorExportQueueItem> earlier" ) ;
377-
378- let index = index as usize ;
379- if index < model. row_count ( ) {
380- if let Some ( task) = model. row_data ( index) {
381- let mut updated = task. clone ( ) ;
382- updated. is_cancelled = true ;
383- model. set_row_data ( index, updated) ;
384- }
385- }
386- } ) ;
387-
388- crate :: logic:: toast:: async_toast_info (
389- ui. as_weak ( ) ,
390- "Export marked for cancellation" . to_string ( ) ,
391- ) ;
392315}
393316
394317fn video_editor_export_queue_remove ( ui : & AppWindow , index : i32 ) {
395- if index < 0 {
396- crate :: logic :: toast :: async_toast_warn ( ui. as_weak ( ) , "Invalid export index" . to_string ( ) ) ;
397- return ;
318+ if index > 0 && ( index as usize ) < store_video_editor_export_queue ! ( ui ) . row_count ( ) {
319+ store_video_editor_export_queue ! ( ui) . remove ( index as usize ) ;
320+ crate :: toast_success! ( ui , "Export removed from queue" ) ;
398321 }
399-
400- let ui_weak = ui. as_weak ( ) ;
401- _ = ui_weak. upgrade_in_event_loop ( move |ui| {
402- let queue = global_store ! ( ui) . get_video_editor_export_queue ( ) ;
403- let model = queue
404- . as_any ( )
405- . downcast_ref :: < VecModel < UIVideoEditorExportQueueItem > > ( )
406- . expect ( "We know we set a VecModel<UIVideoEditorExportQueueItem> earlier" ) ;
407-
408- let index = index as usize ;
409- if index < model. row_count ( ) {
410- model. remove ( index) ;
411- }
412- } ) ;
413-
414- crate :: logic:: toast:: async_toast_success ( ui. as_weak ( ) , "Export removed from queue" . to_string ( ) ) ;
415322}
416323
417324pub fn picker_save_file (
0 commit comments