carousel thing
This commit is contained in:
parent
c43adb66eb
commit
a33fe4ba63
6 changed files with 106 additions and 31 deletions
|
@ -80,7 +80,7 @@ template $AudreyUiAlbumCarousel: Adw.Bin {
|
|||
homogeneous: true;
|
||||
|
||||
Label {
|
||||
label: bind template.item as <StringObject>.string;
|
||||
label: bind template.item as <$AudreyModelAlbum>.name;
|
||||
ellipsize: end;
|
||||
xalign: 0;
|
||||
margin-start: 6;
|
||||
|
@ -91,7 +91,7 @@ template $AudreyUiAlbumCarousel: Adw.Bin {
|
|||
}
|
||||
|
||||
Label {
|
||||
label: bind template.item as <StringObject>.string;
|
||||
label: bind template.item as <$AudreyModelAlbum>.artist;
|
||||
ellipsize: end;
|
||||
xalign: 0;
|
||||
margin-start: 6;
|
||||
|
|
|
@ -41,22 +41,22 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
|
|||
child: Box {
|
||||
orientation: vertical;
|
||||
|
||||
$AudreyUiAlbumCarousel {
|
||||
$AudreyUiAlbumCarousel carousel1 {
|
||||
title: _("Explore from your library");
|
||||
type: random;
|
||||
}
|
||||
|
||||
$AudreyUiAlbumCarousel {
|
||||
$AudreyUiAlbumCarousel carousel2 {
|
||||
title: _("Newly added releases");
|
||||
type: newest;
|
||||
}
|
||||
|
||||
$AudreyUiAlbumCarousel {
|
||||
$AudreyUiAlbumCarousel carousel3 {
|
||||
title: _("Recently played");
|
||||
type: recent;
|
||||
}
|
||||
|
||||
$AudreyUiAlbumCarousel {
|
||||
$AudreyUiAlbumCarousel carousel4 {
|
||||
title: _("Most played");
|
||||
type: frequent;
|
||||
}
|
||||
|
|
|
@ -30,3 +30,15 @@ mod imp {
|
|||
glib::wrapper! {
|
||||
pub struct Album(ObjectSubclass<imp::Album>);
|
||||
}
|
||||
|
||||
impl Album {
|
||||
pub fn from_api(album: &crate::subsonic::schema::AlbumID3) -> Self {
|
||||
let album: Self = glib::Object::builder()
|
||||
.property("id", &album.id)
|
||||
.property("name", &album.name)
|
||||
.property("artist", &album.artist)
|
||||
.build();
|
||||
|
||||
album
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,21 +22,24 @@ impl Client {
|
|||
size: u32,
|
||||
offset: u32,
|
||||
) -> Result<Vec<schema::AlbumID3>, Error> {
|
||||
match type_ {
|
||||
AlbumListType::Newest => {
|
||||
self.get_subsonic::<schema::AlbumList2Outer>(self.url(
|
||||
&["rest", "getAlbumList2"],
|
||||
&[
|
||||
("type", "newest"),
|
||||
("size", &size.to_string()),
|
||||
("offset", &offset.to_string()),
|
||||
],
|
||||
))
|
||||
.await
|
||||
}
|
||||
let type_ = match type_ {
|
||||
AlbumListType::Newest => "newest",
|
||||
AlbumListType::Random => "random",
|
||||
AlbumListType::Recent => "recent",
|
||||
AlbumListType::Frequent => "frequent",
|
||||
|
||||
_ => todo!("{type_:?}"),
|
||||
}
|
||||
};
|
||||
|
||||
self.get_subsonic::<schema::AlbumList2Outer>(self.url(
|
||||
&["rest", "getAlbumList2"],
|
||||
&[
|
||||
("type", type_),
|
||||
("size", &size.to_string()),
|
||||
("offset", &offset.to_string()),
|
||||
],
|
||||
))
|
||||
.await
|
||||
.map(|response| response.album_list2.album.unwrap_or_default())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use crate::subsonic::AlbumListType;
|
||||
use adw::prelude::*;
|
||||
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};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, glib::Enum)]
|
||||
#[enum_type(name = "AudreyUiAlbumCarouselType")]
|
||||
|
@ -26,6 +29,7 @@ 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>,
|
||||
|
@ -95,16 +99,43 @@ mod imp {
|
|||
.get_or_init(gio::ListStore::new::<crate::model::Album>)
|
||||
}
|
||||
|
||||
fn update_model(&self) {
|
||||
let window: crate::ui::Window = match self.obj().root() {
|
||||
None => return,
|
||||
Some(root) => root.dynamic_cast().unwrap(),
|
||||
};
|
||||
let _api = window.api();
|
||||
pub fn update_model(&self) {
|
||||
self.model().remove_all();
|
||||
|
||||
match self.r#type.get() {
|
||||
_ => todo!(),
|
||||
}
|
||||
let api = self.api.borrow();
|
||||
let api = match api.as_ref() {
|
||||
Some(api) => api,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let api = Rc::clone(&api);
|
||||
let carousel = self.obj().downgrade();
|
||||
|
||||
let type_ = match self.r#type.get() {
|
||||
Type::Random => AlbumListType::Random,
|
||||
Type::Newest => AlbumListType::Newest,
|
||||
Type::Recent => AlbumListType::Recent,
|
||||
Type::Frequent => AlbumListType::Frequent,
|
||||
};
|
||||
|
||||
glib::spawn_future_local(async move {
|
||||
let album_list = match api.album_list(&type_, 50, 0).await {
|
||||
Ok(album_list) => album_list,
|
||||
Err(err) => {
|
||||
event!(Level::ERROR, "could not fetch albums for carousel: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: handle to cancel on drop etc etc
|
||||
let carousel = carousel.upgrade().unwrap();
|
||||
for album in album_list {
|
||||
carousel
|
||||
.imp()
|
||||
.model()
|
||||
.append(&crate::model::Album::from_api(&album));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,3 +145,10 @@ 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::model::Song;
|
||||
use crate::ui::AlbumCarousel;
|
||||
use crate::util::buffering::BufferingPulseController;
|
||||
use crate::{mpris, mpv};
|
||||
use adw::prelude::*;
|
||||
|
@ -90,6 +91,15 @@ 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 {
|
||||
|
@ -152,6 +162,11 @@ mod imp {
|
|||
refreshing_albums: Cell::new(true),
|
||||
|
||||
css_provider: gtk::CssProvider::new(),
|
||||
|
||||
carousel1: Default::default(),
|
||||
carousel2: Default::default(),
|
||||
carousel3: Default::default(),
|
||||
carousel4: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1011,11 +1026,18 @@ impl Window {
|
|||
}
|
||||
|
||||
pub fn setup_connected(&self, api: crate::subsonic::Client) {
|
||||
if self.imp().api.replace(Some(Rc::new(api))).is_some() {
|
||||
unimplemented!("changing the api object");
|
||||
}
|
||||
let api = Rc::new(api);
|
||||
|
||||
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() {
|
||||
unimplemented!("changing the api object");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn playlist_next(&self) {
|
||||
|
|
Loading…
Reference in a new issue