update_version.rs

  1use std::sync::Arc;
  2
  3use anyhow::anyhow;
  4use auto_update::{AutoUpdateStatus, AutoUpdater, UpdateCheckType, VersionCheckType};
  5use gpui::{Empty, Render};
  6use semver::Version;
  7use ui::{UpdateButton, prelude::*};
  8
  9pub struct UpdateVersion {
 10    status: AutoUpdateStatus,
 11    update_check_type: UpdateCheckType,
 12    dismissed: bool,
 13}
 14
 15impl UpdateVersion {
 16    pub fn new(cx: &mut Context<Self>) -> Self {
 17        if let Some(auto_updater) = AutoUpdater::get(cx) {
 18            cx.observe(&auto_updater, |this, auto_update, cx| {
 19                this.status = auto_update.read(cx).status();
 20                this.update_check_type = auto_update.read(cx).update_check_type();
 21                if this.status.is_updated() {
 22                    this.dismissed = false;
 23                }
 24            })
 25            .detach();
 26            Self {
 27                status: auto_updater.read(cx).status(),
 28                update_check_type: UpdateCheckType::Automatic,
 29                dismissed: false,
 30            }
 31        } else {
 32            Self {
 33                status: AutoUpdateStatus::Idle,
 34                update_check_type: UpdateCheckType::Automatic,
 35                dismissed: false,
 36            }
 37        }
 38    }
 39
 40    pub fn update_simulation(&mut self, cx: &mut Context<Self>) {
 41        let next_state = match self.status {
 42            AutoUpdateStatus::Idle => AutoUpdateStatus::Checking,
 43            AutoUpdateStatus::Checking => AutoUpdateStatus::Downloading {
 44                version: VersionCheckType::Semantic(Version::new(1, 99, 0)),
 45            },
 46            AutoUpdateStatus::Downloading { .. } => AutoUpdateStatus::Installing {
 47                version: VersionCheckType::Semantic(Version::new(1, 99, 0)),
 48            },
 49            AutoUpdateStatus::Installing { .. } => AutoUpdateStatus::Updated {
 50                version: VersionCheckType::Semantic(Version::new(1, 99, 0)),
 51            },
 52            AutoUpdateStatus::Updated { .. } => AutoUpdateStatus::Errored {
 53                error: Arc::new(anyhow!("Network timeout")),
 54            },
 55            AutoUpdateStatus::Errored { .. } => AutoUpdateStatus::Idle,
 56        };
 57
 58        self.status = next_state;
 59        self.update_check_type = UpdateCheckType::Manual;
 60        self.dismissed = false;
 61        cx.notify()
 62    }
 63
 64    pub fn show_update_in_menu_bar(&self) -> bool {
 65        self.dismissed && self.status.is_updated()
 66    }
 67
 68    fn version_tooltip_message(version: &VersionCheckType) -> String {
 69        format!("Version: {}", {
 70            match version {
 71                VersionCheckType::Sha(sha) => format!("{}", sha.short()),
 72                VersionCheckType::Semantic(semantic_version) => semantic_version.to_string(),
 73            }
 74        })
 75    }
 76}
 77
 78impl Render for UpdateVersion {
 79    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 80        if self.dismissed {
 81            return Empty.into_any_element();
 82        }
 83        match &self.status {
 84            AutoUpdateStatus::Checking if self.update_check_type.is_manual() => {
 85                UpdateButton::checking().into_any_element()
 86            }
 87            AutoUpdateStatus::Downloading { version } if self.update_check_type.is_manual() => {
 88                let tooltip = Self::version_tooltip_message(&version);
 89                UpdateButton::downloading(tooltip).into_any_element()
 90            }
 91            AutoUpdateStatus::Installing { version } if self.update_check_type.is_manual() => {
 92                let tooltip = Self::version_tooltip_message(&version);
 93                UpdateButton::installing(tooltip).into_any_element()
 94            }
 95            AutoUpdateStatus::Updated { version } => {
 96                let tooltip = Self::version_tooltip_message(&version);
 97                UpdateButton::updated(tooltip)
 98                    .on_click(|_, _, cx| {
 99                        workspace::reload(cx);
100                    })
101                    .on_dismiss(cx.listener(|this, _, _window, cx| {
102                        this.dismissed = true;
103                        cx.notify()
104                    }))
105                    .into_any_element()
106            }
107            AutoUpdateStatus::Errored { error } => {
108                let error_str = error.to_string();
109                UpdateButton::errored(error_str)
110                    .on_click(|_, window, cx| {
111                        window.dispatch_action(Box::new(workspace::OpenLog), cx);
112                    })
113                    .on_dismiss(cx.listener(|this, _, _window, cx| {
114                        this.dismissed = true;
115                        cx.notify()
116                    }))
117                    .into_any_element()
118            }
119            AutoUpdateStatus::Idle
120            | AutoUpdateStatus::Checking { .. }
121            | AutoUpdateStatus::Downloading { .. }
122            | AutoUpdateStatus::Installing { .. } => Empty.into_any_element(),
123        }
124    }
125}
126#[cfg(test)]
127mod tests {
128    use auto_update::VersionCheckType;
129    use release_channel::AppCommitSha;
130    use semver::Version;
131
132    use super::*;
133
134    #[test]
135    fn test_version_tooltip_message() {
136        let message = UpdateVersion::version_tooltip_message(&VersionCheckType::Semantic(
137            Version::new(1, 0, 0),
138        ));
139
140        assert_eq!(message, "Version: 1.0.0");
141
142        let message = UpdateVersion::version_tooltip_message(&VersionCheckType::Sha(
143            AppCommitSha::new("14d9a4189f058d8736339b06ff2340101eaea5af".to_string()),
144        ));
145
146        assert_eq!(message, "Version: 14d9a41…");
147    }
148}