aboutsummaryrefslogtreecommitdiff
path: root/src/subtitle_selection_dialog.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/subtitle_selection_dialog.rs')
-rw-r--r--src/subtitle_selection_dialog.rs214
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);
}