Add app details and icon cache (T-204)
This commit is contained in:
@@ -61,6 +61,8 @@ UI 固定交互模式:
|
||||
|
||||
T-203 已把共享列表状态落在 `core/application.CatalogListModel`:源快照、搜索、单分类、all/installed/updates 视图和 selected app ID 都是无 IO 纯内存状态。两个 Gio 适配分别保存 Editor、`layout.List` 与以 app ID 为键的 Clickable;500 项 viewport 测试验证只布局可见行。主循环或后台用例通过 `SetItems` 替换准备好的快照,Layout 不扫描 installed-app.json、不获取 Catalog。
|
||||
|
||||
T-204 图标链路为 `Catalog icon digest + DPI → IconFetcher → SHA-256/图片资源限制校验 → 原子磁盘缓存 → 内存字节 → 后台 DecodeIcon → UI ApplyIcon(paint.ImageOp)`。磁盘与远端都重新校验;断网只使用已验证磁盘缓存。两个详情右栏只读取 `CatalogListModel.SelectedItem` 与内存 ImageOp,关闭详情不清空筛选或列表位置。
|
||||
|
||||
## 三、仓库目录结构
|
||||
|
||||
```text
|
||||
|
||||
+14
-1
@@ -76,6 +76,19 @@
|
||||
|
||||
T-201 已把该签名域接入正式客户端加载链路并用客户端测试向量覆盖。`softbox-catalog` 发布端仍必须补跨实现向量测试;密钥 ID/轮换字段尚未定稿,在单公钥协议升级前不得另造签名域。
|
||||
|
||||
### 1.2 图标内容引用与本地缓存
|
||||
|
||||
Catalog `icon` v1 是 `sha256:<64 hex>` 内容引用,不是可直接请求的 URL。最终分发字段仍由发布端定稿;客户端通过注入的 IconFetcher 把引用解析为图标字节,不得在 UI 中拼接或猜测 URL。
|
||||
|
||||
客户端缓存合约:
|
||||
|
||||
1. 请求键为 `(icon digest, DPI)`;DPI 接受 48~768 的整数值。
|
||||
2. 加载顺序为内存 → 磁盘 → 注入 Fetcher;磁盘文件名为 `<digest>-<dpi>.icon`。
|
||||
3. 远端和磁盘字节都必须复核 SHA-256,并通过图片解码、2 MiB 默认字节上限与 2048×2048 默认尺寸上限。
|
||||
4. 只有验证成功的远端字节可用同目录临时文件原子写入磁盘;损坏的普通缓存文件删除后可重新获取,symlink/非普通文件按不安全布局拒绝。
|
||||
5. 新进程断网时可读取再次验证成功的磁盘缓存;缓存损坏且远端不可用时返回 `no valid icon available`,UI 使用稳定占位图。
|
||||
6. 后台完成 `IconCache.Load` 与 `DecodeIcon` 后调用 Gio `ApplyIcon`;Layout 只复用内存 `paint.ImageOp`。
|
||||
|
||||
## 2. 标准软件包协议 v1(ZIP)
|
||||
|
||||
```text
|
||||
@@ -267,6 +280,6 @@ V1.1:命名管道 `\\.\pipe\softbox.<app-id>`,盒子发送 `{"command": "prepare
|
||||
|
||||
- 清单密钥 ID/轮换字段定稿后同步 `schemas/`。
|
||||
- 错误码完整枚举表。
|
||||
- 图标资源的分发方式(内嵌哈希 vs 独立 URL)。
|
||||
- 图标资源从内容哈希到下载位置/分辨率变体的发布端映射格式。
|
||||
- 撤销名单的结构与宽限期时长。
|
||||
- machine_hash 的标识来源清单与加权算法(平台层内部文档)。
|
||||
|
||||
+10
-10
@@ -13,26 +13,26 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-16
|
||||
- 阶段:Phase 2 进行中;T-201~T-203 已完成,下一步 T-204 软件详情与图标缓存
|
||||
- 阶段:Phase 2 已完成(T-201~T-204);下一步 Phase 3 的 T-301 下载队列
|
||||
- 技术栈:根 Go workspace 纳入 core/app-modern/app-win7 三模块;`app-win7/go.work` 隔离 Go 1.20.14 构建;modern Gio v0.10.1 与 win7 Gio v0.6.0 已实际接入
|
||||
- 生产代码:core 已有 Catalog/本地状态/存储与无 IO 软件列表模型;modern/win7 AppShell 已实现搜索、分类、全部/已安装/可更新切换和惰性软件列表;安装安全原型保持可用
|
||||
- 测试:core 覆盖 Catalog、SemVer/12 状态、本地安装记录与列表筛选;两个 app 覆盖 AppShell、500 项虚拟列表、ID 控件稳定性与平台 stub;ZIP/安装恢复矩阵保持通过
|
||||
- 生产代码:core 已有 Catalog/本地状态/存储、无 IO 软件列表模型与按 digest+DPI 的可信图标缓存;modern/win7 AppShell 已实现搜索/分类/视图、惰性列表、详情右栏与内存图标
|
||||
- 测试:core 覆盖 Catalog、SemVer/12 状态、本地安装记录、列表筛选和图标内存/磁盘/离线/损坏恢复;两个 app 覆盖 500 项虚拟列表、ID 控件稳定性、详情/ApplyIcon 与平台 stub;ZIP/安装恢复矩阵保持通过
|
||||
- 数据:`schemas/` 已有 manifest/app.json/installed-app.json v1 Schema;`testdata/catalog/` 有公开虚构清单样例;`testdata/zip/` 记录运行时生成的 ZIP 攻击矩阵
|
||||
- 标准启动路径:`./init.sh` / `./init.ps1`(同步依赖、执行完整 Phase 0 闸门、打印双目标构建命令)
|
||||
- 标准验证路径:`bash scripts/verify_phase0.sh` / `./scripts/verify_phase0.ps1`
|
||||
- 版本管理:git 已初始化,main 分支,远端 origin 为 Gitea `opc/soft_quay`;harness 文档已提交
|
||||
- 当前 blocker:无;下一步按路线图落成并领取 T-204
|
||||
- 当前 blocker:无;下一步按路线图落成并领取 T-301
|
||||
|
||||
## 当前目录要点
|
||||
|
||||
| 路径 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `docs/` | 已有 | harness coding 文档集(本次初始化完成) |
|
||||
| `docs/tasks/` | 已有 | Phase 0、Phase 1 与 T-201~T-203 已完成;T-204 待按路线图落成 |
|
||||
| `docs/tasks/` | 已有 | Phase 0、Phase 1 与 Phase 2 任务均已完成;T-301 待按路线图落成 |
|
||||
| `scripts/` | 已有 | harness 治理、core 边界、Go 版本检查与 Phase 0 双平台验证入口 |
|
||||
| `core/` | 已建 | Go 1.20 兼容;已有状态/事件、正式 Catalog、本地安装状态/存储与 Phase 1 安装安全原型 |
|
||||
| `app-modern/` | 已建 | Go 1.25.0 + Gio v0.10.1;Modern AppShell 已接入虚拟软件列表 |
|
||||
| `app-win7/` | 已建 | Go 1.20 + Gio v0.6.0;Legacy AppShell 已接入低成本虚拟软件列表 |
|
||||
| `core/` | 已建 | Go 1.20 兼容;已有正式 Catalog、本地状态/存储、列表模型、图标缓存与 Phase 1 安装安全原型 |
|
||||
| `app-modern/` | 已建 | Go 1.25.0 + Gio v0.10.1;Modern AppShell 已接入虚拟列表、详情和内存图标 |
|
||||
| `app-win7/` | 已建 | Go 1.20 + Gio v0.6.0;Legacy AppShell 已接入低成本列表、详情和内存图标 |
|
||||
| `schemas/` | 已建 | `manifest.schema.json`、`app.schema.json` 与 `installed-app.schema.json` |
|
||||
| `testdata/` | 已建 | 当前包含 Catalog 假数据与恶意样例;后续任务继续扩展 |
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
|
||||
任务状态以 `docs/tasks/` 各任务文件 frontmatter 的 `status` 为准。本节只写项目级摘要:
|
||||
|
||||
- 已完成:Phase 0 的 `T-001`~`T-004`;Phase 1 的 `T-101`、`T-102`、`T-103`;Phase 2 的 `T-201`、`T-202`、`T-203`。
|
||||
- 已完成:Phase 0 的 `T-001`~`T-004`;Phase 1 的 `T-101`、`T-102`、`T-103`;Phase 2 的 `T-201`~`T-204`。
|
||||
- 正在进行:无。
|
||||
- 下一个可领取任务:按路线图落成并领取 `T-204 软件详情与图标缓存`。
|
||||
- 下一个可领取任务:按路线图落成并领取 `T-301 下载队列`。
|
||||
|
||||
## 当前可运行内容
|
||||
|
||||
|
||||
+8
-1
@@ -24,7 +24,7 @@
|
||||
| 视图 | 职责 | MVP |
|
||||
| --- | --- | --- |
|
||||
| 软件列表(主视图) | T-203 已实现全部/已安装/可更新切换、名称/ID/tag 即时搜索、单分类筛选、稳定滚动与明确空状态;下载中/最近使用和多标签复选随对应用例后续接入 | P0 |
|
||||
| 软件详情(弹层或右栏) | 版本、简介、教程链接、授权状态;下载/更新/启动/取消操作 | P0 |
|
||||
| 软件详情(弹层或右栏) | T-204 已实现右栏、关闭、版本/分类/简介/tags/状态/不可用原因/教程/主页展示与内存图标;真实操作和授权事实随对应模块接入 | P0 |
|
||||
| 下载队列 | 所有任务的进度、速度、剩余时间;暂停/取消/重试 | P0 |
|
||||
| 设置 | 并发数、目录、代理、自动检查更新、beta 通道、日志级别、便携模式(V2) | P0(最小集) |
|
||||
| 授权 | 许可证导入、已授权软件列表、machine 信息、换绑/申诉入口 | P0 |
|
||||
@@ -61,6 +61,13 @@ T-203 已落地的列表交互约束:
|
||||
- 行 Clickable 保存在以 app ID 为键的 map;筛选、视图切换或 Catalog 快照更新不按可见序号迁移控件状态。
|
||||
- 无 Catalog 与过滤无结果是两个不同空状态;后者提供“显示全部软件”恢复操作。
|
||||
|
||||
T-204 已落地的详情/图标约束:
|
||||
|
||||
- 点击软件行用 selected app ID 打开右侧详情,关闭后回到同一列表/筛选/滚动上下文。
|
||||
- modern 与 Legacy 均显示版本、分类、简介、tags、状态、不可用原因、教程和主页文本;尚未接入的安装/启动/授权不伪装为已可执行操作。
|
||||
- 后台把已验证图标解码为 `image.Image` 后调用 `ApplyIcon`;该方法预建 `paint.ImageOp`,列表与详情 Layout 只绘制内存操作。
|
||||
- 图标未命中或离线缓存不可用时显示非 emoji 的字母占位,不阻塞列表或详情。
|
||||
|
||||
## 导航规则
|
||||
|
||||
- 列表 → 详情:点击软件项;详情保留返回/关闭。
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
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:<digest>` + 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` 与本任务无关,已保留且未纳入提交。
|
||||
Reference in New Issue
Block a user