summary refs log tree commit diff
path: root/src/app.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app.rs')
-rw-r--r--src/app.rs146
1 files changed, 49 insertions, 97 deletions
diff --git a/src/app.rs b/src/app.rs
index 10c20e6..18f03e8 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,6 +1,4 @@
 use adw::prelude::*;
-use gst::glib::clone;
-use gtk::gio::{Menu, MenuItem, SimpleAction, SimpleActionGroup};
 use relm4::{WorkerController, prelude::*};
 
 use crate::{
@@ -9,13 +7,14 @@ use crate::{
     subtitle_extractor::{
         StreamIndex, SubtitleExtractor, SubtitleExtractorMsg, SubtitleExtractorOutput, TRACKS,
     },
+    subtitle_selection_dialog::{
+        SubtitleSelectionDialog, SubtitleSelectionDialogMsg, SubtitleSelectionDialogOutput,
+    },
     subtitle_view::{SubtitleView, SubtitleViewMsg, SubtitleViewOutput},
     transcript::{Transcript, TranscriptMsg, TranscriptOutput},
     util::OptionTracker,
 };
 
-const TRACK_SELECTION_ACTION_GROUP_NAME: &str = "subtitle_track_selection";
-
 pub struct App {
     url: String,
     transcript: Controller<Transcript>,
@@ -23,9 +22,7 @@ pub struct App {
     subtitle_view: Controller<SubtitleView>,
     extractor: WorkerController<SubtitleExtractor>,
     preferences: Controller<Preferences>,
-
-    subtitle_selection_menu: Menu,
-    subtitle_selection_action_group: SimpleActionGroup,
+    subtitle_selection_dialog: Controller<SubtitleSelectionDialog>,
 
     primary_stream_ix: Option<StreamIndex>,
     primary_last_cue_ix: OptionTracker<usize>,
@@ -42,11 +39,13 @@ pub struct App {
 pub enum AppMsg {
     NewOrUpdatedTrackMetadata(StreamIndex),
     NewCue(StreamIndex, crate::subtitle_extractor::SubtitleCue),
-    ExtractionComplete,
-    TrackSelected(StreamIndex),
+    SubtitleExtractionComplete,
+    PrimarySubtitleTrackSelected(Option<StreamIndex>),
+    SecondarySubtitleTrackSelected(Option<StreamIndex>),
     PositionUpdate(gst::ClockTime),
     SetHoveringSubtitleCue(bool),
     ShowPreferences,
+    ShowSubtitleSelectionDialog,
 }
 
 #[relm4::component(pub)]
@@ -65,14 +64,9 @@ impl SimpleComponent for App {
             #[name(toolbar_view)]
             adw::ToolbarView {
                 add_top_bar = &adw::HeaderBar {
-                    pack_start = &gtk::MenuButton {
-                        set_label: "Select Subtitle Track",
-                        set_popover: Some(&gtk::PopoverMenu::from_model(Some(&model.subtitle_selection_menu))),
-                    },
                     pack_start = &gtk::Button {
-                        set_label: "Preferences",
+                        set_icon_name: "settings-symbolic",
                         connect_clicked => AppMsg::ShowPreferences,
-                        add_css_class: "flat",
                     }
                 },
 
@@ -96,14 +90,6 @@ impl SimpleComponent for App {
         root: Self::Root,
         sender: ComponentSender<Self>,
     ) -> ComponentParts<Self> {
-        let subtitle_selection_menu = Menu::new();
-        let subtitle_selection_action_group = SimpleActionGroup::new();
-        root.insert_action_group(
-            TRACK_SELECTION_ACTION_GROUP_NAME,
-            Some(&subtitle_selection_action_group),
-        );
-        Self::add_dummy_menu_item(&subtitle_selection_action_group, &subtitle_selection_menu);
-
         let subtitle_view = SubtitleView::builder().launch(()).forward(
             sender.input_sender(),
             |output| match output {
@@ -114,6 +100,7 @@ impl SimpleComponent for App {
             .launch(())
             .forward(sender.input_sender(), |output| match output {
                 PlayerOutput::PositionUpdate(pos) => AppMsg::PositionUpdate(pos),
+                PlayerOutput::SubtitleSelectionButtonPressed => AppMsg::ShowSubtitleSelectionDialog,
             });
         let transcript =
             Transcript::builder()
@@ -131,11 +118,21 @@ impl SimpleComponent for App {
                 SubtitleExtractorOutput::NewCue(stream_index, cue) => {
                     AppMsg::NewCue(stream_index, cue)
                 }
-                SubtitleExtractorOutput::ExtractionComplete => AppMsg::ExtractionComplete,
+                SubtitleExtractorOutput::ExtractionComplete => AppMsg::SubtitleExtractionComplete,
             },
         );
 
         let preferences = Preferences::builder().launch(root.clone().into()).detach();
+        let subtitle_selection_dialog = SubtitleSelectionDialog::builder()
+            .launch(root.clone().into())
+            .forward(sender.input_sender(), |output| match output {
+                SubtitleSelectionDialogOutput::PrimaryTrackSelected(ix) => {
+                    AppMsg::PrimarySubtitleTrackSelected(ix)
+                }
+                SubtitleSelectionDialogOutput::SecondaryTrackSelected(ix) => {
+                    AppMsg::SecondarySubtitleTrackSelected(ix)
+                }
+            });
 
         let model = Self {
             url: url.clone(), // TODO remove clone
@@ -144,8 +141,7 @@ impl SimpleComponent for App {
             subtitle_view,
             extractor,
             preferences,
-            subtitle_selection_menu,
-            subtitle_selection_action_group,
+            subtitle_selection_dialog,
 
             primary_stream_ix: None,
             primary_last_cue_ix: OptionTracker::new(None),
@@ -173,31 +169,32 @@ impl SimpleComponent for App {
         ComponentParts { model, widgets }
     }
 
-    fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
+    fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
         self.primary_last_cue_ix.reset();
         self.secondary_last_cue_ix.reset();
 
         match msg {
-            AppMsg::NewOrUpdatedTrackMetadata(_stream_index) => {
-                self.update_subtitle_selection_menu(&sender);
-            }
+            AppMsg::NewOrUpdatedTrackMetadata(_stream_index) => {}
             AppMsg::NewCue(stream_index, cue) => {
                 self.transcript
                     .sender()
                     .send(TranscriptMsg::NewCue(stream_index, cue))
                     .unwrap();
             }
-            AppMsg::ExtractionComplete => {
-                println!("Subtitle extraction complete");
+            AppMsg::SubtitleExtractionComplete => {
+                log::info!("Subtitle extraction complete");
             }
-            AppMsg::TrackSelected(stream_index) => {
-                self.primary_stream_ix = Some(stream_index);
+            AppMsg::PrimarySubtitleTrackSelected(stream_index) => {
+                self.primary_stream_ix = stream_index;
 
                 self.transcript
                     .sender()
                     .send(TranscriptMsg::SelectTrack(stream_index))
                     .unwrap();
             }
+            AppMsg::SecondarySubtitleTrackSelected(stream_index) => {
+                self.secondary_stream_ix = stream_index;
+            }
             AppMsg::PositionUpdate(pos) => {
                 if let Some(stream_ix) = self.primary_stream_ix {
                     let cue =
@@ -239,14 +236,18 @@ impl SimpleComponent for App {
                     }
                 }
                 if let Some(stream_ix) = self.secondary_stream_ix {
-                    self.subtitle_view
-                        .sender()
-                        .send(SubtitleViewMsg::SetPrimaryCue(Self::get_cue_and_update_ix(
-                            stream_ix,
-                            pos,
-                            &mut self.primary_last_cue_ix,
-                        )))
-                        .unwrap();
+                    if !self.autopaused {
+                        self.subtitle_view
+                            .sender()
+                            .send(SubtitleViewMsg::SetSecondaryCue(
+                                Self::get_cue_and_update_ix(
+                                    stream_ix,
+                                    pos,
+                                    &mut self.secondary_last_cue_ix,
+                                ),
+                            ))
+                            .unwrap();
+                    }
                 }
             }
             AppMsg::SetHoveringSubtitleCue(hovering) => {
@@ -262,66 +263,17 @@ impl SimpleComponent for App {
                     .send(PreferencesMsg::Show)
                     .unwrap();
             }
+            AppMsg::ShowSubtitleSelectionDialog => {
+                self.subtitle_selection_dialog
+                    .sender()
+                    .send(SubtitleSelectionDialogMsg::Show)
+                    .unwrap();
+            }
         }
     }
 }
 
 impl App {
-    fn update_subtitle_selection_menu(&mut self, sender: &ComponentSender<Self>) {
-        self.subtitle_selection_menu.remove_all();
-
-        for action_name in self.subtitle_selection_action_group.list_actions() {
-            self.subtitle_selection_action_group
-                .remove_action(&action_name);
-        }
-
-        let tracks = TRACKS.read();
-        if tracks.is_empty() {
-            Self::add_dummy_menu_item(
-                &self.subtitle_selection_action_group,
-                &self.subtitle_selection_menu,
-            );
-        } else {
-            for (stream_index, track) in tracks.iter() {
-                let unknown_string = "<unknown>".to_string();
-                let language = track.language_code.as_ref().unwrap_or(&unknown_string);
-                let label = format!("{} (Stream {})", language, stream_index);
-
-                let action_name = format!("select_{}", stream_index);
-                let action = SimpleAction::new(&action_name, None);
-
-                action.connect_activate(clone!(
-                    #[strong]
-                    sender,
-                    #[strong]
-                    stream_index,
-                    move |_, _| {
-                        let _ = sender.input(AppMsg::TrackSelected(stream_index));
-                    }
-                ));
-
-                self.subtitle_selection_action_group.add_action(&action);
-
-                // Create menu item
-                let action_target =
-                    format!("{}.{}", TRACK_SELECTION_ACTION_GROUP_NAME, action_name);
-                let item = MenuItem::new(Some(&label), Some(&action_target));
-                self.subtitle_selection_menu.append_item(&item);
-            }
-        }
-    }
-
-    // Add disabled "No tracks available" item
-    fn add_dummy_menu_item(action_group: &SimpleActionGroup, menu: &Menu) {
-        let disabled_action = SimpleAction::new("no_tracks", None);
-        disabled_action.set_enabled(false);
-        action_group.add_action(&disabled_action);
-
-        let action_target = format!("{}.no_tracks", TRACK_SELECTION_ACTION_GROUP_NAME);
-        let item = MenuItem::new(Some("No tracks available"), Some(&action_target));
-        menu.append_item(&item);
-    }
-
     fn get_cue_and_update_ix(
         stream_ix: StreamIndex,
         position: gst::ClockTime,