diff --git a/resources/window.blp b/resources/window.blp index a264e91..0119b8e 100644 --- a/resources/window.blp +++ b/resources/window.blp @@ -136,6 +136,8 @@ template $AudreyUiWindow: Adw.ApplicationWindow { volume: bind template.volume bidirectional; mute: bind template.mute bidirectional; pause: bind template.pause bidirectional; + position: bind template.time-pos; + duration: bind template.song as <$AudreyPlaybinSong>.duration; } } } diff --git a/src/mpv/error.rs b/src/mpv/error.rs index eb7c604..bb6bc0e 100644 --- a/src/mpv/error.rs +++ b/src/mpv/error.rs @@ -19,6 +19,10 @@ impl Error { .to_str() .unwrap() } + + pub fn is_property_unavailable(self) -> bool { + self.0 == ffi::mpv_error_MPV_ERROR_PROPERTY_UNAVAILABLE + } } impl fmt::Display for Error { diff --git a/src/ui/play_queue.rs b/src/ui/play_queue.rs index a7f873d..78adbf3 100644 --- a/src/ui/play_queue.rs +++ b/src/ui/play_queue.rs @@ -2,11 +2,9 @@ pub mod song; pub use song::Song; mod imp { - use crate::{Playbin, PlaybinSong}; use adw::{gio, glib, prelude::*, subclass::prelude::*}; use glib::{subclass::InitializingObject, WeakRef}; - use std::cell::{Cell, RefCell}; - use std::rc::Rc; + use std::cell::Cell; use tracing::{event, Level}; #[derive(gtk::CompositeTemplate, glib::Properties, Default)] @@ -100,11 +98,8 @@ mod imp { } } -use crate::Playbin; use adw::prelude::*; -use adw::subclass::prelude::*; use gtk::glib; -use std::rc::Rc; glib::wrapper! { pub struct PlayQueue(ObjectSubclass) diff --git a/src/ui/play_queue/song.rs b/src/ui/play_queue/song.rs index ad1e9a5..46d4c69 100644 --- a/src/ui/play_queue/song.rs +++ b/src/ui/play_queue/song.rs @@ -172,8 +172,6 @@ mod imp { use crate::PlaybinSong; use adw::prelude::*; -use adw::subclass::prelude::*; -use glib::Object; use gtk::glib; glib::wrapper! { diff --git a/src/ui/playbar.rs b/src/ui/playbar.rs index 305eb12..d1fabf1 100644 --- a/src/ui/playbar.rs +++ b/src/ui/playbar.rs @@ -145,15 +145,7 @@ mod imp { #[template_callback] fn on_play_pause_clicked(&self, _button: >k::Button) { - /* - let playbin = self.playbin.upgrade().unwrap(); - - if playbin.state() == crate::playbin::State::Playing { - playbin.pause(); - } else { - playbin.play(); - }*/ - todo!() + self.window().set_pause(!self.window().pause()); } #[template_callback] diff --git a/src/ui/window.rs b/src/ui/window.rs index a037363..358e815 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -44,6 +44,8 @@ mod imp { _pause: (), #[property(type = i64, get = Self::playlist_pos)] _playlist_pos: (), + #[property(type = f64, get = Self::time_pos)] + _time_pos: (), } impl Default for Window { @@ -78,6 +80,7 @@ mod imp { _mute: (), _pause: (), _playlist_pos: (), + _time_pos: (), } } } @@ -135,7 +138,18 @@ mod imp { _ => unreachable!(), }, - mpv::Event::Hook(event) => match event.reply_userdata { + Event::StartFile(_) => { + let song: PlaybinSong = window + .playlist_model() + .item(window.playlist_pos() as u32) + .unwrap() + .dynamic_cast() + .unwrap(); + window.set_song(Some(&song)); + // TODO: load cover art + } + + Event::Hook(event) => match event.reply_userdata { 0 => { assert_eq!(&event.name, "on_before_start_file"); event!(Level::DEBUG, "on_before_start_file triggered"); @@ -182,7 +196,7 @@ mod imp { crate::mpris::Player::setup(conn.object_server(), &window.imp().playbin) .await .expect("could not serve mpris player"); - */ + FIXME */ drop(window); // don't keep this alive @@ -191,6 +205,19 @@ mod imp { .await .expect("could not register name in session bus"); }); + + // notify of new time-pos every 100 ms + glib::source::timeout_add_local(std::time::Duration::from_millis(100), { + let window = self.obj().downgrade(); + move || { + let window = match window.upgrade() { + None => return glib::ControlFlow::Break, + Some(window) => window, + }; + window.notify("time-pos"); + glib::ControlFlow::Continue + } + }); } } @@ -216,10 +243,12 @@ mod imp { self.mpv.command(["stop"]).unwrap(); self.playlist_model.remove_all(); - let api = self.api.borrow(); - let api = api.as_ref().unwrap(); + let api = { + let api = self.api.borrow(); + Rc::clone(api.as_ref().unwrap()) + }; for song in api.get_random_songs(10).await.unwrap().into_iter() { - let song = PlaybinSong::from_child(api, &song); + let song = PlaybinSong::from_child(&api, &song); self.mpv .command(["loadfile", &song.stream_url(), "append-play"]) .unwrap(); @@ -233,35 +262,6 @@ mod imp { self.setup.present(Some(self.obj().as_ref())); } - pub(super) fn now_playing(&self, _song: &PlaybinSong) { - /* - this.song = song; - // api.scrobble.begin (this.song.id); TODO - - if (this.cancel_loading_art != null) { - this.cancel_loading_art.cancel (); - } - this.cancel_loading_art = new GLib.Cancellable (); - - this.playing_cover_art = null; // TODO: preload next art somehow - this.cover_art_loading = true; - - string song_id = this.song.id; - this.api.cover_art.begin (song_id, -1, Priority.DEFAULT, this.cancel_loading_art, (obj, res) => { - try { - this.playing_cover_art = Gdk.Texture.for_pixbuf (this.api.cover_art.end (res)); - this.cover_art_loading = false; - } catch (Error e) { - if (!(e is IOError.CANCELLED)) { - warning ("could not load cover for %s: %s", song_id, e.message); - this.cover_art_loading = false; - } - } - }); - */ - todo!() - } - fn volume(&self) -> i64 { self.mpv.get_property("volume").unwrap() } @@ -289,6 +289,15 @@ mod imp { fn playlist_pos(&self) -> i64 { self.mpv.get_property("playlist-pos").unwrap() } + + fn time_pos(&self) -> f64 { + match self.mpv.get_property("time-pos") { + Ok(time_pos) => Ok(time_pos), + Err(err) if err.is_property_unavailable() => Ok(0.0), //placeholder + Err(err) => Err(err), + } + .unwrap() + } } impl Drop for Window { @@ -312,53 +321,6 @@ impl Window { pub fn new(app: &impl IsA) -> Self { let window: Self = glib::Object::builder().property("application", app).build(); - // manual bidirectional sync - /* - window - .imp() - .playbar - .set_volume(window.imp().mpv.get_property::("volume") as i32); - */ - - /* - window.imp().playbar.set_mute(window.imp().playbin.muted()); - window.imp().playbar.connect_notify_local( - Some("mute"), - glib::clone!( - #[weak(rename_to = playbin)] - window.imp().playbin, - move |playbar, _| playbin.set_muted(playbar.mute()) - ), - ); - - window.imp().playbin.file_started().connect_object( - &*window.imp().playbar, - |playbin, playbar, ()| { - let entry = &playbin.entries()[playbin.current_entry().unwrap()]; - playbar.set_duration(entry.duration() as f64); - true - }, - );*/ - - // update position every 100 ms - /* - glib::source::timeout_add_local(std::time::Duration::from_millis(100), { - let playbar = window.imp().playbar.downgrade(); - let playbin = Rc::downgrade(&window.imp().playbin); - move || { - let playbar = match playbar.upgrade() { - None => return glib::ControlFlow::Break, - Some(playbar) => playbar, - }; - let playbin = match playbin.upgrade() { - None => return glib::ControlFlow::Break, - Some(playbin) => playbin, - }; - playbar.set_position(playbin.position().unwrap_or(0.0)); - glib::ControlFlow::Continue - } - });*/ - window .imp() .setup @@ -371,18 +333,6 @@ impl Window { }); window.imp().setup.load(); - /* - window - .imp() - .playbin - .file_started() - .connect_object(&window, |playbin, window, ()| { - window - .imp() - .now_playing(&playbin.entries()[playbin.current_entry().unwrap()]); - true - });*/ - window }