- Chapter navigation with auto-scroll to current chapter and end-of-chapter sleep timer - Opt-in listening history (local-only) with XML export and per-item quick menu - Bookmarks with server sync via Audiobookshelf API - Live MB counter during downloads via URLSessionDownloadTask delegate - In-progress downloads shown in "Heruntergeladen" with dimmed cover + ring overlay - Cover image cache (50 MB memory / 500 MB disk URLCache) - German/English localization (de.lproj, en.lproj) - Loading spinner now triggers immediately on view switch instead of waiting for the network Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
55 lines
1.4 KiB
Swift
55 lines
1.4 KiB
Swift
import SwiftUI
|
|
|
|
struct ContentView: View {
|
|
@Environment(AppState.self) private var app
|
|
#if os(iOS)
|
|
@State private var splashVisible = true
|
|
#endif
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
mainContent
|
|
#if os(iOS)
|
|
if splashVisible {
|
|
SplashView()
|
|
.zIndex(10)
|
|
.transition(.opacity.animation(.easeOut(duration: 0.55)))
|
|
}
|
|
#endif
|
|
}
|
|
.task { await boot() }
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var mainContent: some View {
|
|
Group {
|
|
if app.auth.isLoggedIn {
|
|
MainView()
|
|
} else {
|
|
LoginView()
|
|
}
|
|
}
|
|
.environment(\.locale, Locale(identifier: app.language))
|
|
#if os(iOS)
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
#else
|
|
.frame(minWidth: 900, minHeight: 600)
|
|
#endif
|
|
}
|
|
|
|
private func boot() async {
|
|
#if os(iOS)
|
|
// Run bootstrap and minimum splash time in parallel;
|
|
// dismiss splash only after BOTH complete.
|
|
await withTaskGroup(of: Void.self) { group in
|
|
group.addTask { await app.bootstrap() }
|
|
group.addTask { try? await Task.sleep(for: .seconds(1.2)) }
|
|
await group.waitForAll()
|
|
}
|
|
withAnimation { splashVisible = false }
|
|
#else
|
|
await app.bootstrap()
|
|
#endif
|
|
}
|
|
}
|