1use crate::engine::hardware::HwPreflightResult;
4use crate::stats::StatsState;
5use crate::ui::focus::ConfigFocus;
6use crate::ui::help::HelpModalState;
7use ratatui::{
8 layout::Rect,
9 widgets::{ListState, TableState},
10};
11use std::collections::VecDeque;
12use std::rc::Rc;
13use std::time::Instant;
14use sysinfo::System;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum Screen {
18 Dashboard,
19 Config,
20 Stats,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum RateControlMode {
25 CQ, CQCap, TwoPassVBR, CBR, }
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum InputMode {
33 Normal, Editing, }
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
38pub enum CodecSelection {
39 #[default]
40 Vp9,
41 Av1,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
45pub enum ColorSpacePreset {
46 #[default]
47 Auto, Sdr, Hdr10, }
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
55pub enum AudioPrimaryCodec {
56 #[default]
57 Passthrough, Opus, Aac, Mp3, Vorbis, }
63
64impl AudioPrimaryCodec {
65 pub fn is_passthrough(&self) -> bool {
66 matches!(self, Self::Passthrough)
67 }
68
69 pub fn ffmpeg_codec(&self) -> Option<&'static str> {
70 match self {
71 Self::Passthrough => None,
72 Self::Opus => Some("libopus"),
73 Self::Aac => Some("aac"),
74 Self::Mp3 => Some("mp3"),
75 Self::Vorbis => Some("vorbis"),
76 }
77 }
78
79 pub fn from_index(idx: usize) -> Self {
80 match idx {
81 0 => Self::Passthrough,
82 1 => Self::Opus,
83 2 => Self::Aac,
84 3 => Self::Mp3,
85 4 => Self::Vorbis,
86 _ => Self::Opus,
87 }
88 }
89
90 pub fn to_index(self) -> usize {
91 match self {
92 Self::Passthrough => 0,
93 Self::Opus => 1,
94 Self::Aac => 2,
95 Self::Mp3 => 3,
96 Self::Vorbis => 4,
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
103pub enum AudioStereoCodec {
104 #[default]
105 Aac, Opus, }
108
109impl AudioStereoCodec {
110 pub fn ffmpeg_codec(&self) -> &'static str {
111 match self {
112 Self::Aac => "aac",
113 Self::Opus => "libopus",
114 }
115 }
116
117 pub fn from_index(idx: usize) -> Self {
118 match idx {
119 0 => Self::Aac,
120 1 => Self::Opus,
121 _ => Self::Aac,
122 }
123 }
124
125 pub fn to_index(self) -> usize {
126 match self {
127 Self::Aac => 0,
128 Self::Opus => 1,
129 }
130 }
131}
132
133#[derive(Debug, Clone)]
135pub struct QuitConfirmationState {
136 pub running_count: usize,
138}
139
140pub struct AppState {
141 pub current_screen: Screen,
142 pub dashboard: DashboardState,
143 pub config: ConfigState,
144 pub stats: StatsState,
145 pub last_metrics_update: Instant,
146 pub viewport: Rect,
147 pub worker_pool: Option<Rc<crate::engine::worker::WorkerPool>>,
148 pub enc_state: Option<crate::engine::EncState>,
149 pub root_path: Option<std::path::PathBuf>,
150 pub help_modal: Option<HelpModalState>,
151 pub quit_confirmation: Option<QuitConfirmationState>, pub app_version: String,
153 pub ffmpeg_version: Option<String>,
154 pub ffprobe_version: Option<String>,
155 pub hw_preflight_result: Option<HwPreflightResult>,
156 pub huc_available: Option<bool>, pub scan_in_progress: bool, pub pending_autostart: bool, }
160
161impl Default for AppState {
162 fn default() -> Self {
163 Self {
164 current_screen: Screen::Dashboard,
165 dashboard: DashboardState::default(),
166 config: ConfigState::default(),
167 stats: StatsState::default(),
168 last_metrics_update: Instant::now(),
169 viewport: Rect::default(),
170 worker_pool: None, enc_state: None, root_path: None, help_modal: None, quit_confirmation: None, app_version: env!("CARGO_PKG_VERSION").to_string(),
176 ffmpeg_version: None, ffprobe_version: None, hw_preflight_result: None, huc_available: None, scan_in_progress: false,
181 pending_autostart: false,
182 }
183 }
184}
185
186pub struct DashboardState {
187 pub cpu_data: VecDeque<u64>,
188 pub mem_data: VecDeque<u64>,
189 pub table_state: TableState,
190 pub foreground_job_index: usize,
191 pub system: System,
192
193 pub table_area: Option<Rect>,
195 pub table_inner_area: Option<Rect>,
196 pub hovered_row: Option<usize>,
197
198 pub jobs: Vec<crate::engine::VideoJob>,
200
201 pub gpu_data: VecDeque<u64>, pub gpu_mem_data: VecDeque<u64>, pub gpu_available: bool, pub gpu_model: Option<String>, pub gpu_vendor: crate::engine::hardware::GpuVendor, pub start_time: Instant,
210}
211
212impl Default for DashboardState {
213 fn default() -> Self {
214 let mut table_state = TableState::default();
215 table_state.select(Some(0));
216
217 Self {
218 cpu_data: VecDeque::with_capacity(240),
219 mem_data: VecDeque::with_capacity(240),
220 table_state,
221 foreground_job_index: 0,
222 system: System::new_all(),
223 table_area: None,
224 table_inner_area: None,
225 hovered_row: None,
226 jobs: Vec::new(),
227
228 gpu_data: VecDeque::with_capacity(240),
230 gpu_mem_data: VecDeque::with_capacity(240),
231 gpu_available: false,
232 gpu_model: None,
233 gpu_vendor: crate::engine::hardware::GpuVendor::Unknown,
234
235 start_time: Instant::now(),
236 }
237 }
238}
239
240pub struct ConfigState {
241 pub focus: ConfigFocus,
242 pub profile_list_state: ListState,
243 pub quality_mode_state: ListState,
244 pub profile_dropdown_state: ListState,
245 pub pix_fmt_state: ListState,
246 pub aq_mode_state: ListState,
247 pub tune_content_state: ListState,
248 pub colorspace_preset_state: ListState,
249 pub arnr_type_state: ListState,
250 pub fps_dropdown_state: ListState,
251 pub resolution_dropdown_state: ListState,
252
253 pub video_codec_state: ListState,
255 pub codec_selection: CodecSelection,
256
257 pub av1_preset: u32, pub av1_tune_state: ListState, pub av1_film_grain: u32, pub av1_film_grain_denoise: bool, pub av1_enable_overlays: bool,
263 pub av1_scd: bool, pub av1_scm_state: ListState, pub av1_enable_tf: bool, pub av1_hw_preset: u32, pub av1_hw_cq: u32, pub av1_svt_crf: u32, pub av1_qsv_cq: u32, pub av1_nvenc_cq: u32, pub av1_vaapi_cq: u32, pub av1_hw_lookahead: u32, pub av1_hw_tile_cols: u32, pub av1_hw_tile_rows: u32, pub current_profile_name: Option<String>, pub is_modified: bool, pub available_profiles: Vec<String>, pub output_dir: String,
288 pub overwrite: bool,
289 pub max_workers: u32, pub filename_pattern: String,
294 pub container_dropdown_state: ListState, pub additional_args: String,
298
299 pub fps: u32, pub scale_width: i32, pub scale_height: i32, pub rate_control_mode: RateControlMode,
306 pub crf: u32,
307 pub video_target_bitrate: u32,
308 pub video_min_bitrate: u32,
309 pub video_max_bitrate: u32,
310 pub video_bufsize: u32,
311 pub undershoot_pct: i32, pub overshoot_pct: i32, pub cpu_used: u32,
316 pub cpu_used_pass1: u32, pub cpu_used_pass2: u32, pub two_pass: bool,
319
320 pub row_mt: bool,
322 pub tile_columns: i32,
323 pub tile_rows: i32,
324 pub threads: u32,
325 pub frame_parallel: bool,
326
327 pub gop_length: String,
329 pub keyint_min: String, pub fixed_gop: bool,
331 pub lag_in_frames: u32,
332 pub auto_alt_ref: u32,
333
334 pub arnr_max_frames: u32,
339 pub arnr_strength: u32,
340 pub arnr_type: i32, pub enable_tpl: bool,
344 pub sharpness: i32,
345 pub noise_sensitivity: u32,
346 pub static_thresh: String, pub max_intra_rate: String, pub colorspace: i32, pub color_primaries: i32, pub color_trc: i32, pub color_range: i32, pub colorspace_preset: ColorSpacePreset, pub audio_primary_codec: AudioPrimaryCodec,
359 pub audio_primary_codec_state: ListState, pub audio_primary_bitrate: u32, pub audio_primary_downmix: bool, pub audio_add_ac3: bool,
365 pub audio_ac3_bitrate: u32, pub audio_add_stereo: bool,
369 pub audio_stereo_codec: AudioStereoCodec,
370 pub audio_stereo_codec_state: ListState, pub audio_stereo_bitrate: u32, pub use_hardware_encoding: bool,
375 pub hw_encoding_available: Option<bool>, pub hw_availability_message: Option<String>,
377 pub gpu_vendor: crate::engine::hardware::GpuVendor, pub vaapi_rc_mode: String, pub qsv_global_quality: u32, pub vaapi_compression_level: String, pub vaapi_b_frames: String, pub vaapi_loop_filter_level: String, pub vaapi_loop_filter_sharpness: String, pub hw_denoise: String, pub hw_detail: String, pub vp9_qsv_preset: u32, pub vp9_qsv_lookahead: bool,
392 pub vp9_qsv_lookahead_depth: u32,
393
394 pub auto_vmaf_enabled: bool,
396 pub auto_vmaf_target: String, pub auto_vmaf_step: String, pub auto_vmaf_max_attempts: String, pub active_dropdown: Option<ConfigFocus>,
402
403 pub name_input_dialog: Option<String>,
405
406 pub input_mode: InputMode,
408
409 pub cursor_pos: usize,
411
412 pub overwrite_checkbox_area: Option<Rect>,
414 pub two_pass_checkbox_area: Option<Rect>,
415 pub row_mt_checkbox_area: Option<Rect>,
416 pub frame_parallel_checkbox_area: Option<Rect>,
417 pub fixed_gop_checkbox_area: Option<Rect>,
418 pub auto_alt_ref_checkbox_area: Option<Rect>,
419 pub enable_tpl_checkbox_area: Option<Rect>,
420 pub save_button_area: Option<Rect>,
421 pub delete_button_area: Option<Rect>,
422 pub output_dir_area: Option<Rect>,
423 pub filename_pattern_area: Option<Rect>,
424 pub container_dropdown_area: Option<Rect>,
425 pub fps_area: Option<Rect>,
426 pub scale_width_area: Option<Rect>,
427 pub scale_height_area: Option<Rect>,
428 pub profile_list_area: Option<Rect>,
429 pub quality_mode_area: Option<Rect>,
430 pub vp9_profile_list_area: Option<Rect>,
431 pub pix_fmt_area: Option<Rect>,
432 pub aq_mode_area: Option<Rect>,
433 pub tune_content_area: Option<Rect>,
434 pub rate_control_mode_area: Option<Rect>,
435 pub crf_slider_area: Option<Rect>,
436 pub cpu_used_slider_area: Option<Rect>,
437 pub cpu_used_pass1_slider_area: Option<Rect>,
438 pub cpu_used_pass2_slider_area: Option<Rect>,
439 pub tile_columns_slider_area: Option<Rect>,
440 pub tile_rows_slider_area: Option<Rect>,
441 pub threads_area: Option<Rect>,
442 pub max_workers_area: Option<Rect>,
443 pub gop_length_area: Option<Rect>,
444 pub keyint_min_area: Option<Rect>,
445 pub lag_in_frames_slider_area: Option<Rect>,
446 pub arnr_max_frames_slider_area: Option<Rect>,
447 pub arnr_strength_slider_area: Option<Rect>,
448 pub sharpness_slider_area: Option<Rect>,
449 pub noise_sensitivity_slider_area: Option<Rect>,
450 pub video_target_bitrate_area: Option<Rect>,
451 pub video_min_bitrate_area: Option<Rect>,
452 pub video_max_bitrate_area: Option<Rect>,
453 pub video_bufsize_area: Option<Rect>,
454 pub audio_primary_codec_area: Option<Rect>,
456 pub audio_primary_bitrate_area: Option<Rect>,
457 pub audio_primary_downmix_area: Option<Rect>,
458 pub audio_ac3_checkbox_area: Option<Rect>,
459 pub audio_ac3_bitrate_area: Option<Rect>,
460 pub audio_stereo_checkbox_area: Option<Rect>,
461 pub audio_stereo_codec_area: Option<Rect>,
462 pub audio_stereo_bitrate_area: Option<Rect>,
463 pub colorspace_preset_area: Option<Rect>,
464 pub arnr_type_area: Option<Rect>,
465 pub static_thresh_area: Option<Rect>,
466 pub max_intra_rate_area: Option<Rect>,
467 pub undershoot_pct_area: Option<Rect>,
468 pub overshoot_pct_area: Option<Rect>,
469
470 pub hw_encoding_checkbox_area: Option<Rect>,
472 pub qsv_quality_slider_area: Option<Rect>,
473 pub vaapi_compression_level_slider_area: Option<Rect>,
474 pub vaapi_b_frames_area: Option<Rect>,
475 pub vaapi_loop_filter_level_area: Option<Rect>,
476 pub vaapi_loop_filter_sharpness_area: Option<Rect>,
477 pub hw_denoise_area: Option<Rect>,
478 pub hw_detail_area: Option<Rect>,
479
480 pub video_codec_area: Option<Rect>,
482
483 pub av1_preset_slider_area: Option<Rect>,
485 pub av1_tune_area: Option<Rect>,
486 pub av1_film_grain_slider_area: Option<Rect>,
487 pub av1_film_grain_denoise_checkbox_area: Option<Rect>,
488 pub av1_enable_overlays_checkbox_area: Option<Rect>,
489 pub av1_scd_checkbox_area: Option<Rect>,
490 pub av1_scm_area: Option<Rect>,
491 pub av1_enable_tf_checkbox_area: Option<Rect>,
492
493 pub av1_hw_preset_area: Option<Rect>,
495 pub av1_hw_cq_slider_area: Option<Rect>,
496 pub av1_hw_lookahead_area: Option<Rect>,
497 pub av1_hw_tile_cols_area: Option<Rect>,
498 pub av1_hw_tile_rows_area: Option<Rect>,
499
500 pub vp9_qsv_preset_area: Option<Rect>,
502 pub vp9_qsv_lookahead_checkbox_area: Option<Rect>,
503 pub vp9_qsv_lookahead_depth_area: Option<Rect>,
504
505 pub auto_vmaf_checkbox_area: Option<Rect>,
507 pub auto_vmaf_target_area: Option<Rect>,
508 pub auto_vmaf_step_area: Option<Rect>,
509 pub auto_vmaf_max_attempts_area: Option<Rect>,
510
511 pub additional_args_area: Option<Rect>,
513
514 pub status_message: Option<(String, Instant)>,
516}
517
518impl Default for ConfigState {
519 fn default() -> Self {
520 let mut profile_list_state = ListState::default();
521 profile_list_state.select(Some(0));
522
523 let mut quality_mode_state = ListState::default();
524 quality_mode_state.select(Some(0)); let mut profile_dropdown_state = ListState::default();
527 profile_dropdown_state.select(Some(0)); let mut pix_fmt_state = ListState::default();
530 pix_fmt_state.select(Some(0)); let mut aq_mode_state = ListState::default();
533 aq_mode_state.select(Some(2)); let mut tune_content_state = ListState::default();
536 tune_content_state.select(Some(0)); let mut colorspace_preset_state = ListState::default();
539 colorspace_preset_state.select(Some(0)); let mut arnr_type_state = ListState::default();
542 arnr_type_state.select(Some(0)); let mut fps_dropdown_state = ListState::default();
545 fps_dropdown_state.select(Some(0)); let mut resolution_dropdown_state = ListState::default();
548 resolution_dropdown_state.select(Some(0)); let mut container_dropdown_state = ListState::default();
551 container_dropdown_state.select(Some(0)); let mut video_codec_state = ListState::default();
555 video_codec_state.select(Some(1)); let mut av1_tune_state = ListState::default();
559 av1_tune_state.select(Some(0)); let mut av1_scm_state = ListState::default();
562 av1_scm_state.select(Some(0)); Self {
565 focus: ConfigFocus::default(),
566 profile_list_state,
567 quality_mode_state,
568 profile_dropdown_state,
569 pix_fmt_state,
570 aq_mode_state,
571 tune_content_state,
572 colorspace_preset_state,
573 arnr_type_state,
574 fps_dropdown_state,
575 resolution_dropdown_state,
576 container_dropdown_state,
577
578 video_codec_state,
580 codec_selection: CodecSelection::Av1,
581
582 av1_preset: 8,
584 av1_tune_state,
585 av1_film_grain: 0,
586 av1_film_grain_denoise: false,
587 av1_enable_overlays: false,
588 av1_scd: true,
589 av1_scm_state,
590 av1_enable_tf: true,
591
592 av1_hw_preset: 4, av1_hw_cq: 30, av1_svt_crf: 28, av1_qsv_cq: 65, av1_nvenc_cq: 16, av1_vaapi_cq: 65, av1_hw_lookahead: 0,
603 av1_hw_tile_cols: 0,
604 av1_hw_tile_rows: 0,
605
606 current_profile_name: Some("YouTube 4K".to_string()), is_modified: false,
609 available_profiles: Vec::new(), output_dir: std::env::current_dir()
613 .ok()
614 .and_then(|p| p.to_str().map(|s| s.to_string()))
615 .unwrap_or_else(|| ".".to_string()),
616 overwrite: true,
617 max_workers: 1, filename_pattern: "{basename}".to_string(),
621
622 additional_args: String::new(),
624
625 fps: 0, scale_width: -2, scale_height: -2, rate_control_mode: RateControlMode::CQ,
632 crf: 30,
633 video_target_bitrate: 0,
634 video_min_bitrate: 0,
635 video_max_bitrate: 0,
636 video_bufsize: 0,
637 undershoot_pct: -1, overshoot_pct: -1, cpu_used: 1, cpu_used_pass1: 4, cpu_used_pass2: 1, two_pass: true, row_mt: true,
648 tile_columns: 2, tile_rows: 0,
650 threads: 0, frame_parallel: false,
652
653 gop_length: "240".to_string(),
655 keyint_min: "0".to_string(), fixed_gop: false,
657 lag_in_frames: 25,
658 auto_alt_ref: 1,
659
660 arnr_max_frames: 7,
662 arnr_strength: 3,
663 arnr_type: -1, enable_tpl: true, sharpness: -1, noise_sensitivity: 0,
669 static_thresh: "0".to_string(), max_intra_rate: "0".to_string(), colorspace: -1,
674 color_primaries: -1,
675 color_trc: -1,
676 color_range: -1,
677 colorspace_preset: ColorSpacePreset::Auto,
678
679 audio_primary_codec: AudioPrimaryCodec::Opus,
681 audio_primary_codec_state: {
682 let mut state = ListState::default();
683 state.select(Some(1)); state
685 },
686 audio_primary_bitrate: 128,
687 audio_primary_downmix: false,
688 audio_add_ac3: false,
689 audio_ac3_bitrate: 448,
690 audio_add_stereo: false,
691 audio_stereo_codec: AudioStereoCodec::Aac,
692 audio_stereo_codec_state: {
693 let mut state = ListState::default();
694 state.select(Some(0)); state
696 },
697 audio_stereo_bitrate: 128,
698
699 use_hardware_encoding: false,
701 hw_encoding_available: None,
702 hw_availability_message: None,
703 gpu_vendor: crate::engine::hardware::GpuVendor::Unknown,
704 qsv_global_quality: 70,
705 vaapi_rc_mode: "1".to_string(), vaapi_compression_level: "4".to_string(),
707 vaapi_b_frames: "0".to_string(),
708 vaapi_loop_filter_level: "16".to_string(),
709 vaapi_loop_filter_sharpness: "4".to_string(),
710 hw_denoise: "0".to_string(),
711 hw_detail: "0".to_string(),
712
713 vp9_qsv_preset: 4,
715 vp9_qsv_lookahead: true,
716 vp9_qsv_lookahead_depth: 40,
717
718 auto_vmaf_enabled: false,
720 auto_vmaf_target: "93.0".to_string(),
721 auto_vmaf_step: "2".to_string(),
722 auto_vmaf_max_attempts: "3".to_string(),
723
724 active_dropdown: None,
726
727 name_input_dialog: None,
729
730 input_mode: InputMode::Normal,
732
733 cursor_pos: 0,
735
736 overwrite_checkbox_area: None,
738 two_pass_checkbox_area: None,
739 row_mt_checkbox_area: None,
740 frame_parallel_checkbox_area: None,
741 fixed_gop_checkbox_area: None,
742 auto_alt_ref_checkbox_area: None,
743 enable_tpl_checkbox_area: None,
744 save_button_area: None,
745 delete_button_area: None,
746 output_dir_area: None,
747 filename_pattern_area: None,
748 container_dropdown_area: None,
749 fps_area: None,
750 scale_width_area: None,
751 scale_height_area: None,
752 profile_list_area: None,
753 quality_mode_area: None,
754 vp9_profile_list_area: None,
755 pix_fmt_area: None,
756 aq_mode_area: None,
757 tune_content_area: None,
758 rate_control_mode_area: None,
759 crf_slider_area: None,
760 cpu_used_slider_area: None,
761 cpu_used_pass1_slider_area: None,
762 cpu_used_pass2_slider_area: None,
763 tile_columns_slider_area: None,
764 tile_rows_slider_area: None,
765 threads_area: None,
766 max_workers_area: None,
767 gop_length_area: None,
768 keyint_min_area: None,
769 lag_in_frames_slider_area: None,
770 arnr_max_frames_slider_area: None,
771 arnr_strength_slider_area: None,
772 sharpness_slider_area: None,
773 noise_sensitivity_slider_area: None,
774 video_target_bitrate_area: None,
775 video_min_bitrate_area: None,
776 video_max_bitrate_area: None,
777 video_bufsize_area: None,
778 audio_primary_codec_area: None,
780 audio_primary_bitrate_area: None,
781 audio_primary_downmix_area: None,
782 audio_ac3_checkbox_area: None,
783 audio_ac3_bitrate_area: None,
784 audio_stereo_checkbox_area: None,
785 audio_stereo_codec_area: None,
786 audio_stereo_bitrate_area: None,
787 colorspace_preset_area: None,
788 arnr_type_area: None,
789 static_thresh_area: None,
790 max_intra_rate_area: None,
791 undershoot_pct_area: None,
792 overshoot_pct_area: None,
793
794 hw_encoding_checkbox_area: None,
796 qsv_quality_slider_area: None,
797 vaapi_compression_level_slider_area: None,
798 vaapi_b_frames_area: None,
799 vaapi_loop_filter_level_area: None,
800 vaapi_loop_filter_sharpness_area: None,
801 hw_denoise_area: None,
802 hw_detail_area: None,
803
804 video_codec_area: None,
806
807 av1_preset_slider_area: None,
809 av1_tune_area: None,
810 av1_film_grain_slider_area: None,
811 av1_film_grain_denoise_checkbox_area: None,
812 av1_enable_overlays_checkbox_area: None,
813 av1_scd_checkbox_area: None,
814 av1_scm_area: None,
815 av1_enable_tf_checkbox_area: None,
816
817 av1_hw_preset_area: None,
819 av1_hw_cq_slider_area: None,
820 av1_hw_lookahead_area: None,
821 av1_hw_tile_cols_area: None,
822 av1_hw_tile_rows_area: None,
823
824 vp9_qsv_preset_area: None,
826 vp9_qsv_lookahead_checkbox_area: None,
827 vp9_qsv_lookahead_depth_area: None,
828
829 auto_vmaf_checkbox_area: None,
831 auto_vmaf_target_area: None,
832 auto_vmaf_step_area: None,
833 auto_vmaf_max_attempts_area: None,
834
835 additional_args_area: None,
837
838 status_message: None,
839 }
840 }
841}
842
843impl ConfigState {
844 pub fn refresh_available_profiles(&mut self) {
846 use crate::engine::Profile;
847
848 if let Ok(profiles_dir) = Profile::profiles_dir() {
849 if let Ok(saved_profiles) = Profile::list_saved(&profiles_dir) {
850 self.available_profiles = saved_profiles;
851 }
852 }
853 }
854}
855
856#[cfg(test)]
857mod tests {
858 use super::*;
859
860 #[test]
861 fn test_all_list_states_initialized() {
862 let state = ConfigState::default();
863
864 assert!(state.profile_list_state.selected().is_some());
866 assert!(state.quality_mode_state.selected().is_some());
867 assert!(state.profile_dropdown_state.selected().is_some());
868 assert!(state.audio_primary_codec_state.selected().is_some());
869 assert!(state.audio_stereo_codec_state.selected().is_some());
870 assert!(state.pix_fmt_state.selected().is_some());
871 assert!(state.aq_mode_state.selected().is_some());
872 assert!(state.tune_content_state.selected().is_some());
873 }
874
875 #[test]
876 fn test_dropdown_item_counts() {
877 let profiles = vec!["YouTube 4K", "Archival", "Low Latency", "Create New..."];
879 let quality_modes = vec!["good", "realtime", "best"];
880 let vp9_profiles = vec![
881 "Profile 0 (8-bit)",
882 "Profile 1 (8-bit)",
883 "Profile 2 (10-bit)",
884 "Profile 3 (10-bit)",
885 ];
886 let primary_codecs = vec!["Passthrough", "Opus", "AAC", "MP3", "Vorbis"];
887 let stereo_codecs = vec!["AAC", "Opus"];
888 let pix_fmts = vec!["yuv420p (8-bit)", "yuv420p10le (10-bit)"];
889 let aq_modes = vec![
890 "Auto",
891 "Off",
892 "Variance",
893 "Complexity",
894 "Cyclic",
895 "360 Video",
896 ];
897 let tune_contents = vec!["default", "screen", "film"];
898
899 assert_eq!(profiles.len(), 4);
900 assert_eq!(quality_modes.len(), 3);
901 assert_eq!(vp9_profiles.len(), 4);
902 assert_eq!(primary_codecs.len(), 5);
903 assert_eq!(stereo_codecs.len(), 2);
904 assert_eq!(pix_fmts.len(), 2);
905 assert_eq!(aq_modes.len(), 6);
906 assert_eq!(tune_contents.len(), 3);
907 }
908}