Added hot config system, fixed gamemode option
This commit is contained in:
parent
a6667f73d4
commit
737aa7e8bc
6 changed files with 69 additions and 16 deletions
|
@ -14,7 +14,7 @@ gtk4 = "0.4"
|
||||||
gtk4 = "0.4"
|
gtk4 = "0.4"
|
||||||
libadwaita = "0.1"
|
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 = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -19,7 +19,26 @@ pub use hud::HUD;
|
||||||
pub use wine_sync::WineSync;
|
pub use wine_sync::WineSync;
|
||||||
pub use wine_lang::WineLang;
|
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> {
|
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() {
|
match config_file() {
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
// Try to read config if the file exists
|
// Try to read config if the file exists
|
||||||
|
@ -30,14 +49,20 @@ pub fn get() -> Result<Config, Error> {
|
||||||
file.read_to_string(&mut json)?;
|
file.read_to_string(&mut json)?;
|
||||||
|
|
||||||
match serde_json::from_str::<Config>(&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())))
|
Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to decode data from json format: {}", err.to_string())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise create default config file
|
// Otherwise create default config file
|
||||||
else {
|
else {
|
||||||
update(Config::default())?;
|
update_raw(Config::default())?;
|
||||||
|
|
||||||
Ok(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() {
|
match config_file() {
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
let mut file = File::create(&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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub launcher: Launcher,
|
pub launcher: Launcher,
|
||||||
|
|
|
@ -42,6 +42,11 @@ async fn main() {
|
||||||
main.show();
|
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
|
// Run app
|
||||||
application.run();
|
application.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ pub enum Actions {
|
||||||
|
|
||||||
impl Actions {
|
impl Actions {
|
||||||
pub fn into_fn<T: gtk::glib::IsA<gtk::Widget>>(&self, app: &App) -> Box<dyn Fn(&T)> {
|
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));
|
app.update(action.clone()).expect(&format!("Failed to execute action {:?}", &action));
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,8 +154,7 @@ impl App {
|
||||||
match action {
|
match action {
|
||||||
Actions::OptionSelection(update, value) => {
|
Actions::OptionSelection(update, value) => {
|
||||||
if let Ok(config) = config::get() {
|
if let Ok(config) = config::get() {
|
||||||
// TODO: show toast
|
config::update((update)(config, value));
|
||||||
config::update((update)(config, value)).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +192,7 @@ impl App {
|
||||||
self.widgets.fsr_switcher.set_state(config.game.enhancements.fsr.enabled);
|
self.widgets.fsr_switcher.set_state(config.game.enhancements.fsr.enabled);
|
||||||
|
|
||||||
// Gamemode switching
|
// Gamemode switching
|
||||||
self.widgets.fsr_switcher.set_state(config.game.enhancements.gamemode);
|
self.widgets.gamemode_switcher.set_state(config.game.enhancements.gamemode);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ pub enum Actions {
|
||||||
|
|
||||||
impl Actions {
|
impl Actions {
|
||||||
pub fn into_fn<T: gtk::glib::IsA<gtk::Widget>>(&self, app: &App) -> Box<dyn Fn(&T)> {
|
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));
|
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
|
/// Add default events and values to the widgets
|
||||||
fn init_events(self) -> Self {
|
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 let Some(model) = combo_row.model() {
|
||||||
if model.n_items() > 0 {
|
if model.n_items() > 0 {
|
||||||
this.update(Actions::SelectWineVersion(Rc::new(combo_row.selected() as usize))).unwrap();
|
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 let Some(model) = combo_row.model() {
|
||||||
if model.n_items() > 0 {
|
if model.n_items() > 0 {
|
||||||
this.update(Actions::SelectDxvkVersion(Rc::new(combo_row.selected() as usize))).unwrap();
|
this.update(Actions::SelectDxvkVersion(Rc::new(combo_row.selected() as usize))).unwrap();
|
||||||
|
@ -216,7 +216,7 @@ impl App {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Set wine recommended only switcher event
|
// 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 group in &*this.widgets.wine_components {
|
||||||
for component in &group.version_components {
|
for component in &group.version_components {
|
||||||
component.row.set_visible(if switcher.state() {
|
component.row.set_visible(if switcher.state() {
|
||||||
|
@ -238,7 +238,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set DXVK recommended only switcher event
|
// 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 {
|
for component in &*this.widgets.dxvk_components {
|
||||||
component.row.set_visible(if switcher.state() {
|
component.row.set_visible(if switcher.state() {
|
||||||
component.version.recommended
|
component.version.recommended
|
||||||
|
@ -254,7 +254,7 @@ impl App {
|
||||||
for (i, component) in components.into_iter().enumerate() {
|
for (i, component) in components.into_iter().enumerate() {
|
||||||
component.button.connect_clicked(Actions::DxvkPerformAction(Rc::new(i)).into_fn(&self));
|
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 || {
|
std::thread::spawn(clone!(@strong component, @strong this => move || {
|
||||||
let config = config::get().expect("Failed to load config");
|
let config = config::get().expect("Failed to load config");
|
||||||
|
|
||||||
|
@ -400,7 +400,7 @@ impl App {
|
||||||
|
|
||||||
this.values.set(values);
|
this.values.set(values);
|
||||||
|
|
||||||
config::update(config).expect("Failed to update config");
|
config::update(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions::UpdateWineComboRow => {
|
Actions::UpdateWineComboRow => {
|
||||||
|
@ -446,7 +446,7 @@ impl App {
|
||||||
|
|
||||||
this.values.set(values);
|
this.values.set(values);
|
||||||
|
|
||||||
config::update(config).expect("Failed to update config");
|
config::update(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions::ToastError(toast) => {
|
Actions::ToastError(toast) => {
|
||||||
|
|
Loading…
Reference in a new issue