// // OnboardingDay.swift // Feels (iOS) // // Created by Trey Tartt on 1/20/22. // import SwiftUI enum DayOptions: Int, CaseIterable, RawRepresentable, Codable { case Today case Previous var localizedValue: String { switch self { case .Today: return String(localized: "onboarding_day_options_today") case .Previous: return String(localized: "onboarding_day_options_yesterday") } } } 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) { Spacer() // Icon ZStack { Circle() .fill(.white.opacity(0.15)) .frame(width: 120, height: 120) Image(systemName: "calendar") .font(.largeTitle) .foregroundColor(.white) } .padding(.bottom, 32) // Title Text("Which day should\nyou rate?") .font(.title.weight(.bold)) .foregroundColor(.white) .multilineTextAlignment(.center) .padding(.bottom, 12) // Subtitle Text("When you get your reminder, do you want to rate today or yesterday?") .font(.body.weight(.medium)) .foregroundColor(.white.opacity(0.85)) .multilineTextAlignment(.center) .padding(.horizontal, 40) Spacer() // Options VStack(spacing: 14) { DayOptionCard( title: "Today", subtitle: "Rate the current day", example: "e.g. Tue reminder → Rate Tue", icon: "sun.max.fill", isSelected: onboardingData.inputDay == .Today, action: { onboardingData.inputDay = .Today }, testID: AccessibilityID.Onboarding.dayToday ) DayOptionCard( title: "Yesterday", subtitle: "Rate the previous day", example: "e.g. Tue reminder → Rate Mon", icon: "moon.fill", isSelected: onboardingData.inputDay == .Previous, action: { onboardingData.inputDay = .Previous }, testID: AccessibilityID.Onboarding.dayYesterday ) } .padding(.horizontal, 20) Spacer() // Tip HStack(spacing: 12) { Image(systemName: "lightbulb.fill") .font(.headline) .foregroundColor(.yellow) Text("Tip: \"Yesterday\" works great for evening reminders") .font(.subheadline.weight(.medium)) .foregroundColor(.white.opacity(0.9)) } .padding(.horizontal, 30) .padding(.bottom, 80) } } .accessibilityIdentifier(AccessibilityID.Onboarding.dayScreen) } } struct DayOptionCard: View { let title: String let subtitle: String let example: String let icon: String let isSelected: Bool let action: () -> Void var testID: String? = nil var body: some View { Button(action: action) { HStack(spacing: 14) { // Icon ZStack { Circle() .fill(isSelected ? Color.white : Color.white.opacity(0.2)) .frame(width: 46, height: 46) Image(systemName: icon) .font(.title3) .foregroundColor(isSelected ? Color(hex: "4facfe") : .white) } .accessibilityHidden(true) // Text VStack(alignment: .leading, spacing: 3) { Text(title) .font(.body.weight(.semibold)) .foregroundColor(isSelected ? Color(hex: "4facfe") : .white) Text(subtitle) .font(.caption) .foregroundColor(isSelected ? Color(hex: "4facfe").opacity(0.8) : .white.opacity(0.8)) Text(example) .font(.caption2.weight(.medium)) .foregroundColor(isSelected ? Color(hex: "4facfe").opacity(0.6) : .white.opacity(0.6)) .lineLimit(1) .minimumScaleFactor(0.8) } Spacer(minLength: 8) // Checkmark if isSelected { Image(systemName: "checkmark.circle.fill") .font(.title3) .foregroundColor(Color(hex: "4facfe")) .accessibilityHidden(true) } } .padding(.horizontal, 16) .padding(.vertical, 18) .background( RoundedRectangle(cornerRadius: 18) .fill(isSelected ? .white : .white.opacity(0.15)) .shadow(color: isSelected ? .black.opacity(0.1) : .clear, radius: 10, y: 5) ) } .buttonStyle(.plain) .accessibilityLabel("\(title), \(subtitle)") .accessibilityHint(example) .accessibilityAddTraits(isSelected ? [.isSelected] : []) .accessibilityIdentifier(testID ?? "") } } struct OnboardingDay_Previews: PreviewProvider { static var previews: some View { Group { OnboardingDay(onboardingData: OnboardingData()) OnboardingDay(onboardingData: OnboardingData()) .preferredColorScheme(.dark) } } }