diff --git a/Cargo.lock b/Cargo.lock index 117a3d7..1f5b91e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,7 +31,7 @@ dependencies = [ [[package]] name = "anime-game-core" -version = "1.1.8" +version = "1.1.9" dependencies = [ "anyhow", "bzip2", @@ -56,6 +56,7 @@ version = "1.1.3" dependencies = [ "anime-game-core", "anyhow", + "cached", "dirs", "gtk4", "lazy_static", @@ -2303,9 +2304,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wincompatlib" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fb138cb8c6312731e7385e4500a2491be768ff4c8cfc04544dcc9227533f250" +checksum = "34cd4c8511402616780eeb46726ca69ad958c4ba123398389ce306552428b715" dependencies = [ "regex", ] diff --git a/Cargo.toml b/Cargo.toml index 600e890..defe395 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ adw = { package = "libadwaita", version = "0.2.0-alpha.3", features = ["v1_2"] } rfd = { version = "0.10", features = ["xdg-portal"], default-features = false } anime-game-core = { path = "anime-game-core", features = ["all", "static", "genshin"] } -wincompatlib = { version = "0.1.0", features = ["dxvk"] } +wincompatlib = { version = "0.1.2", features = ["dxvk"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -32,3 +32,4 @@ regex = "1.6.0" lazy_static = "1.4.0" anyhow = "1.0" md5 = "0.7" +cached = { version = "0.39", features = ["proc_macro"]} diff --git a/anime-game-core b/anime-game-core index 6230dbf..66b0e5f 160000 --- a/anime-game-core +++ b/anime-game-core @@ -1 +1 @@ -Subproject commit 6230dbf8ca26e3cd34cbe32468df18c823e89158 +Subproject commit 66b0e5f9c44a7d3247010b9a830f386f715b5ac5 diff --git a/build.rs b/build.rs index a8f77f7..90785b8 100644 --- a/build.rs +++ b/build.rs @@ -31,42 +31,40 @@ fn blp_process_dir(dir: String) { let dist_dir = format!("assets/ui/.dist/{}", &dir).replace("//", "/"); if let Ok(entries) = read_dir(&source_dir) { - if let Err(_) = read_dir(&dist_dir) { + if read_dir(&dist_dir).is_err() { create_dir_all(&dist_dir).expect("UI dist dir couldn't be created"); } // println!("cargo:rerun-if-changed={}/*.blp", &source_dir); - for entry in entries { - if let Ok(entry) = entry { - if let Ok(metadata) = entry.metadata() { - let entry_path = entry.path().to_str().unwrap().to_string(); - let entry_filename = entry.file_name().to_str().unwrap().to_string(); + for entry in entries.flatten() { + if let Ok(metadata) = entry.metadata() { + let entry_path = entry.path().to_str().unwrap().to_string(); + let entry_filename = entry.file_name().to_str().unwrap().to_string(); - if metadata.is_file() { - let entry_dist_path = format!("{}/{}.ui", &dist_dir, &entry_filename[..entry_filename.len() - 4]); + if metadata.is_file() { + let entry_dist_path = format!("{}/{}.ui", &dist_dir, &entry_filename[..entry_filename.len() - 4]); - match compile_blueprint(&entry_path) { - Ok(xml) => { - let result = fs::write(entry_dist_path, xml); + match compile_blueprint(&entry_path) { + Ok(xml) => { + let result = fs::write(entry_dist_path, xml); - if let Err(err) = result { - println!("cargo:warning=Couldn't write compiled XML UI: {}", err); - } - }, - Err(err) => { - if Path::new(&entry_dist_path).exists() { - fs::remove_file(entry_dist_path).expect("Couldn't remove broken file"); - } - - println!("cargo:warning=Couldn't compile {}: {}", entry_path, err); + if let Err(err) = result { + println!("cargo:warning=Couldn't write compiled XML UI: {}", err); } + }, + Err(err) => { + if Path::new(&entry_dist_path).exists() { + fs::remove_file(entry_dist_path).expect("Couldn't remove broken file"); + } + + println!("cargo:warning=Couldn't compile {}: {}", entry_path, err); } } + } - else if metadata.is_dir() && &entry_filename[0..1] != "." { - blp_process_dir(format!("{}/{}", &dir, &entry_filename)); - } + else if metadata.is_dir() && &entry_filename[0..1] != "." { + blp_process_dir(format!("{}/{}", &dir, &entry_filename)); } } } @@ -76,7 +74,7 @@ fn blp_process_dir(dir: String) { fn main() { blp_process_dir(String::new()); - if let Ok(_) = read_to_string("assets/resources.xml") { + if read_to_string("assets/resources.xml").is_ok() { gtk::gio::compile_resources( "assets", "assets/resources.xml", diff --git a/src/lib/config/game/dxvk.rs b/src/lib/config/game/dxvk.rs index aebee5c..ea0dbd6 100644 --- a/src/lib/config/game/dxvk.rs +++ b/src/lib/config/game/dxvk.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; @@ -5,7 +7,7 @@ use crate::lib::consts::launcher_dir; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Dxvk { - pub builds: String + pub builds: PathBuf } impl Default for Dxvk { @@ -13,7 +15,7 @@ impl Default for Dxvk { let launcher_dir = launcher_dir().expect("Failed to get launcher dir"); Self { - builds: format!("{launcher_dir}/dxvks") + builds: launcher_dir.join("dxvks") } } } @@ -24,7 +26,10 @@ impl From<&JsonValue> for Dxvk { Self { builds: match value.get("builds") { - Some(value) => value.as_str().unwrap_or(&default.builds).to_string(), + Some(value) => match value.as_str() { + Some(value) => PathBuf::from(value), + None => default.builds + }, None => default.builds } } diff --git a/src/lib/config/game/enhancements/fps_unlocker/mod.rs b/src/lib/config/game/enhancements/fps_unlocker/mod.rs index 1a9e1ca..040993b 100644 --- a/src/lib/config/game/enhancements/fps_unlocker/mod.rs +++ b/src/lib/config/game/enhancements/fps_unlocker/mod.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; @@ -15,7 +17,7 @@ use prelude::*; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FpsUnlocker { - pub path: String, + pub path: PathBuf, pub enabled: bool, pub config: Config } @@ -25,7 +27,7 @@ impl Default for FpsUnlocker { let launcher_dir = launcher_dir().expect("Failed to get launcher dir"); Self { - path: format!("{launcher_dir}/fps-unlocker"), + path: launcher_dir.join("fps-unlocker"), enabled: false, config: Config::default() } @@ -38,7 +40,10 @@ impl From<&JsonValue> for FpsUnlocker { Self { path: match value.get("path") { - Some(value) => value.as_str().unwrap_or(&default.path).to_string(), + Some(value) => match value.as_str() { + Some(value) => PathBuf::from(value), + None => default.path + }, None => default.path }, diff --git a/src/lib/config/game/enhancements/gamescope/window_type.rs b/src/lib/config/game/enhancements/gamescope/window_type.rs index 0ce8d4c..3889808 100644 --- a/src/lib/config/game/enhancements/gamescope/window_type.rs +++ b/src/lib/config/game/enhancements/gamescope/window_type.rs @@ -15,6 +15,6 @@ impl Default for WindowType { impl From<&JsonValue> for WindowType { fn from(value: &JsonValue) -> Self { - serde_json::from_value(value.clone()).unwrap_or(Self::default()) + serde_json::from_value(value.clone()).unwrap_or_default() } } diff --git a/src/lib/config/game/enhancements/hud.rs b/src/lib/config/game/enhancements/hud.rs index 2d97419..d95a706 100644 --- a/src/lib/config/game/enhancements/hud.rs +++ b/src/lib/config/game/enhancements/hud.rs @@ -20,7 +20,7 @@ impl Default for HUD { impl From<&JsonValue> for HUD { fn from(value: &JsonValue) -> Self { - serde_json::from_value(value.clone()).unwrap_or(Self::default()) + serde_json::from_value(value.clone()).unwrap_or_default() } } @@ -37,6 +37,7 @@ impl TryFrom for HUD { } } +#[allow(clippy::from_over_into)] impl Into for HUD { fn into(self) -> u32 { match self { diff --git a/src/lib/config/game/mod.rs b/src/lib/config/game/mod.rs index 443b337..df672e5 100644 --- a/src/lib/config/game/mod.rs +++ b/src/lib/config/game/mod.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::path::PathBuf; use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; @@ -21,7 +22,7 @@ use prelude::*; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Game { - pub path: String, + pub path: PathBuf, pub voices: Vec, pub wine: prelude::Wine, pub dxvk: prelude::Dxvk, @@ -35,7 +36,7 @@ impl Default for Game { let launcher_dir = launcher_dir().expect("Failed to get launcher dir"); Self { - path: format!("{launcher_dir}/game/drive_c/Program Files/Genshin Impact"), + path: launcher_dir.join("game/drive_c/Program Files/Genshin Impact"), voices: vec![ String::from("en-us") ], @@ -54,7 +55,10 @@ impl From<&JsonValue> for Game { Self { path: match value.get("path") { - Some(value) => value.as_str().unwrap_or(&default.path).to_string(), + Some(value) => match value.as_str() { + Some(value) => PathBuf::from(value), + None => default.path + }, None => default.path }, diff --git a/src/lib/config/game/wine/mod.rs b/src/lib/config/game/wine/mod.rs index dcb4f19..d48f627 100644 --- a/src/lib/config/game/wine/mod.rs +++ b/src/lib/config/game/wine/mod.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; @@ -18,8 +20,8 @@ use prelude::*; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Wine { - pub prefix: String, - pub builds: String, + pub prefix: PathBuf, + pub builds: PathBuf, pub selected: Option, pub sync: WineSync, pub language: WineLang, @@ -32,8 +34,8 @@ impl Default for Wine { let launcher_dir = launcher_dir().expect("Failed to get launcher dir"); Self { - prefix: format!("{launcher_dir}/game"), - builds: format!("{launcher_dir}/runners"), + prefix: launcher_dir.join("game"), + builds: launcher_dir.join("runners"), selected: None, sync: WineSync::default(), language: WineLang::default(), @@ -49,12 +51,18 @@ impl From<&JsonValue> for Wine { Self { prefix: match value.get("prefix") { - Some(value) => value.as_str().unwrap_or(&default.prefix).to_string(), + Some(value) => match value.as_str() { + Some(value) => PathBuf::from(value), + None => default.prefix + }, None => default.prefix }, builds: match value.get("builds") { - Some(value) => value.as_str().unwrap_or(&default.builds).to_string(), + Some(value) => match value.as_str() { + Some(value) => PathBuf::from(value), + None => default.builds + }, None => default.builds }, diff --git a/src/lib/config/game/wine/wine_lang.rs b/src/lib/config/game/wine/wine_lang.rs index 26c4b54..ad3d1eb 100644 --- a/src/lib/config/game/wine/wine_lang.rs +++ b/src/lib/config/game/wine/wine_lang.rs @@ -26,10 +26,11 @@ impl Default for WineLang { impl From<&JsonValue> for WineLang { fn from(value: &JsonValue) -> Self { - serde_json::from_value(value.clone()).unwrap_or(Self::default()) + serde_json::from_value(value.clone()).unwrap_or_default() } } +#[allow(clippy::from_over_into)] impl Into for WineLang { fn into(self) -> u32 { for (i, lang) in Self::list().into_iter().enumerate() { @@ -69,10 +70,6 @@ impl WineLang { model } - pub fn to_string(&self) -> String { - format!("{:?}", self) - } - /// Get environment variables corresponding to used wine language pub fn get_env_vars(&self) -> HashMap<&str, &str> { HashMap::from([("LANG", match self { @@ -91,3 +88,9 @@ impl WineLang { })]) } } + +impl std::fmt::Display for WineLang { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&format!("{:?}", self)) + } +} diff --git a/src/lib/config/game/wine/wine_sync.rs b/src/lib/config/game/wine/wine_sync.rs index 9e22dcc..183a834 100644 --- a/src/lib/config/game/wine/wine_sync.rs +++ b/src/lib/config/game/wine/wine_sync.rs @@ -19,7 +19,7 @@ impl Default for WineSync { impl From<&JsonValue> for WineSync { fn from(value: &JsonValue) -> Self { - serde_json::from_value(value.clone()).unwrap_or(Self::default()) + serde_json::from_value(value.clone()).unwrap_or_default() } } @@ -38,6 +38,7 @@ impl TryFrom for WineSync { } } +#[allow(clippy::from_over_into)] impl Into for WineSync { fn into(self) -> u32 { match self { diff --git a/src/lib/config/launcher/mod.rs b/src/lib/config/launcher/mod.rs index 9b7a1d7..f3d5635 100644 --- a/src/lib/config/launcher/mod.rs +++ b/src/lib/config/launcher/mod.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; @@ -41,11 +43,11 @@ impl Default for GameEdition { } } -impl Into for GameEdition { - fn into(self) -> CoreGameEdition { - match self { - Self::Global => CoreGameEdition::Global, - Self::China => CoreGameEdition::China +impl From for CoreGameEdition { + fn from(edition: GameEdition) -> Self { + match edition { + GameEdition::Global => CoreGameEdition::Global, + GameEdition::China => CoreGameEdition::China } } } @@ -62,7 +64,7 @@ impl From for GameEdition { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Launcher { pub language: String, - pub temp: Option, + pub temp: Option, pub speed_limit: u64, pub repairer: Repairer, pub edition: GameEdition @@ -96,7 +98,7 @@ impl From<&JsonValue> for Launcher { None } else { match value.as_str() { - Some(value) => Some(value.to_string()), + Some(value) => Some(PathBuf::from(value)), None => default.temp } } diff --git a/src/lib/config/mod.rs b/src/lib/config/mod.rs index 4e69f61..9a6965d 100644 --- a/src/lib/config/mod.rs +++ b/src/lib/config/mod.rs @@ -1,11 +1,13 @@ use std::fs::File; use std::io::Read; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::io::Write; use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; +use wincompatlib::dxvk::Dxvk; + use crate::lib; use super::consts::*; use super::wine::{ @@ -107,7 +109,7 @@ pub fn update_raw(config: Config) -> anyhow::Result<()> { match serde_json::to_string_pretty(&config) { Ok(json) => { - file.write_all(&mut json.as_bytes())?; + file.write_all(json.as_bytes())?; Ok(()) }, @@ -141,8 +143,7 @@ impl Config { Some(selected) => { WineList::get().iter() .flat_map(|group| group.versions.clone()) - .filter(|version| version.name.eq(selected)) - .next() + .find(|version| version.name.eq(selected)) }, None => None } @@ -153,12 +154,12 @@ impl Config { /// Returns `Some("wine64")` if: /// 1) `game.wine.selected = None` /// 2) wine64 installed and available in system - pub fn try_get_wine_executable(&self) -> Option { + pub fn try_get_wine_executable(&self) -> Option { match self.try_get_selected_wine_info() { - Some(selected) => Some(format!("{}/{}/{}", &self.game.wine.builds, selected.name, selected.files.wine64)), + Some(selected) => Some(self.game.wine.builds.join(selected.name).join(selected.files.wine64)), None => { if lib::is_available("wine64") { - Some(String::from("wine64")) + Some(PathBuf::from("wine64")) } else { None } @@ -173,34 +174,14 @@ impl Config { /// 2) `Ok(None)` if version wasn't found, so too old or dxvk is not applied /// 3) `Err(..)` if failed to get applied dxvk version, likely because wrong prefix path specified pub fn try_get_selected_dxvk_info(&self) -> std::io::Result> { - let (bytes, from, to) = match std::fs::read(format!("{}/drive_c/windows/system32/dxgi.dll", &self.game.wine.prefix)) { - Ok(bytes) => (bytes, 1600000, 1700000), - Err(_) => { - let bytes = std::fs::read(format!("{}/drive_c/windows/system32/d3d11.dll", &self.game.wine.prefix))?; - - (bytes, 2400000, 2500000) - } - }; - - let bytes = if bytes.len() > to { - bytes[from..to].to_vec() - } else { - return Ok(None); - }; - - Ok({ - DxvkList::get() - .iter() - .flat_map(|group| group.versions.clone()) - .filter(|version| { - let version = format!("\0v{}\0", &version.version); - let version = version.as_bytes(); - - bytes.windows(version.len()) - .position(|window| window == version) - .is_some() - }) - .next() + Ok(match Dxvk::get_version(&self.game.wine.prefix)? { + Some(version) => { + DxvkList::get() + .iter() + .flat_map(|group| group.versions.clone()) + .find(move |dxvk| dxvk.version == version) + }, + None => None }) } } diff --git a/src/lib/config/patch.rs b/src/lib/config/patch.rs index 47ff4a5..d8044ab 100644 --- a/src/lib/config/patch.rs +++ b/src/lib/config/patch.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; @@ -7,7 +7,7 @@ use crate::lib::consts::launcher_dir; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Patch { - pub path: String, + pub path: PathBuf, pub servers: Vec, pub root: bool } @@ -17,7 +17,7 @@ impl Default for Patch { let launcher_dir = launcher_dir().expect("Failed to get launcher dir"); Self { - path: format!("{launcher_dir}/patch"), + path: launcher_dir.join("patch"), servers: vec![ "https://notabug.org/Krock/dawn".to_string(), "https://codespace.gay/Maroxy/dawnin".to_string() @@ -35,7 +35,10 @@ impl From<&JsonValue> for Patch { Self { path: match value.get("path") { - Some(value) => value.as_str().unwrap_or(&default.path).to_string(), + Some(value) => match value.as_str() { + Some(value) => PathBuf::from(value), + None => default.path + }, None => default.path }, diff --git a/src/lib/config/resolution.rs b/src/lib/config/resolution.rs index 95dd82f..e71ebdb 100644 --- a/src/lib/config/resolution.rs +++ b/src/lib/config/resolution.rs @@ -64,10 +64,12 @@ impl Resolution { Self::Custom(w, h) => (*w, *h) } } +} - pub fn to_string(&self) -> String { +impl std::fmt::Display for Resolution { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let (w, h) = self.get_pair(); - format!("{w}x{h}") + f.write_str(&format!("{w}x{h}")) } } diff --git a/src/lib/consts.rs b/src/lib/consts.rs index bf1d7d1..ad3dce2 100644 --- a/src/lib/consts.rs +++ b/src/lib/consts.rs @@ -1,7 +1,7 @@ +use std::path::PathBuf; use std::time::Duration; -static mut LAUNCHER_DIR: Option> = None; -static mut CONFIG_FILE: Option> = None; +use cached::proc_macro::cached; /// Timeout used by `anime_game_core::telemetry::is_disabled` to check acessibility of telemetry servers pub const TELEMETRY_CHECK_TIMEOUT: Option = Some(Duration::from_secs(3)); @@ -9,38 +9,12 @@ pub const TELEMETRY_CHECK_TIMEOUT: Option = Some(Duration::from_secs(3 /// Timeout used by `anime_game_core::linux_patch::Patch::try_fetch` to fetch patch info pub const PATCH_FETCHING_TIMEOUT: Option = Some(Duration::from_secs(5)); -pub fn launcher_dir() -> Option { - unsafe { - match &LAUNCHER_DIR { - Some(value) => value.clone(), - None => { - let value = match dirs::data_dir() { - Some(dir) => Some(format!("{}/anime-game-launcher", dir.to_string_lossy())), - None => None - }; - - LAUNCHER_DIR = Some(value.clone()); - - value - } - } - } +#[cached] +pub fn launcher_dir() -> Option { + dirs::data_dir().map(|dir| dir.join("anime-game-launcher")) } -pub fn config_file() -> Option { - unsafe { - match &CONFIG_FILE { - Some(value) => value.clone(), - None => { - let value = match launcher_dir() { - Some(dir) => Some(format!("{}/config.json", dir)), - None => None - }; - - CONFIG_FILE = Some(value.clone()); - - value - } - } - } +#[cached] +pub fn config_file() -> Option { + launcher_dir().map(|dir| dir.join("config.json")) } diff --git a/src/lib/dxvk.rs b/src/lib/dxvk.rs index 198f9ab..42c71f9 100644 --- a/src/lib/dxvk.rs +++ b/src/lib/dxvk.rs @@ -33,12 +33,12 @@ impl List { } /// List only downloaded DXVK versions in some specific folder - pub fn list_downloaded(folder: T) -> std::io::Result> { + pub fn list_downloaded>(folder: T) -> std::io::Result> { let mut downloaded = Vec::new(); let list = Self::get(); - for entry in std::fs::read_dir(folder.to_string())? { + for entry in std::fs::read_dir(folder.into())? { let name = entry?.file_name(); for group in &list { @@ -76,32 +76,34 @@ impl Version { Ok(List::get()[0].versions[0].clone()) } - pub fn is_downloaded_in(&self, folder: T) -> bool { - std::path::Path::new(&format!("{}/{}", folder.to_string(), self.name)).exists() + pub fn is_downloaded_in>(&self, folder: T) -> bool { + folder.into().join(&self.name).exists() } - pub fn apply(&self, dxvks_folder: T, prefix_path: T) -> anyhow::Result { - let apply_path = format!("{}/{}/setup_dxvk.sh", dxvks_folder.to_string(), self.name); + pub fn apply>(&self, dxvks_folder: T, prefix_path: T) -> anyhow::Result { + let apply_path = dxvks_folder.into().join(&self.name).join("setup_dxvk.sh"); let config = config::get()?; let (wine_path, wineserver_path, wineboot_path) = match config.try_get_selected_wine_info() { Some(wine) => { - let wine_path = format!("{}/{}/{}", &config.game.wine.builds, wine.name, wine.files.wine64); - let wineserver_path = format!("{}/{}/{}", &config.game.wine.builds, wine.name, wine.files.wineserver); - let wineboot_path = format!("{}/{}/{}", &config.game.wine.builds, wine.name, wine.files.wineboot); + let wine_folder = config.game.wine.builds.join(wine.name); + + let wine_path = wine_folder.join(wine.files.wine64); + let wineserver_path = wine_folder.join(wine.files.wineserver); + let wineboot_path = wine_folder.join(wine.files.wineboot); (wine_path, wineserver_path, wineboot_path) }, - None => (String::from("wine64"), String::from("wineserver"), String::from("wineboot")) + None => (PathBuf::from("wine64"), PathBuf::from("wineserver"), PathBuf::from("wineboot")) }; let result = Dxvk::install( - PathBuf::from(apply_path), - PathBuf::from(prefix_path.to_string()), - PathBuf::from(&wine_path), - PathBuf::from(wine_path), - PathBuf::from(wineboot_path), - PathBuf::from(wineserver_path) + apply_path, + prefix_path.into(), + wine_path.clone(), + wine_path, + wineboot_path, + wineserver_path ); match result { diff --git a/src/lib/fps_unlocker/mod.rs b/src/lib/fps_unlocker/mod.rs index ccf957b..c4ffcf4 100644 --- a/src/lib/fps_unlocker/mod.rs +++ b/src/lib/fps_unlocker/mod.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use anime_game_core::installer::downloader::Downloader; use crate::lib::config::game::enhancements::fps_unlocker::config::Config as FpsUnlockerConfig; @@ -11,7 +13,7 @@ const LATEST_INFO: (&str, &str) = ( #[derive(Debug, Clone, PartialEq, Eq)] pub struct FpsUnlocker { - dir: String + dir: PathBuf } impl FpsUnlocker { @@ -21,28 +23,32 @@ impl FpsUnlocker { /// - `Err(..)` if failed to read `unlocker.exe` file /// - `Ok(None)` if version is not latest /// - `Ok(..)` if version is latest - pub fn from_dir(dir: T) -> anyhow::Result> { - let hash = format!("{:x}", md5::compute(std::fs::read(format!("{}/unlocker.exe", dir.to_string()))?)); + pub fn from_dir>(dir: T) -> anyhow::Result> { + let dir = dir.into(); - if hash == LATEST_INFO.0 { - Ok(Some(Self { dir: dir.to_string() })) + let hash = format!("{:x}", md5::compute(std::fs::read(dir.join("unlocker.exe"))?)); + + Ok(if hash == LATEST_INFO.0 { + Some(Self { dir }) } else { - Ok(None) - } + None + }) } /// Download FPS unlocker to specified directory - pub fn download(dir: T) -> anyhow::Result { + pub fn download>(dir: T) -> anyhow::Result { let mut downloader = Downloader::new(LATEST_INFO.1)?; + let dir = dir.into(); + // Create FPS unlocker folder if needed - if !std::path::Path::new(&dir.to_string()).exists() { - std::fs::create_dir_all(dir.to_string())?; + if !dir.exists() { + std::fs::create_dir_all(&dir)?; } - match downloader.download_to(format!("{}/unlocker.exe", dir.to_string()), |_, _| {}) { + match downloader.download_to(dir.join("unlocker.exe"), |_, _| {}) { Ok(_) => Ok(Self { - dir: dir.to_string() + dir }), Err(err) => { let err: std::io::Error = err.into(); @@ -52,16 +58,16 @@ impl FpsUnlocker { } } - pub fn get_binary(&self) -> String { + pub fn get_binary(&self) -> PathBuf { Self::get_binary_in(&self.dir) } - pub fn get_binary_in(dir: T) -> String { - format!("{}/unlocker.exe", dir.to_string()) + pub fn get_binary_in>(dir: T) -> PathBuf { + dir.into().join("unlocker.exe") } - pub fn dir(&self) -> &str { - self.dir.as_str() + pub fn dir(&self) -> &PathBuf { + &self.dir } /// Generate and save FPS unlocker config file to the game's directory @@ -69,7 +75,7 @@ impl FpsUnlocker { let config = config_schema::ConfigSchema::from_config(config); Ok(std::fs::write( - format!("{}/fps_config.json", self.dir), + self.dir.join("fps_config.json"), config.json()? )?) } diff --git a/src/lib/game.rs b/src/lib/game.rs index 1dd3eb8..f62a350 100644 --- a/src/lib/game.rs +++ b/src/lib/game.rs @@ -110,13 +110,13 @@ pub fn run() -> anyhow::Result<()> { return Err(anyhow::anyhow!("Failed to update FPS unlocker config: {err}")); } - let bat_path = format!("{}/fpsunlocker.bat", config.game.path); - let original_bat_path = format!("{}/launcher.bat", config.game.path); + let bat_path = config.game.path.join("fpsunlocker.bat"); + let original_bat_path = config.game.path.join("launcher.bat"); // Generate fpsunlocker.bat from launcher.bat std::fs::write(bat_path, std::fs::read_to_string(original_bat_path)? - .replace("start GenshinImpact.exe %*", &format!("start GenshinImpact.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir())) - .replace("start YuanShen.exe %*", &format!("start YuanShen.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir())))?; + .replace("start GenshinImpact.exe %*", &format!("start GenshinImpact.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir().to_string_lossy())) + .replace("start YuanShen.exe %*", &format!("start YuanShen.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir().to_string_lossy())))?; } // Prepare bash -c '' @@ -127,7 +127,7 @@ pub fn run() -> anyhow::Result<()> { bash_chain += "gamemoderun "; } - bash_chain += &format!("'{wine_executable}' "); + bash_chain += &format!("'{}' ", wine_executable.to_string_lossy()); if let Some(virtual_desktop) = config.game.wine.virtual_desktop.get_command() { bash_chain += &format!("{virtual_desktop} "); diff --git a/src/lib/launcher/states.rs b/src/lib/launcher/states.rs index f6b0b4e..eca61c9 100644 --- a/src/lib/launcher/states.rs +++ b/src/lib/launcher/states.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use anime_game_core::prelude::*; use anime_game_core::genshin::prelude::*; @@ -51,12 +49,12 @@ impl LauncherState { let config = config::get()?; // Check wine existence - if let None = config.try_get_wine_executable() { + if config.try_get_wine_executable().is_none() { return Ok(Self::WineNotInstalled); } // Check prefix existence - if !PathBuf::from(&config.game.wine.prefix).join("drive_c").exists() { + if !config.game.wine.prefix.join("drive_c").exists() { return Ok(Self::PrefixNotExists); } diff --git a/src/lib/wine.rs b/src/lib/wine.rs index db67078..c92020d 100644 --- a/src/lib/wine.rs +++ b/src/lib/wine.rs @@ -37,12 +37,12 @@ impl List { } /// List only downloaded wine versions in some specific folder - pub fn list_downloaded(folder: T) -> std::io::Result> { + pub fn list_downloaded>(folder: T) -> std::io::Result> { let mut downloaded = Vec::new(); let list = Self::get(); - for entry in std::fs::read_dir(folder.to_string())? { + for entry in std::fs::read_dir(folder.into())? { let name = entry?.file_name(); for group in &list { diff --git a/src/main.rs b/src/main.rs index 9c65572..bc323a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,9 +69,9 @@ fn main() { // Create default launcher folder if needed let launcher_dir = lib::consts::launcher_dir().expect("Failed to get launcher dir"); - if !Path::new(&launcher_dir).exists() || Path::new(&format!("{}/.first-run", launcher_dir)).exists() { + if !launcher_dir.exists() || launcher_dir.join(".first-run").exists() { fs::create_dir_all(&launcher_dir).expect("Failed to create default launcher dir"); - fs::write(format!("{}/.first-run", launcher_dir), "").expect("Failed to create .first-run file"); + fs::write(launcher_dir.join(".first-run"), "").expect("Failed to create .first-run file"); let first_run = FirstRunApp::new(app).expect("Failed to init FirstRunApp"); diff --git a/src/ui/components/dxvk_group.rs b/src/ui/components/dxvk_group.rs index ee7ce05..5948c80 100644 --- a/src/ui/components/dxvk_group.rs +++ b/src/ui/components/dxvk_group.rs @@ -1,5 +1,7 @@ use adw::prelude::*; +use std::path::PathBuf; + use crate::lib::dxvk::Group; use super::dxvk_row::DxvkRow; @@ -35,9 +37,11 @@ impl DxvkGroup { } } - pub fn update_states(&self, runners_folder: T) { + pub fn update_states>(&self, runners_folder: T) { + let runners_folder = runners_folder.into(); + for component in &self.version_components { - component.update_state(runners_folder.to_string()); + component.update_state(&runners_folder); } } } diff --git a/src/ui/components/dxvk_row.rs b/src/ui/components/dxvk_row.rs index 0ac93f6..05e17a8 100644 --- a/src/ui/components/dxvk_row.rs +++ b/src/ui/components/dxvk_row.rs @@ -1,6 +1,8 @@ use gtk::prelude::*; use adw::prelude::*; +use std::path::PathBuf; + use crate::lib::dxvk::Version; use crate::ui::traits::download_component::*; @@ -57,7 +59,7 @@ impl DxvkRow { } } - pub fn update_state(&self, dxvks_folder: T) { + pub fn update_state>(&self, dxvks_folder: T) { if self.is_downloaded(dxvks_folder) { self.button.set_icon_name("user-trash-symbolic"); @@ -71,7 +73,7 @@ impl DxvkRow { } } - pub fn apply(&self, dxvks_folder: T, prefix_path: T) -> anyhow::Result { + pub fn apply>(&self, dxvks_folder: T, prefix_path: T) -> anyhow::Result { self.button.set_sensitive(false); self.apply_button.set_sensitive(false); @@ -85,8 +87,8 @@ impl DxvkRow { } impl DownloadComponent for DxvkRow { - fn get_component_path(&self, installation_path: T) -> String { - format!("{}/{}", installation_path.to_string(), self.version.name) + fn get_component_path>(&self, installation_path: T) -> PathBuf { + installation_path.into().join(&self.version.name) } fn get_downloading_widgets(&self) -> (gtk::ProgressBar, gtk::Button) { diff --git a/src/ui/components/wine_group.rs b/src/ui/components/wine_group.rs index 164e649..00c8017 100644 --- a/src/ui/components/wine_group.rs +++ b/src/ui/components/wine_group.rs @@ -1,5 +1,7 @@ use adw::prelude::*; +use std::path::PathBuf; + use crate::lib::wine::Group; use super::wine_row::WineRow; @@ -35,9 +37,11 @@ impl WineGroup { } } - pub fn update_states(&self, runners_folder: T) { + pub fn update_states>(&self, runners_folder: T) { + let runners_folder = runners_folder.into(); + for component in &self.version_components { - component.update_state(runners_folder.to_string()); + component.update_state(&runners_folder); } } } diff --git a/src/ui/components/wine_row.rs b/src/ui/components/wine_row.rs index 4b816e2..77aa79a 100644 --- a/src/ui/components/wine_row.rs +++ b/src/ui/components/wine_row.rs @@ -1,6 +1,8 @@ use gtk::prelude::*; use adw::prelude::*; +use std::path::PathBuf; + use crate::lib::wine::Version; use crate::ui::traits::download_component::*; @@ -46,7 +48,7 @@ impl WineRow { } } - pub fn update_state(&self, runners_folder: T) { + pub fn update_state>(&self, runners_folder: T) { if self.is_downloaded(runners_folder) { self.button.set_icon_name("user-trash-symbolic"); } @@ -58,8 +60,8 @@ impl WineRow { } impl DownloadComponent for WineRow { - fn get_component_path(&self, installation_path: T) -> String { - format!("{}/{}", installation_path.to_string(), self.version.name) + fn get_component_path>(&self, installation_path: T) -> PathBuf { + installation_path.into().join(&self.version.name) } fn get_downloading_widgets(&self) -> (gtk::ProgressBar, gtk::Button) { diff --git a/src/ui/first_run/default_paths.rs b/src/ui/first_run/default_paths.rs index 64d864b..a373cd6 100644 --- a/src/ui/first_run/default_paths.rs +++ b/src/ui/first_run/default_paths.rs @@ -3,6 +3,8 @@ use adw::prelude::*; use gtk::glib; use gtk::glib::clone; +use std::path::PathBuf; + use wait_not_await::Await; use crate::lib::config; @@ -65,13 +67,13 @@ impl Page { let config = config::get()?; // Add paths to subtitles - result.runners_folder.set_subtitle(&config.game.wine.builds); - result.dxvk_folder.set_subtitle(&config.game.dxvk.builds); - result.prefix_folder.set_subtitle(&config.game.wine.prefix); - result.game_folder.set_subtitle(&config.game.path); - result.patch_folder.set_subtitle(&config.patch.path); + result.runners_folder.set_subtitle(config.game.wine.builds.to_str().unwrap()); + result.dxvk_folder.set_subtitle(config.game.dxvk.builds.to_str().unwrap()); + result.prefix_folder.set_subtitle(config.game.wine.prefix.to_str().unwrap()); + result.game_folder.set_subtitle(config.game.path.to_str().unwrap()); + result.patch_folder.set_subtitle(config.patch.path.to_str().unwrap()); result.temp_folder.set_subtitle(&match config.launcher.temp { - Some(temp) => temp, + Some(temp) => temp.to_string_lossy().to_string(), None => String::from("/tmp") }); @@ -107,12 +109,12 @@ impl Page { } pub fn update_config(&self, mut config: config::Config) -> config::Config { - config.game.wine.builds = self.runners_folder.subtitle().unwrap().to_string(); - config.game.dxvk.builds = self.dxvk_folder.subtitle().unwrap().to_string(); - config.game.wine.prefix = self.prefix_folder.subtitle().unwrap().to_string(); - config.game.path = self.game_folder.subtitle().unwrap().to_string(); - config.patch.path = self.patch_folder.subtitle().unwrap().to_string(); - config.launcher.temp = Some(self.temp_folder.subtitle().unwrap().to_string()); + config.game.wine.builds = PathBuf::from(self.runners_folder.subtitle().unwrap().to_string()); + config.game.dxvk.builds = PathBuf::from(self.dxvk_folder.subtitle().unwrap().to_string()); + config.game.wine.prefix = PathBuf::from(self.prefix_folder.subtitle().unwrap().to_string()); + config.game.path = PathBuf::from(self.game_folder.subtitle().unwrap().to_string()); + config.patch.path = PathBuf::from(self.patch_folder.subtitle().unwrap().to_string()); + config.launcher.temp = Some(PathBuf::from(self.temp_folder.subtitle().unwrap().to_string())); config } diff --git a/src/ui/first_run/mod.rs b/src/ui/first_run/mod.rs index 03f9b96..8b54e06 100644 --- a/src/ui/first_run/mod.rs +++ b/src/ui/first_run/mod.rs @@ -6,7 +6,6 @@ use gtk::glib::clone; use std::rc::Rc; use std::cell::Cell; use std::process::Command; -use std::path::PathBuf; use anime_game_core::prelude::*; @@ -248,7 +247,7 @@ impl App { let progress_bar = this.widgets.download_components.progress_bar.clone(); - let wine_version = this.widgets.download_components.get_wine_version().clone(); + let wine_version = this.widgets.download_components.get_wine_version(); let dxvk_version = this.widgets.download_components.get_dxvk_version().clone(); // Prepare wine downloader @@ -262,7 +261,7 @@ impl App { match Installer::new(&wine_version_copy.uri) { Ok(mut installer) => { if let Some(temp_folder) = config.launcher.temp { - installer.temp_folder = PathBuf::from(temp_folder); + installer.temp_folder = temp_folder; } installer.downloader @@ -333,7 +332,7 @@ impl App { match Installer::new(&dxvk_version.uri) { Ok(mut installer) => { if let Some(temp_folder) = config.launcher.temp { - installer.temp_folder = PathBuf::from(temp_folder); + installer.temp_folder = temp_folder; } installer.downloader @@ -393,9 +392,9 @@ impl App { // Remove .first-run file let launcher_dir = crate::lib::consts::launcher_dir().unwrap(); - - std::fs::remove_file(format!("{}/.first-run", launcher_dir)).unwrap(); - + + std::fs::remove_file(launcher_dir.join(".first-run")).unwrap(); + // Show next page this.update(Actions::DownloadComponentsContinue).unwrap(); }, diff --git a/src/ui/main.rs b/src/ui/main.rs index 5a71978..b3d1939 100644 --- a/src/ui/main.rs +++ b/src/ui/main.rs @@ -7,7 +7,7 @@ use std::rc::Rc; use std::cell::Cell; use std::io::Error; use std::process::{Command, Stdio}; -use std::path::PathBuf; +use std::path::Path; use wait_not_await::Await; @@ -68,7 +68,7 @@ impl AppWidgets { let result = Self { window: window.clone(), - toast_overlay: toast_overlay.clone(), + toast_overlay, menu: get_object(&builder, "menu")?, about: get_object(&builder, "about")?, @@ -127,6 +127,7 @@ impl AppWidgets { let curl_info = anime_game_core::curl_sys::Version::get(); + #[allow(clippy::or_fun_call)] result.about.set_debug_info(&[ format!("Anime Game core library version: {}", anime_game_core::VERSION), format!("Curl version: {}", curl_info.version()), @@ -162,6 +163,7 @@ pub enum Actions { } impl Actions { + #[allow(clippy::expect_fun_call, clippy::wrong_self_convention)] pub fn into_fn>(&self, app: &App) -> Box { Box::new(clone!(@strong self as action, @weak app => move |_| { app.update(action.clone()).expect(&format!("Failed to execute action {:?}", &action)); @@ -443,7 +445,7 @@ impl App { match Installer::new(wine.uri) { Ok(mut installer) => { if let Some(temp_folder) = config.launcher.temp { - installer.temp_folder = PathBuf::from(temp_folder); + installer.temp_folder = temp_folder; } installer.downloader @@ -750,7 +752,7 @@ impl App { }).unwrap(); } - if broken.len() > 0 { + if !broken.is_empty() { this.update(Actions::UpdateProgress { fraction: Rc::new(0.0), title: Rc::new(String::from("Repairing files: 0%")) @@ -771,7 +773,7 @@ impl App { println!("Patch status: {}", is_patch_applied); - fn should_ignore(path: &PathBuf) -> bool { + fn should_ignore(path: &Path) -> bool { for part in ["UnityPlayer.dll", "xlua.dll", "crashreport.exe", "upload_crash.exe", "vulkan-1.dll"] { if path.ends_with(part) { return true; @@ -890,7 +892,7 @@ impl App { // Calculate size of the update let size = game.size().unwrap_or((0, 0)).0 + - voices.into_iter().fold(0, |acc, voice| acc + voice.size().unwrap_or((0, 0)).0); + voices.iter().fold(0, |acc, voice| acc + voice.size().unwrap_or((0, 0)).0); // Update tooltip self.widgets.predownload_game.set_tooltip_text(Some(&format!("Pre-download {} update ({})", game.latest(), prettify_bytes(size)))); @@ -902,12 +904,10 @@ impl App { if let Ok(config) = config::get() { if let Some(temp) = config.launcher.temp { - let tmp = PathBuf::from(temp); - // If all the files were downloaded let downloaded = - tmp.join(game.file_name().unwrap()).exists() && - voices.into_iter().fold(true, move |acc, voice| acc && tmp.join(voice.file_name().unwrap()).exists()); + temp.join(game.file_name().unwrap()).exists() && + voices.iter().all(|voice| temp.join(voice.file_name().unwrap()).exists()); if downloaded { self.widgets.predownload_game.remove_css_class("warning"); diff --git a/src/ui/preferences/environment.rs b/src/ui/preferences/environment.rs index edd9a43..8bf42a7 100644 --- a/src/ui/preferences/environment.rs +++ b/src/ui/preferences/environment.rs @@ -146,34 +146,32 @@ impl App { Actions::Add(strs) => { let (name, value) = &*strs; - if !name.is_empty() && !value.is_empty() { - if !values.rows.contains_key(name) { - config.game.environment.insert(name.clone(), value.clone()); + if !name.is_empty() && !value.is_empty() && !values.rows.contains_key(name) { + config.game.environment.insert(name.clone(), value.clone()); - let row = adw::ActionRow::new(); + let row = adw::ActionRow::new(); - row.set_title(name); - row.set_subtitle(value); + row.set_title(name); + row.set_subtitle(value); - let button = gtk::Button::new(); + let button = gtk::Button::new(); - button.set_icon_name("user-trash-symbolic"); - button.set_valign(gtk::Align::Center); - button.add_css_class("flat"); + button.set_icon_name("user-trash-symbolic"); + button.set_valign(gtk::Align::Center); + button.add_css_class("flat"); - button.connect_clicked(clone!(@weak this, @strong name => move |_| { - this.update(Actions::Delete(Rc::new(name.clone()))).unwrap(); - })); + button.connect_clicked(clone!(@weak this, @strong name => move |_| { + this.update(Actions::Delete(Rc::new(name.clone()))).unwrap(); + })); - row.add_suffix(&button); + row.add_suffix(&button); - this.widgets.variables.add(&row); + this.widgets.variables.add(&row); - values.rows.insert(name.clone(), row); + values.rows.insert(name.clone(), row); - this.widgets.name.set_text(""); - this.widgets.value.set_text(""); - } + this.widgets.name.set_text(""); + this.widgets.value.set_text(""); } } @@ -230,7 +228,7 @@ impl App { status_page.set_description(Some("Loading environment...")); // Set game command - self.widgets.command.set_text(&config.game.command.unwrap_or(String::new())); + self.widgets.command.set_text(&config.game.command.unwrap_or_default()); // Add environment variables for (name, value) in config.game.environment { diff --git a/src/ui/preferences/general.rs b/src/ui/preferences/general.rs index 7f4aa40..1157d1a 100644 --- a/src/ui/preferences/general.rs +++ b/src/ui/preferences/general.rs @@ -152,6 +152,7 @@ pub enum Actions { } impl Actions { + #[allow(clippy::expect_fun_call, clippy::wrong_self_convention)] pub fn into_fn>(&self, app: &App) -> Box { Box::new(clone!(@strong self as action, @weak app => move |_| { app.update(action.clone()).expect(&format!("Failed to execute action {:?}", &action)); @@ -211,7 +212,7 @@ impl App { self.widgets.repair_game.connect_clicked(Actions::RepairGame.into_fn(&self)); // Voiceover download/delete button event - for (i, row) in (&*self.widgets.voieover_components).into_iter().enumerate() { + for (i, row) in (*self.widgets.voieover_components).iter().enumerate() { row.button.connect_clicked(clone!(@weak self as this => move |_| { this.update(Actions::VoiceoverPerformAction(Rc::new(i))).unwrap(); })); @@ -251,8 +252,8 @@ impl App { // Wine install/remove buttons let components = &*self.widgets.wine_components; - for (i, group) in components.into_iter().enumerate() { - for (j, component) in (&group.version_components).into_iter().enumerate() { + for (i, group) in components.iter().enumerate() { + for (j, component) in group.version_components.iter().enumerate() { component.button.connect_clicked(Actions::WinePerformAction(Rc::new((i, j))).into_fn(&self)); } } @@ -273,8 +274,8 @@ impl App { // DXVK install/remove/apply buttons let components = &*self.widgets.dxvk_components; - for (i, group) in components.into_iter().enumerate() { - for (j, component) in (&group.version_components).into_iter().enumerate() { + for (i, group) in components.iter().enumerate() { + for (j, component) in group.version_components.iter().enumerate() { component.button.connect_clicked(Actions::DxvkPerformAction(Rc::new((i, j))).into_fn(&self)); component.apply_button.connect_clicked(clone!(@strong component, @weak self as this => move |_| { @@ -314,7 +315,7 @@ impl App { match action { Actions::RepairGame => { - let option = (&*this.app).take(); + let option = (*this.app).take(); this.app.set(option.clone()); let app = option.unwrap(); @@ -345,7 +346,7 @@ impl App { } else { - let option = (&*this.app).take(); + let option = (*this.app).take(); this.app.set(option.clone()); let app = option.unwrap(); @@ -382,23 +383,21 @@ impl App { this.update(Actions::UpdateDxvkComboRow).unwrap(); } - else { - if let Ok(awaiter) = component.download(&config.game.dxvk.builds) { - awaiter.then(clone!(@strong this => move |_| { - match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) { - Ok(output) => println!("{}", String::from_utf8_lossy(&output.stdout)), - Err(err) => { - this.update(Actions::Toast(Rc::new(( - String::from("Failed to apply DXVK"), err.to_string() - )))).unwrap(); - } + else if let Ok(awaiter) = component.download(&config.game.dxvk.builds) { + awaiter.then(clone!(@strong this => move |_| { + match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) { + Ok(output) => println!("{}", String::from_utf8_lossy(&output.stdout)), + Err(err) => { + this.update(Actions::Toast(Rc::new(( + String::from("Failed to apply DXVK"), err.to_string() + )))).unwrap(); } + } - component.update_state(&config.game.dxvk.builds); + component.update_state(&config.game.dxvk.builds); - this.update(Actions::UpdateDxvkComboRow).unwrap(); - })); - } + this.update(Actions::UpdateDxvkComboRow).unwrap(); + })); } } @@ -419,14 +418,12 @@ impl App { this.update(Actions::UpdateWineComboRow).unwrap(); } - else { - if let Ok(awaiter) = component.download(&config.game.wine.builds) { - awaiter.then(clone!(@strong this => move |_| { - component.update_state(&config.game.wine.builds); + else if let Ok(awaiter) = component.download(&config.game.wine.builds) { + awaiter.then(clone!(@strong this => move |_| { + component.update_state(&config.game.wine.builds); - this.update(Actions::UpdateWineComboRow).unwrap(); - })); - } + this.update(Actions::UpdateWineComboRow).unwrap(); + })); } } @@ -518,7 +515,7 @@ impl App { let mut selected = 0; - for (i, version) in (&list).into_iter().enumerate() { + for (i, version) in list.iter().enumerate() { model.append(version.title.as_str()); if let Some(curr) = &config.game.wine.selected { @@ -708,7 +705,7 @@ impl App { impl Toast for App { fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) { - let app = (&*self.app).take(); + let app = (*self.app).take(); self.app.set(app.clone()); app.unwrap().get_toast_widgets() diff --git a/src/ui/preferences/mod.rs b/src/ui/preferences/mod.rs index 76a080d..51b2481 100644 --- a/src/ui/preferences/mod.rs +++ b/src/ui/preferences/mod.rs @@ -91,7 +91,7 @@ impl PreferencesStack { impl Toast for PreferencesStack { fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) { - let app = (&*self.app).take(); + let app = (*self.app).take(); self.app.set(app.clone()); app.unwrap().get_toast_widgets() diff --git a/src/ui/traits/download_component.rs b/src/ui/traits/download_component.rs index b0375fc..92fd557 100644 --- a/src/ui/traits/download_component.rs +++ b/src/ui/traits/download_component.rs @@ -17,15 +17,15 @@ pub enum DownloadingResult { } pub trait DownloadComponent { - fn get_component_path(&self, installation_path: T) -> String; + fn get_component_path>(&self, installation_path: T) -> PathBuf; fn get_downloading_widgets(&self) -> (gtk::ProgressBar, gtk::Button); fn get_download_uri(&self) -> String; - fn is_downloaded(&self, installation_path: T) -> bool { + fn is_downloaded>(&self, installation_path: T) -> bool { Path::new(&self.get_component_path(installation_path)).exists() } - fn download(&self, installation_path: T) -> anyhow::Result> { + fn download>(&self, installation_path: T) -> anyhow::Result> { let (sender, receiver) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); let (progress_bar, button) = self.get_downloading_widgets(); @@ -66,11 +66,11 @@ pub trait DownloadComponent { } InstallerUpdate::DownloadingError(err) => { - downl_send.send(DownloadingResult::DownloadingError(err.into())).unwrap(); + downl_send.send(DownloadingResult::DownloadingError(err)).unwrap(); } InstallerUpdate::UnpackingError(err) => { - downl_send.send(DownloadingResult::UnpackingError(err.to_string())).unwrap(); + downl_send.send(DownloadingResult::UnpackingError(err)).unwrap(); } } @@ -83,17 +83,17 @@ pub trait DownloadComponent { let mut installer = Installer::new(self.get_download_uri())?; if let Some(temp_folder) = config.launcher.temp { - installer.temp_folder = PathBuf::from(temp_folder); + installer.temp_folder = temp_folder; } installer.downloader .set_downloading_speed(config.launcher.speed_limit) .expect("Failed to set downloading speed limit"); - let installation_path = installation_path.to_string(); - send.send(installer).unwrap(); + let installation_path = installation_path.into(); + std::thread::spawn(move || { let mut installer = recv.recv().unwrap(); @@ -107,7 +107,7 @@ pub trait DownloadComponent { })) } - fn delete(&self, installation_path: T) -> std::io::Result<()> { + fn delete>(&self, installation_path: T) -> std::io::Result<()> { std::fs::remove_dir_all(self.get_component_path(installation_path)) } } diff --git a/src/ui/traits/toast.rs b/src/ui/traits/toast.rs index 787bc8b..a1aaebc 100644 --- a/src/ui/traits/toast.rs +++ b/src/ui/traits/toast.rs @@ -16,7 +16,7 @@ pub trait Toast { let message = format!("{}", message); - if message.len() > 0 { + if !message.is_empty() { toast.set_button_label(Some("See message")); toast.set_action_name(Some("see-message.see-message"));