From 1f58092dcb67cded75a850db364f3b46d86181f3 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Tue, 21 Apr 2026 21:53:16 -0500 Subject: feat(v2.2.0): add foreground monitoring, notifications, and smarter diffs - implement “Check All” sweep for tracked domains - add local notifications for changes and certificate expiration - introduce change severity filtering (low/medium/high) - enhance change summaries and diff readability - add certificate expiration tracking and alerts - improve watchlist indicators for changes - add sweep summary screen - optimize performance for larger watchlists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DomainDig/BatchSweepSummaryView.swift | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 DomainDig/BatchSweepSummaryView.swift (limited to 'DomainDig/BatchSweepSummaryView.swift') diff --git a/DomainDig/BatchSweepSummaryView.swift b/DomainDig/BatchSweepSummaryView.swift new file mode 100644 index 0000000..fda2bc5 --- /dev/null +++ b/DomainDig/BatchSweepSummaryView.swift @@ -0,0 +1,68 @@ +import SwiftUI + +struct BatchSweepSummaryView: View { + @Bindable var viewModel: DomainViewModel + let summary: BatchSweepSummary + + @State private var showUnchangedDomains = false + + private var visibleResults: [BatchLookupResult] { + if showUnchangedDomains { + return summary.results + } + + return summary.results.filter { + ($0.changeSeverity ?? .low) >= .medium || $0.certificateWarningLevel != .none || $0.status == .failed + } + } + + var body: some View { + NavigationStack { + List { + Section("Overview") { + statRow(label: "Checked", value: "\(summary.totalDomains)") + statRow(label: "Changed", value: "\(summary.changedDomains)") + statRow(label: "Warnings", value: "\(summary.warningDomains)") + statRow(label: "Unchanged", value: "\(summary.unchangedDomains)") + } + + Section { + Toggle("Show unchanged domains", isOn: $showUnchangedDomains) + } + + Section(visibleResults.isEmpty ? "Changed Domains" : "Results") { + if visibleResults.isEmpty { + Text("No domains with changes or warnings") + .font(.system(.caption, design: .monospaced)) + .foregroundStyle(.secondary) + } else { + ForEach(visibleResults) { result in + if let entry = viewModel.historyEntry(for: result) { + NavigationLink { + HistoryDetailView(viewModel: viewModel, entry: entry) + } label: { + BatchResultRowView(result: result) + } + } else { + BatchResultRowView(result: result) + } + } + } + } + } + .navigationTitle(summary.source == .watchlistRefresh ? "Sweep Summary" : "Batch Summary") + } + } + + private func statRow(label: String, value: String) -> some View { + HStack { + Text(label) + .font(.system(.caption, design: .monospaced)) + .foregroundStyle(.secondary) + Spacer() + Text(value) + .font(.system(.callout, design: .monospaced)) + .foregroundStyle(.primary) + } + } +} -- cgit v1.2.3