diff --git a/data/ui/home_page.blp b/data/ui/home_page.blp index 1c19312..f401fca 100644 --- a/data/ui/home_page.blp +++ b/data/ui/home_page.blp @@ -45,12 +45,28 @@ template $MusicusHomePage : Adw.NavigationPage { Gtk.Label { styles ["heading"] - visible: bind persons_flow_box.visible; + visible: bind composers_flow_box.visible; halign: start; - label: _("Composers and performers"); + label: _("Composers"); } - Gtk.FlowBox persons_flow_box { + Gtk.FlowBox composers_flow_box { + margin-top: 12; + margin-bottom: 24; + column-spacing: 12; + row-spacing: 12; + homogeneous: true; + selection-mode: none; + } + + Gtk.Label { + styles ["heading"] + visible: bind performers_flow_box.visible; + halign: start; + label: _("Performers"); + } + + Gtk.FlowBox performers_flow_box { margin-top: 12; margin-bottom: 24; column-spacing: 12; diff --git a/src/home_page.rs b/src/home_page.rs index 354a9de..2b36df9 100644 --- a/src/home_page.rs +++ b/src/home_page.rs @@ -25,7 +25,8 @@ mod imp { #[property(get, construct_only)] pub player: OnceCell, - pub persons: RefCell>, + pub composers: RefCell>, + pub performers: RefCell>, pub ensembles: RefCell>, pub works: RefCell>, pub recordings: RefCell>, @@ -35,7 +36,9 @@ mod imp { #[template_child] pub stack: TemplateChild, #[template_child] - pub persons_flow_box: TemplateChild, + pub composers_flow_box: TemplateChild, + #[template_child] + pub performers_flow_box: TemplateChild, #[template_child] pub ensembles_flow_box: TemplateChild, #[template_child] @@ -114,16 +117,19 @@ impl MusicusHomePage { fn select(&self, search_entry: &MusicusSearchEntry) { let imp = self.imp(); - let (person, ensemble, work) = { + let (composer, performer, ensemble, work) = { ( - imp.persons.borrow().first().cloned(), + imp.composers.borrow().first().cloned(), + imp.performers.borrow().first().cloned(), imp.ensembles.borrow().first().cloned(), imp.works.borrow().first().cloned(), ) }; - if let Some(person) = person { - search_entry.add_tag(Tag::Person(person)); + if let Some(person) = composer { + search_entry.add_tag(Tag::Composer(person)); + } else if let Some(person) = performer { + search_entry.add_tag(Tag::Performer(person)); } else if let Some(ensemble) = ensemble { search_entry.add_tag(Tag::Ensemble(ensemble)); } else if let Some(work) = work { @@ -136,7 +142,8 @@ impl MusicusHomePage { let results = self.library().query(query); for flowbox in [ - &imp.persons_flow_box, + &imp.composers_flow_box, + &imp.performers_flow_box, &imp.ensembles_flow_box, &imp.works_flow_box, &imp.recordings_flow_box, @@ -151,17 +158,24 @@ impl MusicusHomePage { } else { imp.stack.set_visible_child_name("results"); - imp.persons_flow_box - .set_visible(!results.persons.is_empty()); + imp.composers_flow_box + .set_visible(!results.composers.is_empty()); + imp.performers_flow_box + .set_visible(!results.performers.is_empty()); imp.ensembles_flow_box .set_visible(!results.ensembles.is_empty()); imp.works_flow_box.set_visible(!results.works.is_empty()); imp.recordings_flow_box .set_visible(!results.recordings.is_empty()); - for person in &results.persons { - imp.persons_flow_box - .append(&MusicusTile::with_title(&person.name_fl())); + for composer in &results.composers { + imp.composers_flow_box + .append(&MusicusTile::with_title(&composer.name_fl())); + } + + for performer in &results.performers { + imp.performers_flow_box + .append(&MusicusTile::with_title(&performer.name_fl())); } for ensemble in &results.ensembles { @@ -183,7 +197,8 @@ impl MusicusHomePage { )); } - imp.persons.replace(results.persons); + imp.composers.replace(results.composers); + imp.performers.replace(results.performers); imp.ensembles.replace(results.ensembles); imp.works.replace(results.works); imp.recordings.replace(results.recordings); diff --git a/src/library.rs b/src/library.rs index de23e2b..3c9df33 100644 --- a/src/library.rs +++ b/src/library.rs @@ -50,13 +50,22 @@ impl MusicusLibrary { match query { LibraryQuery { - person: None, + composer: None, + performer: None, ensemble: None, work: None, .. } => { - let persons = self.con() - .prepare("SELECT id, first_name, last_name FROM persons WHERE first_name LIKE ?1 OR last_name LIKE ?1 LIMIT 9") + let composers = self.con() + .prepare("SELECT DISTINCT persons.id, persons.first_name, persons.last_name FROM persons INNER JOIN works ON works.composer = persons.id WHERE persons.first_name LIKE ?1 OR persons.last_name LIKE ?1 LIMIT 9") + .unwrap() + .query_map([&search], Person::from_row) + .unwrap() + .collect::>>() + .unwrap(); + + let performers = self.con() + .prepare("SELECT DISTINCT persons.id, persons.first_name, persons.last_name FROM persons INNER JOIN performances ON performances.person = persons.id WHERE persons.first_name LIKE ?1 OR persons.last_name LIKE ?1 LIMIT 9") .unwrap() .query_map([&search], Person::from_row) .unwrap() @@ -82,22 +91,24 @@ impl MusicusLibrary { .unwrap(); LibraryResults { - persons, + composers, + performers, ensembles, works, ..Default::default() } } LibraryQuery { - person: Some(person), + composer: Some(composer), + performer: None, ensemble: None, work: None, .. } => { - let persons = self.con() + let performers = self.con() .prepare("SELECT DISTINCT persons.id, persons.first_name, persons.last_name FROM persons INNER JOIN performances ON performances.person = persons.id INNER JOIN recordings ON recordings.id = performances.recording INNER JOIN works ON works.id = recordings.work WHERE works.composer IS ?1 AND (persons.first_name LIKE ?2 OR persons.last_name LIKE ?2) LIMIT 9") .unwrap() - .query_map([&person.id, &search], Person::from_row) + .query_map([&composer.id, &search], Person::from_row) .unwrap() .collect::>>() .unwrap(); @@ -106,7 +117,7 @@ impl MusicusLibrary { .con() .prepare("SELECT DISTINCT ensembles.id, ensembles.name FROM ensembles INNER JOIN performances ON performances.ensemble = ensembles.id INNER JOIN recordings ON recordings.id = performances.recording INNER JOIN works ON works.id = recordings.work WHERE works.composer IS ?1 AND ensembles.name LIKE ?2 LIMIT 9") .unwrap() - .query_map([&person.id, &search], Ensemble::from_row) + .query_map([&composer.id, &search], Ensemble::from_row) .unwrap() .collect::>>() .unwrap(); @@ -115,34 +126,26 @@ impl MusicusLibrary { .con() .prepare("SELECT DISTINCT works.id, works.title, persons.id, persons.first_name, persons.last_name FROM works INNER JOIN persons ON works.composer = persons.id WHERE works.composer = ?1 AND title LIKE ?2 LIMIT 9") .unwrap() - .query_map([&person.id, &search], Work::from_row) + .query_map([&composer.id, &search], Work::from_row) .unwrap() .collect::>>() .unwrap(); - let recordings = self - .con() - .prepare("SELECT DISTINCT recordings.id, works.id, works.title, persons.id, persons.first_name, persons.last_name FROM recordings INNER JOIN works ON recordings.work = works.id INNER JOIN persons ON works.composer = persons.id INNER JOIN performances ON recordings.id = performances.recording WHERE performances.person IS ?1 AND (works.title LIKE ?2 OR persons.first_name LIKE ?2 OR persons.last_name LIKE ?2) LIMIT 9") - .unwrap() - .query_map([&person.id, &search], Recording::from_row) - .unwrap() - .collect::>>() - .unwrap(); - LibraryResults { - persons, + performers, ensembles, works, - recordings, + ..Default::default() } } LibraryQuery { - person: None, + composer: None, + performer: None, ensemble: Some(ensemble), work: None, .. } => { - let persons = self.con() + let composers = self.con() .prepare("SELECT DISTINCT persons.id, persons.first_name, persons.last_name FROM persons INNER JOIN works ON works.composer = persons.id INNER JOIN recordings ON recordings.work = works.id INNER JOIN performances ON performances.recording = recordings.id WHERE performances.ensemble IS ?1 AND (persons.first_name LIKE ?2 OR persons.last_name LIKE ?2) LIMIT 9") .unwrap() .query_map([&ensemble.id, &search], Person::from_row) @@ -160,22 +163,71 @@ impl MusicusLibrary { .unwrap(); LibraryResults { - persons, + composers, recordings, ..Default::default() } }, LibraryQuery { - person: Some(person), + composer: None, + performer: Some(performer), + work: None, + .. + } => { + let composers = self.con() + .prepare("SELECT DISTINCT persons.id, persons.first_name, persons.last_name FROM persons INNER JOIN works ON works.composer = persons.id INNER JOIN recordings ON recordings.work = works.id INNER JOIN performances ON performances.recording = recordings.id WHERE performances.person IS ?1 AND (persons.first_name LIKE ?2 OR persons.last_name LIKE ?2) LIMIT 9") + .unwrap() + .query_map([&performer.id, &search], Person::from_row) + .unwrap() + .collect::>>() + .unwrap(); + + let recordings = self + .con() + .prepare("SELECT DISTINCT recordings.id, works.id, works.title, persons.id, persons.first_name, persons.last_name FROM recordings INNER JOIN works ON recordings.work = works.id INNER JOIN persons ON works.composer = persons.id INNER JOIN performances ON recordings.id = performances.recording WHERE performances.person IS ?1 AND (works.title LIKE ?2 OR persons.first_name LIKE ?2 OR persons.last_name LIKE ?2) LIMIT 9") + .unwrap() + .query_map([&performer.id, &search], Recording::from_row) + .unwrap() + .collect::>>() + .unwrap(); + + LibraryResults { + composers, + recordings, + ..Default::default() + } + }, + LibraryQuery { + composer: Some(composer), ensemble: Some(ensemble), work: None, .. } => { let recordings = self .con() - .prepare("SELECT DISTINCT recordings.id, works.id, works.title, persons.id, persons.first_name, persons.last_name FROM recordings INNER JOIN works ON recordings.work = works.id INNER JOIN persons ON works.composer = persons.id INNER JOIN performances ON recordings.id = performances.recording WHERE works.composer IS ?1 AND performances.ensemble IS ?2 AND (works.title LIKE ?3 OR persons.first_name LIKE ?3 OR persons.last_name LIKE ?3) LIMIT 9") + .prepare("SELECT DISTINCT recordings.id, works.id, works.title, persons.id, persons.first_name, persons.last_name FROM recordings INNER JOIN works ON recordings.work = works.id INNER JOIN persons ON works.composer = persons.id INNER JOIN performances ON recordings.id = performances.recording WHERE works.composer IS ?1 AND performances.ensemble IS ?2 AND works.title LIKE ?3 LIMIT 9") .unwrap() - .query_map([&person.id, &ensemble.id, &search], Recording::from_row) + .query_map([&composer.id, &ensemble.id, &search], Recording::from_row) + .unwrap() + .collect::>>() + .unwrap(); + + LibraryResults { + recordings, + ..Default::default() + } + }, + LibraryQuery { + composer: Some(composer), + performer: Some(performer), + work: None, + .. + } => { + let recordings = self + .con() + .prepare("SELECT DISTINCT recordings.id, works.id, works.title, persons.id, persons.first_name, persons.last_name FROM recordings INNER JOIN works ON recordings.work = works.id INNER JOIN persons ON works.composer = persons.id INNER JOIN performances ON recordings.id = performances.recording WHERE works.composer IS ?1 AND performances.person IS ?2 AND works.title LIKE ?3 LIMIT 9") + .unwrap() + .query_map([&composer.id, &performer.id, &search], Recording::from_row) .unwrap() .collect::>>() .unwrap(); @@ -213,7 +265,8 @@ impl MusicusLibrary { #[derive(Default, Debug)] pub struct LibraryQuery { - pub person: Option, + pub composer: Option, + pub performer: Option, pub ensemble: Option, pub work: Option, pub search: String, @@ -221,7 +274,8 @@ pub struct LibraryQuery { #[derive(Default, Debug)] pub struct LibraryResults { - pub persons: Vec, + pub composers: Vec, + pub performers: Vec, pub ensembles: Vec, pub works: Vec, pub recordings: Vec, @@ -229,7 +283,8 @@ pub struct LibraryResults { impl LibraryResults { pub fn is_empty(&self) -> bool { - self.persons.is_empty() + self.composers.is_empty() + && self.performers.is_empty() && self.ensembles.is_empty() && self.works.is_empty() && self.recordings.is_empty() diff --git a/src/search_entry.rs b/src/search_entry.rs index a28ac0e..fead481 100644 --- a/src/search_entry.rs +++ b/src/search_entry.rs @@ -160,7 +160,8 @@ impl MusicusSearchEntry { for tag in &*self.imp().tags.borrow() { match tag.tag().clone() { - Tag::Person(person) => query.person = Some(person), + Tag::Composer(person) => query.composer = Some(person), + Tag::Performer(person) => query.performer = Some(person), Tag::Ensemble(ensemble) => query.ensemble = Some(ensemble), Tag::Work(work) => query.work = Some(work), } diff --git a/src/search_tag.rs b/src/search_tag.rs index 41e3b98..c81a676 100644 --- a/src/search_tag.rs +++ b/src/search_tag.rs @@ -54,7 +54,8 @@ impl MusicusSearchTag { let obj: MusicusSearchTag = glib::Object::new(); obj.imp().label.set_label(&match &tag { - Tag::Person(person) => person.name_fl(), + Tag::Composer(person) => person.name_fl(), + Tag::Performer(person) => person.name_fl(), Tag::Ensemble(ensemble) => ensemble.name.clone(), Tag::Work(work) => work.title.clone(), }); @@ -76,7 +77,8 @@ impl MusicusSearchTag { #[derive(Debug, Clone)] pub enum Tag { - Person(Person), + Composer(Person), + Performer(Person), Ensemble(Ensemble), Work(Work), }