diff --git a/Cargo.toml b/Cargo.toml index 49687b8c..42e084b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ bevy_kira_audio = { git = "https://github.com/robtfm/bevy_kira_audio", branch = bevy_simple_text_input = { git = "https://github.com/robtfm/bevy_simple_text_input", features=["clipboard"], branch="multiline" } directories = "5" uuid = { version = "1.7", features = ["v4"] } +build-time = "0.1.3" [dependencies] analytics = { workspace = true } @@ -140,7 +141,7 @@ uuid = { workspace = true } pico-args = "0.5.0" mimalloc = { version = "*", default-features = false } -build-time = "0.1.3" +build-time = { workspace = true } chrono = { workspace = true } tracing-appender = "0.2.3" log-panics = { version = "2.1.0", features = ["with-backtrace"] } diff --git a/assets/ui/update.dui b/assets/ui/update.dui new file mode 100644 index 00000000..589cee25 --- /dev/null +++ b/assets/ui/update.dui @@ -0,0 +1,14 @@ + + +
+
+ +
+
+
+ +
+
+
+
+ diff --git a/crates/common/src/structs.rs b/crates/common/src/structs.rs index 06209304..0da289c0 100644 --- a/crates/common/src/structs.rs +++ b/crates/common/src/structs.rs @@ -537,7 +537,7 @@ impl ActiveDialog { .clone() .try_acquire_owned() .ok() - .map(|p| DialogPermit { _p: p }) + .map(|p| DialogPermit { _p: Some(p) }) } pub fn in_use(&self) -> bool { @@ -547,7 +547,15 @@ impl ActiveDialog { #[derive(Component)] pub struct DialogPermit { - _p: OwnedSemaphorePermit, + _p: Option, +} + +impl DialogPermit { + pub fn take(&mut self) -> Self { + Self { + _p: Some(self._p.take().unwrap()), + } + } } #[derive(Component, Default, Clone, Copy, PartialEq, Eq)] diff --git a/crates/system_ui/Cargo.toml b/crates/system_ui/Cargo.toml index cbde0b24..7fda3e61 100644 --- a/crates/system_ui/Cargo.toml +++ b/crates/system_ui/Cargo.toml @@ -43,6 +43,7 @@ chrono = { workspace = true } clap = { workspace = true } opener = { workspace = true } urlencoding = { workspace = true } +build-time = { workspace = true } copypasta = "0.10" shlex = "1" diff --git a/crates/system_ui/src/lib.rs b/crates/system_ui/src/lib.rs index 259a7b3f..1aed416d 100644 --- a/crates/system_ui/src/lib.rs +++ b/crates/system_ui/src/lib.rs @@ -16,6 +16,7 @@ pub mod profile_detail; pub mod sysinfo; pub mod toasts; pub mod tooltip; +pub mod version_check; pub mod wearables; use bevy::prelude::*; diff --git a/crates/system_ui/src/login.rs b/crates/system_ui/src/login.rs index afbd8c9f..6e1cf3c4 100644 --- a/crates/system_ui/src/login.rs +++ b/crates/system_ui/src/login.rs @@ -10,7 +10,7 @@ use bevy::{ use bevy_dui::{DuiCommandsExt, DuiEntityCommandsExt, DuiProps, DuiRegistry}; use common::{ profile::SerializedProfile, - structs::{ActiveDialog, AppConfig, ChainLink, PreviousLogin}, + structs::{ActiveDialog, AppConfig, ChainLink, DialogPermit, PreviousLogin}, util::{project_directories, TaskExt}, }; use comms::{ @@ -32,6 +32,8 @@ use wallet::{ Wallet, }; +use crate::version_check::check_update; + pub struct LoginPlugin; impl Plugin for LoginPlugin { @@ -81,16 +83,44 @@ fn login( mut motd_shown: Local, ) { if !*motd_shown { + let update = check_update(); let permit = active_dialog.try_acquire().unwrap(); - let components = commands - .spawn_template( - &dui, - "motd", - DuiProps::default() - .with_prop("buttons", vec![DuiButton::new_enabled("Ok", close_ui)]), - ) - .unwrap(); - commands.entity(components.root).insert(permit); + + if let Some((desc, url)) = update { + let components = commands + .spawn_template( + &dui, + "update-available", + DuiProps::new() + .with_prop("download", url) + .with_prop("body", desc) + .with_prop("buttons", vec![DuiButton::new_enabled("Ok", (|mut commands: Commands, dui: Res, mut permit: Query<&mut DialogPermit>| { + let mut permit = permit.single_mut(); + let permit = permit.take(); + let components = commands + .spawn_template( + &dui, + "motd", + DuiProps::default() + .with_prop("buttons", vec![DuiButton::new_enabled("Ok", close_ui)]), + ) + .unwrap(); + commands.entity(components.root).insert(permit); + }).pipe(close_ui))]), + ) + .unwrap(); + commands.entity(components.root).insert(permit); + } else { + let components = commands + .spawn_template( + &dui, + "motd", + DuiProps::default() + .with_prop("buttons", vec![DuiButton::new_enabled("Ok", close_ui)]), + ) + .unwrap(); + commands.entity(components.root).insert(permit); + } *motd_shown = true; return; } diff --git a/crates/system_ui/src/version_check.rs b/crates/system_ui/src/version_check.rs new file mode 100644 index 00000000..34aab77d --- /dev/null +++ b/crates/system_ui/src/version_check.rs @@ -0,0 +1,35 @@ +use isahc::ReadResponseExt; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +struct GitData { + tag_name: String, + html_url: String, + body: String, +} + +pub fn build_date() -> chrono::NaiveDate { + chrono::NaiveDate::parse_from_str(build_time::build_time_utc!("%Y-%m-%d"), "%Y-%m-%d").unwrap() +} + +pub fn check_update() -> Option<(String, String)> { + let latest: GitData = + isahc::get("https://api.github.com/repos/decentraland/bevy-explorer/releases/latest") + .ok()? + .json() + .ok()?; + let latest_date = latest + .tag_name + .split('-') + .skip(1) + .take(3) + .collect::>() + .join("-"); + let latest_date = chrono::NaiveDate::parse_from_str(&latest_date, "%Y-%m-%d").ok()?; + + if latest_date > build_date() { + Some((latest.body, latest.html_url)) + } else { + None + } +}