feat: made migrate installation button work

This commit is contained in:
Observer KRypt0n_ 2023-04-09 17:06:05 +02:00
parent 285195954e
commit 567df16610
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
4 changed files with 153 additions and 35 deletions

View file

@ -42,6 +42,7 @@ components-index = Components index
patch-folder = Patch folder
temp-folder = Temp folder
migrate = Migrate
select-voice-packages = Select voice packages

View file

@ -5,14 +5,19 @@ use adw::prelude::*;
use anime_launcher_sdk::config;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use crate::*;
use crate::i18n::*;
use super::main::*;
use crate::ui::components::progress_bar::*;
pub struct DefaultPathsApp {
progress_bar: AsyncController<ProgressBar>,
show_additional: bool,
migrate_installation: bool,
show_progress: bool,
launcher: PathBuf,
runners: PathBuf,
@ -50,7 +55,8 @@ pub enum DefaultPathsAppMsg {
#[relm4::component(async, pub)]
impl SimpleAsyncComponent for DefaultPathsApp {
type Init = ();
/// If `true`, then use migrate installation mode
type Init = bool;
type Input = DefaultPathsAppMsg;
type Output = FirstRunAppMsg;
@ -72,6 +78,9 @@ impl SimpleAsyncComponent for DefaultPathsApp {
set_valign: gtk::Align::End,
set_vexpand: true,
#[watch]
set_sensitive: !model.show_progress,
adw::ActionRow {
set_title: &tr("launcher-folder"),
set_icon_name: Some("folder-symbolic"),
@ -107,6 +116,9 @@ impl SimpleAsyncComponent for DefaultPathsApp {
#[watch]
set_visible: model.show_additional,
#[watch]
set_sensitive: !model.show_progress,
adw::ActionRow {
set_title: &tr("runners-folder"),
set_icon_name: Some("folder-symbolic"),
@ -211,36 +223,75 @@ impl SimpleAsyncComponent for DefaultPathsApp {
set_valign: gtk::Align::Center,
set_vexpand: true,
#[watch]
set_visible: !model.show_progress,
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_halign: gtk::Align::Center,
set_spacing: 8,
gtk::Button {
set_label: &tr("continue"),
set_label: &if model.migrate_installation {
tr("migrate")
} else {
tr("continue")
},
set_css_classes: &["suggested-action", "pill"],
connect_clicked => DefaultPathsAppMsg::Continue
},
gtk::Button {
set_label: &tr("exit"),
set_label: &if model.migrate_installation {
tr("close")
} else {
tr("exit")
},
add_css_class: "pill",
connect_clicked => DefaultPathsAppMsg::Exit
}
}
},
add = &adw::PreferencesGroup {
set_valign: gtk::Align::Center,
set_vexpand: true,
#[watch]
set_visible: model.show_progress,
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_halign: gtk::Align::Center,
append = model.progress_bar.widget(),
}
}
}
}
async fn init(
_init: Self::Init,
init: Self::Init,
root: Self::Root,
_sender: AsyncComponentSender<Self>,
) -> AsyncComponentParts<Self> {
let model = Self {
progress_bar: ProgressBar::builder()
.launch(ProgressBarInit {
caption: None,
display_progress: true,
display_fraction: false,
visible: false
})
.detach(),
show_additional: false,
migrate_installation: init,
show_progress: false,
launcher: LAUNCHER_FOLDER.to_path_buf(),
runners: CONFIG.game.wine.builds.clone(),
@ -256,6 +307,9 @@ impl SimpleAsyncComponent for DefaultPathsApp {
temp: CONFIG.launcher.temp.clone().unwrap_or(std::env::temp_dir())
};
// Set progress bar width
model.progress_bar.widget().set_width_request(400);
let widgets = view_output!();
AsyncComponentParts { model, widgets }
@ -303,17 +357,95 @@ impl SimpleAsyncComponent for DefaultPathsApp {
#[allow(unused_must_use)]
DefaultPathsAppMsg::Continue => {
match self.update_config() {
Ok(_) => sender.output(Self::Output::ScrollToSelectVoiceovers),
let old_config = config::get().unwrap_or_else(|_| CONFIG.clone());
Err(err) => sender.output(Self::Output::Toast {
title: tr("config-update-error"),
description: Some(err.to_string())
})
};
match self.update_config() {
Ok(_) => {
if self.migrate_installation {
self.progress_bar.sender().send(ProgressBarMsg::SetVisible(true));
self.show_progress = true;
let folders = [
(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.components.path, &self.components),
(old_config.patch.path, &self.patch),
(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(
from.to_str().map(|str| str.to_string()).unwrap_or_else(|| format!("{:?}", from))
)));
if &from != to && from.exists() {
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));
}
// Restart the app
std::process::Command::new(std::env::current_exe().unwrap()).spawn().unwrap();
relm4::main_application().quit();
}
else {
sender.output(Self::Output::ScrollToSelectVoiceovers);
}
}
Err(err) => {
sender.output(Self::Output::Toast {
title: tr("config-update-error"),
description: Some(err.to_string())
});
}
}
}
DefaultPathsAppMsg::Exit => relm4::main_application().quit()
DefaultPathsAppMsg::Exit => {
if self.migrate_installation {
// TODO: this shit should return message to general preferences component somehow to close MigrateInstallation window
todo!();
}
else {
relm4::main_application().quit();
}
}
}
}
}

View file

@ -145,7 +145,7 @@ impl SimpleComponent for FirstRunApp {
.forward(sender.input_sender(), std::convert::identity),
default_paths: DefaultPathsApp::builder()
.launch(())
.launch(false)
.forward(sender.input_sender(), std::convert::identity),
select_voiceovers: SelectVoiceoversApp::builder()

View file

@ -2,9 +2,6 @@ use relm4::prelude::*;
use relm4::component::*;
use gtk::prelude::*;
use adw::prelude::*;
use crate::*;
use super::first_run::default_paths::DefaultPathsApp;
@ -12,21 +9,17 @@ pub struct MigrateInstallationApp {
default_paths: AsyncController<DefaultPathsApp>,
}
#[derive(Debug)]
pub enum MigrateInstallationAppMsg {
Migrate
}
#[relm4::component(pub)]
impl SimpleComponent for MigrateInstallationApp {
type Init = ();
type Input = MigrateInstallationAppMsg;
type Input = ();
type Output = ();
view! {
adw::Window {
set_default_size: (780, 560),
set_modal: true,
set_hide_on_close: true,
#[watch]
set_title: Some("Migrate installation"),
@ -46,13 +39,13 @@ impl SimpleComponent for MigrateInstallationApp {
fn init(
_init: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
_sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
tracing::info!("Initializing migration window");
let model = Self {
default_paths: DefaultPathsApp::builder()
.launch(())
.launch(true)
.detach()
};
@ -60,12 +53,4 @@ impl SimpleComponent for MigrateInstallationApp {
ComponentParts { model, widgets }
}
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
match msg {
MigrateInstallationAppMsg::Migrate => {
todo!()
}
}
}
}