| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- import SwiftUI
- struct SplashScreenView: View {
- @Bindable var viewModel: SplashViewModel
- @Environment(AppearanceManager.self) private var appearanceManager
- @State private var contentScale: CGFloat = 0.9
- @State private var contentOpacity: Double = 0
- @State private var detailsOpacity: Double = 0
- @State private var glowPulse = false
- var body: some View {
- let isDark = appearanceManager.isDarkMode
- ZStack {
- background(isDark: isDark)
- glowOrb(isDark: isDark)
- VStack(spacing: 28) {
- brandMark
- VStack(spacing: 24) {
- VStack(spacing: 10) {
- title
- Text("AI Assistant for Reddit")
- .font(.system(size: 14, weight: .medium))
- .foregroundStyle(AppTheme.textSecondary)
- }
- loadingBar
- }
- .opacity(detailsOpacity)
- }
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .scaleEffect(contentScale)
- .opacity(contentOpacity)
- }
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .ignoresSafeArea()
- .onAppear {
- withAnimation(.spring(response: 0.62, dampingFraction: 0.78)) {
- contentScale = 1
- contentOpacity = 1
- }
- withAnimation(.easeOut(duration: 0.55).delay(0.12)) {
- detailsOpacity = 1
- }
- withAnimation(.easeInOut(duration: 2.4).repeatForever(autoreverses: true)) {
- glowPulse = true
- }
- }
- }
- private func background(isDark: Bool) -> some View {
- Group {
- if isDark {
- AppTheme.background
- } else {
- LinearGradient(
- colors: [
- Color(hex: 0xF3F0FF),
- AppTheme.background
- ],
- startPoint: .top,
- endPoint: .bottom
- )
- }
- }
- .ignoresSafeArea()
- }
- private func glowOrb(isDark: Bool) -> some View {
- Circle()
- .fill(
- RadialGradient(
- colors: [
- AppTheme.accentPurple.opacity(isDark ? 0.22 : 0.14),
- Color.clear
- ],
- center: .center,
- startRadius: 0,
- endRadius: 280
- )
- )
- .frame(width: 560, height: 560)
- .scaleEffect(glowPulse ? 1.06 : 0.94)
- .offset(x: 180, y: -220)
- .allowsHitTesting(false)
- }
- private var brandMark: some View {
- Image("AppLogo")
- .resizable()
- .interpolation(.high)
- .scaledToFit()
- .frame(width: 80, height: 80)
- .shadow(color: Color(hex: 0xFF4500).opacity(0.35), radius: 28, y: 10)
- }
- private var loadingBar: some View {
- VStack(spacing: 12) {
- GeometryReader { geometry in
- ZStack(alignment: .leading) {
- Capsule()
- .fill(AppTheme.border)
- Capsule()
- .fill(
- LinearGradient(
- colors: [AppTheme.accentPurple, AppTheme.accentPurpleLight],
- startPoint: .leading,
- endPoint: .trailing
- )
- )
- .frame(width: max(geometry.size.width * viewModel.loadingProgress, geometry.size.height))
- }
- }
- .frame(width: 300, height: 7)
- Text("Loading…")
- .font(.system(size: 12, weight: .medium))
- .foregroundStyle(AppTheme.textTertiary)
- }
- .frame(maxWidth: .infinity)
- }
- private var title: some View {
- Text(AppLinks.appName)
- .font(.system(size: 34, weight: .bold))
- .tracking(-0.6)
- .foregroundStyle(AppTheme.textPrimary)
- }
- }
|