Add home page header and hook up editors

This commit is contained in:
Elias Projahn 2024-06-05 19:03:04 +02:00
parent 38613c0063
commit f49f23a501
10 changed files with 236 additions and 55 deletions

View file

@ -21,14 +21,65 @@ template $MusicusHomePage : Adw.NavigationPage {
maximum-size: 1000;
tightening-threshold: 600;
Gtk.Box {
orientation: vertical;
$MusicusSearchEntry search_entry {
activate => $select() swapped;
}
Gtk.Box header_box {
visible: false;
spacing: 12;
margin-start: 12;
margin-end: 12;
margin-top: 24;
margin-bottom: 12;
Gtk.Button {
styles [
"flat"
]
valign: center;
icon-name: "go-previous-symbolic";
clicked => $back_button_clicked() swapped;
}
Gtk.Box {
orientation: vertical;
hexpand: true;
Gtk.Label title_label {
styles [
"title-1"
]
xalign: 0.0;
}
Gtk.Label subtitle_label {
xalign: 0.0;
}
}
Gtk.Button {
styles [
"flat"
]
valign: center;
icon-name: "document-edit-symbolic";
clicked => $edit_button_clicked() swapped;
}
}
}
}
Gtk.Stack stack {
Gtk.StackPage {
name: "results";
child: Gtk.ScrolledWindow {
hscrollbar-policy: never;
@ -44,7 +95,10 @@ template $MusicusHomePage : Adw.NavigationPage {
margin-bottom: 68;
Gtk.Label {
styles ["heading"]
styles [
"heading"
]
visible: bind composers_flow_box.visible;
halign: start;
label: _("Composers");
@ -61,7 +115,10 @@ template $MusicusHomePage : Adw.NavigationPage {
}
Gtk.Label {
styles ["heading"]
styles [
"heading"
]
visible: bind performers_flow_box.visible;
halign: start;
label: _("Performers");
@ -78,7 +135,10 @@ template $MusicusHomePage : Adw.NavigationPage {
}
Gtk.Label {
styles ["heading"]
styles [
"heading"
]
visible: bind ensembles_flow_box.visible;
halign: start;
label: _("Ensembles");
@ -95,7 +155,10 @@ template $MusicusHomePage : Adw.NavigationPage {
}
Gtk.Label {
styles ["heading"]
styles [
"heading"
]
visible: bind works_flow_box.visible;
halign: start;
label: _("Works");
@ -112,7 +175,10 @@ template $MusicusHomePage : Adw.NavigationPage {
}
Gtk.Label {
styles ["heading"]
styles [
"heading"
]
visible: bind recordings_flow_box.visible;
halign: start;
label: _("Recordings");
@ -129,7 +195,10 @@ template $MusicusHomePage : Adw.NavigationPage {
}
Gtk.Label {
styles ["heading"]
styles [
"heading"
]
visible: bind albums_flow_box.visible;
halign: start;
label: _("Albums");
@ -148,8 +217,10 @@ template $MusicusHomePage : Adw.NavigationPage {
}
};
}
Gtk.StackPage {
name: "empty";
child: Adw.StatusPage {
icon-name: "system-search-symbolic";
title: _("Nothing Found");
@ -161,7 +232,11 @@ template $MusicusHomePage : Adw.NavigationPage {
[overlay]
Gtk.Button play_button {
styles ["pill", "suggested-action"]
styles [
"pill",
"suggested-action"
]
halign: end;
valign: end;
margin-end: 24;
@ -177,10 +252,12 @@ menu primary_menu {
label: _("_Library manager");
action: "win.library";
}
item {
label: _("_Preferences");
action: "app.preferences";
}
item {
label: _("_About Musicus");
action: "app.about";

View file

@ -9,6 +9,9 @@ template $MusicusPersonEditor: Adw.NavigationPage {
Adw.HeaderBar header_bar {}
Adw.Clamp {
Gtk.Box {
orientation: vertical;
Gtk.Label {
label: _("Name");
xalign: 0;
@ -20,7 +23,8 @@ template $MusicusPersonEditor: Adw.NavigationPage {
}
$MusicusTranslationEditor name_editor {
margin-start: 12;
margin-top: 12;
}
}
}
}

View file

@ -35,5 +35,12 @@ template $MusicusRecordingTile : Gtk.FlowBoxChild {
wrap: true;
}
}
Gtk.Button {
styles ["flat"]
valign: start;
margin-top: 12;
icon-name: "view-more-symbolic";
}
}
}

View file

@ -1,14 +1,17 @@
use adw::{prelude::*, subclass::prelude::*};
use gtk::glib;
use crate::editor::translation_editor::MusicusTranslationEditor;
use crate::{db::models::Person, editor::translation_editor::MusicusTranslationEditor};
mod imp {
use super::*;
#[derive(Debug, Default, gtk::CompositeTemplate)]
#[template(file = "data/ui/person_editor.blp")]
pub struct MusicusPersonEditor {}
pub struct MusicusPersonEditor {
#[template_child]
pub name_editor: TemplateChild<MusicusTranslationEditor>,
}
#[glib::object_subclass]
impl ObjectSubclass for MusicusPersonEditor {
@ -39,7 +42,13 @@ glib::wrapper! {
#[gtk::template_callbacks]
impl MusicusPersonEditor {
pub fn new() -> Self {
glib::Object::new()
pub fn new(person: Option<&Person>) -> Self {
let obj: Self = glib::Object::new();
if let Some(person) = person {
obj.imp().name_editor.set_translation(&person.name);
}
obj
}
}

View file

@ -55,19 +55,20 @@ glib::wrapper! {
#[gtk::template_callbacks]
impl MusicusTranslationEditor {
pub fn new(translation: TranslatedString) -> Self {
let obj: Self = glib::Object::new();
let mut translation = translation.0;
pub fn new() -> Self {
glib::Object::new()
}
obj.imp()
pub fn set_translation(&self, translation: &TranslatedString) {
let mut translation = translation.0.clone();
self.imp()
.entry_row
.set_text(&translation.remove("generic").unwrap_or_default());
for (lang, translation) in translation {
obj.add_entry(&lang, &translation);
self.add_entry(&lang, &translation);
}
obj
}
#[template_callback]
@ -92,11 +93,17 @@ impl MusicusTranslationEditor {
let obj = self.clone();
entry.connect_remove(move |entry| {
obj.imp().translation_entries.borrow_mut().retain(|e| e != entry);
obj.imp()
.translation_entries
.borrow_mut()
.retain(|e| e != entry);
obj.imp().list_box.remove(entry);
});
self.imp().list_box.insert(&entry, self.imp().translation_entries.borrow().len() as i32 + 1);
self.imp().list_box.insert(
&entry,
self.imp().translation_entries.borrow().len() as i32 + 1,
);
entry.grab_focus();
self.imp().translation_entries.borrow_mut().push(entry);

View file

@ -1,7 +1,7 @@
use crate::{
db::{
self,
models::{Composer, Instrument, Person, WorkPart},
models::{Composer, Instrument, Person, Work, WorkPart},
},
editor::{
instrument_selector_popover::MusicusInstrumentSelectorPopover,
@ -25,6 +25,9 @@ mod imp {
#[properties(wrapper_type = super::MusicusWorkEditor)]
#[template(file = "data/ui/work_editor.blp")]
pub struct MusicusWorkEditor {
#[property(get, construct_only)]
pub navigation: OnceCell<adw::NavigationView>,
#[property(get, construct_only)]
pub library: OnceCell<MusicusLibrary>,
@ -38,6 +41,8 @@ mod imp {
pub persons_popover: OnceCell<MusicusPersonSelectorPopover>,
pub instruments_popover: OnceCell<MusicusInstrumentSelectorPopover>,
#[template_child]
pub name_editor: TemplateChild<MusicusTranslationEditor>,
#[template_child]
pub composer_list: TemplateChild<gtk::ListBox>,
#[template_child]
@ -146,8 +151,21 @@ glib::wrapper! {
#[gtk::template_callbacks]
impl MusicusWorkEditor {
pub fn new(library: &MusicusLibrary) -> Self {
glib::Object::builder().property("library", library).build()
pub fn new(
navigation: &adw::NavigationView,
library: &MusicusLibrary,
work: Option<&Work>,
) -> Self {
let obj: Self = glib::Object::builder()
.property("navigation", navigation)
.property("library", library)
.build();
if let Some(_work) = work {
// TODO: Initialize work data.
}
obj
}
#[template_callback]

View file

@ -1,6 +1,7 @@
use crate::{
album_tile::MusicusAlbumTile,
db::models::*,
editor::{person_editor::MusicusPersonEditor, work_editor::MusicusWorkEditor},
library::{LibraryQuery, MusicusLibrary},
player::MusicusPlayer,
playlist_item::PlaylistItem,
@ -25,6 +26,9 @@ mod imp {
#[properties(wrapper_type = super::MusicusHomePage)]
#[template(file = "data/ui/home_page.blp")]
pub struct MusicusHomePage {
#[property(get, construct_only)]
pub navigation: OnceCell<adw::NavigationView>,
#[property(get, construct_only)]
pub library: OnceCell<MusicusLibrary>,
@ -43,6 +47,12 @@ mod imp {
#[template_child]
pub stack: TemplateChild<gtk::Stack>,
#[template_child]
pub header_box: TemplateChild<gtk::Box>,
#[template_child]
pub title_label: TemplateChild<gtk::Label>,
#[template_child]
pub subtitle_label: TemplateChild<gtk::Label>,
#[template_child]
pub composers_flow_box: TemplateChild<gtk::FlowBox>,
#[template_child]
pub performers_flow_box: TemplateChild<gtk::FlowBox>,
@ -109,13 +119,41 @@ glib::wrapper! {
#[gtk::template_callbacks]
impl MusicusHomePage {
pub fn new(library: &MusicusLibrary, player: &MusicusPlayer) -> Self {
pub fn new(
navigation: &adw::NavigationView,
library: &MusicusLibrary,
player: &MusicusPlayer,
) -> Self {
glib::Object::builder()
.property("navigation", navigation)
.property("library", library)
.property("player", player)
.build()
}
#[template_callback]
fn back_button_clicked(&self, _: &gtk::Button) {
self.imp().search_entry.reset();
}
#[template_callback]
fn edit_button_clicked(&self, _: &gtk::Button) {
if let Some(tag) = self.imp().search_entry.tags().first() {
match tag {
Tag::Composer(person) | Tag::Performer(person) => {
self.navigation()
.push(&MusicusPersonEditor::new(Some(person)));
}
Tag::Ensemble(_) => todo!(),
Tag::Work(work) => self.navigation().push(&MusicusWorkEditor::new(
&self.navigation(),
&self.library(),
Some(work),
)),
}
}
}
#[template_callback]
fn play(&self, _: &gtk::Button) {
log::info!("Play button clicked");
@ -262,6 +300,28 @@ impl MusicusHomePage {
}
}
if let Some(tag) = imp.search_entry.tags().first() {
match tag {
Tag::Composer(person) | Tag::Performer(person) => {
imp.title_label.set_text(&person.name.get());
imp.subtitle_label.set_visible(false);
}
Tag::Ensemble(ensemble) => {
imp.title_label.set_text(&ensemble.name.get());
imp.subtitle_label.set_visible(false);
}
Tag::Work(work) => {
imp.title_label.set_text(&work.name.get());
imp.subtitle_label.set_text(&work.composers_string());
imp.subtitle_label.set_visible(true);
}
}
imp.header_box.set_visible(true);
} else {
imp.header_box.set_visible(false);
}
if results.is_empty() {
imp.stack.set_visible_child_name("empty");
} else {

View file

@ -5,7 +5,6 @@ use adw::{
use gtk::glib::{self, Properties};
use std::cell::OnceCell;
use crate::editor::work_editor::MusicusWorkEditor;
use crate::library::MusicusLibrary;
mod imp {
@ -36,12 +35,7 @@ mod imp {
}
#[glib::derived_properties]
impl ObjectImpl for LibraryManager {
fn constructed(&self) {
self.parent_constructed();
self.obj().set_child(Some(&MusicusWorkEditor::new(self.library.get().unwrap())));
}
}
impl ObjectImpl for LibraryManager {}
impl WidgetImpl for LibraryManager {}
impl NavigationPageImpl for LibraryManager {}

View file

@ -174,6 +174,15 @@ impl MusicusSearchEntry {
self.emit_by_name::<()>("query-changed", &[]);
}
pub fn tags(&self) -> Vec<Tag> {
self.imp()
.tags
.borrow()
.iter()
.map(|t| t.tag().to_owned())
.collect()
}
pub fn query(&self) -> LibraryQuery {
let mut query = LibraryQuery {
search: self.imp().text.text().to_string(),

View file

@ -155,12 +155,8 @@ impl MusicusWindow {
fn load_library(&self, path: impl AsRef<Path>) {
let library = MusicusLibrary::new(path);
self.imp()
.navigation_view
.replace(&[MusicusHomePage::new(&library, &self.imp().player).into()]);
self.imp()
.navigation_view
.add(&LibraryManager::new(&library));
let navigation = self.imp().navigation_view.get();
navigation.replace(&[MusicusHomePage::new(&navigation, &library, &self.imp().player).into()]);
navigation.add(&LibraryManager::new(&library));
}
}