Set up the settings user interface #225

Merged
savanni merged 5 commits from kifu/main-menu into main 2024-03-21 21:11:03 +00:00
5 changed files with 61 additions and 46 deletions
Showing only changes of commit 05a6dcf3af - Show all commits

View File

@ -1,3 +1,8 @@
.content { .content {
padding: 8px; padding: 8px;
} }
.settings-view {
margin: 8px;
background-color: @view_bg_color;
}

View File

@ -19,9 +19,11 @@ use gio::resources_lookup_data;
use glib::IsA; use glib::IsA;
use gtk::STYLE_PROVIDER_PRIORITY_USER; use gtk::STYLE_PROVIDER_PRIORITY_USER;
use kifu_core::{Config, Core}; use kifu_core::{Config, Core};
use std::sync::{Arc, RwLock};
use crate::view_models::SettingsViewModel; use crate::view_models::SettingsViewModel;
#[derive(Clone)]
enum AppView { enum AppView {
Settings(SettingsViewModel), Settings(SettingsViewModel),
Home, Home,
@ -31,6 +33,7 @@ enum AppView {
// - an overlay widget // - an overlay widget
// - the main content in a stack on the bottom panel of the overlay // - the main content in a stack on the bottom panel of the overlay
// - the settings and the about page in bins atop the overlay // - the settings and the about page in bins atop the overlay
#[derive(Clone)]
pub struct AppWindow { pub struct AppWindow {
pub window: adw::ApplicationWindow, pub window: adw::ApplicationWindow,
header: adw::HeaderBar, header: adw::HeaderBar,
@ -48,42 +51,14 @@ pub struct AppWindow {
// anywhere but shouldn't be part of the main application flow. // anywhere but shouldn't be part of the main application flow.
panel_overlay: gtk::Overlay, panel_overlay: gtk::Overlay,
core: Core, core: Core,
// Not liking this, but I have to keep track of the settings view model separately from
// anything else. I'll have to look into this later.
settings_view_model: Arc<RwLock<Option<SettingsViewModel>>>,
} }
impl AppWindow { impl AppWindow {
pub fn new(app: &adw::Application, core: Core) -> Self { pub fn new(app: &adw::Application, core: Core) -> Self {
/*
let stylesheet = String::from_utf8(
resources_lookup_data(
"/com/luminescent-dreams/kifu-gtk/style.css",
gio::ResourceLookupFlags::NONE,
)
.expect("stylesheet should just be available")
.to_vec(),
)
.expect("to parse stylesheet");
let provider = gtk::CssProvider::new();
provider.load_from_data(&stylesheet);
let context = window.style_context();
context.add_provider(&provider, STYLE_PROVIDER_PRIORITY_USER);
let header = setup_header();
let current_view = match config.get::<Database>() {
Some(_) => AppView::Home,
None => AppView::Config(SettingsViewModel::new(core.clone())),
};
let content = adw::Bin::builder().css_classes(vec!["content"]).build();
content.set_child(Some(
));
window.set_content(Some(&layout));
*/
let window = Self::setup_window(app); let window = Self::setup_window(app);
let header = Self::setup_header(); let header = Self::setup_header();
let panel_overlay = Self::setup_panel_overlay(); let panel_overlay = Self::setup_panel_overlay();
@ -105,9 +80,16 @@ impl AppWindow {
content, content,
panel_overlay, panel_overlay,
core, core,
settings_view_model: Default::default(),
} }
} }
pub fn open_settings(&self) {
let view_model = SettingsViewModel::new(self.core.clone());
self.panel_overlay.add_overlay(&view_model.widget);
*self.settings_view_model.write().unwrap() = Some(view_model);
}
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)
@ -124,7 +106,7 @@ impl AppWindow {
.build(); .build();
let app_menu = gio::Menu::new(); let app_menu = gio::Menu::new();
let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show_config")); let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show_settings"));
app_menu.append_item(&menu_item); app_menu.append_item(&menu_item);
let hamburger = gtk::MenuButton::builder() let hamburger = gtk::MenuButton::builder()

View File

@ -55,17 +55,17 @@ fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse)
fn load_config(app_id: &str) -> Config { fn load_config(app_id: &str) -> Config {
let settings = gio::Settings::new(app_id); let settings = gio::Settings::new(app_id);
let db_path: String = settings.string("database-path").into(); let lib_path: String = settings.string("library-path").into();
let mut config = Config::new(); let mut config = Config::new();
config.set(ConfigOption::LibraryPath(db_path.into())); config.set(ConfigOption::LibraryPath(lib_path.into()));
config config
} }
fn setup_app_configuration_action(app: &adw::Application) { fn setup_app_configuration_action(app: &adw::Application, app_window: AppWindow) {
println!("setup_app_configuration_action"); println!("setup_app_configuration_action");
let action = ActionEntry::builder("show_config") let action = ActionEntry::builder("show_settings")
.activate(|_app: &adw::Application, _, _| { .activate(move |_app: &adw::Application, _, _| {
println!("show configuration window"); app_window.open_settings();
}) })
.build(); .build();
app.add_action_entries([action]); app.add_action_entries([action]);
@ -125,14 +125,21 @@ fn main() {
app.connect_activate({ app.connect_activate({
let runtime = runtime.clone(); let runtime = runtime.clone();
move |app| { move |app| {
let app_window = AppWindow::new(app, core.clone()); let mut app_window = AppWindow::new(app, core.clone());
setup_app_configuration_action(app); match *core.library() {
Some(_) => {},
None => app_window.open_settings(),
}
setup_app_configuration_action(app, app_window.clone());
/*
let api = CoreApi { let api = CoreApi {
rt: runtime.clone(), rt: runtime.clone(),
core: core.clone(), core: core.clone(),
}; };
*/
/* /*
let action_config = gio::SimpleAction::new("show-config", None); let action_config = gio::SimpleAction::new("show-config", None);

View File

@ -16,17 +16,19 @@ You should have received a copy of the GNU General Public License along with Kif
use crate::{views, LocalObserver, views::SettingsView}; use crate::{views, LocalObserver, views::SettingsView};
use kifu_core::{Core, CoreNotification}; use kifu_core::{Core, CoreNotification};
use std::sync::Arc;
/// SettingsViewModel /// SettingsViewModel
/// ///
/// Listens for messages from the core, and serves as intermediary between the Settings UI and the /// Listens for messages from the core, and serves as intermediary between the Settings UI and the
/// core. Because it needs to respond to events from the core, it owns the widget, which allows it /// core. Because it needs to respond to events from the core, it owns the widget, which allows it
/// to tell the widget to update after certain events. /// to tell the widget to update after certain events.
#[derive(Clone)]
pub struct SettingsViewModel { pub struct SettingsViewModel {
core: Core, core: Core,
// Technically, Settings doesn't care about any events from Core. We will keep this around for // Technically, Settings doesn't care about any events from Core. We will keep this around for
// now as reference, until something which does care shows up. // now as reference, until something which does care shows up.
notification_observer: LocalObserver<CoreNotification>, notification_observer: Arc<LocalObserver<CoreNotification>>,
pub widget: views::SettingsView, pub widget: views::SettingsView,
} }
@ -38,7 +40,7 @@ impl SettingsViewModel {
Self { Self {
core, core,
notification_observer, notification_observer: Arc::new(notification_observer),
widget: SettingsView::new(), widget: SettingsView::new(),
} }
} }

View File

@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with Kif
use glib::Object; use glib::Object;
use gtk::{prelude::*, subclass::prelude::*}; use gtk::{prelude::*, subclass::prelude::*};
use adw::prelude::*;
pub struct SettingsPrivate {} pub struct SettingsPrivate {}
@ -23,7 +24,7 @@ pub struct SettingsPrivate {}
impl ObjectSubclass for SettingsPrivate { impl ObjectSubclass for SettingsPrivate {
const NAME: &'static str = "Settings"; const NAME: &'static str = "Settings";
type Type = SettingsView; type Type = SettingsView;
type ParentType = gtk::Box; type ParentType = gtk::Frame;
fn new() -> Self { fn new() -> Self {
Self {} Self {}
@ -32,15 +33,33 @@ impl ObjectSubclass for SettingsPrivate {
impl ObjectImpl for SettingsPrivate {} impl ObjectImpl for SettingsPrivate {}
impl WidgetImpl for SettingsPrivate {} impl WidgetImpl for SettingsPrivate {}
impl BoxImpl for SettingsPrivate {} #[allow(deprecated)]
impl FrameImpl for SettingsPrivate {}
glib::wrapper! { glib::wrapper! {
pub struct SettingsView(ObjectSubclass<SettingsPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable; pub struct SettingsView(ObjectSubclass<SettingsPrivate>) @extends gtk::Frame, gtk::Widget, @implements gtk::Accessible, gtk::Buildable, gtk::Orientable;
} }
impl SettingsView { impl SettingsView {
pub fn new() -> Self { pub fn new() -> Self {
let s: Self = Object::builder().build(); let s: Self = Object::builder().build();
let group = adw::PreferencesGroup::builder().build();
let library_row = adw::PreferencesRow::builder()
.title("Library Path")
.child(&gtk::Label::builder().label("Library Path").build())
.build();
group.add(&library_row);
let layout = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.vexpand(true)
.build();
layout.append(&group);
s.set_child(Some(&layout));
s.set_css_classes(&["settings-view"]);
s s
} }
} }