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}