Atoll/DynamicIsland/components/Onboarding/OnboardingView.swift
Hariharan Mudaliar bc25ec8526 Update: Onboarding
2025-11-30 12:55:23 +05:30

120 lines
4.1 KiB
Swift

//
// OnboardingView.swift
// DynamicIsland
//
// Created by Alexander on 2025-06-23.
//
import SwiftUI
import AVFoundation
enum OnboardingStep {
case welcome
case cameraPermission
case calendarPermission
case musicPermission
case profileSelection
case finished
}
private let calendarService = CalendarService()
struct OnboardingView: View {
@State private var step: OnboardingStep = .welcome
let onFinish: () -> Void
let onOpenSettings: () -> Void
var body: some View {
ZStack {
switch step {
case .welcome:
WelcomeView {
withAnimation(.easeInOut(duration: 0.6)) {
step = .cameraPermission
}
}
.transition(.opacity)
case .cameraPermission:
PermissionRequestView(
icon: Image(systemName: "camera.fill"),
title: "Enable Camera Access",
description: "Atoll includes a mirror feature that lets you quickly check your appearance using your camera, right from the notch. Camera access is required only to show this live preview. You can turn the mirror feature on or off at any time in the app.",
privacyNote: "Your camera is never used without your consent, and nothing is recorded or stored.",
onAllow: {
Task {
await requestCameraPermission()
withAnimation(.easeInOut(duration: 0.6)) {
step = .calendarPermission
}
}
},
onSkip: {
withAnimation(.easeInOut(duration: 0.6)) {
step = .calendarPermission
}
}
)
.transition(.opacity)
case .calendarPermission:
PermissionRequestView(
icon: Image(systemName: "calendar"),
title: "Enable Calendar Access",
description: "Atoll can show all your upcoming events in one place. Access to your calendar is needed to display your schedule.",
privacyNote: "Your calendar data is only used to show your events and is never shared.",
onAllow: {
Task {
await requestCalendarPermission()
withAnimation(.easeInOut(duration: 0.6)) {
step = .musicPermission
}
}
},
onSkip: {
withAnimation(.easeInOut(duration: 0.6)) {
step = .musicPermission
}
}
)
.transition(.opacity)
case .musicPermission:
MusicControllerSelectionView(
onContinue: {
withAnimation(.easeInOut(duration: 0.6)) {
step = .profileSelection
}
}
)
.transition(.opacity)
case .profileSelection:
ProfileSelectionView(
onContinue: { profiles in
applyProfileSettings(profiles)
withAnimation(.easeInOut(duration: 0.6)) {
step = .finished
}
}
)
.transition(.opacity)
case .finished:
OnboardingFinishView(onFinish: onFinish, onOpenSettings: onOpenSettings)
}
}
.frame(width: 400, height: 600)
}
// MARK: - Permission Request Logic
func requestCameraPermission() async {
await AVCaptureDevice.requestAccess(for: .video)
}
func requestCalendarPermission() async {
await calendarService.requestAccess()
}
}