Made some progress on adding game/voiceovers downloading

This commit is contained in:
Observer KRypt0n_ 2022-07-17 16:59:57 +02:00
parent a4df021a2d
commit 9d5b3b27ed
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
3 changed files with 114 additions and 32 deletions

View file

@ -38,7 +38,7 @@ impl Default for LauncherState {
}
impl LauncherState {
pub fn get(status_page: Option<adw::StatusPage>) -> std::io::Result<Self> {
pub fn get(status_page: Option<&adw::StatusPage>) -> std::io::Result<Self> {
let config = config::get()?;
let game = Game::new(&config.game.path);

View file

@ -7,11 +7,14 @@ use gtk4::glib::clone;
use std::rc::Rc;
use std::cell::Cell;
use anime_game_core::prelude::*;
use crate::ui::*;
use super::preferences::PreferencesStack;
use super::traits::toast_error::ToastError;
use crate::lib::config;
use crate::lib::game;
use crate::lib::tasks;
use crate::lib::launcher::states::LauncherState;
@ -80,7 +83,7 @@ pub enum Actions {
OpenPreferencesPage,
PreferencesGoBack,
PerformButtonEvent,
LaunchGame,
DownloadDiff(Rc<VersionDiff>),
ShowProgressBar,
UpdateProgress { fraction: Rc<f64>, title: Rc<String> },
HideProgressBar
@ -136,12 +139,12 @@ impl App {
// Load initial launcher state
std::thread::spawn(clone!(@strong result => move || {
match LauncherState::get(Some(result.widgets.status_page.clone())) {
match LauncherState::get(Some(&result.widgets.status_page)) {
Ok(state) => {
result.set_state(state);
result.widgets.status_page.set_visible(false);
result.widgets.launcher_content.set_visible(true);
result.widgets.status_page.hide();
result.widgets.launcher_content.show();
},
Err(err) => {
glib::MainContext::default().invoke(move || {
@ -207,28 +210,111 @@ impl App {
match state {
LauncherState::Launch => {
this.update(Actions::LaunchGame);
// Display toast message if the game is failed to run
if let Err(err) = game::run(false) {
this.toast_error("Failed to run game", err);
}
},
LauncherState::PatchAvailable(_) => todo!(),
LauncherState::VoiceUpdateAvailable(_) => todo!(),
LauncherState::VoiceOutdated(_) => todo!(),
LauncherState::VoiceNotInstalled(_) => todo!(),
LauncherState::GameUpdateAvailable(_) => todo!(),
LauncherState::GameOutdated(_) => todo!(),
LauncherState::GameNotInstalled(_) => todo!()
LauncherState::VoiceUpdateAvailable(diff) |
LauncherState::VoiceNotInstalled(diff) |
LauncherState::GameUpdateAvailable(diff) |
LauncherState::GameNotInstalled(diff) => {
this.update(Actions::DownloadDiff(Rc::new(diff)));
},
LauncherState::GameOutdated(_) => (),
LauncherState::VoiceOutdated(_) => ()
}
}
Actions::DownloadDiff(diff) => {
match config::get() {
Ok(config) => {
fn to_gb(bytes: u64) -> f64 {
(bytes as f64 / 1024.0 / 1024.0 / 1024.0 * 100.0).ceil() / 100.0
}
Actions::LaunchGame => {
// Display toast message if the game is failed to run
if let Err(err) = game::run(false) {
this.toast_error("Failed to run game", err);
let diff = (*diff).clone();
std::thread::spawn(clone!(@strong this => move || {
diff.install_to(config.game.path, clone!(@strong this => move |state| {
match state {
InstallerUpdate::DownloadingStarted(_) => {
this.update(Actions::ShowProgressBar);
this.update(Actions::UpdateProgress {
fraction: Rc::new(0.0),
title: Rc::new(String::from("Downloading..."))
});
}
InstallerUpdate::DownloadingProgress(curr, total) => {
// To reduce amount of action requests
if curr % 10000 < 200 {
let progress = curr as f64 / total as f64;
this.update(Actions::UpdateProgress {
fraction: Rc::new(progress),
title: Rc::new(format!(
"Downloading: {:.2}% ({} of {} GB)",
progress * 100.0,
to_gb(curr),
to_gb(total)
))
});
}
}
InstallerUpdate::UnpackingStarted(_) => {
this.update(Actions::UpdateProgress {
fraction: Rc::new(0.0),
title: Rc::new(String::from("Unpacking..."))
});
}
InstallerUpdate::UnpackingProgress(curr, total) => {
let progress = curr as f64 / total as f64;
this.update(Actions::UpdateProgress {
fraction: Rc::new(progress),
title: Rc::new(format!(
"Unpacking: {:.2}% ({} of {} GB)",
progress * 100.0,
to_gb(curr),
to_gb(total)
))
});
}
InstallerUpdate::DownloadingFinished => (),
InstallerUpdate::UnpackingFinished => {
this.update(Actions::HideProgressBar);
}
InstallerUpdate::DownloadingError(err) => this.toast_error("Failed to download game", err),
InstallerUpdate::UnpackingError => this.toast_error("Failed to unpack game", "?")
}
})).unwrap();
}));
},
Err(err) => {
glib::MainContext::default().invoke(clone!(@strong this => move || {
this.toast_error("Failed to load config", err);
}));
}
}
}
Actions::ShowProgressBar => {
this.widgets.launch_game_group.set_visible(false);
this.widgets.progress_bar_group.set_visible(true);
this.widgets.progress_bar.set_text(None);
this.widgets.progress_bar.set_fraction(0.0);
this.widgets.launch_game_group.hide();
this.widgets.progress_bar_group.show();
}
Actions::UpdateProgress { fraction, title } => {
@ -237,8 +323,8 @@ impl App {
}
Actions::HideProgressBar => {
this.widgets.launch_game_group.set_visible(true);
this.widgets.progress_bar_group.set_visible(false);
this.widgets.launch_game_group.show();
this.widgets.progress_bar_group.hide();
}
}
@ -281,24 +367,22 @@ impl App {
self.widgets.launch_game.set_label("Apply patch");
}
LauncherState::GameUpdateAvailable(_) => {
self.widgets.launch_game.set_label("Update");
}
LauncherState::GameUpdateAvailable(_) |
LauncherState::VoiceUpdateAvailable(_) => {
self.widgets.launch_game.set_label("Update");
}
LauncherState::GameNotInstalled(_) => {
self.widgets.launch_game.set_label("Download");
}
LauncherState::GameNotInstalled(_) |
LauncherState::VoiceNotInstalled(_) => {
self.widgets.launch_game.set_label("Download");
}
LauncherState::VoiceOutdated(_) => todo!(),
LauncherState::GameOutdated(_) => todo!()
LauncherState::VoiceOutdated(_) |
LauncherState::GameOutdated(_) => {
self.widgets.launch_game.set_label("Update");
self.widgets.launch_game.set_tooltip_text(Some("Version is too outdated and can't be updated"));
self.widgets.launch_game.set_sensitive(false);
}
}
let mut values = self.values.take();

View file

@ -62,8 +62,6 @@ impl PreferencesStack {
/// Update page info before opening it
///
/// Being called from the `MainApp` struct
///
/// TODO: do it asynchronously. The problem is that I somehow need to handle this function's error to display it as a toast
pub fn update(&self) -> Result<(), Error> {
self.status_page.set_visible(true);
self.status_page.set_description(None);