diff --git a/resources/play_queue.blp b/resources/play_queue.blp index 02e103c..5d95042 100644 --- a/resources/play_queue.blp +++ b/resources/play_queue.blp @@ -5,7 +5,7 @@ template $AudreyUiPlayQueue: Adw.Bin { name: "play-queue"; child: Stack { - visible-child-name: bind $visible_child_name (template.playbin as <$AudreyPlaybin>.play-queue-length) as ; + visible-child-name: bind $visible_child_name (template.model as <$GListStore>.n-items) as ; StackPage { name: "empty"; @@ -31,7 +31,7 @@ template $AudreyUiPlayQueue: Adw.Bin { activate => $on_row_activated () swapped; model: NoSelection { - model: bind template.playbin as <$AudreyPlaybin>.play_queue; + model: bind template.model; }; factory: SignalListItemFactory { diff --git a/resources/play_queue_song.blp b/resources/play_queue_song.blp index 05f8dd5..48e5637 100644 --- a/resources/play_queue_song.blp +++ b/resources/play_queue_song.blp @@ -35,7 +35,7 @@ template $AudreyUiPlayQueueSong: Box { margin-top: 1; margin-bottom: 1; pixel-size: 50; - paintable: bind template.song as <$AudreyPlaybinSong>.thumbnail; + //paintable: bind template.song as <$AudreyPlaybinSong>.thumbnail; } Box title_box { diff --git a/resources/window.blp b/resources/window.blp index 0d0b58d..67e7a4f 100644 --- a/resources/window.blp +++ b/resources/window.blp @@ -119,7 +119,7 @@ template $AudreyUiWindow: Adw.ApplicationWindow { margin-end: 24; styles [ "frame" ] - playbin: bind template.playbin; + //playbin: bind template.playbin; } }; } diff --git a/src/playbin2.rs b/src/playbin2.rs index 370555f..05c9b91 100644 --- a/src/playbin2.rs +++ b/src/playbin2.rs @@ -163,7 +163,9 @@ where pub fn remove_entry(&self, index: usize) { let mut entries = self.entries.borrow_mut(); - self.mpv.command(["remove", &index.to_string()]).unwrap(); + self.mpv + .command(["playlist-remove", &index.to_string()]) + .unwrap(); entries.remove(index as usize); drop(entries); @@ -241,6 +243,22 @@ where self.muted_changed.signal() } + pub fn current_entry_changed(&self) -> Signal<'_, Self, ()> { + self.current_entry_changed.signal() + } + + pub fn entry_inserted(&self) -> Signal<'_, Self, usize> { + self.entry_inserted.signal() + } + + pub fn stopped(&self) -> Signal<'_, Self, ()> { + self.stopped.signal() + } + + pub fn entry_removed(&self) -> Signal<'_, Self, usize> { + self.entry_removed.signal() + } + pub fn file_started(&self) -> Signal<'_, Self, ()> { self.file_started.signal() } diff --git a/src/signal.rs b/src/signal.rs index cb1780e..946093a 100644 --- a/src/signal.rs +++ b/src/signal.rs @@ -25,7 +25,7 @@ pub struct Signal<'a, E, T> { just_connected: &'a RefCell>>, } -#[derive(Clone)] +#[derive(Clone, Default)] pub struct SignalHandler(Weak>); impl SignalHandler { diff --git a/src/ui/play_queue.rs b/src/ui/play_queue.rs index bc49061..0a7cc7f 100644 --- a/src/ui/play_queue.rs +++ b/src/ui/play_queue.rs @@ -2,15 +2,22 @@ pub mod song; pub use song::Song; mod imp { - use adw::{glib, prelude::*, subclass::prelude::*}; + use crate::playbin::Song as PlaybinSong; + use adw::{gio, glib, prelude::*, subclass::prelude::*}; use glib::{subclass::InitializingObject, WeakRef}; + use std::cell::{Cell, RefCell}; + use std::rc::Rc; + + type Playbin = crate::playbin2::Playbin; #[derive(gtk::CompositeTemplate, glib::Properties, Default)] #[template(resource = "/eu/callcc/audrey/play_queue.ui")] #[properties(wrapper_type = super::PlayQueue)] pub struct PlayQueue { #[property(get, set)] - playbin: WeakRef, + pub(super) model: RefCell>, + + pub(super) playbin: RefCell>>, } #[glib::object_subclass] @@ -30,7 +37,13 @@ mod imp { } #[glib::derived_properties] - impl ObjectImpl for PlayQueue {} + impl ObjectImpl for PlayQueue { + fn constructed(&self) { + self.parent_constructed(); + + self.obj().set_model(gio::ListStore::new::()); + } + } impl WidgetImpl for PlayQueue {} @@ -49,7 +62,7 @@ mod imp { #[template_callback] fn on_song_list_setup(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) { - let child = super::Song::new(&self.playbin.upgrade().unwrap()); + let child = super::Song::new(self.playbin.borrow().as_ref().unwrap()); child.set_draggable(true); child.set_show_position(true); @@ -81,7 +94,11 @@ mod imp { #[template_callback] fn on_row_activated(&self, position: u32) { - self.obj().playbin().unwrap().select_track(position); + self.playbin + .borrow() + .as_ref() + .unwrap() + .play_entry(position as usize); } } @@ -92,10 +109,47 @@ mod imp { } } +use crate::playbin::Song as PlaybinSong; +use adw::subclass::prelude::*; use gtk::glib; +use std::rc::Rc; + +type Playbin = crate::playbin2::Playbin; glib::wrapper! { pub struct PlayQueue(ObjectSubclass) @extends adw::Bin, gtk::Widget, @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget; } + +impl PlayQueue { + pub fn set_playbin(&self, playbin: &Rc) { + assert!(self + .imp() + .playbin + .replace(Some(Rc::clone(playbin))) + .is_none()); // only set once + + playbin + .entry_inserted() + .connect_object(self, |playbin, play_queue, index| { + play_queue + .model() + .unwrap() + .insert(index as u32, &playbin.entries()[index]); + true + }); + playbin + .stopped() + .connect_object(self, |playbin, play_queue, ()| { + play_queue.model().unwrap().remove_all(); + true + }); + playbin + .entry_removed() + .connect_object(self, |playbin, play_queue, index| { + play_queue.model().unwrap().remove(index as u32); + true + }); + } +} diff --git a/src/ui/play_queue/song.rs b/src/ui/play_queue/song.rs index eba2fab..96cd66c 100644 --- a/src/ui/play_queue/song.rs +++ b/src/ui/play_queue/song.rs @@ -1,14 +1,17 @@ mod imp { + use crate::playbin::Song as PlaybinSong; + use crate::signal::SignalHandler; use glib::{subclass::InitializingObject, WeakRef}; use gtk::{gdk, gio, glib, prelude::*, subclass::prelude::*}; use std::cell::{Cell, RefCell}; + use std::rc::Rc; + + type Playbin = crate::playbin2::Playbin; #[derive(gtk::CompositeTemplate, glib::Properties, Default)] #[template(resource = "/eu/callcc/audrey/play_queue_song.ui")] #[properties(wrapper_type = super::Song)] pub struct Song { - pub(super) playbin: WeakRef, - #[property(set, get)] draggable: Cell, #[property(set, get)] @@ -24,12 +27,13 @@ mod imp { #[property(set, get)] displayed_position: Cell, #[property(get, set)] - song: RefCell>, - - pub(super) connection: Cell>, + song: RefCell>, drag_pos: Cell<(i32, i32)>, drag_widget: Cell>, + + pub(super) playbin: RefCell>>, + pub(super) connection: Cell, } #[glib::object_subclass] @@ -61,7 +65,7 @@ mod imp { self_ .obj() .playbin() - .remove_track(self_.obj().displayed_position() - 1) + .remove_entry(self_.obj().displayed_position() as usize - 1) } )) .build(); @@ -169,10 +173,14 @@ mod imp { } } +use crate::playbin::Song as PlaybinSong; use adw::prelude::*; use adw::subclass::prelude::*; use glib::Object; use gtk::glib; +use std::rc::Rc; + +type Playbin = crate::playbin2::Playbin; glib::wrapper! { pub struct Song(ObjectSubclass) @@ -181,36 +189,38 @@ glib::wrapper! { } impl Song { - pub fn new(playbin: &crate::Playbin) -> Self { + pub fn new(playbin: &Rc) -> Self { let song: Self = Object::new(); - song.imp().playbin.set(Some(playbin)); + + assert!(song + .imp() + .playbin + .replace(Some(Rc::clone(playbin))) + .is_none()); // only set once + song } - fn playbin(&self) -> crate::Playbin { - self.imp().playbin.upgrade().unwrap() + fn playbin(&self) -> Rc { + Rc::clone(self.imp().playbin.borrow().as_ref().unwrap()) } pub fn bind(&self, position: u32, song: &crate::playbin::Song) { self.set_displayed_position(position + 1); self.set_song(song); - self.set_current(self.playbin().play_queue_position() == position); + self.set_current(self.playbin().current_entry() == Some(position as usize)); self.imp() .connection - .replace(Some(self.playbin().connect_notify_local( - Some("play-queue-position"), - glib::clone!( - #[weak(rename_to = self_)] - self, - move |playbin: &crate::Playbin, _| { - self_.set_current(playbin.play_queue_position() == position) - } - ), - ))); + .replace(self.playbin().current_entry_changed().connect_object( + self, + move |playbin, song, ()| { + song.set_current(playbin.current_entry() == Some(position as usize)); + true + }, + )); } pub fn unbind(&self) { - self.playbin() - .disconnect(self.imp().connection.take().unwrap()); + self.imp().connection.take().disconnect(); } } diff --git a/src/ui/window.rs b/src/ui/window.rs index cb0bc7f..5cb4422 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -19,6 +19,9 @@ mod imp { #[template_child] pub(super) playbar: TemplateChild, + #[template_child] + pub(super) play_queue: TemplateChild, + #[property(get, set)] playbin: RefCell, @@ -72,6 +75,8 @@ mod imp { } })); + self.play_queue.set_playbin(&self.playbin2); + // set up mpris let window = self.obj().clone(); glib::spawn_future_local(async move {