gpui2: Notifications

This commit is contained in:
Conrad Irwin 2023-11-26 22:27:33 -07:00
parent 700168467e
commit 039c933d8e
11 changed files with 190 additions and 111 deletions

View File

@ -1,12 +1,13 @@
use gpui::{div, Div, EventEmitter, ParentElement, Render, SemanticVersion, ViewContext}; use gpui::{
div, DismissEvent, Div, EventEmitter, ParentElement, Render, SemanticVersion, ViewContext,
};
use menu::Cancel; use menu::Cancel;
use workspace::notifications::NotificationEvent;
pub struct UpdateNotification { pub struct UpdateNotification {
_version: SemanticVersion, _version: SemanticVersion,
} }
impl EventEmitter<NotificationEvent> for UpdateNotification {} impl EventEmitter<DismissEvent> for UpdateNotification {}
impl Render for UpdateNotification { impl Render for UpdateNotification {
type Element = Div; type Element = Div;
@ -82,6 +83,6 @@ impl UpdateNotification {
} }
pub fn _dismiss(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) { pub fn _dismiss(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
cx.emit(NotificationEvent::Dismiss); cx.emit(DismissEvent::Dismiss);
} }
} }

View File

@ -1,8 +1,9 @@
use collections::{CommandPaletteFilter, HashMap}; use collections::{CommandPaletteFilter, HashMap};
use fuzzy::{StringMatch, StringMatchCandidate}; use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{ use gpui::{
actions, div, prelude::*, Action, AppContext, Div, EventEmitter, FocusHandle, FocusableView, actions, div, prelude::*, Action, AppContext, DismissEvent, Div, EventEmitter, FocusHandle,
Keystroke, Manager, ParentElement, Render, Styled, View, ViewContext, VisualContext, WeakView, FocusableView, Keystroke, ParentElement, Render, Styled, View, ViewContext, VisualContext,
WeakView,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use std::{ use std::{
@ -68,7 +69,7 @@ impl CommandPalette {
} }
} }
impl EventEmitter<Manager> for CommandPalette {} impl EventEmitter<DismissEvent> for CommandPalette {}
impl FocusableView for CommandPalette { impl FocusableView for CommandPalette {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle { fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
@ -268,7 +269,7 @@ impl PickerDelegate for CommandPaletteDelegate {
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) { fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
self.command_palette self.command_palette
.update(cx, |_, cx| cx.emit(Manager::Dismiss)) .update(cx, |_, cx| cx.emit(DismissEvent::Dismiss))
.log_err(); .log_err();
} }

View File

@ -2,8 +2,8 @@ use collections::HashMap;
use editor::{scroll::autoscroll::Autoscroll, Bias, Editor}; use editor::{scroll::autoscroll::Autoscroll, Bias, Editor};
use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; use fuzzy::{CharBag, PathMatch, PathMatchCandidate};
use gpui::{ use gpui::{
actions, div, AppContext, Div, EventEmitter, FocusHandle, FocusableView, InteractiveElement, actions, div, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView,
IntoElement, Manager, Model, ParentElement, Render, Styled, Task, View, ViewContext, InteractiveElement, IntoElement, Model, ParentElement, Render, Styled, Task, View, ViewContext,
VisualContext, WeakView, VisualContext, WeakView,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
@ -111,7 +111,7 @@ impl FileFinder {
} }
} }
impl EventEmitter<Manager> for FileFinder {} impl EventEmitter<DismissEvent> for FileFinder {}
impl FocusableView for FileFinder { impl FocusableView for FileFinder {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle { fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
self.picker.focus_handle(cx) self.picker.focus_handle(cx)
@ -690,7 +690,7 @@ impl PickerDelegate for FileFinderDelegate {
} }
} }
finder finder
.update(&mut cx, |_, cx| cx.emit(Manager::Dismiss)) .update(&mut cx, |_, cx| cx.emit(DismissEvent::Dismiss))
.ok()?; .ok()?;
Some(()) Some(())
@ -702,7 +702,7 @@ impl PickerDelegate for FileFinderDelegate {
fn dismissed(&mut self, cx: &mut ViewContext<Picker<FileFinderDelegate>>) { fn dismissed(&mut self, cx: &mut ViewContext<Picker<FileFinderDelegate>>) {
self.file_finder self.file_finder
.update(cx, |_, cx| cx.emit(Manager::Dismiss)) .update(cx, |_, cx| cx.emit(DismissEvent::Dismiss))
.log_err(); .log_err();
} }

View File

@ -1,7 +1,8 @@
use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Editor}; use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Editor};
use gpui::{ use gpui::{
actions, div, prelude::*, AppContext, Div, EventEmitter, FocusHandle, FocusableView, Manager, actions, div, prelude::*, AppContext, DismissEvent, Div, EventEmitter, FocusHandle,
Render, SharedString, Styled, Subscription, View, ViewContext, VisualContext, WindowContext, FocusableView, Render, SharedString, Styled, Subscription, View, ViewContext, VisualContext,
WindowContext,
}; };
use text::{Bias, Point}; use text::{Bias, Point};
use theme::ActiveTheme; use theme::ActiveTheme;
@ -28,7 +29,7 @@ impl FocusableView for GoToLine {
self.active_editor.focus_handle(cx) self.active_editor.focus_handle(cx)
} }
} }
impl EventEmitter<Manager> for GoToLine {} impl EventEmitter<DismissEvent> for GoToLine {}
impl GoToLine { impl GoToLine {
fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) { fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
@ -88,7 +89,7 @@ impl GoToLine {
) { ) {
match event { match event {
// todo!() this isn't working... // todo!() this isn't working...
editor::EditorEvent::Blurred => cx.emit(Manager::Dismiss), editor::EditorEvent::Blurred => cx.emit(DismissEvent::Dismiss),
editor::EditorEvent::BufferEdited { .. } => self.highlight_current_line(cx), editor::EditorEvent::BufferEdited { .. } => self.highlight_current_line(cx),
_ => {} _ => {}
} }
@ -123,7 +124,7 @@ impl GoToLine {
} }
fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) { fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
cx.emit(Manager::Dismiss); cx.emit(DismissEvent::Dismiss);
} }
fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) { fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
@ -140,7 +141,7 @@ impl GoToLine {
self.prev_scroll_position.take(); self.prev_scroll_position.take();
} }
cx.emit(Manager::Dismiss); cx.emit(DismissEvent::Dismiss);
} }
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, FocusableView, AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, DismissEvent,
ForegroundExecutor, Manager, Model, ModelContext, Render, Result, Task, View, ViewContext, FocusableView, ForegroundExecutor, Model, ModelContext, Render, Result, Task, View,
VisualContext, WindowContext, WindowHandle, ViewContext, VisualContext, WindowContext, WindowHandle,
}; };
use anyhow::{anyhow, Context as _}; use anyhow::{anyhow, Context as _};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
@ -326,7 +326,7 @@ impl VisualContext for AsyncWindowContext {
V: crate::ManagedView, V: crate::ManagedView,
{ {
self.window.update(self, |_, cx| { self.window.update(self, |_, cx| {
view.update(cx, |_, cx| cx.emit(Manager::Dismiss)) view.update(cx, |_, cx| cx.emit(DismissEvent::Dismiss))
}) })
} }
} }

