settings: added patch status displaying

This commit is contained in:
Observer KRypt0n_ 2023-01-29 15:11:13 +02:00
parent 84163c470d
commit 29702782e2
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
6 changed files with 155 additions and 63 deletions

View file

@ -1,6 +1,8 @@
use relm4::prelude::*;
use anime_launcher_sdk::config;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
pub mod i18n;
pub mod ui;
@ -13,6 +15,46 @@ pub const APP_ID: &str = "moe.launcher.an-anime-game-launcher-gtk";
pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const APP_DEBUG: bool = cfg!(debug_assertions);
/// Sets to `true` when the `App` component is ready (fully initialized)
pub static mut READY: bool = false;
// TODO: get rid of using this function in all the components' events
// e.g. by converting preferences pages into Relm4 Components
pub fn is_ready() -> bool {
unsafe { READY }
}
lazy_static::lazy_static! {
/// Config loaded on the app's start. Use `config::get()` to get up to date config instead.
/// This one is used to prepare some launcher UI components on start
pub static ref CONFIG: config::Config = config::get().expect("Failed to load config");
pub static ref GAME: Game = Game::new(&CONFIG.game.path);
// TODO: add loading screen for heavy tasks like this
// UPD: tried once. The problem is that I use this variable, as well as ones above,
// in the view! macro, which makes it times harder to make the main window load
// faster than this variable calculates its value to show StatusPage with loader.
// As for now I have no idea how to fix this
pub static ref GAME_DIFF: Option<VersionDiff> = match GAME.try_get_diff() {
Ok(diff) => Some(diff),
Err(err) => {
tracing::error!("Failed to get game diff {err}");
None
}
};
pub static ref PATCH: Option<Patch> = match Patch::try_fetch(&CONFIG.patch.servers, None) {
Ok(patch) => Some(patch),
Err(err) => {
tracing::error!("Failed to fetch patch info {err}");
None
}
};
}
fn main() {
tracing_subscriber::fmt()
.with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)

View file

