Fix more settings UX problems (#39760)
And remove the feature flag for now. Release Notes: - N/A
This commit is contained in:
Generated
-1
@@ -14363,7 +14363,6 @@ dependencies = [
|
||||
"anyhow",
|
||||
"assets",
|
||||
"client",
|
||||
"command_palette_hooks",
|
||||
"editor",
|
||||
"feature_flags",
|
||||
"fs",
|
||||
|
||||
@@ -1213,6 +1213,11 @@ impl WindowBounds {
|
||||
WindowBounds::Fullscreen(bounds) => *bounds,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new window bounds that centers the window on the screen.
|
||||
pub fn centered(size: Size<Pixels>, cx: &App) -> Self {
|
||||
WindowBounds::Windowed(Bounds::centered(None, size, cx))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WindowOptions {
|
||||
|
||||
@@ -17,7 +17,6 @@ test-support = []
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
command_palette_hooks.workspace = true
|
||||
heck.workspace = true
|
||||
editor.workspace = true
|
||||
feature_flags.workspace = true
|
||||
|
||||
@@ -4,12 +4,12 @@ mod page_data;
|
||||
|
||||
use anyhow::Result;
|
||||
use editor::{Editor, EditorEvent};
|
||||
use feature_flags::{FeatureFlag, FeatureFlagAppExt as _};
|
||||
use feature_flags::FeatureFlag;
|
||||
use fuzzy::StringMatchCandidate;
|
||||
use gpui::{
|
||||
Action, App, Div, Entity, FocusHandle, Focusable, FontWeight, Global, ReadGlobal as _,
|
||||
ScrollHandle, Task, TitlebarOptions, UniformListScrollHandle, Window, WindowHandle,
|
||||
WindowOptions, actions, div, point, prelude::*, px, size, uniform_list,
|
||||
ScrollHandle, Task, TitlebarOptions, UniformListScrollHandle, Window, WindowBounds,
|
||||
WindowHandle, WindowOptions, actions, div, point, prelude::*, px, size, uniform_list,
|
||||
};
|
||||
use heck::ToTitleCase as _;
|
||||
use project::WorktreeId;
|
||||
@@ -29,9 +29,8 @@ use std::{
|
||||
sync::{Arc, LazyLock, RwLock, atomic::AtomicBool},
|
||||
};
|
||||
use ui::{
|
||||
ContextMenu, Divider, DividerColor, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding,
|
||||
KeybindingHint, PopoverMenu, Switch, SwitchColor, Tooltip, TreeViewItem, WithScrollbar,
|
||||
prelude::*,
|
||||
ContextMenu, Divider, DividerColor, DropdownMenu, DropdownStyle, IconButtonShape, PopoverMenu,
|
||||
Switch, SwitchColor, Tooltip, TreeViewItem, WithScrollbar, prelude::*,
|
||||
};
|
||||
use ui_input::{NumberField, NumberFieldType};
|
||||
use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath};
|
||||
@@ -42,8 +41,12 @@ use crate::components::SettingsEditor;
|
||||
|
||||
const NAVBAR_CONTAINER_TAB_INDEX: isize = 0;
|
||||
const NAVBAR_GROUP_TAB_INDEX: isize = 1;
|
||||
const CONTENT_CONTAINER_TAB_INDEX: isize = 2;
|
||||
const CONTENT_GROUP_TAB_INDEX: isize = 3;
|
||||
|
||||
const HEADER_CONTAINER_TAB_INDEX: isize = 2;
|
||||
const HEADER_GROUP_TAB_INDEX: isize = 3;
|
||||
|
||||
const CONTENT_CONTAINER_TAB_INDEX: isize = 4;
|
||||
const CONTENT_GROUP_TAB_INDEX: isize = 5;
|
||||
|
||||
actions!(
|
||||
settings_editor,
|
||||
@@ -206,35 +209,12 @@ pub fn init(cx: &mut App) {
|
||||
init_renderers(cx);
|
||||
|
||||
cx.observe_new(|workspace: &mut workspace::Workspace, _, _| {
|
||||
workspace.register_action_renderer(|div, _, _, cx| {
|
||||
let settings_ui_actions = [
|
||||
TypeId::of::<OpenSettingsEditor>(),
|
||||
TypeId::of::<ToggleFocusNav>(),
|
||||
TypeId::of::<FocusFile>(),
|
||||
TypeId::of::<FocusNextFile>(),
|
||||
TypeId::of::<FocusPreviousFile>(),
|
||||
];
|
||||
let has_flag = cx.has_flag::<SettingsUiFeatureFlag>();
|
||||
command_palette_hooks::CommandPaletteFilter::update_global(cx, |filter, _| {
|
||||
if has_flag {
|
||||
filter.show_action_types(&settings_ui_actions);
|
||||
} else {
|
||||
filter.hide_action_types(&settings_ui_actions);
|
||||
}
|
||||
});
|
||||
if has_flag {
|
||||
div.on_action(
|
||||
cx.listener(|workspace, _: &OpenSettingsEditor, window, cx| {
|
||||
let window_handle = window
|
||||
.window_handle()
|
||||
.downcast::<Workspace>()
|
||||
.expect("Workspaces are root Windows");
|
||||
open_settings_editor(workspace, window_handle, cx);
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
div
|
||||
}
|
||||
workspace.register_action(|workspace, _: &OpenSettingsEditor, window, cx| {
|
||||
let window_handle = window
|
||||
.window_handle()
|
||||
.downcast::<Workspace>()
|
||||
.expect("Workspaces are root Windows");
|
||||
open_settings_editor(workspace, window_handle, cx);
|
||||
});
|
||||
})
|
||||
.detach();
|
||||
@@ -472,7 +452,8 @@ pub fn open_settings_editor(
|
||||
show: true,
|
||||
kind: gpui::WindowKind::Normal,
|
||||
window_background: cx.theme().window_background_appearance(),
|
||||
window_min_size: Some(size(px(800.), px(600.))), // 4:3 Aspect Ratio
|
||||
window_min_size: Some(size(px(900.), px(750.))), // 4:3 Aspect Ratio
|
||||
window_bounds: Some(WindowBounds::centered(size(px(900.), px(750.)), cx)),
|
||||
..Default::default()
|
||||
},
|
||||
|window, cx| cx.new(|cx| SettingsWindow::new(Some(workspace_handle), window, cx)),
|
||||
@@ -886,7 +867,10 @@ impl SettingsWindow {
|
||||
.focus_handle()
|
||||
.tab_index(CONTENT_CONTAINER_TAB_INDEX)
|
||||
.tab_stop(false),
|
||||
files_focus_handle: cx.focus_handle().tab_stop(false),
|
||||
files_focus_handle: cx
|
||||
.focus_handle()
|
||||
.tab_index(HEADER_CONTAINER_TAB_INDEX)
|
||||
.tab_stop(false),
|
||||
};
|
||||
|
||||
this.fetch_files(cx);
|
||||
@@ -1206,7 +1190,7 @@ impl SettingsWindow {
|
||||
.find_map(|(prev_file, handle)| {
|
||||
(prev_file == &settings_ui_file).then(|| handle.clone())
|
||||
})
|
||||
.unwrap_or_else(|| cx.focus_handle());
|
||||
.unwrap_or_else(|| cx.focus_handle().tab_index(0).tab_stop(true));
|
||||
ui_files.push((settings_ui_file, focus_handle));
|
||||
}
|
||||
ui_files.reverse();
|
||||
@@ -1223,14 +1207,22 @@ impl SettingsWindow {
|
||||
fn change_file(&mut self, ix: usize, cx: &mut Context<SettingsWindow>) {
|
||||
if ix >= self.files.len() {
|
||||
self.current_file = SettingsUiFile::User;
|
||||
self.build_ui(cx);
|
||||
return;
|
||||
}
|
||||
if self.files[ix].0 == self.current_file {
|
||||
return;
|
||||
}
|
||||
self.current_file = self.files[ix].0.clone();
|
||||
// self.navbar_entry = 0;
|
||||
self.navbar_entry = 0;
|
||||
self.build_ui(cx);
|
||||
|
||||
let first_navbar_entry_index = self
|
||||
.visible_navbar_entries()
|
||||
.next()
|
||||
.map(|e| e.0)
|
||||
.unwrap_or(0);
|
||||
self.navbar_entry = first_navbar_entry_index;
|
||||
}
|
||||
|
||||
fn render_files_header(
|
||||
@@ -1242,6 +1234,9 @@ impl SettingsWindow {
|
||||
.w_full()
|
||||
.gap_1()
|
||||
.justify_between()
|
||||
.tab_group()
|
||||
.track_focus(&self.files_focus_handle)
|
||||
.tab_index(HEADER_GROUP_TAB_INDEX)
|
||||
.child(
|
||||
h_flex()
|
||||
.id("file_buttons_container")
|
||||
@@ -1261,26 +1256,23 @@ impl SettingsWindow {
|
||||
.toggle_state(file == &self.current_file)
|
||||
.selected_style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.track_focus(focus_handle)
|
||||
.on_click(cx.listener(
|
||||
move |this, evt: &gpui::ClickEvent, window, cx| {
|
||||
.on_click(cx.listener({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |this, _: &gpui::ClickEvent, window, cx| {
|
||||
this.change_file(ix, cx);
|
||||
if evt.is_keyboard() {
|
||||
this.focus_first_nav_item(window, cx);
|
||||
}
|
||||
},
|
||||
))
|
||||
focus_handle.focus(window);
|
||||
}
|
||||
}))
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
Button::new(
|
||||
"edit-in-json",
|
||||
format!("Edit in {}", self.file_location_str()),
|
||||
)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.on_click(cx.listener(|this, _, _, cx| {
|
||||
this.open_current_settings_file(cx);
|
||||
})),
|
||||
Button::new("edit-in-json", "Edit in settings.json")
|
||||
.tab_index(0_isize)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.on_click(cx.listener(|this, _, _, cx| {
|
||||
this.open_current_settings_file(cx);
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1307,26 +1299,28 @@ impl SettingsWindow {
|
||||
}
|
||||
}
|
||||
|
||||
fn file_location_str(&self) -> String {
|
||||
match &self.current_file {
|
||||
SettingsUiFile::User => "settings.json".to_string(),
|
||||
SettingsUiFile::Project((worktree_id, path)) => self
|
||||
.worktree_root_dirs
|
||||
.get(&worktree_id)
|
||||
.map(|directory_name| {
|
||||
let path_style = PathStyle::local();
|
||||
let file_path = path.join(paths::local_settings_file_relative_path());
|
||||
format!(
|
||||
"{}{}{}",
|
||||
directory_name,
|
||||
path_style.separator(),
|
||||
file_path.display(path_style)
|
||||
)
|
||||
})
|
||||
.expect("Current file should always be present in root dir map"),
|
||||
SettingsUiFile::Server(file) => file.to_string(),
|
||||
}
|
||||
}
|
||||
// TODO:
|
||||
// Reconsider this after preview launch
|
||||
// fn file_location_str(&self) -> String {
|
||||
// match &self.current_file {
|
||||
// SettingsUiFile::User => "settings.json".to_string(),
|
||||
// SettingsUiFile::Project((worktree_id, path)) => self
|
||||
// .worktree_root_dirs
|
||||
// .get(&worktree_id)
|
||||
// .map(|directory_name| {
|
||||
// let path_style = PathStyle::local();
|
||||
// let file_path = path.join(paths::local_settings_file_relative_path());
|
||||
// format!(
|
||||
// "{}{}{}",
|
||||
// directory_name,
|
||||
// path_style.separator(),
|
||||
// file_path.display(path_style)
|
||||
// )
|
||||
// })
|
||||
// .expect("Current file should always be present in root dir map"),
|
||||
// SettingsUiFile::Server(file) => file.to_string(),
|
||||
// }
|
||||
// }
|
||||
|
||||
fn render_search(&self, _window: &mut Window, cx: &mut App) -> Div {
|
||||
h_flex()
|
||||
@@ -1349,11 +1343,11 @@ impl SettingsWindow {
|
||||
) -> impl IntoElement {
|
||||
let visible_count = self.visible_navbar_entries().count();
|
||||
|
||||
let focus_keybind_label = if self.navbar_focus_handle.contains_focused(window, cx) {
|
||||
"Focus Content"
|
||||
} else {
|
||||
"Focus Navbar"
|
||||
};
|
||||
// let focus_keybind_label = if self.navbar_focus_handle.contains_focused(window, cx) {
|
||||
// "Focus Content"
|
||||
// } else {
|
||||
// "Focus Navbar"
|
||||
// };
|
||||
|
||||
v_flex()
|
||||
.w_64()
|
||||
@@ -1437,24 +1431,25 @@ impl SettingsWindow {
|
||||
)
|
||||
.vertical_scrollbar_for(self.list_handle.clone(), window, cx),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.p_2()
|
||||
.pb_0p5()
|
||||
.flex_none()
|
||||
.border_t_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.children(
|
||||
KeyBinding::for_action(&ToggleFocusNav, window, cx).map(|this| {
|
||||
KeybindingHint::new(
|
||||
this,
|
||||
cx.theme().colors().surface_background.opacity(0.5),
|
||||
)
|
||||
.suffix(focus_keybind_label)
|
||||
}),
|
||||
),
|
||||
)
|
||||
// TODO: Restore this once we've fixed the ToggleFocusNav action
|
||||
// .child(
|
||||
// h_flex()
|
||||
// .w_full()
|
||||
// .p_2()
|
||||
// .pb_0p5()
|
||||
// .flex_none()
|
||||
// .border_t_1()
|
||||
// .border_color(cx.theme().colors().border_variant)
|
||||
// .children(
|
||||
// KeyBinding::for_action(&ToggleFocusNav, window, cx).map(|this| {
|
||||
// KeybindingHint::new(
|
||||
// this,
|
||||
// cx.theme().colors().surface_background.opacity(0.5),
|
||||
// )
|
||||
// .suffix(focus_keybind_label)
|
||||
// }),
|
||||
// ),
|
||||
// )
|
||||
}
|
||||
|
||||
fn focus_first_nav_item(&self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
|
||||
@@ -129,7 +129,6 @@ impl RenderOnce for TreeViewItem {
|
||||
|
||||
let selected_border = cx.theme().colors().border.opacity(0.6);
|
||||
let focused_border = cx.theme().colors().border_focused;
|
||||
let transparent_border = cx.theme().colors().border_transparent;
|
||||
|
||||
let item_size = rems_from_px(28.);
|
||||
let indentation_line = h_flex().size(item_size).flex_none().justify_center().child(
|
||||
@@ -150,6 +149,13 @@ impl RenderOnce for TreeViewItem {
|
||||
.cursor_pointer()
|
||||
.size_full()
|
||||
.relative()
|
||||
.border_1()
|
||||
.focus(|s| s.border_color(focused_border))
|
||||
.when_some(self.tab_index, |this, index| this.tab_index(index))
|
||||
.when(self.selected, |this| {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
})
|
||||
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||
.map(|this| {
|
||||
let label = self.label;
|
||||
|
||||
@@ -158,14 +164,6 @@ impl RenderOnce for TreeViewItem {
|
||||
.px_1()
|
||||
.gap_2p5()
|
||||
.rounded_sm()
|
||||
.border_1()
|
||||
.border_color(transparent_border)
|
||||
.when(self.selected, |this| {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
})
|
||||
.focus(|s| s.border_color(focused_border))
|
||||
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||
.when_some(self.tab_index, |this, index| this.tab_index(index))
|
||||
.child(
|
||||
Disclosure::new("toggle", self.expanded)
|
||||
.when_some(
|
||||
@@ -189,14 +187,7 @@ impl RenderOnce for TreeViewItem {
|
||||
.flex_grow()
|
||||
.px_1()
|
||||
.rounded_sm()
|
||||
.border_1()
|
||||
.border_color(transparent_border)
|
||||
.when(self.selected, |this| {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
})
|
||||
.focus(|s| s.border_color(focused_border))
|
||||
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||
.when_some(self.tab_index, |this, index| this.tab_index(index))
|
||||
.child(
|
||||
Label::new(label)
|
||||
.when(!self.selected, |this| this.color(Color::Muted)),
|
||||
|
||||
Reference in New Issue
Block a user