Remove ViewContext::dispatch_any_action

This commit is contained in:
Antonio Scandurra 2023-05-01 14:09:39 +02:00
parent 029538fe21
commit d815fc88ae
11 changed files with 197 additions and 202 deletions

View file

@ -114,17 +114,14 @@ impl Workspace {
pub fn show_toast(&mut self, toast: Toast, cx: &mut ViewContext<Self>) {
self.dismiss_notification::<simple_message_notification::MessageNotification>(toast.id, cx);
self.show_notification(toast.id, cx, |cx| {
cx.add_view(|_cx| match &toast.click {
Some((click_msg, action)) => {
simple_message_notification::MessageNotification::new_boxed_action(
toast.msg.clone(),
action.boxed_clone(),
click_msg.clone(),
)
}
None => {
simple_message_notification::MessageNotification::new_message(toast.msg.clone())
cx.add_view(|_cx| match toast.on_click.as_ref() {
Some((click_msg, on_click)) => {
let on_click = on_click.clone();
simple_message_notification::MessageNotification::new(toast.msg.clone())
.with_click_message(click_msg.clone())
.on_click(move |cx| on_click(cx))
}
None => simple_message_notification::MessageNotification::new(toast.msg.clone()),
})
})
}
@ -152,19 +149,17 @@ impl Workspace {
}
pub mod simple_message_notification {
use std::borrow::Cow;
use gpui::{
actions,
elements::{Flex, MouseEventHandler, Padding, ParentElement, Svg, Text},
impl_actions,
platform::{CursorStyle, MouseButton},
Action, AppContext, Element, Entity, View, ViewContext,
AppContext, Element, Entity, View, ViewContext,
};
use menu::Cancel;
use serde::Deserialize;
use settings::Settings;
use std::{borrow::Cow, sync::Arc};
use crate::Workspace;
@ -194,7 +189,7 @@ pub mod simple_message_notification {
pub struct MessageNotification {
message: Cow<'static, str>,
click_action: Option<Box<dyn Action>>,
on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>)>>,
click_message: Option<Cow<'static, str>>,
}
@ -207,36 +202,31 @@ pub mod simple_message_notification {
}
impl MessageNotification {
pub fn new_message<S: Into<Cow<'static, str>>>(message: S) -> MessageNotification {
pub fn new<S>(message: S) -> MessageNotification
where
S: Into<Cow<'static, str>>,
{
Self {
message: message.into(),
click_action: None,
on_click: None,
click_message: None,
}
}
pub fn new_boxed_action<S1: Into<Cow<'static, str>>, S2: Into<Cow<'static, str>>>(
message: S1,
click_action: Box<dyn Action>,
click_message: S2,
) -> Self {
Self {
message: message.into(),
click_action: Some(click_action),
click_message: Some(click_message.into()),
}
pub fn with_click_message<S>(mut self, message: S) -> Self
where
S: Into<Cow<'static, str>>,
{
self.click_message = Some(message.into());
self
}
pub fn new<S1: Into<Cow<'static, str>>, A: Action, S2: Into<Cow<'static, str>>>(
message: S1,
click_action: A,
click_message: S2,
) -> Self {
Self {
message: message.into(),
click_action: Some(Box::new(click_action) as Box<dyn Action>),
click_message: Some(click_message.into()),
}
pub fn on_click<F>(mut self, on_click: F) -> Self
where
F: 'static + Fn(&mut ViewContext<Self>),
{
self.on_click = Some(Arc::new(on_click));
self
}
pub fn dismiss(&mut self, _: &CancelMessageNotification, cx: &mut ViewContext<Self>) {
@ -255,14 +245,10 @@ pub mod simple_message_notification {
enum MessageNotificationTag {}
let click_action = self
.click_action
.as_ref()
.map(|action| action.boxed_clone());
let click_message = self.click_message.as_ref().map(|message| message.clone());
let click_message = self.click_message.clone();
let message = self.message.clone();
let has_click_action = click_action.is_some();
let on_click = self.on_click.clone();
let has_click_action = on_click.is_some();
MouseEventHandler::<MessageNotificationTag, _>::new(0, cx, |state, cx| {
Flex::column()
@ -326,10 +312,10 @@ pub mod simple_message_notification {
// Since we're not using a proper overlay, we have to capture these extra events
.on_down(MouseButton::Left, |_, _, _| {})
.on_up(MouseButton::Left, |_, _, _| {})
.on_click(MouseButton::Left, move |_, _, cx| {
if let Some(click_action) = click_action.as_ref() {
cx.dispatch_any_action(click_action.boxed_clone());
cx.dispatch_action(CancelMessageNotification)
.on_click(MouseButton::Left, move |_, this, cx| {
if let Some(on_click) = on_click.as_ref() {
on_click(cx);
this.dismiss(&Default::default(), cx);
}
})
.with_cursor_style(if has_click_action {
@ -372,7 +358,7 @@ where
Err(err) => {
workspace.show_notification(0, cx, |cx| {
cx.add_view(|_cx| {
simple_message_notification::MessageNotification::new_message(format!(
simple_message_notification::MessageNotification::new(format!(
"Error: {:?}",
err,
))

View file

@ -43,8 +43,9 @@ use gpui::{
CursorStyle, MouseButton, PathPromptOptions, Platform, PromptLevel, WindowBounds,
WindowOptions,
},
Action, AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext,
ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
WindowContext,
};
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
use language::LanguageRegistry;
@ -59,7 +60,7 @@ use std::{
};
use crate::{
notifications::simple_message_notification::{MessageNotification, OsOpen},
notifications::simple_message_notification::MessageNotification,
persistence::model::{SerializedPane, SerializedPaneGroup, SerializedWorkspace},
};
use lazy_static::lazy_static;
@ -137,7 +138,7 @@ pub struct ActivatePane(pub usize);
pub struct Toast {
id: usize,
msg: Cow<'static, str>,
click: Option<(Cow<'static, str>, Box<dyn Action>)>,
on_click: Option<(Cow<'static, str>, Arc<dyn Fn(&mut WindowContext)>)>,
}
impl Toast {
@ -145,21 +146,17 @@ impl Toast {
Toast {
id,
msg: msg.into(),
click: None,
on_click: None,
}
}
pub fn new_action<I1: Into<Cow<'static, str>>, I2: Into<Cow<'static, str>>>(
id: usize,
msg: I1,
click_msg: I2,
action: impl Action,
) -> Self {
Toast {
id,
msg: msg.into(),
click: Some((click_msg.into(), Box::new(action))),
}
pub fn on_click<F, M>(mut self, message: M, on_click: F) -> Self
where
M: Into<Cow<'static, str>>,
F: Fn(&mut WindowContext) + 'static,
{
self.on_click = Some((message.into(), Arc::new(on_click)));
self
}
}
@ -167,7 +164,7 @@ impl PartialEq for Toast {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.msg == other.msg
&& self.click.is_some() == other.click.is_some()
&& self.on_click.is_some() == other.on_click.is_some()
}
}
@ -176,10 +173,7 @@ impl Clone for Toast {
Toast {
id: self.id,
msg: self.msg.to_owned(),
click: self
.click
.as_ref()
.map(|(msg, click)| (msg.to_owned(), click.boxed_clone())),
on_click: self.on_click.clone(),
}
}
}
@ -260,6 +254,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
cx.add_async_action(Workspace::follow_next_collaborator);
cx.add_async_action(Workspace::close);
cx.add_global_action(Workspace::close_global);
cx.add_global_action(restart);
cx.add_async_action(Workspace::save_all);
cx.add_action(Workspace::add_folder_to_project);
cx.add_action(
@ -303,9 +298,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
} else {
workspace.show_notification(1, cx, |cx| {
cx.add_view(|_| {
MessageNotification::new_message(
"Successfully installed the `zed` binary",
)
MessageNotification::new("Successfully installed the `zed` binary")
})
});
}
@ -2668,36 +2661,37 @@ impl Workspace {
}
fn notify_if_database_failed(workspace: &WeakViewHandle<Workspace>, cx: &mut AsyncAppContext) {
workspace.update(cx, |workspace, cx| {
if (*db::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) {
workspace.show_notification_once(0, cx, |cx| {
cx.add_view(|_| {
MessageNotification::new(
"Failed to load any database file.",
OsOpen::new("https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml".to_string()),
"Click to let us know about this error"
)
})
});
} else {
let backup_path = (*db::BACKUP_DB_PATH).read();
if let Some(backup_path) = &*backup_path {
const REPORT_ISSUE_URL: &str ="https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml";
workspace
.update(cx, |workspace, cx| {
if (*db::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) {
workspace.show_notification_once(0, cx, |cx| {
cx.add_view(|_| {
let backup_path = backup_path.to_string_lossy();
MessageNotification::new(
format!(
"Database file was corrupted. Old database backed up to {}",
backup_path
),
OsOpen::new(backup_path.to_string()),
"Click to show old database in finder",
)
MessageNotification::new("Failed to load any database file.")
.with_click_message("Click to let us know about this error")
.on_click(|cx| cx.platform().open_url(REPORT_ISSUE_URL))
})
});
} else {
let backup_path = (*db::BACKUP_DB_PATH).read();
if let Some(backup_path) = backup_path.clone() {
workspace.show_notification_once(0, cx, move |cx| {
cx.add_view(move |_| {
MessageNotification::new(format!(
"Database file was corrupted. Old database backed up to {}",
backup_path.display()
))
.with_click_message("Click to show old database in finder")
.on_click(move |cx| {
cx.platform().open_url(&backup_path.to_string_lossy())
})
})
});
}
}
}
}).log_err();
})
.log_err();
}
impl Entity for Workspace {
@ -3062,6 +3056,58 @@ pub fn join_remote_project(
})
}
pub fn restart(_: &Restart, cx: &mut AppContext) {
let mut workspaces = cx
.window_ids()
.filter_map(|window_id| {
Some(
cx.root_view(window_id)?
.clone()
.downcast::<Workspace>()?
.downgrade(),
)
})
.collect::<Vec<_>>();
// If multiple windows have unsaved changes, and need a save prompt,
// prompt in the active window before switching to a different window.
workspaces.sort_by_key(|workspace| !cx.window_is_active(workspace.window_id()));
let should_confirm = cx.global::<Settings>().confirm_quit;
cx.spawn(|mut cx| async move {
if let (true, Some(workspace)) = (should_confirm, workspaces.first()) {
let answer = cx.prompt(
workspace.window_id(),
PromptLevel::Info,
"Are you sure you want to restart?",
&["Restart", "Cancel"],
);
if let Some(mut answer) = answer {
let answer = answer.next().await;
if answer != Some(0) {
return Ok(());
}
}
}
// 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(true, cx)
})?
.await?
{
return Ok(());
}
}
cx.platform().restart();
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
fn parse_pixel_position_env_var(value: &str) -> Option<Vector2F> {
let mut parts = value.split(',');
let width: usize = parts.next()?.parse().ok()?;