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

@@ -24,7 +24,7 @@ use unlucky_design::typography::TypeRole;
use crate::icons;
use crate::theme::Ui;
use super::super::interaction::Interaction;
use super::super::interaction::{Base, Interaction};
use super::geometry::SwitchGeometry;
use super::paint::{self, Frame};
use super::shell::{self, StateSource};
@@ -36,6 +36,8 @@ pub struct Switch<'a, M> {
value: bool,
on_toggle: Option<M>,
state: Option<Interaction>,
/// 脚下那一层的底(M234,禁用态合成用)。
base: Base,
}
impl<'a, M> Switch<'a, M> {
@@ -46,6 +48,7 @@ impl<'a, M> Switch<'a, M> {
value,
on_toggle: Some(on_toggle),
state: None,
base: Base::CANVAS,
}
}
@@ -56,6 +59,7 @@ impl<'a, M> Switch<'a, M> {
value,
on_toggle: None,
state: None,
base: Base::CANVAS,
}
}
@@ -64,6 +68,12 @@ impl<'a, M> Switch<'a, M> {
self.state = Some(state);
self
}
/// **告诉开关它踩在什么底上**(M234):禁用态的 12% 轨道 / 38% 滑块叠在这个底上。
pub fn base(mut self, base: impl Into<Base>) -> Self {
self.base = base.into();
self
}
}
/// 画一个开关(轨道 + 滑块 + 标签)。
@@ -71,11 +81,12 @@ pub fn switch<'a, M: Clone + 'a>(ui: &'a Ui, spec: Switch<'a, M>) -> Element<'a,
let geometry = SwitchGeometry::of(ui);
let selected = spec.value;
let thumb_side = geometry.thumb(selected, false);
let base = spec.base;
let source = StateSource::new(spec.state, spec.on_toggle.is_some());
// 滑块内的勾:颜色只随选中/禁用变(A1 的 `Selected*IconColor` 都是 `OnPrimaryContainer`),
// 所以静态求值;未选中态官方图标色 = 轨道色(画了也看不见),因此不画。
let at_rest = paint::switch(ui, selected, source.get());
let at_rest = paint::switch(ui, base, selected, source.get());
let glyph: Element<'a, M> = match at_rest.icon {
Some(ink) => super::super::layout::centered_fixed(
geometry.icon,
@@ -94,7 +105,7 @@ pub fn switch<'a, M: Clone + 'a>(ui: &'a Ui, spec: Switch<'a, M>) -> Element<'a,
.align_y(Alignment::Center)
.style(source.container_style(move |state| {
Frame {
fill: Some(paint::switch(ui, selected, state).thumb),
fill: Some(paint::switch(ui, base, selected, state).thumb),
outline: None,
stroke: 0.0,
radius: thumb_side / 2.0,
@@ -124,7 +135,9 @@ pub fn switch<'a, M: Clone + 'a>(ui: &'a Ui, spec: Switch<'a, M>) -> Element<'a,
.width(Length::Fixed(geometry.track_width))
.height(Length::Fixed(geometry.track_height))
.style(source.container_style(move |state| {
paint::switch(ui, selected, state).track.container_style()
paint::switch(ui, base, selected, state)
.track
.container_style()
}));
// 绘制区 = 轨道 + 状态层外扩;两层叠放(层序:轨道在下,滑块与状态层在上)
@@ -159,7 +172,7 @@ pub fn switch<'a, M: Clone + 'a>(ui: &'a Ui, spec: Switch<'a, M>) -> Element<'a,
text(spec.label)
.size(style.size_px)
.font(ui.font_of(style))
.color(paint::label(ui, source.get())),
.color(paint::label(ui, base, source.get())),
);
}