feat(app-iced): 禁用态合成底改成容器给的 Base(M234)

`interaction::disabled` 的四个入口一直收一个「底」,但 8 个调用点全传死
`Role::Surface`:卡片(SurfaceContainer)/ 面板(SurfaceContainerLow)里的禁用控件
把 10%(按钮族)/ 12%(面状控件族)叠在画布色上 —— M223「CR 1.05、形丢失」的根因。

- 新增 `interaction::Base`(画布 / 容器底的一等参数,`From<Role>` 兼容历史调用点);
  四个入口改成 `(ui, base, …)`,内部不再出现任何写死的 `Role::Surface`。
- 容器导出自己的 `BASE`:`surfaces::elevated::BASE`(卡)、`inputs::menu::PANEL_BASE`
  (菜单面板,项的 38% 与状态层都改叠它)、`navigation::drawer::BASE`。
- 控件收 `.base(..)`:Button / icon_on / Field / SearchBar / Slider / Checkbox / Radio /
  Switch / Chip / ListItem / Tabs;Fab 与 icon() 是画布默认值。
- `feedback/action.rs` 的本地 α 合成删掉,改走 `disabled_content_over_role` 并给真实容器底
  (Snackbar `InverseSurface` / Dialog `SurfaceContainerHigh`)。
- 判据:`interaction::disabled::tests`(卡片/面板/画布三档逐值)、
  `buttons::tests::base`(Button::base → StyleSpec → style_closure 接线)、
  `gallery` 新增 `disabledbase` 段 + `gallery::probe::bases` 精确像素断言
  (±10 容差区分不了 1/255 的差,所以自己数逐位相等的像素)。
- 变异自证:assemble 的调用点改回画布底后,上面两条都红(见 artifacts/m234/README.md)。

已知未尽:`crates/app-iced/src/pages/**` 不在 scope 内,页面侧「把控件放进卡片/面板」的
调用点尚未接 `.base(..)`(行为与本 mission 之前一致);`pages/…/java/tests/marker.rs`
有一行被迫更新(入口多了一个实参,语义不变 = 画布底)。
This commit is contained in:
AskaEth committed 2026-11-11 06:34:23 +08:00
1 parent a9d1cb4c44
commit 35dbefb08d
48 files changed
+1690 -496

No files matched your search

@@ -0,0 +1,90 @@
//! Chip 角色与状态层的单测(M234 从 `selection/tests.rs` 纯搬移,守 400 行硬线)。
//!
//! 搬移零改动:判据与注释一字未动,只是**换文件**(`tests.rs` 加了 `.base(..)` 之后到 422 行)。
use super::*;
/// §13.5 / §13.6 / §13.7:选中态**无描边**、Assist 不可选中、禁用文字 @38%。
#[test]
fn chip_roles_follow_the_tokens() {
let ui = ui();
let radius = ChipGeometry::of(&ui).radius;
let selected = paint::chip(
&ui,
Base::CANVAS,
ChipVariant::Filter,
true,
Interaction::Enabled,
radius,
);
assert_eq!(
selected.frame.fill,
Some(ui.color(Role::SecondaryContainer))
);
assert_eq!(selected.frame.outline, None, "13.5:选中描边 0dp");
assert_eq!(selected.label, ui.color(Role::OnSecondaryContainer));
let unselected = paint::chip(
&ui,
Base::CANVAS,
ChipVariant::Filter,
false,
Interaction::Enabled,
radius,
);
assert_eq!(
unselected.frame.outline,
Some(ui.color(Role::OutlineVariant))
);
assert_eq!(unselected.label, ui.color(Role::OnSurfaceVariant));
// Assist 没有选中态:即使传 selected = true 也不会变 SecondaryContainer
let assist = paint::chip(
&ui,
Base::CANVAS,
ChipVariant::Assist,
true,
Interaction::Enabled,
radius,
);
assert_ne!(assist.frame.fill, Some(ui.color(Role::SecondaryContainer)));
assert_eq!(
assist.icon,
ui.color(Role::Primary),
"13.4:Assist 前置图标 Primary"
);
let disabled = paint::chip(
&ui,
Base::CANVAS,
ChipVariant::Filter,
false,
Interaction::Disabled,
radius,
);
assert_ne!(disabled.label, unselected.label, "13.7:禁用文字降到 38%");
}
/// 状态层只在三态存在,且**不是**满档角色色(α 由 `interaction` 给)。
#[test]
fn state_layer_only_exists_on_lifted_states() {
let ui = ui();
for (state, expected) in [
(Interaction::Enabled, false),
(Interaction::Hovered, true),
(Interaction::Focused, true),
(Interaction::Pressed, true),
(Interaction::Disabled, false),
] {
let layer = paint::state_layer(&ui, state, Role::OnSurfaceVariant);
assert_eq!(layer.is_some(), expected, "{state:?} 的状态层有无");
if let Some(color) = layer {
assert_eq!(color.a, 1.0, "状态层必须是实色(D27:CPU/GPU 一致)");
}
}
// 同态下 hover 比 pressed 浅(8% < 10%)
let hover = paint::state_layer(&ui, Interaction::Hovered, Role::OnSurface).unwrap();
let pressed = paint::state_layer(&ui, Interaction::Pressed, Role::OnSurface).unwrap();
assert_ne!(hover, pressed);
}