zed2: Port ProjectSharedNotification (#3545)

Julia created

Release Notes:

- N/A

Change summary

crates/collab_ui2/src/notifications.rs                             |   4 
crates/collab_ui2/src/notifications/incoming_call_notification.rs  | 164 
crates/collab_ui2/src/notifications/project_shared_notification.rs | 185 
3 files changed, 97 insertions(+), 256 deletions(-)

Detailed changes

crates/collab_ui2/src/notifications.rs 🔗

@@ -3,9 +3,9 @@ use std::sync::Arc;
 use workspace::AppState;
 
 pub mod incoming_call_notification;
-// pub mod project_shared_notification;
+pub mod project_shared_notification;
 
 pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
     incoming_call_notification::init(app_state, cx);
-    //project_shared_notification::init(app_state, cx);
+    project_shared_notification::init(app_state, cx);
 }

crates/collab_ui2/src/notifications/incoming_call_notification.rs 🔗

@@ -33,8 +33,8 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
                     height: px(64.),
                 };
 
-                for window in unique_screens {
-                    let options = notification_window_options(window, window_size);
+                for screen in unique_screens {
+                    let options = notification_window_options(screen, window_size);
                     let window = cx
                         .open_window(options, |cx| {
                             cx.build_view(|_| {
@@ -47,15 +47,6 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
                         .unwrap();
                     notification_windows.push(window);
                 }
-
-                // for screen in cx.platform().screens() {
-                //     let window = cx
-                //         .add_window(notification_window_options(screen, window_size), |_| {
-                //             IncomingCallNotification::new(incoming_call.clone(), app_state.clone())
-                //         });
-
-                //     notification_windows.push(window);
-                // }
             }
         }
     })
@@ -84,21 +75,22 @@ impl IncomingCallNotificationState {
         let active_call = ActiveCall::global(cx);
         if accept {
             let join = active_call.update(cx, |active_call, cx| active_call.accept_incoming(cx));
+            let caller_user_id = self.call.calling_user.id;
             let initial_project_id = self.call.initial_project.as_ref().map(|project| project.id);
             let app_state = self.app_state.clone();
             let cx: &mut AppContext = cx;
             cx.spawn(|cx| async move {
                 join.await?;
-                if let Some(_project_id) = initial_project_id {
-                    cx.update(|_cx| {
-                        if let Some(_app_state) = app_state.upgrade() {
-                            // workspace::join_remote_project(
-                            //     project_id,
-                            //     caller_user_id,
-                            //     app_state,
-                            //     cx,
-                            // )
-                            // .detach_and_log_err(cx);
+                if let Some(project_id) = initial_project_id {
+                    cx.update(|cx| {
+                        if let Some(app_state) = app_state.upgrade() {
+                            workspace::join_remote_project(
+                                project_id,
+                                caller_user_id,
+                                app_state,
+                                cx,
+                            )
+                            .detach_and_log_err(cx);
                         }
                     })
                     .log_err();
@@ -138,135 +130,25 @@ impl IncomingCallNotification {
                     )))
                     .child(self.render_buttons(cx)),
             )
-        // let theme = &theme::current(cx).incoming_call_notification;
-        // let default_project = proto::ParticipantProject::default();
-        // let initial_project = self
-        //     .call
-        //     .initial_project
-        //     .as_ref()
-        //     .unwrap_or(&default_project);
-        // Flex::row()
-        //     .with_children(self.call.calling_user.avatar.clone().map(|avatar| {
-        //         Image::from_data(avatar)
-        //             .with_style(theme.caller_avatar)
-        //             .aligned()
-        //     }))
-        //     .with_child(
-        //         Flex::column()
-        //             .with_child(
-        //                 Label::new(
-        //                     self.call.calling_user.github_login.clone(),
-        //                     theme.caller_username.text.clone(),
-        //                 )
-        //                 .contained()
-        //                 .with_style(theme.caller_username.container),
-        //             )
-        //             .with_child(
-        //                 Label::new(
-        //                     format!(
-        //                         "is sharing a project in Zed{}",
-        //                         if initial_project.worktree_root_names.is_empty() {
-        //                             ""
-        //                         } else {
-        //                             ":"
-        //                         }
-        //                     ),
-        //                     theme.caller_message.text.clone(),
-        //                 )
-        //                 .contained()
-        //                 .with_style(theme.caller_message.container),
-        //             )
-        //             .with_children(if initial_project.worktree_root_names.is_empty() {
-        //                 None
-        //             } else {
-        //                 Some(
-        //                     Label::new(
-        //                         initial_project.worktree_root_names.join(", "),
-        //                         theme.worktree_roots.text.clone(),
-        //                     )
-        //                     .contained()
-        //                     .with_style(theme.worktree_roots.container),
-        //                 )
-        //             })
-        //             .contained()
-        //             .with_style(theme.caller_metadata)
-        //             .aligned(),
-        //     )
-        //     .contained()
-        //     .with_style(theme.caller_container)
-        //     .flex(1., true)
-        //     .into_any()
     }
 
     fn render_buttons(&self, cx: &mut ViewContext<Self>) -> impl Element {
         h_stack()
-            .child(
-                Button::new("accept", "Accept")
-                    .render(cx)
-                    // .bg(green())
-                    .on_click({
-                        let state = self.state.clone();
-                        move |_, cx| state.respond(true, cx)
-                    }),
-            )
-            .child(
-                Button::new("decline", "Decline")
-                    .render(cx)
-                    // .bg(red())
-                    .on_click({
-                        let state = self.state.clone();
-                        move |_, cx| state.respond(false, cx)
-                    }),
-            )
-
-        // enum Accept {}
-        // enum Decline {}
-
-        // let theme = theme::current(cx);
-        // Flex::column()
-        //     .with_child(
-        //         MouseEventHandler::new::<Accept, _>(0, cx, |_, _| {
-        //             let theme = &theme.incoming_call_notification;
-        //             Label::new("Accept", theme.accept_button.text.clone())
-        //                 .aligned()
-        //                 .contained()
-        //                 .with_style(theme.accept_button.container)
-        //         })
-        //         .with_cursor_style(CursorStyle::PointingHand)
-        //         .on_click(MouseButton::Left, |_, this, cx| {
-        //             this.respond(true, cx);
-        //         })
-        //         .flex(1., true),
-        //     )
-        //     .with_child(
-        //         MouseEventHandler::new::<Decline, _>(0, cx, |_, _| {
-        //             let theme = &theme.incoming_call_notification;
-        //             Label::new("Decline", theme.decline_button.text.clone())
-        //                 .aligned()
-        //                 .contained()
-        //                 .with_style(theme.decline_button.container)
-        //         })
-        //         .with_cursor_style(CursorStyle::PointingHand)
-        //         .on_click(MouseButton::Left, |_, this, cx| {
-        //             this.respond(false, cx);
-        //         })
-        //         .flex(1., true),
-        //     )
-        //     .constrained()
-        //     .with_width(theme.incoming_call_notification.button_width)
-        //     .into_any()
+            .child(Button::new("accept", "Accept").render(cx).on_click({
+                let state = self.state.clone();
+                move |_, cx| state.respond(true, cx)
+            }))
+            .child(Button::new("decline", "Decline").render(cx).on_click({
+                let state = self.state.clone();
+                move |_, cx| state.respond(false, cx)
+            }))
     }
 }
+
 impl Render for IncomingCallNotification {
     type Element = Div;
+
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         div().bg(red()).flex_none().child(self.render_caller(cx))
-        // Flex::row()
-        //     .with_child()
-        //     .with_child(self.render_buttons(cx))
-        //     .contained()
-        //     .with_background_color(background)
-        //     .expanded()
-        //     .into_any()
     }
 }

crates/collab_ui2/src/notifications/project_shared_notification.rs 🔗

@@ -3,12 +3,11 @@ use call::{room, ActiveCall};
 use client::User;
 use collections::HashMap;
 use gpui::{
-    elements::*,
-    geometry::vector::vec2f,
-    platform::{CursorStyle, MouseButton},
-    AppContext, Entity, View, ViewContext,
+    px, AppContext, Div, Element, ParentElement, Render, RenderOnce, Size, Styled, ViewContext,
+    VisualContext,
 };
 use std::sync::{Arc, Weak};
+use ui::{h_stack, v_stack, Avatar, Button, Clickable, Label};
 use workspace::AppState;
 
 pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
@@ -21,38 +20,54 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
             project_id,
             worktree_root_names,
         } => {
-            let theme = &theme::current(cx).project_shared_notification;
-            let window_size = vec2f(theme.window_width, theme.window_height);
+            let window_size = Size {
+                width: px(380.),
+                height: px(64.),
+            };
 
-            for screen in cx.platform().screens() {
-                let window =
-                    cx.add_window(notification_window_options(screen, window_size), |_| {
+            for screen in cx.displays() {
+                let options = notification_window_options(screen, window_size);
+                let window = cx.open_window(options, |cx| {
+                    cx.build_view(|_| {
                         ProjectSharedNotification::new(
                             owner.clone(),
                             *project_id,
                             worktree_root_names.clone(),
                             app_state.clone(),
                         )
-                    });
+                    })
+                });
                 notification_windows
                     .entry(*project_id)
                     .or_insert(Vec::new())
                     .push(window);
             }
         }
+
         room::Event::RemoteProjectUnshared { project_id }
         | room::Event::RemoteProjectJoined { project_id }
         | room::Event::RemoteProjectInvitationDiscarded { project_id } => {
             if let Some(windows) = notification_windows.remove(&project_id) {
                 for window in windows {
-                    window.remove(cx);
+                    window
+                        .update(cx, |_, cx| {
+                            // todo!()
+                            cx.remove_window();
+                        })
+                        .ok();
                 }
             }
         }
+
         room::Event::Left => {
             for (_, windows) in notification_windows.drain() {
                 for window in windows {
-                    window.remove(cx);
+                    window
+                        .update(cx, |_, cx| {
+                            // todo!()
+                            cx.remove_window();
+                        })
+                        .ok();
                 }
             }
         }
@@ -102,116 +117,60 @@ impl ProjectSharedNotification {
         }
     }
 
-    fn render_owner(&self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-        let theme = &theme::current(cx).project_shared_notification;
-        Flex::row()
-            .with_children(self.owner.avatar.clone().map(|avatar| {
-                Image::from_data(avatar)
-                    .with_style(theme.owner_avatar)
-                    .aligned()
-            }))
-            .with_child(
-                Flex::column()
-                    .with_child(
-                        Label::new(
-                            self.owner.github_login.clone(),
-                            theme.owner_username.text.clone(),
-                        )
-                        .contained()
-                        .with_style(theme.owner_username.container),
-                    )
-                    .with_child(
-                        Label::new(
-                            format!(
-                                "is sharing a project in Zed{}",
-                                if self.worktree_root_names.is_empty() {
-                                    ""
-                                } else {
-                                    ":"
-                                }
-                            ),
-                            theme.message.text.clone(),
-                        )
-                        .contained()
-                        .with_style(theme.message.container),
-                    )
-                    .with_children(if self.worktree_root_names.is_empty() {
+    fn render_owner(&self) -> impl Element {
+        h_stack()
+            .children(
+                self.owner
+                    .avatar
+                    .clone()
+                    .map(|avatar| Avatar::data(avatar.clone())),
+            )
+            .child(
+                v_stack()
+                    .child(Label::new(self.owner.github_login.clone()))
+                    .child(Label::new(format!(
+                        "is sharing a project in Zed{}",
+                        if self.worktree_root_names.is_empty() {
+                            ""
+                        } else {
+                            ":"
+                        }
+                    )))
+                    .children(if self.worktree_root_names.is_empty() {
                         None
                     } else {
-                        Some(
-                            Label::new(
-                                self.worktree_root_names.join(", "),
-                                theme.worktree_roots.text.clone(),
-                            )
-                            .contained()
-                            .with_style(theme.worktree_roots.container),
-                        )
-                    })
-                    .contained()
-                    .with_style(theme.owner_metadata)
-                    .aligned(),
+                        Some(Label::new(self.worktree_root_names.join(", ")))
+                    }),
             )
-            .contained()
-            .with_style(theme.owner_container)
-            .flex(1., true)
-            .into_any()
     }
 
-    fn render_buttons(&self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-        enum Open {}
-        enum Dismiss {}
-
-        let theme = theme::current(cx);
-        Flex::column()
-            .with_child(
-                MouseEventHandler::new::<Open, _>(0, cx, |_, _| {
-                    let theme = &theme.project_shared_notification;
-                    Label::new("Open", theme.open_button.text.clone())
-                        .aligned()
-                        .contained()
-                        .with_style(theme.open_button.container)
-                })
-                .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(MouseButton::Left, move |_, this, cx| this.join(cx))
-                .flex(1., true),
-            )
-            .with_child(
-                MouseEventHandler::new::<Dismiss, _>(0, cx, |_, _| {
-                    let theme = &theme.project_shared_notification;
-                    Label::new("Dismiss", theme.dismiss_button.text.clone())
-                        .aligned()
-                        .contained()
-                        .with_style(theme.dismiss_button.container)
-                })
-                .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(MouseButton::Left, |_, this, cx| {
-                    this.dismiss(cx);
-                })
-                .flex(1., true),
+    fn render_buttons(&self, cx: &mut ViewContext<Self>) -> impl Element {
+        let this = cx.view().clone();
+        v_stack()
+            .child(Button::new("open", "Open").render(cx).on_click({
+                let this = this.clone();
+                move |_, cx| {
+                    this.update(cx, |this, cx| this.join(cx));
+                }
+            }))
+            .child(
+                Button::new("dismiss", "Dismiss")
+                    .render(cx)
+                    .on_click(move |_, cx| {
+                        this.update(cx, |this, cx| this.dismiss(cx));
+                    }),
             )
-            .constrained()
-            .with_width(theme.project_shared_notification.button_width)
-            .into_any()
     }
 }
 
-impl Entity for ProjectSharedNotification {
-    type Event = ();
-}
-
-impl View for ProjectSharedNotification {
-    fn ui_name() -> &'static str {
-        "ProjectSharedNotification"
-    }
+impl Render for ProjectSharedNotification {
+    type Element = Div;
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::AnyElement<Self> {
-        let background = theme::current(cx).project_shared_notification.background;
-        Flex::row()
-            .with_child(self.render_owner(cx))
-            .with_child(self.render_buttons(cx))
-            .contained()
-            .with_background_color(background)
-            .expanded()
-            .into_any()
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        h_stack()
+            .size_full()
+            .bg(gpui::red())
+            .child(self.render_owner())
+            .child(self.render_buttons(cx))
     }
 }