auto_update_ui: Show update notification across workspaces (#23458)

James Roberts and Michael Sloan created

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>

Change summary

crates/auto_update_ui/src/auto_update_ui.rs | 27 +++++++++++++---------
crates/zed/src/zed.rs                       |  2 -
2 files changed, 16 insertions(+), 13 deletions(-)

Detailed changes

crates/auto_update_ui/src/auto_update_ui.rs 🔗

@@ -9,7 +9,7 @@ use release_channel::{AppVersion, ReleaseChannel};
 use serde::Deserialize;
 use smol::io::AsyncReadExt;
 use util::ResultExt as _;
-use workspace::notifications::NotificationId;
+use workspace::notifications::{show_app_notification, NotificationId};
 use workspace::Workspace;
 
 use crate::update_notification::UpdateNotification;
@@ -17,6 +17,7 @@ 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);
@@ -124,31 +125,35 @@ fn view_release_notes_locally(
         .detach();
 }
 
-pub fn notify_of_any_new_update(window: &mut Window, cx: &mut Context<Workspace>) -> Option<()> {
-    let updater = AutoUpdater::get(cx)?;
+/// 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_in(window, |workspace, mut cx| async move {
+    cx.spawn(|cx| async move {
         let should_show_notification = should_show_notification.await?;
         if should_show_notification {
-            workspace.update(&mut cx, |workspace, cx| {
-                let workspace_handle = workspace.weak_handle();
-                workspace.show_notification(
+            cx.update(|cx| {
+                show_app_notification(
                     NotificationId::unique::<UpdateNotification>(),
                     cx,
-                    |cx| cx.new(|_| UpdateNotification::new(version, workspace_handle)),
+                    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();
-
-    None
 }

crates/zed/src/zed.rs 🔗

@@ -213,8 +213,6 @@ pub fn initialize_workspace(
             status_bar.add_right_item(cursor_position, window, cx);
         });
 
-        auto_update_ui::notify_of_any_new_update(window, cx);
-
         let handle = cx.entity().downgrade();
         window.on_window_should_close(cx, move |window, cx| {
             handle