From fd8ca178a379da71f5bb19c461524888cad9447e Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Fri, 17 Jul 2026 11:18:25 -0500 Subject: v4.8.0: Add scheduled report generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ScheduledReportService (@MainActor, headless/storage-backed like DomainMonitoringService): builds the latest report for every tracked domain from persisted history, exports it via DomainReportExporter in the configured format (markdown/PDF/JSON), writes it to a local Documents subdirectory, logs the run, and fires a "Scheduled Report Ready" local notification. - ScheduledReportScheduler mirrors DomainMonitoringScheduler's BGTaskScheduler approach with its own task identifier (net.cleberg.DomainDig.report.schedule, added to Info.plist) and a daily/weekly cadence. - ScheduledReportsView (Settings → Scheduled Reports): enable toggle, cadence and format pickers, "Generate Now", and a log of past reports each shareable via the existing ExportPresenter share sheet. - Gated behind the existing .automatedMonitoring capability (Pro), consistent with monitoring being the other background-automation feature. - Settings/logs persist via UserDefaults (DomainExportFormat is now Codable), not DomainDataPortabilityService backup/restore — this is local automation configuration, not user-authored content, same reasoning as v4.7.0's watchlist saved views. --- DomainDig/LocalNotificationService.swift | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'DomainDig/LocalNotificationService.swift') diff --git a/DomainDig/LocalNotificationService.swift b/DomainDig/LocalNotificationService.swift index f417619..d3474e3 100644 --- a/DomainDig/LocalNotificationService.swift +++ b/DomainDig/LocalNotificationService.swift @@ -140,6 +140,15 @@ final class LocalNotificationService { ) } + func notifyScheduledReportReady(domainCount: Int) async { + await schedule( + identifier: "scheduled-report-\(UUID().uuidString)", + title: "Scheduled Report Ready", + body: "Report generated for \(domainCount) domain\(domainCount == 1 ? "" : "s").", + interruptionLevel: .active + ) + } + func clearAllNotifications() async { let center = UNUserNotificationCenter.current() center.removeAllPendingNotificationRequests() -- cgit v1.2.3