feat(settings): refine density, group detailed options and add edge maximize gestures

This commit is contained in:
aria committed 2026-10-28 04:49:27 +09:00
1 parent d7e122711a
commit 9908dde9f8
11 files changed
+588 -195

No files matched your search

+144
View File
@@ -1014,3 +1014,147 @@ pub fn fields(page: Page) -> Vec<Field> {
| Page::Connections => vec![],
}
}
pub struct FieldGroup {
pub title: &'static str,
pub fields: Vec<Field>,
}
/// Semantic groups, preserving every field and the declaration order in each group.
pub fn grouped_fields(page: Page, fields: Vec<Field>) -> Vec<FieldGroup> {
let mut groups: Vec<FieldGroup> = Vec::new();
for field in fields {
let p = field.path.as_str();
let title = match page {
Page::General => "Interface",
Page::Windows => {
if p.starts_with("workspaces.") || p == "layout.mode" || p.starts_with("scrolling.")
{
"Workspaces and layout"
} else if p == "layout.inner_gap"
|| p == "layout.outer_gap"
|| p == "theme.geometry.window_radius"
{
"Spacing and corners"
} else {
"Focus and window effects"
}
}
Page::Keyboard => {
if p.starts_with("input.xkb_") {
"Keyboard layout"
} else if p.starts_with("input.repeat_") {
"Keyboard repeat"
} else if p.starts_with("input.mouse.") {
"Mouse"
} else {
"Touchpad"
}
}
Page::LockScreen => {
if p.starts_with("lock_screen.background_") {
"Lock background"
} else if p.contains("after_seconds") {
"Display power"
} else {
"Clock and date"
}
}
Page::Theme => {
if p.ends_with(".file") {
"Theme overrides"
} else if p == "theme.mode" || p.starts_with("theme.schedule.") {
"Automatic appearance"
} else if p.starts_with("theme.typography.") {
"Typography"
} else if p.starts_with("theme.material.") {
"Surface and transparency"
} else {
"Colors and accents"
}
}
Page::Wallpaper => "Wallpaper image",
Page::Notifications => {
if p.ends_with("timeout_ms") {
"Notification timing"
} else {
"Notification behavior"
}
}
Page::Accessibility => {
if p.starts_with("animations.") {
"Motion"
} else {
"Visual accessibility"
}
}
Page::Motion => {
if p.starts_with("animations.") {
"Animations"
} else {
"Focus transition"
}
}
Page::Shortcuts => "Shortcut guide",
Page::Tray => "Application tray",
_ => "General",
};
if let Some(group) = groups.iter_mut().find(|group| group.title == title) {
group.fields.push(field)
} else {
groups.push(FieldGroup {
title,
fields: vec![field],
});
}
}
groups
}
#[cfg(test)]
mod group_tests {
use super::*;
#[test]
fn semantic_groups_keep_every_field_once_and_separate_input_devices() {
for page in Page::ALL {
let mut expected = fields(page).into_iter().map(|f| f.path).collect::<Vec<_>>();
let groups = grouped_fields(page, fields(page));
assert!(groups.iter().all(|g| !g.fields.is_empty()));
let mut actual = groups
.into_iter()
.flat_map(|g| g.fields.into_iter().map(|f| f.path))
.collect::<Vec<_>>();
expected.sort();
actual.sort();
assert_eq!(actual, expected, "{page:?}");
}
let keyboard = grouped_fields(Page::Keyboard, fields(Page::Keyboard));
assert!(
keyboard
.iter()
.find(|g| g.title == "Mouse")
.unwrap()
.fields
.iter()
.all(|f| f.path.starts_with("input.mouse."))
);
assert!(
keyboard
.iter()
.find(|g| g.title == "Touchpad")
.unwrap()
.fields
.iter()
.all(|f| f.path.starts_with("input.touchpad."))
);
let windows = grouped_fields(Page::Windows, fields(Page::Windows));
assert_eq!(
windows.iter().map(|g| g.title).collect::<Vec<_>>(),
vec![
"Workspaces and layout",
"Spacing and corners",
"Focus and window effects"
]
);
}
}