fix(app-iced): M75 r5 —— 禁用内容角色按变体(A1)+ 删 probe 重复块 + 逐行护栏

1) A1 逐变体(AAR javap):Filled/Elevated/Outlined/Text = OnSurfaceVariant@0.38;
   FilledTonal = OnSurface@0.38(FilledTonalButtonTokens.DisabledLabelTextColor);
   Standard/Filled IconButton = OnSurface@0.38(*IconButtonTokens.DisabledColor)。
   新增 Variant::disabled_content() / IconVariant::disabled_content(),
   interaction::disabled_content_over_role(ui, role, on_container) 成唯一入口。
2) probe.rs 删掉被两个 reviewer 点名的重复块(disabled_colors 调用两次、
   disabled_container 绑定两次),并补 grep 证据。
3) 护栏改成**逐行**:矩阵 7 个有内容的变体行各自断言 disabled 列的 38% 墨迹 > 40 px
   (浅/深同一套阈值,单行回退就会红),取代原来按浅色标定的全局 500 阈值。
6) 删掉 interaction/mod.rs 里挂在 mod tests 头上的悬挂文档。
This commit is contained in:
AskaEth committed 2026-11-02 04:51:03 +08:00
1 parent b31a758cda
commit eed1c9d3f7
5 files changed
+99 -51

No files matched your search

+34 -31
View File
@@ -23,6 +23,8 @@ use unlucky_design::typography::Platform;
use crate::theme::{Families, Ui};
use crate::app::components::interaction;
use super::scan::{matches, nearer, rgb, Shot};
const FAMILIES: Families = Families {
@@ -312,9 +314,12 @@ fn gallery_geometry_matches_the_tokens() {
"单条分隔线墨量覆盖率应 ≈1.0(= 1dp),实测 {coverage:.2}(1.5dp 会到 ~1.5)"
);
// ---- 12b 1.8:禁用格必须与静息格不同 ------------------------------------
let disabled_container =
crate::app::components::interaction::disabled_colors(&ui, Role::Surface).0;
// ---- 12b 1.8 禁用态:容器 + **每一行**的内容色(A1 逐变体不同)----------------
//
// 上一版把两个 reviewer 都指出的重复块留在这里(`disabled_colors` 被调两次、
// `disabled_container` 被绑定两次),且只有一条「全图数墨迹」的护栏 —— 深色下阈值失效、
// 单行回退也抓不住。现在按矩阵的行逐条断言。
let (disabled_container, _) = interaction::disabled_colors(&ui, Role::Surface);
assert!(
shot.bbox_of(rgb(disabled_container))
.iter()
@@ -322,37 +327,36 @@ fn gallery_geometry_matches_the_tokens() {
"没找到禁用态实心按钮(12b 1.8:容器 = on-surface@12%)"
);
// ---- 12b 1.8(视觉 reviewer 的 P1-A):禁用态的内容色必须真的下发 ----
let (disabled_container, disabled_ink) =
crate::app::components::interaction::disabled_colors(&ui, Role::Surface);
let ink_px = count_pixels(&shot, rgb(disabled_ink));
assert!(
ink_px > 200,
"**有容器**四式的禁用内容(OnSurfaceVariant@38% 叠 12% 容器)只出现 {ink_px} 像素: 说明 Filled/Tonal/Elevated 的字形没走 38%"
);
// 矩阵行序(gallery/buttons.rs 的 Variant::ALL + IconVariant::ALL),行距 48 = 40 + 8
let row_step = 48usize;
let rows: [(usize, Role, bool, &str); 7] = [
(0, Role::OnSurfaceVariant, true, "filled"),
(1, Role::OnSurface, true, "tonal"), // A1:FilledTonal 是例外
(2, Role::OnSurfaceVariant, true, "elevated"),
(3, Role::OnSurfaceVariant, false, "outlined"),
(4, Role::OnSurfaceVariant, false, "text"),
(5, Role::OnSurface, false, "icon·standard"), // A1:IconButton 全是 OnSurface
(6, Role::OnSurface, false, "icon·filled"),
];
let column_from = shot.width * 2 / 3; // 矩阵最右列 = disabled 列
for (index, role, on_container, name) in rows {
let y0 = label_button.top + index * row_step;
let y1 = y0 + 44;
let ink = interaction::disabled_content_over_role(&ui, role, on_container);
let count = shot.count_in(rgb(ink), column_from, shot.width, y0, y1);
assert!(
count > 40,
"{name} 行的禁用内容({role:?}@38%)在 disabled 列里只有 {count} px —— 说明这一行没走 A1 的禁用角色"
);
}
// **无容器**三式(Text / Outlined / standard IconButton)的禁用内容叠在 surface 上,
// 是另一个色值;单查上面那个只会覆盖到有容器的四式(reviewer code-r2 p2-1:护栏漏一半)。
let bare_ink = crate::app::components::interaction::disabled_content_over(&ui, Role::Surface);
// **只数 disabled 列**(矩阵最右那一列,x ≥ 全宽 2/3):整图计数会被别处的抗锯齿像素
// 抬到 1000+,把该列涂回满档色也降不到阈值以下 —— 那正是「护栏拦不住」的成因。
let bare_px = shot.count_pixels_in(rgb(bare_ink), shot.width * 2 / 3, shot.width);
// 阈值 500 的来历(实测,矩阵 8 行 × 5 列):
// 浅色正常 800 px、深色正常 1966 px;把 disabled 列的 38% 墨迹涂回满档色后只剩 348 px
// (剩下的都是别处抗锯齿像素恰好落进容差)——所以 500 是「真墨迹在 / 不在」的分界。
assert!(
bare_px > 500,
"**无容器**三式在 disabled 列里的 38% 墨迹只出现 {bare_px} 像素: 说明 Text/Outlined/standard 的字形没走 38%"
);
// filled 禁用容器里不许出现满档 OnPrimary(旧实现是 #FFFFFF 压在 12% 容器上 = 1.23:1)
// filled 禁用容器里不许出现满档 OnPrimary(旧实现是白字压在 12% 容器上 = 1.23:1)
let full_content = rgb(ui.color(Role::OnPrimary));
for bbox in shot.bbox_of(rgb(disabled_container)) {
if bbox.width() < 60 {
continue;
}
// 只扫**内带**:圆角外的页面底色 (246,250,255) 与 OnPrimary(255,255,255) 在容差内,
// 贴边扫描会把圆角透出的底色当成「满档内容」(首版就在 (866,162) 误报)。
// 只扫**内带**:圆角外的页面底色与 OnPrimary 在容差内,贴边扫描会误报。
for y in (bbox.top + 12)..=(bbox.bottom - 12) {
for x in (bbox.left + 12)..=(bbox.right - 12) {
assert!(
@@ -369,7 +373,7 @@ fn gallery_geometry_matches_the_tokens() {
顶行左内缩 {}(r=20 应 ≈14;8 圆角 ≈4;直角 0)
实心块 {} 个(含 40×40 IconButton)
分隔线长行 {} 行(每条 1px)
禁用容器 (on-surface@12%) 命中 · 禁用内容 38% 墨迹 {} px(有容器)/ {} px(无容器)
禁用容器 (on-surface@12%) 命中 · 逐行禁用内容断言 {} 行通过
分隔线墨量覆盖率 {:.2}(1dp 应 ≈1.0)
字形墨迹 {}px(24 盒应 16~26)",
flavor,
@@ -378,8 +382,7 @@ fn gallery_geometry_matches_the_tokens() {
top_inset,
primary.len(),
runs,
ink_px,
bare_px,
rows.len(),
coverage,
glyph_width
);