feat: initial transition to the new sdk version

This commit is contained in:
Nikita Podvirnyi 2024-07-04 09:44:19 +02:00
parent 35710a83ae
commit 08725de1e0
No known key found for this signature in database
GPG key ID: 859D416E5142AFF3
20 changed files with 67 additions and 655 deletions

20
Cargo.lock generated
View file

@ -57,8 +57,8 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]]
name = "anime-game-core"
version = "1.20.2"
source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.20.2#3f013bffed78ca9c22db1d8bb10d4ae8ef527c5c"
version = "1.21.0"
source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.21.0#d4ec0fde4c467f37bf7eaa8332949fd84b3d631a"
dependencies = [
"anyhow",
"bzip2",
@ -82,8 +82,8 @@ dependencies = [
[[package]]
name = "anime-launcher-sdk"
version = "1.15.4"
source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.15.4#eebd048fb05034959fd06e499fcdfaebbcce1d6c"
version = "1.16.0"
source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.16.0#b55ea3f4606dffc3d63760d56a903f99417c673b"
dependencies = [
"anime-game-core",
"anyhow",
@ -463,9 +463,9 @@ dependencies = [
[[package]]
name = "cached"
version = "0.51.4"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0feb64151eed3da6107fddd2d717a6ca4b9dbd74e43784c55c841d1abfe5a295"
checksum = "a8466736fe5dbcaf8b8ee24f9bbefe43c884dc3e9ff7178da70f55bffca1133c"
dependencies = [
"ahash",
"cached_proc_macro",
@ -478,9 +478,9 @@ dependencies = [
[[package]]
name = "cached_proc_macro"
version = "0.21.0"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771aa57f3b17da6c8bcacb187bb9ec9bc81c8160e72342e67c329e0e1651a669"
checksum = "575f32e012222055211b70f5b0601f951f84523410a0e65c81f2744a6042450d"
dependencies = [
"darling",
"proc-macro2",
@ -1901,9 +1901,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "open"
version = "5.1.4"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5ca541f22b1c46d4bb9801014f234758ab4297e7870b904b6a8415b980a7388"
checksum = "9d2c909a3fce3bd80efef4cd1c6c056bd9376a8fe06fcfdbebaf32cb485a7e37"
dependencies = [
"is-wsl",
"libc",

View file

@ -19,8 +19,8 @@ glib-build-tools = "0.19"
[dependencies.anime-launcher-sdk]
git = "https://github.com/an-anime-team/anime-launcher-sdk"
tag = "1.15.4"
features = ["all", "genshin"]
tag = "1.16.0"
features = ["all", "zzz"]
# path = "../anime-launcher-sdk" # ! for dev purposes only
@ -30,13 +30,13 @@ gtk = { package = "gtk4", version = "0.8.1", features = ["v4_12"] }
adw = { package = "libadwaita", version = "0.6.0", features = ["v1_4"] }
rfd = { version = "0.14.1", features = ["xdg-portal", "tokio"], default-features = false }
open = "5.0.0"
open = "5.2.0"
whatadistro = "0.1.0"
serde_json = "1.0"
anyhow = "1.0"
lazy_static = "1.4.0"
cached = { version = "0.51", features = ["proc_macro"] }
lazy_static = "1.5.0"
cached = { version = "0.52", features = ["proc_macro"] }
md-5 = { version = "0.10", features = ["asm"] }
enum-ordinalize = "4.3"

View file

@ -25,6 +25,7 @@ in pkgs.mkShell {
pkg-config
xdelta
p7zip
libwebp
];

View file

@ -4,16 +4,16 @@ use std::sync::atomic::{AtomicBool, Ordering};
use relm4::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::{Config, Schema};
use anime_launcher_sdk::zzz::config::{Config, Schema};
use anime_launcher_sdk::genshin::states::LauncherState;
use anime_launcher_sdk::genshin::consts::*;
use anime_launcher_sdk::zzz::states::LauncherState;
use anime_launcher_sdk::zzz::consts::*;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
use anime_launcher_sdk::anime_game_core::zzz::prelude::*;
use anime_launcher_sdk::sessions::SessionsExt;
use anime_launcher_sdk::genshin::sessions::Sessions;
use anime_launcher_sdk::zzz::sessions::Sessions;
use tracing_subscriber::prelude::*;
use tracing_subscriber::filter::*;
@ -233,13 +233,13 @@ fn main() -> anyhow::Result<()> {
match state {
LauncherState::Launch => {
anime_launcher_sdk::genshin::game::run().expect("Failed to run the game");
anime_launcher_sdk::zzz::game::run().expect("Failed to run the game");
return Ok(());
}
LauncherState::PredownloadAvailable { .. } if just_run_game => {
anime_launcher_sdk::genshin::game::run().expect("Failed to run the game");
anime_launcher_sdk::zzz::game::run().expect("Failed to run the game");
return Ok(());
}

View file

@ -2,7 +2,7 @@ use relm4::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::zzz::prelude::*;
use crate::*;

View file

@ -8,10 +8,10 @@ use adw::prelude::*;
use gtk::glib::clone;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
use anime_launcher_sdk::anime_game_core::zzz::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use anime_launcher_sdk::zzz::config::Config;
use super::ComponentGroupMsg;
use super::progress_bar::ProgressBarMsg;

View file

@ -21,7 +21,6 @@ pub struct DefaultPathsApp {
prefix: PathBuf,
game_global: PathBuf,
game_china: PathBuf,
fps_unlocker: PathBuf,
components: PathBuf,
temp: PathBuf
}
@ -34,7 +33,6 @@ pub enum Folders {
Prefix,
GameGlobal,
GameChina,
FpsUnlocker,
Components,
Temp
}
@ -186,20 +184,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
}
},
adw::ActionRow {
set_title: &tr!("fps-unlocker-folder"),
set_activatable: true,
#[watch]
set_subtitle: model.fps_unlocker.to_str().unwrap(),
connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::FpsUnlocker),
add_prefix = &gtk::Image {
set_icon_name: Some("folder-symbolic")
}
},
adw::ActionRow {
set_title: &tr!("components-index"),
set_activatable: true,
@ -308,7 +292,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
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(),
components: CONFIG.components.path.clone(),
#[allow(clippy::or_fun_call)]
@ -340,9 +323,8 @@ impl SimpleAsyncComponent for DefaultPathsApp {
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.game_global = result.join(concat!("Zen", "less Z", "one Zero"));
self.game_china = result.join(concat!("Zen", "less Z", "one Zero"));
self.components = result.join("components");
self.temp.clone_from(&result);
@ -355,7 +337,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
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::Temp => self.temp = result
}
@ -379,9 +360,7 @@ impl SimpleAsyncComponent for DefaultPathsApp {
(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.components.path, &self.components),
(old_config.game.enhancements.fps_unlocker.path, &self.fps_unlocker)
(old_config.components.path, &self.components)
];
#[allow(clippy::expect_fun_call)]
@ -405,7 +384,7 @@ impl SimpleAsyncComponent for DefaultPathsApp {
}
else {
sender.output(Self::Output::ScrollToSelectVoiceovers);
sender.output(Self::Output::ScrollToDownloadComponents);
}
}
@ -442,7 +421,6 @@ impl DefaultPathsApp {
config.game.path.global.clone_from(&self.game_global);
config.game.path.china.clone_from(&self.game_china);
config.components.path.clone_from(&self.components);
config.game.enhancements.fps_unlocker.path.clone_from(&self.fps_unlocker);
config.launcher.temp = Some(self.temp.clone());

View file

@ -10,7 +10,7 @@ use anime_launcher_sdk::components::*;
use anime_launcher_sdk::components::wine::UnifiedWine;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use anime_launcher_sdk::zzz::config::Config;
use super::main::FirstRunAppMsg;

View file

@ -10,7 +10,6 @@ use crate::*;
use super::welcome::*;
use super::dependencies::*;
use super::default_paths::*;
use super::select_voiceovers::*;
use super::download_components::*;
use super::finish::*;
@ -22,7 +21,6 @@ pub struct FirstRunApp {
welcome: AsyncController<WelcomeApp>,
dependencies: AsyncController<DependenciesApp>,
default_paths: AsyncController<DefaultPathsApp>,
select_voiceovers: AsyncController<SelectVoiceoversApp>,
download_components: AsyncController<DownloadComponentsApp>,
finish: AsyncController<FinishApp>,
@ -39,7 +37,6 @@ pub enum FirstRunAppMsg {
ScrollToDependencies,
ScrollToDefaultPaths,
ScrollToSelectVoiceovers,
ScrollToDownloadComponents,
ScrollToFinish,
@ -98,7 +95,6 @@ impl SimpleComponent for FirstRunApp {
append = model.welcome.widget(),
append = model.dependencies.widget(),
append = model.default_paths.widget(),
append = model.select_voiceovers.widget(),
append = model.download_components.widget(),
append = model.finish.widget(),
},
@ -134,10 +130,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),
@ -189,12 +181,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")))));

View file

@ -2,6 +2,5 @@ pub mod main;
pub mod welcome;
pub mod dependencies;
pub mod default_paths;
pub mod select_voiceovers;
pub mod download_components;
pub mod finish;

View file

@ -1,174 +0,0 @@
use relm4::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use crate::*;
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_active: 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<Self>) -> AsyncComponentParts<Self> {
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<Self>) {
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)
}
}

View file

@ -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::zzz::config::Config;
use crate::*;

View file

@ -1,7 +1,7 @@
use relm4::prelude::*;
use gtk::prelude::*;
use anime_launcher_sdk::genshin::config::schema::prelude::LauncherBehavior;
use anime_launcher_sdk::zzz::config::schema::prelude::LauncherBehavior;
use crate::*;
@ -22,7 +22,7 @@ pub fn launch(sender: ComponentSender<App>) {
}
std::thread::spawn(move || {
if let Err(err) = anime_launcher_sdk::genshin::game::run() {
if let Err(err) = anime_launcher_sdk::zzz::game::run() {
tracing::error!("Failed to launch game: {err}");
sender.input(AppMsg::Toast {

View file

@ -20,12 +20,12 @@ 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::zzz::config::Config;
use anime_launcher_sdk::genshin::config::schema::launcher::LauncherStyle;
use anime_launcher_sdk::zzz::config::schema::launcher::LauncherStyle;
use anime_launcher_sdk::genshin::states::*;
use anime_launcher_sdk::genshin::consts::*;
use anime_launcher_sdk::zzz::states::*;
use anime_launcher_sdk::zzz::consts::*;
use crate::*;
use crate::ui::components::*;
@ -39,7 +39,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");
@ -118,10 +117,6 @@ impl SimpleComponent for App {
&tr!("debug-file") => DebugFile,
},
section! {
&tr!("wish-url") => WishUrl
},
section! {
&tr!("about") => About
}
@ -306,12 +301,8 @@ impl SimpleComponent for App {
},
"size" = match model.state.as_ref() {
Some(LauncherState::PredownloadAvailable { game, voices }) => {
let mut size = game.downloaded_size().unwrap_or(0);
for voice in voices {
size += voice.downloaded_size().unwrap_or(0);
}
Some(LauncherState::PredownloadAvailable { game }) => {
let size = game.downloaded_size().unwrap_or(0);
prettify_bytes(size)
}
@ -325,26 +316,14 @@ 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 mut downloaded = temp.join(game.file_name().unwrap()).metadata()
let downloaded = temp.join(game.file_name().unwrap()).metadata()
.map(|metadata| Some(metadata.len()) == game.downloaded_size())
.unwrap_or(false);
if downloaded {
for voice in voices {
downloaded = !temp.join(voice.file_name().unwrap()).metadata()
.map(|metadata| Some(metadata.len()) == voice.downloaded_size())
.unwrap_or(false);
if downloaded {
break;
}
}
}
!downloaded
}
@ -353,26 +332,14 @@ 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 mut downloaded = temp.join(game.file_name().unwrap()).metadata()
let downloaded = temp.join(game.file_name().unwrap()).metadata()
.map(|metadata| Some(metadata.len()) == game.downloaded_size())
.unwrap_or(false);
if downloaded {
for voice in voices {
downloaded = !temp.join(voice.file_name().unwrap()).metadata()
.map(|metadata| Some(metadata.len()) == voice.downloaded_size())
.unwrap_or(false);
if downloaded {
break;
}
}
}
if downloaded {
&["success", "circular"]
} else {
@ -525,7 +492,7 @@ impl SimpleComponent for App {
let result = std::process::Command::new("pkill")
.arg("-f") // full text search
.arg("-i") // case-insensitive
.arg("GenshinImpact|YuanShen|fpsunlock\\.exe")
.arg("ZenlessZoneZero")
.spawn();
if let Err(err) = result {
@ -727,84 +694,6 @@ impl SimpleComponent for App {
}
})));
group.add_action::<WishUrl>(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");
// Find newest cache folder
let mut web_cache_id = None;
if let Ok(entries) = web_cache.read_dir() {
for entry in entries.flatten() {
if entry.path().is_dir() &&
entry.file_name().to_string_lossy().trim_matches(|c| "0123456789.".contains(c)).is_empty() &&
Some(entry.file_name()) > web_cache_id
{
web_cache_id = Some(entry.file_name());
}
}
}
if let Some(web_cache_id) = web_cache_id {
let web_cache = web_cache
.join(web_cache_id)
.join("Cache/Cache_Data/data_2");
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-v3/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())
});
}
}
}
else {
tracing::error!("Couldn't find wishes URL: cache file doesn't exist");
sender.input(AppMsg::Toast {
title: tr!("wish-url-search-failed"),
description: None
});
}
}));
})));
group.add_action::<About>(RelmAction::new_stateless(move |_| {
about_dialog_broker.send(AboutDialogMsg::Show);
}));
@ -944,12 +833,6 @@ impl SimpleComponent for App {
StateUpdating::Game => {
sender.input(AppMsg::SetLoadingStatus(Some(Some(tr!("loading-launcher-state--game")))));
}
StateUpdating::Voice(locale) => {
sender.input(AppMsg::SetLoadingStatus(Some(Some(tr!("loading-launcher-state--voice", {
"locale" = locale.to_name()
})))));
}
}
}
});
@ -1028,7 +911,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;
@ -1037,26 +920,18 @@ impl SimpleComponent for App {
progress_bar_input.send(ProgressBarMsg::UpdateCaption(Some(tr!("downloading"))));
let mut diffs: Vec<VersionDiff> = vec![game];
diffs.append(&mut voices);
std::thread::spawn(move || {
for mut diff in diffs {
let result = diff.download_to(&tmp, clone!(@strong progress_bar_input => move |curr, total| {
progress_bar_input.send(ProgressBarMsg::UpdateProgress(curr, total));
}));
let result = game.download_to(&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));

View file

@ -19,18 +19,8 @@ pub fn repair_game(sender: ComponentSender<App>, progress_bar_input: Sender<Prog
std::thread::spawn(move || {
match repairer::try_get_integrity_files(config.launcher.edition, None) {
Ok(mut files) => {
// Add voiceovers files
Ok(files) => {
let game_path = config.game.path.for_edition(config.launcher.edition).to_path_buf();
let game = Game::new(&game_path, config.launcher.edition);
if let Ok(voiceovers) = game.get_voice_packages() {
for package in voiceovers {
if let Ok(mut voiceover_files) = repairer::try_get_voice_integrity_files(config.launcher.edition, package.locale(), None) {
files.append(&mut voiceover_files);
}
}
}
progress_bar_input.send(ProgressBarMsg::UpdateProgress(0, 0));

View file

@ -4,7 +4,7 @@ use relm4::factory::*;
use adw::prelude::*;
use anime_launcher_sdk::sessions::SessionsExt;
use anime_launcher_sdk::genshin::sessions::Sessions;
use anime_launcher_sdk::zzz::sessions::Sessions;
use crate::*;

View file

@ -9,7 +9,7 @@ use relm4::factory::{
use adw::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use anime_launcher_sdk::zzz::config::Config;
use anime_launcher_sdk::config::schema_blanks::prelude::*;
use anime_launcher_sdk::anime_game_core::installer::downloader::Downloader;
@ -544,87 +544,6 @@ impl SimpleAsyncComponent for EnhancementsApp {
}
}
}
},
add = &adw::PreferencesGroup {
set_title: &tr!("fps-unlocker"),
adw::ComboRow {
set_title: &tr!("enabled"),
set_subtitle: &tr!("fps-unlocker-description"),
#[wrap(Some)]
set_model = &gtk::StringList::new(&[
"90",
"120",
"144",
"165",
"180",
"200",
"240",
&tr!("custom")
]),
set_selected: match Fps::from_num(CONFIG.game.enhancements.fps_unlocker.config.fps) {
Fps::Ninety => 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 = &gtk::Switch {
set_valign: gtk::Align::Center,
set_active: 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.is_active();
Config::update(config);
}
}
}
}
},
adw::ActionRow {
set_title: &tr!("fps-unlocker-interval"),
set_subtitle: &tr!("fps-unlocker-interval-description"),
add_suffix = &gtk::SpinButton {
set_valign: gtk::Align::Center,
set_adjustment: &gtk::Adjustment::new(1.0, 1000.0, 60000.0, 1000.0, 1.0, 0.0),
set_value: CONFIG.game.enhancements.fps_unlocker.config.interval as f64,
connect_changed => |row| {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.game.enhancements.fps_unlocker.config.interval = row.value() as u64;
Config::update(config);
}
}
}
}
},
}
},

View file

@ -2,7 +2,7 @@ use relm4::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use anime_launcher_sdk::zzz::config::Config;
use anime_launcher_sdk::config::schema_blanks::prelude::*;

View file

@ -1,22 +1,16 @@
use relm4::prelude::*;
use relm4::factory::{
AsyncFactoryVecDeque,
AsyncFactoryComponent,
AsyncFactorySender
};
use gtk::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::wincompatlib::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use anime_launcher_sdk::genshin::config::schema::prelude::*;
use anime_launcher_sdk::zzz::config::Config;
use anime_launcher_sdk::zzz::config::schema::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::consts::GameEdition;
use anime_launcher_sdk::genshin::env_emulation::Environment;
use anime_launcher_sdk::anime_game_core::zzz::consts::GameEdition;
use anime_launcher_sdk::zzz::env_emulation::Environment;
pub mod components;
@ -28,81 +22,7 @@ use crate::*;
use super::main::PreferencesAppMsg;
#[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 ParentWidget = adw::ExpanderRow;
view! {
root = adw::ActionRow {
set_title: &tr!(&self.locale.to_name().to_ascii_lowercase()),
add_suffix = &gtk::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 = &gtk::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()));
}
}
}
}
async fn init_model(
init: Self::Init,
_index: &DynamicIndex,
_sender: AsyncFactorySender<Self>,
) -> Self {
Self {
locale: init.0,
installed: init.1,
sensitive: true
}
}
async fn update(&mut self, msg: Self::Input, sender: AsyncFactorySender<Self>) {
self.installed = !self.installed;
sender.output(msg)
.unwrap();
}
}
pub struct GeneralApp {
voice_packages: AsyncFactoryVecDeque<VoicePackageComponent>,
migrate_installation: Controller<MigrateInstallationApp>,
components_page: AsyncController<ComponentsPage>,
@ -117,13 +37,6 @@ pub enum GeneralAppMsg {
/// was retrieved from the API
SetGameDiff(Option<VersionDiff>),
// 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),
UpdateDownloadedWine,
UpdateDownloadedDxvk,
@ -330,12 +243,6 @@ impl SimpleAsyncComponent for GeneralApp {
}
},
#[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,
@ -538,11 +445,7 @@ impl SimpleAsyncComponent for GeneralApp {
) -> AsyncComponentParts<Self> {
tracing::info!("Initializing general settings");
let mut model = Self {
voice_packages: AsyncFactoryVecDeque::builder()
.launch_default()
.forward(sender.input_sender(), std::convert::identity),
let model = Self {
migrate_installation: MigrateInstallationApp::builder()
.launch(())
.detach(),
@ -556,14 +459,6 @@ impl SimpleAsyncComponent for GeneralApp {
languages: SUPPORTED_LANGUAGES.iter().map(|lang| tr!(format_lang(lang).as_str())).collect()
};
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 components_page = model.components_page.widget();
let widgets = view_output!();
@ -579,63 +474,6 @@ impl SimpleAsyncComponent for GeneralApp {
self.game_diff = diff;
}
#[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, config.launcher.edition).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::UpdateDownloadedWine => {
self.components_page.sender()
.send(ComponentsPageMsg::UpdateDownloadedWine)

View file

@ -3,11 +3,11 @@ use relm4::prelude::*;
use gtk::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
use anime_launcher_sdk::anime_game_core::zzz::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::zzz::config::Config;
use anime_launcher_sdk::zzz::config::schema::launcher::LauncherStyle;
use crate::tr;