add wrapper class for api client
This commit is contained in:
parent
a249a00120
commit
8c61f7545b
8 changed files with 87 additions and 53 deletions
|
@ -41,24 +41,28 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
|
|||
child: Box {
|
||||
orientation: vertical;
|
||||
|
||||
$AudreyUiAlbumCarousel carousel1 {
|
||||
$AudreyUiAlbumCarousel {
|
||||
title: _("Explore from your library");
|
||||
type: random;
|
||||
client: bind template.client;
|
||||
}
|
||||
|
||||
$AudreyUiAlbumCarousel carousel2 {
|
||||
$AudreyUiAlbumCarousel {
|
||||
title: _("Newly added releases");
|
||||
type: newest;
|
||||
client: bind template.client;
|
||||
}
|
||||
|
||||
$AudreyUiAlbumCarousel carousel3 {
|
||||
$AudreyUiAlbumCarousel {
|
||||
title: _("Recently played");
|
||||
type: recent;
|
||||
client: bind template.client;
|
||||
}
|
||||
|
||||
$AudreyUiAlbumCarousel carousel4 {
|
||||
$AudreyUiAlbumCarousel {
|
||||
title: _("Most played");
|
||||
type: frequent;
|
||||
client: bind template.client;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -18,6 +18,7 @@ use gtk::{gio, glib};
|
|||
pub mod mpv;
|
||||
|
||||
pub mod util;
|
||||
pub mod wrappers;
|
||||
|
||||
fn init_tracing() {
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
|
@ -74,8 +74,7 @@ glib::wrapper! {
|
|||
}
|
||||
|
||||
impl Song {
|
||||
pub fn from_child(window: &crate::ui::Window, song: &subsonic::schema::Child) -> Self {
|
||||
let api = window.api();
|
||||
pub fn from_child(client: &crate::wrappers::Client, song: &subsonic::schema::Child) -> Self {
|
||||
let song: Self = Object::builder()
|
||||
.property("id", &song.id)
|
||||
.property("title", &song.title)
|
||||
|
@ -84,20 +83,20 @@ impl Song {
|
|||
.property("genre", &song.genre)
|
||||
.property("duration", song.duration as i64)
|
||||
.property("track", song.track.map(i64::from).unwrap_or(-1))
|
||||
.property("stream-url", api.stream_url(&song.id).as_str())
|
||||
.property("stream-url", client.stream_url(&song.id).as_str())
|
||||
.property("cover-art", &song.cover_art)
|
||||
.build();
|
||||
|
||||
song
|
||||
}
|
||||
|
||||
pub fn need_thumbnail(&self, window: &crate::ui::Window) {
|
||||
let api = window.api();
|
||||
pub fn need_thumbnail(&self, client: &crate::wrappers::Client, scale_factor: u32) {
|
||||
let api = client.clone();
|
||||
let mut thumbnail_loading = self.imp().thumbnail_loading.borrow_mut();
|
||||
if thumbnail_loading.is_none() {
|
||||
let id = self.id();
|
||||
let song_weak = self.downgrade();
|
||||
let scale_factor = window.scale_factor() as u32; // NOTE: assumed constant
|
||||
let scale_factor = scale_factor; // NOTE: assumed constant
|
||||
*thumbnail_loading = Some(glib::spawn_future_local(async move {
|
||||
let _permit = SEM.acquire().await.unwrap();
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ use adw::subclass::prelude::*;
|
|||
use adw::{gio, glib};
|
||||
use glib::subclass::InitializingObject;
|
||||
use std::cell::{Cell, OnceCell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::sync::OnceLock;
|
||||
use tracing::{event, Level};
|
||||
|
||||
|
@ -29,10 +28,10 @@ mod imp {
|
|||
#[derive(gtk::CompositeTemplate, Default)]
|
||||
#[template(resource = "/eu/callcc/audrey/album_carousel.ui")]
|
||||
pub struct AlbumCarousel {
|
||||
pub api: RefCell<Option<Rc<crate::subsonic::Client>>>,
|
||||
title: RefCell<String>,
|
||||
model: OnceCell<gio::ListStore>,
|
||||
r#type: Cell<Type>,
|
||||
client: RefCell<Option<crate::wrappers::Client>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
@ -61,6 +60,7 @@ mod imp {
|
|||
glib::ParamSpecObject::builder::<gio::ListModel>("model")
|
||||
.read_only()
|
||||
.build(),
|
||||
glib::ParamSpecObject::builder::<crate::wrappers::Client>("client").build(),
|
||||
]
|
||||
})
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ mod imp {
|
|||
1 => self.title.borrow().clone().into(),
|
||||
2 => self.r#type.get().into(),
|
||||
3 => self.model().into(),
|
||||
4 => self.client.borrow().clone().into(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +84,10 @@ mod imp {
|
|||
self.r#type.replace(value.get_owned().unwrap());
|
||||
self.update_model();
|
||||
}
|
||||
4 => {
|
||||
self.client.replace(value.get_owned().unwrap());
|
||||
self.update_model();
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -102,13 +107,13 @@ mod imp {
|
|||
pub fn update_model(&self) {
|
||||
self.model().remove_all();
|
||||
|
||||
let api = self.api.borrow();
|
||||
let api = self.client.borrow();
|
||||
let api = match api.as_ref() {
|
||||
Some(api) => api,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let api = Rc::clone(&api);
|
||||
let api = api.clone();
|
||||
let carousel = self.obj().downgrade();
|
||||
|
||||
let type_ = match self.r#type.get() {
|
||||
|
@ -145,10 +150,3 @@ glib::wrapper! {
|
|||
@extends adw::Bin, gtk::Widget,
|
||||
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
impl AlbumCarousel {
|
||||
pub fn set_api(&self, api: Option<&Rc<crate::subsonic::Client>>) {
|
||||
self.imp().api.replace(api.map(Rc::clone));
|
||||
self.imp().update_model();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,7 +200,10 @@ impl Song {
|
|||
self.set_position(position);
|
||||
self.set_playlist_pos(window.playlist_pos());
|
||||
|
||||
song.need_thumbnail(window);
|
||||
song.need_thumbnail(
|
||||
window.client().as_ref().unwrap(),
|
||||
window.scale_factor() as u32,
|
||||
);
|
||||
}
|
||||
|
||||
pub const fn unbind(&self) {}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::model::Song;
|
||||
use crate::ui::AlbumCarousel;
|
||||
use crate::util::buffering::BufferingPulseController;
|
||||
use crate::{mpris, mpv};
|
||||
use adw::prelude::*;
|
||||
|
@ -49,7 +48,8 @@ mod imp {
|
|||
|
||||
pub(super) setup: crate::ui::Setup,
|
||||
|
||||
pub(super) api: RefCell<Option<Rc<crate::subsonic::Client>>>,
|
||||
#[property(get, set, nullable)]
|
||||
pub client: RefCell<Option<crate::wrappers::Client>>,
|
||||
|
||||
pub(super) mpv: mpv::Handle,
|
||||
#[property(get)]
|
||||
|
@ -91,15 +91,6 @@ mod imp {
|
|||
refreshing_albums: Cell<bool>,
|
||||
|
||||
css_provider: gtk::CssProvider,
|
||||
|
||||
#[template_child]
|
||||
pub carousel1: TemplateChild<AlbumCarousel>,
|
||||
#[template_child]
|
||||
pub carousel2: TemplateChild<AlbumCarousel>,
|
||||
#[template_child]
|
||||
pub carousel3: TemplateChild<AlbumCarousel>,
|
||||
#[template_child]
|
||||
pub carousel4: TemplateChild<AlbumCarousel>,
|
||||
}
|
||||
|
||||
impl Default for Window {
|
||||
|
@ -131,7 +122,7 @@ mod imp {
|
|||
background: Default::default(),
|
||||
_song: (),
|
||||
setup: Default::default(),
|
||||
api: Default::default(),
|
||||
client: Default::default(),
|
||||
mpv,
|
||||
|
||||
playlist_model: gio::ListStore::new::<Song>(),
|
||||
|
@ -162,11 +153,6 @@ mod imp {
|
|||
refreshing_albums: Cell::new(true),
|
||||
|
||||
css_provider: gtk::CssProvider::new(),
|
||||
|
||||
carousel1: Default::default(),
|
||||
carousel2: Default::default(),
|
||||
carousel3: Default::default(),
|
||||
carousel4: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,11 +402,11 @@ mod imp {
|
|||
self.set_pause(false);
|
||||
|
||||
let api = {
|
||||
let api = self.api.borrow();
|
||||
Rc::clone(api.as_ref().unwrap())
|
||||
let api = self.client.borrow();
|
||||
api.as_ref().unwrap().clone()
|
||||
};
|
||||
for song in api.random_songs(50).await.unwrap().into_iter() {
|
||||
let song = Song::from_child(&self.obj(), &song);
|
||||
let song = Song::from_child(&api, &song);
|
||||
self.mpv
|
||||
.command(["loadfile", &song.stream_url(), "append-play"])
|
||||
.unwrap();
|
||||
|
@ -757,7 +743,7 @@ mod imp {
|
|||
if let Some(handle) = self
|
||||
.loading_cover_handle
|
||||
.replace(Some(glib::spawn_future_local(async move {
|
||||
let api = window.imp().api.borrow().as_ref().unwrap().clone();
|
||||
let api = window.imp().client.borrow().as_ref().unwrap().clone();
|
||||
let image = match api
|
||||
.cover_art(&song_id, Some(800 * scale_factor)) // 800px times ui scale
|
||||
.await
|
||||
|
@ -1032,14 +1018,15 @@ impl Window {
|
|||
|
||||
self.set_can_click_shuffle_all(true);
|
||||
|
||||
self.imp().carousel1.set_api(Some(&api));
|
||||
self.imp().carousel2.set_api(Some(&api));
|
||||
self.imp().carousel3.set_api(Some(&api));
|
||||
self.imp().carousel4.set_api(Some(&api));
|
||||
|
||||
if self.imp().api.replace(Some(api)).is_some() {
|
||||
if self
|
||||
.imp()
|
||||
.client
|
||||
.replace(Some(crate::wrappers::Client::new((*api).clone())))
|
||||
.is_some()
|
||||
{
|
||||
unimplemented!("changing the api object");
|
||||
}
|
||||
self.notify("client");
|
||||
}
|
||||
|
||||
pub fn playlist_next(&self) {
|
||||
|
@ -1153,8 +1140,4 @@ impl Window {
|
|||
self.imp().mpv.command(["stop"]).unwrap();
|
||||
self.playlist_model().remove_all();
|
||||
}
|
||||
|
||||
pub fn api(&self) -> Rc<crate::subsonic::Client> {
|
||||
Rc::clone(self.imp().api.borrow().as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
2
src/wrappers.rs
Normal file
2
src/wrappers.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod client;
|
||||
pub use client::Client;
|
44
src/wrappers/client.rs
Normal file
44
src/wrappers/client.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
// simple wrapper class so we can use the client object as a glib property
|
||||
|
||||
use crate::subsonic;
|
||||
use glib::subclass::prelude::*;
|
||||
use std::cell::OnceCell;
|
||||
use std::ops::Deref;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Client(pub OnceCell<subsonic::Client>);
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for Client {
|
||||
const NAME: &'static str = "AudreyClient";
|
||||
type Type = super::Client;
|
||||
}
|
||||
|
||||
impl ObjectImpl for Client {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct Client(ObjectSubclass<imp::Client>);
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(inner: subsonic::Client) -> Self {
|
||||
let client: Self = glib::Object::new();
|
||||
client.imp().0.set(inner).map_err(|_| ()).unwrap();
|
||||
client
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Client {
|
||||
type Target = subsonic::Client;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.imp()
|
||||
.0
|
||||
.get()
|
||||
.expect("tried to deref uninitialized client object")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue