When Zed reopens after an auto-update is installed, a notification was previously displayed in the first window opened. If there were multiple windows open, the notification could be hidden because Zed reopens the last session's window stack in order from back to front. Now, the notification is opened in every workspace, and dismissing the notification in any workspace will dismisses it everywhere. Closes #23236 Release Notes: - Improved notification after Zed is updated to be visible in all workspaces. --------- Co-authored-by: Michael Sloan <michael@zed.dev>
160 lines
5.8 KiB
Rust
160 lines
5.8 KiB
Rust
mod update_notification;
|
|
|
|
use auto_update::AutoUpdater;
|
|
use editor::{Editor, MultiBuffer};
|
|
use gpui::{actions, prelude::*, App, Context, Entity, SharedString, Window};
|
|
use http_client::HttpClient;
|
|
use markdown_preview::markdown_preview_view::{MarkdownPreviewMode, MarkdownPreviewView};
|
|
use release_channel::{AppVersion, ReleaseChannel};
|
|
use serde::Deserialize;
|
|
use smol::io::AsyncReadExt;
|
|
use util::ResultExt as _;
|
|
use workspace::notifications::{show_app_notification, NotificationId};
|
|
use workspace::Workspace;
|
|
|
|
use crate::update_notification::UpdateNotification;
|
|
|
|
actions!(auto_update, [ViewReleaseNotesLocally]);
|
|
|
|
pub fn init(cx: &mut App) {
|
|
notify_if_app_was_updated(cx);
|
|
cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
|
|
workspace.register_action(|workspace, _: &ViewReleaseNotesLocally, window, cx| {
|
|
view_release_notes_locally(workspace, window, cx);
|
|
});
|
|
})
|
|
.detach();
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct ReleaseNotesBody {
|
|
title: String,
|
|
release_notes: String,
|
|
}
|
|
|
|
fn view_release_notes_locally(
|
|
workspace: &mut Workspace,
|
|
window: &mut Window,
|
|
cx: &mut Context<Workspace>,
|
|
) {
|
|
let release_channel = ReleaseChannel::global(cx);
|
|
|
|
let url = match release_channel {
|
|
ReleaseChannel::Nightly => Some("https://github.com/zed-industries/zed/commits/nightly/"),
|
|
ReleaseChannel::Dev => Some("https://github.com/zed-industries/zed/commits/main/"),
|
|
_ => None,
|
|
};
|
|
|
|
if let Some(url) = url {
|
|
cx.open_url(url);
|
|
return;
|
|
}
|
|
|
|
let version = AppVersion::global(cx).to_string();
|
|
|
|
let client = client::Client::global(cx).http_client();
|
|
let url = client.build_url(&format!(
|
|
"/api/release_notes/v2/{}/{}",
|
|
release_channel.dev_name(),
|
|
version
|
|
));
|
|
|
|
let markdown = workspace
|
|
.app_state()
|
|
.languages
|
|
.language_for_name("Markdown");
|
|
|
|
workspace
|
|
.with_local_workspace(window, cx, move |_, window, cx| {
|
|
cx.spawn_in(window, |workspace, mut cx| async move {
|
|
let markdown = markdown.await.log_err();
|
|
let response = client.get(&url, Default::default(), true).await;
|
|
let Some(mut response) = response.log_err() else {
|
|
return;
|
|
};
|
|
|
|
let mut body = Vec::new();
|
|
response.body_mut().read_to_end(&mut body).await.ok();
|
|
|
|
let body: serde_json::Result<ReleaseNotesBody> =
|
|
serde_json::from_slice(body.as_slice());
|
|
|
|
if let Ok(body) = body {
|
|
workspace
|
|
.update_in(&mut cx, |workspace, window, cx| {
|
|
let project = workspace.project().clone();
|
|
let buffer = project.update(cx, |project, cx| {
|
|
project.create_local_buffer("", markdown, cx)
|
|
});
|
|
buffer.update(cx, |buffer, cx| {
|
|
buffer.edit([(0..0, body.release_notes)], None, cx)
|
|
});
|
|
let language_registry = project.read(cx).languages().clone();
|
|
|
|
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
|
|
|
|
let tab_description = SharedString::from(body.title.to_string());
|
|
let editor = cx.new(|cx| {
|
|
Editor::for_multibuffer(buffer, Some(project), true, window, cx)
|
|
});
|
|
let workspace_handle = workspace.weak_handle();
|
|
let markdown_preview: Entity<MarkdownPreviewView> =
|
|
MarkdownPreviewView::new(
|
|
MarkdownPreviewMode::Default,
|
|
editor,
|
|
workspace_handle,
|
|
language_registry,
|
|
Some(tab_description),
|
|
window,
|
|
cx,
|
|
);
|
|
workspace.add_item_to_active_pane(
|
|
Box::new(markdown_preview.clone()),
|
|
None,
|
|
true,
|
|
window,
|
|
cx,
|
|
);
|
|
cx.notify();
|
|
})
|
|
.log_err();
|
|
}
|
|
})
|
|
.detach();
|
|
})
|
|
.detach();
|
|
}
|
|
|
|
/// Shows a notification across all workspaces if an update was previously automatically installed
|
|
/// and this notification had not yet been shown.
|
|
pub fn notify_if_app_was_updated(cx: &mut App) {
|
|
let Some(updater) = AutoUpdater::get(cx) else {
|
|
return;
|
|
};
|
|
let version = updater.read(cx).current_version();
|
|
let should_show_notification = updater.read(cx).should_show_update_notification(cx);
|
|
|
|
cx.spawn(|cx| async move {
|
|
let should_show_notification = should_show_notification.await?;
|
|
if should_show_notification {
|
|
cx.update(|cx| {
|
|
show_app_notification(
|
|
NotificationId::unique::<UpdateNotification>(),
|
|
cx,
|
|
move |cx| {
|
|
let workspace_handle = cx.entity().downgrade();
|
|
cx.new(|_| UpdateNotification::new(version, workspace_handle))
|
|
},
|
|
);
|
|
updater.update(cx, |updater, cx| {
|
|
updater
|
|
.set_should_show_update_notification(false, cx)
|
|
.detach_and_log_err(cx);
|
|
})
|
|
})?;
|
|
}
|
|
anyhow::Ok(())
|
|
})
|
|
.detach();
|
|
}
|