mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 19:57:25 +01:00
Show albums on home screen
This commit is contained in:
parent
3ab0332475
commit
38613c0063
7 changed files with 172 additions and 3 deletions
25
data/ui/album_tile.blp
Normal file
25
data/ui/album_tile.blp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template $MusicusAlbumTile: Gtk.FlowBoxChild {
|
||||||
|
styles [
|
||||||
|
"card",
|
||||||
|
"activatable",
|
||||||
|
"tile"
|
||||||
|
]
|
||||||
|
|
||||||
|
Gtk.Box {
|
||||||
|
valign: center;
|
||||||
|
|
||||||
|
Gtk.Label title_label {
|
||||||
|
styles [
|
||||||
|
"title"
|
||||||
|
]
|
||||||
|
|
||||||
|
valign: center;
|
||||||
|
halign: start;
|
||||||
|
lines: 1;
|
||||||
|
ellipsize: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -127,6 +127,23 @@ template $MusicusHomePage : Adw.NavigationPage {
|
||||||
selection-mode: none;
|
selection-mode: none;
|
||||||
child-activated => $recording_selected() swapped;
|
child-activated => $recording_selected() swapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gtk.Label {
|
||||||
|
styles ["heading"]
|
||||||
|
visible: bind albums_flow_box.visible;
|
||||||
|
halign: start;
|
||||||
|
label: _("Albums");
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.FlowBox albums_flow_box {
|
||||||
|
margin-top: 12;
|
||||||
|
margin-bottom: 24;
|
||||||
|
column-spacing: 12;
|
||||||
|
row-spacing: 12;
|
||||||
|
homogeneous: true;
|
||||||
|
selection-mode: none;
|
||||||
|
child-activated => $album_selected() swapped;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
56
src/album_tile.rs
Normal file
56
src/album_tile.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use gtk::{glib, subclass::prelude::*};
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
|
use crate::db::models::Album;
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||||
|
#[template(file = "data/ui/album_tile.blp")]
|
||||||
|
pub struct MusicusAlbumTile {
|
||||||
|
pub album: OnceCell<Album>,
|
||||||
|
|
||||||
|
#[template_child]
|
||||||
|
pub title_label: TemplateChild<gtk::Label>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for MusicusAlbumTile {
|
||||||
|
const NAME: &'static str = "MusicusAlbumTile";
|
||||||
|
type Type = super::MusicusAlbumTile;
|
||||||
|
type ParentType = gtk::FlowBoxChild;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for MusicusAlbumTile {}
|
||||||
|
impl WidgetImpl for MusicusAlbumTile {}
|
||||||
|
impl FlowBoxChildImpl for MusicusAlbumTile {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct MusicusAlbumTile(ObjectSubclass<imp::MusicusAlbumTile>)
|
||||||
|
@extends gtk::Widget, gtk::FlowBoxChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MusicusAlbumTile {
|
||||||
|
pub fn new(album: &Album) -> Self {
|
||||||
|
let obj: Self = glib::Object::new();
|
||||||
|
|
||||||
|
obj.imp().title_label.set_label(&album.name.get());
|
||||||
|
obj.imp().album.set(album.clone()).unwrap();
|
||||||
|
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn album(&self) -> &Album {
|
||||||
|
self.imp().album.get().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ use diesel::prelude::*;
|
||||||
use super::{schema::*, tables, TranslatedString};
|
use super::{schema::*, tables, TranslatedString};
|
||||||
|
|
||||||
// Re-exports for tables that don't need additional information.
|
// Re-exports for tables that don't need additional information.
|
||||||
pub use tables::{Instrument, Person, Role};
|
pub use tables::{Album, Instrument, Person, Role};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Work {
|
pub struct Work {
|
||||||
|
|
@ -371,3 +371,10 @@ impl Track {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for Album {}
|
||||||
|
impl PartialEq for Album {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.album_id == other.album_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
album_tile::MusicusAlbumTile,
|
||||||
db::models::*,
|
db::models::*,
|
||||||
library::{LibraryQuery, MusicusLibrary},
|
library::{LibraryQuery, MusicusLibrary},
|
||||||
player::MusicusPlayer,
|
player::MusicusPlayer,
|
||||||
|
|
@ -8,11 +9,13 @@ use crate::{
|
||||||
search_tag::Tag,
|
search_tag::Tag,
|
||||||
tag_tile::MusicusTagTile,
|
tag_tile::MusicusTagTile,
|
||||||
};
|
};
|
||||||
|
|
||||||
use adw::subclass::{navigation_page::NavigationPageImpl, prelude::*};
|
use adw::subclass::{navigation_page::NavigationPageImpl, prelude::*};
|
||||||
use gtk::{
|
use gtk::{
|
||||||
glib::{self, clone, Properties},
|
glib::{self, clone, Properties},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
@ -33,6 +36,7 @@ mod imp {
|
||||||
pub ensembles: RefCell<Vec<Ensemble>>,
|
pub ensembles: RefCell<Vec<Ensemble>>,
|
||||||
pub works: RefCell<Vec<Work>>,
|
pub works: RefCell<Vec<Work>>,
|
||||||
pub recordings: RefCell<Vec<Recording>>,
|
pub recordings: RefCell<Vec<Recording>>,
|
||||||
|
pub albums: RefCell<Vec<Album>>,
|
||||||
|
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub search_entry: TemplateChild<MusicusSearchEntry>,
|
pub search_entry: TemplateChild<MusicusSearchEntry>,
|
||||||
|
|
@ -49,6 +53,8 @@ mod imp {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub recordings_flow_box: TemplateChild<gtk::FlowBox>,
|
pub recordings_flow_box: TemplateChild<gtk::FlowBox>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
pub albums_flow_box: TemplateChild<gtk::FlowBox>,
|
||||||
|
#[template_child]
|
||||||
pub play_button: TemplateChild<gtk::Button>,
|
pub play_button: TemplateChild<gtk::Button>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,13 +126,14 @@ impl MusicusHomePage {
|
||||||
fn select(&self, search_entry: &MusicusSearchEntry) {
|
fn select(&self, search_entry: &MusicusSearchEntry) {
|
||||||
let imp = self.imp();
|
let imp = self.imp();
|
||||||
|
|
||||||
let (composer, performer, ensemble, work, recording) = {
|
let (composer, performer, ensemble, work, recording, album) = {
|
||||||
(
|
(
|
||||||
imp.composers.borrow().first().cloned(),
|
imp.composers.borrow().first().cloned(),
|
||||||
imp.performers.borrow().first().cloned(),
|
imp.performers.borrow().first().cloned(),
|
||||||
imp.ensembles.borrow().first().cloned(),
|
imp.ensembles.borrow().first().cloned(),
|
||||||
imp.works.borrow().first().cloned(),
|
imp.works.borrow().first().cloned(),
|
||||||
imp.recordings.borrow().first().cloned(),
|
imp.recordings.borrow().first().cloned(),
|
||||||
|
imp.albums.borrow().first().cloned(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -140,6 +147,8 @@ impl MusicusHomePage {
|
||||||
search_entry.add_tag(Tag::Work(work));
|
search_entry.add_tag(Tag::Work(work));
|
||||||
} else if let Some(recording) = recording {
|
} else if let Some(recording) = recording {
|
||||||
self.play_recording(&recording);
|
self.play_recording(&recording);
|
||||||
|
} else if let Some(album) = album {
|
||||||
|
self.show_album(&album);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,6 +168,11 @@ impl MusicusHomePage {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn album_selected(&self, tile: >k::FlowBoxChild, _: >k::FlowBox) {
|
||||||
|
self.show_album(tile.downcast_ref::<MusicusAlbumTile>().unwrap().album());
|
||||||
|
}
|
||||||
|
|
||||||
fn play_recording(&self, recording: &Recording) {
|
fn play_recording(&self, recording: &Recording) {
|
||||||
let tracks = &recording.tracks;
|
let tracks = &recording.tracks;
|
||||||
|
|
||||||
|
|
@ -227,6 +241,10 @@ impl MusicusHomePage {
|
||||||
self.player().append(items);
|
self.player().append(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_album(&self, _album: &Album) {
|
||||||
|
todo!("Show album");
|
||||||
|
}
|
||||||
|
|
||||||
fn query(&self, query: &LibraryQuery) {
|
fn query(&self, query: &LibraryQuery) {
|
||||||
let imp = self.imp();
|
let imp = self.imp();
|
||||||
let results = self.library().query(query).unwrap();
|
let results = self.library().query(query).unwrap();
|
||||||
|
|
@ -237,6 +255,7 @@ impl MusicusHomePage {
|
||||||
&imp.ensembles_flow_box,
|
&imp.ensembles_flow_box,
|
||||||
&imp.works_flow_box,
|
&imp.works_flow_box,
|
||||||
&imp.recordings_flow_box,
|
&imp.recordings_flow_box,
|
||||||
|
&imp.albums_flow_box,
|
||||||
] {
|
] {
|
||||||
while let Some(widget) = flowbox.first_child() {
|
while let Some(widget) = flowbox.first_child() {
|
||||||
flowbox.remove(&widget);
|
flowbox.remove(&widget);
|
||||||
|
|
@ -257,6 +276,7 @@ impl MusicusHomePage {
|
||||||
imp.works_flow_box.set_visible(!results.works.is_empty());
|
imp.works_flow_box.set_visible(!results.works.is_empty());
|
||||||
imp.recordings_flow_box
|
imp.recordings_flow_box
|
||||||
.set_visible(!results.recordings.is_empty());
|
.set_visible(!results.recordings.is_empty());
|
||||||
|
imp.albums_flow_box.set_visible(!results.albums.is_empty());
|
||||||
|
|
||||||
for composer in &results.composers {
|
for composer in &results.composers {
|
||||||
imp.composers_flow_box
|
imp.composers_flow_box
|
||||||
|
|
@ -283,11 +303,16 @@ impl MusicusHomePage {
|
||||||
.append(&MusicusRecordingTile::new(recording));
|
.append(&MusicusRecordingTile::new(recording));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for album in &results.albums {
|
||||||
|
imp.albums_flow_box.append(&MusicusAlbumTile::new(album));
|
||||||
|
}
|
||||||
|
|
||||||
imp.composers.replace(results.composers);
|
imp.composers.replace(results.composers);
|
||||||
imp.performers.replace(results.performers);
|
imp.performers.replace(results.performers);
|
||||||
imp.ensembles.replace(results.ensembles);
|
imp.ensembles.replace(results.ensembles);
|
||||||
imp.works.replace(results.works);
|
imp.works.replace(results.works);
|
||||||
imp.recordings.replace(results.recordings);
|
imp.recordings.replace(results.recordings);
|
||||||
|
imp.albums.replace(results.albums);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,11 +109,17 @@ impl MusicusLibrary {
|
||||||
.map(|w| Work::from_table(w, connection))
|
.map(|w| Work::from_table(w, connection))
|
||||||
.collect::<Result<Vec<Work>>>()?;
|
.collect::<Result<Vec<Work>>>()?;
|
||||||
|
|
||||||
|
let albums: Vec<Album> = albums::table
|
||||||
|
.filter(albums::name.like(&search))
|
||||||
|
.limit(9)
|
||||||
|
.load(connection)?;
|
||||||
|
|
||||||
LibraryResults {
|
LibraryResults {
|
||||||
composers,
|
composers,
|
||||||
performers,
|
performers,
|
||||||
ensembles,
|
ensembles,
|
||||||
works,
|
works,
|
||||||
|
albums,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -219,9 +225,24 @@ impl MusicusLibrary {
|
||||||
.map(|r| Recording::from_table(r, &&self.folder(), connection))
|
.map(|r| Recording::from_table(r, &&self.folder(), connection))
|
||||||
.collect::<Result<Vec<Recording>>>()?;
|
.collect::<Result<Vec<Recording>>>()?;
|
||||||
|
|
||||||
|
let albums = albums::table
|
||||||
|
.inner_join(
|
||||||
|
album_recordings::table
|
||||||
|
.inner_join(recordings::table.inner_join(recording_ensembles::table)),
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
recording_ensembles::ensemble_id
|
||||||
|
.eq(&ensemble.ensemble_id)
|
||||||
|
.and(albums::name.like(&search)),
|
||||||
|
)
|
||||||
|
.select(albums::all_columns)
|
||||||
|
.distinct()
|
||||||
|
.load(connection)?;
|
||||||
|
|
||||||
LibraryResults {
|
LibraryResults {
|
||||||
composers,
|
composers,
|
||||||
recordings,
|
recordings,
|
||||||
|
albums,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,9 +286,24 @@ impl MusicusLibrary {
|
||||||
.map(|r| Recording::from_table(r, &self.folder(), connection))
|
.map(|r| Recording::from_table(r, &self.folder(), connection))
|
||||||
.collect::<Result<Vec<Recording>>>()?;
|
.collect::<Result<Vec<Recording>>>()?;
|
||||||
|
|
||||||
|
let albums = albums::table
|
||||||
|
.inner_join(
|
||||||
|
album_recordings::table
|
||||||
|
.inner_join(recordings::table.inner_join(recording_persons::table)),
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
recording_persons::person_id
|
||||||
|
.eq(&performer.person_id)
|
||||||
|
.and(albums::name.like(&search)),
|
||||||
|
)
|
||||||
|
.select(albums::all_columns)
|
||||||
|
.distinct()
|
||||||
|
.load(connection)?;
|
||||||
|
|
||||||
LibraryResults {
|
LibraryResults {
|
||||||
composers,
|
composers,
|
||||||
recordings,
|
recordings,
|
||||||
|
albums,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -426,6 +462,7 @@ pub struct LibraryResults {
|
||||||
pub ensembles: Vec<Ensemble>,
|
pub ensembles: Vec<Ensemble>,
|
||||||
pub works: Vec<Work>,
|
pub works: Vec<Work>,
|
||||||
pub recordings: Vec<Recording>,
|
pub recordings: Vec<Recording>,
|
||||||
|
pub albums: Vec<Album>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LibraryResults {
|
impl LibraryResults {
|
||||||
|
|
@ -435,5 +472,6 @@ impl LibraryResults {
|
||||||
&& self.ensembles.is_empty()
|
&& self.ensembles.is_empty()
|
||||||
&& self.works.is_empty()
|
&& self.works.is_empty()
|
||||||
&& self.recordings.is_empty()
|
&& self.recordings.is_empty()
|
||||||
|
&& self.albums.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
mod album_tile;
|
||||||
mod application;
|
mod application;
|
||||||
mod config;
|
mod config;
|
||||||
mod db;
|
mod db;
|
||||||
mod editor;
|
mod editor;
|
||||||
mod home_page;
|
mod home_page;
|
||||||
mod library_manager;
|
|
||||||
mod library;
|
mod library;
|
||||||
|
mod library_manager;
|
||||||
mod player;
|
mod player;
|
||||||
mod player_bar;
|
mod player_bar;
|
||||||
mod playlist_item;
|
mod playlist_item;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue