Refactor ZStack layouts to .background(), add Year View accessibility IDs, triage QA test plan
Replace ZStack-with-gradient patterns with idiomatic .background() modifier across onboarding, customize, and settings views. Add accessibility identifiers to Year View charts for UI test automation. Mark 67 impossible-to-automate tests RED in QA plan and scaffold initial Year View and Settings onboarding tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,16 +25,7 @@ struct OnboardingDay: View {
|
||||
@ObservedObject var onboardingData: OnboardingData
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Gradient background
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "4facfe"), Color(hex: "00f2fe")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
|
||||
// Icon
|
||||
@@ -103,8 +94,15 @@ struct OnboardingDay: View {
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.padding(.bottom, 80)
|
||||
}
|
||||
}
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "4facfe"), Color(hex: "00f2fe")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.dayScreen)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,7 @@ struct OnboardingStyle: View {
|
||||
@State private var selectedTheme: AppTheme = .celestial
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Gradient background that updates with theme
|
||||
LinearGradient(
|
||||
colors: selectedTheme.previewColors,
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
.animation(.easeInOut(duration: 0.4), value: selectedTheme)
|
||||
|
||||
ScrollView(showsIndicators: false) {
|
||||
ScrollView(showsIndicators: false) {
|
||||
VStack(spacing: 0) {
|
||||
// Icon
|
||||
ZStack {
|
||||
@@ -85,8 +75,16 @@ struct OnboardingStyle: View {
|
||||
.padding(.top, 24)
|
||||
.padding(.bottom, 80)
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: selectedTheme.previewColors,
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
.animation(.easeInOut(duration: 0.4), value: selectedTheme)
|
||||
)
|
||||
.onAppear {
|
||||
// Apply default theme on appear
|
||||
selectedTheme.apply()
|
||||
|
||||
@@ -15,16 +15,7 @@ struct OnboardingSubscription: View {
|
||||
let completionClosure: ((OnboardingData) -> Void)
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Gradient background
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "11998e"), Color(hex: "38ef7d")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
|
||||
// Crown icon
|
||||
@@ -137,8 +128,15 @@ struct OnboardingSubscription: View {
|
||||
}
|
||||
.padding(.horizontal, 24)
|
||||
.padding(.bottom, 50)
|
||||
}
|
||||
}
|
||||
.background(
|
||||
LinearGradient(
|
||||
colors: [Color(hex: "11998e"), Color(hex: "38ef7d")],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
)
|
||||
.accessibilityIdentifier(AccessibilityID.Onboarding.subscriptionScreen)
|
||||
.sheet(isPresented: $showSubscriptionStore, onDismiss: {
|
||||
// After subscription store closes, complete onboarding
|
||||
|
||||
@@ -16,44 +16,35 @@ struct OnboardingTitle: View {
|
||||
@ObservedObject var onboardingData: OnboardingData
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
|
||||
Image("average", bundle: .main)
|
||||
.foregroundColor(Color(UIColor.darkText))
|
||||
.opacity(0.04)
|
||||
.scaleEffect(1.2)
|
||||
.padding(.bottom, 55)
|
||||
.accessibilityHidden(true)
|
||||
|
||||
ScrollView {
|
||||
VStack{
|
||||
Text(String(localized: "onboarding_title_title"))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
.padding([.trailing, .leading], 55)
|
||||
.padding([.top], 25)
|
||||
|
||||
ForEach(OnboardingTitle.titleOptions, id: \.self) { option in
|
||||
Button(action: {
|
||||
ScrollView {
|
||||
VStack{
|
||||
Text(String(localized: "onboarding_title_title"))
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
.padding([.trailing, .leading], 55)
|
||||
.padding([.top], 25)
|
||||
|
||||
ForEach(OnboardingTitle.titleOptions, id: \.self) { option in
|
||||
Button(action: {
|
||||
// onboardingData.title = option
|
||||
}, label: {
|
||||
Text(option)
|
||||
.font(.subheadline.weight(.bold))
|
||||
.foregroundColor(.white)
|
||||
.padding(10)
|
||||
.background(RoundedRectangle(cornerRadius: 10).stroke().foregroundColor(Color.white))
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.padding([.top], 10)
|
||||
}
|
||||
|
||||
Text(String(localized: "onboarding_title_type_your_own"))
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
.padding([.top], 25)
|
||||
.padding([.trailing, .leading], 55)
|
||||
|
||||
}, label: {
|
||||
Text(option)
|
||||
.font(.subheadline.weight(.bold))
|
||||
.foregroundColor(.white)
|
||||
.padding(10)
|
||||
.background(RoundedRectangle(cornerRadius: 10).stroke().foregroundColor(Color.white))
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.padding([.top], 10)
|
||||
}
|
||||
|
||||
Text(String(localized: "onboarding_title_type_your_own"))
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
.padding([.top], 25)
|
||||
.padding([.trailing, .leading], 55)
|
||||
|
||||
// TextField("Notification", text: $onboardingData.title)
|
||||
// .frame(height: 44)
|
||||
// .foregroundColor(Color(UIColor.white))
|
||||
@@ -63,12 +54,21 @@ struct OnboardingTitle: View {
|
||||
// .overlay(RoundedRectangle(cornerRadius: 16).stroke(Color.white))
|
||||
// .padding([.leading, .trailing], 75)
|
||||
// .padding([.top], 45)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.background {
|
||||
ZStack {
|
||||
Color.orange
|
||||
Image("average", bundle: .main)
|
||||
.foregroundColor(Color(UIColor.darkText))
|
||||
.opacity(0.04)
|
||||
.scaleEffect(1.2)
|
||||
.padding(.bottom, 55)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
}
|
||||
.background(.orange)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,56 @@ struct OnboardingWrapup: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
GeometryReader { geometry in
|
||||
GeometryReader { geometry in
|
||||
VStack {
|
||||
ScrollView {
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(String(localized: "onboarding_wrap_up_1"))
|
||||
.padding(.top)
|
||||
.padding()
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Text(formatter.string(from: onboardingData.date))
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.padding()
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Text(String(localized: "onboarding_wrap_up_3"))
|
||||
.font(.title)
|
||||
.padding()
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Text(onboardingData.inputDay.localizedValue)
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.padding()
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.onboardingCompleted(dayId: String(onboardingData.inputDay.rawValue)))
|
||||
completionClosure(onboardingData)
|
||||
}, label: {
|
||||
Text(String(localized: "onboarding_wrap_up_complete_button"))
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(Color(hex: "31d158"))
|
||||
.padding()
|
||||
.background(RoundedRectangle(cornerRadius: 10).fill().foregroundColor(Color.white))
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.padding([.top], 65)
|
||||
}
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.frame(maxWidth: geometry.size.width)
|
||||
}
|
||||
.background {
|
||||
ZStack {
|
||||
Color(hex: "31d158")
|
||||
VStack {
|
||||
Spacer()
|
||||
Image("great", bundle: .main)
|
||||
@@ -30,55 +78,8 @@ struct OnboardingWrapup: View {
|
||||
.accessibilityHidden(true)
|
||||
Spacer()
|
||||
}
|
||||
|
||||
VStack {
|
||||
ScrollView {
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(String(localized: "onboarding_wrap_up_1"))
|
||||
.padding(.top)
|
||||
.padding()
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Text(formatter.string(from: onboardingData.date))
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.padding()
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Text(String(localized: "onboarding_wrap_up_3"))
|
||||
.font(.title)
|
||||
.padding()
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Text(onboardingData.inputDay.localizedValue)
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.padding()
|
||||
.foregroundColor(Color(UIColor.white))
|
||||
|
||||
Button(action: {
|
||||
AnalyticsManager.shared.track(.onboardingCompleted(dayId: String(onboardingData.inputDay.rawValue)))
|
||||
completionClosure(onboardingData)
|
||||
}, label: {
|
||||
Text(String(localized: "onboarding_wrap_up_complete_button"))
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(Color(hex: "31d158"))
|
||||
.padding()
|
||||
.background(RoundedRectangle(cornerRadius: 10).fill().foregroundColor(Color.white))
|
||||
.cornerRadius(10)
|
||||
})
|
||||
.padding([.top], 65)
|
||||
}
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.frame(maxWidth: geometry.size.width)
|
||||
}
|
||||
}
|
||||
.background(Color(hex: "31d158"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user