feat: ios mobil arayüz tasarımı
This commit is contained in:
53
ios/Bookibra/App/AppRouter.swift
Normal file
53
ios/Bookibra/App/AppRouter.swift
Normal file
@@ -0,0 +1,53 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
final class AppRouter: ObservableObject {
|
||||
enum Route: Hashable {
|
||||
case addBooks
|
||||
case category(name: String)
|
||||
case detail(BookRemote)
|
||||
}
|
||||
|
||||
@Published var isAuthenticated = false
|
||||
@Published var path: [Route] = []
|
||||
|
||||
func resetToHome() {
|
||||
path.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
struct AppDependencies {
|
||||
let apiClient: APIClientProtocol
|
||||
let authService: AuthServiceProtocol
|
||||
let booksService: BooksServiceProtocol
|
||||
let keychain: KeychainStoreProtocol
|
||||
let imageCache: ImageCacheProtocol
|
||||
|
||||
static func live() -> AppDependencies {
|
||||
let config = URLSessionConfiguration.default
|
||||
config.waitsForConnectivity = false
|
||||
config.timeoutIntervalForRequest = 8
|
||||
config.timeoutIntervalForResource = 15
|
||||
let session = URLSession(configuration: config)
|
||||
let client = APIClient(baseURL: Bundle.main.apiBaseURL, session: session)
|
||||
return AppDependencies(
|
||||
apiClient: client,
|
||||
authService: AuthService(client: client),
|
||||
booksService: BooksService(client: client),
|
||||
keychain: KeychainStore(),
|
||||
imageCache: ImageCache.shared
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private struct DependenciesKey: EnvironmentKey {
|
||||
static let defaultValue = AppDependencies.live()
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
var dependencies: AppDependencies {
|
||||
get { self[DependenciesKey.self] }
|
||||
set { self[DependenciesKey.self] = newValue }
|
||||
}
|
||||
}
|
||||
72
ios/Bookibra/App/BookibraApp.swift
Normal file
72
ios/Bookibra/App/BookibraApp.swift
Normal file
@@ -0,0 +1,72 @@
|
||||
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 {
|
||||
HomeView(viewModel: HomeViewModel())
|
||||
} else {
|
||||
AuthView(viewModel: AuthViewModel(authService: dependencies.authService, keychain: dependencies.keychain))
|
||||
}
|
||||
}
|
||||
.navigationDestination(for: AppRouter.Route.self) { route in
|
||||
switch route {
|
||||
case .addBooks:
|
||||
AddBooksView(viewModel: AddBooksViewModel(booksService: dependencies.booksService))
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user