play queue now works again (sort of)

This commit is contained in:
Erica Z 2024-11-03 18:45:52 +01:00
parent 0a5f8a9162
commit ec0992ce54
8 changed files with 121 additions and 34 deletions

View file

@ -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 <string>;
visible-child-name: bind $visible_child_name (template.model as <$GListStore>.n-items) as <string>;
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 {

View file

@ -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 {

View file

@ -119,7 +119,7 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
margin-end: 24;
styles [ "frame" ]
playbin: bind template.playbin;
//playbin: bind template.playbin;
}
};
}

View file

@ -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()
}

View file

@ -25,7 +25,7 @@ pub struct Signal<'a, E, T> {
just_connected: &'a RefCell<Vec<SignalHandlerBox<E, T>>>,
}
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct SignalHandler(Weak<Cell<bool>>);
impl SignalHandler {

View file

@ -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<PlaybinSong>;
#[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<crate::Playbin>,
pub(super) model: RefCell<Option<gio::ListStore>>,
pub(super) playbin: RefCell<Option<Rc<Playbin>>>,
}
#[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::<PlaybinSong>());
}
}
impl WidgetImpl for PlayQueue {}
@ -49,7 +62,7 @@ mod imp {
#[template_callback]
fn on_song_list_setup(&self, item: &gtk::ListItem, _factory: &gtk::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<PlaybinSong>;
glib::wrapper! {
pub struct PlayQueue(ObjectSubclass<imp::PlayQueue>)
@extends adw::Bin, gtk::Widget,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}
impl PlayQueue {
pub fn set_playbin(&self, playbin: &Rc<Playbin>) {
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
});
}
}

View file

@ -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<PlaybinSong>;
#[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<crate::Playbin>,
#[property(set, get)]
draggable: Cell<bool>,
#[property(set, get)]
@ -24,12 +27,13 @@ mod imp {
#[property(set, get)]
displayed_position: Cell<u32>,
#[property(get, set)]
song: RefCell<Option<crate::playbin::Song>>,
pub(super) connection: Cell<Option<glib::SignalHandlerId>>,
song: RefCell<Option<PlaybinSong>>,
drag_pos: Cell<(i32, i32)>,
drag_widget: Cell<Option<gtk::ListBox>>,
pub(super) playbin: RefCell<Option<Rc<Playbin>>>,
pub(super) connection: Cell<SignalHandler>,
}
#[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<PlaybinSong>;
glib::wrapper! {
pub struct Song(ObjectSubclass<imp::Song>)
@ -181,36 +189,38 @@ glib::wrapper! {
}
impl Song {
pub fn new(playbin: &crate::Playbin) -> Self {
pub fn new(playbin: &Rc<Playbin>) -> 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<Playbin> {
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();
}
}

View file

@ -19,6 +19,9 @@ mod imp {
#[template_child]
pub(super) playbar: TemplateChild<crate::ui::Playbar>,
#[template_child]
pub(super) play_queue: TemplateChild<crate::ui::PlayQueue>,
#[property(get, set)]
playbin: RefCell<crate::Playbin>,
@ -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 {