Compare commits

..

No commits in common. "de54ec676f9eea35d520cb82cd0ef5fafeb68ded" and "c3c144e0359de7546c37385aa27853b4921bcb1f" have entirely different histories.

6 changed files with 41 additions and 139 deletions

View File

@ -4,14 +4,5 @@
.settings-view { .settings-view {
margin: 8px; margin: 8px;
padding: 4px;
background-color: @view_bg_color; background-color: @view_bg_color;
} }
.settings-view {
padding: 8px;
}
.preference-item > suffixes {
margin: 4px;
}

View File

@ -23,12 +23,12 @@ use gtk::STYLE_PROVIDER_PRIORITY_USER;
use kifu_core::{Config, Core}; use kifu_core::{Config, Core};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use crate::{view_models::HomeViewModel, view_models::SettingsViewModel}; use crate::view_models::SettingsViewModel;
#[derive(Clone)] #[derive(Clone)]
enum AppView { enum AppView {
Settings(SettingsViewModel), Settings(SettingsViewModel),
Home(HomeViewModel), Home,
} }
// An application window should generally contain // An application window should generally contain
@ -87,27 +87,11 @@ impl AppWindow {
} }
pub fn open_settings(&self) { pub fn open_settings(&self) {
let view_model = SettingsViewModel::new(&self.window, self.core.clone(), { let view_model = SettingsViewModel::new(&self.window, self.core.clone());
let s = self.clone();
move || {
s.close_overlay();
}
});
self.panel_overlay.add_overlay(&view_model.widget); self.panel_overlay.add_overlay(&view_model.widget);
*self.settings_view_model.write().unwrap() = Some(view_model); *self.settings_view_model.write().unwrap() = Some(view_model);
} }
pub fn close_overlay(&self) {
let mut vm = self.settings_view_model.write().unwrap();
match *vm {
Some(ref mut view_model) => {
self.panel_overlay.remove_overlay(&view_model.widget);
*vm = None;
}
None => {}
}
}
fn setup_window(app: &adw::Application) -> adw::ApplicationWindow { fn setup_window(app: &adw::Application) -> adw::ApplicationWindow {
let window = adw::ApplicationWindow::builder() let window = adw::ApplicationWindow::builder()
.application(app) .application(app)
@ -152,7 +136,7 @@ impl AppWindow {
.child(&nothing_page) .child(&nothing_page)
.build(), .build(),
); );
content.push(AppView::Home(HomeViewModel::new(core.clone()))); content.push(AppView::Home);
/* /*
match *core.library() { match *core.library() {

View File

@ -1,8 +1,6 @@
use adw::prelude::*; use adw::prelude::*;
use async_std::channel::Receiver;
use async_std::task::spawn;
use gio::ActionEntry; use gio::ActionEntry;
use kifu_core::{Config, ConfigOption, Core, CoreNotification, LibraryPath, Observable}; use kifu_core::{Config, ConfigOption, Core};
use kifu_gtk::{ use kifu_gtk::{
perftrace, perftrace,
// ui::{ConfigurationPage, Home, PlayingField}, // ui::{ConfigurationPage, Home, PlayingField},
@ -16,29 +14,6 @@ const APP_ID_PROD: &str = "com.luminescent-dreams.kifu-gtk";
const RESOURCE_BASE_PATH: &str = "/com/luminescent-dreams/kifu-gtk/"; const RESOURCE_BASE_PATH: &str = "/com/luminescent-dreams/kifu-gtk/";
async fn handler(notifications: Receiver<CoreNotification>, app_id: String) {
loop {
let msg = notifications.recv().await;
match msg {
Ok(CoreNotification::ConfigurationUpdated(cfg)) => {
println!("commiting configuration");
let settings = gio::Settings::new(&app_id);
if let Some(LibraryPath(library_path)) = cfg.get() {
let _ = settings.set_string(
"library-path",
&library_path.into_os_string().into_string().unwrap(),
);
}
}
Ok(_) => println!("discarding message"),
Err(err) => {
println!("shutting down handler with error: {:?}", err);
return;
}
}
}
}
/* /*
fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse) { fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse) {
let playing_field = Arc::new(RwLock::new(None)); let playing_field = Arc::new(RwLock::new(None));
@ -132,12 +107,6 @@ fn main() {
let core = Core::new(config); let core = Core::new(config);
spawn({
let notifier = core.subscribe();
let app_id = app_id.to_owned();
handler(notifier, app_id)
});
/* /*
let core_handle = runtime.spawn({ let core_handle = runtime.spawn({
let core = core.clone(); let core = core.clone();
@ -152,13 +121,14 @@ fn main() {
.resource_base_path("/com/luminescent-dreams/kifu-gtk") .resource_base_path("/com/luminescent-dreams/kifu-gtk")
.build(); .build();
app.connect_activate({ app.connect_activate({
let runtime = runtime.clone(); let runtime = runtime.clone();
move |app| { move |app| {
let mut app_window = AppWindow::new(app, core.clone()); let mut app_window = AppWindow::new(app, core.clone());
match *core.library() { match *core.library() {
Some(_) => {} Some(_) => {},
None => app_window.open_settings(), None => app_window.open_settings(),
} }

View File

@ -16,25 +16,23 @@ You should have received a copy of the GNU General Public License along with Kif
use crate::LocalObserver; use crate::LocalObserver;
use kifu_core::{Core, CoreNotification}; use kifu_core::{Core, CoreNotification};
use std::sync::Arc;
/// Home controls the view that the user sees when starting the application if there are no games in progress. It provides a window into the database, showing a list of recently recorded games. It also provides the UI for starting a new game. This will render an empty database view if the user hasn't configured a database yet. /// Home controls the view that the user sees when starting the application if there are no games in progress. It provides a window into the database, showing a list of recently recorded games. It also provides the UI for starting a new game. This will render an empty database view if the user hasn't configured a database yet.
#[derive(Clone)]
pub struct HomeViewModel { pub struct HomeViewModel {
core: Core, core: Core,
notification_observer: Arc<LocalObserver<CoreNotification>>, notification_observer: LocalObserver<CoreNotification>,
widget: gtk::Box, widget: gtk::Box,
} }
impl HomeViewModel { impl HomeViewModel {
pub fn new(core: Core) -> Self { fn new(core: Core) -> Self {
let notification_observer = LocalObserver::new(&core, |msg| { let notification_observer = LocalObserver::new(&core, |msg| {
println!("HomeViewModel handler called with message: {:?}", msg) println!("DatabaseViewModelHandler called with message: {:?}", msg)
}); });
Self { Self {
core, core,
notification_observer: Arc::new(notification_observer), notification_observer,
widget: gtk::Box::new(gtk::Orientation::Horizontal, 0), widget: gtk::Box::new(gtk::Orientation::Horizontal, 0),
} }
} }

View File

@ -18,7 +18,7 @@ use crate::{views, views::SettingsView, LocalObserver};
use async_std::task::spawn; use async_std::task::spawn;
use gtk::prelude::*; use gtk::prelude::*;
use kifu_core::{Config, Core, CoreNotification}; use kifu_core::{Config, Core, CoreNotification};
use std::{sync::Arc, rc::Rc}; use std::sync::Arc;
/// SettingsViewModel /// SettingsViewModel
/// ///
@ -35,39 +35,24 @@ pub struct SettingsViewModel {
} }
impl SettingsViewModel { impl SettingsViewModel {
pub fn new(parent: &impl IsA<gtk::Window>, core: Core, on_close: impl Fn() + 'static) -> Self { pub fn new(parent: &impl IsA<gtk::Window>, core: Core) -> Self {
let on_close = Arc::new(on_close);
let notification_observer = LocalObserver::new(&core, |msg| { let notification_observer = LocalObserver::new(&core, |msg| {
println!("SettingsViewModel called with message: {:?}", msg) println!("SettingsViewModel called with message: {:?}", msg)
}); });
let config = core.get_config(); let config = core.get_config();
let widget = SettingsView::new(
parent,
config,
{
let core = core.clone();
let on_close = on_close.clone();
move |new_config| {
spawn({
let core = core.clone();
on_close();
async move {
println!("running set_config in the background");
core.set_config(new_config).await;
}
});
}
},
move || on_close(),
);
Self { Self {
core: core.clone(), core: core.clone(),
notification_observer: Arc::new(notification_observer), notification_observer: Arc::new(notification_observer),
widget, widget: SettingsView::new(parent, config, {
&|new_config| {
spawn({
let core = core.clone();
async move { core.set_config(new_config).await }
});
}
}),
} }
} }
} }

View File

@ -14,7 +14,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License along with Kifu. If not, see <https://www.gnu.org/licenses/>. You should have received a copy of the GNU General Public License along with Kifu. If not, see <https://www.gnu.org/licenses/>.
*/ */
use std::{cell::RefCell, path::Path, rc::Rc, borrow::Cow}; use std::{cell::RefCell, path::Path, rc::Rc};
use adw::prelude::*; use adw::prelude::*;
use glib::Object; use glib::Object;
@ -23,48 +23,35 @@ use kifu_core::{Config, ConfigOption, LibraryPath};
fn library_chooser_row( fn library_chooser_row(
parent: &impl IsA<gtk::Window>, parent: &impl IsA<gtk::Window>,
library_path: Option<LibraryPath>,
on_library_chosen: Rc<impl Fn(ConfigOption) + 'static>, on_library_chosen: Rc<impl Fn(ConfigOption) + 'static>,
) -> adw::ActionRow { ) -> adw::ActionRow {
let dialog = gtk::FileDialog::builder().build(); let dialog = gtk::FileDialog::builder().build();
let dialog_button = gtk::Button::builder() let dialog_button = gtk::Button::builder()
.child(&gtk::Label::new(Some("Select Library"))) .child(&gtk::Label::new(Some("Select Library")))
.valign(gtk::Align::Center)
.build(); .build();
let parent = parent.clone(); let parent = parent.clone();
dialog_button.connect_clicked(move |_| {
let library_row = adw::ActionRow::builder()
.title("Library Path")
.subtitle(library_path.map(|LibraryPath(path)| path.to_string_lossy().into_owned()).unwrap_or("No library set".to_owned()))
.css_classes(["preference-item"])
.build();
dialog_button.connect_clicked({
let library_row = library_row.clone();
move |_| {
let no_parent: Option<&gtk::Window> = None; let no_parent: Option<&gtk::Window> = None;
let not_cancellable: Option<&gio::Cancellable> = None; let not_cancellable: Option<&gio::Cancellable> = None;
let on_library_chosen = on_library_chosen.clone(); let on_library_chosen = on_library_chosen.clone();
dialog.select_folder(no_parent, not_cancellable, { dialog.select_folder(no_parent, not_cancellable, move |result| match result {
let library_row = library_row.clone();
move |result| match result {
Ok(path) => { Ok(path) => {
let path_str: String = on_library_chosen(ConfigOption::LibraryPath(LibraryPath(path.path().unwrap())))
path.path().unwrap().into_os_string().into_string().unwrap();
library_row.set_subtitle(&path_str);
on_library_chosen(ConfigOption::LibraryPath(LibraryPath(
path.path().unwrap(),
)))
} }
Err(err) => println!("Error choosing a library: {:?}", err), Err(err) => println!("Error choosing a library: {:?}", err),
}
}); });
}
}); });
let library_row = adw::ActionRow::builder()
.title("Library Path")
.subtitle("No library set")
// .child(&library_row)
.build();
library_row.add_suffix(&dialog_button); library_row.add_suffix(&dialog_button);
library_row.connect_activate(|_| println!("library row activated"));
library_row library_row
} }
@ -95,52 +82,39 @@ impl SettingsView {
pub fn new( pub fn new(
parent: &impl IsA<gtk::Window>, parent: &impl IsA<gtk::Window>,
config: Config, config: Config,
on_save: impl Fn(Config) + 'static, on_save: &impl FnOnce(Config),
on_cancel: impl Fn() + 'static,
) -> Self { ) -> Self {
let s: Self = Object::builder().build(); let s: Self = Object::builder().build();
let config = Rc::new(RefCell::new(config)); let config = Rc::new(RefCell::new(config));
let group = adw::PreferencesGroup::builder().build(); let group = adw::PreferencesGroup::builder().vexpand(true).build();
let library_row = library_chooser_row( let library_row = library_chooser_row(
parent, parent,
config.borrow().get(),
Rc::new({ Rc::new({
let config = config.clone(); let config = config.clone();
move |library_path| { move |library_path| {
config.borrow_mut().set(library_path); config.borrow_mut().set(library_path);
println!("library path changed, need to update the UI");
} }
}), }),
); );
group.add(&library_row); group.add(&library_row);
let cancel_button = gtk::Button::builder().label("Cancel").build(); let cancel_button = gtk::Button::builder().label("Cancel").build();
cancel_button.connect_clicked(move |_| on_cancel());
let save_button = gtk::Button::builder().label("Save").build(); let save_button = gtk::Button::builder().label("Save").build();
save_button.connect_clicked({
let config = config.clone();
move |_| on_save(config.borrow().clone())
});
let action_row = gtk::Box::builder() let action_row = gtk::Box::builder()
.orientation(gtk::Orientation::Horizontal) .orientation(gtk::Orientation::Horizontal)
.halign(gtk::Align::End) .halign(gtk::Align::End)
.valign(gtk::Align::End)
.build(); .build();
action_row.append(&cancel_button); action_row.append(&cancel_button);
action_row.append(&save_button); action_row.append(&save_button);
let preferences_box = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.build();
preferences_box.append(&group);
let layout = gtk::Box::builder() let layout = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical) .orientation(gtk::Orientation::Vertical)
.spacing(8) .vexpand(true)
.build(); .build();
layout.append(&preferences_box); layout.append(&group);
layout.append(&action_row); layout.append(&action_row);
s.set_child(Some(&layout)); s.set_child(Some(&layout));