Create, populate, and start using the Application Context
This commit is contained in:
parent
ff1d117e8c
commit
4114e64b8e
|
@ -2709,6 +2709,8 @@ dependencies = [
|
|||
"libadwaita",
|
||||
"pango",
|
||||
"sgf",
|
||||
"sys-locale",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ adw = { version = "0.5", package = "libadwaita", features = [ "v1_2"
|
|||
async-channel = { version = "2" }
|
||||
async-std = { version = "1" }
|
||||
cairo-rs = { version = "0.18" }
|
||||
fluent = { version = "0.16" }
|
||||
fluent-ergonomics = { path = "../../fluent-ergonomics" }
|
||||
fluent = { version = "0.16" }
|
||||
gio = { version = "0.18" }
|
||||
glib = { version = "0.18" }
|
||||
gtk = { version = "0.7", package = "gtk4", features = [ "v4_8" ] }
|
||||
|
@ -23,6 +23,8 @@ kifu-core = { path = "../core" }
|
|||
l10n = { path = "../../l10n" }
|
||||
pango = { version = "*" }
|
||||
sgf = { path = "../../sgf" }
|
||||
sys-locale = { version = "0.3" }
|
||||
thiserror = { version = "1" }
|
||||
tokio = { version = "1.26", features = [ "full" ] }
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use async_std::task::yield_now;
|
||||
use kifu_core::{Core, CoreRequest, Observable};
|
||||
use l10n::{NonEmptyList, L10N};
|
||||
use std::{rc::Rc, sync::Arc};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
mod messages {
|
||||
include!(env!("KIFU_GTK_MESSAGES"));
|
||||
}
|
||||
|
@ -7,11 +13,6 @@ pub mod ui;
|
|||
mod view_models;
|
||||
mod views;
|
||||
|
||||
use async_std::task::yield_now;
|
||||
use kifu_core::{Core, CoreRequest, CoreResponse, Observable};
|
||||
use std::{rc::Rc, sync::Arc};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CoreApi {
|
||||
pub rt: Arc<Runtime>,
|
||||
|
@ -43,6 +44,45 @@ where
|
|||
result
|
||||
}
|
||||
|
||||
/// AppContext is our global store for things that need to be available everywhere. Developers
|
||||
/// should never pass this around directly, but should instead pass it around by traits. This is to
|
||||
/// provide systems such as:
|
||||
///
|
||||
/// - Feature Flags
|
||||
/// - L10N
|
||||
pub struct AppContext {
|
||||
pub l10n: L10N,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AppContextInitError {}
|
||||
|
||||
impl AppContext {
|
||||
pub fn new() -> Result<Self, AppContextInitError> {
|
||||
let mut locale_list = NonEmptyList::new("en-US");
|
||||
|
||||
let user_locale = sys_locale::get_locale().unwrap();
|
||||
println!("user locale: {}", user_locale);
|
||||
if locale_list.find(|l| *l == user_locale).is_none() {
|
||||
locale_list.push(&user_locale);
|
||||
}
|
||||
let mut l10n = l10n::L10N::new("messages".into());
|
||||
l10n.set_locales(locale_list);
|
||||
|
||||
Ok(Self { l10n })
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ProvidesL10N {
|
||||
fn l10n(&self) -> &L10N;
|
||||
}
|
||||
|
||||
impl ProvidesL10N for AppContext {
|
||||
fn l10n(&self) -> &L10N {
|
||||
&self.l10n
|
||||
}
|
||||
}
|
||||
|
||||
/// LocalObserver creates a task on the current thread which watches the specified observer for notifications and calls the handler function with each one.
|
||||
///
|
||||
/// The LocalObserver starts a task which listens for notifications during the constructor. When the observer goes out of scope, it will make a point of aborting the task. This combination means that anything which uses the observer can create it, hold on to a reference of it, and then drop it when done, and not have to do anything else with the observer object.
|
||||
|
|
|
@ -3,8 +3,9 @@ use kifu_core::{Config, ConfigOption, Core, CoreRequest, CoreResponse, DatabaseP
|
|||
use kifu_gtk::{
|
||||
perftrace,
|
||||
ui::{AppWindow, ConfigurationPage, Home, PlayingField},
|
||||
CoreApi,
|
||||
AppContext, CoreApi,
|
||||
};
|
||||
use l10n::NonEmptyList;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
const APP_ID_DEV: &str = "com.luminescent-dreams.kifu-gtk.dev";
|
||||
|
@ -104,7 +105,9 @@ fn main() {
|
|||
app.connect_activate({
|
||||
let runtime = runtime.clone();
|
||||
move |app| {
|
||||
let app_window = AppWindow::new(app);
|
||||
|
||||
let ctx = AppContext::new().unwrap();
|
||||
let app_window = AppWindow::new(app, &ctx);
|
||||
|
||||
let api = CoreApi {
|
||||
rt: runtime.clone(),
|
||||
|
|
|
@ -4,7 +4,7 @@ use glib::IsA;
|
|||
use gtk::STYLE_PROVIDER_PRIORITY_USER;
|
||||
use l10n::{L10N, NonEmptyList};
|
||||
use std::path::PathBuf;
|
||||
use crate::messages;
|
||||
use crate::{ProvidesL10N, messages};
|
||||
|
||||
mod chat;
|
||||
pub use chat::Chat;
|
||||
|
@ -40,7 +40,7 @@ pub struct AppWindow {
|
|||
}
|
||||
|
||||
impl AppWindow {
|
||||
pub fn new(app: &adw::Application) -> Self {
|
||||
pub fn new(app: &adw::Application, ctx: &impl ProvidesL10N) -> Self {
|
||||
let window = adw::ApplicationWindow::builder()
|
||||
.application(app)
|
||||
.width_request(800)
|
||||
|
@ -78,10 +78,8 @@ impl AppWindow {
|
|||
header.pack_end(&hamburger);
|
||||
|
||||
let content = adw::Bin::builder().css_classes(vec!["content"]).build();
|
||||
let mut l10n = L10N::new(PathBuf::from("resources"));
|
||||
l10n.set_locales(NonEmptyList::from_iter(vec!["en-US", "eo"]).unwrap());
|
||||
content.set_child(Some(
|
||||
&adw::StatusPage::builder().title(l10n.tr(messages::NothingHere)).build(),
|
||||
&adw::StatusPage::builder().title(ctx.l10n().tr(messages::NothingHere)).build(),
|
||||
));
|
||||
|
||||
let layout = gtk::Box::builder()
|
||||
|
|
|
@ -22,7 +22,7 @@ pub enum NonEmptyListError {
|
|||
pub struct NonEmptyList<A>(Vec<A>);
|
||||
|
||||
impl<A> NonEmptyList<A> {
|
||||
fn new(elem: A) -> Self {
|
||||
pub fn new(elem: A) -> Self {
|
||||
Self(vec![elem])
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,14 @@ impl<A> NonEmptyList<A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, item: A) {
|
||||
self.0.push(item);
|
||||
}
|
||||
|
||||
pub fn find(&self, f: impl Fn(&A) -> bool) -> Option<&A> {
|
||||
self.0.iter().find(|item| f(*item))
|
||||
}
|
||||
|
||||
fn first(&self) -> &A {
|
||||
&self.0[0]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue