mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
Add work details screen
This commit is contained in:
parent
d741f463f5
commit
b2ab93cefa
3 changed files with 118 additions and 0 deletions
|
|
@ -19,6 +19,7 @@ enum BackendAction {
|
||||||
UpdateRecording(RecordingInsertion, Sender<Result<(), String>>),
|
UpdateRecording(RecordingInsertion, Sender<Result<(), String>>),
|
||||||
GetRecordingsForPerson(i64, Sender<Vec<RecordingDescription>>),
|
GetRecordingsForPerson(i64, Sender<Vec<RecordingDescription>>),
|
||||||
GetRecordingsForEnsemble(i64, Sender<Vec<RecordingDescription>>),
|
GetRecordingsForEnsemble(i64, Sender<Vec<RecordingDescription>>),
|
||||||
|
GetRecordingsForWork(i64, Sender<Vec<RecordingDescription>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
use BackendAction::*;
|
use BackendAction::*;
|
||||||
|
|
@ -140,6 +141,12 @@ impl Backend {
|
||||||
.send(recordings)
|
.send(recordings)
|
||||||
.expect("Failed to send result from database thread!");
|
.expect("Failed to send result from database thread!");
|
||||||
}
|
}
|
||||||
|
GetRecordingsForWork(id, sender) => {
|
||||||
|
let recordings = db.get_recordings_for_work(id);
|
||||||
|
sender
|
||||||
|
.send(recordings)
|
||||||
|
.expect("Failed to send result from database thread!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -421,4 +428,22 @@ impl Backend {
|
||||||
.send(GetRecordingsForEnsemble(id, sender))
|
.send(GetRecordingsForEnsemble(id, sender))
|
||||||
.expect("Failed to send action to database thread!");
|
.expect("Failed to send action to database thread!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_recordings_for_work<F: Fn(Vec<RecordingDescription>) -> () + 'static>(
|
||||||
|
&self,
|
||||||
|
id: i64,
|
||||||
|
callback: F,
|
||||||
|
) {
|
||||||
|
let (sender, receiver) =
|
||||||
|
glib::MainContext::channel::<Vec<RecordingDescription>>(glib::PRIORITY_DEFAULT);
|
||||||
|
|
||||||
|
receiver.attach(None, move |result| {
|
||||||
|
callback(result);
|
||||||
|
glib::Continue(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.action_sender
|
||||||
|
.send(GetRecordingsForWork(id, sender))
|
||||||
|
.expect("Failed to send action to database thread!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -364,6 +364,20 @@ impl Database {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_recordings_for_work(&self, id: i64) -> Vec<RecordingDescription> {
|
||||||
|
let recordings = recordings::table
|
||||||
|
.inner_join(works::table.on(works::id.eq(recordings::work)))
|
||||||
|
.filter(works::id.eq(id))
|
||||||
|
.select(recordings::table::all_columns())
|
||||||
|
.load::<Recording>(&self.c)
|
||||||
|
.expect("Error loading recordings for work!");
|
||||||
|
|
||||||
|
recordings
|
||||||
|
.iter()
|
||||||
|
.map(|recording| self.get_recording_description_for_recording(recording.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delete_recording(&self, id: i64) {
|
pub fn delete_recording(&self, id: i64) {
|
||||||
diesel::delete(recordings::table.filter(recordings::id.eq(id)))
|
diesel::delete(recordings::table.filter(recordings::id.eq(id)))
|
||||||
.execute(&self.c)
|
.execute(&self.c)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,12 @@ enum WindowState {
|
||||||
String,
|
String,
|
||||||
),
|
),
|
||||||
WorkScreenLoading(PersonOrEnsemble, WorkDescription),
|
WorkScreenLoading(PersonOrEnsemble, WorkDescription),
|
||||||
|
WorkScreen(
|
||||||
|
PersonOrEnsemble,
|
||||||
|
WorkDescription,
|
||||||
|
Vec<RecordingDescription>,
|
||||||
|
String,
|
||||||
|
),
|
||||||
RecordingScreenLoading(PersonOrEnsemble, RecordingDescription),
|
RecordingScreenLoading(PersonOrEnsemble, RecordingDescription),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,11 +66,13 @@ pub struct Window {
|
||||||
overview_recording_list: gtk::ListBox,
|
overview_recording_list: gtk::ListBox,
|
||||||
work_details_header: libhandy::HeaderBar,
|
work_details_header: libhandy::HeaderBar,
|
||||||
work_details_stack: gtk::Stack,
|
work_details_stack: gtk::Stack,
|
||||||
|
work_details_recording_list: gtk::ListBox,
|
||||||
recording_details_header: libhandy::HeaderBar,
|
recording_details_header: libhandy::HeaderBar,
|
||||||
recording_details_stack: gtk::Stack,
|
recording_details_stack: gtk::Stack,
|
||||||
sidebar_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
|
sidebar_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
|
||||||
overview_work_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
|
overview_work_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
|
||||||
overview_recording_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
|
overview_recording_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
|
||||||
|
work_details_recording_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
|
@ -90,6 +98,7 @@ impl Window {
|
||||||
get_widget!(builder, libhandy::HeaderBar, work_details_header);
|
get_widget!(builder, libhandy::HeaderBar, work_details_header);
|
||||||
get_widget!(builder, gtk::Button, work_details_back_button);
|
get_widget!(builder, gtk::Button, work_details_back_button);
|
||||||
get_widget!(builder, gtk::Stack, work_details_stack);
|
get_widget!(builder, gtk::Stack, work_details_stack);
|
||||||
|
get_widget!(builder, gtk::ListBox, work_details_recording_list);
|
||||||
get_widget!(builder, libhandy::HeaderBar, recording_details_header);
|
get_widget!(builder, libhandy::HeaderBar, recording_details_header);
|
||||||
get_widget!(builder, gtk::Button, recording_details_back_button);
|
get_widget!(builder, gtk::Button, recording_details_back_button);
|
||||||
get_widget!(builder, gtk::Stack, recording_details_stack);
|
get_widget!(builder, gtk::Stack, recording_details_stack);
|
||||||
|
|
@ -115,11 +124,13 @@ impl Window {
|
||||||
overview_recording_list: overview_recording_list,
|
overview_recording_list: overview_recording_list,
|
||||||
work_details_header: work_details_header,
|
work_details_header: work_details_header,
|
||||||
work_details_stack: work_details_stack,
|
work_details_stack: work_details_stack,
|
||||||
|
work_details_recording_list: work_details_recording_list,
|
||||||
recording_details_header: recording_details_header,
|
recording_details_header: recording_details_header,
|
||||||
recording_details_stack: recording_details_stack,
|
recording_details_stack: recording_details_stack,
|
||||||
sidebar_list_row_activated_handler_id: Cell::new(None),
|
sidebar_list_row_activated_handler_id: Cell::new(None),
|
||||||
overview_work_list_row_activated_handler_id: Cell::new(None),
|
overview_work_list_row_activated_handler_id: Cell::new(None),
|
||||||
overview_recording_list_row_activated_handler_id: Cell::new(None),
|
overview_recording_list_row_activated_handler_id: Cell::new(None),
|
||||||
|
work_details_recording_list_row_activated_handler_id: Cell::new(None),
|
||||||
});
|
});
|
||||||
|
|
||||||
action!(
|
action!(
|
||||||
|
|
@ -250,6 +261,9 @@ impl Window {
|
||||||
WorkScreenLoading(poe, _) => {
|
WorkScreenLoading(poe, _) => {
|
||||||
result.clone().set_state(OverviewScreenLoading(poe));
|
result.clone().set_state(OverviewScreenLoading(poe));
|
||||||
},
|
},
|
||||||
|
WorkScreen(poe, _, _, _) => {
|
||||||
|
result.clone().set_state(OverviewScreenLoading(poe));
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
@ -533,11 +547,76 @@ impl Window {
|
||||||
.set_title(Some(&work.composer.name_fl()));
|
.set_title(Some(&work.composer.name_fl()));
|
||||||
self.work_details_header.set_subtitle(Some(&work.title));
|
self.work_details_header.set_subtitle(Some(&work.title));
|
||||||
|
|
||||||
|
self.backend.get_recordings_for_work(
|
||||||
|
work.id,
|
||||||
|
clone!(@strong self as self_ => move |recordings| {
|
||||||
|
self_.clone().set_state(WorkScreen(poe.clone(), work.clone(), recordings, String::new()));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
self.work_details_stack.set_visible_child_name("loading");
|
self.work_details_stack.set_visible_child_name("loading");
|
||||||
self.main_stack
|
self.main_stack
|
||||||
.set_visible_child_name("work_details_screen");
|
.set_visible_child_name("work_details_screen");
|
||||||
self.leaflet.set_visible_child_name("content");
|
self.leaflet.set_visible_child_name("content");
|
||||||
}
|
}
|
||||||
|
WorkScreen(poe, work, recordings, search) => {
|
||||||
|
for child in self.work_details_recording_list.get_children() {
|
||||||
|
self.work_details_recording_list.remove(&child);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, recording) in recordings.iter().enumerate() {
|
||||||
|
let work_text = recording.work.get_title();
|
||||||
|
let performers_text = recording.get_performers();
|
||||||
|
|
||||||
|
if search.is_empty()
|
||||||
|
|| (work_text.to_lowercase().contains(&search)
|
||||||
|
|| performers_text.to_lowercase().contains(&search))
|
||||||
|
{
|
||||||
|
let work_label = gtk::Label::new(Some(&work_text));
|
||||||
|
|
||||||
|
work_label.set_ellipsize(pango::EllipsizeMode::End);
|
||||||
|
work_label.set_halign(gtk::Align::Start);
|
||||||
|
|
||||||
|
let performers_label = gtk::Label::new(Some(&performers_text));
|
||||||
|
performers_label.set_ellipsize(pango::EllipsizeMode::End);
|
||||||
|
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.work_details_recording_list.insert(&row, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.work_details_recording_list_row_activated_handler_id.take() {
|
||||||
|
Some(id) => self.work_details_recording_list.disconnect(id),
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler_id = self.work_details_recording_list.connect_row_activated(
|
||||||
|
clone!(@strong self as self_, @strong recordings, @strong poe => move |_, row| {
|
||||||
|
self_.overview_work_list.unselect_all();
|
||||||
|
|
||||||
|
let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap();
|
||||||
|
let index: usize = row.get_index().try_into().unwrap();
|
||||||
|
let recording = recordings[index].clone();
|
||||||
|
|
||||||
|
self_.clone().set_state(RecordingScreenLoading(poe.clone(), recording));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.work_details_recording_list_row_activated_handler_id
|
||||||
|
.set(Some(handler_id));
|
||||||
|
|
||||||
|
self.work_details_stack.set_visible_child_name("content");
|
||||||
|
self.main_stack
|
||||||
|
.set_visible_child_name("work_details_screen");
|
||||||
|
self.leaflet.set_visible_child_name("content");
|
||||||
|
}
|
||||||
RecordingScreenLoading(poe, recording) => {
|
RecordingScreenLoading(poe, recording) => {
|
||||||
self.recording_details_header
|
self.recording_details_header
|
||||||
.set_title(Some(&recording.work.get_title()));
|
.set_title(Some(&recording.work.get_title()));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue