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:
1 parent
a9d1cb4c44
commit
35dbefb08d
48 files changed
+1690
-496
No files matched your search
@@ -50,7 +50,7 @@ use unlucky_design::typography::TypeRole;
|
||||
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::{TabsGeometry, TABS_ICON_HEIGHT};
|
||||
|
||||
@@ -133,6 +133,8 @@ impl<'a, M> Tab<'a, M> {
|
||||
pub struct Tabs<'a, M> {
|
||||
variant: TabsVariant,
|
||||
tabs: Vec<Tab<'a, M>>,
|
||||
/// 脚下那一层的底(M234,禁用态合成用)。
|
||||
base: Base,
|
||||
}
|
||||
|
||||
impl<'a, M> Tabs<'a, M> {
|
||||
@@ -141,6 +143,7 @@ impl<'a, M> Tabs<'a, M> {
|
||||
Self {
|
||||
variant: TabsVariant::Primary,
|
||||
tabs: Vec::new(),
|
||||
base: Base::CANVAS,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +152,7 @@ impl<'a, M> Tabs<'a, M> {
|
||||
Self {
|
||||
variant: TabsVariant::Secondary,
|
||||
tabs: Vec::new(),
|
||||
base: Base::CANVAS,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,14 +161,20 @@ impl<'a, M> Tabs<'a, M> {
|
||||
self.tabs.push(tab);
|
||||
self
|
||||
}
|
||||
|
||||
/// **告诉 tab 条它踩在什么底上**(M234):禁用态的 38% 标签/指示条叠在这个底上。
|
||||
pub fn base(mut self, base: impl Into<Base>) -> Self {
|
||||
self.base = base.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// 一个 tab 的内容色(A1 的 `Active*` / `Inactive*` / 各态表,见模块文档)。
|
||||
fn content_color(ui: &Ui, primary: bool, state: Interaction, selected: bool) -> Color {
|
||||
fn content_color(ui: &Ui, base: Base, primary: bool, state: Interaction, selected: bool) -> Color {
|
||||
if state.is_disabled() {
|
||||
// A1 的 Tabs 没有 Disabled* token(实读:Primary/Secondary 两套都只有 Active/Inactive × 四态),
|
||||
// 按 ListItem 的 38% 口径处理 —— 登记 `[估]`。
|
||||
return interaction::disabled_content_over_role(ui, Role::OnSurface, false);
|
||||
return interaction::disabled_content_over_role(ui, base, Role::OnSurface, false);
|
||||
}
|
||||
if selected {
|
||||
// 6.5:Primary 选中 `Primary`;Secondary 选中 `OnSurface`
|
||||
@@ -182,13 +192,14 @@ fn content_color(ui: &Ui, primary: bool, state: Interaction, selected: bool) ->
|
||||
}
|
||||
|
||||
/// Primary 指示条的颜色(只有选中项有;禁用项降档,否则「点不动却亮着」)。
|
||||
fn bar_color(ui: &Ui, state: Interaction, selected: bool) -> Option<Color> {
|
||||
fn bar_color(ui: &Ui, base: Base, state: Interaction, selected: bool) -> Option<Color> {
|
||||
if !selected {
|
||||
return None;
|
||||
}
|
||||
if state.is_disabled() {
|
||||
return Some(interaction::disabled_content_over_role(
|
||||
ui,
|
||||
base,
|
||||
Role::OnSurface,
|
||||
false,
|
||||
));
|
||||
@@ -207,6 +218,7 @@ fn secondary_line_color(ui: &Ui) -> Color {
|
||||
pub fn tabs<'a, M: Clone + 'a>(ui: &'a Ui, tabs: Tabs<'a, M>) -> Element<'a, M> {
|
||||
let geometry = TabsGeometry::of(ui);
|
||||
let primary = tabs.variant.is_primary();
|
||||
let base = tabs.base;
|
||||
// 6.1:带图标时容器高 **64**(`IconAndLabelTextContainerHeight`),纯文字 48
|
||||
let height = if tabs.tabs.iter().any(|tab| tab.icon.is_some()) {
|
||||
TABS_ICON_HEIGHT
|
||||
@@ -218,7 +230,7 @@ pub fn tabs<'a, M: Clone + 'a>(ui: &'a Ui, tabs: Tabs<'a, M>) -> Element<'a, M>
|
||||
.height(Length::Fixed(height))
|
||||
.align_y(Alignment::Center);
|
||||
for tab in tabs.tabs {
|
||||
row = row.push(tab_cell(ui, tab, geometry, primary, height));
|
||||
row = row.push(tab_cell(ui, base, tab, geometry, primary, height));
|
||||
}
|
||||
|
||||
let body: Element<'a, M> = if primary {
|
||||
@@ -254,8 +266,10 @@ pub fn tabs<'a, M: Clone + 'a>(ui: &'a Ui, tabs: Tabs<'a, M>) -> Element<'a, M>
|
||||
}
|
||||
|
||||
/// 一个 tab 单元(内容 + 底部条)。
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn tab_cell<'a, M: Clone + 'a>(
|
||||
ui: &'a Ui,
|
||||
base: Base,
|
||||
tab: Tab<'a, M>,
|
||||
geometry: TabsGeometry,
|
||||
primary: bool,
|
||||
@@ -268,7 +282,7 @@ fn tab_cell<'a, M: Clone + 'a>(
|
||||
});
|
||||
let state = forced.unwrap_or(Interaction::Enabled);
|
||||
let selected = tab.selected;
|
||||
let color = content_color(ui, primary, state, selected);
|
||||
let color = content_color(ui, base, primary, state, selected);
|
||||
let style = ui.style(TypeRole::TitleSmall);
|
||||
|
||||
let label = text(tab.label)
|
||||
@@ -291,7 +305,7 @@ fn tab_cell<'a, M: Clone + 'a>(
|
||||
|
||||
let bar_height = geometry.bar(primary);
|
||||
// 底层:内容自己决定宽度(Shrink),底部留出条的高度 —— 未选中的 Primary tab 也占同样的高
|
||||
let base = container(content)
|
||||
let cell = container(content)
|
||||
.height(Length::Fixed(height))
|
||||
// Q21:要给居中就两轴都显式给(`Container` 默认 Left/Top)
|
||||
.align_x(Alignment::Center)
|
||||
@@ -305,12 +319,12 @@ fn tab_cell<'a, M: Clone + 'a>(
|
||||
|
||||
// Primary:逐 tab 画条(要跟随该 tab 的宽度);Secondary:整行一条,在 `tabs()` 里画
|
||||
let bar = if primary {
|
||||
bar_color(ui, state, selected)
|
||||
bar_color(ui, base, state, selected)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let radius = geometry.indicator_radius();
|
||||
let mut stack = Stack::new().push(base);
|
||||
let mut stack = Stack::new().push(cell);
|
||||
if let Some(color) = bar {
|
||||
// 上层:Fill —— `Stack` 先按底层定尺寸,所以这里的 Fill = 这个 tab 的宽(不是整行)
|
||||
stack = stack.push(
|
||||
@@ -333,7 +347,7 @@ fn tab_cell<'a, M: Clone + 'a>(
|
||||
);
|
||||
}
|
||||
|
||||
let fill = interaction::overlay_color(ui, state, Role::OnSurface, Role::Surface);
|
||||
let fill = interaction::overlay_color(ui, state, Role::OnSurface, base.role());
|
||||
let button = button(stack)
|
||||
.height(Length::Fixed(height))
|
||||
.padding(0)
|
||||
|
||||
Reference in new issue
Block a user