e5fa1b871f1580cf46721262f79484db095061f0
后端 902b6ee / 契约 v0.63 给 historyMessage.documents[] 的元素加了可选字段 reason: 只在 status == "unreadable" 时下发(Go omitempty,extracted 时整个键缺席),内容与后端 注入模型清单里的那 10 条是同一份字符串,最长的一条 40+ 字。 改了什么 - DocumentRefDto 加 reason: String? = null。documents[] 在 WS 握手 history、 message_persisted、GET /messages 三处共用这一个 DTO,所以一处解析三条路全覆盖。 KDoc 写明三条口径:可选、只在 unreadable 时下发、是后端原话所以客户端原样显示, 且绝不做整句相等判断(需要分支只允许用稳定子串)。 - DocumentChipModel 加 reason,由 DocumentChips.of(ref) 取 ref.reason 去掉首尾空白后 非空才留,否则归一成 null——一句空话会顶掉弹层里的通用说明,比没有更坏。 芯片外观一个字没改:detail / statusLabel 保持现状(unreadable 仍显示「读不到」)。 理由:那句话太长,塞进一行芯片只会被 Ellipsis 切掉半句,比不显示更糟。 - DocumentPreviewGate.plan 增加 reason 参数:非空白时直接作为正文区那句说明原样返回 (NotText(reason)),压过本端按 mime / 扩展名的裁决;DocumentTarget.previewPlan 顺着 chips.reason 把它带进裁决。预览弹层本身一行代码都没改——它渲染的就是 plan.message 那句话,所以 reason 从 DTO 到用户看见的那句话整条链路上没有任何改写或截断。 - 配套单测 17 条。 为什么这么改 - 服务端那句原因已经断言「无法抽取正文」,它比本端按类型编的通用说明(只知道类型、 不知道到底为什么)准确;替它改写、归纳或截断就是丢掉服务端唯一一次说清原因的机会。 - 它也不该与正文并存:服务端说正文抽不出来,本端再把字节当 UTF-8 渲染,产出的正是 正文闸要消灭的「看着像文件坏了」。 - reason 缺席时(契约 v0.63 之前的历史消息)产出与改之前逐字相同:兜底那句话、判据、 文案全都不动。 测试(新增 17 条) - DocumentDtoTest +5:unreadable 带 reason 逐字解出;extracted 元素没有该键 -> null; v0.62 风格的缺键载荷 -> null(不解码失败、不替服务端编一句话);清单外的未知分类原样 保留;显式 null -> null。 - DocumentChipTest +5:reason 带进模型;句中标点与换行原样、只去首尾空白;空白串 -> null;绝不进芯片副行(detail 逐字不变);待发附件恒为 null。 - DocumentPreviewTest +7:reason 逐字成为正文区那句话(含未知分类,不丢不改不换兜底); 只 trim 一次再原样显示;缺席时与改前逐字相同(拿 refusalMessage 对比); 空白 reason 不改任何行为;text mime + reason 不再假装有正文。 - assembleDebug 通过;testDebugUnitTest 848 个测试 0 失败 0 错误 0 跳过。 已知代价(已写进 KDoc,供人拍板) 服务端判为读不到、但字节其实下得动的附件(例如超限的纯文本)会失去 App 内预览, 「用其它应用打开」与「保存到下载目录」两条出口照旧完整可用——与「未知 mime 判为非文本」 是同一笔不对称账。
…
…
Releases
5
Alpha_v0.1.0_4
Latest