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 {
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 gtk::STYLE_PROVIDER_PRIORITY_USER;
use kifu_core::{Config, Core};
use std::sync::{Arc, RwLock};
use crate::view_models::SettingsViewModel;
#[derive(Clone)]
enum AppView {
Settings(SettingsViewModel),
Home,
@ -31,6 +33,7 @@ enum AppView {
// - an overlay widget
// - the main content in a stack on the bottom panel of the overlay
// - the settings and the about page in bins atop the overlay
#[derive(Clone)]
pub struct AppWindow {
pub window: adw::ApplicationWindow,
header: adw::HeaderBar,
@ -48,42 +51,14 @@ pub struct AppWindow {
// anywhere but shouldn't be part of the main application flow.
panel_overlay: gtk::Overlay,
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 {
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 header = Self::setup_header();
let panel_overlay = Self::setup_panel_overlay();
@ -105,9 +80,16 @@ impl AppWindow {
content,
panel_overlay,
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 {
let window = adw::ApplicationWindow::builder()
.application(app)
@ -124,7 +106,7 @@ impl AppWindow {
.build();
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);
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 {
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();
config.set(ConfigOption::LibraryPath(db_path.into()));
config.set(ConfigOption::LibraryPath(lib_path.into()));
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");
let action = ActionEntry::builder("show_config")
.activate(|_app: &adw::Application, _, _| {
println!("show configuration window");
let action = ActionEntry::builder("show_settings")
.activate(move |_app: &adw::Application, _, _| {
app_window.open_settings();
})
.build();
app.add_action_entries([action]);
@ -125,14 +125,21 @@ fn main() {
app.connect_activate({
let runtime = runtime.clone();
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 {
rt: runtime.clone(),
core: core.clone(),
};
*/
/*
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 kifu_core::{Core, CoreNotification};
use std::sync::Arc;
/// SettingsViewModel
///
/// 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
/// to tell the widget to update after certain events.
#[derive(Clone)]
pub struct SettingsViewModel {
core: Core,
// 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.
notification_observer: LocalObserver<CoreNotification>,
notification_observer: Arc<LocalObserver<CoreNotification>>,
pub widget: views::SettingsView,
}
@ -38,7 +40,7 @@ impl SettingsViewModel {
Self {
core,
notification_observer,
notification_observer: Arc::new(notification_observer),
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 gtk::{prelude::*, subclass::prelude::*};
use adw::prelude::*;
pub struct SettingsPrivate {}
@ -23,7 +24,7 @@ pub struct SettingsPrivate {}
impl ObjectSubclass for SettingsPrivate {
const NAME: &'static str = "Settings";
type Type = SettingsView;
type ParentType = gtk::Box;
type ParentType = gtk::Frame;
fn new() -> Self {
Self {}
@ -32,15 +33,33 @@ impl ObjectSubclass for SettingsPrivate {
impl ObjectImpl for SettingsPrivate {}
impl WidgetImpl for SettingsPrivate {}
impl BoxImpl for SettingsPrivate {}
#[allow(deprecated)]
impl FrameImpl for SettingsPrivate {}
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 {
pub fn new() -> Self {
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
}
}