Fix theme selection bug and update onboarding with AppTheme picker

- Change Theme enum from Int to String raw values to fix theme selection bug
- Replace OnboardingStyle icon/color pickers with unified AppTheme grid
- Remove visible text labels from voting layouts while keeping accessibility labels (WCAG 2.1 AA compliant)
- Update widget voting views to use icons only with proper accessibility support
- Consolidate app icons to single unified icon set

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-28 00:03:34 -06:00
parent 8fab566724
commit c4e013763a
1001 changed files with 1377 additions and 6781 deletions

View File

@@ -146,27 +146,21 @@ struct CardVotingView: View {
LazyVGrid(columns: columns, spacing: 12) {
ForEach(Mood.allValues) { mood in
Button(action: { onMoodSelected(mood) }) {
VStack(spacing: 8) {
mood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
.foregroundColor(moodTint.color(forMood: mood))
Text(mood.strValue)
.font(.caption.weight(.medium))
.foregroundColor(moodTint.color(forMood: mood))
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(
RoundedRectangle(cornerRadius: 12)
.fill(moodTint.color(forMood: mood).opacity(0.15))
)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(moodTint.color(forMood: mood).opacity(0.3), lineWidth: 1)
)
mood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
.foregroundColor(moodTint.color(forMood: mood))
.frame(maxWidth: .infinity)
.padding(.vertical, 20)
.background(
RoundedRectangle(cornerRadius: 12)
.fill(moodTint.color(forMood: mood).opacity(0.15))
)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(moodTint.color(forMood: mood).opacity(0.3), lineWidth: 1)
)
}
.buttonStyle(CardButtonStyle())
.accessibilityLabel(mood.strValue)
@@ -195,22 +189,16 @@ struct RadialVotingView: View {
let position = positionForAngle(angle, radius: radius, center: center)
Button(action: { onMoodSelected(mood) }) {
VStack(spacing: 4) {
mood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 44, height: 44)
.foregroundColor(moodTint.color(forMood: mood))
Text(mood.strValue)
.font(.caption2.weight(.medium))
.foregroundColor(moodTint.color(forMood: mood))
}
.padding(8)
.background(
Circle()
.fill(moodTint.color(forMood: mood).opacity(0.1))
)
mood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 44, height: 44)
.foregroundColor(moodTint.color(forMood: mood))
.padding(12)
.background(
Circle()
.fill(moodTint.color(forMood: mood).opacity(0.1))
)
}
.buttonStyle(MoodButtonStyle())
.position(position)
@@ -312,59 +300,51 @@ struct AuraVotingView: View {
let color = moodTint.color(forMood: mood)
return Button(action: { onMoodSelected(mood) }) {
VStack(spacing: 10) {
// Glowing orb
ZStack {
// Outer atmospheric glow
Circle()
.fill(
RadialGradient(
colors: [
color.opacity(0.5),
color.opacity(0.2),
Color.clear
],
center: .center,
startRadius: 0,
endRadius: 45
)
// Glowing orb
ZStack {
// Outer atmospheric glow
Circle()
.fill(
RadialGradient(
colors: [
color.opacity(0.5),
color.opacity(0.2),
Color.clear
],
center: .center,
startRadius: 0,
endRadius: 45
)
.frame(width: 90, height: 90)
)
.frame(width: 90, height: 90)
// Middle glow ring
Circle()
.fill(
RadialGradient(
colors: [
color.opacity(0.8),
color.opacity(0.4)
],
center: .center,
startRadius: 10,
endRadius: 30
)
// Middle glow ring
Circle()
.fill(
RadialGradient(
colors: [
color.opacity(0.8),
color.opacity(0.4)
],
center: .center,
startRadius: 10,
endRadius: 30
)
.frame(width: 60, height: 60)
)
.frame(width: 60, height: 60)
// Inner solid core
Circle()
.fill(color)
.frame(width: 48, height: 48)
.shadow(color: color.opacity(0.8), radius: 12, x: 0, y: 0)
// Inner solid core
Circle()
.fill(color)
.frame(width: 48, height: 48)
.shadow(color: color.opacity(0.8), radius: 12, x: 0, y: 0)
// Icon
mood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 26, height: 26)
.foregroundColor(.white)
}
// Label with elegant typography
Text(mood.strValue)
.font(.caption.weight(.semibold))
.foregroundColor(color)
.tracking(0.5)
// Icon
mood.icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 26, height: 26)
.foregroundColor(.white)
}
}
.buttonStyle(AuraButtonStyle(color: color))
@@ -687,66 +667,60 @@ struct NeonEqualizerBar: View {
var body: some View {
Button(action: onTap) {
VStack(spacing: 8) {
// The equalizer bar
ZStack(alignment: .bottom) {
// Glow background
RoundedRectangle(cornerRadius: 6)
.fill(barColor.opacity(pulsePhase ? 0.15 : 0.08))
.frame(height: barHeight + 20)
.blur(radius: 15)
// The equalizer bar
ZStack(alignment: .bottom) {
// Glow background
RoundedRectangle(cornerRadius: 6)
.fill(barColor.opacity(pulsePhase ? 0.15 : 0.08))
.frame(height: barHeight + 20)
.blur(radius: 15)
// Main bar
RoundedRectangle(cornerRadius: 6)
.fill(
LinearGradient(
colors: [
barColor,
barColor.opacity(0.7)
],
startPoint: .top,
endPoint: .bottom
)
// Main bar
RoundedRectangle(cornerRadius: 6)
.fill(
LinearGradient(
colors: [
barColor,
barColor.opacity(0.7)
],
startPoint: .top,
endPoint: .bottom
)
.frame(height: isPressed ? barHeight * 0.9 : barHeight)
.shadow(color: barColor.opacity(0.8), radius: pulsePhase ? 12 : 8, x: 0, y: 0)
.shadow(color: barColor.opacity(0.4), radius: pulsePhase ? 20 : 15, x: 0, y: 5)
)
.frame(height: isPressed ? barHeight * 0.9 : barHeight)
.shadow(color: barColor.opacity(0.8), radius: pulsePhase ? 12 : 8, x: 0, y: 0)
.shadow(color: barColor.opacity(0.4), radius: pulsePhase ? 20 : 15, x: 0, y: 5)
// Top highlight
RoundedRectangle(cornerRadius: 6)
.fill(
LinearGradient(
colors: [Color.white.opacity(0.5), Color.clear],
startPoint: .top,
endPoint: .center
)
// Top highlight
RoundedRectangle(cornerRadius: 6)
.fill(
LinearGradient(
colors: [Color.white.opacity(0.5), Color.clear],
startPoint: .top,
endPoint: .center
)
.frame(height: isPressed ? barHeight * 0.9 : barHeight)
)
.frame(height: isPressed ? barHeight * 0.9 : barHeight)
// Level indicators (horizontal lines)
VStack(spacing: 8) {
ForEach(0..<Int(barHeight / 15), id: \.self) { _ in
Rectangle()
.fill(Color.black.opacity(0.3))
.frame(height: 2)
}
// Level indicators (horizontal lines)
VStack(spacing: 8) {
ForEach(0..<Int(barHeight / 15), id: \.self) { _ in
Rectangle()
.fill(Color.black.opacity(0.3))
.frame(height: 2)
}
.frame(height: isPressed ? barHeight * 0.9 - 10 : barHeight - 10)
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding(.horizontal, 4)
.padding(.bottom, 5)
}
.frame(maxHeight: 160, alignment: .bottom)
// Mood label
Text(mood.shortLabel)
.font(.system(size: 10, weight: .bold, design: .monospaced))
.foregroundColor(barColor)
.shadow(color: barColor.opacity(0.8), radius: 4, x: 0, y: 0)
.frame(height: isPressed ? barHeight * 0.9 - 10 : barHeight - 10)
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding(.horizontal, 4)
.padding(.bottom, 5)
}
.frame(maxHeight: 180, alignment: .bottom)
}
.buttonStyle(NeonBarButtonStyle(isPressed: $isPressed))
.frame(maxWidth: .infinity)
.accessibilityLabel(mood.strValue)
.accessibilityHint(String(localized: "Select this mood"))
}
}
@@ -763,15 +737,3 @@ struct NeonBarButtonStyle: ButtonStyle {
}
}
private extension Mood {
var shortLabel: String {
switch self {
case .great: return "GRT"
case .good: return "GUD"
case .average: return "AVG"
case .bad: return "BAD"
case .horrible: return "HRB"
default: return "---"
}
}
}