fix(app-iced): pressed 状态层改走 Interaction 表 + 外观 choice 叠卡底(M284)

四处手写按钮(语言 chip / 主题 chip / 日志行两个动作 / 外观互斥按钮)把
`matches!(status, Hovered | Pressed)` 合成分支换成 `Interaction::from_status(status)`
→ `interaction::layer_color`:pressed 从被压成 hover 的 8% 回到令牌表的 10%。

`appearance/section/mod.rs` 的 `choice` 合成底从写死的 `Role::Surface` 换成
`frame::BASE.role()`(= `MaterialLayer::Card` = `SurfaceContainerLow`),与同屏
`general.rs` / `general/theme.rs` 同源——M234/M237 修过两轮的那个错,这是漏网的第三处。

四处样式闭包抽成自由函数(`choice_style` / `chip_style` / `action_style`),单测直接喂
`Hovered` 与 `Pressed`:断言两色不等 + 各自逐值等于 `state_over` 的令牌求值(改 α 也会红)。
语言行那枚 chip 的断言住在 `general/theme.rs`(`general.rs` 已 390 行,贴 400 硬线)。

未验:hover/pressed 的图像判据。`--force-state` 到不了设置页/外观区(那里不消费
`Model.forced`,`pages/harness.rs` 自己写着),接线另立任务;本轮只出 rest 图并比 md5。
This commit is contained in:
AskaEth committed 2026-11-12 21:48:03 +08:00
1 parent bc2ad85c63
commit 747521fe54
4 files changed
+373 -61

No files matched your search

+43 -19
View File
@@ -38,16 +38,20 @@
//!
//! 分组元数据只有一份(这里的 [`GROUP`]):`settings/mod.rs` 的 `GROUPS` 直接引用它。
use iced::border::Radius;
use iced::widget::{button, column, container, row};
use iced::{Alignment, Background, Border, Element, Length, Padding, Shadow, Theme as IcedTheme};
use iced::{
Alignment, Background, Border, Color, Element, Length, Padding, Shadow, Theme as IcedTheme,
};
use unlucky_design::color::{Role, StateLayer};
use unlucky_design::color::Role;
use unlucky_design::icons::IconKind;
use unlucky_design::spacing::Space;
use unlucky_design::typography::TypeRole;
use unlucky_i18n::catalog::Key;
use unlucky_i18n::LangChoice;
use crate::app::components::interaction::{self, Interaction};
use crate::fonts::install::{CjkInstall, FetchClass};
use crate::pages::{frame, Language, Message};
use crate::theme::Ui;
@@ -315,6 +319,8 @@ fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> El
ui.color(Role::OnSurfaceVariant)
};
let border_color = ui.color(Role::OutlineVariant);
let stroke = crate::theme::STROKE_PX;
let radius = ui.radius(box_.shape, height);
button(
container(frame::text_role(
@@ -331,18 +337,42 @@ fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> El
0.0,
unlucky_design::inkcat::metrics::CHIP_PAD_X,
]))
.style(move |_theme: &IcedTheme, status| {
.style(chip_style(
ui,
selected,
content_color,
border_color,
stroke,
radius,
))
.on_press(Message::Language(choice))
.into()
}
/// [`chip`] 的样式闭包(抽成自由函数:单测要**直接**喂 `Hovered` / `Pressed` 两态)。
///
/// - **α 只从 [`Interaction`] 来**:hover 8% / pressed 10%(M3)。M284 之前两种态合并成一条
/// `matches!(status, Hovered | Pressed)` 分支、都叠 `StateLayer::Hover`,按下于是被压成 8%;
/// - **合成底是 [`frame::BASE`]**(M237:这一组住在 `frame::card` 里,状态层叠卡底而不是画布)。
fn chip_style<'a>(
ui: &'a Ui,
selected: bool,
content_color: Color,
border_color: Color,
stroke: f32,
radius: Radius,
) -> impl Fn(&IcedTheme, button::Status) -> button::Style + 'a {
move |_theme, status| {
let background = if selected {
Some(Background::Color(ui.color(Role::SecondaryContainer)))
} else if matches!(status, button::Status::Hovered | button::Status::Pressed) {
// M237:这一组整个住在 `frame::card` 里,状态层叠**卡底**(不是画布)。
Some(Background::Color(ui.state_over(
StateLayer::Hover,
} else {
interaction::layer_color(
ui,
Interaction::from_status(status),
Role::OnSurface,
frame::BASE.role(),
)))
} else {
None
)
.map(Background::Color)
};
button::Style {
@@ -350,17 +380,11 @@ fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> El
text_color: content_color,
border: Border {
color: border_color,
width: if selected {
0.0
} else {
crate::theme::STROKE_PX
},
radius: ui.radius(box_.shape, height),
width: if selected { 0.0 } else { stroke },
radius,
},
shadow: Shadow::default(),
snap: true,
}
})
.on_press(Message::Language(choice))
.into()
}
}