--- id: T-204 title: 软件详情与图标缓存 phase: 2 deps: [T-203] status: DONE created: 2026-07-16 issue: null context_ref: db8d93e84337489a1a138a6f624df359add3ed36 claim_branch: null work_branch: agent/codex/T-204 write_paths: - docs/tasks/T-204.md - core/catalog/ - core/application/ - app-modern/ui/gio/ - app-win7/ui/gio/ - docs/api.md - docs/routes.md - docs/04-architecture.md - docs/current-state.md --- ## 问题 / 背景 软件行已经可选择,但还没有详情视图,也没有可信图标的后台缓存链路。若 Gio Layout 自行读文件、解码或请求图标,会直接违反每帧无 IO 约束;若磁盘图标不复核 Catalog 内容哈希,损坏或替换的缓存也可能被展示。 ## 方案 1. 在 `core/catalog` 建立 IconCache:以 `sha256:` + DPI 为键,按内存 → 磁盘 → 注入 Fetcher 顺序加载。 2. 远端图标必须满足大小上限、SHA-256 与可解码图片/尺寸上限后才能原子写入磁盘;磁盘命中同样复核哈希与图片头。 3. 磁盘文件按 digest + DPI 隔离;新进程在 Fetcher 离线时仍可读取已验证缓存。 4. `CatalogListItem` 补充 icon/homepage/tutorial 数据与 selected item 查询。 5. modern/win7 在选中软件时显示右侧详情面板,含关闭、版本、分类、简介、tags、状态、不可用原因和教程/主页信息。 6. UI 只提供 `ApplyIcon(appID, image.Image)` 接收后台已解码结果;Layout 仅绘制内存图像,未命中时显示字母占位。 ## 验收要点 - 同一 digest+DPI 首次远端加载,随后内存命中;新 cache 实例断网时可从磁盘命中。 - 不同 DPI 使用不同磁盘键;哈希不符、超限、不可解码/超尺寸图标不写缓存。 - 损坏磁盘缓存不会被返回;有网络时可重新获取修复,离线时返回明确错误。 - 点击行后详情右栏可见且可关闭;列表/详情均能显示后台 ApplyIcon 的内存图像或稳定占位。 - 两个 Gio Layout 中无磁盘、网络、哈希或图片解码。 - Go 1.20 core vet/test、modern/win7 UI 测试与构建、完整闸门和治理校验通过。 ## 边界(不改什么) - 不决定图标 URL/变体的最终 Catalog 字段;Fetcher 由装配层按发布端协议注入。 - 不实现网络请求装配、图片缩放生成、LRU/容量淘汰或 CDN 缓存策略。 - 不实现真实下载/安装/启动动作和许可证详情;详情只展示当前可用事实与后续操作语义。 - 不在 UI 中调用 image.Decode、os、http 或 sha256。 ## 协作约束 未启用 Gitea;本任务在 `agent/codex/T-204` 分支串行执行。延续 `ui-ux-pro-max` 的扁平高对比、44dp、清晰返回/关闭、上下文保留和无昂贵 Layout 工作约束。 ## 执行记录 - 2026-07-16:在 `core/catalog` 建立 IconCache;键为规范化 SHA-256 digest + DPI,加载顺序为 memory → verified disk → injected fetcher,返回 source 与非致命磁盘写 warning。 - 2026-07-16:远端和磁盘统一复核内容哈希、图片完整解码、默认 2 MiB 与 2048×2048 上限;只把验证成功字节用同目录临时文件原子写入,symlink/非普通缓存项拒绝。 - 2026-07-16:测试覆盖首次 remote、随后 memory、新实例断网 disk、96/144 DPI 分盘、哈希不符、非法图片、字节/尺寸超限、坏磁盘在线修复与坏磁盘离线明确失败。 - 2026-07-16:`CatalogListItem` 增加 IconRef/Homepage/Tutorial 与 SelectedItem 查询;筛选/滚动上下文不因打开或关闭详情而重置。 - 2026-07-16:modern/win7 均实现右侧详情、明确“关闭”文字按钮、版本/分类/简介/tags/状态/不可用原因/教程/主页展示;未接入的安装/启动/授权没有伪装为可执行动作。 - 2026-07-16:两个 Gio 适配增加 `ApplyIcon(appID, image.Image)`,在调用时预建 `paint.ImageOp`;列表和详情每帧只复用内存绘制操作,未命中使用非 emoji 字母占位。 - 2026-07-16:按 `ui-ux-pro-max` 交付复查确认关闭按钮有可访问文字名、返回保持上下文,详情延续高对比扁平/44dp 交互体系。 - 2026-07-16:同步 `docs/api.md`、`docs/routes.md`、`docs/04-architecture.md` 与 `docs/current-state.md`;图标下载位置/分辨率映射仍明确留给发布端协议,客户端不猜 URL。 - 定向验证通过:`go -C core test -count=1 ./catalog ./application`、modern/win7 `go test -count=1 ./ui/gio`。 - Layout IO/解码扫描通过:`rg` 检查两个 `ui/gio` 下无 `image.Decode`、`os`、`net/http`、文件读写、filepath 或 sha256 调用。 - 完整验证通过:`./scripts/verify_phase0.ps1`,包含 Go 1.20.14 core vet/test、治理/边界/版本检查及 modern/win7 双目标测试与构建。 - 提交前检查通过:`git diff --check`。 - 工作区中的未跟踪 `soft_quay.code-workspace` 与本任务无关,已保留且未纳入提交。