summaryrefslogtreecommitdiff
path: root/DomainDig/BatchResultsView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'DomainDig/BatchResultsView.swift')
-rw-r--r--DomainDig/BatchResultsView.swift60
1 files changed, 60 insertions, 0 deletions
diff --git a/DomainDig/BatchResultsView.swift b/DomainDig/BatchResultsView.swift
index 4b4f6fd..aeae48f 100644
--- a/DomainDig/BatchResultsView.swift
+++ b/DomainDig/BatchResultsView.swift
@@ -116,6 +116,39 @@ struct BatchResultRowView: View {
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.vertical, 4)
.frame(minHeight: appDensity.metrics.rowMinHeight + 12, alignment: .topLeading)
+ // One VoiceOver stop per row: domain as the label, status as the value,
+ // everything else on the More Content rotor. Reading all eight text
+ // elements inline would make a 200-domain sweep unnavigable. `.high`
+ // importance is spoken without the rotor; the rest waits for a swipe.
+ // Extracted to a modifier — inlined, the chain broke the type-checker.
+ .modifier(BatchRowAccessibility(
+ domain: result.domain,
+ status: "\(quickStatusBadge.title), \(availabilityText)",
+ risk: riskDescription,
+ ip: result.primaryIP ?? "none",
+ checked: result.timestamp.formatted(date: .abbreviated, time: .shortened),
+ source: result.resultSource.label,
+ changeLabel: changeContentLabel,
+ changeValue: changeContentValue
+ ))
+ }
+
+ private var changeContentLabel: String {
+ result.changeClassification != nil ? "Impact" : "Status"
+ }
+
+ private var changeContentValue: String {
+ if let change = result.changeClassification {
+ return change.title
+ }
+ return result.errorMessage ?? result.summaryMessage ?? quickStatusBadge.title
+ }
+
+ private var riskDescription: String {
+ if let score = result.riskScore, let level = result.riskLevel {
+ return "\(score), \(level.title)"
+ }
+ return "not scored"
}
private var availabilityText: String {
@@ -164,3 +197,30 @@ struct BatchResultRowView: View {
}
}
}
+
+/// Row-level VoiceOver treatment for a batch result: a single element whose
+/// label is the domain and whose value is the status, with the remaining fields
+/// on the More Content rotor. Extracted from the row body because inlining the
+/// full modifier chain broke Swift's type-checker.
+private struct BatchRowAccessibility: ViewModifier {
+ let domain: String
+ let status: String
+ let risk: String
+ let ip: String
+ let checked: String
+ let source: String
+ let changeLabel: String
+ let changeValue: String
+
+ func body(content: Content) -> some View {
+ content
+ .accessibilityElement(children: .ignore)
+ .accessibilityLabel(domain)
+ .accessibilityValue(status)
+ .accessibilityCustomContent("Risk", risk, importance: .high)
+ .accessibilityCustomContent("IP address", ip)
+ .accessibilityCustomContent("Checked", checked)
+ .accessibilityCustomContent("Source", source)
+ .accessibilityCustomContent(LocalizedStringResource(stringLiteral: changeLabel), changeValue)
+ }
+}