docs(app-iced): 值字级注释改真 + probe 只认 buttons/divider + 截图主题钉死回归测试(M229 复审 r2)
1) P1-2 的注释值与量测对齐(四处):`elevated.rs` 的 `PAD`/`Texts::title`/`texts()` 与
`pages/instances/detail.rs` 还写着「值 14/400」,而实现是 12/400;`PAD` 文档更把 12px 的
118px 量测挂在「14px 下」。全部改成真值,并把 14px=138px 与 12px=118px 两个量测并列写清。
2) probe 门禁只解决一半:`SECTION=buttons` 绿、`SECTION=all` 仍红(sizes 段的实心块撞「按钮
40 高」判据),断言文案却写「all 或 buttons」。现在:
- 只支持 `buttons`(按钮矩阵,实心块判据**只量矩阵区**,后续段不再参与)与 `divider`
(分隔线两条判据,独立出口);
- `all` / 其它 / 未给 → 明确失败并给理由(整页比 1180×760 高,分隔线段与按钮矩阵不可能同屏;
整页图的 chip/卡片会被当按钮量);
- 模块文档的复现命令补上 `ULL_GALLERY_SECTION`(以前照着跑会 panic);
- `gallery/mod.rs` 的「五段」→ 七段;`gallery/buttons.rs` 的「8 行 + icon·standard」→ 9 行 + 四式。
3) 截图通道的主题档钉死此前没有回归测试(复审 r2 P2-a)。新增
`the_screenshot_channel_pins_the_theme_mode_instead_of_reading_the_file`:两份不同的机器配置 +
同一组截图参数 ⇒ 同一个档位且等于参数;反证非截图通道下两份配置确实分出两档。
变异自证:把分支改回 `bridge.load().1` → 该测试红(left: Dark, right: Light)。
门禁:fmt --check 0 / check -p unlucky-app-iced --all-targets 0 / test -p unlucky-app-iced 0
(887 passed + 6 integration)/ clippy -p unlucky-app-iced --all-targets -D warnings 0 / 400 行扫描干净。
probe 亲跑:buttons 浅+深两张 sheet OK,divider 一张 OK,`all` 按预期被拒。
This commit is contained in:
1 parent
8958b7f67d
commit
f5a2610e4d
7 files changed
+205
-69
No files matched your search
@@ -92,11 +92,6 @@ fn delta_ratio(pixel: [u8; 3], surface: [u8; 3], line: [u8; 3]) -> f32 {
|
||||
/// `ULL_GALLERY_SECTION=buttons`,不满足就明确失败——「跳过」会把「指错了图」变成静默通过。
|
||||
fn shot_path() -> Option<std::path::PathBuf> {
|
||||
let raw = std::env::var_os("ULL_GALLERY_SHOT")?;
|
||||
let section = std::env::var("ULL_GALLERY_SECTION").unwrap_or_default();
|
||||
assert!(
|
||||
!section.trim().is_empty(),
|
||||
"这份 probe 只认 `--screen=gallery` 出的 sheet:请同时给 `ULL_GALLERY_SECTION` (`all` 或 `buttons`)。整页图(页面自己的 chip / 卡片,实心块高 21)会被当成按钮量, 得到的是误导性的红。"
|
||||
);
|
||||
let path = std::path::PathBuf::from(raw);
|
||||
if path.is_absolute() || path.exists() {
|
||||
return Some(path);
|
||||
@@ -132,6 +127,31 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
};
|
||||
let ui = ui(flavor);
|
||||
|
||||
// 这份 probe **只认两种 sheet**(复审 r2 P2-b 的结论):
|
||||
//
|
||||
// - `ULL_GALLERY_SECTION=buttons`:按钮矩阵(五式 × 五态 + 图标四式)——本 probe 的主判据;
|
||||
// - `ULL_GALLERY_SECTION=divider`:分隔线的两条判据(1px / 墨量覆盖率)。
|
||||
//
|
||||
// **为什么不支持 `all`**:gallery 整页比 1180×760 的视口高,`all` 的 sheet 首屏里根本看不到
|
||||
// 分隔线段(实测 0 条长横线),而 sizes 段的实心块又会被「按钮 40 高」的判据量到。一张图装不下
|
||||
// 两段判据,所以按段出图、按段断言。
|
||||
//
|
||||
// **为什么必须给 SECTION**:整页图(下载页/设置页)的 chip 与卡片会被当成按钮量,
|
||||
// 那是误导性的红,不是缺陷。
|
||||
let section = std::env::var("ULL_GALLERY_SECTION")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_ascii_lowercase();
|
||||
assert!(
|
||||
section == "buttons" || section == "divider",
|
||||
"这份 probe 只支持 `ULL_GALLERY_SECTION=buttons`(按钮矩阵)或 `divider`(分隔线); 当前 {section:?}。`all` 不行:整页比视口高,分隔线段与按钮矩阵不可能同屏。"
|
||||
);
|
||||
// 分隔线那段是**独立出口**:`divider` 段的 sheet 里没有按钮矩阵,判据也不同。
|
||||
if section == "divider" {
|
||||
check_divider(&shot, &ui);
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- 12b 1.1 / 1.2:实心按钮 40 高、药丸圆角 20 ------------------------------
|
||||
let primary = shot.bbox_of(rgb(ui.color(Role::Primary)));
|
||||
assert!(
|
||||
@@ -140,12 +160,32 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
primary.len()
|
||||
);
|
||||
|
||||
// **只判「按钮矩阵那一段」**:`--screen=gallery` 默认(`ULL_GALLERY_SECTION=all`)会把
|
||||
// sizes / divider / selection / inputs / feedback / navigation 也画进来,它们各自的实心块
|
||||
// (chips 底、卡片、stop indicator…)不该被「按钮 40 高」这条判据量到 —— 复审 r2 P2-b 的现场
|
||||
// 就是 `all` 模式下在 y≈715 撞到一块 21 高的实心块,probe 红在一个根本不在量程里的东西上。
|
||||
//
|
||||
// 矩阵区的上下界由**第一块文字按钮**(宽 > 60、高 40)的顶边决定,往下 9 行 + 8px 余量。
|
||||
let matrix_top = primary
|
||||
.iter()
|
||||
.filter(|bbox| {
|
||||
bbox.area() >= 800 && bbox.width() > 60 && (39..=41).contains(&bbox.height())
|
||||
})
|
||||
.map(|bbox| bbox.top)
|
||||
.min()
|
||||
.expect("没找到文字按钮的实心块(矩阵不在画面里?)");
|
||||
let matrix_bottom = matrix_top + rows::ROW_COUNT * rows::ROW_STEP + 8;
|
||||
|
||||
let mut label_button = None;
|
||||
for bbox in &primary {
|
||||
// 字形(OnPrimary)会把实心块割出小碎片,只判「成块的」(40×40 = 1600)
|
||||
if bbox.area() < 800 {
|
||||
continue;
|
||||
}
|
||||
// 矩阵之外(后续段)的实心块不在这条判据的量程里。
|
||||
if bbox.top >= matrix_bottom {
|
||||
continue;
|
||||
}
|
||||
assert!(
|
||||
(39..=41).contains(&bbox.height()),
|
||||
"实心块高 {}(参考 40,12b 1.1)@ {:?}",
|
||||
@@ -263,52 +303,6 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
}
|
||||
assert!(measured_glyph, "没量到 IconButton 的字形");
|
||||
|
||||
// ---- 22.1:分隔线 1px(按「非底色的长横线」判,不按精确色:线被抗锯齿摊到两行)----
|
||||
//
|
||||
// **只在分隔线段被渲染时判**:`ULL_GALLERY_SECTION=buttons` 的 sheet 里没有分隔线,
|
||||
// 那一段是「没画」而不是「画错了」,断言只会误报(复审 P2 的同一类问题)。
|
||||
let section = std::env::var("ULL_GALLERY_SECTION")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_ascii_lowercase();
|
||||
let has_divider = section.is_empty() || section == "all" || section == "divider";
|
||||
let surface = rgb(ui.color(Role::Surface));
|
||||
let mut runs = 0usize;
|
||||
let mut coverage = f32::NAN;
|
||||
if has_divider {
|
||||
for y in 0..shot.height {
|
||||
let mut longest = 0;
|
||||
let mut current = 0;
|
||||
for x in 0..shot.width {
|
||||
if !matches(shot.at(x, y), surface) {
|
||||
current += 1;
|
||||
longest = longest.max(current);
|
||||
} else {
|
||||
current = 0;
|
||||
}
|
||||
}
|
||||
if longest > 300 {
|
||||
runs += 1;
|
||||
}
|
||||
}
|
||||
// 两条线 × 各摊 1~2 行 ⇒ 2..=4 行
|
||||
assert!(
|
||||
(2..=4).contains(&runs),
|
||||
"分隔线应 2 条(每条 1px,抗锯齿最多摊 2 行)⇒ 2..=4 行,实测 {runs} 行"
|
||||
);
|
||||
// **墨量覆盖率**:一条 1dp 的线,其各行相对底色的不透明覆盖率之和应 ≈1.0。
|
||||
// 1.5dp 的线会到 ≈1.5,2dp 会到 ≈2.0 —— 这是「容忍 1.5 倍粗」的补丁。
|
||||
let full = rgb(ui.color(Role::OutlineVariant));
|
||||
// 屏上正好 2 条线(通栏 + 列表内缩),所以把总墨量除以 2 得到「单条线的覆盖率」
|
||||
coverage = line_coverage(&shot, surface, full) / 2.0;
|
||||
assert!(
|
||||
(0.8..=1.3).contains(&coverage),
|
||||
"单条分隔线墨量覆盖率应 ≈1.0(= 1dp),实测 {coverage:.2}(1.5dp 会到 ~1.5)"
|
||||
);
|
||||
} else {
|
||||
eprintln!("[probe] section={section:?} 未渲染 divider 段,跳过分隔线判据");
|
||||
}
|
||||
|
||||
// ---- 12b 1.8 禁用态:容器 + **每一行**的内容色(A1 逐变体不同)----------------
|
||||
//
|
||||
// 上一版把两个 reviewer 都指出的重复块留在这里(`disabled_colors` 被调两次、
|
||||
@@ -350,18 +344,53 @@ fn gallery_geometry_matches_the_tokens() {
|
||||
Filled 药丸 {}×{}(参考 高 40 / 宽 ≥58)
|
||||
顶行左内缩 {}(r=20 应 ≈14;8 圆角 ≈4;直角 0)
|
||||
实心块 {} 个(含 40×40 IconButton)
|
||||
分隔线长行 {} 行(每条 1px;未渲染 divider 段时为 0)
|
||||
禁用容器 (on-surface@10%,按钮族) 命中 · 逐行禁用内容断言 {} 行通过
|
||||
分隔线墨量覆盖率 {:.2}(1dp 应 ≈1.0)
|
||||
字形墨迹 {}px(24 盒应 16~26)",
|
||||
flavor,
|
||||
label_button.width(),
|
||||
true_height,
|
||||
top_inset,
|
||||
primary.len(),
|
||||
runs,
|
||||
rows::ROW_COUNT,
|
||||
coverage,
|
||||
glyph_width
|
||||
);
|
||||
}
|
||||
|
||||
/// `ULL_GALLERY_SECTION=divider` 的两条判据:分隔线 2 条(各摊 1~2 行)与单条墨量覆盖率 ≈1.0。
|
||||
///
|
||||
/// 单独成函数:`divider` 段的 sheet 没有按钮矩阵,走不到主流程的按钮判据;而主流程也不需要
|
||||
/// 分隔线(`buttons` 段的 sheet 里根本没画线,断言只会误报)。
|
||||
fn check_divider(shot: &Shot, ui: &Ui) {
|
||||
let surface = rgb(ui.color(Role::Surface));
|
||||
let mut runs = 0usize;
|
||||
for y in 0..shot.height {
|
||||
let mut longest = 0;
|
||||
let mut current = 0;
|
||||
for x in 0..shot.width {
|
||||
if !matches(shot.at(x, y), surface) {
|
||||
current += 1;
|
||||
longest = longest.max(current);
|
||||
} else {
|
||||
current = 0;
|
||||
}
|
||||
}
|
||||
if longest > 300 {
|
||||
runs += 1;
|
||||
}
|
||||
}
|
||||
// 两条线 × 各摊 1~2 行 ⇒ 2..=4 行
|
||||
assert!(
|
||||
(2..=4).contains(&runs),
|
||||
"分隔线应 2 条(每条 1px,抗锯齿最多摊 2 行)⇒ 2..=4 行,实测 {runs} 行"
|
||||
);
|
||||
// **墨量覆盖率**:一条 1dp 的线,其各行相对底色的不透明覆盖率之和应 ≈1.0。
|
||||
// 1.5dp 的线会到 ≈1.5,2dp 会到 ≈2.0 —— 这是「容忍 1.5 倍粗」的补丁。
|
||||
let full = rgb(ui.color(Role::OutlineVariant));
|
||||
// 屏上正好 2 条线(通栏 + 列表内缩),所以把总墨量除以 2 得到「单条线的覆盖率」
|
||||
let coverage = line_coverage(shot, surface, full) / 2.0;
|
||||
assert!(
|
||||
(0.8..=1.3).contains(&coverage),
|
||||
"单条分隔线墨量覆盖率应 ≈1.0(= 1dp),实测 {coverage:.2}(1.5dp 会到 ~1.5)"
|
||||
);
|
||||
eprintln!("[probe] OK section=divider:分隔线 {runs} 行、单条覆盖率 {coverage:.2}");
|
||||
}
|
||||
Reference in new issue
Block a user