mirror of
https://github.com/an-anime-team/sleepy-launcher.git
synced 2025-02-18 02:39:47 +03:00
Added foundation of the launcher states functionality
This commit is contained in:
parent
82a6e01200
commit
bc5b9d2b45
5 changed files with 205 additions and 45 deletions
|
@ -22,7 +22,16 @@ Adw.ApplicationWindow window {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Adw.PreferencesPage {
|
Adw.StatusPage status_page {
|
||||||
|
icon-name: "image-loading-symbolic";
|
||||||
|
title: "Loading data";
|
||||||
|
|
||||||
|
vexpand: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.PreferencesPage launcher_content {
|
||||||
|
visible: false;
|
||||||
|
|
||||||
Adw.PreferencesGroup {
|
Adw.PreferencesGroup {
|
||||||
Gtk.Image {
|
Gtk.Image {
|
||||||
file: "assets/images/icon.png";
|
file: "assets/images/icon.png";
|
||||||
|
@ -47,19 +56,13 @@ Adw.ApplicationWindow window {
|
||||||
margin-top: 64;
|
margin-top: 64;
|
||||||
spacing: 8;
|
spacing: 8;
|
||||||
|
|
||||||
Adw.SplitButton launch_game {
|
Gtk.Button launch_game {
|
||||||
label: "Launch";
|
label: "Launch";
|
||||||
|
|
||||||
hexpand: false;
|
hexpand: false;
|
||||||
width-request: 200;
|
width-request: 200;
|
||||||
|
|
||||||
styles ["suggested-action"]
|
styles ["suggested-action"]
|
||||||
|
|
||||||
popover: Gtk.Popover {
|
|
||||||
Gtk.Button launch_game_debug {
|
|
||||||
label: "Launch in debug mode";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Gtk.Button open_preferences {
|
Gtk.Button open_preferences {
|
||||||
|
|
1
src/lib/launcher/mod.rs
Normal file
1
src/lib/launcher/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod states;
|
89
src/lib/launcher/states.rs
Normal file
89
src/lib/launcher/states.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
use gtk4::{self as gtk, prelude::*};
|
||||||
|
use libadwaita::{self as adw, prelude::*};
|
||||||
|
|
||||||
|
use anime_game_core::prelude::*;
|
||||||
|
|
||||||
|
use crate::lib::config;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum LauncherState {
|
||||||
|
Launch,
|
||||||
|
PatchAvailable(Patch),
|
||||||
|
|
||||||
|
// Always contains `VersionDiff::Diff`
|
||||||
|
VoiceUpdateAvailable(VersionDiff),
|
||||||
|
|
||||||
|
/// Always contains `VersionDiff::Outdated`
|
||||||
|
VoiceOutdated(VersionDiff),
|
||||||
|
|
||||||
|
/// Always contains `VersionDiff::NotInstalled`
|
||||||
|
VoiceNotInstalled(VersionDiff),
|
||||||
|
|
||||||
|
// Always contains `VersionDiff::Diff`
|
||||||
|
GameUpdateAvailable(VersionDiff),
|
||||||
|
|
||||||
|
/// Always contains `VersionDiff::Outdated`
|
||||||
|
GameOutdated(VersionDiff),
|
||||||
|
|
||||||
|
/// Always contains `VersionDiff::NotInstalled`
|
||||||
|
GameNotInstalled(VersionDiff)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LauncherState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Launch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LauncherState {
|
||||||
|
pub fn get(status_page: Option<adw::StatusPage>) -> std::io::Result<Self> {
|
||||||
|
let config = config::get()?;
|
||||||
|
let game = Game::new(&config.game.path);
|
||||||
|
|
||||||
|
if let Some(status_page) = &status_page {
|
||||||
|
status_page.set_description(Some("Updating game info..."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let diff = game.try_get_diff()?;
|
||||||
|
|
||||||
|
Ok(match diff {
|
||||||
|
VersionDiff::Latest(_) => {
|
||||||
|
if let Some(status_page) = &status_page {
|
||||||
|
status_page.set_description(Some("Updating voice info..."));
|
||||||
|
}
|
||||||
|
|
||||||
|
for voice_package in game.get_voice_packages()? {
|
||||||
|
if let Some(status_page) = &status_page {
|
||||||
|
status_page.set_description(Some(format!("Updating voice info ({})...", voice_package.locale().to_name()).as_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let diff = voice_package.try_get_diff()?;
|
||||||
|
|
||||||
|
match diff {
|
||||||
|
VersionDiff::Latest(_) => continue,
|
||||||
|
VersionDiff::Diff { .. } => return Ok(Self::VoiceUpdateAvailable(diff)),
|
||||||
|
VersionDiff::Outdated { .. } => return Ok(Self::VoiceOutdated(diff)),
|
||||||
|
VersionDiff::NotInstalled { .. } => return Ok(Self::VoiceNotInstalled(diff))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(status_page) = &status_page {
|
||||||
|
status_page.set_description(Some("Updating patch info..."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let patch = Patch::try_fetch(config.patch.servers.clone())?;
|
||||||
|
|
||||||
|
if patch.is_applied(&config.game.path)? {
|
||||||
|
Self::Launch
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
Self::PatchAvailable(patch)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
VersionDiff::Diff { .. } => Self::GameUpdateAvailable(diff),
|
||||||
|
VersionDiff::Outdated { .. } => Self::GameOutdated(diff),
|
||||||
|
VersionDiff::NotInstalled { .. } => Self::GameNotInstalled(diff)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,3 +4,4 @@ pub mod tasks;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
pub mod dxvk;
|
pub mod dxvk;
|
||||||
pub mod wine;
|
pub mod wine;
|
||||||
|
pub mod launcher;
|
||||||
|
|
140
src/ui/main.rs
140
src/ui/main.rs
|
@ -14,6 +14,7 @@ use super::traits::toast_error::ToastError;
|
||||||
|
|
||||||
use crate::lib::game;
|
use crate::lib::game;
|
||||||
use crate::lib::tasks;
|
use crate::lib::tasks;
|
||||||
|
use crate::lib::launcher::states::LauncherState;
|
||||||
|
|
||||||
/// This structure is used to describe widgets used in application
|
/// This structure is used to describe widgets used in application
|
||||||
///
|
///
|
||||||
|
@ -26,9 +27,10 @@ pub struct AppWidgets {
|
||||||
pub toast_overlay: adw::ToastOverlay,
|
pub toast_overlay: adw::ToastOverlay,
|
||||||
|
|
||||||
pub leaflet: adw::Leaflet,
|
pub leaflet: adw::Leaflet,
|
||||||
|
pub status_page: adw::StatusPage,
|
||||||
|
pub launcher_content: adw::PreferencesPage,
|
||||||
|
|
||||||
pub launch_game: adw::SplitButton,
|
pub launch_game: gtk::Button,
|
||||||
pub launch_game_debug: gtk::Button,
|
|
||||||
pub open_preferences: gtk::Button,
|
pub open_preferences: gtk::Button,
|
||||||
|
|
||||||
pub launch_game_group: adw::PreferencesGroup,
|
pub launch_game_group: adw::PreferencesGroup,
|
||||||
|
@ -50,9 +52,10 @@ impl AppWidgets {
|
||||||
toast_overlay: toast_overlay.clone(),
|
toast_overlay: toast_overlay.clone(),
|
||||||
|
|
||||||
leaflet: get_object(&builder, "leaflet")?,
|
leaflet: get_object(&builder, "leaflet")?,
|
||||||
|
status_page: get_object(&builder, "status_page")?,
|
||||||
|
launcher_content: get_object(&builder, "launcher_content")?,
|
||||||
|
|
||||||
launch_game: get_object(&builder, "launch_game")?,
|
launch_game: get_object(&builder, "launch_game")?,
|
||||||
launch_game_debug: get_object(&builder, "launch_game_debug")?,
|
|
||||||
open_preferences: get_object(&builder, "open_preferences")?,
|
open_preferences: get_object(&builder, "open_preferences")?,
|
||||||
|
|
||||||
launch_game_group: get_object(&builder, "launch_game_group")?,
|
launch_game_group: get_object(&builder, "launch_game_group")?,
|
||||||
|
@ -76,7 +79,11 @@ impl AppWidgets {
|
||||||
pub enum Actions {
|
pub enum Actions {
|
||||||
OpenPreferencesPage,
|
OpenPreferencesPage,
|
||||||
PreferencesGoBack,
|
PreferencesGoBack,
|
||||||
LaunchGame
|
PerformButtonEvent,
|
||||||
|
LaunchGame,
|
||||||
|
ShowProgressBar,
|
||||||
|
UpdateProgress { fraction: Rc<f64>, title: Rc<String> },
|
||||||
|
HideProgressBar
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actions {
|
impl Actions {
|
||||||
|
@ -93,7 +100,9 @@ impl Actions {
|
||||||
///
|
///
|
||||||
/// This must implement `Default` trait
|
/// This must implement `Default` trait
|
||||||
#[derive(Debug, Default, glib::Downgrade)]
|
#[derive(Debug, Default, glib::Downgrade)]
|
||||||
pub struct Values;
|
pub struct Values {
|
||||||
|
state: Rc<LauncherState>
|
||||||
|
}
|
||||||
|
|
||||||
/// The main application structure
|
/// The main application structure
|
||||||
///
|
///
|
||||||
|
@ -125,6 +134,19 @@ impl App {
|
||||||
// Bind app to the window
|
// Bind app to the window
|
||||||
result.widgets.window.set_application(Some(app));
|
result.widgets.window.set_application(Some(app));
|
||||||
|
|
||||||
|
// Load initial launcher state
|
||||||
|
std::thread::spawn(clone!(@strong result => move || {
|
||||||
|
match LauncherState::get(Some(result.widgets.status_page.clone())) {
|
||||||
|
Ok(state) => {
|
||||||
|
result.set_state(state);
|
||||||
|
|
||||||
|
result.widgets.status_page.set_visible(false);
|
||||||
|
result.widgets.launcher_content.set_visible(true);
|
||||||
|
},
|
||||||
|
Err(err) => result.toast_error("Failed to get initial launcher state", err)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +159,7 @@ impl App {
|
||||||
self.widgets.preferences_stack.preferences_go_back.connect_clicked(Actions::PreferencesGoBack.into_fn(&self));
|
self.widgets.preferences_stack.preferences_go_back.connect_clicked(Actions::PreferencesGoBack.into_fn(&self));
|
||||||
|
|
||||||
// Launch game
|
// Launch game
|
||||||
self.widgets.launch_game.connect_clicked(Actions::LaunchGame.into_fn(&self));
|
self.widgets.launch_game.connect_clicked(Actions::PerformButtonEvent.into_fn(&self));
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -152,10 +174,8 @@ impl App {
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
|
|
||||||
receiver.attach(None, move |action| {
|
receiver.attach(None, move |action| {
|
||||||
let values = this.values.take();
|
|
||||||
|
|
||||||
// Some debug output
|
// Some debug output
|
||||||
println!("[main] [update] action: {:?}, values: {:?}", &action, &values);
|
println!("[main] [update] action: {:?}", &action);
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
Actions::OpenPreferencesPage => {
|
Actions::OpenPreferencesPage => {
|
||||||
|
@ -175,15 +195,48 @@ impl App {
|
||||||
this.widgets.leaflet.navigate(adw::NavigationDirection::Back);
|
this.widgets.leaflet.navigate(adw::NavigationDirection::Back);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Actions::PerformButtonEvent => {
|
||||||
|
let values = this.values.take();
|
||||||
|
let state = (*values.state).clone();
|
||||||
|
|
||||||
|
this.values.set(values);
|
||||||
|
|
||||||
|
match state {
|
||||||
|
LauncherState::Launch => {
|
||||||
|
this.update(Actions::LaunchGame);
|
||||||
|
},
|
||||||
|
LauncherState::PatchAvailable(_) => todo!(),
|
||||||
|
LauncherState::VoiceUpdateAvailable(_) => todo!(),
|
||||||
|
LauncherState::VoiceOutdated(_) => todo!(),
|
||||||
|
LauncherState::VoiceNotInstalled(_) => todo!(),
|
||||||
|
LauncherState::GameUpdateAvailable(_) => todo!(),
|
||||||
|
LauncherState::GameOutdated(_) => todo!(),
|
||||||
|
LauncherState::GameNotInstalled(_) => todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Actions::LaunchGame => {
|
Actions::LaunchGame => {
|
||||||
// Display toast message if the game is failed to run
|
// Display toast message if the game is failed to run
|
||||||
if let Err(err) = game::run(false) {
|
if let Err(err) = game::run(false) {
|
||||||
this.toast_error("Failed to run game", err);
|
this.toast_error("Failed to run game", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.values.set(values);
|
Actions::ShowProgressBar => {
|
||||||
|
this.widgets.launch_game_group.set_visible(false);
|
||||||
|
this.widgets.progress_bar_group.set_visible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Actions::UpdateProgress { fraction, title } => {
|
||||||
|
this.widgets.progress_bar.set_text(Some(title.as_str()));
|
||||||
|
this.widgets.progress_bar.set_fraction(*fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
Actions::HideProgressBar => {
|
||||||
|
this.widgets.launch_game_group.set_visible(true);
|
||||||
|
this.widgets.progress_bar_group.set_visible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glib::Continue(true)
|
glib::Continue(true)
|
||||||
});
|
});
|
||||||
|
@ -211,6 +264,45 @@ impl App {
|
||||||
pub fn show(&self) {
|
pub fn show(&self) {
|
||||||
self.widgets.window.show();
|
self.widgets.window.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&self, state: LauncherState) {
|
||||||
|
println!("[main] [set_state] state: {:?}", &state);
|
||||||
|
|
||||||
|
match state {
|
||||||
|
LauncherState::Launch => {
|
||||||
|
self.widgets.launch_game.set_label("Launch");
|
||||||
|
}
|
||||||
|
|
||||||
|
LauncherState::PatchAvailable(_) => {
|
||||||
|
self.widgets.launch_game.set_label("Apply patch");
|
||||||
|
}
|
||||||
|
|
||||||
|
LauncherState::GameUpdateAvailable(_) => {
|
||||||
|
self.widgets.launch_game.set_label("Update");
|
||||||
|
}
|
||||||
|
|
||||||
|
LauncherState::VoiceUpdateAvailable(_) => {
|
||||||
|
self.widgets.launch_game.set_label("Update");
|
||||||
|
}
|
||||||
|
|
||||||
|
LauncherState::GameNotInstalled(_) => {
|
||||||
|
self.widgets.launch_game.set_label("Download");
|
||||||
|
}
|
||||||
|
|
||||||
|
LauncherState::VoiceNotInstalled(_) => {
|
||||||
|
self.widgets.launch_game.set_label("Download");
|
||||||
|
}
|
||||||
|
|
||||||
|
LauncherState::VoiceOutdated(_) => todo!(),
|
||||||
|
LauncherState::GameOutdated(_) => todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut values = self.values.take();
|
||||||
|
|
||||||
|
values.state = Rc::new(state);
|
||||||
|
|
||||||
|
self.values.set(values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToastError for App {
|
impl ToastError for App {
|
||||||
|
@ -221,29 +313,3 @@ impl ToastError for App {
|
||||||
|
|
||||||
unsafe impl Send for App {}
|
unsafe impl Send for App {}
|
||||||
unsafe impl Sync for App {}
|
unsafe impl Sync for App {}
|
||||||
|
|
||||||
/*
|
|
||||||
pub enum AppState {
|
|
||||||
Launch,
|
|
||||||
Progress {
|
|
||||||
title: String,
|
|
||||||
progress: f64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_state(&self, state: AppState) {
|
|
||||||
match state {
|
|
||||||
AppState::Launch => {
|
|
||||||
self.launch_game_group.set_visible(true);
|
|
||||||
self.progress_bar_group.set_visible(false);
|
|
||||||
},
|
|
||||||
AppState::Progress { title, progress } => {
|
|
||||||
self.launch_game_group.set_visible(false);
|
|
||||||
self.progress_bar_group.set_visible(true);
|
|
||||||
|
|
||||||
self.progress_bar.set_text(Some(&title));
|
|
||||||
self.progress_bar.set_fraction(progress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue