diff --git a/docs/plans/2026-09-29-选图拦截硬封锁-设计方案.md b/docs/plans/2026-09-29-选图拦截硬封锁-设计方案.md new file mode 100644 index 0000000..c94ed4c --- /dev/null +++ b/docs/plans/2026-09-29-选图拦截硬封锁-设计方案.md @@ -0,0 +1,67 @@ +# 选图点选拦截 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` 改为 `Map>`, + `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 双语一处 +文案。不涉及服务端、契约、其它页面。