Diagnose-Bildschirm und Build-Datum
Zweimal in Folge stand „es läuft nicht" gegen „bei mir ist es behoben", ohne dass sich klären ließ, welcher Stand überhaupt auf dem Gerät liegt. Das soll nicht noch einmal passieren. Einstellungen → Diagnose zeigt jetzt: - welcher Server und über welche Verbindung, mit Warnung bei der gedrosselten Plex-Vermittlung - den letzten Abspielversuch: Titel, gewählter Weg, Quelladresse - jeden Schritt mit Zeitabstand zum Start. Der Abstand ist die eigentliche Auskunft: liegt zwischen „Quelle gewählt" und „spielt" eine Minute, hängt es an der Leitung; kommt „spielt" gar nicht, am Motor. - den Zeitpunkt, zu dem der laufende Build entstanden ist Das Build-Datum kommt aus dem Änderungsdatum der eigenen Binärdatei — kein Build-Skript, keine erzeugte Datei, und immer richtig. Der Bericht lässt sich kopieren und enthält keinen Token: die Quelladresse wird ohne Abfrageteil abgelegt, und dort steckt er. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import SwiftUI
|
||||
import FlixyDesign
|
||||
import PlexKit
|
||||
|
||||
/// Was beim letzten Abspielversuch passiert ist.
|
||||
///
|
||||
/// Gedacht als Antwort auf „es läuft nicht": hier steht, welcher Motor gewählt
|
||||
/// wurde, über welche Verbindung, und wie lange jeder Schritt gedauert hat.
|
||||
/// Ein Screenshot davon sagt mehr als jede Beschreibung.
|
||||
struct DiagnosticsView: View {
|
||||
@Environment(FlixySession.self) private var session
|
||||
@Environment(PlaybackDiagnostics.self) private var diagnostics
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section("diagnostics.connection") {
|
||||
if let server = session.server {
|
||||
LabeledContent("settings.serverName", value: server.name)
|
||||
LabeledContent("settings.address", value: server.connection.uri)
|
||||
.font(.flixyCaption)
|
||||
|
||||
if server.connection.relay {
|
||||
// Der häufigste Grund dafür, dass nichts anläuft. Ohne
|
||||
// Hinweis sucht man den Fehler in der App.
|
||||
Label("diagnostics.relayWarning", systemImage: "exclamationmark.triangle")
|
||||
.font(.flixyCaption)
|
||||
.foregroundStyle(Color.flixyDestructive)
|
||||
}
|
||||
} else {
|
||||
Text("diagnostics.noServer").foregroundStyle(Color.flixyTextMuted)
|
||||
}
|
||||
}
|
||||
|
||||
if let attempt = diagnostics.lastAttempt {
|
||||
Section("diagnostics.lastAttempt") {
|
||||
LabeledContent("diagnostics.title.label", value: attempt.title)
|
||||
LabeledContent("diagnostics.method", value: attempt.method)
|
||||
LabeledContent("diagnostics.connectionUsed", value: attempt.connection)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("diagnostics.source")
|
||||
.font(.flixyCaption)
|
||||
.foregroundStyle(Color.flixyTextMuted)
|
||||
Text(attempt.sourceDescription)
|
||||
.font(.system(.caption2, design: .monospaced))
|
||||
.foregroundStyle(Color.flixyTextSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
Section("diagnostics.steps") {
|
||||
ForEach(Array(attempt.steps.enumerated()), id: \.offset) { _, step in
|
||||
Text(step)
|
||||
.font(.system(.caption, design: .monospaced))
|
||||
.foregroundStyle(Color.flixyTextSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
Button {
|
||||
UIPasteboard.general.string = report(for: attempt)
|
||||
} label: {
|
||||
Label("diagnostics.copy", systemImage: "doc.on.doc")
|
||||
}
|
||||
} footer: {
|
||||
Text("diagnostics.copyHint")
|
||||
}
|
||||
} else {
|
||||
Section("diagnostics.lastAttempt") {
|
||||
Text("diagnostics.nothingYet").foregroundStyle(Color.flixyTextMuted)
|
||||
}
|
||||
}
|
||||
|
||||
Section("settings.app") {
|
||||
LabeledContent("settings.version", value: Branding.version)
|
||||
LabeledContent("settings.build", value: Branding.buildStamp)
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(Color.flixyCanvas)
|
||||
.navigationTitle(Text("diagnostics.title"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
/// Der Bericht als Text zum Weitergeben.
|
||||
///
|
||||
/// Enthält bewusst keinen Token: die Quelladresse ist schon ohne
|
||||
/// Abfrageteil abgelegt, und der Servername verrät nichts Vertrauliches.
|
||||
private func report(for attempt: PlaybackDiagnostics.Attempt) -> String {
|
||||
"""
|
||||
Flixy \(Branding.version) · Build \(Branding.buildStamp)
|
||||
Verbindung: \(attempt.connection)
|
||||
Titel: \(attempt.title)
|
||||
Weg: \(attempt.method)
|
||||
Quelle: \(attempt.sourceDescription)
|
||||
|
||||
\(attempt.steps.joined(separator: "\n"))
|
||||
"""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user