mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-29 22:42:17 +03:00
gpui2: Notifications
This commit is contained in:
parent
700168467e
commit
039c933d8e
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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>(
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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(
|
||||||
¬ification,
|
¬ification,
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user