Files
legado-ios/App/Features/RSS/RSSSourceDebugView.swift
T

75 lines
4.0 KiB
Swift

import SwiftUI
@MainActor
private final class RSSSourceDebugModel: ObservableObject {
@Published var input = ""
@Published var running = false
@Published var report: RSSSourceDebugReport?
private let debugger = RSSSourceDebugger()
private var task: Task<Void, Never>?
func run(_ source: RssSource) {
task?.cancel(); running = true; report = nil
task = Task { [debugger, input] in
let result = await debugger.run(source: source, input: input)
guard !Task.isCancelled else { return }
report = result; running = false
}
}
deinit { task?.cancel() }
}
struct RSSSourceDebugView: View {
let source: RssSource
@StateObject private var model = RSSSourceDebugModel()
@State private var rawTitle = ""
@State private var rawText: String?
var body: some View {
List {
Section("调试输入") {
Text(source.sourceName).font(.headline)
TextField("关键词,或 分类::地址", text: $model.input)
.textInputAutocapitalization(.never).disableAutocorrection(true)
.onSubmit { model.run(source) }
Button { model.run(source) } label: { Label(model.running ? "正在调试…" : "运行完整链路", systemImage: "play.fill") }
.disabled(model.running)
}
if model.running { Section { HStack { ProgressView(); Text("正在请求并解析列表与正文") } } }
if let report = model.report {
Section(report.passed ? "调试通过" : "发现兼容问题") {
ForEach(report.steps) { step in
DisclosureGroup {
if step.diagnostics.isEmpty { Text("无规则诊断").foregroundStyle(.secondary) }
ForEach(step.diagnostics) { item in
VStack(alignment: .leading) { Text(item.message); Text(item.code).font(.caption.monospaced()).foregroundStyle(.secondary) }
}
} label: {
Label { VStack(alignment: .leading) { Text(step.stage.title); Text(step.summary).font(.caption).foregroundStyle(.secondary).lineLimit(2) } } icon: { Image(systemName: icon(step.status)).foregroundStyle(color(step.status)) }
}
}
}
if !report.articles.isEmpty {
Section("文章样本") { ForEach(report.articles.prefix(10)) { Text($0.title) } }
}
if let preview = report.contentPreview { Section("正文样本") { Text(preview).textSelection(.enabled) } }
}
}
.navigationTitle("RSS源调试")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Menu("查看源码", systemImage: "doc.plaintext") {
Button("列表源码") { rawTitle = "列表源码"; rawText = model.report?.listSource }.disabled(model.report?.listSource == nil)
Button("正文源码") { rawTitle = "正文源码"; rawText = model.report?.contentSource }.disabled(model.report?.contentSource == nil)
}
}
}
.sheet(isPresented: Binding(get: { rawText != nil }, set: { if !$0 { rawText = nil } })) {
ReadingNavigationStack { ScrollView { Text(rawText ?? "").font(.caption.monospaced()).textSelection(.enabled).frame(maxWidth: .infinity, alignment: .leading).padding() }.navigationTitle(rawTitle).toolbar { ToolbarItem(placement: .confirmationAction) { Button("完成") { rawText = nil } } } }
}
}
private func icon(_ status: SourceDebugStatus) -> String { switch status { case .passed: "checkmark.circle.fill"; case .warning: "exclamationmark.triangle.fill"; case .failed: "xmark.circle.fill"; case .skipped: "forward.end.circle" } }
private func color(_ status: SourceDebugStatus) -> Color { switch status { case .passed: .green; case .warning: .orange; case .failed: .red; case .skipped: .secondary } }
}