Add comprehensive WCAG 2.1 AA accessibility support
- Add VoiceOver labels and hints to all voting layouts, settings, widgets, onboarding screens, and entry cells - Add Reduce Motion support to button animations throughout the app - Ensure 44x44pt minimum touch targets on widget mood buttons - Enhance AccessibilityHelpers with Dynamic Type support, ScaledValue wrapper, and VoiceOver detection utilities - Gate premium features (Insights, Month/Year views) behind subscription - Update widgets to show subscription prompts for non-subscribers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,8 +93,12 @@ struct HorizontalVotingView: View {
|
||||
}
|
||||
.buttonStyle(MoodButtonStyle())
|
||||
.frame(maxWidth: .infinity)
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Select this mood"))
|
||||
}
|
||||
}
|
||||
.accessibilityElement(children: .contain)
|
||||
.accessibilityLabel(String(localized: "Mood selection"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +140,12 @@ struct CardVotingView: View {
|
||||
)
|
||||
}
|
||||
.buttonStyle(CardButtonStyle())
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Select this mood"))
|
||||
}
|
||||
}
|
||||
.accessibilityElement(children: .contain)
|
||||
.accessibilityLabel(String(localized: "Mood selection"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,10 +185,14 @@ struct RadialVotingView: View {
|
||||
}
|
||||
.buttonStyle(MoodButtonStyle())
|
||||
.position(position)
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Select this mood"))
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: 180)
|
||||
.accessibilityElement(children: .contain)
|
||||
.accessibilityLabel(String(localized: "Mood selection"))
|
||||
}
|
||||
|
||||
private func angleForIndex(_ index: Int, total: Int) -> Double {
|
||||
@@ -233,8 +245,12 @@ struct StackedVotingView: View {
|
||||
)
|
||||
}
|
||||
.buttonStyle(CardButtonStyle())
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Select this mood"))
|
||||
}
|
||||
}
|
||||
.accessibilityElement(children: .contain)
|
||||
.accessibilityLabel(String(localized: "Mood selection"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,36 +339,43 @@ struct AuraVotingView: View {
|
||||
}
|
||||
}
|
||||
.buttonStyle(AuraButtonStyle(color: color))
|
||||
.accessibilityLabel(mood.strValue)
|
||||
.accessibilityHint(String(localized: "Select this mood"))
|
||||
}
|
||||
}
|
||||
|
||||
// Custom button style for aura with glow effect on press
|
||||
struct AuraButtonStyle: ButtonStyle {
|
||||
let color: Color
|
||||
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
configuration.label
|
||||
.scaleEffect(configuration.isPressed ? 0.92 : 1.0)
|
||||
.brightness(configuration.isPressed ? 0.1 : 0)
|
||||
.animation(.easeInOut(duration: 0.15), value: configuration.isPressed)
|
||||
.animation(reduceMotion ? nil : .easeInOut(duration: 0.15), value: configuration.isPressed)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Button Styles
|
||||
struct MoodButtonStyle: ButtonStyle {
|
||||
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
configuration.label
|
||||
.scaleEffect(configuration.isPressed ? 0.9 : 1.0)
|
||||
.animation(.easeInOut(duration: 0.15), value: configuration.isPressed)
|
||||
.animation(reduceMotion ? nil : .easeInOut(duration: 0.15), value: configuration.isPressed)
|
||||
}
|
||||
}
|
||||
|
||||
struct CardButtonStyle: ButtonStyle {
|
||||
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
configuration.label
|
||||
.scaleEffect(configuration.isPressed ? 0.96 : 1.0)
|
||||
.opacity(configuration.isPressed ? 0.8 : 1.0)
|
||||
.animation(.easeInOut(duration: 0.15), value: configuration.isPressed)
|
||||
.animation(reduceMotion ? nil : .easeInOut(duration: 0.15), value: configuration.isPressed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user