diff --git a/crates/recent_projects/src/disconnected_overlay.rs b/crates/recent_projects/src/disconnected_overlay.rs index bba61757c6..09342c1d3c 100644 --- a/crates/recent_projects/src/disconnected_overlay.rs +++ b/crates/recent_projects/src/disconnected_overlay.rs @@ -2,6 +2,7 @@ use std::path::PathBuf; use dev_server_projects::DevServer; use gpui::{ClickEvent, DismissEvent, EventEmitter, FocusHandle, FocusableView, Render, WeakView}; +use project::project_settings::ProjectSettings; use remote::SshConnectionOptions; use settings::Settings; use ui::{ @@ -26,6 +27,7 @@ pub struct DisconnectedOverlay { workspace: WeakView, host: Host, focus_handle: FocusHandle, + finished: bool, } impl EventEmitter for DisconnectedOverlay {} @@ -35,6 +37,9 @@ impl FocusableView for DisconnectedOverlay { } } impl ModalView for DisconnectedOverlay { + fn on_before_dismiss(&mut self, _: &mut ViewContext) -> workspace::DismissDecision { + return workspace::DismissDecision::Dismiss(self.finished); + } fn fade_out_background(&self) -> bool { true } @@ -70,6 +75,7 @@ impl DisconnectedOverlay { }; workspace.toggle_modal(cx, |cx| DisconnectedOverlay { + finished: false, workspace: handle, host, focus_handle: cx.focus_handle(), @@ -79,6 +85,7 @@ impl DisconnectedOverlay { } fn handle_reconnect(&mut self, _: &ClickEvent, cx: &mut ViewContext) { + self.finished = true; cx.emit(DismissEvent); match &self.host { @@ -186,6 +193,7 @@ impl DisconnectedOverlay { } fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext) { + self.finished = true; cx.emit(DismissEvent) } } @@ -202,9 +210,17 @@ impl Render for DisconnectedOverlay { "Your connection to the remote project has been lost.".to_string() } Host::SshRemoteProject(options) => { + let autosave = if ProjectSettings::get_global(cx) + .session + .restore_unsaved_buffers + { + "\nUnsaved changes are stored locally." + } else { + "" + }; format!( - "Your connection to {} has been lost", - options.connection_string() + "Your connection to {} has been lost.{}", + options.host, autosave ) } }; diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index d1e00632da..037d6658db 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -31,7 +31,7 @@ use futures::{ }; use gpui::{ action_as, actions, canvas, impl_action_as, impl_actions, point, relative, size, - transparent_black, Action, AnyElement, AnyView, AnyWeakView, AppContext, AsyncAppContext, + transparent_black, Action, AnyView, AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, CursorStyle, Decorations, DragMoveEvent, Entity as _, EntityId, EventEmitter, Flatten, FocusHandle, FocusableView, Global, Hsla, KeyContext, Keystroke, ManagedView, Model, ModelContext, MouseButton, PathPromptOptions, Point, PromptLevel, Render, @@ -762,8 +762,6 @@ pub struct Workspace { bounds_save_task_queued: Option>, on_prompt_for_new_path: Option, on_prompt_for_open_path: Option, - render_disconnected_overlay: - Option) -> AnyElement>>, serializable_items_tx: UnboundedSender>, serialized_ssh_project: Option, _items_serializer: Task>, @@ -1067,7 +1065,6 @@ impl Workspace { bounds_save_task_queued: None, on_prompt_for_new_path: None, on_prompt_for_open_path: None, - render_disconnected_overlay: None, serializable_items_tx, _items_serializer, session_id: Some(session_id), @@ -1472,13 +1469,6 @@ impl Workspace { self.serialized_ssh_project = Some(serialized_ssh_project); } - pub fn set_render_disconnected_overlay( - &mut self, - render: impl Fn(&mut Self, &mut ViewContext) -> AnyElement + 'static, - ) { - self.render_disconnected_overlay = Some(Box::new(render)) - } - pub fn prompt_for_open_path( &mut self, path_prompt_options: PathPromptOptions, @@ -4746,130 +4736,158 @@ impl Render for Workspace { .children(self.titlebar_item.clone()) .child( div() - .id("workspace") - .bg(colors.background) + .size_full() .relative() .flex_1() - .w_full() .flex() .flex_col() - .overflow_hidden() - .border_t_1() - .border_b_1() - .border_color(colors.border) - .child({ - let this = cx.view().clone(); - canvas( - move |bounds, cx| this.update(cx, |this, _cx| this.bounds = bounds), - |_, _, _| {}, - ) - .absolute() - .size_full() - }) - .when(self.zoomed.is_none(), |this| { - this.on_drag_move(cx.listener( - |workspace, e: &DragMoveEvent, cx| match e.drag(cx).0 { - DockPosition::Left => { - let size = e.event.position.x - workspace.bounds.left(); - workspace.left_dock.update(cx, |left_dock, cx| { - left_dock.resize_active_panel(Some(size), cx); - }); - } - DockPosition::Right => { - let size = workspace.bounds.right() - e.event.position.x; - workspace.right_dock.update(cx, |right_dock, cx| { - right_dock.resize_active_panel(Some(size), cx); - }); - } - DockPosition::Bottom => { - let size = workspace.bounds.bottom() - e.event.position.y; - workspace.bottom_dock.update(cx, |bottom_dock, cx| { - bottom_dock.resize_active_panel(Some(size), cx); - }); - } - }, - )) - }) .child( div() + .id("workspace") + .bg(colors.background) + .relative() + .flex_1() + .w_full() .flex() - .flex_row() - .h_full() - // Left Dock - .children(self.render_dock(DockPosition::Left, &self.left_dock, cx)) - // Panes + .flex_col() + .overflow_hidden() + .border_t_1() + .border_b_1() + .border_color(colors.border) + .child({ + let this = cx.view().clone(); + canvas( + move |bounds, cx| { + this.update(cx, |this, _cx| this.bounds = bounds) + }, + |_, _, _| {}, + ) + .absolute() + .size_full() + }) + .when(self.zoomed.is_none(), |this| { + this.on_drag_move(cx.listener( + |workspace, e: &DragMoveEvent, cx| { + match e.drag(cx).0 { + DockPosition::Left => { + let size = e.event.position.x + - workspace.bounds.left(); + workspace.left_dock.update( + cx, + |left_dock, cx| { + left_dock.resize_active_panel( + Some(size), + cx, + ); + }, + ); + } + DockPosition::Right => { + let size = workspace.bounds.right() + - e.event.position.x; + workspace.right_dock.update( + cx, + |right_dock, cx| { + right_dock.resize_active_panel( + Some(size), + cx, + ); + }, + ); + } + DockPosition::Bottom => { + let size = workspace.bounds.bottom() + - e.event.position.y; + workspace.bottom_dock.update( + cx, + |bottom_dock, cx| { + bottom_dock.resize_active_panel( + Some(size), + cx, + ); + }, + ); + } + } + }, + )) + }) .child( div() .flex() - .flex_col() - .flex_1() - .overflow_hidden() - .child( - h_flex() - .flex_1() - .when_some(paddings.0, |this, p| { - this.child(p.border_r_1()) - }) - .child(self.center.render( - &self.project, - &self.follower_states, - self.active_call(), - &self.active_pane, - self.zoomed.as_ref(), - &self.app_state, - cx, - )) - .when_some(paddings.1, |this, p| { - this.child(p.border_l_1()) - }), - ) + .flex_row() + .h_full() + // Left Dock .children(self.render_dock( - DockPosition::Bottom, - &self.bottom_dock, + DockPosition::Left, + &self.left_dock, + cx, + )) + // Panes + .child( + div() + .flex() + .flex_col() + .flex_1() + .overflow_hidden() + .child( + h_flex() + .flex_1() + .when_some(paddings.0, |this, p| { + this.child(p.border_r_1()) + }) + .child(self.center.render( + &self.project, + &self.follower_states, + self.active_call(), + &self.active_pane, + self.zoomed.as_ref(), + &self.app_state, + cx, + )) + .when_some(paddings.1, |this, p| { + this.child(p.border_l_1()) + }), + ) + .children(self.render_dock( + DockPosition::Bottom, + &self.bottom_dock, + cx, + )), + ) + // Right Dock + .children(self.render_dock( + DockPosition::Right, + &self.right_dock, cx, )), ) - // Right Dock - .children(self.render_dock( - DockPosition::Right, - &self.right_dock, - cx, - )), - ) - .children(self.zoomed.as_ref().and_then(|view| { - let zoomed_view = view.upgrade()?; - let div = div() - .occlude() - .absolute() - .overflow_hidden() - .border_color(colors.border) - .bg(colors.background) - .child(zoomed_view) - .inset_0() - .shadow_lg(); + .children(self.zoomed.as_ref().and_then(|view| { + let zoomed_view = view.upgrade()?; + let div = div() + .occlude() + .absolute() + .overflow_hidden() + .border_color(colors.border) + .bg(colors.background) + .child(zoomed_view) + .inset_0() + .shadow_lg(); - Some(match self.zoomed_position { - Some(DockPosition::Left) => div.right_2().border_r_1(), - Some(DockPosition::Right) => div.left_2().border_l_1(), - Some(DockPosition::Bottom) => div.top_2().border_t_1(), - None => div.top_2().bottom_2().left_2().right_2().border_1(), - }) - })) - .child(self.modal_layer.clone()) - .children(self.render_notifications(cx)), - ) - .child(self.status_bar.clone()) - .children(if self.project.read(cx).is_disconnected(cx) { - if let Some(render) = self.render_disconnected_overlay.take() { - let result = render(self, cx); - self.render_disconnected_overlay = Some(render); - Some(result) - } else { - None - } - } else { - None - }), + Some(match self.zoomed_position { + Some(DockPosition::Left) => div.right_2().border_r_1(), + Some(DockPosition::Right) => div.left_2().border_l_1(), + Some(DockPosition::Bottom) => div.top_2().border_t_1(), + None => { + div.top_2().bottom_2().left_2().right_2().border_1() + } + }) + })) + .children(self.render_notifications(cx)), + ) + .child(self.status_bar.clone()) + .child(self.modal_layer.clone()), + ), cx, ) }