@ -55,7 +55,8 @@ impl SimpleComponent for AboutDialog {
add_credit_section: (Some("An Anime Team"), &[
"@Marie https://github.com/Mar0xy",
"@lane https://github.com/laurinneff"
"@lane https://github.com/laurinneff",
"@jiro-too https://github.com/jiro-too"
]),
set_debug_info: &[
@ -88,6 +89,8 @@ impl SimpleComponent for AboutDialog {
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
tracing::info!("Initializing about dialog");
let model = AboutDialog {
visible: false
};

View file

@ -16,20 +16,11 @@ relm4::new_stateless_action!(ConfigFile, WindowActionGroup, "config_file");
relm4::new_stateless_action!(About, WindowActionGroup, "about");
/// Sets to `true` when the `App` component is ready (fully initialized)
pub static mut READY: bool = false;
// TODO: get rid of using this function in all the components' events
// e.g. by converting preferences pages into Relm4 Components
pub fn is_ready() -> bool {
unsafe { READY }
}
static mut PREFERENCES_WINDOW: Option<Controller<PreferencesApp>> = None;
static mut ABOUT_DIALOG: Option<Controller<AboutDialog>> = None;
pub struct App {
preferences_window: Controller<PreferencesApp>,
#[allow(dead_code)]
about_dialog: Controller<AboutDialog>
loading: Option<Option<String>>
}
#[derive(Debug)]
@ -73,7 +64,25 @@ impl SimpleComponent for App {
}
},
adw::StatusPage {
set_title: "Loading data",
set_icon_name: Some("process-working"),
set_vexpand: true,
#[watch]
set_description: match &model.loading {
Some(Some(desc)) => Some(desc),
Some(None) | None => None
},
#[watch]
set_visible: model.loading.is_some()
},
adw::PreferencesPage {
#[watch]
set_visible: model.loading.is_none(),
add = &adw::PreferencesGroup {
gtk::Image {
set_resource: Some("/org/app/images/icon.png"),
@ -127,6 +136,10 @@ impl SimpleComponent for App {
) -> ComponentParts<Self> {
tracing::info!("Initializing main window");
let model = App {
loading: None
};
let widgets = view_output!();
if crate::APP_DEBUG {
@ -135,16 +148,16 @@ impl SimpleComponent for App {
let about_dialog_broker: MessageBroker<AboutDialog> = MessageBroker::new();
let model = App {
preferences_window: PreferencesApp::builder()
unsafe {
PREFERENCES_WINDOW = Some(PreferencesApp::builder()
.launch(widgets.main_window.clone().into())
.detach(),
.detach());
about_dialog: AboutDialog::builder()
ABOUT_DIALOG = Some(AboutDialog::builder()
.transient_for(widgets.main_window.clone())
.launch_with_broker((), &about_dialog_broker)
.detach()
};
.detach());
}
let group = RelmActionGroup::<WindowActionGroup>::new();
@ -167,7 +180,7 @@ impl SimpleComponent for App {
widgets.main_window.insert_action_group("win", Some(&group.into_action_group()));
unsafe {
READY = true;
crate::READY = true;
}
tracing::info!("Main window initialized. App is ready");
@ -179,12 +192,12 @@ impl SimpleComponent for App {
tracing::debug!("Called main window event: {:?}", msg);
match msg {
AppMsg::OpenPreferences => {
self.preferences_window.widgets().preferences_window.show();
AppMsg::OpenPreferences => unsafe {
PREFERENCES_WINDOW.as_ref().unwrap_unchecked().widgets().preferences_window.show();
}
AppMsg::ClosePreferences => {
self.preferences_window.widgets().preferences_window.hide();
AppMsg::ClosePreferences => unsafe {
PREFERENCES_WINDOW.as_ref().unwrap_unchecked().widgets().preferences_window.hide();
}
}
}

View file

@ -6,7 +6,7 @@ use anime_launcher_sdk::config;
use anime_launcher_sdk::config::prelude::*;
use crate::i18n::tr;
use crate::ui::main::is_ready;
use crate::*;
lazy_static::lazy_static! {
static ref CONFIG: config::Config = config::get().expect("Failed to load config");

View file

@ -5,25 +5,9 @@ use adw::prelude::*;
use anime_launcher_sdk::config;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
use crate::i18n::*;
use crate::ui::main::is_ready;
lazy_static::lazy_static! {
static ref CONFIG: config::Config = config::get().expect("Failed to load config");
static ref GAME: Game = Game::new(&CONFIG.game.path);
static ref GAME_DIFF: Option<VersionDiff> = match GAME.try_get_diff() {
Ok(diff) => Some(diff),
Err(err) => {
tracing::error!("Failed to get game diff {err}");
None
}
};
}
use crate::*;
#[relm4::widget_template(pub)]
impl WidgetTemplate for General {
@ -154,20 +138,24 @@ impl WidgetTemplate for General {
None => "success"
},
set_tooltip_text: Some(&match GAME_DIFF.as_ref().unwrap() {
VersionDiff::Latest(_) => String::new(),
VersionDiff::Predownload { current, latest, .. } => tr_args("game-predownload-available", [
("old", current.to_string().into()),
("new", latest.to_string().into())
]),
VersionDiff::Diff { current, latest, .. } => tr_args("game-update-available", [
("old", current.to_string().into()),
("new", latest.to_string().into())
]),
VersionDiff::Outdated { latest, ..} => tr_args("game-outdated", [
("latest", latest.to_string().into())
]),
VersionDiff::NotInstalled { .. } => String::new()
set_tooltip_text: Some(&match GAME_DIFF.as_ref() {
Some(diff) => match diff {
VersionDiff::Latest(_) => String::new(),
VersionDiff::Predownload { current, latest, .. } => tr_args("game-predownload-available", [
("old", current.to_string().into()),
("new", latest.to_string().into())
]),
VersionDiff::Diff { current, latest, .. } => tr_args("game-update-available", [
("old", current.to_string().into()),
("new", latest.to_string().into())
]),
VersionDiff::Outdated { latest, ..} => tr_args("game-outdated", [
("latest", latest.to_string().into())
]),
VersionDiff::NotInstalled { .. } => String::new()
}
None => String::new()
})
}
},
@ -176,8 +164,56 @@ impl WidgetTemplate for General {
set_title: &tr("patch-version"),
add_suffix = &gtk::Label {
set_text: "3.3.0",
add_css_class: "success"
set_text: &match PATCH.as_ref() {
Some(patch) => match patch {
Patch::NotAvailable => tr("patch-not-available"),
Patch::Outdated { current, .. } => tr_args("patch-outdated", [("current", current.to_string().into())]),
Patch::Preparation { .. } => tr("patch-preparation"),
Patch::Testing { version, .. } |
Patch::Available { version, .. } => version.to_string()
}
None => String::from("?")
},
add_css_class: match PATCH.as_ref() {
Some(patch) => match patch {
Patch::NotAvailable => "error",
Patch::Outdated { .. } |
Patch::Preparation { .. } |
Patch::Testing { .. } => "warning",
Patch::Available { .. } => unsafe {
if let Ok(true) = PATCH.as_ref().unwrap_unchecked().is_applied(&CONFIG.game.path) {
"success"
} else {
"warning"
}
}
}
None => ""
},
set_tooltip_text: Some(&match PATCH.as_ref() {
Some(patch) => match patch {
Patch::NotAvailable => tr("patch-not-available-tooltip"),
Patch::Outdated { current, latest, .. } => tr_args("patch-outdated-tooltip", [
("current", current.to_string().into()),
("latest", latest.to_string().into())
]),
Patch::Preparation { .. } => tr("patch-preparation-tooltip"),
Patch::Testing { .. } => tr("patch-testing-tooltip"),
Patch::Available { .. } => unsafe {
if let Ok(true) = PATCH.as_ref().unwrap_unchecked().is_applied(&CONFIG.game.path) {
String::new()
} else {
tr("patch-testing-tooltip")
}
}
}
None => String::new()
})
}
}
},

View file

@ -3,16 +3,12 @@ use relm4::prelude::*;
use gtk::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::config;
use anime_launcher_sdk::components::*;
use crate::ui::components::{self, *};
use crate::i18n::tr;
lazy_static::lazy_static! {
static ref CONFIG: config::Config = config::get().expect("Failed to load config");
}
use crate::CONFIG;
pub struct App {
wine_components: Controller<ComponentsList>,
@ -85,6 +81,8 @@ impl SimpleComponent for App {
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
tracing::info!("Initializing preferences window");
let model = App {
wine_components: ComponentsList::builder()
.launch(ComponentsListPattern {