← All repositories

listless

A simple list app for Apple platforms

git clone https://code.inqk.net/listless.git


ListlessMac/Views/SyncDiagnosticsView.swift (3627B)

1import SwiftUI
2
3struct SyncDiagnosticsView: View {
4    @ObservedObject var syncMonitor: CloudKitSyncMonitor
5
6    private static let timestampFormatter: DateFormatter = {
7        let formatter = DateFormatter()
8        formatter.dateStyle = .none
9        formatter.timeStyle = .medium
10        return formatter
11    }()
12
13    var body: some View {
14        List {
15            Section("Status") {
16                row("Transient Banner", syncMonitor.transientErrorMessage ?? "None")
17                row("Last Error Domain", syncMonitor.lastCloudKitErrorDomain ?? "None")
18                row("Last Error Code", syncMonitor.lastCloudKitErrorCode.map(String.init) ?? "None")
19                row("Last Error Description", syncMonitor.lastCloudKitErrorDescription ?? "None")
20                row(
21                    "Last Success",
22                    syncMonitor.lastSuccessfulSyncDate.map(Self.timestampFormatter.string(from:)) ?? "None"
23                )
24            }
25
26            Section("Recent Events") {
27                if syncMonitor.recentDiagnostics.isEmpty {
28                    Text("No events captured yet.")
29                        .foregroundStyle(.secondary)
30                } else {
31                    ForEach(syncMonitor.recentDiagnostics.reversed()) { entry in
32                        VStack(alignment: .leading, spacing: 4) {
33                            Text(
34                                "\(Self.timestampFormatter.string(from: entry.timestamp)) [\(entry.level.uppercased())]"
35                            )
36                            .font(.caption.monospaced())
37                            .foregroundStyle(.secondary)
38
39                            Text(entry.message)
40                                .font(.caption.monospaced())
41                                .textSelection(.enabled)
42                        }
43                        .padding(.vertical, 2)
44                    }
45                }
46            }
47        }
48        .textSelection(.enabled)
49        .toolbar {
50            ToolbarItem {
51                Button("Copy") {
52                    let pasteboard = NSPasteboard.general
53                    pasteboard.clearContents()
54                    pasteboard.setString(diagnosticDump, forType: .string)
55                }
56            }
57        }
58    }
59
60    @ViewBuilder
61    private func row(_ title: String, _ value: String) -> some View {
62        VStack(alignment: .leading, spacing: 4) {
63            Text(title)
64                .font(.caption)
65                .foregroundStyle(.secondary)
66            Text(value)
67                .font(.body.monospaced())
68                .textSelection(.enabled)
69        }
70        .padding(.vertical, 2)
71    }
72
73    private var diagnosticDump: String {
74        var lines: [String] = []
75        lines.append("Transient Banner: \(syncMonitor.transientErrorMessage ?? "None")")
76        lines.append("Last Error Domain: \(syncMonitor.lastCloudKitErrorDomain ?? "None")")
77        lines.append("Last Error Code: \(syncMonitor.lastCloudKitErrorCode.map(String.init) ?? "None")")
78        lines.append("Last Error Description: \(syncMonitor.lastCloudKitErrorDescription ?? "None")")
79        lines.append(
80            "Last Success: \(syncMonitor.lastSuccessfulSyncDate.map(Self.timestampFormatter.string(from:)) ?? "None")"
81        )
82        lines.append("")
83        lines.append("Recent Events:")
84        for entry in syncMonitor.recentDiagnostics {
85            lines.append(
86                "\(Self.timestampFormatter.string(from: entry.timestamp)) [\(entry.level.uppercased())] \(entry.message)"
87            )
88        }
89        return lines.joined(separator: "\n")
90    }
91}