Several changes

- renamed `ToastError` trait to `Toast`;
  renamed its `toast_error` method to `toast`;
  now `toast` method will not display button if toast's message is empty
- updated `game::run` function, now it prints running command
  and supports `gamemoderun`
This commit is contained in:
Observer KRypt0n_ 2022-08-02 09:38:27 +02:00
parent 85b2e6741e
commit 114d388a8c
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
7 changed files with 105 additions and 82 deletions

View file

@ -61,7 +61,7 @@ pub fn try_get_terminal() -> Option<Terminal> {
/// Try to run the game
///
/// If `debug = true`, then the game will be run in the new terminal window
pub fn run(debug: bool) -> Result<(), Error> {
pub fn run(debug: bool) -> std::io::Result<()> {
let config = config::get()?;
if !Path::new(&config.game.path).exists() {
@ -73,7 +73,15 @@ pub fn run(debug: bool) -> Result<(), Error> {
None => return Err(Error::new(ErrorKind::Other, "Couldn't find wine executable"))
};
let mut command = Command::new(wine_executable);
// Prepare bash -c '<command>'
let mut bash_chain = String::new();
if config.game.enhancements.gamemode {
bash_chain += "gamemoderun ";
}
bash_chain += &format!("'{}' ", wine_executable);
if debug {
// Is not supported now because new spawned terminal needs
@ -92,9 +100,16 @@ pub fn run(debug: bool) -> Result<(), Error> {
}
else {
command.arg("launcher.bat");
bash_chain += "launcher.bat";
}
let mut command = Command::new("bash");
command.arg("-c");
command.arg(&bash_chain);
// Setup environment
command.env("WINEPREFIX", &config.game.wine.prefix);
// Add DXVK_ASYNC=1 for dxvk-async builds automatically
@ -109,9 +124,13 @@ pub fn run(debug: bool) -> Result<(), Error> {
command.envs(config.game.enhancements.fsr.get_env_vars());
command.envs(config.game.wine.language.get_env_vars());
command.envs(config.game.environment)
.current_dir(config.game.path)
.spawn()?;
command.envs(config.game.environment);
// Run command
println!("Running command: bash -c \"{}\"", bash_chain);
command.current_dir(config.game.path).spawn()?;
Ok(())
}

View file

@ -15,7 +15,7 @@ use wait_not_await::Await;
use crate::ui::*;
use super::preferences::PreferencesStack;
use super::traits::toast_error::ToastError;
use super::traits::toast::Toast;
use super::components::progress_bar::*;
use crate::lib::config;
@ -135,7 +135,7 @@ pub enum Actions {
ShowProgressBar,
UpdateProgress { fraction: Rc<f64>, title: Rc<String> },
HideProgressBar,
ToastError(Rc<(String, Error)>)
Toast(Rc<(String, Error)>)
}
impl Actions {
@ -239,7 +239,7 @@ impl App {
glib::MainContext::default().invoke(move || {
this.update(Actions::PreferencesGoBack).unwrap();
this.toast_error("Failed to update preferences", err);
this.toast("Failed to update preferences", err);
});
}
}));
@ -270,7 +270,7 @@ impl App {
if let Err(err) = game::run(false) {
this.widgets.window.show();
this.toast_error("Failed to run game", err);
this.toast("Failed to run game", err);
}
else {
@ -318,20 +318,20 @@ impl App {
Ok(true) => synced = true,
Ok(false) => {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to sync patch folder"), Error::last_os_error()
)))).unwrap();
}
Err(err) => {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to sync patch folder"), err
)))).unwrap();
}
}
}
Err(err) => this.update(Actions::ToastError(Rc::new((
Err(err) => this.update(Actions::Toast(Rc::new((
String::from("Failed to check patch folder state"), err
)))).unwrap()
}
@ -341,7 +341,7 @@ impl App {
Ok(_) => (),
Err(err) => {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to patch game"), err
)))).unwrap();
}
@ -395,7 +395,7 @@ impl App {
ProgressUpdateResult::Error(msg, err) => {
this.widgets.progress_bar.hide();
this.toast_error(msg, err);
this.toast(msg, err);
}
ProgressUpdateResult::Finished => {
@ -419,10 +419,10 @@ impl App {
});
});
},
Err(err) => this.toast_error("Failed to init wine version installer", err)
Err(err) => this.toast("Failed to init wine version installer", err)
}
},
Err(err) => this.toast_error("Failed to get latest wine version", err)
Err(err) => this.toast("Failed to get latest wine version", err)
}
}
@ -430,7 +430,7 @@ impl App {
this.update_state();
}
},
Err(err) => this.toast_error("Failed to list downloaded wine versions", err)
Err(err) => this.toast("Failed to list downloaded wine versions", err)
}
}
@ -445,7 +445,7 @@ impl App {
this.widgets.launch_game.set_sensitive(false);
if let Err(err) = prefix.update(&config.game.wine.builds, wine) {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to create wine prefix"), err
)))).unwrap();
}
@ -455,7 +455,7 @@ impl App {
this.update_state();
});
},
None => this.toast_error("Failed to get selected wine version", Error::last_os_error())
None => this.toast("Failed to get selected wine version", Error::last_os_error())
}
}
@ -477,7 +477,7 @@ impl App {
ProgressUpdateResult::Error(msg, err) => {
this.widgets.progress_bar.hide();
this.toast_error(msg, err);
this.toast(msg, err);
}
ProgressUpdateResult::Finished => {
@ -516,7 +516,7 @@ impl App {
LauncherState::VoiceOutdated(_) => ()
}
},
Err(err) => this.toast_error("Failed to load config", err)
Err(err) => this.toast("Failed to load config", err)
}
}
@ -648,7 +648,7 @@ impl App {
for (i, file) in broken.into_iter().enumerate() {
if !is_patch_applied || !should_ignore(&file.path) {
if let Err(err) = file.repair(&config.game.path) {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to repair game file"), err
)))).unwrap();
}
@ -666,7 +666,7 @@ impl App {
this.update(Actions::HideProgressBar).unwrap();
},
Err(err) => {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to get integrity files"), err
)))).unwrap();
@ -675,7 +675,7 @@ impl App {
}
});
},
Err(err) => this.toast_error("Failed to load config", err)
Err(err) => this.toast("Failed to load config", err)
}
}
@ -691,10 +691,10 @@ impl App {
this.widgets.progress_bar.hide();
}
Actions::ToastError(toast) => {
Actions::Toast(toast) => {
let (msg, err) = (toast.0.clone(), toast.1.to_string());
this.toast_error(msg, err);
this.toast(msg, err);
}
}
@ -829,7 +829,7 @@ impl App {
send.send(Err(err.to_string())).unwrap();
glib::MainContext::default().invoke(move || {
this.toast_error("Failed to get initial launcher state", err);
this.toast("Failed to get initial launcher state", err);
});
}
}
@ -841,7 +841,7 @@ impl App {
}
}
impl ToastError for App {
impl Toast for App {
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) {
(self.widgets.window.clone(), self.widgets.toast_overlay.clone())
}

View file

@ -171,7 +171,7 @@ pub enum Actions {
SelectDxvkVersion(Rc<usize>),
UpdateWineComboRow,
SelectWineVersion(Rc<usize>),
ToastError(Rc<(String, Error)>)
Toast(Rc<(String, Error)>)
}
impl Actions {
@ -304,7 +304,7 @@ impl App {
match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) {
Ok(output) => println!("{}", output),
Err(err) => {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to apply DXVK"), err
)))).unwrap();
}
@ -352,7 +352,7 @@ impl App {
std::thread::spawn(move || {
if let Err(err) = component.package.delete_in(&config.game.path) {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to delete voiceover"), err
)))).unwrap();
}
@ -389,7 +389,7 @@ impl App {
if component.is_downloaded(&config.game.dxvk.builds) {
if let Err(err) = component.delete(&config.game.dxvk.builds) {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to delete DXVK"), err
)))).unwrap();
}
@ -405,7 +405,7 @@ impl App {
match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) {
Ok(output) => println!("{}", output),
Err(err) => {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to apply DXVK"), err
)))).unwrap();
}
@ -426,7 +426,7 @@ impl App {
if component.is_downloaded(&config.game.wine.builds) {
if let Err(err) = component.delete(&config.game.wine.builds) {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to delete wine"), err
)))).unwrap();
}
@ -501,7 +501,7 @@ impl App {
match version.apply(&config.game.dxvk.builds, &config.game.wine.prefix) {
Ok(output) => println!("{}", output),
Err(err) => {
this.update(Actions::ToastError(Rc::new((
this.update(Actions::Toast(Rc::new((
String::from("Failed to apply DXVK"), err
)))).unwrap();
}
@ -566,10 +566,10 @@ impl App {
config::update(config);
}
Actions::ToastError(toast) => {
Actions::Toast(toast) => {
let (msg, err) = (toast.0.clone(), toast.1.to_string());
this.toast_error(msg, err);
this.toast(msg, err);
}
}
@ -697,7 +697,7 @@ impl App {
}
}
impl ToastError for App {
impl Toast for App {
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) {
let app = (&*self.app).take();
self.app.set(app.clone());

View file

@ -89,7 +89,7 @@ impl PreferencesStack {
}
}
impl ToastError for PreferencesStack {
impl Toast for PreferencesStack {
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) {
let app = (&*self.app).take();
self.app.set(app.clone());

View file

@ -1,7 +1,7 @@
pub mod toast_error;
pub mod toast;
pub mod download_component;
pub mod prelude {
pub use super::toast_error::*;
pub use super::toast::*;
pub use super::download_component::*;
}

44
src/ui/traits/toast.rs Normal file
View file

@ -0,0 +1,44 @@
use gtk4::{self as gtk, prelude::*};
use libadwaita as adw;
use crate::ui::add_action;
pub trait Toast {
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay);
/// Show toast with `toast` title and `See message` button
///
/// This button will show message dialog with some message
fn toast<T: ToString, F: std::fmt::Display + 'static>(&self, toast: T, message: F) {
let toast = adw::Toast::new(toast.to_string().as_str());
let (window, toast_overlay) = self.get_toast_widgets();
toast.set_timeout(0);
let message = format!("{}", message);
if message.len() > 0 {
toast.set_button_label(Some("See message"));
toast.set_action_name(Some("see-message.see-message"));
// Show message in a dialog window
add_action(&toast_overlay, "see-message", move || {
let dialog = gtk::MessageDialog::new(
Some(&window),
gtk::DialogFlags::all(),
gtk::MessageType::Info,
gtk::ButtonsType::Close,
&message
);
dialog.connect_response(move |dialog, _| {
dialog.close();
});
dialog.show();
});
}
toast_overlay.add_toast(&toast);
}
}

View file

@ -1,40 +0,0 @@
use gtk4::{self as gtk, prelude::*};
use libadwaita as adw;
use crate::ui::add_action;
pub trait ToastError {
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay);
/// Show toast with `toast` title and `See message` button
///
/// This button will show message dialog with error message
fn toast_error<T: ToString, F: std::fmt::Display + 'static>(&self, toast: T, err: F) {
let toast = adw::Toast::new(toast.to_string().as_str());
toast.set_button_label(Some("See message"));
toast.set_action_name(Some("see-message.see-message"));
toast.set_timeout(0);
let (window, toast_overlay) = self.get_toast_widgets();
// Show error message in a dialog window
add_action(&toast_overlay, "see-message", move || {
let dialog = gtk::MessageDialog::new(
Some(&window),
gtk::DialogFlags::all(),
gtk::MessageType::Info,
gtk::ButtonsType::Close,
&format!("{}", err)
);
dialog.connect_response(move |dialog, _| {
dialog.close();
});
dialog.show();
});
toast_overlay.add_toast(&toast);
}
}