Added hot config system, fixed gamemode option

This commit is contained in:
Observer KRypt0n_ 2022-07-24 15:01:59 +02:00
parent a6667f73d4
commit 737aa7e8bc
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
6 changed files with 69 additions and 16 deletions

View file

@ -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"

View file

@ -19,7 +19,26 @@ pub use hud::HUD;
pub use wine_sync::WineSync;
pub use wine_lang::WineLang;
static mut CONFIG: Option<Config> = 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<Config, Error> {
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<Config, Error> {
match config_file() {
Some(path) => {
// Try to read config if the file exists
@ -30,14 +49,20 @@ pub fn get() -> Result<Config, Error> {
file.read_to_string(&mut json)?;
match serde_json::from_str::<Config>(&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<Config, Error> {
}
}
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,

View file

@ -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();
}

View file

@ -91,7 +91,7 @@ pub enum Actions {
impl Actions {
pub fn into_fn<T: gtk::glib::IsA<gtk::Widget>>(&self, app: &App) -> Box<dyn Fn(&T)> {
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));
}))
}

View file

@ -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(())
}

View file

@ -150,7 +150,7 @@ pub enum Actions {
impl Actions {
pub fn into_fn<T: gtk::glib::IsA<gtk::Widget>>(&self, app: &App) -> Box<dyn Fn(&T)> {
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) => {