30180ab1e5e13a3b198c5bfd09aa47f10b264cf0
把 W6 做好的「文档进对话」数据层接上 UI 与发送路径,产品决定按 05 的定案执行: **不做长正文自动转文件**、**附件与正文各自独立存在**、上行**只给服务端存储名 `name`、≤5 条**、 带附件一律走 REST。 改了什么(按清单): - AppContainer:照 cachedUploadApi 的写法加 documentsApi + documentRepository,**与 chatApi 同 baseUrl / 同 token·401 策略**(上传拿到的 name 要交给同一个后端的 /chat,不同源必然 404)。 - domain/chat/DocumentAttachment.kt(新):DraftDocument(待发附件,只带本地引用,**不带字节**)、 admit()(去重 → 20 MiB 单份预检 → 5 份上限,被挡下的**都计数**、绝不静默裁)、 readBounded()(超限回 null、IO 异常原样抛——「太大」与「读不到」必须分得开)。 - domain/chat/DocumentChip.kt(新):附件芯片的展示换算(类型 / 体积 / 注入字数 / 状态), unreadable(读不到)与 truncated(注入被预算截断)**两句文案分开**,未知 status 原样显示。 - domain/chat/DocumentDelivery.kt:加 planForCount(text, 份数)——同一套判定矩阵,但只看份数, 因为 VM 手上还没有字节(最多 5×20 MiB 一次性读进内存不可接受)。plan() 委托给它,行为不变。 - ChatViewModel:ChatUiState 加 draftDocuments / attachmentNotice;send() → deliver() 走 DocumentDelivery 判定 → 逐份上传(保留扩展名、200+deduped 当成功)→ payload(names) 为 null 时**提示而不截断** → sendViaRest 带 documents;失败与正文、图片一起回滚(附件还给输入栏)。 - ChatScreen:SAF OpenMultipleDocuments 入口(MiuixIcons.File + contentDescription「添加文件附件」), MIME 列表贴近后端文本白名单的语义(含 octet-stream 以免「后端收得下、用户选不到」), 输入栏上方一排可移除芯片;发送按钮在只有附件时也可用(纯附件回合服务端支持)。 - MessageBubble:documents 渲染成芯片(名字中略保住扩展名 / 类型·体积·字数·状态), unreadable 整枚转灰并明写「读不到」;空列表不占位。PendingBubble 显示本地待发件。 - ShareIntake + ShareRules:EXTRA_STREAM 按 ContentResolver.getType 分流——image/ 前缀走既有 图片路,其余(含 null)走**文档路**(拷进 cache、带显示名与真实字节数)。此前一律当图片拷, 一份 .md 只能得到「图片处理失败」。**Manifest 一行未改**:后端明令拒绝 html/SVG/zip/脚本, 声明全通配会造出「点进去必然失败」的入口,text/plain 已能接住 .txt/.md/.log。 测试:485 → 536(+51,0 失败 0 错误)。
Releases
5
Alpha_v0.1.0_4
Latest