feat: add "阅读原文件" button to KnowledgeDetailPage

Blue gradient button at bottom of plain text content view.
Writes content to temp .md file and navigates to MaterialReaderView,
which triggers reading event collection.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-06-18 21:19:05 +08:00
parent def8c4c93a
commit 1c0a625192

View File

@ -1109,6 +1109,28 @@ struct KnowledgeDetailPage: View {
.padding(16).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14))
}
Text(content).font(.system(size: 14)).foregroundColor(Color.zxF0).lineSpacing(6)
// button
if let path = vm.localPath ?? (try? writeTempFile(content: content, itemId: item.id)), let mt = vm.detectedType ?? detectTypeFromContent(content, sourceType: item.sourceType) {
NavigationLink(value: Route.materialReader(
materialId: item.id,
filePath: path,
materialType: mt,
knowledgeBaseId: item.knowledgeBaseId,
title: item.title
)) {
HStack(spacing: 8) {
Image(systemName: "book")
Text("阅读原文件")
}
.font(.system(size: 15, weight: .bold))
.foregroundColor(.white)
.frame(maxWidth: .infinity).frame(height: 48)
.background(LinearGradient(colors: [Color.zxPurple, Color.zxAccent], startPoint: .leading, endPoint: .trailing))
.clipShape(RoundedRectangle(cornerRadius: 14))
}
.padding(.top, 8)
}
}.padding(.horizontal, 20).padding(.top, 8).padding(.bottom, 100)
}.scrollIndicators(.hidden)
}
@ -1452,3 +1474,30 @@ struct EditKnowledgePage: View {
}.navigationBarTitleDisplayMode(.inline).toolbarBackground(.hidden, for: .navigationBar).toolbar(.hidden, for: .tabBar)
}
}
// MARK: - Helpers
private func writeTempFile(content: String, itemId: String) throws -> String {
let dir = FileManager.default.temporaryDirectory
let url = dir.appendingPathComponent("kd_text_\(itemId).md")
try content.write(to: url, atomically: true, encoding: .utf8)
return url.path
}
private func detectTypeFromContent(_ content: String, sourceType: String?) -> MaterialType? {
if let st = sourceType {
switch st.lowercased() {
case "markdown", "md": return .markdown
case "txt", "text": return .text
case "pdf": return .pdf
case "epub": return .epub
case "docx", "doc": return .word
case "xlsx", "xls": return .excel
case "pptx", "ppt": return .powerPoint
default: break
}
}
// Detect from content
if content.hasPrefix("#") || content.contains("```") { return .markdown }
return .text
}