fix(chat): 保存附件时不要被 SAF 补成双扩展名

实机复现(2026-10-05):把服务端附件 `809320…e.md` 保存到下载目录,落盘成了
`809320…e.md.txt` —— 因为 `CreateDocument` 传的是服务端**字节嗅探所得的基类型**
(`.md` 也会报 `text/plain`),而 SAF 的 Downloads provider 会按该 mime 给文件名**补扩展名**。

改为传 `*/*`:没有可补的扩展名,原扩展名因此保真。
**「用其它应用打开」那条路刻意不改** —— 那里要的正是「能读懂这段内容的类型」,照旧用嗅探所得的 mime。

实机复核:同一枚附件保存后落盘为 `809320…e.md`(95 字节,与源一致),不再出现 `.md.txt`。
This commit is contained in:
AskaEth committed 2026-10-04 19:27:53 +08:00
1 parent 60b0eacafd
commit ffa7ed2661
1 file changed
+6 -2
@@ -178,9 +178,13 @@ fun ChatScreen(
val previewFileName = previewTarget?.suggestedFileName() ?: FALLBACK_PREVIEW_FILE_NAME
// 「保存到下载目录」走系统 SAF:用户自己挑落点,本端不申请任何存储权限。
// 契约带上的 MIME 用文档自己的类型(服务端嗅探所得,不按扩展名猜)。
// ⚠️ 这里的 MIME **不能用 `previewType`**:那是**字节嗅探所得的基类型**(`.md` 也报
// `text/plain`),而 SAF 的 Downloads provider 会按该 mime 给文件名**补扩展名** ⇒
// 2026-10-05 实机复现:存的 `…e.md` 变成了 `…e.md.txt`。传 `*/*` 就没有可补的扩展名,
// 原扩展名因此保真。(「用其它应用打开」那条路刻意相反:那里要的正是「能读懂这段内容的
// 类型」,所以照旧用嗅探所得 mime。)
val createDocument = rememberLauncherForActivityResult(
remember(previewType) { ActivityResultContracts.CreateDocument(previewType) },
ActivityResultContracts.CreateDocument("*/*"),
) { destination ->
val ready = previewState as? DocumentPreviewState.Ready
if (destination == null || ready == null) return@rememberLauncherForActivityResult