commit
1fecd3c327
13 changed files with 115 additions and 58 deletions
|
@ -13,6 +13,7 @@ use picker::{Picker, PickerDelegate};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use util::TryFutureExt;
|
use util::TryFutureExt;
|
||||||
|
use workspace::ModalView;
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
SelectNextControl,
|
SelectNextControl,
|
||||||
|
@ -140,6 +141,7 @@ impl ChannelModal {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<DismissEvent> for ChannelModal {}
|
impl EventEmitter<DismissEvent> for ChannelModal {}
|
||||||
|
impl ModalView for ChannelModal {}
|
||||||
|
|
||||||
impl FocusableView for ChannelModal {
|
impl FocusableView for ChannelModal {
|
||||||
fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
|
fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
|
||||||
|
|
|
@ -9,6 +9,7 @@ use std::sync::Arc;
|
||||||
use theme::ActiveTheme as _;
|
use theme::ActiveTheme as _;
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use util::{ResultExt as _, TryFutureExt};
|
use util::{ResultExt as _, TryFutureExt};
|
||||||
|
use workspace::ModalView;
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
//Picker::<ContactFinderDelegate>::init(cx);
|
//Picker::<ContactFinderDelegate>::init(cx);
|
||||||
|
@ -95,6 +96,7 @@ pub struct ContactFinderDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<DismissEvent> for ContactFinder {}
|
impl EventEmitter<DismissEvent> for ContactFinder {}
|
||||||
|
impl ModalView for ContactFinder {}
|
||||||
|
|
||||||
impl FocusableView for ContactFinder {
|
impl FocusableView for ContactFinder {
|
||||||
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use util::{
|
||||||
channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
|
channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
|
||||||
ResultExt,
|
ResultExt,
|
||||||
};
|
};
|
||||||
use workspace::Workspace;
|
use workspace::{ModalView, Workspace};
|
||||||
use zed_actions::OpenZedURL;
|
use zed_actions::OpenZedURL;
|
||||||
|
|
||||||
actions!(Toggle);
|
actions!(Toggle);
|
||||||
|
@ -26,6 +26,8 @@ pub fn init(cx: &mut AppContext) {
|
||||||
cx.observe_new_views(CommandPalette::register).detach();
|
cx.observe_new_views(CommandPalette::register).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModalView for CommandPalette {}
|
||||||
|
|
||||||
pub struct CommandPalette {
|
pub struct CommandPalette {
|
||||||
picker: View<Picker<CommandPaletteDelegate>>,
|
picker: View<Picker<CommandPaletteDelegate>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::bail;
|
||||||
use client::{Client, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
|
use client::{Client, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
|
||||||
use db::kvp::KEY_VALUE_STORE;
|
use db::kvp::KEY_VALUE_STORE;
|
||||||
use editor::{Editor, EditorEvent};
|
use editor::{Editor, EditorEvent};
|
||||||
use futures::AsyncReadExt;
|
use futures::{AsyncReadExt, Future};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, rems, serde_json, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView,
|
div, rems, serde_json, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView,
|
||||||
Model, PromptLevel, Render, Task, View, ViewContext,
|
Model, PromptLevel, Render, Task, View, ViewContext,
|
||||||
|
@ -16,7 +16,7 @@ use regex::Regex;
|
||||||
use serde_derive::Serialize;
|
use serde_derive::Serialize;
|
||||||
use ui::{prelude::*, Button, ButtonStyle, IconPosition, Tooltip};
|
use ui::{prelude::*, Button, ButtonStyle, IconPosition, Tooltip};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::Workspace;
|
use workspace::{ModalView, Workspace};
|
||||||
|
|
||||||
use crate::{system_specs::SystemSpecs, GiveFeedback, OpenZedCommunityRepo};
|
use crate::{system_specs::SystemSpecs, GiveFeedback, OpenZedCommunityRepo};
|
||||||
|
|
||||||
|
@ -52,6 +52,13 @@ impl FocusableView for FeedbackModal {
|
||||||
}
|
}
|
||||||
impl EventEmitter<DismissEvent> for FeedbackModal {}
|
impl EventEmitter<DismissEvent> for FeedbackModal {}
|
||||||
|
|
||||||
|
impl ModalView for FeedbackModal {
|
||||||
|
fn dismiss(&mut self, cx: &mut ViewContext<Self>) -> Task<bool> {
|
||||||
|
let prompt = Self::prompt_dismiss(cx);
|
||||||
|
cx.spawn(|_, _| prompt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FeedbackModal {
|
impl FeedbackModal {
|
||||||
pub fn register(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
|
pub fn register(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
|
||||||
let _handle = cx.view().downgrade();
|
let _handle = cx.view().downgrade();
|
||||||
|
@ -105,7 +112,7 @@ impl FeedbackModal {
|
||||||
let feedback_editor = cx.build_view(|cx| {
|
let feedback_editor = cx.build_view(|cx| {
|
||||||
let mut editor = Editor::for_buffer(buffer, Some(project.clone()), cx);
|
let mut editor = Editor::for_buffer(buffer, Some(project.clone()), cx);
|
||||||
editor.set_placeholder_text(
|
editor.set_placeholder_text(
|
||||||
"You can use markdown to add links or organize feedback.",
|
"You can use markdown to organize your feedback wiht add code and links, or organize feedback.",
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
// editor.set_show_gutter(false, cx);
|
// editor.set_show_gutter(false, cx);
|
||||||
|
@ -238,11 +245,29 @@ impl FeedbackModal {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Escape button calls dismiss
|
// TODO: Escape button calls dismiss
|
||||||
// TODO: Should do same as hitting cancel / clicking outside of modal
|
|
||||||
// Close immediately if no text in field
|
|
||||||
// Ask to close if text in the field
|
|
||||||
fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
|
fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
|
||||||
cx.emit(DismissEvent);
|
self.dismiss_event(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dismiss_event(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
|
let has_feedback = self.feedback_editor.read(cx).text_option(cx).is_some();
|
||||||
|
let dismiss = Self::prompt_dismiss(cx);
|
||||||
|
|
||||||
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
if !has_feedback || (has_feedback && dismiss.await) {
|
||||||
|
this.update(&mut cx, |_, cx| cx.emit(DismissEvent)).ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prompt_dismiss(cx: &mut ViewContext<Self>) -> impl Future<Output = bool> {
|
||||||
|
let answer = cx.prompt(PromptLevel::Info, "Discard feedback?", &["Yes", "No"]);
|
||||||
|
|
||||||
|
async {
|
||||||
|
let answer = answer.await.ok();
|
||||||
|
answer == Some(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,27 +285,12 @@ impl Render for FeedbackModal {
|
||||||
let allow_submission =
|
let allow_submission =
|
||||||
valid_character_count && valid_email_address && !self.pending_submission;
|
valid_character_count && valid_email_address && !self.pending_submission;
|
||||||
|
|
||||||
let has_feedback = self.feedback_editor.read(cx).text_option(cx).is_some();
|
|
||||||
|
|
||||||
let submit_button_text = if self.pending_submission {
|
let submit_button_text = if self.pending_submission {
|
||||||
"Submitting..."
|
"Submitting..."
|
||||||
} else {
|
} else {
|
||||||
"Submit"
|
"Submit"
|
||||||
};
|
};
|
||||||
let dismiss = cx.listener(|_, _, cx| {
|
|
||||||
cx.emit(DismissEvent);
|
|
||||||
});
|
|
||||||
// TODO: get the "are you sure you want to dismiss?" prompt here working
|
|
||||||
let dismiss_prompt = cx.listener(|_, _, _| {
|
|
||||||
// let answer = cx.prompt(PromptLevel::Info, "Exit feedback?", &["Yes", "No"]);
|
|
||||||
// cx.spawn(|_, _| async move {
|
|
||||||
// let answer = answer.await.ok();
|
|
||||||
// if answer == Some(0) {
|
|
||||||
// cx.emit(DismissEvent);
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .detach();
|
|
||||||
});
|
|
||||||
let open_community_repo =
|
let open_community_repo =
|
||||||
cx.listener(|_, _, cx| cx.dispatch_action(Box::new(OpenZedCommunityRepo)));
|
cx.listener(|_, _, cx| cx.dispatch_action(Box::new(OpenZedCommunityRepo)));
|
||||||
|
|
||||||
|
@ -364,15 +374,9 @@ impl Render for FeedbackModal {
|
||||||
Button::new("cancel_feedback", "Cancel")
|
Button::new("cancel_feedback", "Cancel")
|
||||||
.style(ButtonStyle::Subtle)
|
.style(ButtonStyle::Subtle)
|
||||||
.color(Color::Muted)
|
.color(Color::Muted)
|
||||||
// TODO: replicate this logic when clicking outside the modal
|
.on_click(cx.listener(move |this, _, cx| {
|
||||||
// TODO: Will require somehow overriding the modal dismal default behavior
|
this.dismiss_event(cx)
|
||||||
.map(|this| {
|
})),
|
||||||
if has_feedback {
|
|
||||||
this.on_click(dismiss_prompt)
|
|
||||||
} else {
|
|
||||||
this.on_click(dismiss)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("send_feedback", submit_button_text)
|
Button::new("send_feedback", submit_button_text)
|
||||||
|
@ -402,3 +406,4 @@ impl Render for FeedbackModal {
|
||||||
|
|
||||||
// TODO: Add compilation flags to enable debug mode, where we can simulate sending feedback that both succeeds and fails, so we can test the UI
|
// TODO: Add compilation flags to enable debug mode, where we can simulate sending feedback that both succeeds and fails, so we can test the UI
|
||||||
// TODO: Maybe store email address whenever the modal is closed, versus just on submit, so users can remove it if they want without submitting
|
// TODO: Maybe store email address whenever the modal is closed, versus just on submit, so users can remove it if they want without submitting
|
||||||
|
// TODO: Fix bug of being asked twice to discard feedback when clicking cancel
|
||||||
|
|
|
@ -17,10 +17,12 @@ use std::{
|
||||||
use text::Point;
|
use text::Point;
|
||||||
use ui::{prelude::*, HighlightedLabel, ListItem};
|
use ui::{prelude::*, HighlightedLabel, ListItem};
|
||||||
use util::{paths::PathLikeWithPosition, post_inc, ResultExt};
|
use util::{paths::PathLikeWithPosition, post_inc, ResultExt};
|
||||||
use workspace::Workspace;
|
use workspace::{ModalView, Workspace};
|
||||||
|
|
||||||
actions!(Toggle);
|
actions!(Toggle);
|
||||||
|
|
||||||
|
impl ModalView for FileFinder {}
|
||||||
|
|
||||||
pub struct FileFinder {
|
pub struct FileFinder {
|
||||||
picker: View<Picker<FileFinderDelegate>>,
|
picker: View<Picker<FileFinderDelegate>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use text::{Bias, Point};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use ui::{h_stack, prelude::*, v_stack, Label};
|
use ui::{h_stack, prelude::*, v_stack, Label};
|
||||||
use util::paths::FILE_ROW_COLUMN_DELIMITER;
|
use util::paths::FILE_ROW_COLUMN_DELIMITER;
|
||||||
|
use workspace::ModalView;
|
||||||
|
|
||||||
actions!(Toggle);
|
actions!(Toggle);
|
||||||
|
|
||||||
|
@ -23,6 +24,8 @@ pub struct GoToLine {
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModalView for GoToLine {}
|
||||||
|
|
||||||
impl FocusableView for GoToLine {
|
impl FocusableView for GoToLine {
|
||||||
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||||
self.line_editor.focus_handle(cx)
|
self.line_editor.focus_handle(cx)
|
||||||
|
|
|
@ -14,7 +14,7 @@ use project::Project;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::{prelude::*, HighlightedLabel, ListItem};
|
use ui::{prelude::*, HighlightedLabel, ListItem};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::Workspace;
|
use workspace::{ModalView, Workspace};
|
||||||
|
|
||||||
actions!(Toggle);
|
actions!(Toggle);
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ impl FocusableView for LanguageSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<DismissEvent> for LanguageSelector {}
|
impl EventEmitter<DismissEvent> for LanguageSelector {}
|
||||||
|
impl ModalView for LanguageSelector {}
|
||||||
|
|
||||||
pub struct LanguageSelectorDelegate {
|
pub struct LanguageSelectorDelegate {
|
||||||
language_selector: WeakView<LanguageSelector>,
|
language_selector: WeakView<LanguageSelector>,
|
||||||
|
|
|
@ -20,7 +20,7 @@ use std::{
|
||||||
use theme::{color_alpha, ActiveTheme, ThemeSettings};
|
use theme::{color_alpha, ActiveTheme, ThemeSettings};
|
||||||
use ui::{prelude::*, ListItem};
|
use ui::{prelude::*, ListItem};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::Workspace;
|
use workspace::{ModalView, Workspace};
|
||||||
|
|
||||||
actions!(Toggle);
|
actions!(Toggle);
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ impl FocusableView for OutlineView {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<DismissEvent> for OutlineView {}
|
impl EventEmitter<DismissEvent> for OutlineView {}
|
||||||
|
impl ModalView for OutlineView {}
|
||||||
|
|
||||||
impl Render for OutlineView {
|
impl Render for OutlineView {
|
||||||
type Element = Div;
|
type Element = Div;
|
||||||
|
|
|
@ -13,8 +13,8 @@ use std::sync::Arc;
|
||||||
use ui::{prelude::*, ListItem};
|
use ui::{prelude::*, ListItem};
|
||||||
use util::paths::PathExt;
|
use util::paths::PathExt;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
notifications::simple_message_notification::MessageNotification, Workspace, WorkspaceLocation,
|
notifications::simple_message_notification::MessageNotification, ModalView, Workspace,
|
||||||
WORKSPACE_DB,
|
WorkspaceLocation, WORKSPACE_DB,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use projects::OpenRecent;
|
pub use projects::OpenRecent;
|
||||||
|
@ -27,6 +27,8 @@ pub struct RecentProjects {
|
||||||
picker: View<Picker<RecentProjectsDelegate>>,
|
picker: View<Picker<RecentProjectsDelegate>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModalView for RecentProjects {}
|
||||||
|
|
||||||
impl RecentProjects {
|
impl RecentProjects {
|
||||||
fn new(delegate: RecentProjectsDelegate, cx: &mut ViewContext<Self>) -> Self {
|
fn new(delegate: RecentProjectsDelegate, cx: &mut ViewContext<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
||||||
use theme::{Theme, ThemeMeta, ThemeRegistry, ThemeSettings};
|
use theme::{Theme, ThemeMeta, ThemeRegistry, ThemeSettings};
|
||||||
use ui::{prelude::*, v_stack, ListItem};
|
use ui::{prelude::*, v_stack, ListItem};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{ui::HighlightedLabel, Workspace};
|
use workspace::{ui::HighlightedLabel, ModalView, Workspace};
|
||||||
|
|
||||||
actions!(Toggle, Reload);
|
actions!(Toggle, Reload);
|
||||||
|
|
||||||
|
@ -52,6 +52,8 @@ pub fn reload(cx: &mut AppContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModalView for ThemeSelector {}
|
||||||
|
|
||||||
pub struct ThemeSelector {
|
pub struct ThemeSelector {
|
||||||
picker: View<Picker<ThemeSelectorDelegate>>,
|
picker: View<Picker<ThemeSelectorDelegate>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use settings::{update_settings_file, Settings};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::{prelude::*, ListItem};
|
use ui::{prelude::*, ListItem};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{ui::HighlightedLabel, Workspace};
|
use workspace::{ui::HighlightedLabel, ModalView, Workspace};
|
||||||
|
|
||||||
actions!(ToggleBaseKeymapSelector);
|
actions!(ToggleBaseKeymapSelector);
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ impl FocusableView for BaseKeymapSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<DismissEvent> for BaseKeymapSelector {}
|
impl EventEmitter<DismissEvent> for BaseKeymapSelector {}
|
||||||
|
impl ModalView for BaseKeymapSelector {}
|
||||||
|
|
||||||
impl BaseKeymapSelector {
|
impl BaseKeymapSelector {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
|
|
@ -1,11 +1,32 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::*, px, AnyView, Div, FocusHandle, ManagedView, Render, Subscription, View,
|
div, prelude::*, px, AnyView, Div, FocusHandle, ManagedView, Render, Subscription, Task, View,
|
||||||
ViewContext,
|
ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
use ui::{h_stack, v_stack};
|
use ui::{h_stack, v_stack};
|
||||||
|
|
||||||
|
pub trait ModalView: ManagedView {
|
||||||
|
fn dismiss(&mut self, cx: &mut ViewContext<Self>) -> Task<bool> {
|
||||||
|
Task::ready(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ModalViewHandle {
|
||||||
|
fn should_dismiss(&mut self, cx: &mut WindowContext) -> Task<bool>;
|
||||||
|
fn view(&self) -> AnyView;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: ModalView> ModalViewHandle for View<V> {
|
||||||
|
fn should_dismiss(&mut self, cx: &mut WindowContext) -> Task<bool> {
|
||||||
|
self.update(cx, |this, cx| this.dismiss(cx))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> AnyView {
|
||||||
|
self.clone().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ActiveModal {
|
pub struct ActiveModal {
|
||||||
modal: AnyView,
|
modal: Box<dyn ModalViewHandle>,
|
||||||
subscription: Subscription,
|
subscription: Subscription,
|
||||||
previous_focus_handle: Option<FocusHandle>,
|
previous_focus_handle: Option<FocusHandle>,
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
|
@ -22,11 +43,11 @@ impl ModalLayer {
|
||||||
|
|
||||||
pub fn toggle_modal<V, B>(&mut self, cx: &mut ViewContext<Self>, build_view: B)
|
pub fn toggle_modal<V, B>(&mut self, cx: &mut ViewContext<Self>, build_view: B)
|
||||||
where
|
where
|
||||||
V: ManagedView,
|
V: ModalView,
|
||||||
B: FnOnce(&mut ViewContext<V>) -> V,
|
B: FnOnce(&mut ViewContext<V>) -> V,
|
||||||
{
|
{
|
||||||
if let Some(active_modal) = &self.active_modal {
|
if let Some(active_modal) = &self.active_modal {
|
||||||
let is_close = active_modal.modal.clone().downcast::<V>().is_ok();
|
let is_close = active_modal.modal.view().downcast::<V>().is_ok();
|
||||||
self.hide_modal(cx);
|
self.hide_modal(cx);
|
||||||
if is_close {
|
if is_close {
|
||||||
return;
|
return;
|
||||||
|
@ -38,10 +59,10 @@ impl ModalLayer {
|
||||||
|
|
||||||
pub fn show_modal<V>(&mut self, new_modal: View<V>, cx: &mut ViewContext<Self>)
|
pub fn show_modal<V>(&mut self, new_modal: View<V>, cx: &mut ViewContext<Self>)
|
||||||
where
|
where
|
||||||
V: ManagedView,
|
V: ModalView,
|
||||||
{
|
{
|
||||||
self.active_modal = Some(ActiveModal {
|
self.active_modal = Some(ActiveModal {
|
||||||
modal: new_modal.clone().into(),
|
modal: Box::new(new_modal.clone()),
|
||||||
subscription: cx.subscribe(&new_modal, |this, modal, e, cx| this.hide_modal(cx)),
|
subscription: cx.subscribe(&new_modal, |this, modal, e, cx| this.hide_modal(cx)),
|
||||||
previous_focus_handle: cx.focused(),
|
previous_focus_handle: cx.focused(),
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
|
@ -51,23 +72,36 @@ impl ModalLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hide_modal(&mut self, cx: &mut ViewContext<Self>) {
|
pub fn hide_modal(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(active_modal) = self.active_modal.take() {
|
let Some(active_modal) = self.active_modal.as_mut() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let dismiss = active_modal.modal.should_dismiss(cx);
|
||||||
|
|
||||||
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
if dismiss.await {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
if let Some(active_modal) = this.active_modal.take() {
|
||||||
if let Some(previous_focus) = active_modal.previous_focus_handle {
|
if let Some(previous_focus) = active_modal.previous_focus_handle {
|
||||||
if active_modal.focus_handle.contains_focused(cx) {
|
if active_modal.focus_handle.contains_focused(cx) {
|
||||||
previous_focus.focus(cx);
|
previous_focus.focus(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn active_modal<V>(&self) -> Option<View<V>>
|
pub fn active_modal<V>(&self) -> Option<View<V>>
|
||||||
where
|
where
|
||||||
V: 'static,
|
V: 'static,
|
||||||
{
|
{
|
||||||
let active_modal = self.active_modal.as_ref()?;
|
let active_modal = self.active_modal.as_ref()?;
|
||||||
active_modal.modal.clone().downcast::<V>().ok()
|
active_modal.modal.view().downcast::<V>().ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +132,7 @@ impl Render for ModalLayer {
|
||||||
.on_mouse_down_out(cx.listener(|this, _, cx| {
|
.on_mouse_down_out(cx.listener(|this, _, cx| {
|
||||||
this.hide_modal(cx);
|
this.hide_modal(cx);
|
||||||
}))
|
}))
|
||||||
.child(active_modal.modal.clone()),
|
.child(active_modal.modal.view()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3414,7 +3414,7 @@ impl Workspace {
|
||||||
self.modal_layer.read(cx).active_modal()
|
self.modal_layer.read(cx).active_modal()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_modal<V: ManagedView, B>(&mut self, cx: &mut ViewContext<Self>, build: B)
|
pub fn toggle_modal<V: ModalView, B>(&mut self, cx: &mut ViewContext<Self>, build: B)
|
||||||
where
|
where
|
||||||
B: FnOnce(&mut ViewContext<V>) -> V,
|
B: FnOnce(&mut ViewContext<V>) -> V,
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue