Compare commits
No commits in common. "acd1d7d80363e79f87afb977d5657b59b1eab511" and "e4083288e674fb0fc4b6bb9ca3bfd3cc1c167d96" have entirely different histories.
acd1d7d803
...
e4083288e6
8 changed files with 111 additions and 199 deletions
|
@ -150,7 +150,7 @@ template $AudreyUiPlaybar: Adw.Bin {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
icon-name: bind $mute_button_icon_name (template.mute) as <string>;
|
icon-name: bind $mute_button_icon_name (template.playbin as <$AudreyPlaybin>.mute) as <string>;
|
||||||
valign: center;
|
valign: center;
|
||||||
|
|
||||||
clicked => $on_mute_toggle () swapped;
|
clicked => $on_mute_toggle () swapped;
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub use playbin::Playbin;
|
||||||
pub mod subsonic;
|
pub mod subsonic;
|
||||||
pub mod subsonic_vala;
|
pub mod subsonic_vala;
|
||||||
|
|
||||||
pub mod playbin2;
|
mod playbin2;
|
||||||
|
|
||||||
mod signal;
|
mod signal;
|
||||||
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::mpv;
|
use crate::mpv;
|
||||||
use crate::signal::{Signal, SignalEmitter};
|
use crate::signal::SignalEmitter;
|
||||||
use event_listener::EventListener;
|
use event_listener::EventListener;
|
||||||
use std::cell::{Ref, RefCell};
|
use std::cell::{Ref, RefCell};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub trait PlaybinEntry {
|
pub trait PlaybinEntry {
|
||||||
fn url(&self) -> Url;
|
fn url(&self) -> &Url;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaybinEntry for Url {
|
impl PlaybinEntry for Url {
|
||||||
fn url(&self) -> Url {
|
fn url(&self) -> &Url {
|
||||||
self.clone()
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,16 +19,12 @@ pub struct Playbin<E> {
|
||||||
mpv: mpv::Handle,
|
mpv: mpv::Handle,
|
||||||
entries: RefCell<Vec<E>>,
|
entries: RefCell<Vec<E>>,
|
||||||
|
|
||||||
volume_changed: SignalEmitter<Self, ()>,
|
paused_changed: SignalEmitter<()>,
|
||||||
muted_changed: SignalEmitter<Self, ()>,
|
current_entry_changed: SignalEmitter<()>,
|
||||||
paused_changed: SignalEmitter<Self, ()>,
|
|
||||||
current_entry_changed: SignalEmitter<Self, ()>,
|
|
||||||
|
|
||||||
entry_inserted: SignalEmitter<Self, u32>,
|
entry_inserted: SignalEmitter<u32>,
|
||||||
stopped: SignalEmitter<Self, ()>,
|
stopped: SignalEmitter<()>,
|
||||||
entry_removed: SignalEmitter<Self, u32>,
|
entry_removed: SignalEmitter<u32>,
|
||||||
|
|
||||||
file_started: SignalEmitter<Self, ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Default for Playbin<E> {
|
impl<E> Default for Playbin<E> {
|
||||||
|
@ -40,10 +36,8 @@ impl<E> Default for Playbin<E> {
|
||||||
mpv.set_property("prefetch-playlist", true).unwrap();
|
mpv.set_property("prefetch-playlist", true).unwrap();
|
||||||
mpv.set_property("gapless-audio", true).unwrap();
|
mpv.set_property("gapless-audio", true).unwrap();
|
||||||
|
|
||||||
mpv.observe_property(0, "volume").unwrap();
|
mpv.observe_property(0, "pause").unwrap();
|
||||||
mpv.observe_property(1, "mute").unwrap();
|
mpv.observe_property(1, "playlist-pos").unwrap();
|
||||||
mpv.observe_property(2, "pause").unwrap();
|
|
||||||
mpv.observe_property(3, "playlist-pos").unwrap();
|
|
||||||
|
|
||||||
// "Useful to drain property changes before a new file is loaded."
|
// "Useful to drain property changes before a new file is loaded."
|
||||||
mpv.add_hook(0, "on_before_start_file", 0).unwrap();
|
mpv.add_hook(0, "on_before_start_file", 0).unwrap();
|
||||||
|
@ -52,16 +46,12 @@ impl<E> Default for Playbin<E> {
|
||||||
mpv,
|
mpv,
|
||||||
entries: RefCell::new(vec![]),
|
entries: RefCell::new(vec![]),
|
||||||
|
|
||||||
volume_changed: Default::default(),
|
|
||||||
muted_changed: Default::default(),
|
|
||||||
paused_changed: Default::default(),
|
paused_changed: Default::default(),
|
||||||
current_entry_changed: Default::default(),
|
current_entry_changed: Default::default(),
|
||||||
|
|
||||||
entry_inserted: Default::default(),
|
entry_inserted: Default::default(),
|
||||||
stopped: Default::default(),
|
stopped: Default::default(),
|
||||||
entry_removed: Default::default(),
|
entry_removed: Default::default(),
|
||||||
|
|
||||||
file_started: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,22 +60,6 @@ impl<E> Playbin<E>
|
||||||
where
|
where
|
||||||
E: PlaybinEntry,
|
E: PlaybinEntry,
|
||||||
{
|
{
|
||||||
pub fn volume(&self) -> i64 {
|
|
||||||
self.mpv.get_property("volume").unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_volume(&self, volume: i64) {
|
|
||||||
self.mpv.set_property("volume", volume).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn muted(&self) -> bool {
|
|
||||||
self.mpv.get_property("mute").unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_muted(&self, muted: bool) {
|
|
||||||
self.mpv.set_property("mute", muted).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paused(&self) -> bool {
|
pub fn paused(&self) -> bool {
|
||||||
self.mpv.get_property("pause").unwrap()
|
self.mpv.get_property("pause").unwrap()
|
||||||
}
|
}
|
||||||
|
@ -137,7 +111,7 @@ where
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.entry_inserted.emit(self, index as u32);
|
self.entry_inserted.emit(index as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_entry(&self, index: u32, entry: E) {
|
pub fn insert_entry(&self, index: u32, entry: E) {
|
||||||
|
@ -148,7 +122,7 @@ where
|
||||||
entries.insert(index as usize, entry);
|
entries.insert(index as usize, entry);
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.entry_inserted.emit(self, index);
|
self.entry_inserted.emit(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop playback and clear playlist
|
// stop playback and clear playlist
|
||||||
|
@ -158,7 +132,7 @@ where
|
||||||
entries.clear();
|
entries.clear();
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.stopped.emit(self, ());
|
self.stopped.emit(());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_entry(&self, index: u32) {
|
pub fn remove_entry(&self, index: u32) {
|
||||||
|
@ -167,7 +141,7 @@ where
|
||||||
entries.remove(index as usize);
|
entries.remove(index as usize);
|
||||||
|
|
||||||
drop(entries);
|
drop(entries);
|
||||||
self.entry_removed.emit(self, index);
|
self.entry_removed.emit(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_entry(&self, _from: u32, _to: u32) {
|
pub fn move_entry(&self, _from: u32, _to: u32) {
|
||||||
|
@ -186,26 +160,14 @@ where
|
||||||
match event {
|
match event {
|
||||||
mpv::Event::PropertyChange(event) => match event.reply_userdata {
|
mpv::Event::PropertyChange(event) => match event.reply_userdata {
|
||||||
0 => {
|
0 => {
|
||||||
assert_eq!(&event.name, "volume");
|
|
||||||
self.volume_changed.emit(self, ());
|
|
||||||
println!("new volume! {:?}", self.volume());
|
|
||||||
}
|
|
||||||
|
|
||||||
1 => {
|
|
||||||
assert_eq!(&event.name, "mute");
|
|
||||||
self.muted_changed.emit(self, ());
|
|
||||||
println!("new muted! {:?}", self.muted());
|
|
||||||
}
|
|
||||||
|
|
||||||
2 => {
|
|
||||||
assert_eq!(&event.name, "pause");
|
assert_eq!(&event.name, "pause");
|
||||||
self.paused_changed.emit(self, ());
|
self.paused_changed.emit(());
|
||||||
println!("new paused! {:?}", self.paused());
|
println!("new paused! {:?}", self.paused());
|
||||||
}
|
}
|
||||||
|
|
||||||
3 => {
|
1 => {
|
||||||
assert_eq!(&event.name, "playlist-pos");
|
assert_eq!(&event.name, "playlist-pos");
|
||||||
self.current_entry_changed.emit(self, ());
|
self.current_entry_changed.emit(());
|
||||||
println!("new current_entry! {:?}", self.current_entry());
|
println!("new current_entry! {:?}", self.current_entry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,27 +185,9 @@ where
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
|
|
||||||
mpv::Event::StartFile(_) => {
|
|
||||||
// since we set up the hook before, the current song is guaranteed not to change
|
|
||||||
// under our feet
|
|
||||||
self.file_started.emit(self, ());
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => println!("mpv event {:?}", event),
|
_ => println!("mpv event {:?}", event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn volume_changed(&self) -> Signal<'_, Self, ()> {
|
|
||||||
self.volume_changed.signal()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn muted_changed(&self) -> Signal<'_, Self, ()> {
|
|
||||||
self.muted_changed.signal()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_started(&self) -> Signal<'_, Self, ()> {
|
|
||||||
self.file_started.signal()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Drop for Playbin<E> {
|
impl<E> Drop for Playbin<E> {
|
||||||
|
|
|
@ -5,14 +5,14 @@ use gtk::{
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
type SignalHandlerBox<E, T> = Box<dyn FnMut(&E, T) -> bool>;
|
type SignalHandlerBox<T> = Box<dyn FnMut(T) -> bool>;
|
||||||
|
|
||||||
pub struct SignalEmitter<E, T> {
|
pub struct SignalEmitter<T> {
|
||||||
handlers: RefCell<Vec<SignalHandlerBox<E, T>>>,
|
handlers: RefCell<Vec<SignalHandlerBox<T>>>,
|
||||||
just_connected: RefCell<Vec<SignalHandlerBox<E, T>>>,
|
just_connected: RefCell<Vec<SignalHandlerBox<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, T> Default for SignalEmitter<E, T> {
|
impl<T> Default for SignalEmitter<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
handlers: RefCell::new(vec![]),
|
handlers: RefCell::new(vec![]),
|
||||||
|
@ -21,8 +21,8 @@ impl<E, T> Default for SignalEmitter<E, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Signal<'a, E, T> {
|
pub struct Signal<'a, T> {
|
||||||
just_connected: &'a RefCell<Vec<SignalHandlerBox<E, T>>>,
|
just_connected: &'a RefCell<Vec<SignalHandlerBox<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -40,19 +40,19 @@ impl SignalHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, T> Signal<'_, E, T> {
|
impl<T> Signal<'_, T> {
|
||||||
fn connect_impl(&self, f: impl FnMut(&E, T) -> bool + 'static) {
|
fn connect_impl(&self, f: impl FnMut(T) -> bool + 'static) {
|
||||||
self.just_connected.borrow_mut().push(Box::new(f));
|
self.just_connected.borrow_mut().push(Box::new(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(&self, mut f: impl FnMut(&E, T) -> bool + 'static) -> SignalHandler {
|
pub fn connect(&self, mut f: impl FnMut(T) -> bool + 'static) -> SignalHandler {
|
||||||
let disconnect = Rc::new(Cell::new(false));
|
let disconnect = Rc::new(Cell::new(false));
|
||||||
let disconnect_weak = Rc::downgrade(&disconnect);
|
let disconnect_weak = Rc::downgrade(&disconnect);
|
||||||
|
|
||||||
self.connect_impl(move |e, t| match disconnect.get() {
|
self.connect_impl(move |t| match disconnect.get() {
|
||||||
true => false,
|
false => false,
|
||||||
false => {
|
true => {
|
||||||
f(e, t);
|
f(t);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -63,38 +63,38 @@ impl<E, T> Signal<'_, E, T> {
|
||||||
pub fn connect_rc<L: 'static>(
|
pub fn connect_rc<L: 'static>(
|
||||||
&self,
|
&self,
|
||||||
listener: &Rc<L>,
|
listener: &Rc<L>,
|
||||||
mut f: impl FnMut(&E, Rc<L>, T) -> bool + 'static,
|
mut f: impl FnMut(Rc<L>, T) -> bool + 'static,
|
||||||
) -> SignalHandler {
|
) -> SignalHandler {
|
||||||
let listener = Rc::downgrade(listener);
|
let listener = Rc::downgrade(listener);
|
||||||
|
|
||||||
self.connect(move |e, t| match listener.upgrade() {
|
self.connect(move |t| match listener.upgrade() {
|
||||||
None => false,
|
None => false,
|
||||||
Some(listener) => f(e, listener, t),
|
Some(listener) => f(listener, t),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_object<L: IsA<Object>>(
|
pub fn connect_object<L: IsA<Object>>(
|
||||||
&self,
|
&self,
|
||||||
listener: &L,
|
listener: &L,
|
||||||
mut f: impl FnMut(&E, L, T) -> bool + 'static,
|
mut f: impl FnMut(L, T) -> bool + 'static,
|
||||||
) -> SignalHandler {
|
) -> SignalHandler {
|
||||||
let listener = listener.downgrade();
|
let listener = listener.downgrade();
|
||||||
|
|
||||||
self.connect(move |e, t| match listener.upgrade() {
|
self.connect(move |t| match listener.upgrade() {
|
||||||
None => false,
|
None => false,
|
||||||
Some(listener) => f(e, listener, t),
|
Some(listener) => f(listener, t),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, T> SignalEmitter<E, T> {
|
impl<T> SignalEmitter<T> {
|
||||||
pub fn signal(&self) -> Signal<'_, E, T> {
|
pub fn signal(&self) -> Signal<'_, T> {
|
||||||
Signal {
|
Signal {
|
||||||
just_connected: &self.just_connected,
|
just_connected: &self.just_connected,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_with(&self, emitter: &E, mut f: impl FnMut() -> T) {
|
pub fn emit_with(&self, mut f: impl FnMut() -> T) {
|
||||||
let mut handlers = self
|
let mut handlers = self
|
||||||
.handlers
|
.handlers
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
|
@ -108,7 +108,7 @@ impl<E, T> SignalEmitter<E, T> {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut skip = 0;
|
let mut skip = 0;
|
||||||
loop {
|
loop {
|
||||||
if handlers[i + skip](emitter, f()) {
|
if handlers[i + skip](f()) {
|
||||||
i += 1;
|
i += 1;
|
||||||
} else {
|
} else {
|
||||||
skip += 1;
|
skip += 1;
|
||||||
|
@ -121,16 +121,15 @@ impl<E, T> SignalEmitter<E, T> {
|
||||||
handlers.swap(i, i + skip);
|
handlers.swap(i, i + skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("emitted to {i} listeners");
|
|
||||||
handlers.truncate(i);
|
handlers.truncate(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, T> SignalEmitter<E, T>
|
impl<T> SignalEmitter<T>
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Clone,
|
||||||
{
|
{
|
||||||
pub fn emit(&self, emitter: &E, t: T) {
|
pub fn emit(&self, t: T) {
|
||||||
self.emit_with(emitter, || t.clone());
|
self.emit_with(|| t.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
pub mod schema;
|
mod schema;
|
||||||
|
|
||||||
use md5::Digest;
|
use md5::Digest;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
@ -145,22 +145,17 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn url(&self, path: &[&str], query: &[(&str, &str)]) -> url::Url {
|
|
||||||
let mut url = self.base_url.clone();
|
|
||||||
url.path_segments_mut()
|
|
||||||
// literally can't fail
|
|
||||||
.unwrap_or_else(|_| unsafe { std::hint::unreachable_unchecked() })
|
|
||||||
.extend(path);
|
|
||||||
url.query_pairs_mut().extend_pairs(query);
|
|
||||||
url
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get<T: serde::de::DeserializeOwned + Send + 'static>(
|
async fn get<T: serde::de::DeserializeOwned + Send + 'static>(
|
||||||
&self,
|
&self,
|
||||||
path: &[&str],
|
path: &[&str],
|
||||||
query: &[(&str, &str)],
|
query: &[(&str, &str)],
|
||||||
) -> Result<T, Error> {
|
) -> Result<T, Error> {
|
||||||
self.send(self.client.get(self.url(path, query))).await
|
let mut url = self.base_url.clone();
|
||||||
|
url.path_segments_mut()
|
||||||
|
// literally can't fail
|
||||||
|
.unwrap_or_else(|_| unsafe { std::hint::unreachable_unchecked() })
|
||||||
|
.extend(path);
|
||||||
|
self.send(self.client.get(url).query(query)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ping(&self) -> Result<(), Error> {
|
pub async fn ping(&self) -> Result<(), Error> {
|
||||||
|
@ -175,10 +170,6 @@ impl Client {
|
||||||
.await
|
.await
|
||||||
.map(|response| response.random_songs.song)
|
.map(|response| response.random_songs.song)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stream_url(&self, id: &str) -> url::Url {
|
|
||||||
self.url(&["rest", "stream"], &[("id", id)])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Client {
|
impl Drop for Client {
|
||||||
|
|
|
@ -21,8 +21,6 @@ mod imp {
|
||||||
|
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
volume: Cell<i32>,
|
volume: Cell<i32>,
|
||||||
#[property(get, set)]
|
|
||||||
mute: Cell<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -158,7 +156,8 @@ mod imp {
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn on_mute_toggle(&self) {
|
fn on_mute_toggle(&self) {
|
||||||
self.obj().set_mute(!self.obj().mute());
|
let playbin = self.playbin.upgrade().unwrap();
|
||||||
|
playbin.set_mute(!playbin.mute());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
mod imp {
|
mod imp {
|
||||||
use crate::signal::SignalEmitter;
|
|
||||||
use adw::{glib, prelude::*, subclass::prelude::*};
|
use adw::{glib, prelude::*, subclass::prelude::*};
|
||||||
use glib::subclass::{InitializingObject, Signal};
|
use glib::subclass::{InitializingObject, Signal};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||||
|
@ -24,8 +22,6 @@ mod imp {
|
||||||
username: RefCell<String>,
|
username: RefCell<String>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
password: RefCell<String>,
|
password: RefCell<String>,
|
||||||
|
|
||||||
pub(super) connected: SignalEmitter<super::Setup, Rc<crate::subsonic::Client>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -149,7 +145,6 @@ mod imp {
|
||||||
self.obj().set_authn_can_edit(true);
|
self.obj().set_authn_can_edit(true);
|
||||||
|
|
||||||
self.obj().emit_by_name::<()>("connected", &[&vala_api]);
|
self.obj().emit_by_name::<()>("connected", &[&vala_api]);
|
||||||
self.connected.emit(self.obj().as_ref(), Rc::new(api));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,10 +170,6 @@ impl Default for Setup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::signal::Signal;
|
|
||||||
use crate::subsonic;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
impl Setup {
|
impl Setup {
|
||||||
pub fn load(&self) {
|
pub fn load(&self) {
|
||||||
glib::spawn_future_local(glib::clone!(
|
glib::spawn_future_local(glib::clone!(
|
||||||
|
@ -218,10 +209,6 @@ impl Setup {
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connected(&self) -> Signal<'_, super::Setup, Rc<subsonic::Client>> {
|
|
||||||
self.imp().connected.signal()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod ffi {
|
mod ffi {
|
||||||
|
|
118
src/ui/window.rs
118
src/ui/window.rs
|
@ -26,9 +26,9 @@ mod imp {
|
||||||
song: RefCell<Option<crate::playbin::Song>>,
|
song: RefCell<Option<crate::playbin::Song>>,
|
||||||
|
|
||||||
pub(super) setup: crate::ui::Setup,
|
pub(super) setup: crate::ui::Setup,
|
||||||
|
pub(super) api: RefCell<Option<crate::subsonic_vala::Client>>,
|
||||||
|
|
||||||
pub(super) playbin2: Rc<crate::playbin2::Playbin<url::Url>>,
|
playbin2: Rc<crate::playbin2::Playbin<url::Url>>,
|
||||||
pub(super) api2: RefCell<Option<Rc<crate::subsonic::Client>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -52,6 +52,13 @@ mod imp {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
|
|
||||||
|
self.playbin2.tick();
|
||||||
|
self.playbin2.push_entry(
|
||||||
|
"https://www.youtube.com/watch?v=19y8YTbvri8"
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
let playbin = Rc::downgrade(&self.playbin2);
|
let playbin = Rc::downgrade(&self.playbin2);
|
||||||
glib::spawn_future_local(glib::clone!(async move {
|
glib::spawn_future_local(glib::clone!(async move {
|
||||||
loop {
|
loop {
|
||||||
|
@ -121,15 +128,22 @@ mod imp {
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
async fn shuffle_all(&self) {
|
async fn shuffle_all(&self) {
|
||||||
self.obj().set_can_click_shuffle_all(false);
|
/*
|
||||||
self.playbin2.stop();
|
this.can_click_shuffle_all = false;
|
||||||
let api = self.api2.borrow();
|
this.playbin.clear ();
|
||||||
let api = api.as_ref().unwrap();
|
api.get_random_songs.begin (null, (song) => {
|
||||||
for song in api.get_random_songs(10).await.unwrap().into_iter() {
|
this.playbin.append_track (song);
|
||||||
println!("{song:?}");
|
}, (obj, res) => {
|
||||||
self.playbin2.push_entry(api.stream_url(&song.id));
|
try {
|
||||||
}
|
api.get_random_songs.end (res);
|
||||||
self.obj().set_can_click_shuffle_all(true);
|
} catch (Error e) {
|
||||||
|
error ("could not get random songs: %s", e.message);
|
||||||
|
}
|
||||||
|
this.can_click_shuffle_all = true;
|
||||||
|
|
||||||
|
this.playbin.select_track (0);
|
||||||
|
});*/
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
@ -188,61 +202,39 @@ impl Window {
|
||||||
pub fn new(app: &impl IsA<gtk::Application>) -> Self {
|
pub fn new(app: &impl IsA<gtk::Application>) -> Self {
|
||||||
let window: Self = glib::Object::builder().property("application", app).build();
|
let window: Self = glib::Object::builder().property("application", app).build();
|
||||||
|
|
||||||
// manual bidirectional sync
|
|
||||||
window.imp().playbar.set_volume(window.imp().playbin2.volume() as i32);
|
|
||||||
window.imp().playbin2.volume_changed().connect_object(
|
|
||||||
&*window.imp().playbar,
|
|
||||||
|playbin, playbar, ()| {
|
|
||||||
playbar.set_volume(playbin.volume() as i32);
|
|
||||||
true
|
|
||||||
},
|
|
||||||
);
|
|
||||||
window.imp().playbar.connect_notify_local(
|
|
||||||
Some("volume"),
|
|
||||||
glib::clone!(
|
|
||||||
#[weak(rename_to = playbin)]
|
|
||||||
window.imp().playbin2,
|
|
||||||
move |playbar, _| playbin.set_volume(playbar.volume() as i64)
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
window.imp().playbar.set_mute(window.imp().playbin2.muted());
|
|
||||||
window.imp().playbin2.muted_changed().connect_object(
|
|
||||||
&*window.imp().playbar,
|
|
||||||
|playbin, playbar, ()| {
|
|
||||||
playbar.set_mute(playbin.muted());
|
|
||||||
true
|
|
||||||
},
|
|
||||||
);
|
|
||||||
window.imp().playbar.connect_notify_local(
|
|
||||||
Some("mute"),
|
|
||||||
glib::clone!(
|
|
||||||
#[weak(rename_to = playbin)]
|
|
||||||
window.imp().playbin2,
|
|
||||||
move |playbar, _| playbin.set_muted(playbar.mute())
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
window
|
window
|
||||||
.imp()
|
.playbin()
|
||||||
.setup
|
.bind_property("volume", &*window.imp().playbar, "volume")
|
||||||
.connected()
|
.bidirectional()
|
||||||
.connect_object(&window, |_setup, window, api| {
|
.sync_create()
|
||||||
window.imp().api2.replace(Some(api));
|
.build();
|
||||||
window.imp().playbin2.stop();
|
|
||||||
window.set_can_click_shuffle_all(true);
|
window.imp().setup.connect_closure(
|
||||||
true
|
"connected",
|
||||||
});
|
false,
|
||||||
|
glib::closure_local!(
|
||||||
|
#[weak]
|
||||||
|
window,
|
||||||
|
move |_setup: crate::ui::Setup, api: crate::subsonic_vala::Client| {
|
||||||
|
window.imp().api.replace(Some(api.clone()));
|
||||||
|
window.playbin().set_api(&api);
|
||||||
|
window.set_can_click_shuffle_all(true);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
window.imp().setup.load();
|
window.imp().setup.load();
|
||||||
|
|
||||||
window
|
window.playbin().connect_closure(
|
||||||
.imp()
|
"new-track",
|
||||||
.playbin2
|
false,
|
||||||
.file_started()
|
glib::closure_local!(
|
||||||
.connect_object(&window, |_playbin, _window, ()| {
|
#[weak]
|
||||||
// TODO window.imp().now_playing(song);
|
window,
|
||||||
true
|
move |_playbin: crate::Playbin, song: crate::playbin::Song| {
|
||||||
});
|
window.imp().now_playing(&song);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
window.playbin().connect_closure(
|
window.playbin().connect_closure(
|
||||||
"stopped",
|
"stopped",
|
||||||
|
|
Loading…
Reference in a new issue