albums list wip
This commit is contained in:
parent
1c4f694157
commit
f66262b95f
5 changed files with 92 additions and 56 deletions
|
@ -27,3 +27,11 @@
|
||||||
#play-queue .playing label.title {
|
#play-queue .playing label.title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gridview.albums child {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
gridview.albums child image {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
|
@ -83,7 +83,52 @@ template $AudreyUiWindow: Adw.ApplicationWindow {
|
||||||
ScrolledWindow {
|
ScrolledWindow {
|
||||||
vexpand: true;
|
vexpand: true;
|
||||||
|
|
||||||
GridView {}
|
GridView {
|
||||||
|
styles [ "albums" ]
|
||||||
|
single-click-activate: true;
|
||||||
|
|
||||||
|
model: NoSelection {
|
||||||
|
model: bind template.albums-model;
|
||||||
|
};
|
||||||
|
|
||||||
|
factory: BuilderListItemFactory {
|
||||||
|
template ListItem {
|
||||||
|
child: Box {
|
||||||
|
orientation: vertical;
|
||||||
|
margin-bottom: 6;
|
||||||
|
|
||||||
|
Image {
|
||||||
|
icon-name: "media-optical-cd";
|
||||||
|
pixel-size: 160;
|
||||||
|
halign: center;
|
||||||
|
hexpand: false;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"frame"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
label: bind template.item as <$AudreyModelAlbum>.name;
|
||||||
|
ellipsize: end;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"heading"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
label: bind template.item as <$AudreyModelAlbum>.artist;
|
||||||
|
ellipsize: end;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"caption"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
mod song;
|
mod song;
|
||||||
pub use song::Song;
|
pub use song::Song;
|
||||||
|
|
||||||
|
mod album;
|
||||||
|
pub use album::Album;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
mod imp {
|
mod imp {
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
|
use gtk::glib;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use gtk::{gdk, glib};
|
use std::cell::RefCell;
|
||||||
use std::cell::{Cell, RefCell};
|
|
||||||
|
|
||||||
#[derive(glib::Properties, Default)]
|
#[derive(glib::Properties, Default)]
|
||||||
#[properties(wrapper_type = super::Album)]
|
#[properties(wrapper_type = super::Album)]
|
||||||
|
@ -12,7 +12,7 @@ mod imp {
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
name: RefCell<String>,
|
name: RefCell<String>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
artist: RefCell<Option<String>>,
|
artist: RefCell<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -20,55 +20,13 @@ mod imp {
|
||||||
const NAME: &'static str = "AudreyModelAlbum";
|
const NAME: &'static str = "AudreyModelAlbum";
|
||||||
type Type = super::Album;
|
type Type = super::Album;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[glib::derived_properties]
|
||||||
|
impl ObjectImpl for Album {}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::subsonic;
|
use gtk::glib;
|
||||||
use adw::{prelude::*, subclass::prelude::*};
|
|
||||||
use glib::Object;
|
|
||||||
use gtk::{gdk, glib};
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct Album(ObjectSubclass<imp::Album>);
|
pub struct Album(ObjectSubclass<imp::Album>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Album {
|
|
||||||
pub fn from_api(
|
|
||||||
album: &subsonic::schema::Child,
|
|
||||||
load_thumbnail: bool,
|
|
||||||
) -> Self {
|
|
||||||
let album: Album = Object::builder()
|
|
||||||
.property("id", &album.id)
|
|
||||||
.property("title", &album.title)
|
|
||||||
.property("artist", &album.artist)
|
|
||||||
.property("album", &album.album)
|
|
||||||
.property("genre", &album.genre)
|
|
||||||
.property("duration", album.duration as i64)
|
|
||||||
.property("track", album.track.map(i64::from).unwrap_or(-1))
|
|
||||||
.property("stream-url", api.stream_url(&album.id).as_str())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if load_thumbnail {
|
|
||||||
let api = Rc::clone(&api);
|
|
||||||
let id = album.id();
|
|
||||||
let album_weak = album.downgrade();
|
|
||||||
album.imp()
|
|
||||||
.thumbnail_loading
|
|
||||||
.replace(Some(glib::spawn_future_local(async move {
|
|
||||||
let bytes = api
|
|
||||||
.cover_art(&id, Some(50)) // TODO: WidgetExt::scale_factor
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let album = match album_weak.upgrade() {
|
|
||||||
None => return,
|
|
||||||
Some(album) => album,
|
|
||||||
};
|
|
||||||
album.set_thumbnail(
|
|
||||||
gdk::Texture::from_bytes(&glib::Bytes::from_owned(bytes)).unwrap(),
|
|
||||||
);
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
album
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
mod imp {
|
mod imp {
|
||||||
use crate::model::Song;
|
use crate::model::{Album, Song};
|
||||||
use crate::{mpris, mpv};
|
use crate::{mpris, mpv};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
|
@ -38,6 +38,9 @@ mod imp {
|
||||||
#[property(get)]
|
#[property(get)]
|
||||||
playlist_model: gio::ListStore,
|
playlist_model: gio::ListStore,
|
||||||
|
|
||||||
|
#[property(get)]
|
||||||
|
albums_model: gio::ListStore,
|
||||||
|
|
||||||
#[property(type = i64, get = Self::volume, set = Self::set_volume, minimum = 0, maximum = 100)]
|
#[property(type = i64, get = Self::volume, set = Self::set_volume, minimum = 0, maximum = 100)]
|
||||||
_volume: (),
|
_volume: (),
|
||||||
#[property(type = bool, get = Self::mute, set = Self::set_mute)]
|
#[property(type = bool, get = Self::mute, set = Self::set_mute)]
|
||||||
|
@ -98,7 +101,9 @@ mod imp {
|
||||||
setup: Default::default(),
|
setup: Default::default(),
|
||||||
api: Default::default(),
|
api: Default::default(),
|
||||||
mpv,
|
mpv,
|
||||||
|
|
||||||
playlist_model: gio::ListStore::new::<Song>(),
|
playlist_model: gio::ListStore::new::<Song>(),
|
||||||
|
albums_model: gio::ListStore::new::<Album>(),
|
||||||
|
|
||||||
_volume: (),
|
_volume: (),
|
||||||
_mute: (),
|
_mute: (),
|
||||||
|
@ -653,20 +658,28 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_connected(&self, api: crate::subsonic::Client) {
|
pub fn setup_connected(&self, api: crate::subsonic::Client) {
|
||||||
self.imp().api.replace(Some(Rc::new(api)));
|
if self.imp().api.replace(Some(Rc::new(api))).is_some() {
|
||||||
|
unimplemented!("changing the api object");
|
||||||
|
}
|
||||||
|
|
||||||
self.set_can_click_shuffle_all(true);
|
self.set_can_click_shuffle_all(true);
|
||||||
|
|
||||||
let api = Rc::clone(self.imp().api.borrow().as_ref().unwrap());
|
let api = Rc::clone(self.imp().api.borrow().as_ref().unwrap());
|
||||||
|
let albums_model = self.albums_model().clone();
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
let mut albums =
|
let mut albums =
|
||||||
std::pin::pin!(api.album_list_full(crate::subsonic::AlbumListType::Newest));
|
std::pin::pin!(api.album_list_full(crate::subsonic::AlbumListType::Newest));
|
||||||
while albums.try_next().await.unwrap().is_some() {
|
while let Some(album) = albums.try_next().await.unwrap() {
|
||||||
count += 1;
|
albums_model.append(
|
||||||
|
&glib::Object::builder::<crate::model::Album>()
|
||||||
|
.property("id", &album.id)
|
||||||
|
.property("name", &album.name)
|
||||||
|
.property("artist", &album.artist)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
println!("gathered {count} albums");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,4 +745,13 @@ impl Window {
|
||||||
Ordering::Equal => {}
|
Ordering::Equal => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stop(&self) {
|
||||||
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue