diff --git a/Cargo.lock b/Cargo.lock index 8e61321..896c865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,8 +40,8 @@ dependencies = [ [[package]] name = "anime-game-core" -version = "1.5.2" -source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.5.2#002bed907fc47c53d18764fb87aec2398413f1a0" +version = "1.6.0" +source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.6.0#e08cef50412928cca426534644142de0fe6a8499" dependencies = [ "anyhow", "bzip2", @@ -86,8 +86,8 @@ dependencies = [ [[package]] name = "anime-launcher-sdk" -version = "0.5.14" -source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=0.5.14#98de4c7d707ed7428257953526625e8f168f7d84" +version = "0.5.15" +source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=0.5.15#5ebd018a5d5bd6fd0e06d0ab9459a7aec53dcd98" dependencies = [ "anime-game-core", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 66ef36a..ebc72a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ glib-build-tools = "0.17" [dependencies.anime-launcher-sdk] git = "https://github.com/an-anime-team/anime-launcher-sdk" -tag = "0.5.14" +tag = "0.5.15" # path = "../anime-launcher-sdk" # ! for dev purposes only diff --git a/README.md b/README.md index 4bc7352..310e945 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ This should be automatically enabled if you're using zh_cn (Chinese) as your sys | Folder | Description | | - | - | -| anime-launcher-sdk | Unified core functionality for the launcher | | src | Rust source code | | assets | App assets folder | | assets/locales | App localizations | diff --git a/assets/locales/de/main.ftl b/assets/locales/de/main.ftl index f58f4fb..e2c9a86 100644 --- a/assets/locales/de/main.ftl +++ b/assets/locales/de/main.ftl @@ -40,12 +40,17 @@ downloading = Lade Herunter unpacking = Entpacken verifying-files = Verifiziere Dateien repairing-files = Repariere Dateien +migrating-folders = Migrating folders +applying-hdiff = Applying hdiff patches +removing-outdated = Removing outdated files components-index-updated = Kompontentenverzeichnis würde aktualisiert launch = Starten +migrate-folders = Migrate folders +migrate-folders-tooltip = Update game folders structure apply-patch = Patch anwenden download-wine = Wine Herunterladen create-prefix = Prefix erstellen diff --git a/assets/locales/en/main.ftl b/assets/locales/en/main.ftl index 8f921d1..f36da46 100644 --- a/assets/locales/en/main.ftl +++ b/assets/locales/en/main.ftl @@ -40,12 +40,17 @@ downloading = Downloading unpacking = Unpacking verifying-files = Verifying files repairing-files = Repairing files +migrating-folders = Migrating folders +applying-hdiff = Applying hdiff patches +removing-outdated = Removing outdated files components-index-updated = Components index was updated launch = Launch +migrate-folders = Migrate folders +migrate-folders-tooltip = Update game folders structure apply-patch = Apply patch download-wine = Download wine create-prefix = Create prefix diff --git a/assets/locales/es/main.ftl b/assets/locales/es/main.ftl index 975fa7f..3510d72 100755 --- a/assets/locales/es/main.ftl +++ b/assets/locales/es/main.ftl @@ -40,12 +40,17 @@ downloading = Descargando unpacking = Descomprimiendo verifying-files = Verificación de archivos repairing-files = Reparación de archivos +migrating-folders = Migrating folders +applying-hdiff = Applying hdiff patches +removing-outdated = Removing outdated files components-index-updated = Se actualizó el índice de componentes launch = Iniciar +migrate-folders = Migrate folders +migrate-folders-tooltip = Update game folders structure apply-patch = Aplicar parche download-wine = Descargar wine create-prefix = Crear prefijo diff --git a/assets/locales/fr/main.ftl b/assets/locales/fr/main.ftl index 2244e86..f473b7d 100644 --- a/assets/locales/fr/main.ftl +++ b/assets/locales/fr/main.ftl @@ -40,12 +40,17 @@ downloading = Téléchargement unpacking = Décompression verifying-files = Vérification des fichiers repairing-files = Réparation des fichiers +migrating-folders = Migrating folders +applying-hdiff = Applying hdiff patches +removing-outdated = Removing outdated files components-index-updated = L'index des composants a été mis à jour launch = Lancer +migrate-folders = Migrate folders +migrate-folders-tooltip = Update game folders structure apply-patch = Appliquer le patch download-wine = Télécharger wine create-prefix = Créer le préfix wine diff --git a/assets/locales/ru/main.ftl b/assets/locales/ru/main.ftl index eea1e75..1cb3861 100644 --- a/assets/locales/ru/main.ftl +++ b/assets/locales/ru/main.ftl @@ -46,12 +46,17 @@ downloading = Загрузка unpacking = Распаковка verifying-files = Проверка файлов repairing-files = Починка файлов +migrating-folders = Перемещение папок +applying-hdiff = Применение патчей hdiff +removing-outdated = Удаление устаревших файлов components-index-updated = Индекс компонентов был обновлен launch = Запустить +migrate-folders = Переместить папки +migrate-folders-tooltip = Обновить структуру файлов игры apply-patch = Применить патч download-wine = Установить Wine create-prefix = Создать префикс diff --git a/assets/locales/tr/main.ftl b/assets/locales/tr/main.ftl index 67c0e45..0dd70c6 100644 --- a/assets/locales/tr/main.ftl +++ b/assets/locales/tr/main.ftl @@ -40,12 +40,17 @@ downloading = İndiriliyor unpacking = Paketten çıkartılıyor verifying-files = Dosyalar Doğrulanıyor repairing-files = Dosyalar tamir ediliyor +migrating-folders = Migrating folders +applying-hdiff = Applying hdiff patches +removing-outdated = Removing outdated files components-index-updated = Components index was updated launch = Çalıştır +migrate-folders = Migrate folders +migrate-folders-tooltip = Update game folders structure apply-patch = Yamayı uygula download-wine = Wine indir create-prefix = Prefix oluştur diff --git a/assets/locales/zh-cn/main.ftl b/assets/locales/zh-cn/main.ftl index 4d45fb2..38ea420 100644 --- a/assets/locales/zh-cn/main.ftl +++ b/assets/locales/zh-cn/main.ftl @@ -40,12 +40,17 @@ downloading = 正在下载 unpacking = 正在解压缩 verifying-files = 正在检验文件 repairing-files = 正在修复文件 +migrating-folders = Migrating folders +applying-hdiff = Applying hdiff patches +removing-outdated = Removing outdated files components-index-updated = 组件索引已更新 launch = 启动 +migrate-folders = Migrate folders +migrate-folders-tooltip = Update game folders structure apply-patch = 安装补丁 download-wine = 下载 Wine create-prefix = 创建 Wine prefix diff --git a/src/main.rs b/src/main.rs index 70c2f77..f17433f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,9 +12,10 @@ use tracing_subscriber::filter::*; use std::path::PathBuf; +pub mod move_folder; pub mod i18n; -pub mod ui; pub mod background; +pub mod ui; use ui::main::*; use ui::first_run::main::*; diff --git a/src/move_folder.rs b/src/move_folder.rs new file mode 100644 index 0000000..c975607 --- /dev/null +++ b/src/move_folder.rs @@ -0,0 +1,26 @@ +use std::path::Path; + +pub fn move_folder(from: &Path, to: &Path) -> std::io::Result<()> { + if !to.exists() { + std::fs::create_dir_all(to)?; + } + + for entry in from.read_dir()?.flatten() { + let to_path = to.join(entry.file_name()); + + if entry.metadata()?.is_dir() { + move_folder(&entry.path(), &to_path)?; + } + + else if entry.metadata()?.is_file() { + std::fs::copy(entry.path(), to_path)?; + std::fs::remove_file(entry.path())?; + } + + // TODO: symlinks? + } + + std::fs::remove_dir_all(from)?; + + Ok(()) +} diff --git a/src/ui/components/progress_bar.rs b/src/ui/components/progress_bar.rs index 2d86ddf..681e028 100644 --- a/src/ui/components/progress_bar.rs +++ b/src/ui/components/progress_bar.rs @@ -3,8 +3,7 @@ use relm4::component::*; use adw::prelude::*; -use anime_launcher_sdk::anime_game_core::installer::installer::Update as InstallerUpdate; -use anime_launcher_sdk::anime_game_core::prettify_bytes::prettify_bytes; +use anime_launcher_sdk::anime_game_core::prelude::*; use crate::i18n::*; @@ -44,7 +43,7 @@ pub enum ProgressBarMsg { /// (current bytes, total bytes) UpdateProgress(u64, u64), - UpdateFromState(InstallerUpdate), + UpdateFromState(DiffUpdate), SetVisible(bool) } @@ -128,12 +127,36 @@ impl SimpleAsyncComponent for ProgressBar { ProgressBarMsg::UpdateFromState(state) => { match state { - InstallerUpdate::CheckingFreeSpace(_) => self.caption = Some(tr("checking-free-space")), - InstallerUpdate::DownloadingStarted(_) => self.caption = Some(tr("downloading")), - InstallerUpdate::UnpackingStarted(_) => self.caption = Some(tr("unpacking")), + DiffUpdate::InstallerUpdate(InstallerUpdate::CheckingFreeSpace(_)) => self.caption = Some(tr("checking-free-space")), - InstallerUpdate::DownloadingProgress(curr, total) | - InstallerUpdate::UnpackingProgress(curr, total) => { + DiffUpdate::InstallerUpdate(InstallerUpdate::DownloadingStarted(_)) => { + self.caption = Some(tr("downloading")); + + self.display_fraction = true; + } + + DiffUpdate::InstallerUpdate(InstallerUpdate::UnpackingStarted(_)) => { + self.caption = Some(tr("unpacking")); + + self.display_fraction = true; + } + + DiffUpdate::ApplyingHdiffStarted => { + self.caption = Some(tr("applying-hdiff")); + + self.display_fraction = false; + } + + DiffUpdate::RemovingOutdatedStarted => { + self.caption = Some(tr("removing-outdated")); + + self.display_fraction = false; + } + + DiffUpdate::InstallerUpdate(InstallerUpdate::DownloadingProgress(curr, total)) | + DiffUpdate::InstallerUpdate(InstallerUpdate::UnpackingProgress(curr, total)) | + DiffUpdate::ApplyingHdiffProgress(curr, total) | + DiffUpdate::RemovingOutdatedProgress(curr, total) => { self.fraction = curr as f64 / total as f64; self.downloaded = Some(( @@ -142,11 +165,14 @@ impl SimpleAsyncComponent for ProgressBar { )); } - InstallerUpdate::DownloadingFinished => tracing::info!("Downloading finished"), - InstallerUpdate::UnpackingFinished => tracing::info!("Unpacking finished"), + DiffUpdate::InstallerUpdate(InstallerUpdate::DownloadingFinished) => tracing::info!("Downloading finished"), + DiffUpdate::InstallerUpdate(InstallerUpdate::UnpackingFinished) => tracing::info!("Unpacking finished"), - InstallerUpdate::DownloadingError(err) => tracing::error!("Downloading error: {:?}", err), - InstallerUpdate::UnpackingError(err) => tracing::error!("Unpacking error: {:?}", err) + DiffUpdate::ApplyingHdiffFinished => tracing::info!("Applying hdiffs finished"), + DiffUpdate::RemovingOutdatedFinished => tracing::info!("Removing outdated files finished"), + + DiffUpdate::InstallerUpdate(InstallerUpdate::DownloadingError(err)) => tracing::error!("Downloading error: {:?}", err), + DiffUpdate::InstallerUpdate(InstallerUpdate::UnpackingError(err)) => tracing::error!("Unpacking error: {:?}", err) } } diff --git a/src/ui/components/version.rs b/src/ui/components/version.rs index 6e7e9f1..5f10ca3 100644 --- a/src/ui/components/version.rs +++ b/src/ui/components/version.rs @@ -9,7 +9,7 @@ use gtk::glib::clone; use super::progress_bar::ProgressBarMsg; use anime_launcher_sdk::config; -use anime_launcher_sdk::anime_game_core::installer::installer::*; +use anime_launcher_sdk::anime_game_core::prelude::*; use std::path::PathBuf; @@ -162,12 +162,12 @@ impl SimpleAsyncComponent for ComponentVersion { installer.install(download_folder, move |state| { match &state { - Update::UnpackingFinished | - Update::DownloadingError(_) | - Update::UnpackingError(_) => { + InstallerUpdate::UnpackingFinished | + InstallerUpdate::DownloadingError(_) | + InstallerUpdate::UnpackingError(_) => { progress_bar_sender.send(ProgressBarMsg::SetVisible(false)); - if let Update::UnpackingFinished = &state { + if let InstallerUpdate::UnpackingFinished = &state { sender.input(AppMsg::SetState(VersionState::Downloaded)); sender.output(super::group::AppMsg::CallOnDownloaded); } @@ -180,7 +180,7 @@ impl SimpleAsyncComponent for ComponentVersion { _ => () } - progress_bar_sender.send(ProgressBarMsg::UpdateFromState(state)); + progress_bar_sender.send(ProgressBarMsg::UpdateFromState(DiffUpdate::InstallerUpdate(state))); }); })); } diff --git a/src/ui/first_run/default_paths.rs b/src/ui/first_run/default_paths.rs index d20fb29..ca78482 100644 --- a/src/ui/first_run/default_paths.rs +++ b/src/ui/first_run/default_paths.rs @@ -5,7 +5,7 @@ use adw::prelude::*; use anime_launcher_sdk::config; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use crate::*; use crate::i18n::*; @@ -381,30 +381,6 @@ impl SimpleAsyncComponent for DefaultPathsApp { (old_config.game.enhancements.fps_unlocker.path, &self.fps_unlocker) ]; - fn move_folder(from: &Path, to: &Path) -> std::io::Result<()> { - if !to.exists() { - std::fs::create_dir_all(to); - } - - for entry in from.read_dir()?.flatten() { - let to_path = to.join(entry.file_name()); - - if entry.metadata()?.is_dir() { - move_folder(&entry.path(), &to_path)?; - } - - else if entry.metadata()?.is_file() { - std::fs::copy(entry.path(), &to_path); - } - - // TODO: symlinks? - } - - std::fs::remove_dir_all(from)?; - - Ok(()) - } - #[allow(clippy::expect_fun_call)] for (i, (from, to)) in folders.iter().enumerate() { self.progress_bar.sender().send(ProgressBarMsg::UpdateCaption(Some( @@ -412,7 +388,7 @@ impl SimpleAsyncComponent for DefaultPathsApp { ))); if &from != to && from.exists() { - move_folder(from, to).expect(&format!("Failed to move folder: {:?} -> {:?}", from, to)); + move_folder::move_folder(from, to).expect(&format!("Failed to move folder: {:?} -> {:?}", from, to)); } self.progress_bar.sender().send(ProgressBarMsg::UpdateProgress(i as u64 + 1, folders.len() as u64)); diff --git a/src/ui/first_run/download_components.rs b/src/ui/first_run/download_components.rs index 6d18701..987e6e6 100644 --- a/src/ui/first_run/download_components.rs +++ b/src/ui/first_run/download_components.rs @@ -3,9 +3,9 @@ use relm4::component::*; use adw::prelude::*; +use anime_launcher_sdk::anime_game_core::prelude::*; use anime_launcher_sdk::components::*; use anime_launcher_sdk::components::wine::WincompatlibWine; -use anime_launcher_sdk::anime_game_core::installer::prelude::*; use anime_launcher_sdk::config; use anime_launcher_sdk::wincompatlib::prelude::*; @@ -421,7 +421,7 @@ impl SimpleAsyncComponent for DownloadComponentsApp { _ => () } - progress_bar_input.send(ProgressBarMsg::UpdateFromState(update)); + progress_bar_input.send(ProgressBarMsg::UpdateFromState(DiffUpdate::InstallerUpdate(update))); }); } @@ -532,7 +532,7 @@ impl SimpleAsyncComponent for DownloadComponentsApp { _ => () } - progress_bar_input.send(ProgressBarMsg::UpdateFromState(update)); + progress_bar_input.send(ProgressBarMsg::UpdateFromState(DiffUpdate::InstallerUpdate(update))); }); } diff --git a/src/ui/main/download_diff.rs b/src/ui/main/download_diff.rs index 48a778a..c35d4d3 100644 --- a/src/ui/main/download_diff.rs +++ b/src/ui/main/download_diff.rs @@ -20,10 +20,9 @@ pub fn download_diff(sender: ComponentSender, progress_bar_input: Sender move |state| { match &state { - InstallerUpdate::DownloadingError(err) => { + DiffUpdate::InstallerUpdate(InstallerUpdate::DownloadingError(err)) => { tracing::error!("Downloading failed: {err}"); sender.input(AppMsg::Toast { @@ -32,7 +31,7 @@ pub fn download_diff(sender: ComponentSender, progress_bar_input: Sender { + DiffUpdate::InstallerUpdate(InstallerUpdate::UnpackingError(err)) => { tracing::error!("Unpacking failed: {err}"); sender.input(AppMsg::Toast { @@ -44,7 +43,9 @@ pub fn download_diff(sender: ComponentSender, progress_bar_input: Sender () } - progress_bar_input.send(ProgressBarMsg::UpdateFromState(state)); + #[allow(unused_must_use)] { + progress_bar_input.send(ProgressBarMsg::UpdateFromState(state)); + } })); let mut perform_on_download_needed = true; diff --git a/src/ui/main/download_wine.rs b/src/ui/main/download_wine.rs index d813764..d33ea3c 100644 --- a/src/ui/main/download_wine.rs +++ b/src/ui/main/download_wine.rs @@ -55,7 +55,6 @@ pub fn download_wine(sender: ComponentSender, progress_bar_input: Sender move || { - #[allow(unused_must_use)] installer.install(&config.game.wine.builds, clone!(@strong sender => move |state| { match &state { InstallerUpdate::DownloadingError(err) => { @@ -79,7 +78,9 @@ pub fn download_wine(sender: ComponentSender, progress_bar_input: Sender () } - progress_bar_input.send(ProgressBarMsg::UpdateFromState(state)); + #[allow(unused_must_use)] { + progress_bar_input.send(ProgressBarMsg::UpdateFromState(DiffUpdate::InstallerUpdate(state))); + } })); config.game.wine.selected = Some(wine.name.clone()); diff --git a/src/ui/main/migrate_folder.rs b/src/ui/main/migrate_folder.rs new file mode 100644 index 0000000..74d6b61 --- /dev/null +++ b/src/ui/main/migrate_folder.rs @@ -0,0 +1,25 @@ +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 830dcc1..0ed377d 100644 --- a/src/ui/main/mod.rs +++ b/src/ui/main/mod.rs @@ -15,6 +15,7 @@ mod apply_patch; mod download_wine; mod create_prefix; mod download_diff; +mod migrate_folder; mod launch; use anime_launcher_sdk::config::launcher::LauncherStyle; @@ -371,18 +372,19 @@ impl SimpleComponent for App { gtk::Button { #[watch] set_label: &match model.state { - Some(LauncherState::Launch) => tr("launch"), - Some(LauncherState::PredownloadAvailable { .. }) => tr("launch"), - 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::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"), None => String::from("...") }, @@ -432,6 +434,8 @@ impl SimpleComponent for App { Some(LauncherState::GameOutdated { .. }) | Some(LauncherState::VoiceOutdated(_)) => 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 { PatchStatus::NotAvailable => tr("main-window--patch-unavailable-tooltip"), @@ -1006,6 +1010,9 @@ impl SimpleComponent for App { 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()), @@ -1016,7 +1023,8 @@ impl SimpleComponent for App { 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::GameNotInstalled(diff) => + download_diff::download_diff(sender, self.progress_bar.sender().to_owned(), diff.to_owned()), LauncherState::VoiceOutdated(_) | LauncherState::GameOutdated(_) => ()