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
+ }
+}