Files
Reflect/Shared/Onboarding/views/OnboardingDay.swift
Trey t 4851eee5f8 Fix paywall width overflow on iOS 18, update onboarding tip from Yesterday to Today
Add containerRelativeFrame to paywall marketing content so feature cards
fit within screen width on iOS 18. Update onboarding tip text and all
localizations (DE, ES, FR, JA, KO, PT-BR).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:21:41 -06:00

188 lines
6.2 KiB
Swift

//
// 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 {
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: \"Today\" works great for evening reminders")
.font(.subheadline.weight(.medium))
.foregroundColor(.white.opacity(0.9))
}
.padding(.horizontal, 30)
.padding(.bottom, 80)
}
.background(
LinearGradient(
colors: [Color(hex: "4facfe"), Color(hex: "00f2fe")],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
.ignoresSafeArea()
)
.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)
.accessibilityElement(children: .combine)
.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)
}
}
}