fix: preferences were broken

This commit is contained in:
2026-04-08 21:09:46 +02:00
parent b8b51c794a
commit 9867bf9c65
3 changed files with 81 additions and 18 deletions

View File

@@ -44,6 +44,7 @@ pub enum Message {
SetActiveView(SidebarView),
ToggleSidebar,
TogglePanel,
OpenSettingsSection(crate::views::settings_view::SettingsSection),
// Sidebar resize
SidebarResizeStart,
@@ -748,6 +749,19 @@ impl BdsApp {
self.panel_visible = !self.panel_visible;
Task::none()
}
Message::OpenSettingsSection(section) => {
self.sidebar_view = SidebarView::Settings;
self.sidebar_visible = true;
self.open_singleton_tab(TabType::Settings, "common.settings");
if self.settings_state.is_none() {
self.settings_state = Some(self.hydrate_settings_state());
}
if let Some(state) = self.settings_state.as_mut() {
state.focus_section(section);
}
self.sync_menu_state();
Task::none()
}
Message::SidebarResizeStart => {
self.sidebar_dragging = true;
Task::none()
@@ -3463,16 +3477,7 @@ impl BdsApp {
}
}
SettingsMsg::FocusSection(section) => {
// Expand the target section, collapse all others
use crate::views::settings_view::SettingsSection;
let all_others: Vec<SettingsSection> = SettingsSection::all()
.iter()
.filter(|s| **s != section)
.cloned()
.collect();
state.collapsed = all_others;
// Clear search filter to ensure section is visible
state.search_query.clear();
state.focus_section(section);
}
}
Task::none()

View File

@@ -53,6 +53,7 @@ impl SettingsSection {
pub struct SettingsViewState {
pub search_query: String,
pub collapsed: Vec<SettingsSection>,
pub active_section: Option<SettingsSection>,
// Project
pub project_name: String,
pub project_description: text_editor::Content,
@@ -88,6 +89,7 @@ impl Clone for SettingsViewState {
Self {
search_query: self.search_query.clone(),
collapsed: self.collapsed.clone(),
active_section: self.active_section.clone(),
project_name: self.project_name.clone(),
project_description: text_editor::Content::with_text(&self.project_description.text()),
data_path: self.data_path.clone(),
@@ -113,6 +115,7 @@ impl Default for SettingsViewState {
Self {
search_query: String::new(),
collapsed: Vec::new(),
active_section: None,
project_name: String::new(),
project_description: text_editor::Content::new(),
data_path: String::new(),
@@ -133,6 +136,29 @@ impl Default for SettingsViewState {
}
}
impl SettingsViewState {
pub fn focus_section(&mut self, section: SettingsSection) {
self.collapsed = SettingsSection::all()
.iter()
.filter(|candidate| **candidate != section)
.cloned()
.collect();
self.search_query.clear();
self.active_section = Some(section);
}
fn ordered_sections(&self) -> Vec<SettingsSection> {
let mut sections = SettingsSection::all().to_vec();
if let Some(active) = &self.active_section {
if let Some(index) = sections.iter().position(|section| section == active) {
let focused = sections.remove(index);
sections.insert(0, focused);
}
}
sections
}
}
/// Settings view messages.
#[derive(Debug, Clone)]
pub enum SettingsMsg {
@@ -190,13 +216,13 @@ pub fn view<'a>(
let query_lower = state.search_query.to_lowercase();
let mut sections = column![].spacing(12).width(Length::Fill);
for section in SettingsSection::all() {
for section in state.ordered_sections() {
let label = t(locale, section.i18n_key());
if !query_lower.is_empty() && !label.to_lowercase().contains(&query_lower) {
continue;
}
let collapsed = state.collapsed.contains(section);
let section_el = render_section(state, section, &label, collapsed, locale);
let collapsed = state.collapsed.contains(&section);
let section_el = render_section(state, &section, &label, collapsed, locale);
sections = sections.push(section_el);
}
@@ -215,6 +241,38 @@ pub fn view<'a>(
.into()
}
#[cfg(test)]
mod tests {
use super::{SettingsSection, SettingsViewState};
#[test]
fn focus_section_collapses_other_sections_and_clears_search() {
let mut state = SettingsViewState {
search_query: "publish".to_string(),
..SettingsViewState::default()
};
state.focus_section(SettingsSection::Publishing);
assert_eq!(state.active_section, Some(SettingsSection::Publishing));
assert!(state.search_query.is_empty());
assert!(!state.collapsed.contains(&SettingsSection::Publishing));
assert!(state.collapsed.contains(&SettingsSection::Project));
assert!(state.collapsed.contains(&SettingsSection::MCP));
}
#[test]
fn focused_section_is_rendered_first() {
let mut state = SettingsViewState::default();
state.focus_section(SettingsSection::Technology);
let ordered = state.ordered_sections();
assert_eq!(ordered.first(), Some(&SettingsSection::Technology));
assert_eq!(ordered.len(), SettingsSection::all().len());
}
}
fn render_section<'a>(
state: &'a SettingsViewState,
section: &SettingsSection,

View File

@@ -930,7 +930,7 @@ pub fn view(
}
SidebarView::Settings => {
// Per sidebar_views.allium SettingsNav: 9 fixed-order sections
use crate::views::settings_view::{SettingsSection, SettingsMsg};
use crate::views::settings_view::SettingsSection;
let sections: &[(&str, Option<SettingsSection>)] = &[
("settings.nav.project", Some(SettingsSection::Project)),
("settings.nav.editor", Some(SettingsSection::Editor)),
@@ -950,12 +950,12 @@ pub fn view(
.size(12)
.shaping(Shaping::Advanced);
let msg = if let Some(section) = section_opt {
Message::Settings(SettingsMsg::FocusSection(section.clone()))
Message::OpenSettingsSection(section.clone())
} else {
Message::OpenTab(Tab {
id: "settings".to_string(),
tab_type: TabType::Settings,
title: t(locale, "common.settings"),
id: "style".to_string(),
tab_type: TabType::Style,
title: t(locale, "tabBar.style"),
is_transient: false,
is_dirty: false,
})