use std::sync::Arc; use anyhow::anyhow; use auto_update::{AutoUpdateStatus, AutoUpdater, UpdateCheckType, VersionCheckType}; use gpui::{Empty, Render}; use semver::Version; use ui::{UpdateButton, prelude::*}; pub struct UpdateVersion { status: AutoUpdateStatus, update_check_type: UpdateCheckType, dismissed: bool, } impl UpdateVersion { pub fn new(cx: &mut Context) -> Self { if let Some(auto_updater) = AutoUpdater::get(cx) { cx.observe(&auto_updater, |this, auto_update, cx| { this.status = auto_update.read(cx).status(); this.update_check_type = auto_update.read(cx).update_check_type(); if this.status.is_updated() { this.dismissed = false; } }) .detach(); Self { status: auto_updater.read(cx).status(), update_check_type: UpdateCheckType::Automatic, dismissed: false, } } else { Self { status: AutoUpdateStatus::Idle, update_check_type: UpdateCheckType::Automatic, dismissed: false, } } } pub fn update_simulation(&mut self, cx: &mut Context) { let next_state = match self.status { AutoUpdateStatus::Idle => AutoUpdateStatus::Checking, AutoUpdateStatus::Checking => AutoUpdateStatus::Downloading { version: VersionCheckType::Semantic(Version::new(1, 99, 0)), }, AutoUpdateStatus::Downloading { .. } => AutoUpdateStatus::Installing { version: VersionCheckType::Semantic(Version::new(1, 99, 0)), }, AutoUpdateStatus::Installing { .. } => AutoUpdateStatus::Updated { version: VersionCheckType::Semantic(Version::new(1, 99, 0)), }, AutoUpdateStatus::Updated { .. } => AutoUpdateStatus::Errored { error: Arc::new(anyhow!("Network timeout")), }, AutoUpdateStatus::Errored { .. } => AutoUpdateStatus::Idle, }; self.status = next_state; self.update_check_type = UpdateCheckType::Manual; self.dismissed = false; cx.notify() } pub fn show_update_in_menu_bar(&self) -> bool { self.dismissed && self.status.is_updated() } fn version_tooltip_message(version: &VersionCheckType) -> String { format!("Version: {}", { match version { VersionCheckType::Sha(sha) => format!("{}…", sha.short()), VersionCheckType::Semantic(semantic_version) => semantic_version.to_string(), } }) } } impl Render for UpdateVersion { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { if self.dismissed { return Empty.into_any_element(); } match &self.status { AutoUpdateStatus::Checking if self.update_check_type.is_manual() => { UpdateButton::checking().into_any_element() } AutoUpdateStatus::Downloading { version } => { let tooltip = Self::version_tooltip_message(&version); UpdateButton::downloading(tooltip).into_any_element() } AutoUpdateStatus::Installing { version } => { let tooltip = Self::version_tooltip_message(&version); UpdateButton::installing(tooltip).into_any_element() } AutoUpdateStatus::Updated { version } => { let tooltip = Self::version_tooltip_message(&version); UpdateButton::updated(tooltip) .on_click(|_, _, cx| { workspace::reload(cx); }) .on_dismiss(cx.listener(|this, _, _window, cx| { this.dismissed = true; cx.notify() })) .into_any_element() } AutoUpdateStatus::Errored { error } => { let error_str = error.to_string(); UpdateButton::errored(error_str) .on_click(|_, window, cx| { window.dispatch_action(Box::new(workspace::OpenLog), cx); }) .on_dismiss(cx.listener(|this, _, _window, cx| { this.dismissed = true; cx.notify() })) .into_any_element() } AutoUpdateStatus::Idle | AutoUpdateStatus::Checking { .. } => Empty.into_any_element(), } } } #[cfg(test)] mod tests { use auto_update::VersionCheckType; use release_channel::AppCommitSha; use semver::Version; use super::*; #[test] fn test_version_tooltip_message() { let message = UpdateVersion::version_tooltip_message(&VersionCheckType::Semantic( Version::new(1, 0, 0), )); assert_eq!(message, "Version: 1.0.0"); let message = UpdateVersion::version_tooltip_message(&VersionCheckType::Sha( AppCommitSha::new("14d9a4189f058d8736339b06ff2340101eaea5af".to_string()), )); assert_eq!(message, "Version: 14d9a41…"); } }