aboutsummaryrefslogtreecommitdiff
path: root/src/track_selector.rs
diff options
context:
space:
mode:
authorMalte Voos <git@mal.tc>2025-11-14 15:30:49 +0100
committerMalte Voos <git@mal.tc>2025-11-14 15:30:49 +0100
commita8457a25ccb9b1ef47f5ce9d7ac1a84c47600c9e (patch)
tree542b42d3316138043272faba42e0d1005f8403b6 /src/track_selector.rs
parenta42a73378b7c527a5e4600544b2d7a86d68c5aac (diff)
downloadlleap-a8457a25ccb9b1ef47f5ce9d7ac1a84c47600c9e.tar.gz
lleap-a8457a25ccb9b1ef47f5ce9d7ac1a84c47600c9e.zip
implement file/url open dialog
Diffstat (limited to 'src/track_selector.rs')
-rw-r--r--src/track_selector.rs188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/track_selector.rs b/src/track_selector.rs
new file mode 100644
index 0000000..5c56e4d
--- /dev/null
+++ b/src/track_selector.rs
@@ -0,0 +1,188 @@
+use adw::prelude::*;
+use gtk::{gio, glib};
+use relm4::prelude::*;
+
+use crate::tracks::StreamIndex;
+
+glib::wrapper! {
+ pub struct TrackInfo(ObjectSubclass<imp::TrackInfo>);
+}
+
+impl TrackInfo {
+ 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::TrackInfo)]
+ pub struct TrackInfo {
+ #[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 TrackInfo {
+ const NAME: &'static str = "TrackInfo";
+ type Type = super::TrackInfo;
+ }
+
+ #[glib::derived_properties]
+ impl ObjectImpl for TrackInfo {}
+}
+
+pub struct TrackSelector {
+ track_list_model: gio::ListStore,
+ track_ix: Option<StreamIndex>,
+}
+
+pub struct TrackSelectorInit {
+ pub title: &'static str,
+ pub subtitle: Option<&'static str>,
+}
+
+#[derive(Debug)]
+pub enum TrackSelectorMsg {
+ SetListModel(gio::ListStore),
+}
+
+#[derive(Debug)]
+pub enum TrackSelectorOutput {
+ Changed(Option<StreamIndex>),
+}
+
+#[relm4::component(pub)]
+impl SimpleComponent for TrackSelector {
+ type Init = TrackSelectorInit;
+ type Input = TrackSelectorMsg;
+ type Output = TrackSelectorOutput;
+
+ view! {
+ #[root]
+ #[name(primary_combo)]
+ adw::ComboRow {
+ set_title: init.title,
+ set_subtitle?: init.subtitle,
+ set_factory: Some(&track_factory),
+ #[watch]
+ set_model: Some(&model.track_list_model),
+ #[watch]
+ set_selected: model.track_ix.map_or(gtk::INVALID_LIST_POSITION, |ix| get_list_ix_from_stream_ix(&model.track_list_model, ix)),
+ connect_selected_notify[sender] => move |combo| {
+ let stream_index = get_stream_ix_from_combo(combo);
+ sender.output(TrackSelectorOutput::Changed(stream_index)).unwrap();
+ },
+ },
+
+ #[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::<TrackInfo>().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(
+ init: Self::Init,
+ root: Self::Root,
+ sender: ComponentSender<Self>,
+ ) -> ComponentParts<Self> {
+ let track_list_model = gio::ListStore::new::<TrackInfo>();
+
+ let model = Self {
+ track_list_model: track_list_model,
+ track_ix: None,
+ };
+
+ let widgets = view_output!();
+
+ ComponentParts { model, widgets }
+ }
+
+ fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
+ match msg {
+ TrackSelectorMsg::SetListModel(list_model) => {
+ self.track_list_model = list_model;
+ }
+ }
+ }
+}
+
+fn get_stream_ix_from_combo(combo: &adw::ComboRow) -> Option<StreamIndex> {
+ let ix = combo
+ .selected_item()?
+ .downcast_ref::<TrackInfo>()
+ .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::<TrackInfo>() {
+ if track_info.get_stream_index() == stream_ix {
+ return i;
+ }
+ }
+ }
+ }
+ panic!("Stream index {} not found in list model", stream_ix);
+}