From 29c3b81a0a6d8fd1994d827ed979a5ee5f83809d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 11 Oct 2022 14:52:47 +0200 Subject: [PATCH] Show prompt when closing last window while there's an active call Co-Authored-By: Nathan Sobo --- crates/gpui/src/app.rs | 10 ++++ crates/workspace/src/workspace.rs | 46 ++++++++++++++++--- crates/zed/src/zed.rs | 4 +- .../src/styleTree/incomingCallNotification.ts | 2 +- 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index f55dd2b464..765501368c 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -794,6 +794,16 @@ impl AsyncAppContext { self.update(|cx| cx.activate_window(window_id)) } + pub fn prompt( + &mut self, + window_id: usize, + level: PromptLevel, + msg: &str, + answers: &[&str], + ) -> oneshot::Receiver { + self.update(|cx| cx.prompt(window_id, level, msg, answers)) + } + pub fn platform(&self) -> Arc { self.0.borrow().platform() } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index db9ac3a0c6..6472a6f697 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -17,7 +17,7 @@ use client::{proto, Client, PeerId, TypedEnvelope, UserStore}; use collections::{hash_map, HashMap, HashSet}; use dock::{DefaultItemFactory, Dock, ToggleDockButton}; use drag_and_drop::DragAndDrop; -use futures::{channel::oneshot, FutureExt}; +use futures::{channel::oneshot, FutureExt, StreamExt}; use gpui::{ actions, elements::*, @@ -1231,7 +1231,7 @@ impl Workspace { _: &CloseWindow, cx: &mut ViewContext, ) -> Option>> { - let prepare = self.prepare_to_close(cx); + let prepare = self.prepare_to_close(false, cx); Some(cx.spawn(|this, mut cx| async move { if prepare.await? { this.update(&mut cx, |_, cx| { @@ -1243,8 +1243,42 @@ impl Workspace { })) } - pub fn prepare_to_close(&mut self, cx: &mut ViewContext) -> Task> { - self.save_all_internal(true, cx) + pub fn prepare_to_close( + &mut self, + quitting: bool, + cx: &mut ViewContext, + ) -> Task> { + let active_call = ActiveCall::global(cx); + let window_id = cx.window_id(); + let workspace_count = cx + .window_ids() + .flat_map(|window_id| cx.root_view::(window_id)) + .count(); + cx.spawn(|this, mut cx| async move { + if !quitting + && workspace_count == 1 + && active_call.read_with(&cx, |call, _| call.room().is_some()) + { + let answer = cx + .prompt( + window_id, + PromptLevel::Warning, + "Do you want to leave the current call?", + &["Close window and hang up", "Cancel"], + ) + .next() + .await; + if answer == Some(1) { + return anyhow::Ok(false); + } else { + active_call.update(&mut cx, |call, cx| call.hang_up(cx))?; + } + } + + Ok(this + .update(&mut cx, |this, cx| this.save_all_internal(true, cx)) + .await?) + }) } fn save_all(&mut self, _: &SaveAll, cx: &mut ViewContext) -> Option>> { @@ -2944,7 +2978,7 @@ mod tests { // When there are no dirty items, there's nothing to do. let item1 = cx.add_view(&workspace, |_| TestItem::new()); workspace.update(cx, |w, cx| w.add_item(Box::new(item1.clone()), cx)); - let task = workspace.update(cx, |w, cx| w.prepare_to_close(cx)); + let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx)); assert!(task.await.unwrap()); // When there are dirty untitled items, prompt to save each one. If the user @@ -2964,7 +2998,7 @@ mod tests { w.add_item(Box::new(item2.clone()), cx); w.add_item(Box::new(item3.clone()), cx); }); - let task = workspace.update(cx, |w, cx| w.prepare_to_close(cx)); + let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx)); cx.foreground().run_until_parked(); cx.simulate_prompt_answer(window_id, 2 /* cancel */); cx.foreground().run_until_parked(); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index be3d0cfb88..d032e661d7 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -344,7 +344,9 @@ fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) { // If the user cancels any save prompt, then keep the app open. for workspace in workspaces { if !workspace - .update(&mut cx, |workspace, cx| workspace.prepare_to_close(cx)) + .update(&mut cx, |workspace, cx| { + workspace.prepare_to_close(true, cx) + }) .await? { return Ok(()); diff --git a/styles/src/styleTree/incomingCallNotification.ts b/styles/src/styleTree/incomingCallNotification.ts index 30b8ae90ca..55f5cc80fd 100644 --- a/styles/src/styleTree/incomingCallNotification.ts +++ b/styles/src/styleTree/incomingCallNotification.ts @@ -2,7 +2,7 @@ import Theme from "../themes/common/theme"; import { backgroundColor, borderColor, text } from "./components"; export default function incomingCallNotification(theme: Theme): Object { - const avatarSize = 32; + const avatarSize = 48; return { windowHeight: 74, windowWidth: 380,