From 59405f440ce2db667c04953780924eba04487481 Mon Sep 17 00:00:00 2001 From: Observer KRypt0n_ Date: Fri, 1 Jul 2022 20:12:25 +0200 Subject: [PATCH] Added game and patch status updating in settings --- assets/ui/main.blp | 2 +- assets/ui/preferences_general.blp | 4 +- src/lib/game.rs | 41 +++++++++++++- src/main.rs | 6 +- src/ui/main.rs | 37 +++++++++++-- src/ui/preferences/enhanced_page.rs | 11 +++- src/ui/preferences/general_page.rs | 15 ++++- src/ui/preferences/mod.rs | 86 +++++++++++++++++++++++++++-- 8 files changed, 180 insertions(+), 22 deletions(-) diff --git a/assets/ui/main.blp b/assets/ui/main.blp index f9927d3..42944aa 100644 --- a/assets/ui/main.blp +++ b/assets/ui/main.blp @@ -58,7 +58,7 @@ Adw.ApplicationWindow window { styles ["suggested-action"] popover: Gtk.Popover { - Gtk.Button { + Gtk.Button launch_game_debug { label: "Launch in debug mode"; } }; diff --git a/assets/ui/preferences_general.blp b/assets/ui/preferences_general.blp index 9d297de..7bfad34 100644 --- a/assets/ui/preferences_general.blp +++ b/assets/ui/preferences_general.blp @@ -26,7 +26,7 @@ Adw.PreferencesPage general_page { Adw.ActionRow { title: "Game version"; - Gtk.Label { + Gtk.Label game_version { label: "2.7.0"; styles ["success"] @@ -36,7 +36,7 @@ Adw.PreferencesPage general_page { Adw.ActionRow { title: "Patch version"; - Gtk.Label { + Gtk.Label patch_version { label: "2.7.0"; styles ["success"] diff --git a/src/lib/game.rs b/src/lib/game.rs index 687aa52..3992404 100644 --- a/src/lib/game.rs +++ b/src/lib/game.rs @@ -27,6 +27,22 @@ impl Terminal { Terminal::Xfce4Terminal ].into_iter() } + + pub fn get_args(&self, bash_command: &str) -> Vec { + match self { + Terminal::GnomeTerminal => vec![ + String::from("--"), + String::from("bash"), + String::from("-c"), + format!("{} && bash", bash_command) + ], + Terminal::Konsole | Terminal::Xfce4Terminal => vec![ + String::from("--hold"), + String::from("-e"), + format!("\"bash -c '{} && bash'\"", bash_command) + ] + } + } } /// Try to get GUI terminal installed in system @@ -43,7 +59,9 @@ pub fn try_get_terminal() -> Option { } /// Try to run the game -pub fn run() -> Result<(), Error> { +/// +/// If `debug = true`, then the game will be run in the new terminal window +pub fn run(debug: bool) -> Result<(), Error> { let config = config::get()?; if !Path::new(&config.game.path).exists() { @@ -57,12 +75,31 @@ pub fn run() -> Result<(), Error> { let mut command = Command::new(wine_executable); + if debug { + // Is not supported now because new spawned terminal needs + // to have cwd and env variables specified directly + // which is kinda difficult + todo!(); + + match try_get_terminal() { + Some(terminal) => { + command = Command::new(terminal.get_command()); + + command.args(terminal.get_args("launcher.bat")); + }, + None => return Err(Error::new(ErrorKind::Other, "Couldn't find terminal application")) + } + } + + else { + command.arg("launcher.bat"); + } + command.env("WINEPREFIX", &config.game.wine.prefix); command.envs(config.get_wine_sync_env_vars()); command.envs(config.game.environment) .current_dir(config.game.path) - .arg("launcher.bat") .spawn()?; Ok(()) diff --git a/src/main.rs b/src/main.rs index 6118e29..b37d182 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,8 +20,12 @@ fn main() { application.connect_activate(|app| { let app = MainApp::new(app).unwrap(); + let app_copy = app.clone(); + app.open_preferences.connect_clicked(move |_| { - app.leaflet.set_visible_child_name("preferences_page"); + if let Err(err) = app_copy.open_preferences_page() { + app_copy.toast_error("Failed to open settings page", err); + } }); app.window.show(); diff --git a/src/ui/main.rs b/src/ui/main.rs index b5a4cd3..600e9d8 100644 --- a/src/ui/main.rs +++ b/src/ui/main.rs @@ -1,6 +1,8 @@ use gtk4::{self as gtk, prelude::*}; use libadwaita::{self as adw, prelude::*}; +use std::io::Error; + use super::{get_object, add_action}; use super::preferences::PreferencesStack; @@ -11,8 +13,11 @@ pub struct App { pub window: adw::ApplicationWindow, pub leaflet: adw::Leaflet, pub launch_game: adw::SplitButton, + pub launch_game_debug: gtk::Button, pub open_preferences: gtk::Button, - pub toast_overlay: adw::ToastOverlay + pub toast_overlay: adw::ToastOverlay, + + pub preferences_stack: PreferencesStack } impl App { @@ -25,18 +30,20 @@ impl App { window: get_object(&builder, "window")?, leaflet: get_object(&builder, "leaflet")?, launch_game: get_object(&builder, "launch_game")?, + launch_game_debug: get_object(&builder, "launch_game_debug")?, open_preferences: get_object(&builder, "open_preferences")?, - toast_overlay: get_object(&builder, "toast_overlay")? + toast_overlay: get_object(&builder, "toast_overlay")?, + + preferences_stack: PreferencesStack::new()? }; // Add preferences page to the leaflet - let stack = PreferencesStack::new()?; let leaflet = result.leaflet.clone(); - result.leaflet.append(&stack.preferences).set_name(Some("preferences_page")); + result.leaflet.append(&result.preferences_stack.preferences).set_name(Some("preferences_page")); // Go back button for preferences page - stack.preferences_go_back.connect_clicked(move |_| { + result.preferences_stack.preferences_go_back.connect_clicked(move |_| { leaflet.navigate(adw::NavigationDirection::Back); }); @@ -45,11 +52,21 @@ impl App { result.launch_game.connect_clicked(move |_| { // Display toast message if the game is failed to run - if let Err(err) = game::run() { + if let Err(err) = game::run(false) { app_copy.toast_error("Failed to run game", err); } }); + // Launch game in debug mode + /*let app_copy = result.clone(); + + result.launch_game_debug.connect_clicked(move |_| { + // Display toast message if the game is failed to run + if let Err(err) = game::run(true) { + app_copy.toast_error("Failed to run game", err); + } + });*/ + // Bind app to the window result.window.set_application(Some(app)); @@ -86,4 +103,12 @@ impl App { self.toast_overlay.add_toast(&toast); } + + pub fn open_preferences_page(&self) -> Result<(), Error> { + self.preferences_stack.update()?; + + self.leaflet.set_visible_child_name("preferences_page"); + + Ok(()) + } } diff --git a/src/ui/preferences/enhanced_page.rs b/src/ui/preferences/enhanced_page.rs index 8e4a1cf..cb89a8c 100644 --- a/src/ui/preferences/enhanced_page.rs +++ b/src/ui/preferences/enhanced_page.rs @@ -3,13 +3,18 @@ use libadwaita::{self as adw, prelude::*}; use crate::ui::get_object; -pub struct Page; +#[derive(Clone)] +pub struct Page { + pub page: adw::PreferencesPage +} impl Page { - pub fn get() -> Result { + pub fn new() -> Result { let builder = gtk::Builder::from_string(include_str!("../../../assets/ui/.dist/preferences_enhanced.ui")); - Ok(get_object(&builder, "enhanced_page")?) + Ok(Self { + page: get_object(&builder, "enhanced_page")? + }) } pub fn title() -> String { diff --git a/src/ui/preferences/general_page.rs b/src/ui/preferences/general_page.rs index 06ecda7..e63a105 100644 --- a/src/ui/preferences/general_page.rs +++ b/src/ui/preferences/general_page.rs @@ -3,13 +3,22 @@ use libadwaita::{self as adw, prelude::*}; use crate::ui::get_object; -pub struct Page; +#[derive(Clone)] +pub struct Page { + pub page: adw::PreferencesPage, + pub game_version: gtk::Label, + pub patch_version: gtk::Label +} impl Page { - pub fn get() -> Result { + pub fn new() -> Result { let builder = gtk::Builder::from_string(include_str!("../../../assets/ui/.dist/preferences_general.ui")); - Ok(get_object(&builder, "general_page")?) + Ok(Self { + page: get_object(&builder, "general_page")?, + game_version: get_object(&builder, "game_version")?, + patch_version: get_object(&builder, "patch_version")? + }) } pub fn title() -> String { diff --git a/src/ui/preferences/mod.rs b/src/ui/preferences/mod.rs index f7ec8ca..2994a11 100644 --- a/src/ui/preferences/mod.rs +++ b/src/ui/preferences/mod.rs @@ -1,7 +1,12 @@ use gtk4::{self as gtk, prelude::*}; use libadwaita::{self as adw, prelude::*}; +use std::io::Error; + +use anime_game_core::prelude::*; + use crate::ui::get_object; +use crate::lib::config; mod general_page; mod enhanced_page; @@ -11,10 +16,13 @@ pub mod pages { pub use super::enhanced_page::Page as EnhancedPage; } +#[derive(Clone)] pub struct PreferencesStack { pub preferences: gtk::Box, pub preferences_go_back: gtk::Button, - pub stack: gtk::Stack + pub stack: gtk::Stack, + pub general_page: pages::GeneralPage, + pub enhanced_page: pages::EnhancedPage } impl PreferencesStack { @@ -24,12 +32,82 @@ impl PreferencesStack { let result = Self { preferences: get_object(&builder, "preferences")?, preferences_go_back: get_object(&builder, "preferences_go_back")?, - stack: get_object(&builder, "stack")? + stack: get_object(&builder, "stack")?, + general_page: pages::GeneralPage::new()?, + enhanced_page: pages::EnhancedPage::new()? }; - result.stack.add_titled(&pages::GeneralPage::get()?, None, &pages::GeneralPage::title()); - result.stack.add_titled(&pages::EnhancedPage::get()?, None, &pages::EnhancedPage::title()); + result.stack.add_titled(&result.general_page.page, None, &pages::GeneralPage::title()); + result.stack.add_titled(&result.enhanced_page.page, None, &pages::EnhancedPage::title()); Ok(result) } + + /// Update page info before opening it + /// + /// Being called from the `MainApp` struct + /// + /// TODO: do it asynchronously + pub fn update(&self) -> Result<(), Error> { + let config = config::get()?; + let game = Game::new(config.game.path); + + self.general_page.game_version.set_tooltip_text(None); + self.general_page.patch_version.set_tooltip_text(None); + + match game.try_get_diff()? { + VersionDiff::Latest(version) => { + self.general_page.game_version.set_label(&version.to_string()); + }, + VersionDiff::Diff { current, latest, .. } => { + self.general_page.game_version.set_label(¤t.to_string()); + self.general_page.game_version.set_css_classes(&["warning"]); + + self.general_page.game_version.set_tooltip_text(Some(&format!("Game update available: {} -> {}", current, latest))); + }, + VersionDiff::Outdated { current, latest } => { + self.general_page.game_version.set_label(¤t.to_string()); + self.general_page.game_version.set_css_classes(&["error"]); + + self.general_page.game_version.set_tooltip_text(Some(&format!("Game is too outdated and can't be updated. Latest version: {}", latest))); + }, + VersionDiff::NotInstalled { .. } => { + self.general_page.game_version.set_label("not installed"); + self.general_page.game_version.set_css_classes(&[]); + } + } + + match Patch::try_fetch(config.patch.servers)? { + Patch::NotAvailable => { + self.general_page.patch_version.set_label("not available"); + self.general_page.patch_version.set_css_classes(&["error"]); + + self.general_page.patch_version.set_tooltip_text(Some("Patch is not available")); + }, + Patch::Outdated { current, latest, .. } => { + self.general_page.patch_version.set_label("outdated"); + self.general_page.patch_version.set_css_classes(&["warning"]); + + self.general_page.patch_version.set_tooltip_text(Some(&format!("Patch is outdated ({} -> {})", current, latest))); + }, + Patch::Preparation { .. } => { + self.general_page.patch_version.set_label("preparation"); + self.general_page.patch_version.set_css_classes(&["warning"]); + + self.general_page.patch_version.set_tooltip_text(Some("Patch is in preparation state and will be available later")); + }, + Patch::Testing { version, .. } => { + self.general_page.patch_version.set_label(&version.to_string()); + self.general_page.patch_version.set_css_classes(&["warning"]); + + self.general_page.patch_version.set_tooltip_text(Some("Patch is in testing phase")); + }, + Patch::Available { version, .. } => { + self.general_page.patch_version.set_label(&version.to_string()); + self.general_page.patch_version.set_css_classes(&["success"]); + } + } + + Ok(()) + } }