View File

@ -611,7 +611,7 @@ impl<'a> VisualContext for VisualTestContext<'a> {
{ {
self.window self.window
.update(self.cx, |_, cx| { .update(self.cx, |_, cx| {
view.update(cx, |_, cx| cx.emit(crate::Manager::Dismiss)) view.update(cx, |_, cx| cx.emit(crate::DismissEvent::Dismiss))
}) })
.unwrap() .unwrap()
} }

View File

@ -193,11 +193,11 @@ pub trait FocusableView: 'static + Render {
/// ManagedView is a view (like a Modal, Popover, Menu, etc.) /// ManagedView is a view (like a Modal, Popover, Menu, etc.)
/// where the lifecycle of the view is handled by another view. /// where the lifecycle of the view is handled by another view.
pub trait ManagedView: FocusableView + EventEmitter<Manager> {} pub trait ManagedView: FocusableView + EventEmitter<DismissEvent> {}
impl<M: FocusableView + EventEmitter<Manager>> ManagedView for M {} impl<M: FocusableView + EventEmitter<DismissEvent>> ManagedView for M {}
pub enum Manager { pub enum DismissEvent {
Dismiss, Dismiss,
} }
@ -1663,7 +1663,7 @@ impl VisualContext for WindowContext<'_> {
where where
V: ManagedView, V: ManagedView,
{ {
self.update_view(view, |_, cx| cx.emit(Manager::Dismiss)) self.update_view(view, |_, cx| cx.emit(DismissEvent::Dismiss))
} }
} }
@ -2349,7 +2349,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
where where
V: ManagedView, V: ManagedView,
{ {
self.defer(|_, cx| cx.emit(Manager::Dismiss)) self.defer(|_, cx| cx.emit(DismissEvent::Dismiss))
} }
pub fn listener<E>( pub fn listener<E>(

View File

@ -4,9 +4,9 @@ use std::rc::Rc;
use crate::{prelude::*, v_stack, Label, List}; use crate::{prelude::*, v_stack, Label, List};
use crate::{ListItem, ListSeparator, ListSubHeader}; use crate::{ListItem, ListSeparator, ListSubHeader};
use gpui::{ use gpui::{
overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, ClickEvent, DispatchPhase, overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, ClickEvent, DismissEvent,
Div, EventEmitter, FocusHandle, FocusableView, IntoElement, LayoutId, ManagedView, Manager, DispatchPhase, Div, EventEmitter, FocusHandle, FocusableView, IntoElement, LayoutId,
MouseButton, MouseDownEvent, Pixels, Point, Render, View, VisualContext, ManagedView, MouseButton, MouseDownEvent, Pixels, Point, Render, View, VisualContext,
}; };
pub enum ContextMenuItem { pub enum ContextMenuItem {
@ -26,7 +26,7 @@ impl FocusableView for ContextMenu {
} }
} }
impl EventEmitter<Manager> for ContextMenu {} impl EventEmitter<DismissEvent> for ContextMenu {}
impl ContextMenu { impl ContextMenu {
pub fn build( pub fn build(
@ -74,11 +74,11 @@ impl ContextMenu {
pub fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) { pub fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
// todo!() // todo!()
cx.emit(Manager::Dismiss); cx.emit(DismissEvent::Dismiss);
} }
pub fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) { pub fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
cx.emit(Manager::Dismiss); cx.emit(DismissEvent::Dismiss);
} }
} }
@ -111,7 +111,7 @@ impl Render for ContextMenu {
} }
ContextMenuItem::Entry(entry, callback) => { ContextMenuItem::Entry(entry, callback) => {
let callback = callback.clone(); let callback = callback.clone();
let dismiss = cx.listener(|_, _, cx| cx.emit(Manager::Dismiss)); let dismiss = cx.listener(|_, _, cx| cx.emit(DismissEvent::Dismiss));
ListItem::new(entry.clone()) ListItem::new(entry.clone())
.child(Label::new(entry.clone())) .child(Label::new(entry.clone()))
@ -265,7 +265,7 @@ impl<M: ManagedView> Element for MenuHandle<M> {
let new_menu = (builder)(cx); let new_menu = (builder)(cx);
let menu2 = menu.clone(); let menu2 = menu.clone();
cx.subscribe(&new_menu, move |modal, e, cx| match e { cx.subscribe(&new_menu, move |modal, e, cx| match e {
&Manager::Dismiss => { &DismissEvent::Dismiss => {
*menu2.borrow_mut() = None; *menu2.borrow_mut() = None;
cx.notify(); cx.notify();
} }

View File

@ -63,7 +63,7 @@ use crate::{
}; };
use dock::{Dock, DockPosition, Panel, PanelButtons, PanelHandle}; use dock::{Dock, DockPosition, Panel, PanelButtons, PanelHandle};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use notifications::{NotificationHandle, NotifyResultExt}; use notifications::{simple_message_notification, NotificationHandle, NotifyResultExt};
pub use pane::*; pub use pane::*;
pub use pane_group::*; pub use pane_group::*;
use persistence::{model::SerializedItem, DB}; use persistence::{model::SerializedItem, DB};
@ -776,7 +776,23 @@ impl Workspace {
}), }),
]; ];
cx.defer(|this, cx| this.update_window_title(cx)); cx.defer(|this, cx| {
this.update_window_title(cx);
this.show_notification(0, cx, |cx| {
cx.add_view(|_cx| {
simple_message_notification::MessageNotification::new(format!(
"Error: what happens if this message is very very very very very long "
))
.with_click_message("Click here because!")
})
});
this.show_notification(1, cx, |cx| {
cx.add_view(|_cx| {
simple_message_notification::MessageNotification::new(format!("Nope"))
})
});
});
Workspace { Workspace {
weak_self: weak_handle.clone(), weak_self: weak_handle.clone(),
modal: None, modal: None,

View File

@ -1,6 +1,9 @@
use crate::{Toast, Workspace}; use crate::{Toast, Workspace};
use collections::HashMap; use collections::HashMap;
use gpui::{AnyView, AppContext, Entity, EntityId, EventEmitter, Render, View, ViewContext}; use gpui::{
AnyView, AppContext, AsyncWindowContext, DismissEvent, Entity, EntityId, EventEmitter, Render,
View, ViewContext, VisualContext,
};
use std::{any::TypeId, ops::DerefMut}; use std::{any::TypeId, ops::DerefMut};
pub fn init(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) {
@ -9,13 +12,9 @@ pub fn init(cx: &mut AppContext) {
// simple_message_notification::init(cx); // simple_message_notification::init(cx);
} }
pub enum NotificationEvent { pub trait Notification: EventEmitter<DismissEvent> + Render {}
Dismiss,
}
pub trait Notification: EventEmitter<NotificationEvent> + Render {} impl<V: EventEmitter<DismissEvent> + Render> Notification for V {}
impl<V: EventEmitter<NotificationEvent> + Render> Notification for V {}
pub trait NotificationHandle: Send { pub trait NotificationHandle: Send {
fn id(&self) -> EntityId; fn id(&self) -> EntityId;
@ -107,8 +106,8 @@ impl Workspace {
let notification = build_notification(cx); let notification = build_notification(cx);
cx.subscribe( cx.subscribe(
&notification, &notification,
move |this, handle, event: &NotificationEvent, cx| match event { move |this, handle, event: &DismissEvent, cx| match event {
NotificationEvent::Dismiss => { DismissEvent::Dismiss => {
this.dismiss_notification_internal(type_id, id, cx); this.dismiss_notification_internal(type_id, id, cx);
} }
}, },
@ -120,6 +119,17 @@ impl Workspace {
} }
} }
pub fn show_error<E>(&mut self, err: &E, cx: &mut ViewContext<Self>)
where
E: std::fmt::Debug,
{
self.show_notification(0, cx, |cx| {
cx.build_view(|_cx| {
simple_message_notification::MessageNotification::new(format!("Error: {err:?}"))
})
});
}
pub fn dismiss_notification<V: Notification>(&mut self, id: usize, cx: &mut ViewContext<Self>) { pub fn dismiss_notification<V: Notification>(&mut self, id: usize, cx: &mut ViewContext<Self>) {
let type_id = TypeId::of::<V>(); let type_id = TypeId::of::<V>();
@ -166,13 +176,14 @@ impl Workspace {
} }
pub mod simple_message_notification { pub mod simple_message_notification {
use super::NotificationEvent; use gpui::{
use gpui::{AnyElement, AppContext, Div, EventEmitter, Render, TextStyle, ViewContext}; div, AnyElement, AppContext, DismissEvent, Div, EventEmitter, InteractiveElement,
ParentElement, Render, SharedString, StatefulInteractiveElement, Styled, TextStyle,
ViewContext,
};
use serde::Deserialize; use serde::Deserialize;
use std::{borrow::Cow, sync::Arc}; use std::{borrow::Cow, sync::Arc};
use ui::{h_stack, v_stack, Button, Icon, IconElement, Label, StyledExt};
// todo!()
// actions!(message_notifications, [CancelMessageNotification]);
#[derive(Clone, Default, Deserialize, PartialEq)] #[derive(Clone, Default, Deserialize, PartialEq)]
pub struct OsOpen(pub Cow<'static, str>); pub struct OsOpen(pub Cow<'static, str>);
@ -197,22 +208,22 @@ pub mod simple_message_notification {
// } // }
enum NotificationMessage { enum NotificationMessage {
Text(Cow<'static, str>), Text(SharedString),
Element(fn(TextStyle, &AppContext) -> AnyElement), Element(fn(TextStyle, &AppContext) -> AnyElement),
} }
pub struct MessageNotification { pub struct MessageNotification {
message: NotificationMessage, message: NotificationMessage,
on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>) + Send + Sync>>, on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>) + Send + Sync>>,
click_message: Option<Cow<'static, str>>, click_message: Option<SharedString>,
} }
impl EventEmitter<NotificationMessage> for MessageNotification {} impl EventEmitter<DismissEvent> for MessageNotification {}
impl MessageNotification { impl MessageNotification {
pub fn new<S>(message: S) -> MessageNotification pub fn new<S>(message: S) -> MessageNotification
where where
S: Into<Cow<'static, str>>, S: Into<SharedString>,
{ {
Self { Self {
message: NotificationMessage::Text(message.into()), message: NotificationMessage::Text(message.into()),
@ -221,19 +232,20 @@ pub mod simple_message_notification {
} }
} }
pub fn new_element( // not needed I think (only for the "new panel" toast, which is outdated now)
message: fn(TextStyle, &AppContext) -> AnyElement, // pub fn new_element(
) -> MessageNotification { // message: fn(TextStyle, &AppContext) -> AnyElement,
Self { // ) -> MessageNotification {
message: NotificationMessage::Element(message), // Self {
on_click: None, // message: NotificationMessage::Element(message),
click_message: None, // on_click: None,
} // click_message: None,
} // }
// }
pub fn with_click_message<S>(mut self, message: S) -> Self pub fn with_click_message<S>(mut self, message: S) -> Self
where where
S: Into<Cow<'static, str>>, S: Into<SharedString>,
{ {
self.click_message = Some(message.into()); self.click_message = Some(message.into());
self self
@ -247,17 +259,43 @@ pub mod simple_message_notification {
self self
} }
// todo!() pub fn dismiss(&mut self, cx: &mut ViewContext<Self>) {
// pub fn dismiss(&mut self, _: &CancelMessageNotification, cx: &mut ViewContext<Self>) { cx.emit(DismissEvent::Dismiss);
// cx.emit(MessageNotificationEvent::Dismiss); }
// }
} }
impl Render for MessageNotification { impl Render for MessageNotification {
type Element = Div; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
todo!() v_stack()
.elevation_3(cx)
.p_4()
.child(
h_stack()
.justify_between()
.child(div().max_w_80().child(match &self.message {
NotificationMessage::Text(text) => Label::new(text.clone()),
NotificationMessage::Element(element) => {
todo!()
}
}))
.child(
div()
.id("cancel")
.child(IconElement::new(Icon::Close))
.cursor_pointer()
.on_click(cx.listener(|this, event, cx| this.dismiss(cx))),
),
)
.children(self.click_message.iter().map(|message| {
Button::new(message.clone()).on_click(cx.listener(|this, _, cx| {
if let Some(on_click) = this.on_click.as_ref() {
(on_click)(cx)
};
this.dismiss(cx)
}))
}))
} }
} }
// todo!() // todo!()
@ -359,8 +397,6 @@ pub mod simple_message_notification {
// .into_any() // .into_any()
// } // }
// } // }
impl EventEmitter<NotificationEvent> for MessageNotification {}
} }
pub trait NotifyResultExt { pub trait NotifyResultExt {
@ -371,6 +407,8 @@ pub trait NotifyResultExt {
workspace: &mut Workspace, workspace: &mut Workspace,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> Option<Self::Ok>; ) -> Option<Self::Ok>;
fn notify_async_err(self, cx: &mut AsyncWindowContext) -> Option<Self::Ok>;
} }
impl<T, E> NotifyResultExt for Result<T, E> impl<T, E> NotifyResultExt for Result<T, E>
@ -384,14 +422,23 @@ where
Ok(value) => Some(value), Ok(value) => Some(value),
Err(err) => { Err(err) => {
log::error!("TODO {err:?}"); log::error!("TODO {err:?}");
// todo!() workspace.show_error(&err, cx);
// workspace.show_notification(0, cx, |cx| { None
// cx.add_view(|_cx| { }
// simple_message_notification::MessageNotification::new(format!( }
// "Error: {err:?}", }
// ))
// }) fn notify_async_err(self, cx: &mut AsyncWindowContext) -> Option<T> {
// }); match self {
Ok(value) => Some(value),
Err(err) => {
log::error!("TODO {err:?}");
cx.update(|view, cx| {
if let Ok(workspace) = view.downcast::<Workspace>() {
workspace.update(cx, |workspace, cx| workspace.show_error(&err, cx))
}
})
.ok();
None None
} }
} }

View File

@ -683,7 +683,21 @@ impl Workspace {
}), }),
]; ];
cx.defer(|this, cx| this.update_window_title(cx)); cx.defer(|this, cx| {
this.update_window_title(cx);
// todo! @nate - these are useful for testing notifications
// this.show_error(
// &anyhow::anyhow!("what happens if this message is very very very very very long"),
// cx,
// );
// this.show_notification(1, cx, |cx| {
// cx.build_view(|_cx| {
// simple_message_notification::MessageNotification::new(format!("Error:"))
// .with_click_message("click here because!")
// })
// });
});
Workspace { Workspace {
window_self: window_handle, window_self: window_handle,
weak_self: weak_handle.clone(), weak_self: weak_handle.clone(),
@ -2566,32 +2580,31 @@ impl Workspace {
// } // }
// } // }
// fn render_notifications( fn render_notifications(&self, cx: &ViewContext<Self>) -> Option<Div> {
// &self, if self.notifications.is_empty() {
// theme: &theme::Workspace, None
// cx: &AppContext, } else {
// ) -> Option<AnyElement<Workspace>> { Some(
// if self.notifications.is_empty() { div()
// None .absolute()
// } else { .z_index(100)
// Some( .right_3()
// Flex::column() .bottom_3()
// .with_children(self.notifications.iter().map(|(_, _, notification)| { .w_96()
// ChildView::new(notification.as_any(), cx) .h_full()
// .contained() .flex()
// .with_style(theme.notification) .flex_col()
// })) .justify_end()
// .constrained() .gap_2()
// .with_width(theme.notifications.width) .children(self.notifications.iter().map(|(_, _, notification)| {
// .contained() div()
// .with_style(theme.notifications.container) .on_any_mouse_down(|_, cx| cx.stop_propagation())
// .aligned() .on_any_mouse_up(|_, cx| cx.stop_propagation())
// .bottom() .child(notification.to_any())
// .right() })),
// .into_any(), )
// ) }
// } }
// }
// // RPC handlers // // RPC handlers
@ -3653,7 +3666,6 @@ impl Render for Workspace {
.bg(cx.theme().colors().background) .bg(cx.theme().colors().background)
.children(self.titlebar_item.clone()) .children(self.titlebar_item.clone())
.child( .child(
// todo! should this be a component a view?
div() div()
.id("workspace") .id("workspace")
.relative() .relative()
@ -3703,7 +3715,8 @@ impl Render for Workspace {
.overflow_hidden() .overflow_hidden()
.child(self.right_dock.clone()), .child(self.right_dock.clone()),
), ),
), )
.children(self.render_notifications(cx)),
) )
.child(self.status_bar.clone()) .child(self.status_bar.clone())
} }