diff --git a/Cargo.lock b/Cargo.lock index db62b10..1e8e89b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,8 +40,7 @@ dependencies = [ [[package]] name = "anime-game-core" -version = "1.7.2" -source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.7.2#b367ea1303c9687217024902e37dbb4e24b05f37" +version = "1.7.4" dependencies = [ "anyhow", "bzip2", @@ -65,8 +64,7 @@ dependencies = [ [[package]] name = "anime-launcher-sdk" -version = "1.0.10" -source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.0.10#204369158e57056dfc64fbff62fbe6a571034913" +version = "1.0.12" dependencies = [ "anime-game-core", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 91ef4f8..ecc56df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,11 @@ opt-level = "s" glib-build-tools = "0.17" [dependencies.anime-launcher-sdk] -git = "https://github.com/an-anime-team/anime-launcher-sdk" -tag = "1.0.10" -features = ["all", "genshin"] +# git = "https://github.com/an-anime-team/anime-launcher-sdk" +# tag = "1.0.10" +features = ["all", "star-rail"] -# path = "../anime-launcher-sdk" # ! for dev purposes only +path = "../anime-launcher-sdk" # ! for dev purposes only [dependencies] relm4 = { version = "0.6.0-alpha.2", features = ["macros", "libadwaita"] } diff --git a/src/main.rs b/src/main.rs index b12dbcf..99c9cf4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,13 @@ use relm4::prelude::*; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::{Config, Schema}; +use anime_launcher_sdk::star_rail::config::{Config, Schema}; -use anime_launcher_sdk::genshin::states::LauncherState; -use anime_launcher_sdk::genshin::consts::launcher_dir; +use anime_launcher_sdk::star_rail::states::LauncherState; +use anime_launcher_sdk::star_rail::consts::launcher_dir; use anime_launcher_sdk::anime_game_core::prelude::*; -use anime_launcher_sdk::anime_game_core::genshin::prelude::*; +use anime_launcher_sdk::anime_game_core::star_rail::prelude::*; use tracing_subscriber::prelude::*; use tracing_subscriber::filter::*; @@ -22,7 +22,7 @@ pub mod ui; use ui::main::*; use ui::first_run::main::*; -pub const APP_ID: &str = "moe.launcher.an-anime-game-launcher"; +pub const APP_ID: &str = "moe.launcher.the-honkers-railway-launcher"; pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const APP_DEBUG: bool = cfg!(debug_assertions); @@ -40,7 +40,7 @@ lazy_static::lazy_static! { /// This one is used to prepare some launcher UI components on start pub static ref CONFIG: Schema = Config::get().expect("Failed to load config"); - pub static ref GAME: Game = Game::new(CONFIG.game.path.for_edition(CONFIG.launcher.edition)); + pub static ref GAME: Game = Game::new(&CONFIG.game.path); /// Path to launcher folder. Standard is `$HOME/.local/share/anime-game-launcher` pub static ref LAUNCHER_FOLDER: PathBuf = launcher_dir().expect("Failed to get launcher folder"); @@ -162,9 +162,6 @@ fn main() { }} ", BACKGROUND_FILE.to_string_lossy())); - // Set game edition - CONFIG.launcher.edition.select(); - // Set UI language let lang = CONFIG.launcher.language.parse().expect("Wrong language format used in config"); @@ -189,16 +186,15 @@ fn main() { match state { LauncherState::Launch => { - anime_launcher_sdk::genshin::game::run().expect("Failed to run the game"); + anime_launcher_sdk::star_rail::game::run().expect("Failed to run the game"); return; } LauncherState::PredownloadAvailable { .. } | - LauncherState::UnityPlayerPatchAvailable(UnityPlayerPatch { status: PatchStatus::NotAvailable, .. }) | - LauncherState::XluaPatchAvailable(XluaPatch { status: PatchStatus::NotAvailable, .. }) => { + LauncherState::MainPatchAvailable(MainPatch { status: PatchStatus::NotAvailable, .. }) => { if just_run_game { - anime_launcher_sdk::genshin::game::run().expect("Failed to run the game"); + anime_launcher_sdk::star_rail::game::run().expect("Failed to run the game"); return; } diff --git a/src/ui/components/version.rs b/src/ui/components/version.rs index 9870ae9..cf53929 100644 --- a/src/ui/components/version.rs +++ b/src/ui/components/version.rs @@ -9,7 +9,7 @@ use gtk::glib::clone; use anime_launcher_sdk::anime_game_core::prelude::*; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; +use anime_launcher_sdk::star_rail::config::Config; use std::path::PathBuf; diff --git a/src/ui/first_run/default_paths.rs b/src/ui/first_run/default_paths.rs index dc5731f..763d5e2 100644 --- a/src/ui/first_run/default_paths.rs +++ b/src/ui/first_run/default_paths.rs @@ -21,9 +21,7 @@ pub struct DefaultPathsApp { runners: PathBuf, dxvks: PathBuf, prefix: PathBuf, - game_global: PathBuf, - game_china: PathBuf, - fps_unlocker: PathBuf, + game: PathBuf, components: PathBuf, patch: PathBuf, temp: PathBuf @@ -35,9 +33,7 @@ pub enum Folders { Runners, DXVK, Prefix, - GameGlobal, - GameChina, - FpsUnlocker, + Game, Components, Patch, Temp @@ -151,36 +147,14 @@ impl SimpleAsyncComponent for DefaultPathsApp { }, adw::ActionRow { - set_title: &tr("global-game-installation-folder"), + set_title: &tr("global-game-installation-folder"), // FIXME: locale set_icon_name: Some("folder-symbolic"), set_activatable: true, #[watch] - set_subtitle: model.game_global.to_str().unwrap(), + set_subtitle: model.game.to_str().unwrap(), - connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::GameGlobal) - }, - - adw::ActionRow { - set_title: &tr("chinese-game-installation-folder"), - set_icon_name: Some("folder-symbolic"), - set_activatable: true, - - #[watch] - set_subtitle: model.game_china.to_str().unwrap(), - - connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::GameChina) - }, - - adw::ActionRow { - set_title: &tr("fps-unlocker-folder"), - set_icon_name: Some("folder-symbolic"), - set_activatable: true, - - #[watch] - set_subtitle: model.fps_unlocker.to_str().unwrap(), - - connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::FpsUnlocker) + connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::Game) }, adw::ActionRow { @@ -298,9 +272,7 @@ impl SimpleAsyncComponent for DefaultPathsApp { runners: CONFIG.game.wine.builds.clone(), dxvks: CONFIG.game.dxvk.builds.clone(), prefix: CONFIG.game.wine.prefix.clone(), - game_global: CONFIG.game.path.global.clone(), - game_china: CONFIG.game.path.china.clone(), - fps_unlocker: CONFIG.game.enhancements.fps_unlocker.path.clone(), + game: CONFIG.game.path.clone(), components: CONFIG.components.path.clone(), patch: CONFIG.patch.path.clone(), @@ -330,28 +302,24 @@ impl SimpleAsyncComponent for DefaultPathsApp { match folder { Folders::Launcher => { - self.runners = result.join("runners"); - self.dxvks = result.join("dxvks"); - self.prefix = result.join("prefix"); - self.game_global = result.join(concat!("Ge", "nshi", "n Imp", "act")); - self.game_china = result.join(concat!("Yu", "anS", "hen")); - self.fps_unlocker = result.join("fps-unlocker"); - self.components = result.join("components"); - self.patch = result.join("patch"); - self.temp = result.clone(); + self.runners = result.join("runners"); + self.dxvks = result.join("dxvks"); + self.prefix = result.join("prefix"); + self.game = result.join(concat!("Hon", "kai Sta", "r Rail")); + self.components = result.join("components"); + self.patch = result.join("patch"); + self.temp = result.clone(); self.launcher = result; } - Folders::Runners => self.runners = result, - Folders::DXVK => self.dxvks = result, - Folders::Prefix => self.prefix = result, - Folders::GameGlobal => self.game_global = result, - Folders::GameChina => self.game_china = result, - Folders::FpsUnlocker => self.fps_unlocker = result, - Folders::Components => self.components = result, - Folders::Patch => self.patch = result, - Folders::Temp => self.temp = result + Folders::Runners => self.runners = result, + Folders::DXVK => self.dxvks = result, + Folders::Prefix => self.prefix = result, + Folders::Game => self.game = result, + Folders::Components => self.components = result, + Folders::Patch => self.patch = result, + Folders::Temp => self.temp = result } } } @@ -371,12 +339,9 @@ impl SimpleAsyncComponent for DefaultPathsApp { (old_config.game.wine.builds, &self.runners), (old_config.game.dxvk.builds, &self.dxvks), (old_config.game.wine.prefix, &self.prefix), - (old_config.game.path.global, &self.game_global), - (old_config.game.path.china, &self.game_china), + (old_config.game.path, &self.game), (old_config.components.path, &self.components), - (old_config.patch.path, &self.patch), - - (old_config.game.enhancements.fps_unlocker.path, &self.fps_unlocker) + (old_config.patch.path, &self.patch) ]; #[allow(clippy::expect_fun_call)] @@ -400,7 +365,7 @@ impl SimpleAsyncComponent for DefaultPathsApp { } else { - sender.output(Self::Output::ScrollToSelectVoiceovers); + sender.output(Self::Output::ScrollToDownloadComponents); } } @@ -434,14 +399,11 @@ impl DefaultPathsApp { config.game.wine.builds = self.runners.clone(); config.game.dxvk.builds = self.dxvks.clone(); config.game.wine.prefix = self.prefix.clone(); - config.game.path.global = self.game_global.clone(); - config.game.path.china = self.game_china.clone(); + config.game.path = self.game.clone(); config.components.path = self.components.clone(); config.patch.path = self.patch.clone(); config.launcher.temp = Some(self.temp.clone()); - config.game.enhancements.fps_unlocker.path = self.fps_unlocker.clone(); - Config::update_raw(config) } } diff --git a/src/ui/first_run/download_components.rs b/src/ui/first_run/download_components.rs index 7db9a1a..29d1618 100644 --- a/src/ui/first_run/download_components.rs +++ b/src/ui/first_run/download_components.rs @@ -10,7 +10,7 @@ use anime_launcher_sdk::components::*; use anime_launcher_sdk::components::wine::WincompatlibWine; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; +use anime_launcher_sdk::star_rail::config::Config; use std::path::PathBuf; diff --git a/src/ui/first_run/main.rs b/src/ui/first_run/main.rs index 2e8abec..f023018 100644 --- a/src/ui/first_run/main.rs +++ b/src/ui/first_run/main.rs @@ -13,7 +13,6 @@ use super::welcome::*; use super::tos_warning::*; use super::dependencies::*; use super::default_paths::*; -use super::select_voiceovers::*; use super::download_components::*; use super::finish::*; @@ -26,7 +25,6 @@ pub struct FirstRunApp { tos_warning: AsyncController, dependencies: AsyncController, default_paths: AsyncController, - select_voiceovers: AsyncController, download_components: AsyncController, finish: AsyncController, @@ -44,7 +42,6 @@ pub enum FirstRunAppMsg { ScrollToTosWarning, ScrollToDependencies, ScrollToDefaultPaths, - ScrollToSelectVoiceovers, ScrollToDownloadComponents, ScrollToFinish, @@ -104,7 +101,6 @@ impl SimpleComponent for FirstRunApp { append = model.tos_warning.widget(), append = model.dependencies.widget(), append = model.default_paths.widget(), - append = model.select_voiceovers.widget(), append = model.download_components.widget(), append = model.finish.widget(), }, @@ -148,10 +144,6 @@ impl SimpleComponent for FirstRunApp { .launch(false) .forward(sender.input_sender(), std::convert::identity), - select_voiceovers: SelectVoiceoversApp::builder() - .launch(()) - .forward(sender.input_sender(), std::convert::identity), - download_components: DownloadComponentsApp::builder() .launch(()) .forward(sender.input_sender(), std::convert::identity), @@ -209,12 +201,6 @@ impl SimpleComponent for FirstRunApp { self.carousel.scroll_to(self.default_paths.widget(), true); } - FirstRunAppMsg::ScrollToSelectVoiceovers => { - self.title = tr("select-voice-packages"); - - self.carousel.scroll_to(self.select_voiceovers.widget(), true); - } - FirstRunAppMsg::ScrollToDownloadComponents => { // Update components index sender.input(FirstRunAppMsg::SetLoadingStatus(Some(Some(tr("updating-components-index"))))); diff --git a/src/ui/first_run/mod.rs b/src/ui/first_run/mod.rs index 37e26e1..b917b5d 100644 --- a/src/ui/first_run/mod.rs +++ b/src/ui/first_run/mod.rs @@ -3,6 +3,5 @@ pub mod welcome; pub mod tos_warning; pub mod dependencies; pub mod default_paths; -pub mod select_voiceovers; pub mod download_components; pub mod finish; diff --git a/src/ui/first_run/select_voiceovers.rs b/src/ui/first_run/select_voiceovers.rs deleted file mode 100644 index 397e90a..0000000 --- a/src/ui/first_run/select_voiceovers.rs +++ /dev/null @@ -1,179 +0,0 @@ -use relm4::prelude::*; -use relm4::component::*; - -use adw::prelude::*; - -use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; - -use crate::i18n::*; -use super::main::*; - -pub struct SelectVoiceoversApp { - english: gtk::Switch, - japanese: gtk::Switch, - korean: gtk::Switch, - chinese: gtk::Switch -} - -#[derive(Debug, Clone)] -pub enum SelectVoiceoversAppMsg { - Continue, - Exit -} - -#[relm4::component(async, pub)] -impl SimpleAsyncComponent for SelectVoiceoversApp { - type Init = (); - type Input = SelectVoiceoversAppMsg; - type Output = FirstRunAppMsg; - - view! { - adw::PreferencesPage { - set_hexpand: true, - - add = &adw::PreferencesGroup { - set_valign: gtk::Align::Center, - set_vexpand: true, - - gtk::Label { - set_label: &tr("select-voice-packages"), - add_css_class: "title-1" - } - }, - - add = &adw::PreferencesGroup { - set_valign: gtk::Align::Center, - set_vexpand: true, - - adw::ActionRow { - set_title: &tr("english"), - - #[local_ref] - add_suffix = english -> gtk::Switch { - set_valign: gtk::Align::Center, - set_state: true - } - }, - - adw::ActionRow { - set_title: &tr("japanese"), - - #[local_ref] - add_suffix = japanese -> gtk::Switch { - set_valign: gtk::Align::Center - } - }, - - adw::ActionRow { - set_title: &tr("korean"), - - #[local_ref] - add_suffix = korean -> gtk::Switch { - set_valign: gtk::Align::Center - } - }, - - adw::ActionRow { - set_title: &tr("chinese"), - - #[local_ref] - add_suffix = chinese -> gtk::Switch { - set_valign: gtk::Align::Center - } - } - }, - - add = &adw::PreferencesGroup { - set_valign: gtk::Align::Center, - set_vexpand: true, - - gtk::Box { - set_orientation: gtk::Orientation::Horizontal, - set_halign: gtk::Align::Center, - set_spacing: 8, - - gtk::Button { - set_label: &tr("continue"), - set_css_classes: &["suggested-action", "pill"], - - connect_clicked => SelectVoiceoversAppMsg::Continue - }, - - gtk::Button { - set_label: &tr("exit"), - add_css_class: "pill", - - connect_clicked => SelectVoiceoversAppMsg::Exit - } - } - } - } - } - - async fn init( - _init: Self::Init, - root: Self::Root, - _sender: AsyncComponentSender, - ) -> AsyncComponentParts { - let model = Self { - english: gtk::Switch::new(), - japanese: gtk::Switch::new(), - korean: gtk::Switch::new(), - chinese: gtk::Switch::new() - }; - - let english = &model.english; - let japanese = &model.japanese; - let korean = &model.korean; - let chinese = &model.chinese; - - let widgets = view_output!(); - - AsyncComponentParts { model, widgets } - } - - async fn update(&mut self, msg: Self::Input, sender: AsyncComponentSender) { - match msg { - #[allow(unused_must_use)] - SelectVoiceoversAppMsg::Continue => { - match self.update_config() { - Ok(_) => sender.output(Self::Output::ScrollToDownloadComponents), - - Err(err) => sender.output(Self::Output::Toast { - title: tr("config-update-error"), - description: Some(err.to_string()) - }) - }; - } - - SelectVoiceoversAppMsg::Exit => relm4::main_application().quit() - } - } -} - -impl SelectVoiceoversApp { - pub fn update_config(&self) -> anyhow::Result<()> { - let mut config = Config::get()?; - - config.game.voices = Vec::new(); - - if self.english.state() { - config.game.voices.push(String::from("en-us")); - } - - if self.japanese.state() { - config.game.voices.push(String::from("ja-jp")); - } - - if self.korean.state() { - config.game.voices.push(String::from("ko-kr")); - } - - if self.chinese.state() { - config.game.voices.push(String::from("zh-cn")); - } - - Config::update_raw(config) - } -} diff --git a/src/ui/main/apply_patch.rs b/src/ui/main/apply_patch.rs index 0a5a9da..5d1589d 100644 --- a/src/ui/main/apply_patch.rs +++ b/src/ui/main/apply_patch.rs @@ -4,11 +4,10 @@ use crate::*; use crate::i18n::*; use super::{App, AppMsg}; -pub fn apply_patch(sender: ComponentSender, patch: T) { +pub fn apply_patch(sender: ComponentSender, patch: MainPatch) { match patch.status() { PatchStatus::NotAvailable | - PatchStatus::Outdated { .. } | - PatchStatus::Preparation { .. } => unreachable!(), + PatchStatus::Outdated { .. } => unreachable!(), PatchStatus::Testing { .. } | PatchStatus::Available { .. } => { @@ -19,7 +18,7 @@ pub fn apply_patch(sender: ComponentSender< std::thread::spawn(move || { let mut apply_patch_if_needed = true; - if let Err(err) = patch.apply(config.game.path.for_edition(config.launcher.edition), config.patch.root) { + if let Err(err) = patch.apply(config.game.path, config.patch.root) { tracing::error!("Failed to patch the game"); sender.input(AppMsg::Toast { diff --git a/src/ui/main/create_prefix.rs b/src/ui/main/create_prefix.rs index 62d6cb1..8a6fcd1 100644 --- a/src/ui/main/create_prefix.rs +++ b/src/ui/main/create_prefix.rs @@ -3,7 +3,7 @@ use relm4::prelude::*; use anime_launcher_sdk::wincompatlib::prelude::*; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; +use anime_launcher_sdk::star_rail::config::Config; use crate::i18n::*; use super::{App, AppMsg}; diff --git a/src/ui/main/download_diff.rs b/src/ui/main/download_diff.rs index 60c0147..6a29428 100644 --- a/src/ui/main/download_diff.rs +++ b/src/ui/main/download_diff.rs @@ -17,9 +17,8 @@ pub fn download_diff(sender: ComponentSender, progress_bar_input: Sender move |state| { + let result = diff.install_to_by(config.game.path, config.launcher.temp, clone!(@strong sender => move |state| { match &state { DiffUpdate::InstallerUpdate(InstallerUpdate::DownloadingError(err)) => { tracing::error!("Downloading failed: {err}"); diff --git a/src/ui/main/launch.rs b/src/ui/main/launch.rs index 481bead..dff800c 100644 --- a/src/ui/main/launch.rs +++ b/src/ui/main/launch.rs @@ -7,7 +7,7 @@ pub fn launch(sender: ComponentSender) { sender.input(AppMsg::HideWindow); std::thread::spawn(move || { - if let Err(err) = anime_launcher_sdk::genshin::game::run() { + if let Err(err) = anime_launcher_sdk::star_rail::game::run() { tracing::error!("Failed to launch game: {err}"); sender.input(AppMsg::Toast { diff --git a/src/ui/main/migrate_folder.rs b/src/ui/main/migrate_folder.rs deleted file mode 100644 index 74d6b61..0000000 --- a/src/ui/main/migrate_folder.rs +++ /dev/null @@ -1,25 +0,0 @@ -use relm4::prelude::*; - -use std::path::PathBuf; - -use crate::*; -use super::{App, AppMsg}; - -pub fn migrate_folder(sender: ComponentSender, from: PathBuf, to: PathBuf, cleanup_folder: Option) { - sender.input(AppMsg::DisableButtons(true)); - - std::thread::spawn(move || { - move_folder::move_folder(&from, &to).expect("Failed to perform migration"); - - if let Some(cleanup_folder) = cleanup_folder { - std::fs::remove_dir_all(cleanup_folder).expect("Failed to remove cleanup folder"); - } - - sender.input(AppMsg::DisableButtons(false)); - sender.input(AppMsg::UpdateLauncherState { - perform_on_download_needed: false, - apply_patch_if_needed: false, - show_status_page: true - }); - }); -} diff --git a/src/ui/main/mod.rs b/src/ui/main/mod.rs index d780ce1..ce1b29e 100644 --- a/src/ui/main/mod.rs +++ b/src/ui/main/mod.rs @@ -15,18 +15,17 @@ mod apply_patch; mod download_wine; mod create_prefix; mod download_diff; -mod migrate_folder; mod launch; use anime_launcher_sdk::components::loader::ComponentsLoader; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; +use anime_launcher_sdk::star_rail::config::Config; -use anime_launcher_sdk::genshin::config::schema::launcher::LauncherStyle; +use anime_launcher_sdk::star_rail::config::schema::launcher::LauncherStyle; -use anime_launcher_sdk::genshin::states::*; -use anime_launcher_sdk::genshin::consts::*; +use anime_launcher_sdk::star_rail::states::*; +use anime_launcher_sdk::star_rail::consts::*; use crate::*; use crate::i18n::*; @@ -41,7 +40,6 @@ relm4::new_stateless_action!(LauncherFolder, WindowActionGroup, "launcher_folder relm4::new_stateless_action!(GameFolder, WindowActionGroup, "game_folder"); relm4::new_stateless_action!(ConfigFile, WindowActionGroup, "config_file"); relm4::new_stateless_action!(DebugFile, WindowActionGroup, "debug_file"); -relm4::new_stateless_action!(WishUrl, WindowActionGroup, "wish_url"); relm4::new_stateless_action!(About, WindowActionGroup, "about"); @@ -80,13 +78,9 @@ pub enum AppMsg { /// was retrieved from the API SetGameDiff(Option), - /// Supposed to be called automatically on app's run when the latest UnityPlayer patch version + /// Supposed to be called automatically on app's run when the latest main patch version /// was retrieved from remote repos - SetUnityPlayerPatch(Option), - - /// Supposed to be called automatically on app's run when the latest xlua patch version - /// was retrieved from remote repos - SetXluaPatch(Option), + SetMainPatch(Option), /// Supposed to be called automatically on app's run when the launcher state was chosen SetLauncherState(Option), @@ -127,10 +121,6 @@ impl SimpleComponent for App { &tr("debug-file") => DebugFile, }, - section! { - &tr("wish-url") => WishUrl - }, - section! { &tr("about") => About } @@ -311,17 +301,13 @@ impl SimpleComponent for App { #[watch] set_tooltip_text: Some(&tr_args("predownload-update", [ ("version", match model.state.as_ref() { - Some(LauncherState::PredownloadAvailable { game, .. }) => game.latest().to_string(), + Some(LauncherState::PredownloadAvailable(game)) => game.latest().to_string(), _ => String::from("?") }.into()), ("size", match model.state.as_ref() { - Some(LauncherState::PredownloadAvailable { game, voices }) => { - let mut size = game.size().unwrap_or((0, 0)).0; - - for voice in voices { - size += voice.size().unwrap_or((0, 0)).0; - } + Some(LauncherState::PredownloadAvailable(game)) => { + let size = game.size().unwrap_or((0, 0)).0; prettify_bytes(size) } @@ -335,14 +321,11 @@ impl SimpleComponent for App { #[watch] set_sensitive: match model.state.as_ref() { - Some(LauncherState::PredownloadAvailable { game, voices }) => { + Some(LauncherState::PredownloadAvailable(game)) => { let config = Config::get().unwrap(); let temp = config.launcher.temp.unwrap_or_else(std::env::temp_dir); - let downloaded = temp.join(game.file_name().unwrap()).exists() && - voices.iter().all(|voice| temp.join(voice.file_name().unwrap()).exists()); - - !downloaded + !temp.join(game.file_name().unwrap()).exists() } _ => false @@ -350,14 +333,11 @@ impl SimpleComponent for App { #[watch] set_css_classes: match model.state.as_ref() { - Some(LauncherState::PredownloadAvailable { game, voices }) => { + Some(LauncherState::PredownloadAvailable(game)) => { let config = Config::get().unwrap(); let temp = config.launcher.temp.unwrap_or_else(std::env::temp_dir); - let downloaded = temp.join(game.file_name().unwrap()).exists() && - voices.iter().all(|voice| temp.join(voice.file_name().unwrap()).exists()); - - if downloaded { + if temp.join(game.file_name().unwrap()).exists() { &["success"] } else { &["warning"] @@ -380,33 +360,25 @@ impl SimpleComponent for App { gtk::Button { #[watch] set_label: &match model.state { - Some(LauncherState::Launch) => tr("launch"), - Some(LauncherState::PredownloadAvailable { .. }) => tr("launch"), - Some(LauncherState::FolderMigrationRequired { .. }) => tr("migrate-folders"), - Some(LauncherState::UnityPlayerPatchAvailable(_)) => tr("apply-patch"), - Some(LauncherState::XluaPatchAvailable(_)) => tr("apply-patch"), - Some(LauncherState::WineNotInstalled) => tr("download-wine"), - Some(LauncherState::PrefixNotExists) => tr("create-prefix"), - Some(LauncherState::VoiceUpdateAvailable(_)) => tr("update"), - Some(LauncherState::VoiceOutdated(_)) => tr("update"), - Some(LauncherState::VoiceNotInstalled(_)) => tr("download"), - Some(LauncherState::GameUpdateAvailable(_)) => tr("update"), - Some(LauncherState::GameOutdated(_)) => tr("update"), - Some(LauncherState::GameNotInstalled(_)) => tr("download"), + Some(LauncherState::Launch) => tr("launch"), + Some(LauncherState::PredownloadAvailable { .. }) => tr("launch"), + Some(LauncherState::MainPatchAvailable(_)) => tr("apply-patch"), + Some(LauncherState::WineNotInstalled) => tr("download-wine"), + Some(LauncherState::PrefixNotExists) => tr("create-prefix"), + Some(LauncherState::GameUpdateAvailable(_)) => tr("update"), + Some(LauncherState::GameOutdated(_)) => tr("update"), + Some(LauncherState::GameNotInstalled(_)) => tr("download"), None => String::from("...") }, #[watch] set_sensitive: !model.disabled_buttons && match &model.state { - Some(LauncherState::GameOutdated { .. }) | - Some(LauncherState::VoiceOutdated(_)) => false, + Some(LauncherState::GameOutdated { .. }) => false, - Some(LauncherState::UnityPlayerPatchAvailable(UnityPlayerPatch { status, .. })) | - Some(LauncherState::XluaPatchAvailable(XluaPatch { status, .. })) => match status { + Some(LauncherState::MainPatchAvailable(MainPatch { status, .. })) => match status { PatchStatus::NotAvailable | - PatchStatus::Outdated { .. } | - PatchStatus::Preparation { .. } => false, + PatchStatus::Outdated { .. } => false, PatchStatus::Testing { .. } | PatchStatus::Available { .. } => true @@ -419,14 +391,11 @@ impl SimpleComponent for App { #[watch] set_css_classes: match &model.state { - Some(LauncherState::GameOutdated { .. }) | - Some(LauncherState::VoiceOutdated(_)) => &["warning"], + Some(LauncherState::GameOutdated { .. }) => &["warning"], - Some(LauncherState::UnityPlayerPatchAvailable(UnityPlayerPatch { status, .. })) | - Some(LauncherState::XluaPatchAvailable(XluaPatch { status, .. })) => match status { + Some(LauncherState::MainPatchAvailable(MainPatch { status, .. })) => match status { PatchStatus::NotAvailable | - PatchStatus::Outdated { .. } | - PatchStatus::Preparation { .. } => &["error"], + PatchStatus::Outdated { .. } => &["error"], PatchStatus::Testing { .. } => &["warning"], PatchStatus::Available { .. } => &["suggested-action"] @@ -439,17 +408,11 @@ impl SimpleComponent for App { #[watch] set_tooltip_text: Some(&match &model.state { - Some(LauncherState::GameOutdated { .. }) | - Some(LauncherState::VoiceOutdated(_)) => tr("main-window--version-outdated-tooltip"), + Some(LauncherState::GameOutdated { .. }) => tr("main-window--version-outdated-tooltip"), - Some(LauncherState::FolderMigrationRequired { .. }) => tr("migrate-folders-tooltip"), - - Some(LauncherState::UnityPlayerPatchAvailable(UnityPlayerPatch { status, .. })) | - Some(LauncherState::XluaPatchAvailable(XluaPatch { status, .. })) => match status { + Some(LauncherState::MainPatchAvailable(MainPatch { status, .. })) => match status { PatchStatus::NotAvailable => tr("main-window--patch-unavailable-tooltip"), - - PatchStatus::Outdated { .. } | - PatchStatus::Preparation { .. } => tr("main-window--patch-outdated-tooltip"), + PatchStatus::Outdated { .. } => tr("main-window--patch-outdated-tooltip"), _ => String::new() }, @@ -567,8 +530,8 @@ impl SimpleComponent for App { group.add_action::(&RelmAction::new_stateless(clone!(@strong sender => move |_| { let path = match Config::get() { - Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(), - Err(_) => CONFIG.game.path.for_edition(CONFIG.launcher.edition).to_path_buf(), + Ok(config) => config.game.path, + Err(_) => CONFIG.game.path.clone() }; if let Err(err) = open::that(path) { @@ -605,66 +568,6 @@ impl SimpleComponent for App { } }))); - group.add_action::(&RelmAction::new_stateless(clone!(@strong sender => move |_| { - std::thread::spawn(clone!(@strong sender => move || { - let config = Config::get().unwrap_or_else(|_| CONFIG.clone()); - - let web_cache = config.game.path.for_edition(config.launcher.edition) - .join(config.launcher.edition.data_folder()) - .join("webCaches/Cache/Cache_Data/data_2"); - - if !web_cache.exists() { - tracing::error!("Couldn't find wishes URL: cache file doesn't exist"); - - sender.input(AppMsg::Toast { - title: tr("wish-url-search-failed"), - description: None - }); - } - - else { - match std::fs::read(&web_cache) { - Ok(web_cache) => { - let web_cache = String::from_utf8_lossy(&web_cache); - - // https://webstatic-sea.[ho-yo-ver-se].com/[ge-nsh-in]/event/e20190909gacha-v2/index.html?...... - if let Some(url) = web_cache.lines().rev().find(|line| line.contains("gacha-v2/index.html")) { - let url_begin_pos = url.find("https://").unwrap(); - let url_end_pos = url_begin_pos + url[url_begin_pos..].find("\0\0\0\0").unwrap(); - - if let Err(err) = open::that(format!("{}#/log", &url[url_begin_pos..url_end_pos])) { - tracing::error!("Failed to open wishes URL: {err}"); - - sender.input(AppMsg::Toast { - title: tr("wish-url-opening-error"), - description: Some(err.to_string()) - }); - } - } - - else { - tracing::error!("Couldn't find wishes URL: no url found"); - - sender.input(AppMsg::Toast { - title: tr("wish-url-search-failed"), - description: None - }); - } - } - - Err(err) => { - tracing::error!("Couldn't find wishes URL: failed to open cache file: {err}"); - - sender.input(AppMsg::Toast { - title: tr("wish-url-search-failed"), - description: Some(err.to_string()) - }); - } - } - } - })); - }))); - group.add_action::(&RelmAction::new_stateless(move |_| { about_dialog_broker.send(AboutDialogMsg::Show); })); @@ -783,28 +686,12 @@ impl SimpleComponent for App { } } - // Get main UnityPlayer patch status - sender.input(AppMsg::SetUnityPlayerPatch(match patch.unity_player_patch() { + // Get the main patch status + sender.input(AppMsg::SetMainPatch(match patch.main_patch() { Ok(patch) => Some(patch), Err(err) => { - tracing::error!("Failed to fetch unity player patch info: {err}"); - - sender.input(AppMsg::Toast { - title: tr("patch-info-fetching-error"), - description: Some(err.to_string()) - }); - - None - } - })); - - // Get additional xlua patch status - sender.input(AppMsg::SetXluaPatch(match patch.xlua_patch() { - Ok(patch) => Some(patch), - - Err(err) => { - tracing::error!("Failed to fetch xlua patch info: {err}"); + tracing::error!("Failed to fetch main patch info: {err}"); sender.input(AppMsg::Toast { title: tr("patch-info-fetching-error"), @@ -874,12 +761,6 @@ impl SimpleComponent for App { sender.input(AppMsg::SetLoadingStatus(Some(Some(tr("loading-launcher-state--game"))))); } - StateUpdating::Voice(locale) => { - sender.input(AppMsg::SetLoadingStatus(Some(Some(tr_args("loading-launcher-state--voice", [ - ("locale", locale.to_name().to_owned().into()) - ]))))); - } - StateUpdating::Patch => { sender.input(AppMsg::SetLoadingStatus(Some(Some(tr("loading-launcher-state--patch"))))); } @@ -905,18 +786,15 @@ impl SimpleComponent for App { } else { self.disabled_buttons = false; } - + if let Some(state) = state { match state { - LauncherState::VoiceUpdateAvailable(_) | - LauncherState::VoiceNotInstalled(_) | LauncherState::GameUpdateAvailable(_) | LauncherState::GameNotInstalled(_) if perform_on_download_needed => { sender.input(AppMsg::PerformAction); } - LauncherState::UnityPlayerPatchAvailable(_) | - LauncherState::XluaPatchAvailable(_) if apply_patch_if_needed => { + LauncherState::MainPatchAvailable(_) if apply_patch_if_needed => { sender.input(AppMsg::PerformAction); } @@ -931,13 +809,8 @@ impl SimpleComponent for App { } #[allow(unused_must_use)] - AppMsg::SetUnityPlayerPatch(patch) => unsafe { - PREFERENCES_WINDOW.as_ref().unwrap_unchecked().sender().send(PreferencesAppMsg::SetUnityPlayerPatch(patch)); - } - - #[allow(unused_must_use)] - AppMsg::SetXluaPatch(patch) => unsafe { - PREFERENCES_WINDOW.as_ref().unwrap_unchecked().sender().send(PreferencesAppMsg::SetXluaPatch(patch)); + AppMsg::SetMainPatch(patch) => unsafe { + PREFERENCES_WINDOW.as_ref().unwrap_unchecked().sender().send(PreferencesAppMsg::SetMainPatch(patch)); } AppMsg::SetLauncherState(state) => { @@ -968,7 +841,7 @@ impl SimpleComponent for App { #[allow(unused_must_use)] AppMsg::PredownloadUpdate => { - if let Some(LauncherState::PredownloadAvailable { game, mut voices }) = self.state.clone() { + if let Some(LauncherState::PredownloadAvailable(mut game)) = self.state.clone() { let tmp = Config::get().unwrap().launcher.temp.unwrap_or_else(std::env::temp_dir); self.downloading = true; @@ -977,26 +850,18 @@ impl SimpleComponent for App { progress_bar_input.send(ProgressBarMsg::UpdateCaption(Some(tr("downloading")))); - let mut diffs: Vec = vec![game]; - - diffs.append(&mut voices); - std::thread::spawn(move || { - for mut diff in diffs { - let result = diff.download_in(&tmp, clone!(@strong progress_bar_input => move |curr, total| { - progress_bar_input.send(ProgressBarMsg::UpdateProgress(curr, total)); - })); + let result = game.download_in(&tmp, clone!(@strong progress_bar_input => move |curr, total| { + progress_bar_input.send(ProgressBarMsg::UpdateProgress(curr, total)); + })); - if let Err(err) = result { - sender.input(AppMsg::Toast { - title: tr("downloading-failed"), - description: Some(err.to_string()) - }); + if let Err(err) = result { + sender.input(AppMsg::Toast { + title: tr("downloading-failed"), + description: Some(err.to_string()) + }); - tracing::error!("Failed to predownload update: {err}"); - - break; - } + tracing::error!("Failed to predownload update: {err}"); } sender.input(AppMsg::SetDownloading(false)); @@ -1011,28 +876,18 @@ impl SimpleComponent for App { AppMsg::PerformAction => unsafe { match self.state.as_ref().unwrap_unchecked() { - LauncherState::UnityPlayerPatchAvailable(UnityPlayerPatch { status: PatchStatus::NotAvailable, .. }) | - LauncherState::XluaPatchAvailable(XluaPatch { status: PatchStatus::NotAvailable, .. }) | + LauncherState::MainPatchAvailable(MainPatch { status: PatchStatus::NotAvailable, .. }) | LauncherState::PredownloadAvailable { .. } | LauncherState::Launch => launch::launch(sender), - LauncherState::FolderMigrationRequired { from, to, cleanup_folder } => - migrate_folder::migrate_folder(sender, from.to_owned(), to.to_owned(), cleanup_folder.to_owned()), - - LauncherState::UnityPlayerPatchAvailable(patch) => apply_patch::apply_patch(sender, patch.to_owned()), - LauncherState::XluaPatchAvailable(patch) => apply_patch::apply_patch(sender, patch.to_owned()), - + LauncherState::MainPatchAvailable(patch) => apply_patch::apply_patch(sender, patch.to_owned()), LauncherState::WineNotInstalled => download_wine::download_wine(sender, self.progress_bar.sender().to_owned()), - LauncherState::PrefixNotExists => create_prefix::create_prefix(sender), - LauncherState::VoiceUpdateAvailable(diff) | - LauncherState::VoiceNotInstalled(diff) | LauncherState::GameUpdateAvailable(diff) | LauncherState::GameNotInstalled(diff) => download_diff::download_diff(sender, self.progress_bar.sender().to_owned(), diff.to_owned()), - LauncherState::VoiceOutdated(_) | LauncherState::GameOutdated(_) => () } } diff --git a/src/ui/main/repair_game.rs b/src/ui/main/repair_game.rs index 4b679ab..6c407c2 100644 --- a/src/ui/main/repair_game.rs +++ b/src/ui/main/repair_game.rs @@ -21,19 +21,7 @@ pub fn repair_game(sender: ComponentSender, progress_bar_input: Sender { - // Add voiceovers files - let game_path = config.game.path.for_edition(config.launcher.edition).to_path_buf(); - let game = Game::new(&game_path); - - if let Ok(voiceovers) = game.get_voice_packages() { - for package in voiceovers { - if let Ok(mut voiceover_files) = repairer::try_get_voice_integrity_files(package.locale(), None) { - files.append(&mut voiceover_files); - } - } - } - + Ok(files) => { progress_bar_input.send(ProgressBarMsg::UpdateProgress(0, 0)); let mut total = 0; @@ -64,7 +52,7 @@ pub fn repair_game(sender: ComponentSender, progress_bar_input: Sender move || { + std::thread::spawn(clone!(@strong config.game.path as game_path => move || { for file in thread_files { let status = if config.launcher.repairer.fast { file.fast_verify(&game_path) @@ -105,34 +93,15 @@ pub fn repair_game(sender: ComponentSender, progress_bar_input: Sender bool { - // Files managed by launch.bat file - for part in ["crashreport.exe", "upload_crash.exe"] { - if path.ends_with(part) { - return true; - } - } - - // UnityPlayer patch related files - if player_patch { - for part in ["UnityPlayer.dll", "vulkan-1.dll"] { - if path.ends_with(part) { - return true; - } - } - } - - // Xlua patch related files - if xlua_patch { - for part in ["xlua.dll", "mhypbase.dll"] { + fn should_ignore(path: &Path, main_patch: bool) -> bool { + // Main patch related files + if main_patch { + for part in ["StarRailBase.dll", "UnityPlayer.dll"] { if path.ends_with(part) { return true; } @@ -143,10 +112,10 @@ pub fn repair_game(sender: ComponentSender, progress_bar_input: Sender 0, - Fps::HundredTwenty => 1, - Fps::HundredFourtyFour => 2, - Fps::HundredSixtyFive => 3, - Fps::HundredEighty => 4, - Fps::TwoHundred => 5, - Fps::TwoHundredFourty => 6, - - Fps::Custom(_) => 7 - }, - - connect_selected_notify => |row| { - if is_ready() && row.selected() < Fps::list().len() as u32 - 1 { - if let Ok(mut config) = Config::get() { - config.game.enhancements.fps_unlocker.config.fps = Fps::list()[row.selected() as usize].to_num(); - - Config::update(config); - } - } - }, - - add_suffix = >k::Switch { - set_valign: gtk::Align::Center, - - set_state: CONFIG.game.enhancements.fps_unlocker.enabled, - - connect_state_notify => |switch| { - if is_ready() { - if let Ok(mut config) = Config::get() { - config.game.enhancements.fps_unlocker.enabled = switch.state(); - - Config::update(config); - } - } - } - } - }, - - adw::ActionRow { - set_title: &tr("power-saving"), - set_subtitle: &tr("power-saving-description"), - - add_suffix = >k::Switch { - set_valign: gtk::Align::Center, - - set_state: CONFIG.game.enhancements.fps_unlocker.config.power_saving, - - connect_state_notify => |switch| { - if is_ready() { - if let Ok(mut config) = Config::get() { - config.game.enhancements.fps_unlocker.config.power_saving = switch.state(); - - Config::update(config); - } - } - } - } - }, - - adw::ActionRow { - set_title: &tr("monitor"), - set_subtitle: &tr("monitor-description"), - - add_suffix = >k::SpinButton { - set_valign: gtk::Align::Center, - set_adjustment: >k::Adjustment::new(1.0, 1.0, 10.0, 1.0, 1.0, 0.0), - - set_value: CONFIG.game.enhancements.fps_unlocker.config.monitor as f64, - - connect_changed => |row| { - if is_ready() { - if let Ok(mut config) = Config::get() { - config.game.enhancements.fps_unlocker.config.monitor = row.value() as u64; - - Config::update(config); - } - } - } - } - }, - - adw::ComboRow { - set_title: &tr("window-mode"), - - #[wrap(Some)] - set_model = >k::StringList::new(&[ - &tr("default"), - &tr("popup"), - &tr("fullscreen") - ]), - - set_selected: CONFIG.game.enhancements.fps_unlocker.config.window_mode.ordinal() as u32, - - connect_selected_notify => |row| unsafe { - if is_ready() { - if let Ok(mut config) = Config::get() { - config.game.enhancements.fps_unlocker.config.window_mode = WindowMode::from_ordinal_unsafe(row.selected() as i8); - - Config::update(config); - } - } - } - }, - - adw::ComboRow { - set_title: &tr("priority"), - set_subtitle: &tr("priority-description"), - - #[wrap(Some)] - set_model = >k::StringList::new(&[ - &tr("realtime"), - &tr("high"), - &tr("above-normal"), - &tr("normal"), - &tr("below-normal"), - &tr("low") - ]), - - set_selected: CONFIG.game.enhancements.fps_unlocker.config.priority as u32, - - connect_selected_notify => |row| { - if is_ready() { - if let Ok(mut config) = Config::get() { - config.game.enhancements.fps_unlocker.config.priority = row.selected() as u64; - - Config::update(config); - } - } - } - }, } } } diff --git a/src/ui/preferences/gamescope.rs b/src/ui/preferences/gamescope.rs index b91480f..02a9716 100644 --- a/src/ui/preferences/gamescope.rs +++ b/src/ui/preferences/gamescope.rs @@ -4,7 +4,7 @@ use relm4::component::*; use adw::prelude::*; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; +use anime_launcher_sdk::star_rail::config::Config; use anime_launcher_sdk::config::schema_blanks::prelude::*; diff --git a/src/ui/preferences/general.rs b/src/ui/preferences/general.rs index 6c09ff2..601e5bf 100644 --- a/src/ui/preferences/general.rs +++ b/src/ui/preferences/general.rs @@ -1,16 +1,10 @@ use relm4::prelude::*; use relm4::component::*; -use relm4::factory::{ - AsyncFactoryVecDeque, - AsyncFactoryComponent, - AsyncFactorySender -}; use gtk::prelude::*; use adw::prelude::*; use anime_launcher_sdk::anime_game_core::prelude::*; -use anime_launcher_sdk::anime_game_core::genshin::consts::GameEdition; use anime_launcher_sdk::wincompatlib::prelude::*; @@ -18,10 +12,8 @@ use anime_launcher_sdk::components::*; use anime_launcher_sdk::components::wine::WincompatlibWine; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; - -use anime_launcher_sdk::genshin::config::schema::launcher::LauncherStyle; -use anime_launcher_sdk::genshin::env_emulation::Environment; +use anime_launcher_sdk::star_rail::config::Config; +use anime_launcher_sdk::star_rail::config::schema::launcher::LauncherStyle; use super::main::PreferencesAppMsg; use crate::ui::migrate_installation::MigrateInstallationApp; @@ -30,93 +22,13 @@ use crate::ui::components::*; use crate::i18n::*; use crate::*; -#[derive(Debug)] -struct VoicePackageComponent { - locale: VoiceLocale, - installed: bool, - sensitive: bool -} - -#[relm4::factory(async)] -impl AsyncFactoryComponent for VoicePackageComponent { - type Init = (VoiceLocale, bool); - type Input = GeneralAppMsg; - type Output = GeneralAppMsg; - type CommandOutput = (); - type ParentInput = GeneralAppMsg; - type ParentWidget = adw::ExpanderRow; - - view! { - root = adw::ActionRow { - set_title: &tr(&self.locale.to_name().to_ascii_lowercase()), - - add_suffix = >k::Button { - #[watch] - set_visible: self.installed, - - #[watch] - set_sensitive: self.sensitive, - - set_icon_name: "user-trash-symbolic", - add_css_class: "flat", - set_valign: gtk::Align::Center, - - connect_clicked[sender, index] => move |_| { - sender.input(GeneralAppMsg::RemoveVoicePackage(index.clone())); - } - }, - - add_suffix = >k::Button { - #[watch] - set_visible: !self.installed, - - #[watch] - set_sensitive: self.sensitive, - - set_icon_name: "document-save-symbolic", - add_css_class: "flat", - set_valign: gtk::Align::Center, - - connect_clicked[sender, index] => move |_| { - sender.input(GeneralAppMsg::AddVoicePackage(index.clone())); - } - } - } - } - - fn output_to_parent_input(output: Self::Output) -> Option { - Some(output) - } - - async fn init_model( - init: Self::Init, - _index: &DynamicIndex, - _sender: AsyncFactorySender, - ) -> Self { - Self { - locale: init.0, - installed: init.1, - sensitive: true - } - } - - async fn update(&mut self, msg: Self::Input, sender: AsyncFactorySender) { - self.installed = !self.installed; - - sender.output(msg); - } -} - pub struct GeneralApp { - voice_packages: AsyncFactoryVecDeque, - migrate_installation: Controller, wine_components: AsyncController>, dxvk_components: AsyncController>, game_diff: Option, - unity_player_patch: Option, - xlua_patch: Option, + main_patch: Option, style: LauncherStyle, @@ -141,18 +53,7 @@ pub enum GeneralAppMsg { /// Supposed to be called automatically on app's run when the latest UnityPlayer patch version /// was retrieved from remote repos - SetUnityPlayerPatch(Option), - - /// Supposed to be called automatically on app's run when the latest xlua patch version - /// was retrieved from remote repos - SetXluaPatch(Option), - - // If one ever wish to change it to accept VoiceLocale - // I'd recommend to use clone!(@strong self.locale as locale => move |_| { .. }) - // in the VoicePackage component - AddVoicePackage(DynamicIndex), - RemoveVoicePackage(DynamicIndex), - SetVoicePackageSensitivity(DynamicIndex, bool), + SetMainPatch(Option), OpenMigrateInstallation, RepairGame, @@ -306,79 +207,6 @@ impl SimpleAsyncComponent for GeneralApp { } }, - adw::ComboRow { - set_title: &tr("game-edition"), - - set_model: Some(>k::StringList::new(&[ - &tr("global"), - &tr("china") - ])), - - set_selected: match CONFIG.launcher.edition { - GameEdition::Global => 0, - GameEdition::China => 1 - }, - - connect_selected_notify[sender] => move |row| { - if is_ready() { - #[allow(unused_must_use)] - if let Ok(mut config) = Config::get() { - config.launcher.edition = match row.selected() { - 0 => GameEdition::Global, - 1 => GameEdition::China, - - _ => unreachable!() - }; - - // Select new game edition - config.launcher.edition.select(); - - Config::update(config); - - sender.output(PreferencesAppMsg::UpdateLauncherState); - } - } - } - }, - - adw::ComboRow { - set_title: &tr("game-environment"), - set_subtitle: &tr("game-environment-description"), - - set_model: Some(>k::StringList::new(&[ - "PC", - "Android" - ])), - - set_selected: match CONFIG.launcher.environment { - Environment::PC => 0, - Environment::Android => 1, - - _ => unreachable!() - }, - - connect_selected_notify => |row| { - if is_ready() { - if let Ok(mut config) = Config::get() { - config.launcher.environment = match row.selected() { - 0 => Environment::PC, - 1 => Environment::Android, - - _ => unreachable!() - }; - - Config::update(config); - } - } - } - }, - - #[local_ref] - voice_packages -> adw::ExpanderRow { - set_title: &tr("game-voiceovers"), - set_subtitle: &tr("game-voiceovers-description") - }, - gtk::Box { set_orientation: gtk::Orientation::Horizontal, set_spacing: 8, @@ -462,11 +290,10 @@ impl SimpleAsyncComponent for GeneralApp { add_suffix = >k::Label { #[watch] - set_text: &match model.unity_player_patch.as_ref() { + set_text: &match model.main_patch.as_ref() { Some(patch) => match patch.status() { PatchStatus::NotAvailable => tr("patch-not-available"), PatchStatus::Outdated { current, .. } => tr_args("patch-outdated", [("current", current.to_string().into())]), - PatchStatus::Preparation { .. } => tr("patch-preparation"), PatchStatus::Testing { version, .. } | PatchStatus::Available { version, .. } => version.to_string() } @@ -475,19 +302,20 @@ impl SimpleAsyncComponent for GeneralApp { }, #[watch] - set_css_classes: match model.unity_player_patch.as_ref() { + set_css_classes: match model.main_patch.as_ref() { Some(patch) => match patch.status() { PatchStatus::NotAvailable => &["error"], + PatchStatus::Outdated { .. } | - PatchStatus::Preparation { .. } | PatchStatus::Testing { .. } => &["warning"], + PatchStatus::Available { .. } => unsafe { let path = match Config::get() { - Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(), - Err(_) => CONFIG.game.path.for_edition(CONFIG.launcher.edition).to_path_buf(), + Ok(config) => config.game.path, + Err(_) => CONFIG.game.path.clone(), }; - if let Ok(true) = model.unity_player_patch.as_ref().unwrap_unchecked().is_applied(path) { + if let Ok(true) = model.main_patch.as_ref().unwrap_unchecked().is_applied(path) { &["success"] } else { &["warning"] @@ -499,93 +327,21 @@ impl SimpleAsyncComponent for GeneralApp { }, #[watch] - set_tooltip_text: Some(&match model.unity_player_patch.as_ref() { + set_tooltip_text: Some(&match model.main_patch.as_ref() { Some(patch) => match patch.status() { PatchStatus::NotAvailable => tr("patch-not-available-tooltip"), PatchStatus::Outdated { current, latest, .. } => tr_args("patch-outdated-tooltip", [ ("current", current.to_string().into()), ("latest", latest.to_string().into()) ]), - PatchStatus::Preparation { .. } => tr("patch-preparation-tooltip"), PatchStatus::Testing { .. } => tr("patch-testing-tooltip"), PatchStatus::Available { .. } => unsafe { let path = match Config::get() { - Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(), - Err(_) => CONFIG.game.path.for_edition(CONFIG.launcher.edition).to_path_buf(), + Ok(config) => config.game.path, + Err(_) => CONFIG.game.path.clone(), }; - if let Ok(true) = model.unity_player_patch.as_ref().unwrap_unchecked().is_applied(path) { - String::new() - } else { - tr("patch-not-applied-tooltip") - } - } - } - - None => String::new() - }) - } - }, - - adw::ActionRow { - set_title: &tr("xlua-patch-version"), - set_subtitle: &tr("xlua-patch-version-description"), - - add_suffix = >k::Label { - #[watch] - set_text: &match model.xlua_patch.as_ref() { - Some(patch) => match patch.status() { - PatchStatus::NotAvailable => tr("patch-not-available"), - PatchStatus::Outdated { current, .. } => tr_args("patch-outdated", [("current", current.to_string().into())]), - PatchStatus::Preparation { .. } => tr("patch-preparation"), - PatchStatus::Testing { version, .. } | - PatchStatus::Available { version, .. } => version.to_string() - } - - None => String::from("?") - }, - - #[watch] - set_css_classes: match model.xlua_patch.as_ref() { - Some(patch) => match patch.status() { - PatchStatus::NotAvailable => &["error"], - PatchStatus::Outdated { .. } | - PatchStatus::Preparation { .. } | - PatchStatus::Testing { .. } => &["warning"], - PatchStatus::Available { .. } => unsafe { - let path = match Config::get() { - Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(), - Err(_) => CONFIG.game.path.for_edition(CONFIG.launcher.edition).to_path_buf(), - }; - - if let Ok(true) = model.xlua_patch.as_ref().unwrap_unchecked().is_applied(path) { - &["success"] - } else { - &["warning"] - } - } - } - - None => &[] - }, - - #[watch] - set_tooltip_text: Some(&match model.xlua_patch.as_ref() { - Some(patch) => match patch.status() { - PatchStatus::NotAvailable => tr("patch-not-available-tooltip"), - PatchStatus::Outdated { current, latest, .. } => tr_args("patch-outdated-tooltip", [ - ("current", current.to_string().into()), - ("latest", latest.to_string().into()) - ]), - PatchStatus::Preparation { .. } => tr("patch-preparation-tooltip"), - PatchStatus::Testing { .. } => tr("patch-testing-tooltip"), - PatchStatus::Available { .. } => unsafe { - let path = match Config::get() { - Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(), - Err(_) => CONFIG.game.path.for_edition(CONFIG.launcher.edition).to_path_buf(), - }; - - if let Ok(true) = model.xlua_patch.as_ref().unwrap_unchecked().is_applied(path) { + if let Ok(true) = model.main_patch.as_ref().unwrap_unchecked().is_applied(path) { String::new() } else { tr("patch-not-applied-tooltip") @@ -600,29 +356,6 @@ impl SimpleAsyncComponent for GeneralApp { }, add = &adw::PreferencesGroup { - adw::ActionRow { - set_title: &tr("apply-xlua-patch"), - - add_suffix = >k::Switch { - set_valign: gtk::Align::Center, - - set_state: CONFIG.patch.apply_xlua, - - connect_state_notify[sender] => move |switch| { - if is_ready() { - #[allow(unused_must_use)] - if let Ok(mut config) = Config::get() { - config.patch.apply_xlua = switch.state(); - - Config::update(config); - - sender.output(PreferencesAppMsg::UpdateLauncherState); - } - } - } - } - }, - adw::ActionRow { set_title: &tr("ask-superuser-permissions"), set_subtitle: &tr("ask-superuser-permissions-description"), @@ -835,9 +568,7 @@ impl SimpleAsyncComponent for GeneralApp { ) -> AsyncComponentParts { tracing::info!("Initializing general settings"); - let mut model = Self { - voice_packages: AsyncFactoryVecDeque::new(adw::ExpanderRow::new(), sender.input_sender()), - + let model = Self { migrate_installation: MigrateInstallationApp::builder() .launch(()) .detach(), @@ -905,8 +636,7 @@ impl SimpleAsyncComponent for GeneralApp { .forward(sender.input_sender(), std::convert::identity), game_diff: None, - unity_player_patch: None, - xlua_patch: None, + main_patch: None, style: CONFIG.launcher.style, @@ -931,15 +661,6 @@ impl SimpleAsyncComponent for GeneralApp { selecting_dxvk_version: false }; - for package in VoiceLocale::list() { - model.voice_packages.guard().push_back(( - *package, - CONFIG.game.voices.iter().any(|voice| VoiceLocale::from_str(voice) == Some(*package)) - )); - } - - let voice_packages = model.voice_packages.widget(); - let widgets = view_output!(); AsyncComponentParts { model, widgets } @@ -953,69 +674,8 @@ impl SimpleAsyncComponent for GeneralApp { self.game_diff = diff; } - GeneralAppMsg::SetUnityPlayerPatch(patch) => { - self.unity_player_patch = patch; - } - - GeneralAppMsg::SetXluaPatch(patch) => { - self.xlua_patch = patch; - } - - #[allow(unused_must_use)] - GeneralAppMsg::AddVoicePackage(index) => { - if let Some(package) = self.voice_packages.get(index.current_index()) { - if let Ok(mut config) = Config::get() { - if !config.game.voices.iter().any(|voice| VoiceLocale::from_str(voice) == Some(package.locale)) { - config.game.voices.push(package.locale.to_code().to_string()); - - Config::update(config); - - sender.output(PreferencesAppMsg::UpdateLauncherState); - } - } - } - } - - #[allow(unused_must_use)] - GeneralAppMsg::RemoveVoicePackage(index) => { - if let Some(package) = self.voice_packages.guard().get_mut(index.current_index()) { - if let Ok(mut config) = Config::get() { - package.sensitive = false; - - config.game.voices.retain(|voice| VoiceLocale::from_str(voice) != Some(package.locale)); - - Config::update(config.clone()); - - let package = VoicePackage::with_locale(package.locale).unwrap(); - let game_path = config.game.path.for_edition(config.launcher.edition).to_path_buf(); - - if package.is_installed_in(&game_path) { - std::thread::spawn(move || { - if let Err(err) = package.delete_in(game_path) { - tracing::error!("Failed to delete voice package: {:?}", package.locale()); - - sender.input(GeneralAppMsg::Toast { - title: tr("voice-package-deletion-error"), - description: Some(err.to_string()) - }); - } - - sender.input(GeneralAppMsg::SetVoicePackageSensitivity(index, true)); - sender.output(PreferencesAppMsg::UpdateLauncherState); - }); - } - - else { - sender.input(GeneralAppMsg::SetVoicePackageSensitivity(index, true)); - } - } - } - } - - GeneralAppMsg::SetVoicePackageSensitivity(index, sensitive) => { - if let Some(package) = self.voice_packages.guard().get_mut(index.current_index()) { - package.sensitive = sensitive; - } + GeneralAppMsg::SetMainPatch(patch) => { + self.main_patch = patch; } GeneralAppMsg::OpenMigrateInstallation => unsafe { diff --git a/src/ui/preferences/main.rs b/src/ui/preferences/main.rs index 7665219..aefd30b 100644 --- a/src/ui/preferences/main.rs +++ b/src/ui/preferences/main.rs @@ -5,11 +5,11 @@ use gtk::prelude::*; use adw::prelude::*; use anime_launcher_sdk::anime_game_core::prelude::*; -use anime_launcher_sdk::anime_game_core::genshin::prelude::*; +use anime_launcher_sdk::anime_game_core::star_rail::prelude::*; use anime_launcher_sdk::config::ConfigExt; -use anime_launcher_sdk::genshin::config::Config; -use anime_launcher_sdk::genshin::config::schema::launcher::LauncherStyle; +use anime_launcher_sdk::star_rail::config::Config; +use anime_launcher_sdk::star_rail::config::schema::launcher::LauncherStyle; use crate::i18n::tr; @@ -33,13 +33,9 @@ pub enum PreferencesAppMsg { /// was retrieved from the API SetGameDiff(Option), - /// Supposed to be called automatically on app's run when the latest UnityPlayer patch version + /// Supposed to be called automatically on app's run when the latest main patch version /// was retrieved from remote repos - SetUnityPlayerPatch(Option), - - /// Supposed to be called automatically on app's run when the latest xlua patch version - /// was retrieved from remote repos - SetXluaPatch(Option), + SetMainPatch(Option), SetLauncherStyle(LauncherStyle), @@ -138,13 +134,8 @@ impl SimpleAsyncComponent for PreferencesApp { } #[allow(unused_must_use)] - PreferencesAppMsg::SetUnityPlayerPatch(patch) => { - self.general.sender().send(GeneralAppMsg::SetUnityPlayerPatch(patch)); - } - - #[allow(unused_must_use)] - PreferencesAppMsg::SetXluaPatch(patch) => { - self.general.sender().send(GeneralAppMsg::SetXluaPatch(patch)); + PreferencesAppMsg::SetMainPatch(patch) => { + self.general.sender().send(GeneralAppMsg::SetMainPatch(patch)); } #[allow(unused_must_use)]