fix: splash screen uses actual app icon in a circle (Wenza style)
Some checks failed
CI / Build · macos-14 · Debug (push) Has been cancelled
CI / Build · macos-15 · Debug (push) Has been cancelled
CI / Build · macos-14 · Release (push) Has been cancelled
CI / Build · macos-15 · Release (push) Has been cancelled

Replaces the custom 3-bar SwiftUI drawing with UIImage(named:"AppIcon")
clipped to a circle, matching the Wenza splash pattern exactly:
- Icon bounces in with spring (scale 0.82→1, opacity 0→1)
- "jarvis" wordmark fades in 320ms later
- Whole screen fades out at 1.6s, onDismiss fires at 1.9s
- Main app renders underneath so it's warm when the splash clears

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Robin Kutesa
2026-06-21 02:24:07 +03:00
parent 207b1827c7
commit b53a4b8f5d

View File

@@ -5,33 +5,53 @@ import SwiftData
import UIKit import UIKit
import BackgroundTasks import BackgroundTasks
// MARK: - Logo + splash // MARK: - Splash
/// The three-bar logo that mirrors the app icon.
struct JarvisLogoMark: View {
var width: CGFloat = 180
var body: some View {
VStack(alignment: .center, spacing: 8) {
// Orange (short) · White (longest) · Grey (medium) same ratios as icon
Capsule().fill(Palette.orange)
.frame(width: width * 0.48, height: width * 0.075)
.shadow(color: Palette.orange.opacity(0.55), radius: 10, y: 2)
Capsule().fill(Color.white)
.frame(width: width, height: width * 0.075)
Capsule().fill(Color(hex: "888888"))
.frame(width: width * 0.74, height: width * 0.075)
}
}
}
struct SplashView: View { struct SplashView: View {
var onDismiss: () -> Void
@State private var iconScale: CGFloat = 0.82
@State private var iconOpacity: Double = 0
@State private var markOpacity: Double = 0
@State private var rootOpacity: Double = 1
var body: some View { var body: some View {
ZStack { ZStack {
Color(hex: "0A0A0A").ignoresSafeArea() Color(hex: "0A0A0A").ignoresSafeArea()
VStack(spacing: 28) { VStack(spacing: 22) {
JarvisLogoMark(width: 180) // App icon displayed as a circle
JarvisWordmark(size: 34) Group {
if let img = UIImage(named: "AppIcon") {
Image(uiImage: img)
.resizable()
} else {
Circle().fill(Palette.surface)
}
}
.frame(width: 108, height: 108)
.clipShape(Circle())
.shadow(color: Color.black.opacity(0.4), radius: 20, y: 6)
.scaleEffect(iconScale)
.opacity(iconOpacity)
JarvisWordmark(size: 28)
.opacity(markOpacity)
}
}
.opacity(rootOpacity)
.onAppear {
withAnimation(.spring(response: 0.48, dampingFraction: 0.74).delay(0.08)) {
iconScale = 1
iconOpacity = 1
}
withAnimation(.easeOut(duration: 0.28).delay(0.32)) {
markOpacity = 1
}
withAnimation(.easeIn(duration: 0.26).delay(1.6)) {
rootOpacity = 0
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.9) {
onDismiss()
} }
} }
} }
@@ -69,7 +89,7 @@ struct JarvisApp: App {
@StateObject private var connectivity = ConnectivitySettings.shared @StateObject private var connectivity = ConnectivitySettings.shared
@StateObject private var connManager = ConnectivityManager.shared @StateObject private var connManager = ConnectivityManager.shared
@StateObject private var notifications = NotificationManager.shared @StateObject private var notifications = NotificationManager.shared
@State private var showSplash = true @State private var splashDone = false
// Single ModelContainer instance shared with BackgroundRefreshManager. // Single ModelContainer instance shared with BackgroundRefreshManager.
private let container: ModelContainer = { private let container: ModelContainer = {
@@ -81,21 +101,19 @@ struct JarvisApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ZStack { ZStack {
if showSplash { // Main app always rendered underneath so it's ready when splash fades.
SplashView() Group {
.transition(.opacity) if settings.isConfigured {
} else { RootTabView()
Group { } else {
if settings.isConfigured { OnboardingView()
RootTabView()
} else {
OnboardingView()
}
} }
.transition(.opacity) }
if !splashDone {
SplashView { splashDone = true }
} }
} }
.animation(.easeOut(duration: 0.5), value: showSplash)
.preferredColorScheme(appearanceMode.colorScheme) .preferredColorScheme(appearanceMode.colorScheme)
.environmentObject(settings) .environmentObject(settings)
.environmentObject(store) .environmentObject(store)
@@ -109,9 +127,6 @@ struct JarvisApp: App {
connManager.start() connManager.start()
await connManager.resolveAndActivate() await connManager.resolveAndActivate()
await notifications.bootstrap() await notifications.bootstrap()
// Hold splash until setup is done, minimum 1.3 s for legibility.
try? await Task.sleep(nanoseconds: 1_300_000_000)
showSplash = false
} }
} }
.modelContainer(container) .modelContainer(container)