diff --git a/res/ui/window.ui b/res/ui/window.ui index 6423fe1..2985cd4 100644 --- a/res/ui/window.ui +++ b/res/ui/window.ui @@ -473,7 +473,6 @@ in - 200 True False diff --git a/src/backend.rs b/src/backend.rs index 3835b31..5e90d26 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -17,6 +17,7 @@ enum BackendAction { DeleteEnsemble(i64, Sender>), GetEnsembles(Sender>), UpdateRecording(RecordingInsertion, Sender>), + GetRecordingsForPerson(i64, Sender>), } use BackendAction::*; @@ -126,6 +127,12 @@ impl Backend { .send(Ok(())) .expect("Failed to send result from database thread!"); } + GetRecordingsForPerson(id, sender) => { + let recordings = db.get_recordings_for_person(id); + sender + .send(recordings) + .expect("Failed to send result from database thread!"); + } } } }); @@ -371,4 +378,22 @@ impl Backend { .send(UpdateRecording(recording, sender)) .expect("Failed to send action to database thread!"); } + + pub fn get_recordings_for_person) -> () + 'static>( + &self, + id: i64, + callback: F, + ) { + let (sender, receiver) = + glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + + receiver.attach(None, move |result| { + callback(result); + glib::Continue(true) + }); + + self.action_sender + .send(GetRecordingsForPerson(id, sender)) + .expect("Failed to send action to database thread!"); + } } diff --git a/src/database/database.rs b/src/database/database.rs index 8ce18e2..caae52d 100644 --- a/src/database/database.rs +++ b/src/database/database.rs @@ -315,6 +315,21 @@ impl Database { } } + pub fn get_recordings_for_person(&self, id: i64) -> Vec { + let recordings = recordings::table + .inner_join(performances::table.on(performances::recording.eq(recordings::id))) + .inner_join(persons::table.on(persons::id.nullable().eq(performances::person))) + .filter(persons::id.eq(id)) + .select(recordings::table::all_columns()) + .load::(&self.c) + .expect("Error loading recordings for person!"); + + recordings + .iter() + .map(|recording| self.get_recording_description_for_recording(recording.clone())) + .collect() + } + pub fn delete_recording(&self, id: i64) { diesel::delete(recordings::table.filter(recordings::id.eq(id))) .execute(&self.c) diff --git a/src/database/models.rs b/src/database/models.rs index e36f27c..09371cd 100644 --- a/src/database/models.rs +++ b/src/database/models.rs @@ -135,6 +135,18 @@ pub struct RecordingDescription { pub performances: Vec, } +impl RecordingDescription { + pub fn get_performers(&self) -> String { + let texts: Vec = self + .performances + .iter() + .map(|performance| performance.get_title()) + .collect(); + + texts.join(", ") + } +} + #[derive(Debug, Clone)] pub struct RecordingInsertion { pub recording: Recording, diff --git a/src/window.rs b/src/window.rs index 7848e50..9dda915 100644 --- a/src/window.rs +++ b/src/window.rs @@ -260,7 +260,12 @@ impl Window { self.backend.get_work_descriptions( person.id, clone!(@strong self as self_ => move |works| { - self_.clone().set_state(Person(works, Vec::new())); + self_.backend.get_recordings_for_person( + person.id, + clone!(@strong self_ => move |recordings| { + self_.clone().set_state(Person(works.clone(), recordings)); + }), + ); }), ); @@ -273,6 +278,10 @@ impl Window { self.work_list.remove(&child); } + for child in self.recording_list.get_children() { + self.recording_list.remove(&child); + } + if works.is_empty() { self.work_box.hide(); } else { @@ -293,6 +302,28 @@ impl Window { self.recording_box.show(); } + for (index, recording) in recordings.iter().enumerate() { + let work_label = gtk::Label::new(Some(&format!( + "{}: {}", + recording.work.composer.name_fl(), + recording.work.title + ))); + + work_label.set_halign(gtk::Align::Start); + + let performers_label = gtk::Label::new(Some(&recording.get_performers())); + performers_label.set_opacity(0.5); + performers_label.set_halign(gtk::Align::Start); + + let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); + vbox.add(&work_label); + vbox.add(&performers_label); + + let row = SelectorRow::new(index.try_into().unwrap(), &vbox); + row.show_all(); + self.recording_list.insert(&row, -1); + } + self.content_stack.set_visible_child_name("content"); self.stack.set_visible_child_name("person_screen"); self.leaflet.set_visible_child_name("content");