feat: hero card layout in all pills, cache-while-loading, logo splash screen
- Every pill (F1, Tech, AI, Cloud, HomeLab…) now shows the same hero card layout as "All" — first story is the big featured card, rest follow as rows - "All" retains its full multi-section front page (US / Tech / AI / Sport…) - Topic pill headers use the pill name instead of "TOP STORIES" - filteredStories now falls back to cached SwiftData rows while loading, so switching to F1 or Tech shows cached cards instantly instead of a blank list - Logo splash screen (3 pill bars + jarvis wordmark) shows on launch and fades out after setup completes; minimum 1.3 s so it's always readable - JarvisWordmark moved to Theme.swift so SplashView and feed can share it Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,38 @@ import SwiftData
|
||||
import UIKit
|
||||
import BackgroundTasks
|
||||
|
||||
// MARK: - Logo + 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 {
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(hex: "0A0A0A").ignoresSafeArea()
|
||||
VStack(spacing: 28) {
|
||||
JarvisLogoMark(width: 180)
|
||||
JarvisWordmark(size: 34)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
func application(_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
@@ -37,6 +69,7 @@ struct JarvisApp: App {
|
||||
@StateObject private var connectivity = ConnectivitySettings.shared
|
||||
@StateObject private var connManager = ConnectivityManager.shared
|
||||
@StateObject private var notifications = NotificationManager.shared
|
||||
@State private var showSplash = true
|
||||
|
||||
// Single ModelContainer instance shared with BackgroundRefreshManager.
|
||||
private let container: ModelContainer = {
|
||||
@@ -47,13 +80,22 @@ struct JarvisApp: App {
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
Group {
|
||||
if settings.isConfigured {
|
||||
RootTabView()
|
||||
ZStack {
|
||||
if showSplash {
|
||||
SplashView()
|
||||
.transition(.opacity)
|
||||
} else {
|
||||
OnboardingView()
|
||||
Group {
|
||||
if settings.isConfigured {
|
||||
RootTabView()
|
||||
} else {
|
||||
OnboardingView()
|
||||
}
|
||||
}
|
||||
.transition(.opacity)
|
||||
}
|
||||
}
|
||||
.animation(.easeOut(duration: 0.5), value: showSplash)
|
||||
.preferredColorScheme(appearanceMode.colorScheme)
|
||||
.environmentObject(settings)
|
||||
.environmentObject(store)
|
||||
@@ -62,13 +104,14 @@ struct JarvisApp: App {
|
||||
.environmentObject(connManager)
|
||||
.environmentObject(notifications)
|
||||
.task {
|
||||
// Wire the shared container before scheduling BG work.
|
||||
BackgroundRefreshManager.container = container
|
||||
BackgroundRefreshManager.scheduleFeedRefresh()
|
||||
|
||||
connManager.start()
|
||||
await connManager.resolveAndActivate()
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user