134 lines
4.0 KiB
Swift
134 lines
4.0 KiB
Swift
import SwiftUI
|
||
import SwiftData
|
||
|
||
@main
|
||
struct BookibraApp: App {
|
||
@StateObject private var router = AppRouter()
|
||
private let dependencies = AppDependencies.live()
|
||
private let container: ModelContainer
|
||
|
||
init() {
|
||
do {
|
||
container = try ModelContainer(for: LibraryBook.self)
|
||
} catch {
|
||
fatalError("SwiftData container oluşturulamadı: \(error)")
|
||
}
|
||
}
|
||
|
||
var body: some Scene {
|
||
WindowGroup {
|
||
RootView()
|
||
.environmentObject(router)
|
||
.environment(\.dependencies, dependencies)
|
||
.modelContainer(container)
|
||
}
|
||
}
|
||
}
|
||
|
||
private struct RootView: View {
|
||
@EnvironmentObject private var router: AppRouter
|
||
@Environment(\.dependencies) private var dependencies
|
||
|
||
var body: some View {
|
||
NavigationStack(path: $router.path) {
|
||
Group {
|
||
if router.isAuthenticated {
|
||
MainTabView()
|
||
} else {
|
||
AuthView(viewModel: AuthViewModel(authService: dependencies.authService, keychain: dependencies.keychain))
|
||
}
|
||
}
|
||
.navigationDestination(for: AppRouter.Route.self) { route in
|
||
switch route {
|
||
case .category(let name):
|
||
CategoryListView(viewModel: CategoryViewModel(categoryName: name))
|
||
case .detail(let book):
|
||
BookDetailView(viewModel: BookDetailViewModel(book: book))
|
||
}
|
||
}
|
||
}
|
||
.task {
|
||
await bootstrapSession()
|
||
}
|
||
}
|
||
|
||
@MainActor
|
||
private func bootstrapSession() async {
|
||
let token = dependencies.keychain.read(for: AuthViewModel.tokenKey)
|
||
guard let token, !token.isEmpty else {
|
||
router.isAuthenticated = false
|
||
return
|
||
}
|
||
|
||
do {
|
||
_ = try await dependencies.authService.profile(token: token)
|
||
router.isAuthenticated = true
|
||
} catch {
|
||
router.isAuthenticated = false
|
||
}
|
||
}
|
||
}
|
||
|
||
private struct MainTabView: View {
|
||
@EnvironmentObject private var router: AppRouter
|
||
@Environment(\.dependencies) private var dependencies
|
||
|
||
var body: some View {
|
||
TabView(selection: $router.selectedTab) {
|
||
HomeView(viewModel: HomeViewModel())
|
||
.tabItem {
|
||
Label("Library", systemImage: "books.vertical")
|
||
}
|
||
.tag(AppRouter.Tab.library)
|
||
|
||
AddBooksView(viewModel: AddBooksViewModel(booksService: dependencies.booksService))
|
||
.tabItem {
|
||
Label("Discover", systemImage: "sparkle.magnifyingglass")
|
||
}
|
||
.tag(AppRouter.Tab.discover)
|
||
|
||
StatsPlaceholderView()
|
||
.tabItem {
|
||
Label("Stats", systemImage: "chart.line.uptrend.xyaxis")
|
||
}
|
||
.tag(AppRouter.Tab.stats)
|
||
|
||
ProfilePlaceholderView()
|
||
.tabItem {
|
||
Label("Profile", systemImage: "person.crop.circle")
|
||
}
|
||
.tag(AppRouter.Tab.profile)
|
||
}
|
||
}
|
||
}
|
||
|
||
private struct StatsPlaceholderView: View {
|
||
var body: some View {
|
||
ContentUnavailableView {
|
||
Label("Stats", systemImage: "chart.bar.xaxis")
|
||
} description: {
|
||
Text("Reading analytics yakında eklenecek.")
|
||
}
|
||
}
|
||
}
|
||
|
||
private struct ProfilePlaceholderView: View {
|
||
@EnvironmentObject private var router: AppRouter
|
||
@Environment(\.dependencies) private var dependencies
|
||
|
||
var body: some View {
|
||
NavigationStack {
|
||
List {
|
||
Section("Session") {
|
||
Button("Logout", role: .destructive) {
|
||
_ = dependencies.keychain.delete(for: AuthViewModel.tokenKey)
|
||
router.isAuthenticated = false
|
||
router.resetToHome()
|
||
}
|
||
}
|
||
}
|
||
.navigationTitle("Profile")
|
||
}
|
||
}
|
||
}
|