From c3b5bbc1b2a0be1a2c3da928d87a95937c4fe01c Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Mon, 3 Aug 2026 08:52:37 +0700 Subject: [PATCH] update --- Cargo.lock | 1 + crates/auto_update/src/lib.rs | 68 +++++++++++++++++++++++++- crates/browser-signer-proxy/index.html | 6 +-- crates/workspace/Cargo.toml | 1 + crates/workspace/src/lib.rs | 14 +++++- 5 files changed, 82 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e938eb..9ff639f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9117,6 +9117,7 @@ name = "workspace" version = "1.0.0-beta5" dependencies = [ "anyhow", + "auto_update", "browser-signer-proxy", "chat", "chat_ui", diff --git a/crates/auto_update/src/lib.rs b/crates/auto_update/src/lib.rs index 4eb6216..be2643b 100644 --- a/crates/auto_update/src/lib.rs +++ b/crates/auto_update/src/lib.rs @@ -1,8 +1,8 @@ #![cfg(not(target_arch = "wasm32"))] -use gpui::{App, AppContext, Context, Entity, Global, Subscription, Window}; +use gpui::{App, AppContext, Context, Entity, Global, SharedString, Subscription, Window}; use gpui_updater::{EngineConfig, GitHubSource, UpdateStatus, Updater, Version}; -use instant::Duration; +use instant::{Duration, Instant}; const COOP_UPDATE_EXPLANATION: &str = "COOP_UPDATE_EXPLANATION"; @@ -52,6 +52,8 @@ pub struct AutoUpdater { pub version: Version, /// Keeps the observer subscription alive. _subscription: Subscription, + /// When the last error was recorded, so we can reset to idle after 5s. + error_time: Option, } impl AutoUpdater { @@ -83,11 +85,24 @@ impl AutoUpdater { // When an update becomes available, automatically download and install it. let subscription = cx.observe(&updater, |this: &mut AutoUpdater, _updater, cx| { let status = this.updater.read(cx).status().clone(); + if matches!(status, UpdateStatus::Available(_)) { this.updater.update(cx, |updater, cx| { updater.download_and_install(cx); }); } + + if matches!(status, UpdateStatus::Errored(_)) { + this.error_time = Some(Instant::now()); + cx.spawn(async move |this, cx| { + cx.background_executor().timer(Duration::from_secs(5)).await; + this.update(cx, |_this, cx| cx.notify()).ok(); + }) + .detach(); + } else { + this.error_time = None; + } + cx.notify(); }); @@ -111,6 +126,55 @@ impl AutoUpdater { updater, version, _subscription: subscription, + error_time: None, + } + } + + pub fn idle(&self, cx: &App) -> bool { + let status = self.updater.read(cx).status(); + if status == &UpdateStatus::Idle { + return true; + } + if matches!(status, UpdateStatus::Errored(_)) + && self + .error_time + .is_some_and(|t| t.elapsed() >= Duration::from_secs(5)) + { + return true; + } + false + } + + pub fn status(&self, cx: &App) -> SharedString { + let status = self.updater.read(cx).status(); + + match status { + UpdateStatus::Idle => "Up to date".into(), + UpdateStatus::Checking => "Checking for updates…".into(), + UpdateStatus::UpToDate => "Up to date".into(), + UpdateStatus::Available(version) => format!("Version {version} available").into(), + UpdateStatus::Downloading { downloaded, total } => { + let total_mb = total.map(|t| t as f64 / 1_048_576.0); + let downloaded_mb = *downloaded as f64 / 1_048_576.0; + match total_mb { + Some(t) => format!("Downloading {downloaded_mb:.1} / {t:.1} MB").into(), + None => format!("Downloading {downloaded_mb:.1} MB").into(), + } + } + UpdateStatus::Installing => "Installing update…".into(), + UpdateStatus::Staged(version) => { + format!("Version {version} ready — restart to apply").into() + } + UpdateStatus::Errored(msg) => { + if self + .error_time + .is_some_and(|t| t.elapsed() >= Duration::from_secs(5)) + { + "Up to date".into() + } else { + format!("Update failed: {msg}").into() + } + } } } } diff --git a/crates/browser-signer-proxy/index.html b/crates/browser-signer-proxy/index.html index 1b5c3a2..1e33dbe 100644 --- a/crates/browser-signer-proxy/index.html +++ b/crates/browser-signer-proxy/index.html @@ -164,12 +164,8 @@
- -

Web Signer

+

This page connects the app to your Nostr Web Signer extension so you can sign in and use Coop securely.

diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index d9690fb..6a75fb2 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -14,6 +14,7 @@ chat = { path = "../chat" } chat_ui = { path = "../chat_ui" } settings = { path = "../settings" } person = { path = "../person" } +auto_update = { path = "../auto_update" } gpui.workspace = true nostr-sdk.workspace = true diff --git a/crates/workspace/src/lib.rs b/crates/workspace/src/lib.rs index 3cb0a4c..668426e 100644 --- a/crates/workspace/src/lib.rs +++ b/crates/workspace/src/lib.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use ::settings::AppSettings; use anyhow::Error; +use auto_update::AutoUpdater; use chat::{ChatEvent, ChatRegistry}; use common::{CoopImageCache, download_dir}; use device::{DeviceEvent, DeviceRegistry}; @@ -379,7 +380,12 @@ impl Workspace { self.import_encryption(window, cx); } Command::Update => { - // + let auto_updater = AutoUpdater::global(cx); + auto_updater.update(cx, |this, cx| { + this.updater.update(cx, |updater, cx| { + updater.check(cx); + }); + }); } } } @@ -604,6 +610,7 @@ impl Workspace { } fn titlebar_right(&mut self, cx: &mut Context) -> impl IntoElement { + let updater = AutoUpdater::global(cx); let chat = ChatRegistry::global(cx); let nip4e_enabled = AppSettings::get_nip4e(cx); let nostr = NostrRegistry::global(cx); @@ -615,10 +622,15 @@ impl Workspace { let persons = PersonRegistry::global(cx); let profile = persons.read(cx).get(&public_key, cx); let announcement = profile.announcement(); + let updater_idle = updater.read(cx).idle(cx); h_flex() .when(!cx.theme().platform.is_mac(), |this| this.pr_2()) .gap_2() + .when(!updater_idle, |this| { + let status = updater.read(cx).status(cx); + this.child(div().text_xs().italic().child(status)) + }) .when(nip4e_enabled, |this| { this.child( Button::new("key")