Set up the settings user interface #225
|
@ -1,13 +1,12 @@
|
|||
use crate::{
|
||||
database::Database,
|
||||
types::{AppState, Config, ConfigOption, DatabasePath, GameState, Player, Rank},
|
||||
ui::{configuration, home, playing_field, ConfigurationView, HomeView, PlayingFieldView},
|
||||
types::{AppState, Config, ConfigOption, LibraryPath, GameState, Player, Rank},
|
||||
};
|
||||
use async_std::channel::{Receiver, Sender};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
sync::{Arc, RwLock},
|
||||
sync::{Arc, RwLock, RwLockReadGuard},
|
||||
};
|
||||
|
||||
pub trait Observable<T> {
|
||||
|
@ -62,6 +61,7 @@ impl From<HotseatPlayerRequest> for Player {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum CoreResponse {
|
||||
ConfigurationView(ConfigurationView),
|
||||
|
@ -69,6 +69,7 @@ pub enum CoreResponse {
|
|||
PlayingFieldView(PlayingFieldView),
|
||||
UpdatedConfigurationView(ConfigurationView),
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum CoreNotification {
|
||||
|
@ -79,7 +80,7 @@ pub enum CoreNotification {
|
|||
pub struct Core {
|
||||
// config: Arc<RwLock<Config>>,
|
||||
// state: Arc<RwLock<AppState>>,
|
||||
database: Arc<RwLock<Option<Database>>>,
|
||||
library: Arc<RwLock<Option<Database>>>,
|
||||
subscribers: Arc<RwLock<Vec<Sender<CoreNotification>>>>,
|
||||
}
|
||||
|
||||
|
@ -92,11 +93,15 @@ impl Core {
|
|||
Self {
|
||||
// config: Arc::new(RwLock::new(config)),
|
||||
// state,
|
||||
database: Arc::new(RwLock::new(None)),
|
||||
library: Arc::new(RwLock::new(None)),
|
||||
subscribers: Arc::new(RwLock::new(vec![])),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn library<'a>(&'a self) -> RwLockReadGuard<'_, Option<Database>> {
|
||||
self.library.read().unwrap()
|
||||
}
|
||||
|
||||
/*
|
||||
pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse {
|
||||
match request {
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
extern crate config_derive;
|
||||
|
||||
mod api;
|
||||
pub use api::{
|
||||
ChangeSettingRequest, Core, CoreNotification, CoreRequest, CoreResponse, CreateGameRequest,
|
||||
HotseatPlayerRequest, Observable, PlayerInfoRequest,
|
||||
};
|
||||
pub use api::{Core, CoreNotification, Observable};
|
||||
|
||||
mod board;
|
||||
pub use board::*;
|
||||
|
@ -12,6 +9,5 @@ pub use board::*;
|
|||
mod database;
|
||||
|
||||
mod types;
|
||||
pub use types::{BoardError, Color, Config, ConfigOption, DatabasePath, Player, Rank, Size};
|
||||
pub use types::{BoardError, Color, Config, ConfigOption, LibraryPath, Player, Rank, Size};
|
||||
|
||||
pub mod ui;
|
||||
|
|
|
@ -10,21 +10,21 @@ use std::{path::PathBuf, time::Duration};
|
|||
use thiserror::Error;
|
||||
|
||||
define_config! {
|
||||
DatabasePath(DatabasePath),
|
||||
LibraryPath(LibraryPath),
|
||||
Me(Me),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ConfigOption)]
|
||||
pub struct DatabasePath(pub PathBuf);
|
||||
pub struct LibraryPath(pub PathBuf);
|
||||
|
||||
impl std::ops::Deref for DatabasePath {
|
||||
impl std::ops::Deref for LibraryPath {
|
||||
type Target = PathBuf;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for DatabasePath {
|
||||
impl From<String> for LibraryPath {
|
||||
fn from(s: String) -> Self {
|
||||
Self(PathBuf::from(s))
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ pub struct AppState {
|
|||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(database_path: DatabasePath) -> Self {
|
||||
pub fn new(database_path: LibraryPath) -> Self {
|
||||
Self {
|
||||
game: Some(GameState::default()),
|
||||
database: Database::open_path(database_path.to_path_buf()).unwrap(),
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
use crate::{
|
||||
types::{Config, DatabasePath},
|
||||
ui::Field,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ConfigurationView {
|
||||
pub library: Field<()>,
|
||||
}
|
||||
|
||||
pub fn configuration(config: &Config) -> ConfigurationView {
|
||||
let path: Option<DatabasePath> = config.get();
|
||||
ConfigurationView {
|
||||
library: Field {
|
||||
id: "library-path-field".to_owned(),
|
||||
label: "Library".to_owned(),
|
||||
value: path.map(|path| path.to_string_lossy().into_owned()),
|
||||
action: (),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ screenplay = []
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
adw = { version = "0.5", package = "libadwaita", features = [ "v1_2" ] }
|
||||
adw = { version = "0.5", package = "libadwaita", features = [ "v1_4" ] }
|
||||
async-channel = { version = "2" }
|
||||
async-std = { version = "1" }
|
||||
cairo-rs = { version = "0.18" }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<schemalist>
|
||||
<schema id="com.luminescent-dreams.kifu-gtk.dev" path="/com/luminescent-dreams/kifu-gtk/dev/">
|
||||
<key name="database-path" type="s">
|
||||
<key name="library-path" type="s">
|
||||
<default>""</default>
|
||||
<summary>Path to the directory of games</summary>
|
||||
</key>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<schemalist>
|
||||
<schema id="com.luminescent-dreams.kifu-gtk" path="/com/luminescent-dreams/kifu-gtk/">
|
||||
<key name="database-path" type="s">
|
||||
<key name="library-path" type="s">
|
||||
<default>""</default>
|
||||
<summary>Path to the directory of games</summary>
|
||||
</key>
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>
|
||||
|
||||
This file is part of Kifu.
|
||||
|
||||
Kifu is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
Kifu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
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/>.
|
||||
*/
|
||||
|
||||
use adw::prelude::*;
|
||||
use gio::resources_lookup_data;
|
||||
use glib::IsA;
|
||||
use gtk::STYLE_PROVIDER_PRIORITY_USER;
|
||||
use kifu_core::{Config, Core};
|
||||
|
||||
use crate::view_models::SettingsViewModel;
|
||||
|
||||
enum AppView {
|
||||
Settings(SettingsViewModel),
|
||||
Home,
|
||||
}
|
||||
|
||||
// An application window should generally contain
|
||||
// - 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
|
||||
pub struct AppWindow {
|
||||
pub window: adw::ApplicationWindow,
|
||||
header: adw::HeaderBar,
|
||||
|
||||
// content is a stack which contains the view models for the application. These are the main
|
||||
// elements that users want to interact with: the home page, the game library, a review, a game
|
||||
// itself, perhaps also chat rooms and player lists on other networks. stack contains the
|
||||
// widgets that need to be rendered. The two of these work together in order to ensure that
|
||||
// we can maintain the state of previous views. Since the two of these work together, they are
|
||||
// a candidate for extraction into a new widget or a new struct.
|
||||
stack: adw::NavigationView,
|
||||
content: Vec<AppView>,
|
||||
|
||||
// Overlays are for transient content, such as about and settings, which can be accessed from
|
||||
// anywhere but shouldn't be part of the main application flow.
|
||||
panel_overlay: gtk::Overlay,
|
||||
core: Core,
|
||||
}
|
||||
|
||||
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();
|
||||
let (stack, content) = Self::setup_content(core.clone());
|
||||
|
||||
let layout = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.build();
|
||||
layout.append(&header);
|
||||
layout.append(&panel_overlay);
|
||||
panel_overlay.set_child(Some(&stack));
|
||||
|
||||
window.set_content(Some(&layout));
|
||||
|
||||
Self {
|
||||
window,
|
||||
header,
|
||||
stack,
|
||||
content,
|
||||
panel_overlay,
|
||||
core,
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_window(app: &adw::Application) -> adw::ApplicationWindow {
|
||||
let window = adw::ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.width_request(800)
|
||||
.height_request(500)
|
||||
.build();
|
||||
|
||||
window
|
||||
}
|
||||
|
||||
fn setup_header() -> adw::HeaderBar {
|
||||
let header = adw::HeaderBar::builder()
|
||||
.title_widget(>k::Label::new(Some("Kifu")))
|
||||
.build();
|
||||
|
||||
let app_menu = gio::Menu::new();
|
||||
let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show_config"));
|
||||
app_menu.append_item(&menu_item);
|
||||
|
||||
let hamburger = gtk::MenuButton::builder()
|
||||
.icon_name("open-menu-symbolic")
|
||||
.build();
|
||||
hamburger.set_menu_model(Some(&app_menu));
|
||||
|
||||
header.pack_end(&hamburger);
|
||||
header
|
||||
}
|
||||
|
||||
fn setup_panel_overlay() -> gtk::Overlay {
|
||||
gtk::Overlay::new()
|
||||
}
|
||||
|
||||
fn setup_content(core: Core) -> (adw::NavigationView, Vec<AppView>) {
|
||||
let stack = adw::NavigationView::new();
|
||||
let mut content = Vec::new();
|
||||
|
||||
let nothing_page = adw::StatusPage::builder().title("Nothing here").build();
|
||||
let _ = stack.push(
|
||||
&adw::NavigationPage::builder()
|
||||
.can_pop(false)
|
||||
.title("Kifu")
|
||||
.child(¬hing_page)
|
||||
.build(),
|
||||
);
|
||||
content.push(AppView::Home);
|
||||
|
||||
/*
|
||||
match *core.library() {
|
||||
Some(_) => {
|
||||
}
|
||||
None => {
|
||||
let settings_vm = SettingsViewModel::new(core.clone());
|
||||
let _ = stack.push(&adw::NavigationPage::new(&settings_vm.widget, "Settings"));
|
||||
content.push(AppView::Settings(settings_vm));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
(stack, content)
|
||||
}
|
||||
|
||||
// pub fn set_content(content: &impl IsA<gtk::Widget>) -> adw::ViewStack {
|
||||
// self.content.set_child(Some(content));
|
||||
// }
|
||||
}
|
|
@ -1,10 +1,29 @@
|
|||
/*
|
||||
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>
|
||||
|
||||
This file is part of Kifu.
|
||||
|
||||
Kifu is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
Kifu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
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/>.
|
||||
*/
|
||||
|
||||
pub mod ui;
|
||||
|
||||
mod app_window;
|
||||
pub use app_window::AppWindow;
|
||||
|
||||
mod view_models;
|
||||
mod views;
|
||||
|
||||
use async_std::task::yield_now;
|
||||
use kifu_core::{Core, CoreRequest, CoreResponse, Observable};
|
||||
use kifu_core::{Core, Observable};
|
||||
use std::{rc::Rc, sync::Arc};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
|
@ -15,6 +34,7 @@ pub struct CoreApi {
|
|||
}
|
||||
|
||||
impl CoreApi {
|
||||
/*
|
||||
pub fn dispatch(&self, request: CoreRequest) {
|
||||
/*
|
||||
spawn({
|
||||
|
@ -26,6 +46,7 @@ impl CoreApi {
|
|||
});
|
||||
*/
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn perftrace<F, A>(trace_name: &str, f: F) -> A
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use adw::prelude::*;
|
||||
use kifu_core::{Config, ConfigOption, Core, CoreRequest, CoreResponse, DatabasePath};
|
||||
use gio::ActionEntry;
|
||||
use kifu_core::{Config, ConfigOption, Core};
|
||||
use kifu_gtk::{
|
||||
perftrace,
|
||||
ui::{AppWindow, ConfigurationPage, Home, PlayingField},
|
||||
// ui::{ConfigurationPage, Home, PlayingField},
|
||||
AppWindow,
|
||||
CoreApi,
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
@ -12,6 +14,7 @@ const APP_ID_PROD: &str = "com.luminescent-dreams.kifu-gtk";
|
|||
|
||||
const RESOURCE_BASE_PATH: &str = "/com/luminescent-dreams/kifu-gtk/";
|
||||
|
||||
/*
|
||||
fn handle_response(api: CoreApi, app_window: &AppWindow, message: CoreResponse) {
|
||||
let playing_field = Arc::new(RwLock::new(None));
|
||||
match message {
|
||||
|
@ -48,6 +51,26 @@ 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 mut config = Config::new();
|
||||
config.set(ConfigOption::LibraryPath(db_path.into()));
|
||||
config
|
||||
}
|
||||
|
||||
fn setup_app_configuration_action(app: &adw::Application) {
|
||||
println!("setup_app_configuration_action");
|
||||
let action = ActionEntry::builder("show_config")
|
||||
.activate(|_app: &adw::Application, _, _| {
|
||||
println!("show configuration window");
|
||||
})
|
||||
.build();
|
||||
app.add_action_entries([action]);
|
||||
println!("setup_app_configuration_action complete");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
gio::resources_register_include!("com.luminescent-dreams.kifu-gtk.gresource")
|
||||
|
@ -59,10 +82,7 @@ fn main() {
|
|||
APP_ID_PROD
|
||||
};
|
||||
|
||||
let settings = gio::Settings::new(app_id);
|
||||
let db_path: String = settings.string("database-path").into();
|
||||
let mut config = Config::new();
|
||||
config.set(ConfigOption::DatabasePath(db_path.into()));
|
||||
let config = load_config(&app_id);
|
||||
|
||||
let runtime = Arc::new(
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
|
@ -101,16 +121,20 @@ fn main() {
|
|||
.resource_base_path("/com/luminescent-dreams/kifu-gtk")
|
||||
.build();
|
||||
|
||||
|
||||
app.connect_activate({
|
||||
let runtime = runtime.clone();
|
||||
move |app| {
|
||||
let app_window = AppWindow::new(app);
|
||||
let app_window = AppWindow::new(app, core.clone());
|
||||
|
||||
setup_app_configuration_action(app);
|
||||
|
||||
let api = CoreApi {
|
||||
rt: runtime.clone(),
|
||||
core: core.clone(),
|
||||
};
|
||||
|
||||
/*
|
||||
let action_config = gio::SimpleAction::new("show-config", None);
|
||||
action_config.connect_activate({
|
||||
let api = api.clone();
|
||||
|
@ -119,6 +143,7 @@ fn main() {
|
|||
}
|
||||
});
|
||||
app.add_action(&action_config);
|
||||
*/
|
||||
|
||||
app_window.window.present();
|
||||
|
||||
|
@ -134,7 +159,7 @@ fn main() {
|
|||
});
|
||||
*/
|
||||
|
||||
api.dispatch(CoreRequest::Home);
|
||||
// api.dispatch(CoreRequest::Home);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,100 +1,27 @@
|
|||
use adw::prelude::*;
|
||||
use gio::resources_lookup_data;
|
||||
use glib::IsA;
|
||||
use gtk::STYLE_PROVIDER_PRIORITY_USER;
|
||||
// mod chat;
|
||||
// pub use chat::Chat;
|
||||
|
||||
mod chat;
|
||||
pub use chat::Chat;
|
||||
// mod config;
|
||||
// pub use config::ConfigurationPage;
|
||||
|
||||
mod config;
|
||||
pub use config::ConfigurationPage;
|
||||
// mod game_preview;
|
||||
// pub use game_preview::GamePreview;
|
||||
|
||||
mod game_preview;
|
||||
pub use game_preview::GamePreview;
|
||||
// mod library;
|
||||
// pub use library::Library;
|
||||
|
||||
mod library;
|
||||
pub use library::Library;
|
||||
// mod player_card;
|
||||
// pub use player_card::PlayerCard;
|
||||
|
||||
mod player_card;
|
||||
pub use player_card::PlayerCard;
|
||||
// mod playing_field;
|
||||
// pub use playing_field::PlayingField;
|
||||
|
||||
mod playing_field;
|
||||
pub use playing_field::PlayingField;
|
||||
// mod home;
|
||||
// pub use home::Home;
|
||||
|
||||
mod home;
|
||||
pub use home::Home;
|
||||
|
||||
mod board;
|
||||
pub use board::Board;
|
||||
// mod board;
|
||||
// pub use board::Board;
|
||||
|
||||
#[cfg(feature = "screenplay")]
|
||||
pub use playing_field::playing_field_view;
|
||||
|
||||
pub struct AppWindow {
|
||||
pub window: adw::ApplicationWindow,
|
||||
pub header: adw::HeaderBar,
|
||||
pub content: adw::Bin,
|
||||
}
|
||||
|
||||
impl AppWindow {
|
||||
pub fn new(app: &adw::Application) -> Self {
|
||||
let window = adw::ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.width_request(800)
|
||||
.height_request(500)
|
||||
.build();
|
||||
|
||||
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 = adw::HeaderBar::builder()
|
||||
.title_widget(>k::Label::new(Some("Kifu")))
|
||||
.build();
|
||||
|
||||
let app_menu = gio::Menu::new();
|
||||
let menu_item = gio::MenuItem::new(Some("Configuration"), Some("app.show-config"));
|
||||
app_menu.append_item(&menu_item);
|
||||
|
||||
let hamburger = gtk::MenuButton::builder()
|
||||
.icon_name("open-menu-symbolic")
|
||||
.build();
|
||||
hamburger.set_menu_model(Some(&app_menu));
|
||||
|
||||
header.pack_end(&hamburger);
|
||||
|
||||
let content = adw::Bin::builder().css_classes(vec!["content"]).build();
|
||||
content.set_child(Some(
|
||||
&adw::StatusPage::builder().title("Nothing here").build(),
|
||||
));
|
||||
|
||||
let layout = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.build();
|
||||
layout.append(&header);
|
||||
layout.append(&content);
|
||||
|
||||
window.set_content(Some(&layout));
|
||||
|
||||
Self {
|
||||
window,
|
||||
header,
|
||||
content,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_content(&self, content: &impl IsA<gtk::Widget>) {
|
||||
self.content.set_child(Some(content));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,17 +14,24 @@ 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/>.
|
||||
*/
|
||||
|
||||
use crate::LocalObserver;
|
||||
use crate::{views, LocalObserver, views::SettingsView};
|
||||
use kifu_core::{Core, CoreNotification};
|
||||
|
||||
/// 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.
|
||||
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>,
|
||||
widget: gtk::Box,
|
||||
pub widget: views::SettingsView,
|
||||
}
|
||||
|
||||
impl SettingsViewModel {
|
||||
fn new(core: Core) -> Self {
|
||||
pub fn new(core: Core) -> Self {
|
||||
let notification_observer = LocalObserver::new(&core, |msg| {
|
||||
println!("SettingsViewModel called with message: {:?}", msg)
|
||||
});
|
||||
|
@ -32,7 +39,7 @@ impl SettingsViewModel {
|
|||
Self {
|
||||
core,
|
||||
notification_observer,
|
||||
widget: gtk::Box::new(gtk::Orientation::Horizontal, 0),
|
||||
widget: SettingsView::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
mod settings;
|
||||
pub use settings::SettingsView;
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>
|
||||
|
||||
This file is part of Kifu.
|
||||
|
||||
Kifu is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
Kifu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
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/>.
|
||||
*/
|
||||
|
||||
use glib::Object;
|
||||
use gtk::{prelude::*, subclass::prelude::*};
|
||||
|
||||
pub struct SettingsPrivate {}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for SettingsPrivate {
|
||||
const NAME: &'static str = "Settings";
|
||||
type Type = SettingsView;
|
||||
type ParentType = gtk::Box;
|
||||
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for SettingsPrivate {}
|
||||
impl WidgetImpl for SettingsPrivate {}
|
||||
impl BoxImpl for SettingsPrivate {}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct SettingsView(ObjectSubclass<SettingsPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable;
|
||||
}
|
||||
|
||||
impl SettingsView {
|
||||
pub fn new() -> Self {
|
||||
let s: Self = Object::builder().build();
|
||||
s
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue