diff --git a/src/playbin.vala b/src/playbin.vala index 1097669..e69de29 100644 --- a/src/playbin.vala +++ b/src/playbin.vala @@ -1,21 +0,0 @@ -public class Audrey.PlaybinSong : Object { - private static int64 next_counter = 0; - public int64 counter { get; private set; } - - public string id { get; set; } - public string title { get; set; } - public string artist { get; set; } - public string album { get; set; } - public string? genre { get; set; } - public int64 duration { get; set; } - public int64 track { get; set; } - public int64 play_count { get; set; } - - public string cover_art_url { get; set; } - public string stream_url { get; set; } - - construct { - this.counter = next_counter; - next_counter += 1; - } -} diff --git a/src/playbin_song.rs b/src/playbin_song.rs index 3f154f0..f6a94a0 100644 --- a/src/playbin_song.rs +++ b/src/playbin_song.rs @@ -1,106 +1,81 @@ -pub mod ffi { +mod imp { + use adw::prelude::*; use gtk::glib; - use std::ffi::c_char; + use gtk::subclass::prelude::*; + use std::cell::{Cell, RefCell}; - #[repr(C)] - pub struct AudreyPlaybinSong { - _data: [u8; 0], + static NEXT_COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); + + #[derive(glib::Properties, Default)] + #[properties(wrapper_type = super::Song)] + pub struct Song { + #[property(get, set)] + counter: Cell, + + #[property(get, set)] + id: RefCell, + #[property(get, set)] + title: RefCell, + #[property(get, set)] + artist: RefCell, + #[property(get, set)] + album: RefCell, + #[property(get, set)] + genre: RefCell>, + #[property(get, set)] + duration: Cell, + #[property(get, set)] + track: Cell, + + #[property(get, set)] + cover_art_url: RefCell, + #[property(get, set)] + stream_url: RefCell, } - #[repr(C)] - pub struct AudreyPlaybinSongClass { - _data: [u8; 0], + #[glib::object_subclass] + impl ObjectSubclass for Song { + const NAME: &'static str = "AudreyPlaybinSong"; + type Type = super::Song; } - extern "C" { - pub fn audrey_playbin_song_get_type() -> glib::ffi::GType; - pub fn audrey_playbin_song_get_counter(self_: *mut AudreyPlaybinSong) -> i64; - pub fn audrey_playbin_song_get_id(self_: *mut AudreyPlaybinSong) -> *const c_char; - pub fn audrey_playbin_song_get_title(self_: *mut AudreyPlaybinSong) -> *const c_char; - pub fn audrey_playbin_song_get_artist(self_: *mut AudreyPlaybinSong) -> *const c_char; - pub fn audrey_playbin_song_get_album(self_: *mut AudreyPlaybinSong) -> *const c_char; - pub fn audrey_playbin_song_get_duration(self_: *mut AudreyPlaybinSong) -> i64; + #[glib::derived_properties] + impl ObjectImpl for Song { + fn constructed(&self) { + self.parent_constructed(); - pub fn audrey_playbin_song_get_cover_art_url( - self_: *mut AudreyPlaybinSong, - ) -> *const c_char; - pub fn audrey_playbin_song_get_stream_url(self_: *mut AudreyPlaybinSong) -> *const c_char; + self.obj() + .set_counter(NEXT_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); + } } } -use glib::translate::{from_glib_none, ToGlibPtr}; -use glib::GString; +use crate::subsonic; +use glib::Object; use gtk::glib; glib::wrapper! { - pub struct Song(Object); - - match fn { - type_ => || ffi::audrey_playbin_song_get_type(), - } + pub struct Song(ObjectSubclass); } impl Song { - pub fn counter(&self) -> i64 { - unsafe { ffi::audrey_playbin_song_get_counter(self.to_glib_none().0) } - } - - pub fn id(&self) -> GString { - unsafe { from_glib_none(ffi::audrey_playbin_song_get_id(self.to_glib_none().0)) } - } - - pub fn title(&self) -> GString { - unsafe { from_glib_none(ffi::audrey_playbin_song_get_title(self.to_glib_none().0)) } - } - - pub fn artist(&self) -> GString { - unsafe { from_glib_none(ffi::audrey_playbin_song_get_artist(self.to_glib_none().0)) } - } - - pub fn album(&self) -> GString { - unsafe { from_glib_none(ffi::audrey_playbin_song_get_album(self.to_glib_none().0)) } - } - - pub fn duration(&self) -> i64 { - unsafe { ffi::audrey_playbin_song_get_duration(self.to_glib_none().0) } - } - - pub fn cover_art_url(&self) -> url::Url { - let url: String = unsafe { - from_glib_none(ffi::audrey_playbin_song_get_cover_art_url( - self.to_glib_none().0, - )) - }; - url::Url::parse(&url).expect("invalid url from vala side") - } - - pub fn stream_url(&self) -> url::Url { - let url: String = unsafe { - from_glib_none(ffi::audrey_playbin_song_get_stream_url( - self.to_glib_none().0, - )) - }; - url::Url::parse(&url).expect("invalid url from vala side") - } - - pub fn from_child( - api: &crate::subsonic::Client, - child: &crate::subsonic::schema::Child, - ) -> Self { - glib::Object::builder() - .property("id", &child.id) - .property("title", &child.title) - .property("artist", &child.artist) - .property("album", &child.album) - .property("duration", child.duration as i64) - .property("cover-art-url", api.cover_art_url(&child.id).as_str()) - .property("stream-url", api.stream_url(&child.id).as_str()) + pub fn from_child(api: &subsonic::Client, song: &subsonic::schema::Child) -> Self { + Object::builder() + .property("id", &song.id) + .property("title", &song.title) + .property("artist", &song.artist) + .property("album", &song.album) + .property("genre", &song.genre) + .property("duration", song.duration as i64) + //.property("track", song.track) + .property("cover-art-url", api.cover_art_url(&song.id).as_str()) + .property("stream-url", api.stream_url(&song.id).as_str()) .build() } } impl crate::playbin::PlaybinEntry for Song { fn url(&self) -> url::Url { - self.stream_url() + url::Url::parse(&self.stream_url()).unwrap() } } diff --git a/src/subsonic/schema.rs b/src/subsonic/schema.rs index 22b90dd..e36c134 100644 --- a/src/subsonic/schema.rs +++ b/src/subsonic/schema.rs @@ -47,7 +47,7 @@ pub struct Child { pub starred: Option>, // TODO: check which is best // applicable pub duration: u64, - pub play_count: Option, + //pub play_count: Option, pub genre: Option, pub cover_art: String, } diff --git a/src/ui/playbar.rs b/src/ui/playbar.rs index 4c88c8e..8a75b49 100644 --- a/src/ui/playbar.rs +++ b/src/ui/playbar.rs @@ -54,23 +54,23 @@ mod imp { #[gtk::template_callbacks] impl Playbar { #[template_callback] - fn song_title(&self, song: Option<&PlaybinSong>) -> Option { + fn song_title(&self, song: Option<&PlaybinSong>) -> Option { song.map(|song| song.title()) } #[template_callback] - fn song_artist(&self, song: Option<&PlaybinSong>) -> Option { + fn song_artist(&self, song: Option<&PlaybinSong>) -> Option { song.map(|song| song.artist()) } #[template_callback] - fn song_album(&self, song: Option<&PlaybinSong>) -> Option { + fn song_album(&self, song: Option<&PlaybinSong>) -> Option { song.map(|song| song.album()) } #[template_callback] - fn format_timestamp(&self, s: f64) -> GString { - gformat!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60) + fn format_timestamp(&self, s: f64) -> String { + format!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60) } #[template_callback]