2020-10-16 21:24:55 +02:00
|
|
|
use crate::backend::*;
|
|
|
|
|
use crate::dialogs::*;
|
|
|
|
|
use crate::screens::*;
|
|
|
|
|
use crate::widgets::*;
|
2020-11-01 10:13:21 +01:00
|
|
|
use futures::prelude::*;
|
2020-09-27 21:58:42 +02:00
|
|
|
use gio::prelude::*;
|
2020-09-28 15:02:19 +02:00
|
|
|
use glib::clone;
|
2020-09-27 21:58:42 +02:00
|
|
|
use gtk::prelude::*;
|
|
|
|
|
use gtk_macros::{action, get_widget};
|
2020-09-28 20:51:56 +02:00
|
|
|
use libhandy::prelude::*;
|
2020-09-28 15:02:19 +02:00
|
|
|
use std::rc::Rc;
|
2020-09-27 21:58:42 +02:00
|
|
|
|
|
|
|
|
pub struct Window {
|
2020-10-09 12:22:02 +02:00
|
|
|
backend: Rc<Backend>,
|
2020-10-16 21:24:55 +02:00
|
|
|
window: libhandy::ApplicationWindow,
|
2020-11-01 10:13:21 +01:00
|
|
|
stack: gtk::Stack,
|
2020-09-28 20:51:56 +02:00
|
|
|
leaflet: libhandy::Leaflet,
|
2020-10-16 21:24:55 +02:00
|
|
|
sidebar_box: gtk::Box,
|
|
|
|
|
poe_list: Rc<PoeList>,
|
2020-10-17 11:31:43 +02:00
|
|
|
navigator: Rc<Navigator>,
|
2020-09-27 21:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Window {
|
2020-09-28 15:02:19 +02:00
|
|
|
pub fn new(app: >k::Application) -> Rc<Self> {
|
2020-11-01 12:49:10 +01:00
|
|
|
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/window.ui");
|
2020-09-28 20:51:56 +02:00
|
|
|
|
|
|
|
|
get_widget!(builder, libhandy::ApplicationWindow, window);
|
2020-11-01 10:13:21 +01:00
|
|
|
get_widget!(builder, gtk::Stack, stack);
|
|
|
|
|
get_widget!(builder, gtk::Button, select_music_library_path_button);
|
2020-09-28 20:51:56 +02:00
|
|
|
get_widget!(builder, libhandy::Leaflet, leaflet);
|
2020-10-31 23:48:11 +01:00
|
|
|
get_widget!(builder, gtk::Button, add_button);
|
2020-10-16 21:24:55 +02:00
|
|
|
get_widget!(builder, gtk::Box, sidebar_box);
|
|
|
|
|
get_widget!(builder, gtk::Box, empty_screen);
|
|
|
|
|
|
2020-11-01 10:13:21 +01:00
|
|
|
let backend = Rc::new(Backend::new());
|
2020-11-01 19:09:31 +01:00
|
|
|
backend.clone().init();
|
|
|
|
|
|
2020-10-16 21:24:55 +02:00
|
|
|
let poe_list = PoeList::new(backend.clone());
|
2020-10-17 11:31:43 +02:00
|
|
|
let navigator = Navigator::new(&empty_screen);
|
2020-10-16 21:24:55 +02:00
|
|
|
|
|
|
|
|
let result = Rc::new(Self {
|
|
|
|
|
backend,
|
|
|
|
|
window,
|
2020-11-01 10:13:21 +01:00
|
|
|
stack,
|
2020-10-16 21:24:55 +02:00
|
|
|
leaflet,
|
|
|
|
|
sidebar_box,
|
|
|
|
|
poe_list,
|
2020-10-17 11:31:43 +02:00
|
|
|
navigator,
|
2020-09-27 21:58:42 +02:00
|
|
|
});
|
|
|
|
|
|
2020-10-16 21:24:55 +02:00
|
|
|
result.window.set_application(Some(app));
|
2020-09-28 23:33:48 +02:00
|
|
|
|
2020-11-01 10:13:21 +01:00
|
|
|
select_music_library_path_button.connect_clicked(clone!(@strong result => move |_| {
|
|
|
|
|
let dialog = gtk::FileChooserNative::new(Some("Select music library folder"), Some(&result.window), gtk::FileChooserAction::SelectFolder, None, None);
|
|
|
|
|
|
|
|
|
|
if let gtk::ResponseType::Accept = dialog.run() {
|
|
|
|
|
if let Some(path) = dialog.get_filename() {
|
|
|
|
|
let context = glib::MainContext::default();
|
|
|
|
|
let backend = result.backend.clone();
|
|
|
|
|
context.spawn_local(async move {
|
|
|
|
|
backend.set_music_library_path(path).await.unwrap();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
|
2020-10-31 23:48:11 +01:00
|
|
|
add_button.connect_clicked(clone!(@strong result => move |_| {
|
|
|
|
|
TracksEditor::new(result.backend.clone(), &result.window, clone!(@strong result => move || {
|
|
|
|
|
result.reload();
|
|
|
|
|
})).show();
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"preferences",
|
|
|
|
|
clone!(@strong result => move |_, _| {
|
|
|
|
|
Preferences::new(result.backend.clone(), &result.window).show();
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2020-09-28 15:02:19 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"add-person",
|
|
|
|
|
clone!(@strong result => move |_, _| {
|
2020-10-09 12:22:02 +02:00
|
|
|
PersonEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| {
|
2020-10-16 21:24:55 +02:00
|
|
|
result.reload();
|
2020-09-28 20:09:49 +02:00
|
|
|
})).show();
|
2020-09-28 15:02:19 +02:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2020-09-28 15:08:24 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"add-instrument",
|
|
|
|
|
clone!(@strong result => move |_, _| {
|
2020-10-09 12:22:02 +02:00
|
|
|
InstrumentEditor::new(result.backend.clone(), &result.window, None, |instrument| {
|
2020-09-28 15:08:24 +02:00
|
|
|
println!("{:?}", instrument);
|
|
|
|
|
}).show();
|
|
|
|
|
})
|
|
|
|
|
);
|
2020-09-27 21:58:42 +02:00
|
|
|
|
2020-09-28 16:00:51 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"add-work",
|
|
|
|
|
clone!(@strong result => move |_, _| {
|
2020-10-09 12:22:02 +02:00
|
|
|
WorkEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| {
|
2020-10-16 21:24:55 +02:00
|
|
|
result.reload();
|
2020-09-28 20:09:49 +02:00
|
|
|
})).show();
|
2020-09-28 16:00:51 +02:00
|
|
|
})
|
|
|
|
|
);
|
2020-09-27 21:58:42 +02:00
|
|
|
|
2020-09-28 15:14:05 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"add-ensemble",
|
|
|
|
|
clone!(@strong result => move |_, _| {
|
2020-10-16 21:24:55 +02:00
|
|
|
EnsembleEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| {
|
|
|
|
|
result.reload();
|
|
|
|
|
})).show();
|
2020-09-28 15:14:05 +02:00
|
|
|
})
|
|
|
|
|
);
|
2020-09-27 21:58:42 +02:00
|
|
|
|
2020-10-09 23:02:50 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"add-recording",
|
|
|
|
|
clone!(@strong result => move |_, _| {
|
|
|
|
|
RecordingEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| {
|
2020-10-16 21:24:55 +02:00
|
|
|
result.reload();
|
2020-10-09 23:02:50 +02:00
|
|
|
})).show();
|
|
|
|
|
})
|
|
|
|
|
);
|
2020-09-27 21:58:42 +02:00
|
|
|
|
2020-10-31 23:07:25 +01:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"add-tracks",
|
|
|
|
|
clone!(@strong result => move |_, _| {
|
|
|
|
|
TracksEditor::new(result.backend.clone(), &result.window, clone!(@strong result => move || {
|
|
|
|
|
result.reload();
|
|
|
|
|
})).show();
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2020-09-28 23:33:48 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"edit-person",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
2020-10-11 21:13:15 +02:00
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
let person = result.backend.get_person(id).await.unwrap();
|
2020-10-09 20:19:46 +02:00
|
|
|
PersonEditor::new(result.backend.clone(), &result.window, Some(person), clone!(@strong result => move |_| {
|
2020-10-16 21:24:55 +02:00
|
|
|
result.reload();
|
2020-10-09 12:22:02 +02:00
|
|
|
})).show();
|
2020-10-11 21:13:15 +02:00
|
|
|
});
|
2020-09-28 23:33:48 +02:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"delete-person",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
2020-10-11 21:13:15 +02:00
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
result.backend.delete_person(id).await.unwrap();
|
2020-10-16 21:24:55 +02:00
|
|
|
result.reload();
|
2020-10-11 21:13:15 +02:00
|
|
|
});
|
2020-09-28 23:33:48 +02:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2020-10-10 12:01:22 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"edit-ensemble",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
2020-10-11 21:13:15 +02:00
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
let ensemble = result.backend.get_ensemble(id).await.unwrap();
|
2020-10-10 12:01:22 +02:00
|
|
|
EnsembleEditor::new(result.backend.clone(), &result.window, Some(ensemble), clone!(@strong result => move |_| {
|
2020-10-16 21:24:55 +02:00
|
|
|
result.reload();
|
2020-10-10 12:01:22 +02:00
|
|
|
})).show();
|
2020-10-11 21:13:15 +02:00
|
|
|
});
|
2020-10-10 12:01:22 +02:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"delete-ensemble",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
2020-10-11 21:13:15 +02:00
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
result.backend.delete_ensemble(id).await.unwrap();
|
2020-10-16 21:24:55 +02:00
|
|
|
result.reload();
|
2020-10-11 21:13:15 +02:00
|
|
|
});
|
2020-10-10 12:01:22 +02:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2020-10-22 15:59:55 +02:00
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"edit-work",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
|
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
let work = result.backend.get_work_description(id).await.unwrap();
|
|
|
|
|
WorkEditor::new(result.backend.clone(), &result.window, Some(work), clone!(@strong result => move |_| {
|
|
|
|
|
result.reload();
|
|
|
|
|
})).show();
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"delete-work",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
|
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
result.backend.delete_work(id).await.unwrap();
|
|
|
|
|
result.reload();
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"edit-recording",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
|
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
let recording = result.backend.get_recording_description(id).await.unwrap();
|
|
|
|
|
RecordingEditor::new(result.backend.clone(), &result.window, Some(recording), clone!(@strong result => move |_| {
|
|
|
|
|
result.reload();
|
|
|
|
|
})).show();
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
action!(
|
|
|
|
|
result.window,
|
|
|
|
|
"delete-recording",
|
|
|
|
|
Some(glib::VariantTy::new("x").unwrap()),
|
|
|
|
|
clone!(@strong result => move |_, id| {
|
|
|
|
|
let id = id.unwrap().get().unwrap();
|
|
|
|
|
let result = result.clone();
|
|
|
|
|
let c = glib::MainContext::default();
|
|
|
|
|
c.spawn_local(async move {
|
|
|
|
|
result.backend.delete_recording(id).await.unwrap();
|
|
|
|
|
result.reload();
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2020-11-01 10:13:21 +01:00
|
|
|
let context = glib::MainContext::default();
|
|
|
|
|
let clone = result.clone();
|
|
|
|
|
context.spawn_local(async move {
|
|
|
|
|
let mut state_stream = clone.backend.state_stream.borrow_mut();
|
|
|
|
|
while let Some(state) = state_stream.next().await {
|
|
|
|
|
match state {
|
|
|
|
|
BackendState::NoMusicLibrary => {
|
|
|
|
|
clone.stack.set_visible_child_name("empty");
|
|
|
|
|
}
|
|
|
|
|
BackendState::Loading => {
|
|
|
|
|
clone.stack.set_visible_child_name("loading");
|
|
|
|
|
}
|
|
|
|
|
BackendState::Ready => {
|
|
|
|
|
clone.stack.set_visible_child_name("content");
|
|
|
|
|
clone.poe_list.clone().reload();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
result.leaflet.add(&result.navigator.widget);
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
.poe_list
|
|
|
|
|
.set_selected(clone!(@strong result => move |poe| {
|
|
|
|
|
result.leaflet.set_visible_child(&result.navigator.widget);
|
|
|
|
|
match poe {
|
|
|
|
|
PersonOrEnsemble::Person(person) => {
|
|
|
|
|
result.navigator.clone().replace(PersonScreen::new(result.backend.clone(), person.clone()));
|
|
|
|
|
}
|
|
|
|
|
PersonOrEnsemble::Ensemble(ensemble) => {
|
|
|
|
|
result.navigator.clone().replace(EnsembleScreen::new(result.backend.clone(), ensemble.clone()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
.sidebar_box
|
|
|
|
|
.pack_start(&result.poe_list.widget, true, true, 0);
|
|
|
|
|
|
2020-09-28 15:02:19 +02:00
|
|
|
result
|
2020-09-27 21:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn present(&self) {
|
|
|
|
|
self.window.present();
|
|
|
|
|
}
|
2020-09-28 20:09:49 +02:00
|
|
|
|
2020-10-16 21:24:55 +02:00
|
|
|
fn reload(&self) {
|
|
|
|
|
self.poe_list.clone().reload();
|
2020-10-17 11:31:43 +02:00
|
|
|
self.navigator.reset();
|
2020-10-16 21:24:55 +02:00
|
|
|
self.leaflet.set_visible_child(&self.sidebar_box);
|
2020-09-28 20:09:49 +02:00
|
|
|
}
|
2020-09-27 21:58:42 +02:00
|
|
|
}
|