summaryrefslogtreecommitdiff
path: root/DayByDay/ContentView.swift
blob: c3ede7ad151b2adf1d503be9f228638384a80f5c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//
//  ContentView.swift
//  DayByDay
//
//  Created by cmc on 2026-03-09.
//

import SwiftUI

struct ContentView: View {
    @State private var selectedTab = 0
    @AppStorage("hasSeenVoiceTip") private var hasSeenVoiceTip = false

    private let tabs: [(label: String, symbol: String)] = [
        ("Days", "calendar"),
        ("Months", "calendar.badge.clock"),
        ("Seasons", "leaf.fill"),
    ]

    var body: some View {
        VStack(spacing: 0) {
            Group {
                switch selectedTab {
                case 0:  DaysOfWeekView()
                case 1:  MonthsOfYearView()
                default: SeasonsView()
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)

            Divider()

            // Bottom tab bar with large tap targets
            HStack(spacing: 0) {
                ForEach(Array(tabs.enumerated()), id: \.offset) { index, tab in
                    Button {
                        selectedTab = index
                    } label: {
                        VStack(spacing: 6) {
                            Image(systemName: tab.symbol)
                                .font(.system(size: 32))
                            Text(tab.label)
                                .font(.system(size: 18, weight: .semibold, design: .rounded))
                        }
                        .foregroundStyle(selectedTab == index ? Color.accentColor : Color.secondary)
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 14)
                        .contentShape(Rectangle())
                    }
                    .buttonStyle(.plain)
                    .accessibilityLabel(tab.label)
                }
            }
            .padding(.horizontal, 24)
            .padding(.bottom, 8)
            .background(.bar)
        }
        .overlay {
            if !hasSeenVoiceTip {
                VoiceTipOverlay {
                    withAnimation { hasSeenVoiceTip = true }
                }
            }
        }
    }
}

/// A one-time informational overlay for parents explaining how to download
/// a higher-quality voice for the best experience. Dismissed with a single tap.
struct VoiceTipOverlay: View {
    let onDismiss: () -> Void

    var body: some View {
        ZStack {
            Color.black.opacity(0.4)
                .ignoresSafeArea()

            VStack(spacing: 20) {
                Image(systemName: "speaker.wave.3.fill")
                    .font(.system(size: 48))
                    .foregroundStyle(.blue)

                Text("Better Voices Available")
                    .font(.system(size: 28, weight: .bold, design: .rounded))

                Text("For the best experience, download an enhanced voice on your iPad.\n\nSettings → Accessibility → Spoken Content → Voices → English → tap a voice marked Enhanced or Premium to download it.")
                    .font(.system(size: 18, design: .rounded))
                    .multilineTextAlignment(.center)
                    .foregroundStyle(.secondary)

                Text("Tap anywhere to dismiss")
                    .font(.system(size: 16, weight: .medium, design: .rounded))
                    .foregroundStyle(.tertiary)
                    .padding(.top, 8)
            }
            .padding(40)
            .frame(maxWidth: 520)
            .background(
                RoundedRectangle(cornerRadius: 32, style: .continuous)
                    .fill(.regularMaterial)
            )
        }
        .contentShape(Rectangle())
        .onTapGesture(perform: onDismiss)
    }
}

#Preview {
    ContentView()
}