From 5210be95feeb75ae801d90cbf354e2dd8c95ddd9 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 28 Feb 2023 22:11:58 -0800 Subject: [PATCH] Added welcome experience sketch Made toolbar hideable --- crates/db/src/db.rs | 11 +++++++++ crates/welcome/src/welcome.rs | 8 +++++-- crates/workspace/src/dock.rs | 40 +++++++++++++++++++------------ crates/workspace/src/item.rs | 8 +++++++ crates/workspace/src/pane.rs | 7 +++--- crates/workspace/src/toolbar.rs | 12 ++++++++++ crates/workspace/src/workspace.rs | 29 +++++++++++----------- crates/zed/src/zed.rs | 37 +++++++++++++++------------- styles/src/styleTree/workspace.ts | 2 +- 9 files changed, 103 insertions(+), 51 deletions(-) diff --git a/crates/db/src/db.rs b/crates/db/src/db.rs index f4d0dc1a46..989dcf0af5 100644 --- a/crates/db/src/db.rs +++ b/crates/db/src/db.rs @@ -4,6 +4,7 @@ pub mod query; // Re-export pub use anyhow; use anyhow::Context; +use gpui::MutableAppContext; pub use indoc::indoc; pub use lazy_static; use parking_lot::{Mutex, RwLock}; @@ -17,6 +18,7 @@ use sqlez::domain::Migrator; use sqlez::thread_safe_connection::ThreadSafeConnection; use sqlez_macros::sql; use std::fs::create_dir_all; +use std::future::Future; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; @@ -237,6 +239,15 @@ macro_rules! define_connection { }; } +pub fn write_and_log(cx: &mut MutableAppContext, db_write: impl FnOnce() -> F + Send + 'static) +where + F: Future> + Send, +{ + cx.background() + .spawn(async move { db_write().await.log_err() }) + .detach() +} + #[cfg(test)] mod tests { use std::{fs, thread}; diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 6985b70069..5a166218ce 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -14,7 +14,7 @@ pub fn init(cx: &mut MutableAppContext) { }) } -struct WelcomePage { +pub struct WelcomePage { _settings_subscription: Subscription, } @@ -98,7 +98,7 @@ impl View for WelcomePage { } impl WelcomePage { - fn new(cx: &mut ViewContext) -> Self { + pub fn new(cx: &mut ViewContext) -> Self { let handle = cx.weak_handle(); let settings_subscription = cx.observe_global::(move |cx| { @@ -163,4 +163,8 @@ impl Item for WelcomePage { ) .boxed() } + + fn show_toolbar(&self) -> bool { + false + } } diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 2bd8808281..4281c04649 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -39,20 +39,24 @@ impl_internal_actions!(dock, [MoveDock, AddDefaultItemToDock]); pub fn init(cx: &mut MutableAppContext) { cx.add_action(Dock::focus_dock); cx.add_action(Dock::hide_dock); - cx.add_action(Dock::move_dock); + cx.add_action( + |workspace: &mut Workspace, &MoveDock(dock_anchor), cx: &mut ViewContext| { + Dock::move_dock(workspace, dock_anchor, true, cx); + }, + ); cx.add_action( |workspace: &mut Workspace, _: &AnchorDockRight, cx: &mut ViewContext| { - Dock::move_dock(workspace, &MoveDock(DockAnchor::Right), cx) + Dock::move_dock(workspace, DockAnchor::Right, true, cx); }, ); cx.add_action( |workspace: &mut Workspace, _: &AnchorDockBottom, cx: &mut ViewContext| { - Dock::move_dock(workspace, &MoveDock(DockAnchor::Bottom), cx) + Dock::move_dock(workspace, DockAnchor::Bottom, true, cx) }, ); cx.add_action( |workspace: &mut Workspace, _: &ExpandDock, cx: &mut ViewContext| { - Dock::move_dock(workspace, &MoveDock(DockAnchor::Expanded), cx) + Dock::move_dock(workspace, DockAnchor::Expanded, true, cx) }, ); cx.add_action( @@ -215,6 +219,7 @@ impl Dock { pub(crate) fn set_dock_position( workspace: &mut Workspace, new_position: DockPosition, + focus: bool, cx: &mut ViewContext, ) { workspace.dock.position = new_position; @@ -235,19 +240,23 @@ impl Dock { let pane = workspace.dock.pane.clone(); if pane.read(cx).items().next().is_none() { if let Some(item_to_add) = (workspace.dock.default_item_factory)(workspace, cx) { - Pane::add_item(workspace, &pane, item_to_add, true, true, None, cx); + Pane::add_item(workspace, &pane, item_to_add, focus, focus, None, cx); } else { workspace.dock.position = workspace.dock.position.hide(); } } else { - cx.focus(pane); + if focus { + cx.focus(pane); + } } } else if let Some(last_active_center_pane) = workspace .last_active_center_pane .as_ref() .and_then(|pane| pane.upgrade(cx)) { - cx.focus(last_active_center_pane); + if focus { + cx.focus(last_active_center_pane); + } } cx.emit(crate::Event::DockAnchorChanged); workspace.serialize_workspace(cx); @@ -255,11 +264,11 @@ impl Dock { } pub fn hide(workspace: &mut Workspace, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.hide(), cx); + Self::set_dock_position(workspace, workspace.dock.position.hide(), true, cx); } - pub fn show(workspace: &mut Workspace, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.show(), cx); + pub fn show(workspace: &mut Workspace, focus: bool, cx: &mut ViewContext) { + Self::set_dock_position(workspace, workspace.dock.position.show(), focus, cx); } pub fn hide_on_sidebar_shown( @@ -275,19 +284,20 @@ impl Dock { } fn focus_dock(workspace: &mut Workspace, _: &FocusDock, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.show(), cx); + Self::set_dock_position(workspace, workspace.dock.position.show(), true, cx); } fn hide_dock(workspace: &mut Workspace, _: &HideDock, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.hide(), cx); + Self::set_dock_position(workspace, workspace.dock.position.hide(), true, cx); } - fn move_dock( + pub fn move_dock( workspace: &mut Workspace, - &MoveDock(new_anchor): &MoveDock, + new_anchor: DockAnchor, + focus: bool, cx: &mut ViewContext, ) { - Self::set_dock_position(workspace, DockPosition::Shown(new_anchor), cx); + Self::set_dock_position(workspace, DockPosition::Shown(new_anchor), focus, cx); } pub fn render( diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index a80b9f8d83..b55c9942f8 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -151,6 +151,9 @@ pub trait Item: View { "deserialize() must be implemented if serialized_item_kind() returns Some(_)" ) } + fn show_toolbar(&self) -> bool { + true + } } pub trait ItemHandle: 'static + fmt::Debug { @@ -213,6 +216,7 @@ pub trait ItemHandle: 'static + fmt::Debug { fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation; fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option>; fn serialized_item_kind(&self) -> Option<&'static str>; + fn show_toolbar(&self, cx: &AppContext) -> bool; } pub trait WeakItemHandle { @@ -591,6 +595,10 @@ impl ItemHandle for ViewHandle { fn serialized_item_kind(&self) -> Option<&'static str> { T::serialized_item_kind() } + + fn show_toolbar(&self, cx: &AppContext) -> bool { + self.read(cx).show_toolbar() + } } impl From> for AnyViewHandle { diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 98fcac664c..235df0202d 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1485,11 +1485,12 @@ impl View for Pane { cx, { let toolbar = self.toolbar.clone(); + let toolbar_hidden = toolbar.read(cx).hidden(); move |_, cx| { Flex::column() - .with_child( - ChildView::new(&toolbar, cx).expanded().boxed(), - ) + .with_children((!toolbar_hidden).then(|| { + ChildView::new(&toolbar, cx).expanded().boxed() + })) .with_child( ChildView::new(active_item, cx) .flex(1., true) diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 7443f19003..df10db91a0 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -42,6 +42,7 @@ pub enum ToolbarItemLocation { pub struct Toolbar { active_pane_item: Option>, + hidden: bool, pane: WeakViewHandle, items: Vec<(Box, ToolbarItemLocation)>, } @@ -211,6 +212,7 @@ impl Toolbar { active_pane_item: None, pane, items: Default::default(), + hidden: false, } } @@ -243,6 +245,12 @@ impl Toolbar { cx: &mut ViewContext, ) { self.active_pane_item = pane_item.map(|item| item.boxed_clone()); + self.hidden = self + .active_pane_item + .as_ref() + .map(|item| !item.show_toolbar(cx)) + .unwrap_or(false); + for (toolbar_item, current_location) in self.items.iter_mut() { let new_location = toolbar_item.set_active_pane_item(pane_item, cx); if new_location != *current_location { @@ -257,6 +265,10 @@ impl Toolbar { .iter() .find_map(|(item, _)| item.to_any().downcast()) } + + pub fn hidden(&self) -> bool { + self.hidden + } } impl ToolbarItemViewHandle for ViewHandle { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 31960fbc1e..442d28579f 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -197,20 +197,12 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { } } }); - cx.add_global_action({ - let app_state = Arc::downgrade(&app_state); - move |_: &Welcome, cx: &mut MutableAppContext| { - if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, cx).detach(); - } - } - }); cx.add_global_action({ let app_state = Arc::downgrade(&app_state); move |_: &NewWindow, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, cx).detach(); + open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile)).detach(); } } }); @@ -1514,7 +1506,7 @@ impl Workspace { self.active_item_path_changed(cx); if &pane == self.dock_pane() { - Dock::show(self, cx); + Dock::show(self, true, cx); } else { self.last_active_center_pane = Some(pane.downgrade()); if self.dock.is_anchored_at(DockAnchor::Expanded) { @@ -2527,7 +2519,12 @@ impl Workspace { // the focus the dock generates start generating alternating // focus due to the deferred execution each triggering each other cx.after_window_update(move |workspace, cx| { - Dock::set_dock_position(workspace, serialized_workspace.dock_position, cx); + Dock::set_dock_position( + workspace, + serialized_workspace.dock_position, + true, + cx, + ); }); cx.notify(); @@ -2859,14 +2856,18 @@ pub fn open_paths( }) } -pub fn open_new(app_state: &Arc, cx: &mut MutableAppContext) -> Task<()> { +pub fn open_new( + app_state: &Arc, + cx: &mut MutableAppContext, + init: impl FnOnce(&mut Workspace, &mut ViewContext) + 'static, +) -> Task<()> { let task = Workspace::new_local(Vec::new(), app_state.clone(), cx); cx.spawn(|mut cx| async move { let (workspace, opened_paths) = task.await; - workspace.update(&mut cx, |_, cx| { + workspace.update(&mut cx, |workspace, cx| { if opened_paths.is_empty() { - cx.dispatch_action(Welcome); + init(workspace, cx) } }) }) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 75cdf0e687..5d13d41bba 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -35,7 +35,7 @@ use std::{borrow::Cow, env, path::Path, str, sync::Arc}; use util::{channel::ReleaseChannel, paths, ResultExt, StaffMode}; use uuid::Uuid; pub use workspace; -use workspace::{sidebar::SidebarSide, AppState, Restart, Welcome, Workspace}; +use workspace::{dock::Dock, open_new, sidebar::SidebarSide, AppState, Restart, Workspace}; pub const FIRST_OPEN: &str = "first_open"; @@ -256,23 +256,27 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { }, ); - cx.add_global_action(|_: &WelcomeExperience, cx| { - if !matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { - return; //noop, in case someone fires this from the command palette - } + cx.add_global_action({ + let app_state = app_state.clone(); + move |_: &WelcomeExperience, cx| { + if !matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { + return; //noop, in case someone fires this from the command palette + } - // Make a workspace, set it up with an open bottom dock and the welcome page - - cx.dispatch_global_action(Welcome); - - cx.background() - .spawn(async move { - KEY_VALUE_STORE - .write_kvp(FIRST_OPEN.to_string(), "false".to_string()) - .await - .log_err(); + open_new(&app_state, cx, |workspace, cx| { + workspace.toggle_sidebar(SidebarSide::Left, cx); + let welcome_page = cx.add_view(|cx| welcome::WelcomePage::new(cx)); + workspace.add_item(Box::new(welcome_page.clone()), cx); + Dock::move_dock(workspace, settings::DockAnchor::Bottom, false, cx); + cx.focus(welcome_page); + cx.notify(); }) .detach(); + + db::write_and_log(cx, || { + KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string()) + }); + } }); activity_indicator::init(cx); @@ -881,7 +885,8 @@ mod tests { #[gpui::test] async fn test_new_empty_workspace(cx: &mut TestAppContext) { let app_state = init(cx); - cx.update(|cx| open_new(&app_state, cx)).await; + cx.update(|cx| open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile))) + .await; let window_id = *cx.window_ids().first().unwrap(); let workspace = cx.root_view::(window_id).unwrap(); diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index f9f49e3c7d..c758e0227e 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -248,7 +248,7 @@ export default function workspace(colorScheme: ColorScheme) { }, dock: { initialSizeRight: 640, - initialSizeBottom: 480, + initialSizeBottom: 300, wash_color: withOpacity(background(colorScheme.highest), 0.5), panel: { border: border(colorScheme.middle),