summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Docs/ACCESSIBILITY.md26
-rw-r--r--DomainDig/AuditModeView.swift4
-rw-r--r--DomainDig/BatchResultsView.swift16
-rw-r--r--DomainDig/BatchSweepSummaryView.swift4
-rw-r--r--DomainDig/ContentView.swift149
-rw-r--r--DomainDig/DashboardView.swift15
-rw-r--r--DomainDig/DomainCompareView.swift2
-rw-r--r--DomainDig/DomainDig/AuditViews.swift36
-rw-r--r--DomainDig/DomainDigApp.swift3
-rw-r--r--DomainDig/DomainDigUI.swift55
-rw-r--r--DomainDig/HistoryView.swift12
-rw-r--r--DomainDig/IntegrationsView.swift22
-rw-r--r--DomainDig/MonitoringView.swift14
-rw-r--r--DomainDig/PaywallView.swift8
-rw-r--r--DomainDig/SavedDomainsView.swift3
-rw-r--r--DomainDig/ScheduledReportsView.swift6
-rw-r--r--DomainDig/TimelineView.swift8
-rw-r--r--DomainDig/WatchlistView.swift26
-rw-r--r--DomainDig/WorkflowsView.swift37
-rw-r--r--DomainDigWidget/DomainDigPortfolioWidget.swift18
-rw-r--r--DomainDigWidget/SweepLiveActivity.swift10
-rw-r--r--Shared/Colors.xcassets/AppTextSecondary.colorset/Contents.json78
22 files changed, 344 insertions, 208 deletions
diff --git a/Docs/ACCESSIBILITY.md b/Docs/ACCESSIBILITY.md
index 7e28d89..7153381 100644
--- a/Docs/ACCESSIBILITY.md
+++ b/Docs/ACCESSIBILITY.md
@@ -29,6 +29,12 @@ worst of those three is shown:
| `StatusWarning` | `#7A5600` | `#FFD60A` | 4.74 | 9.61 |
| `StatusCritical` | `#B3261E` | `#FF6961` | 4.51 | 5.54 |
| `StatusNeutral` | `#5A5A5F` | `#A1A1A6` | 4.92 | 5.88 |
+| `AppTextSecondary` | `#5A5A5F` | `#A1A1A6` | 6.15 | 7.50 |
+
+`AppTextSecondary` replaces `.secondary` for body text. iOS's own `secondaryLabel`
+is only **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
+exposed it across 191 sites.
High Contrast variants push further in the same direction. Surfaces
(`AppBackground`, `AppSurface`, `AppSurfaceElevated`, `AppSeparator`) carry no
@@ -58,6 +64,26 @@ So there are two colours:
`AppOnAccent` is the label colour for a solid accent fill and flips by scheme —
white on the light accent, black on the dark one.
+## Appearance
+
+`AppAppearance` (System / Light / Dark) is stored in `@AppStorage` and applied in
+**exactly one place** — the `WindowGroup` in `DomainDigApp`. Keep it that way. The
+app previously carried 16 separate `.preferredColorScheme(.dark)` calls scattered
+through view bodies, which is how light mode became unreachable without anyone
+noticing; re-applying per view is what let the lock spread.
+
+Users override it under Settings → Display.
+
+### Known light-mode findings
+
+| Finding | Cause | Action |
+| --- | --- | --- |
+| 2× `contrast failed` on Settings | The last rows of a section sit under the translucent tab bar, so the audit measures text against a blended background. Present in dark mode too, since phase 0. | None — standard iOS scroll-under behaviour |
+| 3× `contrast nearly passed` on Settings | iOS-rendered `Section` headers (`TIER`, `PREFERENCES`, `SERVICES`) use the system's grey. | Not fixed. Overriding system header styling across every section to gain ~0.3:1 on decorative labels trades platform convention for very little |
+
+Dark mode reports 18 findings and light mode 21; the three extra are the section
+headers above. Everything the app actually controls passes in both schemes.
+
## Findings are reported, not enforced
The audit surfaces violations that exist today, so failing on all of them would
diff --git a/DomainDig/AuditModeView.swift b/DomainDig/AuditModeView.swift
index b3e363e..08b9e9c 100644
--- a/DomainDig/AuditModeView.swift
+++ b/DomainDig/AuditModeView.swift
@@ -25,7 +25,7 @@ struct AuditModeView: View {
Section("Audit Timeline") {
if auditStore.sessions.isEmpty {
Text("No audits yet.")
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(auditStore.sessions) { session in
Button {
@@ -35,7 +35,7 @@ struct AuditModeView: View {
Text(session.domain).font(.headline)
Text("\(session.createdAt.formatted(date: .abbreviated, time: .shortened)) • \(session.status.title)")
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
diff --git a/DomainDig/BatchResultsView.swift b/DomainDig/BatchResultsView.swift
index afef5cb..bf211dc 100644
--- a/DomainDig/BatchResultsView.swift
+++ b/DomainDig/BatchResultsView.swift
@@ -17,12 +17,12 @@ struct BatchResultsView: View {
.frame(width: 120)
Text(viewModel.batchProgressLabel)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
} else if !viewModel.batchResults.isEmpty {
Text("\(viewModel.batchResults.count) domains")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
@@ -67,7 +67,7 @@ struct BatchResultRowView: View {
Spacer(minLength: 8)
Text(result.resultSource.label.lowercased())
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
AppStatusBadgeView(model: quickStatusBadge)
}
@@ -80,7 +80,7 @@ struct BatchResultRowView: View {
}
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
HStack(spacing: 10) {
Text(result.primaryIP ?? "No IP")
@@ -93,12 +93,12 @@ struct BatchResultRowView: View {
.lineLimit(1)
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let summaryMessage = result.summaryMessage {
Text(summaryMessage)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let changeClassification = result.changeClassification {
@@ -137,7 +137,7 @@ struct BatchResultRowView: View {
return .init(
title: availabilityText,
systemImage: "exclamationmark.circle",
- foregroundColor: .secondary,
+ foregroundColor: Color(.appTextSecondary),
backgroundColor: Color(.appSurfaceElevated)
)
}
@@ -145,7 +145,7 @@ struct BatchResultRowView: View {
private var quickStatusBadge: AppStatusBadgeModel {
switch result.status {
case .pending:
- return .init(title: "Pending", systemImage: "clock", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: "Pending", systemImage: "clock", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
case .running:
return .init(title: "Running", systemImage: "arrow.clockwise", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16))
case .completed:
diff --git a/DomainDig/BatchSweepSummaryView.swift b/DomainDig/BatchSweepSummaryView.swift
index 43ffa74..ae69d06 100644
--- a/DomainDig/BatchSweepSummaryView.swift
+++ b/DomainDig/BatchSweepSummaryView.swift
@@ -32,7 +32,7 @@ struct BatchSweepSummaryView: View {
if visibleResults.isEmpty {
Text("No domains with changes or warnings")
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(visibleResults) { result in
if let entry = viewModel.historyEntry(for: result) {
@@ -56,7 +56,7 @@ struct BatchSweepSummaryView: View {
HStack {
Text(label)
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
Text(value)
.font(.system(.callout, design: .monospaced))
diff --git a/DomainDig/ContentView.swift b/DomainDig/ContentView.swift
index 7eec8a0..efaaf05 100644
--- a/DomainDig/ContentView.swift
+++ b/DomainDig/ContentView.swift
@@ -173,8 +173,6 @@ struct ContentView: View {
)
)
.navigationTitle("DomainDig")
- .toolbarColorScheme(.dark, for: .navigationBar)
- .preferredColorScheme(.dark)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
if viewModel.hasRun {
@@ -182,7 +180,7 @@ struct ContentView: View {
viewModel.reset()
} label: {
Image(systemName: "xmark.circle")
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -327,12 +325,12 @@ struct ContentView: View {
VStack(alignment: .leading, spacing: appDensity.metrics.cardSpacing) {
Text("Paste domains separated by new lines or commas.")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let batchAllowanceSummary = FeatureAccessService.batchAllowanceSummary() {
Text(batchAllowanceSummary)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
TextField(
@@ -544,7 +542,7 @@ struct ContentView: View {
} label: {
Image(systemName: "bolt.circle")
.font(appDensity.font(.body, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Button {
viewModel.toggleSavedDomain()
@@ -583,7 +581,7 @@ struct ContentView: View {
} label: {
Image(systemName: "square.and.arrow.up")
.font(appDensity.font(.body, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -652,13 +650,13 @@ struct ContentView: View {
HStack {
Text("RECENT")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
Button("Clear") {
viewModel.clearRecentSearches()
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
ForEach(viewModel.recentSearches, id: \.self) { domain in
@@ -694,7 +692,7 @@ struct ContentView: View {
.font(appDensity.font(.headline, design: .default, weight: .semibold))
Text(message)
.font(appDensity.font(.callout, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(appDensity.metrics.cardPadding)
@@ -784,7 +782,7 @@ struct SummaryView: View {
VStack(alignment: .leading, spacing: appDensity.metrics.rowSpacing) {
Text(field.label)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(field.value)
.font(appDensity.font(.caption))
.foregroundStyle(ResultColors.color(for: field.tone))
@@ -826,13 +824,13 @@ struct RiskSummaryCardView: View {
Spacer()
Text("Deterministic")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if topFactors.isEmpty {
Text("No major risk factors identified")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(Array(topFactors.enumerated()), id: \.offset) { _, factor in
HStack(alignment: .top, spacing: 8) {
@@ -884,7 +882,7 @@ struct InsightsSummaryCardView: View {
if insights.isEmpty {
Text("No deterministic insights triggered")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(Array(insights.enumerated()), id: \.offset) { _, insight in
HStack(alignment: .top, spacing: 8) {
@@ -940,7 +938,7 @@ struct StickyLookupSummaryView: View {
HStack(spacing: 8) {
Label(primaryIP, systemImage: "network")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer(minLength: 6)
AppCopyButton(value: primaryIP, label: "Copy IP")
}
@@ -966,7 +964,7 @@ struct LookupProgressOverviewView: View {
.foregroundStyle(.primary)
Text(steps.isEmpty ? "Preparing requests" : steps.joined(separator: " • "))
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Spacer()
}
@@ -1049,13 +1047,13 @@ struct DomainChangeSummaryView: View {
.clipShape(Capsule())
Text(summary.generatedAt, style: .time)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
VStack(alignment: .leading, spacing: 4) {
Text("Inference")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(summary.message)
.font(appDensity.font(.caption))
.foregroundStyle(.primary)
@@ -1069,7 +1067,7 @@ struct DomainChangeSummaryView: View {
VStack(alignment: .leading, spacing: 4) {
Text("Observed")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
ForEach(Array(summary.observedFacts.enumerated()), id: \.offset) { _, fact in
Text(fact)
.font(appDensity.font(.caption))
@@ -1171,7 +1169,7 @@ struct DomainDiffView: View {
HStack {
Text(item.label)
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
Text("\(item.changeType.marker) \(item.severity.title) • \(changeLabel(for: item.changeType))")
.font(.system(.caption2, design: .monospaced))
@@ -1186,10 +1184,10 @@ struct DomainDiffView: View {
VStack(alignment: .leading, spacing: 2) {
Text("Old")
.font(.system(.caption2, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(oldValue)
.font(.system(.caption2, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.textSelection(.enabled)
}
}
@@ -1198,7 +1196,7 @@ struct DomainDiffView: View {
VStack(alignment: .leading, spacing: 2) {
Text("New")
.font(.system(.caption2, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(newValue)
.font(.system(.caption, design: .monospaced))
.foregroundStyle(item.hasChanges ? .primary : .secondary)
@@ -1306,7 +1304,7 @@ struct TrackedDomainDetailHeaderView: View {
Text("Last refresh \(trackedDomain.updatedAt.formatted(date: .abbreviated, time: .shortened))")
}
.font(.system(.caption2, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -1394,7 +1392,7 @@ struct DomainSectionView: View {
VStack(alignment: .leading, spacing: 8) {
Text("Part of workflow")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
ForEach(workflows) { workflow in
HStack {
@@ -1429,7 +1427,7 @@ struct DomainSectionView: View {
if showSuggestions {
Text("Suggestions")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.padding(.top, 4)
if suggestionsLoading {
ProgressView("Checking alternatives…")
@@ -1527,7 +1525,7 @@ struct OwnershipSectionView: View {
HStack {
Text("History")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
if let onLoadHistory, history.isEmpty, !historyLoading, !showsHistoryPlaceholder {
Button("Load") {
@@ -1545,12 +1543,12 @@ struct OwnershipSectionView: View {
VStack(alignment: .leading, spacing: 3) {
Text(event.date.formatted(date: .abbreviated, time: .omitted))
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(event.summary)
.font(appDensity.font(.caption))
Text(event.source)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
} else if let historyError {
@@ -1604,7 +1602,7 @@ struct IntelligenceSectionView: View {
.font(appDensity.font(.caption, weight: .semibold))
Text(signal.detail)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -1645,7 +1643,7 @@ struct IntelligenceSectionView: View {
}
Text("First \(item.firstSeen.formatted(date: .abbreviated, time: .omitted)) • Last \(item.lastSeen.formatted(date: .abbreviated, time: .omitted)) • Seen \(item.recurrenceCount)x")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -1678,7 +1676,7 @@ struct IntelligenceSectionView: View {
VStack(alignment: .leading, spacing: 3) {
Text(date.formatted(date: .abbreviated, time: .omitted))
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(title)
.font(appDensity.font(.caption))
}
@@ -1755,7 +1753,7 @@ struct SubdomainsSectionView: View {
if !groups.isEmpty {
Text("Groups")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
ForEach(groups) { group in
HStack {
Text("\(group.label).*")
@@ -1764,7 +1762,7 @@ struct SubdomainsSectionView: View {
Spacer()
Text("\(group.subdomains.count)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -1898,7 +1896,7 @@ struct DNSSectionView: View {
if let wildcardTitle = section.wildcardTitle {
Text(wildcardTitle)
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.padding(.top, 4)
ForEach(section.wildcardRows) { row in
LabeledValueRow(row: row)
@@ -1940,18 +1938,18 @@ struct DNSSectionView: View {
VStack(alignment: .leading, spacing: 3) {
Text(event.date.formatted(date: .abbreviated, time: .omitted))
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(event.summary)
.font(appDensity.font(.caption))
if !event.aRecords.isEmpty {
Text("A: \(event.aRecords.joined(separator: ", "))")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if !event.nameservers.isEmpty {
Text("NS: \(event.nameservers.joined(separator: ", "))")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -2017,7 +2015,7 @@ struct WebSectionView: View {
if let sslInfo, !sslInfo.subjectAltNames.isEmpty {
Text("SANs")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
ForEach(sslInfo.subjectAltNames, id: \.self) { san in
HStack(alignment: .top, spacing: 8) {
Text(san)
@@ -2091,7 +2089,7 @@ struct WebSectionView: View {
HStack(alignment: .top, spacing: 6) {
Text(redirect.stepLabel)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.frame(width: 16, alignment: .trailing)
Text(redirect.statusCode)
.font(appDensity.font(.caption))
@@ -2104,7 +2102,7 @@ struct WebSectionView: View {
if redirect.isFinal {
Text("(final)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -2149,7 +2147,7 @@ struct EmailSectionView: View {
if !assessment.reasons.isEmpty {
Text(assessment.reasons.joined(separator: " | "))
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
if loading {
@@ -2176,7 +2174,7 @@ struct EmailSectionView: View {
if let auxiliaryDetail = row.auxiliaryDetail {
Text(auxiliaryDetail)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -2192,9 +2190,9 @@ struct EmailSectionView: View {
case .warning:
return .init(title: row.status, systemImage: "shield.lefthalf.filled", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
case .failure:
- return .init(title: row.status, systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: row.status, systemImage: "minus.circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
case .primary, .secondary:
- return .init(title: row.status, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: row.status, systemImage: "circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
}
}
@@ -2244,7 +2242,7 @@ struct NetworkSectionView: View {
Spacer()
Text(row.latencyLabel)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
AppStatusBadgeView(model: reachabilityBadge(row))
}
}
@@ -2304,7 +2302,7 @@ struct NetworkSectionView: View {
} else {
Text("Standard Ports")
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
PortRowsView(rows: standardPortRows)
}
@@ -2353,7 +2351,7 @@ struct NetworkSectionView: View {
case .failure:
return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
case .primary, .secondary:
- return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
}
}
@@ -2379,14 +2377,14 @@ struct PortRowsView: View {
if let durationLabel = row.durationLabel {
Text(durationLabel)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
AppStatusBadgeView(model: portBadge(row))
}
if let banner = row.banner {
Text(banner)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.padding(.leading, 8)
}
}
@@ -2404,7 +2402,7 @@ struct PortRowsView: View {
case .failure:
return .init(title: row.statusLabel, systemImage: "xmark.circle.fill", foregroundColor: Color(.statusCritical), backgroundColor: Color(.statusCritical).opacity(0.16))
case .primary, .secondary:
- return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: row.statusLabel, systemImage: "circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
}
}
@@ -2512,15 +2510,15 @@ struct SectionTrustMetadataView: View {
if let confidence {
Text("Confidence \(confidence.title)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let provenance {
Text(provenance.provider ?? provenance.source)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(provenance.resultSource.label)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
DisclosureGroup("Details") {
@@ -2559,7 +2557,7 @@ struct LabeledValueRow: View {
VStack(alignment: .leading, spacing: appDensity.metrics.rowSpacing - 1) {
Text(row.label)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(row.value)
.font(appDensity.font(.caption))
.foregroundStyle(ResultColors.color(for: row.tone))
@@ -2656,7 +2654,7 @@ struct SettingsView: View {
if let statusMessage = purchaseService.statusMessage {
Text(statusMessage)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let errorMessage = purchaseService.errorMessage {
@@ -2732,10 +2730,17 @@ struct SettingsView: View {
private struct DisplaySettingsView: View {
@AppStorage(AppDensity.userDefaultsKey) private var storedDensity = AppDensity.compact.rawValue
+ @AppStorage(AppAppearance.userDefaultsKey) private var storedAppearance = AppAppearance.system.rawValue
var body: some View {
Form {
Section("Display") {
+ Picker("Appearance", selection: $storedAppearance) {
+ ForEach(AppAppearance.allCases) { appearance in
+ Text(appearance.title).tag(appearance.rawValue)
+ }
+ }
+
Picker("Density", selection: $storedDensity) {
ForEach(AppDensity.allCases) { density in
Text(density.title).tag(density.rawValue)
@@ -2778,7 +2783,7 @@ private struct HistoryNetworkSettingsView: View {
Text("History remains local-first. Auto-prune only trims older local snapshots on this device and defaults to unlimited.")
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Section("Network") {
@@ -2870,11 +2875,11 @@ private struct CloudSyncSettingsView: View {
Text("iCloud Sync stores DomainDig data in your private iCloud account. DomainDig does not operate a sync server. Disabling sync keeps local data on this device.")
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(cloudSyncService.detailMessage)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let lastErrorMessage = cloudSyncService.lastErrorMessage {
Text(lastErrorMessage)
@@ -2932,7 +2937,7 @@ private struct LocalAPISettingsView: View {
if let statusMessage = localAPIService.statusMessage {
Text(statusMessage)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
@@ -2947,7 +2952,7 @@ private struct LocalAPISettingsView: View {
Text("Every request requires either `Authorization: Bearer <token>` or `X-API-Token`. DomainDig stores the token in Keychain and only binds the server to localhost.")
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Section("Request Logging") {
@@ -2962,7 +2967,7 @@ private struct LocalAPISettingsView: View {
if localAPIService.requestLogs.isEmpty {
Text("No local API requests logged yet.")
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(localAPIService.requestLogs.prefix(25)) { log in
VStack(alignment: .leading, spacing: 4) {
@@ -2977,11 +2982,11 @@ private struct LocalAPISettingsView: View {
Text(log.timestamp.formatted(date: .abbreviated, time: .standard))
.font(appDensity.font(.caption2, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text("\(Int(log.duration * 1000)) ms")
.font(appDensity.font(.caption2, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -3184,13 +3189,13 @@ private struct MonitoringSettingsView: View {
if let monitoringStatusMessage = viewModel.monitoringStatusMessage {
Text(monitoringStatusMessage)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if !FeatureAccessService.hasAccess(to: .automatedMonitoring) {
Text("Background monitoring and alerts are available in Pro.")
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -3260,7 +3265,7 @@ private struct DataPortabilitySettingsView: View {
Text(importMode.explanation)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Button("Export Full Backup") {
exportFullBackup()
@@ -3317,12 +3322,12 @@ private struct DataPortabilitySettingsView: View {
Text("Data stays on this device unless you export it. Backup files can include domain history, monitoring settings, and notes. Imported files are processed on-device.")
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let portabilityStatusMessage = viewModel.portabilityStatusMessage {
Text(portabilityStatusMessage)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
@@ -3331,7 +3336,7 @@ private struct DataPortabilitySettingsView: View {
Section("Import Debug") {
Text(importDebugStatus)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.textSelection(.enabled)
}
}
@@ -3636,7 +3641,7 @@ private struct DataManagementSettingsView: View {
if let deleteAllSuccessMessage {
Text(deleteAllSuccessMessage)
.font(.footnote.weight(.medium))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.padding(.horizontal, 14)
.padding(.vertical, 10)
.background(.thinMaterial, in: Capsule())
@@ -3722,7 +3727,7 @@ private struct DataImportPreviewSheet: View {
Section("Warnings") {
ForEach(preview.warnings, id: \.self) { warning in
Text(warning)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
diff --git a/DomainDig/DashboardView.swift b/DomainDig/DashboardView.swift
index da8d90a..8d41ccb 100644
--- a/DomainDig/DashboardView.swift
+++ b/DomainDig/DashboardView.swift
@@ -139,7 +139,7 @@ struct DashboardView: View {
.font(appDensity.font(.headline, design: .default, weight: .semibold))
Text("\(group.domains.count) domain\(group.domains.count == 1 ? "" : "s")")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Spacer()
groupBadge(for: group.domains)
@@ -170,7 +170,6 @@ struct DashboardView: View {
}
}
}
- .preferredColorScheme(.dark)
}
private func disclosureBinding(for apexDomain: String) -> Binding<Bool> {
@@ -193,7 +192,7 @@ struct DashboardView: View {
VStack(alignment: .leading, spacing: 8) {
Text(title)
.font(appDensity.font(.caption, design: .default, weight: .semibold))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text("\(value)")
.font(.system(size: 28, weight: .bold, design: .rounded))
.foregroundStyle(.primary)
@@ -230,7 +229,7 @@ struct DashboardView: View {
private func dashboardEmptyRow(_ message: String) -> some View {
Text(message)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.padding(.vertical, 4)
}
@@ -288,7 +287,7 @@ private struct PortfolioActivityRow: View {
Text(relativeTimestamp(item.timestamp))
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
.padding(.vertical, 4)
@@ -320,10 +319,10 @@ private struct PortfolioAttentionRow: View {
.foregroundStyle(.primary)
Text(item.reason)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text(relativeTimestamp(item.timestamp))
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
.padding(.vertical, 4)
@@ -353,7 +352,7 @@ private struct PortfolioExpiryRow: View {
.foregroundStyle(.primary)
Text(expirySubtitle)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Spacer()
AppStatusBadgeView(model: badgeModel)
diff --git a/DomainDig/DomainCompareView.swift b/DomainDig/DomainCompareView.swift
index 90ee5b1..8219fa7 100644
--- a/DomainDig/DomainCompareView.swift
+++ b/DomainDig/DomainCompareView.swift
@@ -38,7 +38,7 @@ struct DomainCompareView: View {
Section {
Text("Choose two different domains to compare.")
.font(.callout)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
diff --git a/DomainDig/DomainDig/AuditViews.swift b/DomainDig/DomainDig/AuditViews.swift
index df5a9a9..50ea137 100644
--- a/DomainDig/DomainDig/AuditViews.swift
+++ b/DomainDig/DomainDig/AuditViews.swift
@@ -41,13 +41,13 @@ struct AuditListView: View {
Spacer()
Text("\(group.sessions.count) audit\(group.sessions.count == 1 ? "" : "s")")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let latest = group.sessions.first {
Text(latest.findings.isEmpty ? "No findings recorded yet" : latest.findings.map(\.title).prefix(2).joined(separator: " • "))
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(2)
HStack(spacing: 8) {
@@ -57,7 +57,7 @@ struct AuditListView: View {
}
Text("Checklist \(latest.completedChecklistCount)/\(latest.checklist.count)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -85,7 +85,6 @@ struct AuditListView: View {
}
}
}
- .preferredColorScheme(.dark)
}
}
@@ -116,7 +115,7 @@ struct AuditDomainTimelineView: View {
Text("Reviewer: \(session.reviewer)")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
HStack(spacing: 8) {
Text("\(session.findings.count) findings")
@@ -126,7 +125,7 @@ struct AuditDomainTimelineView: View {
}
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.padding(.vertical, 4)
}
@@ -143,11 +142,11 @@ struct AuditDomainTimelineView: View {
Spacer()
Text("\(point.findingCount) findings")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text("Open high severity: \(point.openHighSeverityCount) • Repeated issues: \(point.repeatedIssueCount)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.padding(.vertical, 2)
}
@@ -197,7 +196,7 @@ struct AuditSessionDetailView: View {
.font(appDensity.font(.headline, design: .default, weight: .semibold))
Text("Reviewer: \(session.reviewer)")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Spacer()
auditStatusBadge(session.status)
@@ -215,7 +214,7 @@ struct AuditSessionDetailView: View {
Text("Captured \(session.evidence.capturedAt.formatted(date: .abbreviated, time: .shortened))")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
.listRowBackground(Color(.appSurface))
@@ -256,7 +255,7 @@ struct AuditSessionDetailView: View {
.foregroundStyle(.primary)
Text(item.detail)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Spacer()
}
@@ -270,7 +269,7 @@ struct AuditSessionDetailView: View {
if session.findings.isEmpty {
Text("No findings recorded.")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(session.findings) { finding in
Button {
@@ -286,11 +285,11 @@ struct AuditSessionDetailView: View {
}
Text(finding.summary)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(2)
Text("\(finding.status.title) • \(finding.evidenceReferences.count) evidence refs")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.padding(.vertical, 2)
}
@@ -321,7 +320,7 @@ struct AuditSessionDetailView: View {
.font(appDensity.font(.caption, weight: .semibold))
Text(entry.changeSummaryMessage ?? "No change summary")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -337,11 +336,11 @@ struct AuditSessionDetailView: View {
Spacer()
Text(point.status.title)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text("Findings \(point.findingCount) • Open high \(point.openHighSeverityCount) • Repeated \(point.repeatedIssueCount)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -401,7 +400,6 @@ struct AuditSessionDetailView: View {
.background(Color(.appBackground))
}
}
- .preferredColorScheme(.dark)
}
}
@@ -459,7 +457,7 @@ private struct AuditFindingEditorView: View {
ForEach(session.evidence.screenshots) { asset in
Text("\(asset.title): \(asset.reference)")
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
diff --git a/DomainDig/DomainDigApp.swift b/DomainDig/DomainDigApp.swift
index 2f2070c..d392dde 100644
--- a/DomainDig/DomainDigApp.swift
+++ b/DomainDig/DomainDigApp.swift
@@ -12,6 +12,7 @@ struct DomainDigApp: App {
@UIApplicationDelegateAdaptor(DomainDigAppDelegate.self) private var appDelegate
@Environment(\.scenePhase) private var scenePhase
@AppStorage(AppDensity.userDefaultsKey) private var density = AppDensity.compact.rawValue
+ @AppStorage(AppAppearance.userDefaultsKey) private var appearance = AppAppearance.system.rawValue
@State private var viewModel = DomainViewModel()
@State private var purchaseService = PurchaseService.shared
@State private var cloudSyncService = CloudSyncService.shared
@@ -27,6 +28,8 @@ struct DomainDigApp: App {
WindowGroup {
RootTabView(viewModel: viewModel)
.environment(\.appDensity, AppDensity(rawValue: density) ?? .compact)
+ // The single place appearance is applied. Keep it that way.
+ .preferredColorScheme((AppAppearance(rawValue: appearance) ?? .system).colorScheme)
.task {
let _ = purchaseService.currentTier
let _ = cloudSyncService.status
diff --git a/DomainDig/DomainDigUI.swift b/DomainDig/DomainDigUI.swift
index 9c63e73..7d99e4e 100644
--- a/DomainDig/DomainDigUI.swift
+++ b/DomainDig/DomainDigUI.swift
@@ -6,6 +6,45 @@ import UIKit
import AppKit
#endif
+/// User-selected appearance, applied once at the `WindowGroup`.
+///
+/// Deliberately applied in exactly one place. The app previously carried 16
+/// separate `.preferredColorScheme(.dark)` calls scattered across view bodies,
+/// which is how it became impossible to reach light mode at all — re-applying
+/// per view is what let the lock spread unnoticed.
+enum AppAppearance: String, CaseIterable, Identifiable {
+ case system
+ case light
+ case dark
+
+ static let userDefaultsKey = "appAppearance"
+
+ var id: String { rawValue }
+
+ var title: String {
+ switch self {
+ case .system:
+ return "System"
+ case .light:
+ return "Light"
+ case .dark:
+ return "Dark"
+ }
+ }
+
+ /// `nil` hands control back to the system setting.
+ var colorScheme: ColorScheme? {
+ switch self {
+ case .system:
+ return nil
+ case .light:
+ return .light
+ case .dark:
+ return .dark
+ }
+ }
+}
+
enum AppDensity: String, CaseIterable, Identifiable {
case compact
case comfortable
@@ -96,7 +135,7 @@ enum AppStatusFactory {
case .registered:
return .init(title: "Registered", systemImage: "circle.fill", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
case .unknown, .none:
- return .init(title: "Unknown", systemImage: "questionmark.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: "Unknown", systemImage: "questionmark.circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
}
@@ -112,7 +151,7 @@ enum AppStatusFactory {
static func email(_ result: EmailSecurityResult?, error: String?) -> AppStatusBadgeModel {
guard error == nil, let result else {
- return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
let foundCount = [result.spf.found, result.dmarc.found, result.dkim.found].filter { $0 }.count
@@ -122,18 +161,18 @@ enum AppStatusFactory {
case 1, 2:
return .init(title: "Partial", systemImage: "shield.lefthalf.filled", foregroundColor: Color(.statusWarning), backgroundColor: Color(.statusWarning).opacity(0.16))
default:
- return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: "Missing", systemImage: "minus.circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
}
static func change(_ summary: DomainChangeSummary?) -> AppStatusBadgeModel {
guard let summary else {
- return .init(title: "Unchanged", systemImage: "circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: "Unchanged", systemImage: "circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
if summary.hasChanges {
return .init(title: "Changed", systemImage: "arrow.triangle.2.circlepath", foregroundColor: Color(.statusInfo), backgroundColor: Color(.statusInfo).opacity(0.16))
}
- return .init(title: "Unchanged", systemImage: "checkmark.circle", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated))
+ return .init(title: "Unchanged", systemImage: "checkmark.circle", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated))
}
}
@@ -259,7 +298,7 @@ struct EmptyStateCardView: View {
Text(message)
.font(appDensity.font(.body))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.fixedSize(horizontal: false, vertical: true)
Text(suggestion)
@@ -311,14 +350,14 @@ struct CollapsibleSectionView<HeaderTrailing: View, Content: View>: View {
if let subtitle {
Text(subtitle)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
Spacer(minLength: 8)
trailing()
Image(systemName: isCollapsed ? "chevron.down" : "chevron.up")
.font(.caption.weight(.semibold))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.contentShape(Rectangle())
.frame(minHeight: appDensity.metrics.controlMinHeight, alignment: .center)
diff --git a/DomainDig/HistoryView.swift b/DomainDig/HistoryView.swift
index ffa7745..5b788c3 100644
--- a/DomainDig/HistoryView.swift
+++ b/DomainDig/HistoryView.swift
@@ -40,12 +40,12 @@ struct HistoryView: View {
Spacer()
Text("\(item.count) snapshots")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text(item.latest.changeSummaryMessage ?? "No change summary")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(2)
HStack(spacing: 8) {
@@ -129,7 +129,6 @@ struct HistoryView: View {
.onChange(of: viewModel.rerunNavigationToken) { _, _ in
dismiss()
}
- .preferredColorScheme(.dark)
}
private func deleteFilteredHistoryEntries(at offsets: IndexSet) {
@@ -372,7 +371,6 @@ struct HistoryDetailView: View {
}
}
}
- .preferredColorScheme(.dark)
}
private var snapshotBanner: some View {
@@ -385,7 +383,7 @@ struct HistoryDetailView: View {
Spacer()
Text("Live re-run available")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let mismatchNote = viewModel.resolverMismatchNote(for: entry) {
Text(mismatchNote)
@@ -400,10 +398,10 @@ struct HistoryDetailView: View {
if let note = entry.note, !note.isEmpty {
Text(note)
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.padding(8)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(.appSurface))
diff --git a/DomainDig/IntegrationsView.swift b/DomainDig/IntegrationsView.swift
index 163d4d1..bb9abae 100644
--- a/DomainDig/IntegrationsView.swift
+++ b/DomainDig/IntegrationsView.swift
@@ -15,7 +15,7 @@ struct IntegrationsSettingsView: View {
if let statusMessage = integrationService.statusMessage {
Text(statusMessage)
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Button("Process Queue Now") {
@@ -26,7 +26,7 @@ struct IntegrationsSettingsView: View {
Section("Targets") {
if integrationService.targets.isEmpty {
Text("No integrations configured.")
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(integrationService.targets) { target in
NavigationLink {
@@ -42,12 +42,12 @@ struct IntegrationsSettingsView: View {
Text(target.name)
Spacer()
Text(target.type.title)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text(summary(for: target))
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if !target.isEnabled {
Text("Disabled")
@@ -138,7 +138,7 @@ private struct IntegrationDetailView: View {
Section("Delivery Log") {
if integrationService.deliveryRecords(for: target.id).isEmpty {
Text("No deliveries yet.")
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(integrationService.deliveryRecords(for: target.id), id: \.id) { record in
VStack(alignment: .leading, spacing: 4) {
@@ -147,7 +147,7 @@ private struct IntegrationDetailView: View {
Spacer()
Text(record.timestamp.formatted(date: .abbreviated, time: .shortened))
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text(record.summary)
@@ -155,7 +155,7 @@ private struct IntegrationDetailView: View {
Text(record.destination)
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let failureReason = record.failureReason {
let failureColor: Color = record.status == .skipped ? .secondary : Color(.statusCritical)
@@ -169,7 +169,7 @@ private struct IntegrationDetailView: View {
}
} else {
Text("Integration not found.")
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
.navigationTitle(target?.name ?? "Integration")
@@ -265,7 +265,7 @@ private struct IntegrationEditorView: View {
if existingTarget != nil {
Text("Saved webhook URL remains in Keychain unless you replace it.")
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
case .slack:
@@ -278,7 +278,7 @@ private struct IntegrationEditorView: View {
if existingTarget != nil {
Text("Saved Slack webhook remains in Keychain unless you replace it.")
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
case .email:
@@ -315,7 +315,7 @@ private struct IntegrationEditorView: View {
if existingTarget != nil {
Text("Saved SMTP password remains in Keychain unless you replace it.")
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
diff --git a/DomainDig/MonitoringView.swift b/DomainDig/MonitoringView.swift
index decad35..db6f685 100644
--- a/DomainDig/MonitoringView.swift
+++ b/DomainDig/MonitoringView.swift
@@ -31,7 +31,7 @@ struct MonitoringView: View {
!monitoringStatusMessage.isEmpty {
Text(monitoringStatusMessage)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Button(viewModel.monitoringRunInProgress ? "Monitoring…" : "Run Now") {
@@ -68,12 +68,12 @@ struct MonitoringView: View {
Spacer()
Text(log.timestamp.formatted(date: .abbreviated, time: .shortened))
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text(log.summary)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
HStack(spacing: 8) {
metricBadge(title: "\(log.domainsChecked) checked")
@@ -95,7 +95,6 @@ struct MonitoringView: View {
.scrollContentBackground(.hidden)
.background(Color(.appBackground))
.navigationTitle("Monitoring")
- .preferredColorScheme(.dark)
.onAppear {
viewModel.refreshMonitoringState()
}
@@ -152,7 +151,7 @@ struct MonitoringLogDetailView: View {
Text(result.summaryMessage)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
HStack(spacing: 10) {
Text(result.resultSource.label)
@@ -162,7 +161,7 @@ struct MonitoringLogDetailView: View {
}
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let errorMessage = result.errorMessage {
Text(errorMessage)
@@ -188,7 +187,7 @@ struct MonitoringLogDetailView: View {
ForEach(log.errors, id: \.self) { error in
Text(error)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
.listRowBackground(Color(.appSurface))
@@ -197,7 +196,6 @@ struct MonitoringLogDetailView: View {
.scrollContentBackground(.hidden)
.background(Color(.appBackground))
.navigationTitle("Run Details")
- .preferredColorScheme(.dark)
}
private func color(for severity: MonitoringAlertSeverity) -> Color {
diff --git a/DomainDig/PaywallView.swift b/DomainDig/PaywallView.swift
index 27e80ee..2b66037 100644
--- a/DomainDig/PaywallView.swift
+++ b/DomainDig/PaywallView.swift
@@ -12,7 +12,7 @@ struct PaywallView: View {
Section {
Text("Pro unlocks workflows, scale, monitoring automation, and exports. Pro+ adds deeper external intelligence with no additional usage limits.")
.font(appDensity.font(.body, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.fixedSize(horizontal: false, vertical: true)
}
@@ -38,7 +38,7 @@ struct PaywallView: View {
} else if purchaseService.products.isEmpty {
Text("Pricing is unavailable right now.")
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Button("Retry") {
Task {
@@ -58,7 +58,7 @@ struct PaywallView: View {
.foregroundStyle(.primary)
Text(product.displayPrice)
.font(appDensity.font(.callout, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.frame(maxWidth: .infinity, alignment: .leading)
}
@@ -69,7 +69,7 @@ struct PaywallView: View {
if let statusMessage = purchaseService.statusMessage {
Text(statusMessage)
.font(appDensity.font(.caption, design: .default))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let errorMessage = purchaseService.errorMessage {
diff --git a/DomainDig/SavedDomainsView.swift b/DomainDig/SavedDomainsView.swift
index 59dcb73..125d8a0 100644
--- a/DomainDig/SavedDomainsView.swift
+++ b/DomainDig/SavedDomainsView.swift
@@ -9,7 +9,7 @@ struct SavedDomainsView: View {
if viewModel.savedDomains.isEmpty {
Text("No saved domains")
.font(.system(.callout, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.listRowBackground(Color(.appSurface))
} else {
ForEach(viewModel.savedDomains, id: \.self) { domain in
@@ -37,6 +37,5 @@ struct SavedDomainsView: View {
EditButton()
}
}
- .preferredColorScheme(.dark)
}
}
diff --git a/DomainDig/ScheduledReportsView.swift b/DomainDig/ScheduledReportsView.swift
index dffafe3..5c0a14a 100644
--- a/DomainDig/ScheduledReportsView.swift
+++ b/DomainDig/ScheduledReportsView.swift
@@ -13,7 +13,7 @@ struct ScheduledReportsView: View {
if !FeatureAccessService.hasAccess(to: .automatedMonitoring) {
Text("Scheduled reports require Pro.")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Toggle("Scheduled Reports", isOn: Binding(
@@ -59,7 +59,7 @@ struct ScheduledReportsView: View {
if let statusMessage {
Text(statusMessage)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Button(isGenerating ? "Generating…" : "Generate Now") {
@@ -91,7 +91,7 @@ struct ScheduledReportsView: View {
.foregroundStyle(.primary)
Text(log.generatedAt.formatted(date: .abbreviated, time: .shortened))
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
diff --git a/DomainDig/TimelineView.swift b/DomainDig/TimelineView.swift
index 052b088..16e2bf8 100644
--- a/DomainDig/TimelineView.swift
+++ b/DomainDig/TimelineView.swift
@@ -125,7 +125,7 @@ private struct TimelineRow: View {
Text(summary.changeSummaryMessage ?? "No change summary")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(2)
HStack(spacing: 8) {
@@ -137,14 +137,14 @@ private struct TimelineRow: View {
}
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if !entry.intelligenceTimeline.isEmpty {
VStack(alignment: .leading, spacing: 4) {
ForEach(Array(entry.intelligenceTimeline.prefix(2))) { event in
Text("\(event.title): \(event.detail)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(1)
}
}
@@ -161,7 +161,7 @@ private struct TimelineRow: View {
.lineLimit(1)
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
diff --git a/DomainDig/WatchlistView.swift b/DomainDig/WatchlistView.swift
index 5c5609e..ddb6f4a 100644
--- a/DomainDig/WatchlistView.swift
+++ b/DomainDig/WatchlistView.swift
@@ -42,7 +42,7 @@ struct WatchlistView: View {
HStack {
Text(viewModel.batchProgressLabel)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
if viewModel.batchLookupRunning {
Button("Cancel") {
@@ -78,7 +78,7 @@ struct WatchlistView: View {
Section {
Text(limitMessage)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.listRowBackground(Color(.appSurface))
}
@@ -208,7 +208,7 @@ struct WatchlistView: View {
Section {
Text("Adds the domain directly to your watchlist so monitoring can run without a prior inspection.")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let addDomainError {
@@ -267,7 +267,7 @@ struct WatchlistView: View {
.foregroundStyle(.primary)
Text([view.tag, view.filter.title, view.sort.title].compactMap { $0 }.joined(separator: " • "))
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -288,7 +288,6 @@ struct WatchlistView: View {
}
}
}
- .preferredColorScheme(.dark)
}
@ViewBuilder
@@ -450,12 +449,12 @@ struct WatchlistRowView: View {
Text("Updated \(trackedDomain.updatedAt.formatted(date: .abbreviated, time: .shortened))")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let collaboration = trackedDomain.collaboration, collaboration.isShared {
Text("\(collaboration.ownership.title) • \(collaboration.permission.title)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
HStack(spacing: 8) {
@@ -468,19 +467,19 @@ struct WatchlistRowView: View {
}
}
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
indicatorRow
if let note = trackedDomain.note?.trimmingCharacters(in: .whitespacesAndNewlines), !note.isEmpty {
Text(note)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(2)
} else if let summary = trackedDomain.lastChangeSummary {
Text(summary.message)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(2)
}
}
@@ -502,7 +501,7 @@ struct WatchlistRowView: View {
@ViewBuilder
private var statusBadge: some View {
if isRefreshing {
- AppStatusBadgeView(model: .init(title: "Refreshing", systemImage: "arrow.clockwise", foregroundColor: .secondary, backgroundColor: Color(.appSurfaceElevated)))
+ AppStatusBadgeView(model: .init(title: "Refreshing", systemImage: "arrow.clockwise", foregroundColor: Color(.appTextSecondary), backgroundColor: Color(.appSurfaceElevated)))
} else {
AppStatusBadgeView(model: AppStatusFactory.availability(trackedDomain.lastKnownAvailability))
}
@@ -700,7 +699,7 @@ struct TrackedDomainDetailView: View {
if latestSnapshots.isEmpty {
Text("No snapshots yet")
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(latestSnapshots) { entry in
NavigationLink {
@@ -712,7 +711,7 @@ struct TrackedDomainDetailView: View {
.foregroundStyle(.primary)
Text(entry.changeSummary?.hasChanges == true ? "Changed" : "Snapshot")
.font(.system(.caption2, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -723,7 +722,6 @@ struct TrackedDomainDetailView: View {
.scrollContentBackground(.hidden)
.background(Color(.appBackground))
.navigationTitle(liveTrackedDomain.domain)
- .preferredColorScheme(.dark)
.onChange(of: viewModel.rerunNavigationToken) { _, _ in
dismiss()
}
diff --git a/DomainDig/WorkflowsView.swift b/DomainDig/WorkflowsView.swift
index 2195af5..d628ba4 100644
--- a/DomainDig/WorkflowsView.swift
+++ b/DomainDig/WorkflowsView.swift
@@ -22,7 +22,7 @@ struct WorkflowsView: View {
Section {
Text(limitMessage)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.listRowBackground(Color(.appSurface))
}
@@ -54,7 +54,6 @@ struct WorkflowsView: View {
.sheet(item: workflowSummaryBinding) { summary in
WorkflowRunSummaryView(viewModel: viewModel, summary: summary)
}
- .preferredColorScheme(.dark)
}
private var workflowSummaryBinding: Binding<WorkflowRunSummary?> {
@@ -78,7 +77,7 @@ struct WorkflowsView: View {
HStack {
Text(viewModel.batchProgressLabel)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
if viewModel.batchLookupRunning {
Button("Cancel") {
@@ -142,23 +141,23 @@ private struct WorkflowRowView: View {
Spacer(minLength: 8)
Text("\(workflow.domains.count) domains")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text("Updated \(workflow.updatedAt.formatted(date: .abbreviated, time: .shortened))")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
if let collaboration = workflow.collaboration, collaboration.isShared {
Text("\(collaboration.ownership.title) • \(collaboration.permission.title)")
.font(appDensity.font(.caption2))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let notes = workflow.notes, !notes.isEmpty {
Text(notes)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(2)
}
}
@@ -197,12 +196,12 @@ struct WorkflowDetailView: View {
if let notes = workflow.notes, !notes.isEmpty {
Text(notes)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
if let collaboration = workflow.collaboration, collaboration.isShared {
Text("\(collaboration.ownership.title) • \(collaboration.permission.title)")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
@@ -277,7 +276,7 @@ struct WorkflowDetailView: View {
if !latestSummary.workflowInsights.isEmpty {
Text(latestSummary.workflowInsights[0].description)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Button {
@@ -306,7 +305,7 @@ struct WorkflowDetailView: View {
if workflow.domains.isEmpty {
Text("No domains in this workflow")
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(workflow.domains, id: \.self) { domain in
Button {
@@ -318,7 +317,7 @@ struct WorkflowDetailView: View {
.foregroundStyle(.primary)
Spacer()
Image(systemName: "arrow.up.right.circle")
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
.buttonStyle(.plain)
@@ -355,17 +354,16 @@ struct WorkflowDetailView: View {
} else {
Text("Workflow not found")
.font(appDensity.font(.callout))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
- .preferredColorScheme(.dark)
}
private func statRow(label: String, value: String) -> some View {
HStack {
Text(label)
.font(appDensity.font(.caption))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
Text(value)
.font(appDensity.font(.callout))
@@ -449,7 +447,6 @@ struct WorkflowComposerView: View {
}
}
}
- .preferredColorScheme(.dark)
}
private var parsedDomains: [String] {
@@ -507,7 +504,7 @@ struct WorkflowRunSummaryView: View {
.foregroundStyle(.primary)
Text(insight.domainsInvolved.joined(separator: ", "))
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
}
@@ -517,7 +514,7 @@ struct WorkflowRunSummaryView: View {
if visibleResults.isEmpty {
Text("No domains with meaningful changes or warnings")
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
} else {
ForEach(visibleResults) { result in
if let entry = viewModel.historyEntry(for: result) {
@@ -578,14 +575,13 @@ struct WorkflowRunSummaryView: View {
}
}
}
- .preferredColorScheme(.dark)
}
private func statRow(label: String, value: String) -> some View {
HStack {
Text(label)
.font(.system(.caption, design: .monospaced))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
Text(value)
.font(.system(.callout, design: .monospaced))
@@ -687,7 +683,6 @@ struct WorkflowBulkAddSheet: View {
}
}
}
- .preferredColorScheme(.dark)
}
private var selectedDomainList: [String] {
diff --git a/DomainDigWidget/DomainDigPortfolioWidget.swift b/DomainDigWidget/DomainDigPortfolioWidget.swift
index a3335c8..37a96a0 100644
--- a/DomainDigWidget/DomainDigPortfolioWidget.swift
+++ b/DomainDigWidget/DomainDigPortfolioWidget.swift
@@ -61,10 +61,10 @@ struct DomainDigWidgetView: View {
VStack(spacing: 6) {
Image(systemName: "magnifyingglass")
.font(.title2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text("No tracked domains")
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.multilineTextAlignment(.center)
}
}
@@ -80,13 +80,13 @@ struct DomainDigWidgetView: View {
Spacer()
}
.font(.caption2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Text("\(data.totalDomains)")
.font(.system(size: 34, weight: .bold, design: .rounded))
Text("tracked")
.font(.caption2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer(minLength: 0)
@@ -113,11 +113,11 @@ struct DomainDigWidgetView: View {
Label("Domain Portfolio", systemImage: "shield.lefthalf.filled")
.font(.caption)
.fontWeight(.semibold)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
Text("\(data.totalDomains) tracked")
.font(.caption2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
HStack(spacing: 12) {
@@ -147,7 +147,7 @@ struct DomainDigWidgetView: View {
.foregroundStyle(color)
Text(label)
.font(.system(size: 9))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
.frame(maxWidth: .infinity, alignment: .leading)
}
@@ -160,7 +160,7 @@ struct DomainDigWidgetView: View {
if domain.isPinned {
Image(systemName: "pin.fill")
.font(.system(size: 8))
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Text(domain.domain)
.font(.caption)
@@ -168,7 +168,7 @@ struct DomainDigWidgetView: View {
Spacer(minLength: 4)
Text(certLabel(for: domain))
.font(.caption2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
}
diff --git a/DomainDigWidget/SweepLiveActivity.swift b/DomainDigWidget/SweepLiveActivity.swift
index b96f8bf..900ebc1 100644
--- a/DomainDigWidget/SweepLiveActivity.swift
+++ b/DomainDigWidget/SweepLiveActivity.swift
@@ -14,7 +14,7 @@ struct SweepLiveActivity: Widget {
DynamicIslandExpandedRegion(.leading) {
Label(context.attributes.title, systemImage: "arrow.trianglehead.2.clockwise")
.font(.caption)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
DynamicIslandExpandedRegion(.trailing) {
Text("\(context.state.completed)/\(context.state.total)")
@@ -28,7 +28,7 @@ struct SweepLiveActivity: Widget {
if let current = context.state.currentDomain {
Text(current)
.font(.caption2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(1)
}
}
@@ -58,7 +58,7 @@ private struct SweepActivityBannerView: View {
Label(context.attributes.title, systemImage: "arrow.trianglehead.2.clockwise")
.font(.caption)
.fontWeight(.semibold)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
Spacer()
Text("\(context.state.completed) of \(context.state.total)")
.font(.caption)
@@ -72,12 +72,12 @@ private struct SweepActivityBannerView: View {
if let current = context.state.currentDomain {
Text(current)
.font(.caption2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
.lineLimit(1)
} else {
Text(context.state.completed >= context.state.total ? "Finished" : "Working…")
.font(.caption2)
- .foregroundStyle(.secondary)
+ .foregroundStyle(Color(.appTextSecondary))
}
Spacer()
if context.state.changed > 0 {
diff --git a/Shared/Colors.xcassets/AppTextSecondary.colorset/Contents.json b/Shared/Colors.xcassets/AppTextSecondary.colorset/Contents.json
new file mode 100644
index 0000000..9e7bb36
--- /dev/null
+++ b/Shared/Colors.xcassets/AppTextSecondary.colorset/Contents.json
@@ -0,0 +1,78 @@
+{
+ "colors": [
+ {
+ "idiom": "universal",
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "red": "0x5A",
+ "green": "0x5A",
+ "blue": "0x5F",
+ "alpha": "1.000"
+ }
+ }
+ },
+ {
+ "idiom": "universal",
+ "appearances": [
+ {
+ "appearance": "luminosity",
+ "value": "dark"
+ }
+ ],
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "red": "0xA1",
+ "green": "0xA1",
+ "blue": "0xA6",
+ "alpha": "1.000"
+ }
+ }
+ },
+ {
+ "idiom": "universal",
+ "appearances": [
+ {
+ "appearance": "contrast",
+ "value": "high"
+ }
+ ],
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "red": "0x3A",
+ "green": "0x3A",
+ "blue": "0x3C",
+ "alpha": "1.000"
+ }
+ }
+ },
+ {
+ "idiom": "universal",
+ "appearances": [
+ {
+ "appearance": "luminosity",
+ "value": "dark"
+ },
+ {
+ "appearance": "contrast",
+ "value": "high"
+ }
+ ],
+ "color": {
+ "color-space": "srgb",
+ "components": {
+ "red": "0xC7",
+ "green": "0xC7",
+ "blue": "0xCC",
+ "alpha": "1.000"
+ }
+ }
+ }
+ ],
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+}