diff options
Diffstat (limited to 'src/subtitle_selection_dialog.rs')
| -rw-r--r-- | src/subtitle_selection_dialog.rs | 214 |
1 files changed, 55 insertions, 159 deletions
diff --git a/src/subtitle_selection_dialog.rs b/src/subtitle_selection_dialog.rs index 0c7f1cd..6136d56 100644 --- a/src/subtitle_selection_dialog.rs +++ b/src/subtitle_selection_dialog.rs @@ -1,63 +1,18 @@ use adw::prelude::*; -use gtk::{gio, glib}; +use gtk::gio; use relm4::prelude::*; -use crate::subtitle_extractor::{StreamIndex, TRACKS}; -use crate::util::Tracker; - -// Custom GObject wrapper for subtitle track information -glib::wrapper! { - pub struct SubtitleTrackInfo(ObjectSubclass<imp::SubtitleTrackInfo>); -} - -impl SubtitleTrackInfo { - pub fn new( - stream_index: StreamIndex, - language: Option<&'static str>, - title: Option<String>, - ) -> Self { - glib::Object::builder() - .property("stream-index", stream_index as i64) - .property("language", language.unwrap_or_default()) - .property("title", title.unwrap_or_default()) - .build() - } - - pub fn get_stream_index(&self) -> StreamIndex { - let index: i64 = self.property("stream-index"); - index as usize - } -} - -mod imp { - use gtk::{glib, prelude::*, subclass::prelude::*}; - use std::cell::RefCell; - - #[derive(Default, glib::Properties)] - #[properties(wrapper_type = super::SubtitleTrackInfo)] - pub struct SubtitleTrackInfo { - #[property(get, set)] - stream_index: RefCell<i64>, - #[property(get, set)] - language: RefCell<String>, - #[property(get, set)] - title: RefCell<String>, - } - - #[glib::object_subclass] - impl ObjectSubclass for SubtitleTrackInfo { - const NAME: &'static str = "SubtitleTrackInfo"; - type Type = super::SubtitleTrackInfo; - } - - #[glib::derived_properties] - impl ObjectImpl for SubtitleTrackInfo {} -} +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: Tracker<gio::ListStore>, + track_list_model: gio::ListStore, + primary_selector: Controller<TrackSelector>, + secondary_selector: Controller<TrackSelector>, primary_track_ix: Option<StreamIndex>, secondary_track_ix: Option<StreamIndex>, } @@ -91,79 +46,10 @@ impl SimpleComponent for SubtitleSelectionDialog { #[name(page)] adw::PreferencesPage { adw::PreferencesGroup { - #[name(primary_combo)] - adw::ComboRow { - set_title: "Primary Subtitle Track", - set_subtitle: "Main subtitle track for learning", - set_factory: Some(&track_factory), - #[track(model.track_list_model.is_dirty())] - set_model: Some(model.track_list_model.get()), - #[track(model.track_list_model.is_dirty())] - set_selected: model.primary_track_ix.map_or(gtk::INVALID_LIST_POSITION, |ix| get_list_ix_from_stream_ix(model.track_list_model.get(), ix)), - connect_selected_notify[sender] => move |combo| { - let stream_index = get_stream_ix_from_combo(combo); - sender.input(SubtitleSelectionDialogMsg::PrimaryTrackChanged(stream_index)); - }, - }, - - #[name(secondary_combo)] - adw::ComboRow { - set_title: "Secondary Subtitle Track", - set_subtitle: "Optional second track for comparison", - set_factory: Some(&track_factory), - #[track(model.track_list_model.is_dirty())] - set_model: Some(model.track_list_model.get()), - #[track(model.track_list_model.is_dirty())] - set_selected: model.secondary_track_ix.map_or(gtk::INVALID_LIST_POSITION, |ix| get_list_ix_from_stream_ix(model.track_list_model.get(), ix)), - connect_selected_notify[sender] => move |combo| { - let stream_index = get_stream_ix_from_combo(combo); - sender.input(SubtitleSelectionDialogMsg::SecondaryTrackChanged(stream_index)); - }, - }, + model.primary_selector.widget(), + model.secondary_selector.widget(), } }, - - #[name(track_factory)] - gtk::SignalListItemFactory { - connect_setup => move |_, list_item| { - let list_item = list_item.downcast_ref::<gtk::ListItem>().unwrap(); - let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); - - let language_label = gtk::Label::new(None); - language_label.set_halign(gtk::Align::Start); - language_label.set_ellipsize(gtk::pango::EllipsizeMode::End); - - let title_label = gtk::Label::new(None); - title_label.set_halign(gtk::Align::Start); - title_label.set_ellipsize(gtk::pango::EllipsizeMode::End); - title_label.add_css_class("subtitle"); - - vbox.append(&language_label); - vbox.append(&title_label); - list_item.set_child(Some(&vbox)); - }, - connect_bind => move |_, list_item| { - let list_item = list_item.downcast_ref::<gtk::ListItem>().unwrap(); - let item = list_item.item().unwrap(); - let track_info = item.downcast_ref::<SubtitleTrackInfo>().unwrap(); - let vbox = list_item.child().unwrap().downcast::<gtk::Box>().unwrap(); - let language_label = vbox.first_child().unwrap().downcast::<gtk::Label>().unwrap(); - let title_label = vbox.last_child().unwrap().downcast::<gtk::Label>().unwrap(); - - let language = track_info.language(); - let title = track_info.title(); - - let language_text = if !language.is_empty() { - &language - } else { - "Unknown Language" - }; - - language_label.set_text(&language_text); - title_label.set_text(&title); - title_label.set_visible(!title.is_empty()); - }, - }, } fn init( @@ -171,12 +57,33 @@ impl SimpleComponent for SubtitleSelectionDialog { root: Self::Root, sender: ComponentSender<Self>, ) -> ComponentParts<Self> { - let track_list_model = gio::ListStore::new::<SubtitleTrackInfo>(); + 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: Tracker::new(track_list_model), + track_list_model: gio::ListStore::new::<TrackInfo>(), + primary_selector, + secondary_selector, primary_track_ix: None, secondary_track_ix: None, }; @@ -187,11 +94,23 @@ impl SimpleComponent for SubtitleSelectionDialog { } fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) { - self.track_list_model.reset(); - match msg { SubtitleSelectionDialogMsg::Show => { - self.update_combo_models(); + 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) => { @@ -215,43 +134,20 @@ impl SimpleComponent for SubtitleSelectionDialog { } impl SubtitleSelectionDialog { - fn update_combo_models(&mut self) { - let tracks = TRACKS.read(); + fn update_track_list_model(&mut self) { + let tracks = SUBTITLE_TRACKS.read(); // Clear previous entries - self.track_list_model.get_mut().remove_all(); + self.track_list_model.remove_all(); // Add all available tracks for (&stream_index, track) in tracks.iter() { - let track_info = SubtitleTrackInfo::new( + let track_info = TrackInfo::new( stream_index, - track.language.map(|lang| lang.to_name()), - track.title.clone(), + track.metadata.language.map(|lang| lang.to_name()), + track.metadata.title.clone(), ); - self.track_list_model.get_mut().append(&track_info); - } - } -} - -fn get_stream_ix_from_combo(combo: &adw::ComboRow) -> Option<StreamIndex> { - let ix = combo - .selected_item()? - .downcast_ref::<SubtitleTrackInfo>() - .unwrap() - .get_stream_index(); - - Some(ix) -} - -fn get_list_ix_from_stream_ix(list_model: &gio::ListStore, stream_ix: StreamIndex) -> u32 { - for i in 0..list_model.n_items() { - if let Some(item) = list_model.item(i) { - if let Some(track_info) = item.downcast_ref::<SubtitleTrackInfo>() { - if track_info.get_stream_index() == stream_ix { - return i; - } - } + self.track_list_model.append(&track_info); } } - panic!("Stream index {} not found in list model", stream_ix); } |