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

@@ -49,7 +49,7 @@ use unlucky_design::shape::ShapeScale;
use crate::icons;
use crate::theme::Ui;
use super::super::interaction::{self, Interaction};
use super::super::interaction::{self, Base, Interaction};
use super::super::layout;
use super::geometry::{
typography_headline, typography_overline, typography_supporting, ListItemGeometry,
@@ -66,6 +66,8 @@ pub struct ListItem<'a, M> {
on_press: Option<M>,
selected: bool,
state: Option<Interaction>,
/// 脚下那一层的底(M234,禁用态合成用)。
base: Base,
}
impl<'a, M> ListItem<'a, M> {
@@ -80,6 +82,7 @@ impl<'a, M> ListItem<'a, M> {
on_press: Some(on_press),
selected: false,
state: None,
base: Base::CANVAS,
}
}
@@ -119,6 +122,12 @@ impl<'a, M> ListItem<'a, M> {
self
}
/// **告诉列表项它踩在什么底上**(M234):禁用态的 38% 内容叠在这个底上。
pub fn base(mut self, base: impl Into<Base>) -> Self {
self.base = base.into();
self
}
/// 转禁用:**只清消息**,槽位与选中态一律保留。
pub fn disabled(mut self) -> Self {
self.on_press = None;
@@ -141,10 +150,10 @@ struct ItemPalette {
trailing: Color,
}
fn palette(ui: &Ui, state: Interaction, selected: bool) -> ItemPalette {
fn palette(ui: &Ui, base: Base, state: Interaction, selected: bool) -> ItemPalette {
if state.is_disabled() {
// A1:ListItemDisabled*Color = OnSurface × 0.38(无容器时叠在 surface 上)
let ink = interaction::disabled_content_over_role(ui, Role::OnSurface, false);
let ink = interaction::disabled_content_over_role(ui, base, Role::OnSurface, false);
return ItemPalette {
fill: None,
headline: ink,
@@ -213,7 +222,12 @@ pub fn list_item<'a, M: Clone + 'a>(ui: &'a Ui, item: ListItem<'a, M>) -> Elemen
} else {
None
});
let colors = palette(ui, forced.unwrap_or(Interaction::Enabled), item.selected);
let colors = palette(
ui,
item.base,
forced.unwrap_or(Interaction::Enabled),
item.selected,
);
let mut body = iced::widget::Column::new().spacing(0);
if let Some(overline) = item.overline {
@@ -268,9 +282,10 @@ pub fn list_item<'a, M: Clone + 'a>(ui: &'a Ui, item: ListItem<'a, M>) -> Elemen
.align_y(Alignment::Center);
let selected = item.selected;
let base = item.base;
let style = move |_theme: &iced::Theme, status: button::Status| {
let state = forced.unwrap_or_else(|| Interaction::from_status(status));
let colors = palette(ui, state, selected);
let colors = palette(ui, base, state, selected);
button::Style {
background: colors.fill.map(Background::Color),
text_color: colors.headline,