diff --git a/Cargo.toml b/Cargo.toml index 72f45b2..8b4218a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ gtk4 = "0.4" gtk4 = "0.4" libadwaita = "0.1" -anime-game-core = { path = "anime-game-core", features = ["all"] } +anime-game-core = { path = "anime-game-core", features = ["all", "static"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/lib/config/mod.rs b/src/lib/config/mod.rs index a356867..7c6f7be 100644 --- a/src/lib/config/mod.rs +++ b/src/lib/config/mod.rs @@ -19,7 +19,26 @@ pub use hud::HUD; pub use wine_sync::WineSync; pub use wine_lang::WineLang; +static mut CONFIG: Option = None; + +/// Get config data +/// +/// This method will load config from file once and store it into the memory. +/// If you know that the config file was updated - you should run `get_raw` method +/// that always loads config directly from the file. This will also update in-memory config pub fn get() -> Result { + unsafe { + match &CONFIG { + Some(config) => Ok(config.clone()), + None => get_raw() + } + } +} + +/// Get config data +/// +/// This method will always load data directly from the file and update in-memory config +pub fn get_raw() -> Result { match config_file() { Some(path) => { // Try to read config if the file exists @@ -30,14 +49,20 @@ pub fn get() -> Result { file.read_to_string(&mut json)?; match serde_json::from_str::(&json) { - Ok(json) => Ok(json), + Ok(config) => { + unsafe { + CONFIG = Some(config.clone()); + } + + Ok(config) + }, Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to decode data from json format: {}", err.to_string()))) } } // Otherwise create default config file else { - update(Config::default())?; + update_raw(Config::default())?; Ok(Config::default()) } @@ -46,7 +71,21 @@ pub fn get() -> Result { } } -pub fn update(config: Config) -> Result<(), Error> { +/// Update in-memory config data +/// +/// Use `update_raw` if you want to update config file itself +pub fn update(config: Config) { + unsafe { + CONFIG = Some(config); + } +} + +/// Update config file +/// +/// This method will also update in-memory config data +pub fn update_raw(config: Config) -> Result<(), Error> { + update(config.clone()); + match config_file() { Some(path) => { let mut file = File::create(&path)?; @@ -64,6 +103,16 @@ pub fn update(config: Config) -> Result<(), Error> { } } +/// Update config file from the in-memory saved config +pub fn flush() -> Result<(), Error> { + unsafe { + match &CONFIG { + Some(config) => update_raw(config.clone()), + None => Err(Error::new(ErrorKind::Other, "Config wasn't loaded into the memory")) + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Config { pub launcher: Launcher, diff --git a/src/main.rs b/src/main.rs index 67f6e51..4be7c50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,11 @@ async fn main() { main.show(); }); + // Flush config from the memory to the file before closing the app + application.connect_shutdown(|_| { + lib::config::flush().expect("Failed to save config data"); + }); + // Run app application.run(); } diff --git a/src/ui/main.rs b/src/ui/main.rs index d01fa03..fe9ce9b 100644 --- a/src/ui/main.rs +++ b/src/ui/main.rs @@ -91,7 +91,7 @@ pub enum Actions { impl Actions { pub fn into_fn>(&self, app: &App) -> Box { - Box::new(clone!(@strong self as action, @strong app => move |_| { + Box::new(clone!(@strong self as action, @weak app => move |_| { app.update(action.clone()).expect(&format!("Failed to execute action {:?}", &action)); })) } diff --git a/src/ui/preferences/enhancements_page.rs b/src/ui/preferences/enhancements_page.rs index 8e705ad..6d06bfb 100644 --- a/src/ui/preferences/enhancements_page.rs +++ b/src/ui/preferences/enhancements_page.rs @@ -154,8 +154,7 @@ impl App { match action { Actions::OptionSelection(update, value) => { if let Ok(config) = config::get() { - // TODO: show toast - config::update((update)(config, value)).unwrap(); + config::update((update)(config, value)); } } } @@ -193,7 +192,7 @@ impl App { self.widgets.fsr_switcher.set_state(config.game.enhancements.fsr.enabled); // Gamemode switching - self.widgets.fsr_switcher.set_state(config.game.enhancements.gamemode); + self.widgets.gamemode_switcher.set_state(config.game.enhancements.gamemode); Ok(()) } diff --git a/src/ui/preferences/general_page.rs b/src/ui/preferences/general_page.rs index 64d11e0..04a0d88 100644 --- a/src/ui/preferences/general_page.rs +++ b/src/ui/preferences/general_page.rs @@ -150,7 +150,7 @@ pub enum Actions { impl Actions { pub fn into_fn>(&self, app: &App) -> Box { - Box::new(clone!(@strong self as action, @strong app => move |_| { + Box::new(clone!(@strong self as action, @weak app => move |_| { app.update(action.clone()).expect(&format!("Failed to execute action {:?}", &action)); })) } @@ -199,7 +199,7 @@ impl App { /// Add default events and values to the widgets fn init_events(self) -> Self { - self.widgets.wine_selected.connect_selected_notify(clone!(@strong self as this => move |combo_row| { + self.widgets.wine_selected.connect_selected_notify(clone!(@weak self as this => move |combo_row| { if let Some(model) = combo_row.model() { if model.n_items() > 0 { this.update(Actions::SelectWineVersion(Rc::new(combo_row.selected() as usize))).unwrap(); @@ -207,7 +207,7 @@ impl App { } })); - self.widgets.dxvk_selected.connect_selected_notify(clone!(@strong self as this => move |combo_row| { + self.widgets.dxvk_selected.connect_selected_notify(clone!(@weak self as this => move |combo_row| { if let Some(model) = combo_row.model() { if model.n_items() > 0 { this.update(Actions::SelectDxvkVersion(Rc::new(combo_row.selected() as usize))).unwrap(); @@ -216,7 +216,7 @@ impl App { })); // Set wine recommended only switcher event - self.widgets.wine_recommended_only.connect_state_notify(clone!(@strong self as this => move |switcher| { + self.widgets.wine_recommended_only.connect_state_notify(clone!(@weak self as this => move |switcher| { for group in &*this.widgets.wine_components { for component in &group.version_components { component.row.set_visible(if switcher.state() { @@ -238,7 +238,7 @@ impl App { } // Set DXVK recommended only switcher event - self.widgets.dxvk_recommended_only.connect_state_notify(clone!(@strong self as this => move |switcher| { + self.widgets.dxvk_recommended_only.connect_state_notify(clone!(@weak self as this => move |switcher| { for component in &*this.widgets.dxvk_components { component.row.set_visible(if switcher.state() { component.version.recommended @@ -254,7 +254,7 @@ impl App { for (i, component) in components.into_iter().enumerate() { component.button.connect_clicked(Actions::DxvkPerformAction(Rc::new(i)).into_fn(&self)); - component.apply_button.connect_clicked(clone!(@strong component, @strong self as this => move |_| { + component.apply_button.connect_clicked(clone!(@strong component, @weak self as this => move |_| { std::thread::spawn(clone!(@strong component, @strong this => move || { let config = config::get().expect("Failed to load config"); @@ -400,7 +400,7 @@ impl App { this.values.set(values); - config::update(config).expect("Failed to update config"); + config::update(config); } Actions::UpdateWineComboRow => { @@ -446,7 +446,7 @@ impl App { this.values.set(values); - config::update(config).expect("Failed to update config"); + config::update(config); } Actions::ToastError(toast) => {