summaryrefslogtreecommitdiff
path: root/DomainDig/DomainDigApp.swift
Commit message (Collapse)AuthorAgeFilesLines
* feat(a11y): seeded audit fixtures; fix dense-row reflow they exposed (#21)Christian Cleberg13 days1-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The dense rows and portfolio sections never rendered in the audit — the test simulator has no tracked domains or batch results — so five phases of row treatment shipped unmeasured. Driving the add-domain UI was tried earlier and rejected (keyboard contamination, persistent state), so this adds DOMAIN_DIG_SEED_FIXTURES: DEBUG-only launch argument, same pattern as DOMAIN_DIG_FORCE_PRO_PLUS, seeding four tracked domains and four batch results chosen to exercise every badge path, including a failed lookup and a stress-length domain name. Fixtures are strictly in-memory. persistTrackedDomains, refreshWidgetData (App Group file), refreshPersistedData, and refreshMonitoringState are all guarded while fixtures are active — the last one mattered: it runs right after seeding in the app task and was reloading the empty disk over the fixtures, which initially made the seeded watchlist audit pass by silently auditing the empty state. Four new audit tests cover the seeded Dashboard, Tracked Domains, and batch results at default and AccessibilityXXXL. What they found was real. At XXXL the watchlist row rendered the domain as "hea lt…" while the Registered badge wrapped one character per line into a screen-height capsule. Fixes, verified by before/after screenshots and the XXXL audits dropping to 7-8 findings per screen: - AppStatusBadgeView gets .fixedSize() — a capsule badge must never letter-wrap; taking natural width instead forces the row layout to its stacked alternative. - WatchlistRowView, BatchResultRowView, and PortfolioExpiryRow headers use ViewThatFits: domain-beside-badge while it genuinely fits, badge below the domain at accessibility sizes. Domain titles get fixedSize(horizontal: false, vertical: true) so they wrap rather than report a single-line ideal width to ViewThatFits and truncate. - The watchlist monitoring metadata strip (three texts abreast) stacks vertically when it no longer fits instead of wrapping mid-word. Known and deliberate: the seeded default-size audits still report a contrast/dynamicType wave attributed to "unknown element". Bisecting the row and badge accessibility modifiers showed most of it is an audit artifact on children-ignored content (the same rows measure 6-7:1 and render correctly); the artifact classes get characterised suppressions when enforcement lands, not blanket ones.
* feat(a11y): unlock light mode and add appearance preference (#21 phase 2)Christian Cleberg2026-07-201-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Removes the 16 scattered .preferredColorScheme(.dark) calls and the one .toolbarColorScheme, and applies appearance in exactly one place — the WindowGroup in DomainDigApp. Re-applying per view is what let the lock spread across eight files unnoticed until light mode was unreachable. Adds AppAppearance (System / Light / Dark) in @AppStorage, exposed under Settings > Display next to Density. Honouring the system setting and offering an override is one key, and it keeps the deliberate dark aesthetic reachable for anyone who wants it. Also replaces .secondary with AppTextSecondary across 191 sites. iOS's own secondaryLabel is 3.29:1 on a light card — below AA — which never showed while the app was locked to dark, where the same colour reads 6.32:1. Unlocking light mode is precisely what exposed it, so it belongs here rather than in a later phase: without it, light mode would ship with body text under 4.5:1 app-wide. Dark mode reports 18 findings, unchanged from phase 1 — no regression from unlocking. Light mode reports 21. The three extra are iOS-rendered Section headers (TIER, PREFERENCES, SERVICES) using the system's grey; overriding system header styling across every section to gain ~0.3:1 on decorative labels is a poor trade and is left alone. Two long-standing Settings contrast findings are now explained. They are the last rows of a section sitting under the translucent tab bar, so the audit measures text against a blended background — confirmed by screenshot, present in dark mode since phase 0, and standard iOS scroll-under behaviour rather than a defect.
* v4.8.0: Add scheduled report generationChristian Cleberg2026-07-201-0/+3
| | | | | | | | | | | | | | | | | | | | | - 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.
* Implement v4.6.0: sweep Live Activity, share extension, iPad split view, ↵Christian Cleberg2026-07-171-0/+9
| | | | | | | | | | | | | | | | actionable notifications - Sweep Live Activity: SweepActivityAttributes (Shared/), lock-screen + Dynamic Island UI in the widget extension, driven by SweepActivityController wired into the batch pipeline (begin/update/end); NSSupportsLiveActivities in Info.plist. - Share extension (DomainDigShareExtension): accepts a web URL from the share sheet, extracts the host, and hands it to the app via the App Group inbox (DomainDigShareInbox); the app consumes it on activation and inspects it. - iPad layout: RootTabView uses NavigationSplitView in the regular size class and the tab bar in compact. - Actionable notifications: per-domain threadIdentifier grouping, a Re-inspect action, and tap routing into the domain detail via the intent router. - Bump version to 4.6.0 (build 38) across app, widget, and share targets.
* Complete v4.5.0: Run Sweep intent, detail deep link, and portfolio widgetChristian Cleberg2026-07-171-0/+2
| | | | | | | | | | | | | | | | | Finishes the v4.5.0 "Home Screen & Shortcuts reach" scope that the tag shipped partially: - Add RunSweepIntent (opens the app and runs refreshAllTrackedDomains via the in-process router) and expose it in DomainDigShortcuts. - Extend the domaindig:// scheme with `sweep` and `domain` (detail) actions; route .detail to present TrackedDomainDetailView and .sweep to refresh the watchlist. Move DomainDigDeepLink into Shared/ so the widget can build links. - Add a WidgetKit extension (DomainDigWidgetExtension) with small/medium/large Portfolio widgets showing health counts, per-domain status, and certificate countdowns; tapping a domain deep-links into its detail. - Share portfolio state via an App Group (group.net.cleberg.DomainDig): the app writes a DomainDigWidgetData snapshot on launch/foreground and on watchlist changes and reloads timelines; the widget reads the same store.
* DomainDig v4.2.0: Add a local-only HTTP API layer for DomainDigChristian Cleberg2026-04-261-0/+4
| | | | | | | | | | | | | | | | | | | | Expose DomainDig as a programmable local domain intelligence engine over localhost with explicit user opt-in and token-based authentication. Highlights: - add a localhost-only API server with safe start/stop lifecycle - require a local token for every request and store it in Keychain - add read endpoints for portfolio, domains, history, events, and monitoring - add inspection endpoints that reuse the existing inspection engine - add monitoring enable/disable control endpoints - add structured JSON response envelopes with API versioning - add lightweight capped request logging with clear/reset support - add a Settings UI for Local API enablement, token management, status, and logs - start the server on launch only when enabled - include Local API secrets in local data reset cleanup This is the first programmability release for DomainDig and establishes the foundation for Shortcuts, scripts, and other local automation workflows.
* DomainDig v4.0.0 — IntegrationsChristian Cleberg2026-04-251-0/+4
| | | | | | | | | | | | * Outbound webhook delivery * Native Slack webhook integration * SMTP-based email alerts * Per-integration event filtering * Reliable local delivery queue * Delivery logs and retry visibility * Integration management UI * Normalized event severity model * Canonical structured event payloads
* feat(v3.6.0): add iCloud sharing for workflows and tracked domainsChristian Cleberg2026-04-231-0/+11
| | | | | | | | | | | | | | | | - implement CloudKit sharing (CKShare) for TrackedDomain and DomainWorkflow - support read-only and editable permissions - add Share actions and shared state indicators in UI - handle shared record ownership and participant roles - implement deterministic conflict resolution to prevent duplication - ensure compatibility with existing iCloud sync layer - maintain local-first behavior with graceful offline handling - remove debug logging for domain availability/rdap messages notes: - no custom backend or accounts introduced - sharing is Apple ecosystem only (iCloud-based) - large history data remains local-only
* feat(v3.4.0): add backup, restore, and data portabilityChristian Cleberg2026-04-231-0/+13
| | | | | | | | | | | • introduce versioned DomainDig backup format • add full backup export/import with merge and replace modes • implement data validation and conflict handling • add partial exports for tracked domains, workflows, and history • add Data Portability settings section • support Files/iCloud Drive import and export • harden migrations for evolving local models • extend CLI with backup export and validation
* feat(v3​.1​.0): add ​Store​Kit integration and ​Pro tierChristian Cleberg2026-04-221-0/+5
| | | | | | | | | • implement Purchase​Service using StoreKit 2 • activate feature tiers based on entitlement • add minimal paywall and restore flow • enforce free-tier limits with upgrade paths • integrate Pro status into settings • ensure clean and non-intrusive monetization flow
* feat(v3.0.0): unify platform architecture and introduce feature tiersChristian Cleberg2026-04-221-1/+2
| | | | | | | | | | | * consolidate DomainReport as canonical data model * add feature tier system (free/pro/data+ scaffolding) * apply clean feature gating across workflows and tracking * refactor app structure for maintainability * standardize navigation and settings * add data lifecycle controls * ensure consistency across UI, export, and CLI * stabilize internal inspection API
* feat(v2​.6​.0): refine ​UI, density, and usabilityChristian Cleberg2026-04-221-0/+3
| | | | | | | | | • add compact/comfortable density modes • implement collapsible sections and sticky summary header • improve visual status indicators and copy actions • refine watchlist and history UX with swipe actions • reorganize settings and improve empty states • add subtle animations and accessibility improvements
* feat(v2.2.0): add foreground monitoring, notifications, and smarter diffsChristian Cleberg2026-04-211-0/+4
| | | | | | | | | | | - 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
* initial commitChristian Cleberg2026-03-111-0/+17