Files
photo-live/docs/plans/2026-09-29-选图拦截硬封锁-设计方案.md
T
2026-09-29 14:14:06 +08:00

68 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 选图点选拦截 v2:硬封锁 + 仅本机判定(去服务器半场、去强制放行)
日期:2026-09-29 | 状态:用户拍板(方案 A:接受"服务端已删照片无法重传"限制)
## 背景与问题
v1(提交 7e5c550+0673f39)上线后两个实际问题:
1. **选图不灵敏**:`selectPredicate` 每次点选 await 判定,判定含服务器单项预检
(时间帽 2s)。弱网下每次点新照片勾选延迟 0.5~2s,用户以为没点上就反复点
(wechat_assets_picker `selectAsset` 源码:谓词返回前 `provider.selectAsset`
不执行——勾选必然等判定)。
2. **拦截形同虚设**:v1 设计了"二次点击强制选择"活口(escape hatch),配合上述
反复点击习惯,重复照片多点几次必然被强制选中——用户明确要求**重复照片不能
被选择**。
## 方案(v2)
### 1. 点选判定只查本机(治卡顿)
- `_judge` 仅保留本机 TaskStore 半场(同账号+相册+completed,filename+bytes),
删除服务器单项预检及其 2s 时间帽——点选延迟从「最多 2s 网络」降为「毫秒级
本地查询」。
- 服务器查重不消失:**入队时刻统一弹窗**(checkDuplicatesUnified,一次批量
≤500 张)照旧——跨设备/重装场景的重复仍在点上传时拦,服务端 409 兜底不变。
- iOS 注意:`title` 为空(需 FilterOption.needTitle)时本机半场无从匹配 →
放行;iOS 点选拦截实际不生效,跨设备判定依赖入队弹窗(与 v1 服务器半场
行为的差异登记于此)。
### 2. 硬封锁(去强制放行)
- 删除 `_forced` 二次点击放行集:本机命中的重复照片**每次点击都拒选**,
判定缓存命中即秒拦,提示文案改为「这张已上传到该相册,无法重复选择」
(en: This photo has already been uploaded to this album),不再引导再点。
- SnackBar clearSnackBars 防堆积行为保留。
### 3. 判定缓存升级为 in-flight Future 共享
- `_verdicts` 从 `Map<String, bool>` 改为 `Map<String, Future<bool>>`,
`putIfAbsent` 并发去重——同一照片双击/连点只发起一次判定(清偿 9-29 评审
登记 Minor 遗留)。`_judge` 内部全捕获不抛错,缓存 Future 无失败态。
## 已接受的限制(用户拍板 A)
- 照片在后台被删除后想重传同一文件:本机历史仍记「已传」→ 永远拦死。
解决办法:清 App 数据或换设备(罕见场景,先接受;后续可加设置开关/服务端
存活性免疫,未排期)。
## 构造签名变化
`PickerDuplicateGate` 删除 `client` 与 `serverCheckTimeout` 入参(点选路径无
网络依赖);`multiImagePickerProvider` 相应不再注入 ApiClient。
## 测试(enqueue_test 拦截器组重写)
- 本机命中 → 拒选;**连续多次点击均拒选**(无强制路径);新提示文案;
SnackBar 不堆积(第二个重复资产仅一条)。
- 不同 bytes / filename / 相册 / 账号 → 放行。
- in-flight 共享:并发两次 decideFact,fileSize 闭包仅被调用一次。
- title=null(iOS)→ 放行;fileSize 失败 → 放行;取消选择(selected=true)
恒放行且零查询(fileSize 计数为 0)。
- v1 服务器相关用例(②④⑥)随服务器半场移除而删除。
## 影响面
`enqueue.dart`(gate + provider 注入)+ `enqueue_test.dart` + l10n 双语一处
文案。不涉及服务端、契约、其它页面。