iOS VoiceOver accessibility overhaul — 67 files

New framework:
- AccessibilityLabels.swift: centralized A11y struct with VoiceOver strings
- AccessibilityModifiers.swift: reusable .a11yHeader, .a11yDecorative,
  .a11yButton, .a11yCard, .a11yStatValue View extensions

Shared components: decorative elements hidden, stat views combined,
status/priority badges labeled, error views announced, empty states grouped

Cards: ResidenceCard, TaskCard, DynamicTaskCard, ContractorCard,
DocumentCard, WarrantyCard — all grouped with combined labels,
chevrons hidden, action buttons labeled

Main screens: Login, Register, Residences, Tasks, Contractors, Documents —
toolbar buttons labeled, section headers marked, form field hints added

Onboarding: all 10 views — header traits, button hints, task selection
state, progress indicator, decorative backgrounds hidden

Profile/Subscription: toggle hints, theme selection state, feature
comparison table accessibility, subscription button labels

iOS build verified: BUILD SUCCEEDED
This commit is contained in:
Trey T
2026-03-26 14:51:29 -05:00
parent 0d80df07f6
commit af73f8861b
67 changed files with 394 additions and 8 deletions
@@ -0,0 +1,91 @@
import Foundation
/// Centralized accessibility labels for VoiceOver
/// These labels provide human-readable descriptions for screen reader users
struct A11y {
// MARK: - Authentication
struct Auth {
static let loginButton = "Sign in"
static let appleSignIn = "Sign in with Apple"
static let googleSignIn = "Sign in with Google"
static let forgotPassword = "Forgot password"
static let signUp = "Create account"
static let passwordToggle = "Toggle password visibility"
static let appLogo = "honeyDue app logo"
}
// MARK: - Navigation
struct Navigation {
static let residencesTab = "Properties"
static let tasksTab = "Tasks"
static let contractorsTab = "Contractors"
static let documentsTab = "Documents"
static let settingsButton = "Settings"
static let addButton = "Add"
static let backButton = "Back"
static let closeButton = "Close"
static let editButton = "Edit"
static let deleteButton = "Delete"
static let saveButton = "Save"
static let cancelButton = "Cancel"
}
// MARK: - Residence
struct Residence {
static func card(name: String, taskCount: Int, overdueCount: Int) -> String {
"\(name), \(taskCount) tasks, \(overdueCount) overdue"
}
static let addProperty = "Add new property"
static let primaryBadge = "Primary property"
static func openInMaps(address: String) -> String { "Open \(address) in Maps" }
static func shareCode(code: String) -> String { "Share code: \(code)" }
static let copyShareCode = "Copy share code"
static let generateShareCode = "Generate new share code"
static func removeUser(name: String) -> String { "Remove \(name) from property" }
}
// MARK: - Task
struct Task {
static func card(title: String, priority: String, dueDate: String) -> String {
"\(title), \(priority) priority, due \(dueDate)"
}
static let addTask = "Add new task"
static let taskActions = "Task actions"
static func priorityBadge(level: String) -> String { "Priority: \(level)" }
static func statusBadge(status: String) -> String { "Status: \(status)" }
static func completionCount(count: Int) -> String { "View \(count) completions" }
static func rating(value: Int) -> String { "Rated \(value) out of 5" }
static let markInProgress = "Mark as in progress"
static let completeTask = "Complete task"
static let archiveTask = "Archive task"
static let cancelTask = "Cancel task"
}
// MARK: - Contractor
struct Contractor {
static func card(name: String, company: String?, specialty: String) -> String {
[name, company, specialty].compactMap { $0 }.joined(separator: ", ")
}
static let addContractor = "Add new contractor"
static func toggleFavorite(name: String, isFavorite: Bool) -> String {
isFavorite ? "Remove \(name) from favorites" : "Add \(name) to favorites"
}
}
// MARK: - Document
struct Document {
static func card(title: String, type: String) -> String { "\(title), \(type)" }
static let addDocument = "Add new document"
}
// MARK: - Common
struct Common {
static func stat(value: String, label: String) -> String { "\(value) \(label)" }
static let decorative = "" // For .accessibilityHidden(true)
static let retryButton = "Try again"
static let dismissError = "Dismiss error"
static func photo(index: Int) -> String { "Photo \(index)" }
static let removePhoto = "Remove photo"
}
}