Send `LeaveProject` when waiting room is dismissed while waiting

Antonio Scandurra created

Change summary

crates/contacts_panel/src/contacts_panel.rs            |   8 
crates/contacts_panel/src/join_project_notification.rs |  10 
crates/workspace/src/waiting_room.rs                   | 118 ++++++-----
3 files changed, 82 insertions(+), 54 deletions(-)

Detailed changes

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -133,8 +133,12 @@ impl ContactsPanel {
                                 if let Some(workspace) = workspace.upgrade(cx) {
                                     workspace.update(cx, |workspace, cx| {
                                         workspace.show_notification(
-                                            cx.add_view(|_| {
-                                                JoinProjectNotification::new(project, user.clone())
+                                            cx.add_view(|cx| {
+                                                JoinProjectNotification::new(
+                                                    project,
+                                                    user.clone(),
+                                                    cx,
+                                                )
                                             }),
                                             cx,
                                         )

crates/contacts_panel/src/join_project_notification.rs 🔗

@@ -25,7 +25,15 @@ pub struct JoinProjectNotification {
 }
 
 impl JoinProjectNotification {
-    pub fn new(project: ModelHandle<Project>, user: Arc<User>) -> Self {
+    pub fn new(project: ModelHandle<Project>, user: Arc<User>, cx: &mut ViewContext<Self>) -> Self {
+        cx.subscribe(&project, |this, _, event, cx| {
+            if let project::Event::ContactCancelledJoinRequest(user) = event {
+                if *user == this.user {
+                    cx.emit(Event::Dismiss);
+                }
+            }
+        })
+        .detach();
         Self { project, user }
     }
 

crates/workspace/src/waiting_room.rs 🔗

@@ -3,25 +3,35 @@ use crate::{
     AppState,
 };
 use anyhow::Result;
-use client::Contact;
-use gpui::{elements::*, ElementBox, Entity, ImageData, RenderContext, Task, View, ViewContext};
+use client::{proto, Client, Contact};
+use gpui::{
+    elements::*, ElementBox, Entity, ImageData, MutableAppContext, RenderContext, Task, View,
+    ViewContext,
+};
 use project::Project;
 use settings::Settings;
 use std::sync::Arc;
+use util::ResultExt;
 
 pub struct WaitingRoom {
+    project_id: u64,
     avatar: Option<Arc<ImageData>>,
     message: String,
-    joined: bool,
+    waiting: bool,
+    client: Arc<Client>,
     _join_task: Task<Result<()>>,
 }
 
 impl Entity for WaitingRoom {
     type Event = ();
 
-    fn release(&mut self, _: &mut gpui::MutableAppContext) {
-        if !self.joined {
-            // TODO: Cancel the join request
+    fn release(&mut self, _: &mut MutableAppContext) {
+        if self.waiting {
+            self.client
+                .send(proto::LeaveProject {
+                    project_id: self.project_id,
+                })
+                .log_err();
         }
     }
 }
@@ -66,7 +76,7 @@ impl WaitingRoom {
         cx: &mut ViewContext<Self>,
     ) -> Self {
         let project_id = contact.projects[project_index].id;
-
+        let client = app_state.client.clone();
         let _join_task = cx.spawn_weak({
             let contact = contact.clone();
             |this, mut cx| async move {
@@ -81,47 +91,50 @@ impl WaitingRoom {
                 .await;
 
                 if let Some(this) = this.upgrade(&cx) {
-                    this.update(&mut cx, |this, cx| match project {
-                        Ok(project) => {
-                            this.joined = true;
-                            cx.replace_root_view(|cx| {
-                                let mut workspace =
-                                    (app_state.build_workspace)(project, &app_state, cx);
-                                workspace.toggle_sidebar_item(
-                                    &ToggleSidebarItem {
-                                        side: Side::Left,
-                                        item_index: 0,
-                                    },
-                                    cx,
-                                );
-                                workspace
-                            });
-                        }
-                        Err(error @ _) => {
-                            let login = &contact.user.github_login;
-                            let message = match error {
-                                project::JoinProjectError::HostDeclined => {
-                                    format!("@{} declined your request.", login)
-                                }
-                                project::JoinProjectError::HostClosedProject => {
-                                    format!(
-                                        "@{} closed their copy of {}.",
-                                        login,
-                                        humanize_list(
-                                            &contact.projects[project_index].worktree_root_names
+                    this.update(&mut cx, |this, cx| {
+                        this.waiting = false;
+                        match project {
+                            Ok(project) => {
+                                cx.replace_root_view(|cx| {
+                                    let mut workspace =
+                                        (app_state.build_workspace)(project, &app_state, cx);
+                                    workspace.toggle_sidebar_item(
+                                        &ToggleSidebarItem {
+                                            side: Side::Left,
+                                            item_index: 0,
+                                        },
+                                        cx,
+                                    );
+                                    workspace
+                                });
+                            }
+                            Err(error @ _) => {
+                                let login = &contact.user.github_login;
+                                let message = match error {
+                                    project::JoinProjectError::HostDeclined => {
+                                        format!("@{} declined your request.", login)
+                                    }
+                                    project::JoinProjectError::HostClosedProject => {
+                                        format!(
+                                            "@{} closed their copy of {}.",
+                                            login,
+                                            humanize_list(
+                                                &contact.projects[project_index]
+                                                    .worktree_root_names
+                                            )
                                         )
-                                    )
-                                }
-                                project::JoinProjectError::HostWentOffline => {
-                                    format!("@{} went offline.", login)
-                                }
-                                project::JoinProjectError::Other(error) => {
-                                    log::error!("error joining project: {}", error);
-                                    "An error occurred.".to_string()
-                                }
-                            };
-                            this.message = message;
-                            cx.notify();
+                                    }
+                                    project::JoinProjectError::HostWentOffline => {
+                                        format!("@{} went offline.", login)
+                                    }
+                                    project::JoinProjectError::Other(error) => {
+                                        log::error!("error joining project: {}", error);
+                                        "An error occurred.".to_string()
+                                    }
+                                };
+                                this.message = message;
+                                cx.notify();
+                            }
                         }
                     })
                 }
@@ -131,13 +144,15 @@ impl WaitingRoom {
         });
 
         Self {
+            project_id,
             avatar: contact.user.avatar.clone(),
             message: format!(
                 "Asking to join @{}'s copy of {}...",
                 contact.user.github_login,
                 humanize_list(&contact.projects[project_index].worktree_root_names)
             ),
-            joined: false,
+            waiting: true,
+            client,
             _join_task,
         }
     }
@@ -149,10 +164,11 @@ fn humanize_list<'a>(items: impl IntoIterator<Item = &'a String>) -> String {
     while let Some((ix, item)) = items.next() {
         if ix > 0 {
             list.push_str(", ");
+            if items.peek().is_none() {
+                list.push_str("and ");
+            }
         }
-        if items.peek().is_none() {
-            list.push_str("and ");
-        }
+
         list.push_str(item);
     }
     list