use adw::prelude::*; use gtk::gio; use relm4::prelude::*; use crate::track_selector::{ TrackInfo, TrackSelector, TrackSelectorInit, TrackSelectorMsg, TrackSelectorOutput, }; use crate::tracks::{SUBTITLE_TRACKS, StreamIndex}; pub struct SubtitleSelectionDialog { parent_window: adw::ApplicationWindow, dialog: adw::PreferencesDialog, track_list_model: gio::ListStore, primary_selector: Controller, secondary_selector: Controller, primary_track_ix: Option, secondary_track_ix: Option, } #[derive(Debug)] pub enum SubtitleSelectionDialogMsg { Show, PrimaryTrackChanged(Option), SecondaryTrackChanged(Option), } #[derive(Debug)] pub enum SubtitleSelectionDialogOutput { PrimaryTrackSelected(Option), SecondaryTrackSelected(Option), } #[relm4::component(pub)] impl SimpleComponent for SubtitleSelectionDialog { type Init = adw::ApplicationWindow; type Input = SubtitleSelectionDialogMsg; type Output = SubtitleSelectionDialogOutput; view! { #[root] adw::PreferencesDialog { set_title: "Subtitle Settings", add: &page, }, #[name(page)] adw::PreferencesPage { adw::PreferencesGroup { model.primary_selector.widget(), model.secondary_selector.widget(), } }, } fn init( parent_window: Self::Init, root: Self::Root, sender: ComponentSender, ) -> ComponentParts { let primary_selector = TrackSelector::builder() .launch(TrackSelectorInit { title: "Primary subtitle track", subtitle: Some("Select your target language here"), }) .forward(sender.input_sender(), |output| match output { TrackSelectorOutput::Changed(ix) => { SubtitleSelectionDialogMsg::PrimaryTrackChanged(ix) } }); let secondary_selector = TrackSelector::builder() .launch(TrackSelectorInit { title: "Secondary subtitle track", subtitle: Some("Pick a language you already know"), }) .forward(sender.input_sender(), |output| match output { TrackSelectorOutput::Changed(ix) => { SubtitleSelectionDialogMsg::SecondaryTrackChanged(ix) } }); let model = Self { parent_window, dialog: root.clone(), track_list_model: gio::ListStore::new::(), primary_selector, secondary_selector, primary_track_ix: None, secondary_track_ix: None, }; let widgets = view_output!(); ComponentParts { model, widgets } } fn update(&mut self, msg: Self::Input, sender: ComponentSender) { match msg { SubtitleSelectionDialogMsg::Show => { self.update_track_list_model(); self.primary_selector .sender() .send(TrackSelectorMsg::SetListModel( self.track_list_model.clone(), )) .unwrap(); self.secondary_selector .sender() .send(TrackSelectorMsg::SetListModel( self.track_list_model.clone(), )) .unwrap(); self.dialog.present(Some(&self.parent_window)); } SubtitleSelectionDialogMsg::PrimaryTrackChanged(stream_index) => { self.primary_track_ix = stream_index; sender .output(SubtitleSelectionDialogOutput::PrimaryTrackSelected( stream_index, )) .unwrap(); } SubtitleSelectionDialogMsg::SecondaryTrackChanged(stream_index) => { self.secondary_track_ix = stream_index; sender .output(SubtitleSelectionDialogOutput::SecondaryTrackSelected( stream_index, )) .unwrap(); } } } } impl SubtitleSelectionDialog { fn update_track_list_model(&mut self) { let tracks = SUBTITLE_TRACKS.read(); // Clear previous entries self.track_list_model.remove_all(); // Add all available tracks for (&stream_index, track) in tracks.iter() { let track_info = TrackInfo::new( stream_index, track.metadata.language.map(|lang| lang.to_name()), track.metadata.title.clone(), ); self.track_list_model.append(&track_info); } } }