Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import SwiftUI

@MainActor
@Observable
public final class OnboardingCoordinator {
public final class OnboardingCoordinator: @MainActor Identifiable {
public var id: String { "onboarding" }

// Current screen state
public var currentScreen: OnboardingScreen = .welcome

Expand All @@ -17,8 +19,9 @@ public final class OnboardingCoordinator {
public let permissionManager: PermissionManager
public let analytics: AnalyticsManager

// UserDefaults key
// UserDefaults keys
private static let hasCompletedOnboardingKey = "hasCompletedOnboarding"
private static let hasSeenFeaturesKey = "hasSeenOnboardingFeatures"

public init(
permissionManager: PermissionManager,
Expand All @@ -34,6 +37,10 @@ public final class OnboardingCoordinator {
withAnimation(.easeInOut(duration: 0.3)) {
currentScreen = screen
}

if screen == .permissions {
markFeaturesAsSeen()
}
}

func skipToPermissions() {
Expand All @@ -42,6 +49,8 @@ public final class OnboardingCoordinator {
screen: currentScreen.analyticsName
))

markFeaturesAsSeen()

withAnimation(.easeInOut(duration: 0.3)) {
currentScreen = .permissions
}
Expand All @@ -61,6 +70,16 @@ public final class OnboardingCoordinator {
onComplete?()
}

// MARK: - Features Seen State

private func markFeaturesAsSeen() {
UserDefaults.standard.set(true, forKey: Self.hasSeenFeaturesKey)
}

private static var hasSeenFeatures: Bool {
UserDefaults.standard.bool(forKey: hasSeenFeaturesKey)
}

// MARK: - Onboarding State Management

/// Create coordinator if onboarding is needed, returns nil if not needed
Expand All @@ -71,12 +90,19 @@ public final class OnboardingCoordinator {
// Check if onboarding was completed
let hasCompleted = UserDefaults.standard.bool(forKey: hasCompletedOnboardingKey)

// If never completed, create coordinator starting at welcome
// If never completed, create coordinator
if !hasCompleted {
let coordinator = OnboardingCoordinator(
permissionManager: permissionManager,
analytics: analytics
)

// If user already saw features, go directly to permissions
if hasSeenFeatures {
coordinator.currentScreen = .permissions
}
// Otherwise, start from welcome

return coordinator
}

Expand All @@ -86,7 +112,7 @@ public final class OnboardingCoordinator {
permissionManager: permissionManager,
analytics: analytics
)
// Start at permissions screen
// Start at permissions screen (already completed before, no need to see features again)
coordinator.currentScreen = .permissions
return coordinator
}
Expand All @@ -98,6 +124,7 @@ public final class OnboardingCoordinator {
/// Reset onboarding state (for debug/testing)
public static func resetOnboarding() {
UserDefaults.standard.removeObject(forKey: hasCompletedOnboardingKey)
UserDefaults.standard.removeObject(forKey: hasSeenFeaturesKey)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public struct OnboardingBackground: View {
(theme.main.background.color ?? Color.secondary)
.ignoresSafeArea()

Image("normal_sem_fundo", bundle: .module)
Image("normal_without_background", bundle: .module)
.resizable()
.scaledToFit()
.frame(width: 520)
Expand All @@ -20,13 +20,13 @@ public struct OnboardingBackground: View {
.blur(radius: 5)
.accessibilityHidden(true)

Image("alternativa_sem_fundo", bundle: .module)
Image("alternativa_without_background", bundle: .module)
.resizable()
.scaledToFit()
.frame(width: 360)
.rotationEffect(.degrees(18))
.offset(x: -170, y: 220)
.opacity(colorScheme == .dark ? 0.4 : 0.9)
.opacity(colorScheme == .dark ? 0.14 : 0.14)
.blur(radius: 5)
.accessibilityHidden(true)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ public struct OnboardingLogoView: View {
let width: CGFloat
let height: CGFloat

public init(width: CGFloat = 152,
height: CGFloat = 152) {
private var cornerRadius: CGFloat {
min(width, height) * 0.184
}

public init(
width: CGFloat = 152,
height: CGFloat = 152
) {
self.width = width
self.height = height
}
Expand All @@ -15,17 +21,31 @@ public struct OnboardingLogoView: View {
Image("normal", bundle: .module)
.resizable()
.scaledToFit()
.frame(width: self.width, height: self.height)
.clipShape(RoundedRectangle(cornerRadius: 28, style: .continuous))
.frame(width: width, height: height)
.clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous))
.overlay {
RoundedRectangle(cornerRadius: 28, style: .continuous)
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.stroke(.white.opacity(0.15), lineWidth: 1)
}
.background {
RoundedRectangle(cornerRadius: 28, style: .continuous)
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.fill(.regularMaterial)
.shadow(radius: 18, y: 10)
}
.accessibilityHidden(true)
}
}

// MARK: - Preview

#if DEBUG
#Preview("Logo Sizes") {
VStack(spacing: 40) {
OnboardingLogoView(width: 152, height: 152)
OnboardingLogoView(width: 80, height: 80)
OnboardingLogoView(width: 60, height: 60)
}
.padding()
.background(Color.gray.opacity(0.3))
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public struct PermissionCard: View {

public var body: some View {
VStack(alignment: .leading, spacing: 12) {
// Header com Γ­cone e tΓ­tulo
HStack(spacing: 12) {
Image(systemName: icon)
.font(.title2)
Expand All @@ -37,22 +38,25 @@ public struct PermissionCard: View {
.foregroundStyle(.primary)

Spacer()

statusView
}
.accessibilityElement(children: .combine)

// DescriΓ§Γ£o
Text(description)
.font(.subheadline)
.foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)

// BotΓ£o de status
statusView
.frame(maxWidth: .infinity, alignment: .trailing)
}
.padding(16)
.frame(maxWidth: .infinity, alignment: .leading)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(.ultraThinMaterial)
)
.accessibilityElement(children: .combine)
}

@ViewBuilder
Expand Down Expand Up @@ -84,32 +88,37 @@ public struct PermissionCard: View {
}
.buttonStyle(.plain)
.disabled(isProcessing)
.accessibilityLabel("Permitir \(title)")
.accessibilityHint("Toque para autorizar esta permissΓ£o")

case .granted:
HStack(spacing: 6) {
Image(systemName: "checkmark.circle.fill")
.font(.caption)
.font(.subheadline)
Text("Autorizado")
.font(.caption.weight(.medium))
.font(.subheadline.weight(.semibold))
}
.foregroundStyle(.white)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(Color.green)
.clipShape(Capsule())
.accessibilityLabel("\(title) autorizado")

case .denied:
HStack(spacing: 6) {
Image(systemName: "xmark.circle.fill")
.font(.caption)
.font(.subheadline)
Text("Negado")
.font(.caption.weight(.medium))
.font(.subheadline.weight(.semibold))
}
.foregroundStyle(.white)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(Color.gray)
.clipShape(Capsule())
.accessibilityLabel("\(title) negado")
.accessibilityHint("VocΓͺ pode alterar nas ConfiguraΓ§Γ΅es do dispositivo")
}
}
}
Expand All @@ -124,7 +133,7 @@ public enum PermissionCardStatus {

// MARK: - Preview

#Preview("Permission Card - Not Determined") {
#Preview("Permission Card - All States") {
VStack(spacing: 16) {
PermissionCard(
title: "NotificaΓ§Γ΅es",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public struct OnboardingContainerView: View {
public var body: some View {
NavigationStack {
ZStack {
OnboardingBackground()
// OnboardingBackground()

Group {
switch coordinator.currentScreen {
Expand Down Expand Up @@ -48,7 +48,7 @@ public struct OnboardingContainerView: View {
OnboardingSheetPreviewHost()
}

#Preview("Sheet - iPad", traits: .landscapeLeft) {
#Preview("Sheet - Landscape", traits: .landscapeLeft) {
OnboardingSheetPreviewHost()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct WelcomeView: View {
.padding(.top, 16)
.padding(.trailing, 20)
}
.background(OnboardingBackground())
// .background(OnboardingBackground())
.onAppear { animateIn = true }
.onDisappear { animateIn = false }
.trackScreen(
Expand Down
Loading