fix(app-iced): 缩略图墙一行两格 + 副文案只留元数据(出图实测)

- 3 格装不下:详情列宽 = FrameMetrics::column ≤ 424(1180 窗宽),卡片内宽约 370,
  3×160+2×12=504 会把第 3 格挤成一条竖条(实测图上『未生成预览』竖着排)。改成 2 格
  = 332px,与同列元信息卡的两列栅格同宽;
- 原因只进占位框(短句),副文案仍画『大小 · 时间』:160px 里塞「原因 + OS 原文」会摊成
  三行,把墙变得比图还吵;原文留在 ScreenshotThumbFailure::detail 供排障;
- 出图:DevDocs/artifacts/m251/saves-light.png / saves-dark.png(1180×1400,
  --software-renderer --screenshot,ULL_SAVES_FIXTURE=1)。
This commit is contained in:
AskaEth committed 2026-11-11 16:40:41 +08:00
1 parent 843f6d08f9
commit 0b6b8f0a62
4 files changed
+45 -36

No files matched your search

@@ -196,9 +196,9 @@ pub fn from_state(state: &SavesState, catalog: Catalog) -> Saves {
/// | 快照里的状态 | 框里 | 副文案 |
/// |---|---|---|
/// | `Ready`(像素自洽) | 真图 | `大小 · 时间` |
/// | `Ready`(像素长度不对) | 「解不出这张图」 | 同一句 + 原因(防御性:壳层不该拿到坏像素) |
/// | `NotGenerated` | 「未生成预览」 | 同一句(超预算没轮到) |
/// | `Failed` | 具名原因 | 原因 + OS/解码器原文(有的话) |
/// | `Ready`(像素长度不对) | 「解不出这张图」 | `大小 · 时间`(防御性:壳层不该拿到坏像素) |
/// | `NotGenerated` | 「未生成预览」 | `大小 · 时间`(超预算没轮到) |
/// | `Failed` | 具名原因(太大 / 读不出 / 解不出) | `大小 · 时间`(原文留在 DTO 里,不上墙) |
fn shot_cell(shot: &ScreenshotView, texts: Texts) -> Shot {
let stamp = rows::shot_detail(shot.bytes, shot.modified_ms, texts);
match &shot.preview {
@@ -212,31 +212,27 @@ fn shot_cell(shot: &ScreenshotView, texts: Texts) -> Shot {
},
// 像素长度与宽高对不上:壳层不该拿到这种数据,但拿到了也不能画成花屏。
ScreenshotPreview::Ready(_) => {
missing(shot, texts.saves_preview_reason(ScreenshotThumbKind::Decode), "")
missing(shot, texts.saves_preview_reason(ScreenshotThumbKind::Decode), stamp)
}
ScreenshotPreview::NotGenerated => {
missing(shot, texts.saves_preview_none(), stamp)
}
ScreenshotPreview::Failed(failure) => {
missing(shot, texts.saves_preview_reason(failure.kind), stamp)
}
ScreenshotPreview::NotGenerated => missing(shot, texts.saves_preview_none(), ""),
ScreenshotPreview::Failed(failure) => missing(
shot,
texts.saves_preview_reason(failure.kind),
failure.detail.as_str(),
),
}
}
/// 「没有可画的像素」那一格:框里一句短话,格子下面把原因说全。
/// 「没有可画的像素」那一格:**框里说为什么**(短句),**格子下面照旧是大小与时间**。
///
/// 短话与副文案**分开**是刻意的:`160×90` 的框里塞不下 OS 原文,而原文正是用户能自己动手的
/// 那一半信息(权限 / 被占用 / 文件没了),所以它去副文案那一行(会换行,不会丢)。
/// **不靠字符串切分**去拆两句:切分遇到「原因本身带括号」就会切错(这条踩过)。
fn missing(shot: &ScreenshotView, note: &str, detail: &str) -> Shot {
let caption = if detail.is_empty() {
note.to_string()
} else {
format!("{note}({detail})")
};
/// 为什么原因不进副文案:`160px` 宽的格子里,"原因 + OS 原文"会摊成三行,把墙变得比图还吵;
/// 而 `ScreenshotThumbFailure::detail`(`9437184 > 8388608 字节` / `Access is denied.`)留在
/// DTO 里,是排障用的原文,不是给墙看的正文。D54 第 6 条要的是「逐条、结构化、不是静默」——
/// 那一句在框里,每条各说各的。
fn missing(shot: &ScreenshotView, note: &str, stamp: String) -> Shot {
Shot {
name: shot.file.clone(),
detail: caption,
detail: stamp,
preview: ShotPreview::Missing {
note: note.to_string(),
},