Reduce Settings page and config reload overhead

Mount nearby shortcut and theme rows, preserve gallery keyboard navigation, reset page scrolling, and reuse native themes during palette transitions. Prepare and deduplicate live config reloads on a worker and apply only changed runtime sections.

Align pointer focus and overview selection on overlapping outputs, add regression coverage, and clean up workspace Clippy warnings.
This commit is contained in:
Samuel Onoja committed 2026-10-02 23:10:01 +01:00
1 parent 629414e0fb
commit 647eaf4ad9
23 files changed
+1098 -220

No files matched your search

+127
View File
@@ -0,0 +1,127 @@
use cosmic::iced::advanced::widget::Id;
use cosmic::iced::advanced::widget::operation::{Operation, Scrollable};
use cosmic::iced::{Rectangle, Vector};
pub(super) fn gallery_list(appearance: Option<ferese_config::theme::Appearance>) -> &'static str {
match appearance {
Some(ferese_config::theme::Appearance::Light) => "theme-light",
Some(ferese_config::theme::Appearance::Dark) => "theme-dark",
None => "theme",
}
}
pub(super) fn gallery_row_id(list: &str, row: usize) -> Id {
Id::new(format!("{list}-row-{row}"))
}
pub(super) struct RevealRow {
target: Id,
bounds: Option<Rectangle>,
}
impl RevealRow {
pub(super) fn new(list: &str, row: usize) -> Self {
Self {
target: gallery_row_id(list, row),
bounds: None,
}
}
}
impl<M> Operation<M> for RevealRow {
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<M>)) {
operate(self);
}
fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
if id == Some(&self.target) {
self.bounds = Some(bounds);
}
}
fn scrollable(
&mut self,
id: Option<&Id>,
viewport: Rectangle,
_: Rectangle,
translation: Vector,
state: &mut dyn Scrollable,
) {
if id != Some(&Id::new("settings-content")) {
return;
}
if let Some(target) = self.bounds {
let visible = target.y - translation.y;
let delta = if visible < viewport.y {
visible - viewport.y
} else if visible + target.height > viewport.y + viewport.height {
visible + target.height - viewport.y - viewport.height
} else {
return;
};
state.scroll_to(cosmic::iced::widget::scrollable::AbsoluteOffset {
x: None,
y: Some((translation.y + delta).max(0.)),
});
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use cosmic::iced::advanced::widget::operation::scrollable::{AbsoluteOffset, RelativeOffset};
#[derive(Default)]
struct Scroll(Option<AbsoluteOffset<Option<f32>>>);
impl Scrollable for Scroll {
fn snap_to(&mut self, _: RelativeOffset<Option<f32>>) {
panic!("not a snap");
}
fn scroll_to(&mut self, offset: AbsoluteOffset<Option<f32>>) {
self.0 = Some(offset);
}
fn scroll_by(&mut self, _: AbsoluteOffset, _: Rectangle, _: Rectangle) {
panic!("not a relative scroll");
}
}
#[test]
fn wrapping_and_home_end_reveal_only_as_much_as_needed() {
let viewport = Rectangle {
x: 0.,
y: 40.,
width: 600.,
height: 500.,
};
for (top, height, offset, expected) in [
(1000., 200., 0., Some(660.)),
(40., 200., 500., Some(0.)),
(100., 200., 0., None),
] {
let mut operation = RevealRow::new("theme", 10);
let target = operation.target.clone();
Operation::<()>::container(
&mut operation,
Some(&target),
Rectangle {
y: top,
height,
..viewport
},
);
let mut state = Scroll::default();
Operation::<()>::scrollable(
&mut operation,
Some(&Id::new("settings-content")),
viewport,
viewport,
Vector::new(0., offset),
&mut state,
);
assert_eq!(state.0.and_then(|offset| offset.y), expected);
}
}
}