diff --git a/backend/src/lib.rs b/backend/src/lib.rs index 1f1797f..f6ef3ff 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -2,13 +2,10 @@ use gio::prelude::*; use log::warn; use musicus_client::{Client, LoginData}; use musicus_database::DbThread; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::path::PathBuf; use std::rc::Rc; -use tokio::sync::{ - broadcast, - broadcast::Sender, -}; +use tokio::sync::{broadcast, broadcast::Sender}; pub use musicus_client as client; pub use musicus_database as db; @@ -52,6 +49,9 @@ pub struct Backend { /// Access to GSettings. settings: gio::Settings, + /// Whether the server should be used by default when searching for or changing items. + use_server: Cell, + /// The current path to the music library, which is used by the player and the database. This /// is guaranteed to be Some, when the state is set to BackendState::Ready. music_library_path: RefCell>, @@ -83,6 +83,7 @@ impl Backend { Backend { state_sender, settings: gio::Settings::new("de.johrpan.musicus"), + use_server: Cell::new(true), music_library_path: RefCell::new(None), library_updated_sender, database: RefCell::new(None), @@ -127,6 +128,16 @@ impl Backend { Ok(()) } + /// Whether the server should be used by default. + pub fn use_server(&self) -> bool { + self.use_server.get() + } + + /// Set whether the server should be used by default. + pub fn set_use_server(&self, enabled: bool) { + self.use_server.set(enabled); + } + /// Set the URL of the Musicus server to connect to. pub fn set_server_url(&self, url: &str) { if let Err(err) = self.settings.set_string("server-url", url) { diff --git a/musicus/src/editors/ensemble.rs b/musicus/src/editors/ensemble.rs index 44e77e9..fe58d8a 100644 --- a/musicus/src/editors/ensemble.rs +++ b/musicus/src/editors/ensemble.rs @@ -16,7 +16,7 @@ pub struct EnsembleEditor { editor: Editor, name: EntryRow, - upload: UploadSection, + upload: Rc, } impl Screen, Ensemble> for EnsembleEditor { @@ -33,7 +33,7 @@ impl Screen, Ensemble> for EnsembleEditor { list.append(&name.widget); let section = Section::new(&gettext("General"), &list); - let upload = UploadSection::new(); + let upload = UploadSection::new(Rc::clone(&handle.backend)); editor.add_content(§ion.widget); editor.add_content(&upload.widget); diff --git a/musicus/src/editors/instrument.rs b/musicus/src/editors/instrument.rs index a8bf724..6d62a2e 100644 --- a/musicus/src/editors/instrument.rs +++ b/musicus/src/editors/instrument.rs @@ -16,7 +16,7 @@ pub struct InstrumentEditor { editor: Editor, name: EntryRow, - upload: UploadSection, + upload: Rc, } impl Screen, Instrument> for InstrumentEditor { @@ -33,7 +33,7 @@ impl Screen, Instrument> for InstrumentEditor { list.append(&name.widget); let section = Section::new(&gettext("General"), &list); - let upload = UploadSection::new(); + let upload = UploadSection::new(Rc::clone(&handle.backend)); editor.add_content(§ion.widget); editor.add_content(&upload.widget); diff --git a/musicus/src/editors/person.rs b/musicus/src/editors/person.rs index 0839c90..eeb679d 100644 --- a/musicus/src/editors/person.rs +++ b/musicus/src/editors/person.rs @@ -17,7 +17,7 @@ pub struct PersonEditor { editor: Editor, first_name: EntryRow, last_name: EntryRow, - upload: UploadSection, + upload: Rc, } impl Screen, Person> for PersonEditor { @@ -37,7 +37,7 @@ impl Screen, Person> for PersonEditor { list.append(&last_name.widget); let section = Section::new(&gettext("General"), &list); - let upload = UploadSection::new(); + let upload = UploadSection::new(Rc::clone(&handle.backend)); editor.add_content(§ion.widget); editor.add_content(&upload.widget); diff --git a/musicus/src/editors/recording.rs b/musicus/src/editors/recording.rs index a9c9b22..89b55b0 100644 --- a/musicus/src/editors/recording.rs +++ b/musicus/src/editors/recording.rs @@ -45,6 +45,8 @@ impl Screen, Recording> for RecordingEditor { get_widget!(builder, gtk::Frame, performance_frame); get_widget!(builder, gtk::Button, add_performer_button); + upload_switch.set_active(handle.backend.use_server()); + let performance_list = List::new(); performance_frame.set_child(Some(&performance_list.widget)); diff --git a/musicus/src/editors/work.rs b/musicus/src/editors/work.rs index 02d3e83..708c85b 100644 --- a/musicus/src/editors/work.rs +++ b/musicus/src/editors/work.rs @@ -97,6 +97,8 @@ impl Screen, Work> for WorkEditor { None => (generate_id(), None, Vec::new(), Vec::new()), }; + upload_switch.set_active(handle.backend.use_server()); + let this = Rc::new(Self { handle, widget, diff --git a/musicus/src/import/import_screen.rs b/musicus/src/import/import_screen.rs index 4b998a5..07aeae6 100644 --- a/musicus/src/import/import_screen.rs +++ b/musicus/src/import/import_screen.rs @@ -119,6 +119,8 @@ impl Screen, ()> for ImportScreen { get_widget!(builder, gtk::Button, select_button); get_widget!(builder, gtk::Button, add_button); + server_check_button.set_active(handle.backend.use_server()); + let this = Rc::new(Self { handle, session, @@ -136,6 +138,7 @@ impl Screen, ()> for ImportScreen { })); this.server_check_button.connect_toggled(clone!(@weak this => move |_| { + this.handle.backend.set_use_server(this.server_check_button.get_active()); this.load_matches(); })); diff --git a/musicus/src/import/medium_editor.rs b/musicus/src/import/medium_editor.rs index f48e748..14e663d 100644 --- a/musicus/src/import/medium_editor.rs +++ b/musicus/src/import/medium_editor.rs @@ -47,6 +47,8 @@ impl Screen<(Arc, Option), Medium> for MediumEditor { get_widget!(builder, gtk::Button, try_again_button); get_widget!(builder, gtk::Button, cancel_button); + publish_switch.set_active(handle.backend.use_server()); + let list = List::new(); frame.set_child(Some(&list.widget)); @@ -100,6 +102,10 @@ impl Screen<(Arc, Option), Medium> for MediumEditor { }); })); + this.publish_switch.connect_property_state_notify(clone!(@weak this => move |_| { + this.handle.backend.set_use_server(this.publish_switch.get_state()); + })); + this.track_set_list .set_make_widget_cb(clone!(@weak this => move |index| { let track_set = &this.track_sets.borrow()[index]; diff --git a/musicus/src/selectors/ensemble.rs b/musicus/src/selectors/ensemble.rs index cb889c3..d969a7e 100644 --- a/musicus/src/selectors/ensemble.rs +++ b/musicus/src/selectors/ensemble.rs @@ -20,7 +20,7 @@ impl Screen<(), Ensemble> for EnsembleSelector { fn new(_: (), handle: NavigationHandle) -> Rc { // Create UI - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select ensemble")); let this = Rc::new(Self { diff --git a/musicus/src/selectors/instrument.rs b/musicus/src/selectors/instrument.rs index bc70c62..5ce242b 100644 --- a/musicus/src/selectors/instrument.rs +++ b/musicus/src/selectors/instrument.rs @@ -20,7 +20,7 @@ impl Screen<(), Instrument> for InstrumentSelector { fn new(_: (), handle: NavigationHandle) -> Rc { // Create UI - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select instrument")); let this = Rc::new(Self { diff --git a/musicus/src/selectors/medium.rs b/musicus/src/selectors/medium.rs index 6804977..a8c04ad 100644 --- a/musicus/src/selectors/medium.rs +++ b/musicus/src/selectors/medium.rs @@ -35,7 +35,7 @@ impl Screen<(), Medium> for MediumSelector { fn new(_: (), handle: NavigationHandle) -> Rc { // Create UI - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select performer")); let this = Rc::new(Self { @@ -127,7 +127,7 @@ struct MediumSelectorMediumScreen { impl Screen for MediumSelectorMediumScreen { fn new(poe: PersonOrEnsemble, handle: NavigationHandle) -> Rc { - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select medium")); selector.set_subtitle(&poe.get_title()); diff --git a/musicus/src/selectors/person.rs b/musicus/src/selectors/person.rs index d6adb5a..87e2a82 100644 --- a/musicus/src/selectors/person.rs +++ b/musicus/src/selectors/person.rs @@ -20,7 +20,7 @@ impl Screen<(), Person> for PersonSelector { fn new(_: (), handle: NavigationHandle) -> Rc { // Create UI - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select person")); let this = Rc::new(Self { diff --git a/musicus/src/selectors/recording.rs b/musicus/src/selectors/recording.rs index f32b82a..33bd320 100644 --- a/musicus/src/selectors/recording.rs +++ b/musicus/src/selectors/recording.rs @@ -19,7 +19,7 @@ impl Screen<(), Recording> for RecordingSelector { fn new(_: (), handle: NavigationHandle) -> Rc { // Create UI - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select composer")); let this = Rc::new(Self { @@ -109,7 +109,7 @@ struct RecordingSelectorWorkScreen { impl Screen for RecordingSelectorWorkScreen { fn new(person: Person, handle: NavigationHandle) -> Rc { - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select work")); selector.set_subtitle(&person.name_fl()); @@ -174,7 +174,7 @@ struct RecordingSelectorRecordingScreen { impl Screen for RecordingSelectorRecordingScreen { fn new(work: Work, handle: NavigationHandle) -> Rc { - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select recording")); selector.set_subtitle(&work.get_title()); diff --git a/musicus/src/selectors/selector.rs b/musicus/src/selectors/selector.rs index f9e7f12..19bb11b 100644 --- a/musicus/src/selectors/selector.rs +++ b/musicus/src/selectors/selector.rs @@ -2,7 +2,7 @@ use crate::widgets::List; use glib::clone; use gtk::prelude::*; use gtk_macros::get_widget; -use musicus_backend::Result; +use musicus_backend::{Backend, Result}; use std::cell::RefCell; use std::future::Future; use std::pin::Pin; @@ -12,6 +12,7 @@ use std::rc::Rc; /// database and to search within the list. pub struct Selector { pub widget: gtk::Box, + backend: Rc, title_label: gtk::Label, subtitle_label: gtk::Label, search_entry: gtk::SearchEntry, @@ -28,8 +29,9 @@ pub struct Selector { } impl Selector { - /// Create a new selector. - pub fn new() -> Rc { + /// Create a new selector. `use_server` is used to decide whether to search + /// online initially. + pub fn new(backend: Rc) -> Rc { // Create UI let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/selector.ui"); @@ -50,6 +52,7 @@ impl Selector { let this = Rc::new(Self { widget, + backend, title_label, subtitle_label, search_entry, @@ -85,7 +88,10 @@ impl Selector { this.server_check_button .connect_toggled(clone!(@strong this => move |_| { - if this.server_check_button.get_active() { + let active = this.server_check_button.get_active(); + this.backend.set_use_server(active); + + if active { this.clone().load_online(); } else { this.clone().load_local(); @@ -117,7 +123,11 @@ impl Selector { })); // Initialize - this.clone().load_online(); + if this.backend.use_server() { + this.clone().load_online(); + } else { + this.server_check_button.set_active(false); + } this } diff --git a/musicus/src/selectors/work.rs b/musicus/src/selectors/work.rs index 3b3cb75..5355886 100644 --- a/musicus/src/selectors/work.rs +++ b/musicus/src/selectors/work.rs @@ -19,7 +19,7 @@ impl Screen<(), Work> for WorkSelector { fn new(_: (), handle: NavigationHandle) -> Rc { // Create UI - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select composer")); let this = Rc::new(Self { @@ -99,7 +99,7 @@ struct WorkSelectorWorkScreen { impl Screen for WorkSelectorWorkScreen { fn new(person: Person, handle: NavigationHandle) -> Rc { - let selector = Selector::::new(); + let selector = Selector::::new(Rc::clone(&handle.backend)); selector.set_title(&gettext("Select work")); selector.set_subtitle(&person.name_fl()); diff --git a/musicus/src/widgets/upload_section.rs b/musicus/src/widgets/upload_section.rs index 90718fa..b3500e9 100644 --- a/musicus/src/widgets/upload_section.rs +++ b/musicus/src/widgets/upload_section.rs @@ -1,26 +1,30 @@ use super::Section; - use gettextrs::gettext; +use glib::clone; use libadwaita::prelude::*; +use musicus_backend::Backend; +use std::rc::Rc; /// A section showing a switch to enable uploading an item. pub struct UploadSection { /// The GTK widget of the wrapped section. pub widget: gtk::Box, + backend: Rc, + /// The upload switch. switch: gtk::Switch, } impl UploadSection { /// Create a new upload section which will be initially switched on. - pub fn new() -> Self { + pub fn new(backend: Rc) -> Rc { let list = gtk::ListBoxBuilder::new() .selection_mode(gtk::SelectionMode::None) .build(); let switch = gtk::SwitchBuilder::new() - .active(true) + .active(backend.use_server()) .valign(gtk::Align::Center) .build(); @@ -35,10 +39,17 @@ impl UploadSection { let section = Section::new(&gettext("Upload"), &list); - Self { + let this = Rc::new(Self { widget: section.widget.clone(), + backend, switch, - } + }); + + this.switch.connect_property_state_notify(clone!(@weak this => move |_| { + this.backend.set_use_server(this.switch.get_state()); + })); + + this } /// Return whether the user has enabled the upload switch.