remove some signals
This commit is contained in:
parent
4413aaff4b
commit
9ff36afb15
9 changed files with 203 additions and 104 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -217,6 +217,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
name = "audrey"
|
name = "audrey"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-broadcast",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"bindgen",
|
"bindgen",
|
||||||
|
|
|
@ -5,6 +5,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
adw = { version = "0.7.0", package = "libadwaita", features = ["v1_6"] }
|
adw = { version = "0.7.0", package = "libadwaita", features = ["v1_6"] }
|
||||||
|
async-broadcast = "0.7.1"
|
||||||
async-channel = "2.3.1"
|
async-channel = "2.3.1"
|
||||||
base16ct = { version = "0.2.0", features = ["std"] }
|
base16ct = { version = "0.2.0", features = ["std"] }
|
||||||
chrono = { version = "0.4.38", features = ["serde"] }
|
chrono = { version = "0.4.38", features = ["serde"] }
|
||||||
|
|
34
src/broadcast.rs
Normal file
34
src/broadcast.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// nice wrapper to have a Default impl for a (Sender, InactiveReceiver) pair
|
||||||
|
|
||||||
|
use async_broadcast::{broadcast, InactiveReceiver, Receiver, Sender, TrySendError};
|
||||||
|
|
||||||
|
pub struct Broadcast<const N: usize, T> {
|
||||||
|
pub sender: Sender<T>,
|
||||||
|
inactive_receiver: InactiveReceiver<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize, T> Default for Broadcast<N, T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
let (sender, receiver) = broadcast(N);
|
||||||
|
Self {
|
||||||
|
sender,
|
||||||
|
inactive_receiver: receiver.deactivate(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize, T> Broadcast<N, T> where T: Clone {
|
||||||
|
pub fn receiver(&self) -> Receiver<T> {
|
||||||
|
self.inactive_receiver.activate_cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
// like sender.try_broadcast, but ignores if there aren't any active listeners
|
||||||
|
pub fn try_broadcast(&self, msg: T) -> Result<(), TrySendError<T>> {
|
||||||
|
match self.sender.try_broadcast(msg) {
|
||||||
|
Err(TrySendError::Inactive(_)) => Ok(()), // ignore
|
||||||
|
Err(err) => Err(err),
|
||||||
|
Ok(Some(_)) => unreachable!("we do not enable overflow mode"),
|
||||||
|
Ok(None) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/event.rs
Normal file
29
src/event.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Event {
|
||||||
|
PlaybinVolumeChanged,
|
||||||
|
PlaybinMutedChanged,
|
||||||
|
PlaybinPausedChanged,
|
||||||
|
PlaybinCurrentEntryChanged,
|
||||||
|
|
||||||
|
PlaybinEntryInserted(usize),
|
||||||
|
PlaybinStopped,
|
||||||
|
PlaybinEntryRemoved(usize),
|
||||||
|
|
||||||
|
PlaybinFileStarted,
|
||||||
|
}
|
||||||
|
|
||||||
|
use adw::prelude::*;
|
||||||
|
use gtk::glib;
|
||||||
|
|
||||||
|
pub fn spawn_object_listener<O: IsA<glib::Object>>(
|
||||||
|
mut receiver: async_broadcast::Receiver<Event>,
|
||||||
|
obj: &O,
|
||||||
|
mut f: impl FnMut(O, Event) + 'static,
|
||||||
|
) {
|
||||||
|
let weak = obj.downgrade();
|
||||||
|
glib::spawn_future_local(async move {
|
||||||
|
while let Some(obj) = weak.upgrade() {
|
||||||
|
f(obj, receiver.recv_direct().await.unwrap());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -22,6 +22,9 @@ pub type Playbin = playbin::Playbin<PlaybinSong>;
|
||||||
mod signal;
|
mod signal;
|
||||||
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
||||||
|
|
||||||
|
pub mod event;
|
||||||
|
pub use event::Event;
|
||||||
|
|
||||||
use gettextrs::{bind_textdomain_codeset, bindtextdomain, setlocale, textdomain, LocaleCategory};
|
use gettextrs::{bind_textdomain_codeset, bindtextdomain, setlocale, textdomain, LocaleCategory};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{gio, glib};
|
use gtk::{gio, glib};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::mpv;
|
use crate::mpv;
|
||||||
use crate::signal::{Signal, SignalEmitter};
|
use crate::signal::{Signal, SignalEmitter};
|
||||||
|
use crate::Event;
|
||||||
use event_listener::EventListener;
|
use event_listener::EventListener;
|
||||||
use std::cell::{Ref, RefCell};
|
use std::cell::{Ref, RefCell};
|
||||||
use tracing::{event, span, Level};
|
use tracing::{event, span, Level};
|
||||||
|
@ -20,20 +21,19 @@ pub struct Playbin<E> {
|
||||||
mpv: mpv::Handle,
|
mpv: mpv::Handle,
|
||||||
entries: RefCell<Vec<E>>,
|
entries: RefCell<Vec<E>>,
|
||||||
|
|
||||||
volume_changed: SignalEmitter<Self, ()>,
|
sender: async_broadcast::Sender<Event>,
|
||||||
muted_changed: SignalEmitter<Self, ()>,
|
|
||||||
paused_changed: SignalEmitter<Self, ()>,
|
|
||||||
current_entry_changed: SignalEmitter<Self, ()>,
|
|
||||||
|
|
||||||
entry_inserted: SignalEmitter<Self, usize>,
|
|
||||||
stopped: SignalEmitter<Self, ()>,
|
stopped: SignalEmitter<Self, ()>,
|
||||||
entry_removed: SignalEmitter<Self, usize>,
|
entry_removed: SignalEmitter<Self, usize>,
|
||||||
|
|
||||||
file_started: SignalEmitter<Self, ()>,
|
file_started: SignalEmitter<Self, ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Default for Playbin<E> {
|
impl<E> Playbin<E>
|
||||||
fn default() -> Self {
|
where
|
||||||
|
E: PlaybinEntry,
|
||||||
|
{
|
||||||
|
pub fn new(sender: async_broadcast::Sender<Event>) -> Self {
|
||||||
let mpv = mpv::Handle::new();
|
let mpv = mpv::Handle::new();
|
||||||
mpv.set_property("audio-client-name", "audrey").unwrap();
|
mpv.set_property("audio-client-name", "audrey").unwrap();
|
||||||
mpv.set_property("user-agent", crate::USER_AGENT).unwrap();
|
mpv.set_property("user-agent", crate::USER_AGENT).unwrap();
|
||||||
|
@ -53,24 +53,15 @@ impl<E> Default for Playbin<E> {
|
||||||
mpv,
|
mpv,
|
||||||
entries: RefCell::new(vec![]),
|
entries: RefCell::new(vec![]),
|
||||||
|
|
||||||
volume_changed: Default::default(),
|
sender,
|
||||||
muted_changed: Default::default(),
|
|
||||||
paused_changed: Default::default(),
|
|
||||||
current_entry_changed: Default::default(),
|
|
||||||
|
|
||||||
entry_inserted: Default::default(),
|
|
||||||
stopped: Default::default(),
|
stopped: Default::default(),
|
||||||
entry_removed: Default::default(),
|
entry_removed: Default::default(),
|
||||||
|
|
||||||
file_started: Default::default(),
|
file_started: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<E> Playbin<E>
|
|
||||||
where
|
|
||||||
E: PlaybinEntry,
|
|
||||||
{
|
|
||||||
pub fn volume(&self) -> i64 {
|
pub fn volume(&self) -> i64 {
|
||||||
self.mpv.get_property("volume").unwrap()
|
self.mpv.get_property("volume").unwrap()
|
||||||
}
|
}
|
||||||
|
@ -138,7 +129,9 @@ where
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.entry_inserted.emit(self, index);
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinEntryInserted(index))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_entry(&self, index: usize, entry: E) {
|
pub fn insert_entry(&self, index: usize, entry: E) {
|
||||||
|
@ -149,7 +142,9 @@ where
|
||||||
entries.insert(index, entry);
|
entries.insert(index, entry);
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.entry_inserted.emit(self, index);
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinEntryInserted(index))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop playback and clear playlist
|
// stop playback and clear playlist
|
||||||
|
@ -159,7 +154,7 @@ where
|
||||||
entries.clear();
|
entries.clear();
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.stopped.emit(self, ());
|
self.sender.try_broadcast(Event::PlaybinStopped).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_entry(&self, index: usize) {
|
pub fn remove_entry(&self, index: usize) {
|
||||||
|
@ -170,7 +165,9 @@ where
|
||||||
entries.remove(index);
|
entries.remove(index);
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.entry_removed.emit(self, index);
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinEntryRemoved(index))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_entry(&self, _from: usize, _to: usize) {
|
pub fn move_entry(&self, _from: usize, _to: usize) {
|
||||||
|
@ -192,25 +189,33 @@ where
|
||||||
mpv::Event::PropertyChange(event) => match event.reply_userdata {
|
mpv::Event::PropertyChange(event) => match event.reply_userdata {
|
||||||
0 => {
|
0 => {
|
||||||
assert_eq!(&event.name, "volume");
|
assert_eq!(&event.name, "volume");
|
||||||
self.volume_changed.emit(self, ());
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinVolumeChanged)
|
||||||
|
.unwrap();
|
||||||
event!(Level::DEBUG, "volume change {}", self.volume());
|
event!(Level::DEBUG, "volume change {}", self.volume());
|
||||||
}
|
}
|
||||||
|
|
||||||
1 => {
|
1 => {
|
||||||
assert_eq!(&event.name, "mute");
|
assert_eq!(&event.name, "mute");
|
||||||
self.muted_changed.emit(self, ());
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinMutedChanged)
|
||||||
|
.unwrap();
|
||||||
event!(Level::DEBUG, "mute state change to {}", self.muted());
|
event!(Level::DEBUG, "mute state change to {}", self.muted());
|
||||||
}
|
}
|
||||||
|
|
||||||
2 => {
|
2 => {
|
||||||
assert_eq!(&event.name, "pause");
|
assert_eq!(&event.name, "pause");
|
||||||
self.paused_changed.emit(self, ());
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinPausedChanged)
|
||||||
|
.unwrap();
|
||||||
event!(Level::DEBUG, "pause state change to {}", self.paused());
|
event!(Level::DEBUG, "pause state change to {}", self.paused());
|
||||||
}
|
}
|
||||||
|
|
||||||
3 => {
|
3 => {
|
||||||
assert_eq!(&event.name, "playlist-pos");
|
assert_eq!(&event.name, "playlist-pos");
|
||||||
self.current_entry_changed.emit(self, ());
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinCurrentEntryChanged)
|
||||||
|
.unwrap();
|
||||||
event!(
|
event!(
|
||||||
Level::DEBUG,
|
Level::DEBUG,
|
||||||
"playlist-pos change {:?}",
|
"playlist-pos change {:?}",
|
||||||
|
@ -235,7 +240,9 @@ where
|
||||||
mpv::Event::StartFile(_) => {
|
mpv::Event::StartFile(_) => {
|
||||||
// since we set up the hook before, the current song is guaranteed not to change
|
// since we set up the hook before, the current song is guaranteed not to change
|
||||||
// under our feet
|
// under our feet
|
||||||
self.file_started.emit(self, ());
|
self.sender
|
||||||
|
.try_broadcast(Event::PlaybinFileStarted)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -248,22 +255,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn volume_changed(&self) -> Signal<'_, Self, ()> {
|
|
||||||
self.volume_changed.signal()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn muted_changed(&self) -> Signal<'_, Self, ()> {
|
|
||||||
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, ()> {
|
pub fn stopped(&self) -> Signal<'_, Self, ()> {
|
||||||
self.stopped.signal()
|
self.stopped.signal()
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ mod imp {
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn on_song_list_setup(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) {
|
fn on_song_list_setup(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) {
|
||||||
let child = super::Song::new(self.playbin.borrow().as_ref().unwrap());
|
let child = super::Song::new(Some(&self.obj().window()));
|
||||||
|
|
||||||
child.set_draggable(true);
|
child.set_draggable(true);
|
||||||
child.set_show_position(true);
|
child.set_show_position(true);
|
||||||
|
@ -75,10 +75,7 @@ mod imp {
|
||||||
fn on_song_list_bind(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) {
|
fn on_song_list_bind(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) {
|
||||||
let child = item.child().and_downcast::<super::Song>().unwrap();
|
let child = item.child().and_downcast::<super::Song>().unwrap();
|
||||||
|
|
||||||
child.bind(
|
child.bind(item.position(), &self.obj().window());
|
||||||
item.position(),
|
|
||||||
item.item().unwrap().downcast_ref::<PlaybinSong>().unwrap(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
@ -106,6 +103,7 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::Playbin;
|
use crate::Playbin;
|
||||||
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -124,15 +122,6 @@ impl PlayQueue {
|
||||||
.replace(Some(Rc::clone(playbin)))
|
.replace(Some(Rc::clone(playbin)))
|
||||||
.is_none()); // only set once
|
.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
|
playbin
|
||||||
.stopped()
|
.stopped()
|
||||||
.connect_object(self, |_playbin, play_queue, ()| {
|
.connect_object(self, |_playbin, play_queue, ()| {
|
||||||
|
@ -146,4 +135,8 @@ impl PlayQueue {
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn window(&self) -> crate::ui::Window {
|
||||||
|
self.root().unwrap().dynamic_cast().unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
mod imp {
|
mod imp {
|
||||||
use crate::signal::SignalHandler;
|
use crate::PlaybinSong;
|
||||||
use crate::{Playbin, PlaybinSong};
|
|
||||||
use glib::subclass::InitializingObject;
|
use glib::subclass::InitializingObject;
|
||||||
use gtk::{gdk, gio, glib, prelude::*, subclass::prelude::*};
|
use gtk::{gdk, gio, glib, prelude::*, subclass::prelude::*};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||||
#[template(resource = "/eu/callcc/audrey/play_queue_song.ui")]
|
#[template(resource = "/eu/callcc/audrey/play_queue_song.ui")]
|
||||||
|
@ -21,6 +19,8 @@ mod imp {
|
||||||
|
|
||||||
#[property(set = Self::set_current, get)]
|
#[property(set = Self::set_current, get)]
|
||||||
current: Cell<bool>,
|
current: Cell<bool>,
|
||||||
|
#[property(set, get)]
|
||||||
|
position: Cell<u32>,
|
||||||
|
|
||||||
#[property(set, get)]
|
#[property(set, get)]
|
||||||
displayed_position: Cell<u32>,
|
displayed_position: Cell<u32>,
|
||||||
|
@ -29,9 +29,6 @@ mod imp {
|
||||||
|
|
||||||
drag_pos: Cell<(i32, i32)>,
|
drag_pos: Cell<(i32, i32)>,
|
||||||
drag_widget: Cell<Option<gtk::ListBox>>,
|
drag_widget: Cell<Option<gtk::ListBox>>,
|
||||||
|
|
||||||
pub(super) playbin: RefCell<Option<Rc<Playbin>>>,
|
|
||||||
pub(super) connection: Cell<SignalHandler>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -62,6 +59,7 @@ mod imp {
|
||||||
move |_, _, _| {
|
move |_, _, _| {
|
||||||
self_
|
self_
|
||||||
.obj()
|
.obj()
|
||||||
|
.window()
|
||||||
.playbin()
|
.playbin()
|
||||||
.remove_entry(self_.obj().displayed_position() as usize - 1)
|
.remove_entry(self_.obj().displayed_position() as usize - 1)
|
||||||
}
|
}
|
||||||
|
@ -123,7 +121,7 @@ mod imp {
|
||||||
fn on_drag_begin(&self, drag: &gdk::Drag) {
|
fn on_drag_begin(&self, drag: &gdk::Drag) {
|
||||||
let drag_widget = gtk::ListBox::new();
|
let drag_widget = gtk::ListBox::new();
|
||||||
|
|
||||||
let drag_row = super::Song::new(&self.obj().playbin());
|
let drag_row = super::Song::new(None);
|
||||||
drag_row.set_draggable(false);
|
drag_row.set_draggable(false);
|
||||||
drag_row.set_show_position(self.obj().show_position());
|
drag_row.set_show_position(self.obj().show_position());
|
||||||
drag_row.set_show_artist(self.obj().show_artist());
|
drag_row.set_show_artist(self.obj().show_artist());
|
||||||
|
@ -165,11 +163,10 @@ mod imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::{Playbin, PlaybinSong};
|
use crate::PlaybinSong;
|
||||||
use adw::subclass::prelude::*;
|
use adw::prelude::*;
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct Song(ObjectSubclass<imp::Song>)
|
pub struct Song(ObjectSubclass<imp::Song>)
|
||||||
|
@ -178,38 +175,41 @@ glib::wrapper! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Song {
|
impl Song {
|
||||||
pub fn new(playbin: &Rc<Playbin>) -> Self {
|
pub fn new(window: Option<&crate::ui::Window>) -> Self {
|
||||||
let song: Self = Object::new();
|
let song: Self = Object::new();
|
||||||
|
|
||||||
assert!(song
|
if let Some(window) = window {
|
||||||
.imp()
|
use crate::Event;
|
||||||
.playbin
|
|
||||||
.replace(Some(Rc::clone(playbin)))
|
crate::event::spawn_object_listener(
|
||||||
.is_none()); // only set once
|
window.receiver(),
|
||||||
|
&song,
|
||||||
|
|song, event| match event {
|
||||||
|
Event::PlaybinCurrentEntryChanged => {
|
||||||
|
song.set_current(
|
||||||
|
song.window().playbin().current_entry()
|
||||||
|
== Some(song.position() as usize),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
song
|
song
|
||||||
}
|
}
|
||||||
|
|
||||||
fn playbin(&self) -> Rc<Playbin> {
|
fn window(&self) -> crate::ui::Window {
|
||||||
Rc::clone(self.imp().playbin.borrow().as_ref().unwrap())
|
self.root().unwrap().dynamic_cast().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(&self, position: u32, song: &PlaybinSong) {
|
pub fn bind(&self, position: u32, window: &crate::ui::Window) {
|
||||||
self.set_displayed_position(position + 1);
|
self.set_displayed_position(position + 1);
|
||||||
self.set_song(song);
|
self.set_song(&window.playbin().entries()[position as usize]);
|
||||||
self.set_current(self.playbin().current_entry() == Some(position as usize));
|
self.set_current(window.playbin().current_entry() == Some(position as usize));
|
||||||
self.imp()
|
self.set_position(position);
|
||||||
.connection
|
|
||||||
.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) {
|
pub fn unbind(&self) {}
|
||||||
self.imp().connection.take().disconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ mod imp {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use tracing::{event, Level};
|
use tracing::{event, Level};
|
||||||
|
|
||||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
#[derive(gtk::CompositeTemplate, glib::Properties)]
|
||||||
#[template(resource = "/eu/callcc/audrey/window.ui")]
|
#[template(resource = "/eu/callcc/audrey/window.ui")]
|
||||||
#[properties(wrapper_type = super::Window)]
|
#[properties(wrapper_type = super::Window)]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
@ -31,6 +31,28 @@ mod imp {
|
||||||
|
|
||||||
pub(super) playbin: Rc<Playbin>,
|
pub(super) playbin: Rc<Playbin>,
|
||||||
pub(super) api: RefCell<Option<Rc<crate::subsonic::Client>>>,
|
pub(super) api: RefCell<Option<Rc<crate::subsonic::Client>>>,
|
||||||
|
|
||||||
|
pub(super) sender: async_broadcast::Sender<crate::Event>,
|
||||||
|
pub(super) inactive_receiver: async_broadcast::InactiveReceiver<crate::Event>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Window {
|
||||||
|
fn default() -> Self {
|
||||||
|
let (sender, receiver) = async_broadcast::broadcast(100); // TODO: constantize
|
||||||
|
|
||||||
|
Self {
|
||||||
|
playbar: Default::default(),
|
||||||
|
play_queue: Default::default(),
|
||||||
|
can_click_shuffle_all: Cell::new(false),
|
||||||
|
playing_cover_art: Default::default(),
|
||||||
|
song: Default::default(),
|
||||||
|
setup: Default::default(),
|
||||||
|
playbin: Rc::new(Playbin::new(sender.clone())),
|
||||||
|
api: Default::default(),
|
||||||
|
sender,
|
||||||
|
inactive_receiver: receiver.deactivate(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -54,6 +76,37 @@ mod imp {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
|
|
||||||
|
crate::event::spawn_object_listener(
|
||||||
|
self.inactive_receiver.activate_cloned(),
|
||||||
|
self.obj().as_ref(),
|
||||||
|
|window, event| {
|
||||||
|
use crate::Event;
|
||||||
|
match dbg!(event) {
|
||||||
|
Event::PlaybinVolumeChanged => {
|
||||||
|
window
|
||||||
|
.imp()
|
||||||
|
.playbar
|
||||||
|
.set_volume(window.playbin().volume() as i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::PlaybinMutedChanged => {
|
||||||
|
window.imp().playbar.set_mute(window.playbin().muted());
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::PlaybinEntryInserted(index) => {
|
||||||
|
window
|
||||||
|
.imp()
|
||||||
|
.play_queue
|
||||||
|
.model()
|
||||||
|
.unwrap()
|
||||||
|
.insert(index as u32, &window.playbin().entries()[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let playbin = Rc::downgrade(&self.playbin);
|
let playbin = Rc::downgrade(&self.playbin);
|
||||||
glib::spawn_future_local(glib::clone!(async move {
|
glib::spawn_future_local(glib::clone!(async move {
|
||||||
loop {
|
loop {
|
||||||
|
@ -197,13 +250,6 @@ impl Window {
|
||||||
.imp()
|
.imp()
|
||||||
.playbar
|
.playbar
|
||||||
.set_volume(window.imp().playbin.volume() as i32);
|
.set_volume(window.imp().playbin.volume() as i32);
|
||||||
window.imp().playbin.volume_changed().connect_object(
|
|
||||||
&*window.imp().playbar,
|
|
||||||
|playbin, playbar, ()| {
|
|
||||||
playbar.set_volume(playbin.volume() as i32);
|
|
||||||
true
|
|
||||||
},
|
|
||||||
);
|
|
||||||
window.imp().playbar.connect_notify_local(
|
window.imp().playbar.connect_notify_local(
|
||||||
Some("volume"),
|
Some("volume"),
|
||||||
glib::clone!(
|
glib::clone!(
|
||||||
|
@ -214,13 +260,6 @@ impl Window {
|
||||||
);
|
);
|
||||||
|
|
||||||
window.imp().playbar.set_mute(window.imp().playbin.muted());
|
window.imp().playbar.set_mute(window.imp().playbin.muted());
|
||||||
window.imp().playbin.muted_changed().connect_object(
|
|
||||||
&*window.imp().playbar,
|
|
||||||
|playbin, playbar, ()| {
|
|
||||||
playbar.set_mute(playbin.muted());
|
|
||||||
true
|
|
||||||
},
|
|
||||||
);
|
|
||||||
window.imp().playbar.connect_notify_local(
|
window.imp().playbar.connect_notify_local(
|
||||||
Some("mute"),
|
Some("mute"),
|
||||||
glib::clone!(
|
glib::clone!(
|
||||||
|
@ -282,4 +321,12 @@ impl Window {
|
||||||
|
|
||||||
window
|
window
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn playbin(&self) -> &crate::Playbin {
|
||||||
|
&self.imp().playbin
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receiver(&self) -> async_broadcast::Receiver<crate::Event> {
|
||||||
|
self.imp().inactive_receiver.activate_cloned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue