InvestmentTrackerApp/PortfolioJournal/App/ContentView.swift

175 lines
5.8 KiB
Swift

import SwiftUI
import CoreData
struct ContentView: View {
@EnvironmentObject var iapService: IAPService
@EnvironmentObject var adMobService: AdMobService
@EnvironmentObject var tabSelection: TabSelectionStore
@EnvironmentObject var coreDataStack: CoreDataStack
@AppStorage("onboardingCompleted") private var onboardingCompleted = false
@AppStorage("faceIdEnabled") private var faceIdEnabled = false
@AppStorage("pinEnabled") private var pinEnabled = false
@AppStorage("lockOnLaunch") private var lockOnLaunch = true
@AppStorage("lockOnBackground") private var lockOnBackground = false
@Environment(\.scenePhase) private var scenePhase
@State private var isUnlocked = false
@State private var resolvedOnboardingCompleted: Bool?
private var lockEnabled: Bool {
faceIdEnabled || pinEnabled
}
var body: some View {
ZStack {
Group {
if !isReadyForContent {
AppLaunchLoadingView(messageKey: "loading_data")
} else if resolvedOnboardingCompleted == false {
OnboardingView(onboardingCompleted: $onboardingCompleted)
} else {
mainContent
}
}
if onboardingCompleted && lockEnabled && !isUnlocked {
AppLockView(isUnlocked: $isUnlocked)
}
}
.onAppear {
if !lockEnabled {
isUnlocked = true
} else {
isUnlocked = !lockOnLaunch
}
}
.onChange(of: lockEnabled) { _, enabled in
if !enabled {
isUnlocked = true
} else {
isUnlocked = !lockOnLaunch
}
}
.onChange(of: onboardingCompleted) { _, completed in
if completed && lockEnabled {
isUnlocked = !lockOnLaunch
}
}
.onChange(of: scenePhase) { _, phase in
guard onboardingCompleted, lockEnabled else { return }
if phase == .background && lockOnBackground {
isUnlocked = false
}
}
.onAppear {
if coreDataStack.isLoaded {
syncOnboardingState()
}
}
.onChange(of: coreDataStack.isLoaded) { _, loaded in
if loaded {
syncOnboardingState()
}
}
.onChange(of: onboardingCompleted) { _, completed in
resolvedOnboardingCompleted = completed
}
}
private var isReadyForContent: Bool {
coreDataStack.isLoaded && resolvedOnboardingCompleted != nil
}
private func syncOnboardingState() {
let settings = AppSettings.getOrCreate(in: coreDataStack.viewContext)
var resolved = settings.onboardingCompleted || onboardingCompleted
if !resolved && hasExistingData() {
resolved = true
}
if settings.onboardingCompleted != resolved {
settings.onboardingCompleted = resolved
CoreDataStack.shared.save()
}
if onboardingCompleted != resolved {
onboardingCompleted = resolved
}
resolvedOnboardingCompleted = resolved
}
private func hasExistingData() -> Bool {
let context = coreDataStack.viewContext
let sourceRequest: NSFetchRequest<InvestmentSource> = InvestmentSource.fetchRequest()
sourceRequest.fetchLimit = 1
sourceRequest.resultType = .countResultType
if (try? context.count(for: sourceRequest)) ?? 0 > 0 {
return true
}
let snapshotRequest: NSFetchRequest<Snapshot> = Snapshot.fetchRequest()
snapshotRequest.fetchLimit = 1
snapshotRequest.resultType = .countResultType
if (try? context.count(for: snapshotRequest)) ?? 0 > 0 {
return true
}
let accountRequest: NSFetchRequest<Account> = Account.fetchRequest()
accountRequest.fetchLimit = 1
accountRequest.resultType = .countResultType
return ((try? context.count(for: accountRequest)) ?? 0) > 0
}
private var mainContent: some View {
ZStack {
TabView(selection: $tabSelection.selectedTab) {
DashboardView()
.tabItem {
Label("Home", systemImage: "house.fill")
}
.tag(0)
SourceListView(iapService: iapService)
.tabItem {
Label("Sources", systemImage: "list.bullet")
}
.tag(1)
ChartsContainerView(iapService: iapService)
.tabItem {
Label("Charts", systemImage: "chart.xyaxis.line")
}
.tag(2)
JournalView()
.tabItem {
Label("Journal", systemImage: "book.closed")
}
.tag(3)
SettingsView(iapService: iapService)
.tabItem {
Label("Settings", systemImage: "gearshape.fill")
}
.tag(4)
}
}
// Banner ad at bottom for free users
.safeAreaInset(edge: .bottom, spacing: 0) {
if !iapService.isPremium {
BannerAdView()
.frame(height: AppConstants.UI.bannerAdHeight)
.frame(maxWidth: .infinity)
.background(Color(.systemBackground))
}
}
}
}
#Preview {
ContentView()
.environmentObject(CoreDataStack.shared)
.environmentObject(IAPService())
.environmentObject(AdMobService())
.environmentObject(AccountStore(iapService: IAPService()))
.environmentObject(TabSelectionStore())
}