1mod update_notification;
2
3use auto_update::AutoUpdater;
4use editor::{Editor, MultiBuffer};
5use gpui::{actions, prelude::*, AppContext, SharedString, View, ViewContext};
6use http_client::HttpClient;
7use markdown_preview::markdown_preview_view::{MarkdownPreviewMode, MarkdownPreviewView};
8use release_channel::{AppVersion, ReleaseChannel};
9use serde::Deserialize;
10use smol::io::AsyncReadExt;
11use util::ResultExt as _;
12use workspace::notifications::NotificationId;
13use workspace::Workspace;
14
15use crate::update_notification::UpdateNotification;
16
17actions!(auto_update, [ViewReleaseNotesLocally]);
18
19pub fn init(cx: &mut AppContext) {
20 cx.observe_new_views(|workspace: &mut Workspace, _cx| {
21 workspace.register_action(|workspace, _: &ViewReleaseNotesLocally, cx| {
22 view_release_notes_locally(workspace, cx);
23 });
24 })
25 .detach();
26}
27
28#[derive(Deserialize)]
29struct ReleaseNotesBody {
30 title: String,
31 release_notes: String,
32}
33
34fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
35 let release_channel = ReleaseChannel::global(cx);
36
37 let url = match release_channel {
38 ReleaseChannel::Nightly => Some("https://github.com/zed-industries/zed/commits/nightly/"),
39 ReleaseChannel::Dev => Some("https://github.com/zed-industries/zed/commits/main/"),
40 _ => None,
41 };
42
43 if let Some(url) = url {
44 cx.open_url(url);
45 return;
46 }
47
48 let version = AppVersion::global(cx).to_string();
49
50 let client = client::Client::global(cx).http_client();
51 let url = client.build_url(&format!(
52 "/api/release_notes/v2/{}/{}",
53 release_channel.dev_name(),
54 version
55 ));
56
57 let markdown = workspace
58 .app_state()
59 .languages
60 .language_for_name("Markdown");
61
62 workspace
63 .with_local_workspace(cx, move |_, cx| {
64 cx.spawn(|workspace, mut cx| async move {
65 let markdown = markdown.await.log_err();
66 let response = client.get(&url, Default::default(), true).await;
67 let Some(mut response) = response.log_err() else {
68 return;
69 };
70
71 let mut body = Vec::new();
72 response.body_mut().read_to_end(&mut body).await.ok();
73
74 let body: serde_json::Result<ReleaseNotesBody> =
75 serde_json::from_slice(body.as_slice());
76
77 if let Ok(body) = body {
78 workspace
79 .update(&mut cx, |workspace, cx| {
80 let project = workspace.project().clone();
81 let buffer = project.update(cx, |project, cx| {
82 project.create_local_buffer("", markdown, cx)
83 });
84 buffer.update(cx, |buffer, cx| {
85 buffer.edit([(0..0, body.release_notes)], None, cx)
86 });
87 let language_registry = project.read(cx).languages().clone();
88
89 let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
90
91 let tab_description = SharedString::from(body.title.to_string());
92 let editor = cx.new_view(|cx| {
93 Editor::for_multibuffer(buffer, Some(project), true, cx)
94 });
95 let workspace_handle = workspace.weak_handle();
96 let view: View<MarkdownPreviewView> = MarkdownPreviewView::new(
97 MarkdownPreviewMode::Default,
98 editor,
99 workspace_handle,
100 language_registry,
101 Some(tab_description),
102 cx,
103 );
104 workspace.add_item_to_active_pane(
105 Box::new(view.clone()),
106 None,
107 true,
108 cx,
109 );
110 cx.notify();
111 })
112 .log_err();
113 }
114 })
115 .detach();
116 })
117 .detach();
118}
119
120pub fn notify_of_any_new_update(cx: &mut ViewContext<Workspace>) -> Option<()> {
121 let updater = AutoUpdater::get(cx)?;
122 let version = updater.read(cx).current_version();
123 let should_show_notification = updater.read(cx).should_show_update_notification(cx);
124
125 cx.spawn(|workspace, mut cx| async move {
126 let should_show_notification = should_show_notification.await?;
127 if should_show_notification {
128 workspace.update(&mut cx, |workspace, cx| {
129 let workspace_handle = workspace.weak_handle();
130 workspace.show_notification(
131 NotificationId::unique::<UpdateNotification>(),
132 cx,
133 |cx| cx.new_view(|_| UpdateNotification::new(version, workspace_handle)),
134 );
135 updater.update(cx, |updater, cx| {
136 updater
137 .set_should_show_update_notification(false, cx)
138 .detach_and_log_err(cx);
139 });
140 })?;
141 }
142 anyhow::Ok(())
143 })
144 .detach();
145
146 None
147}