Files
vorleser/Vorleser/ContentView.swift

95 lines
2.9 KiB
Swift

import SwiftUI
struct ContentView: View {
@StateObject private var viewModel = LibraryViewModel()
@State private var selectedItem: BookItem?
var body: some View {
NavigationStack {
VStack(alignment: .leading, spacing: 16) {
header
if viewModel.items.isEmpty {
emptyState
} else {
bookList
}
Spacer()
}
.padding(20)
.navigationTitle("Vorleser")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Import EPUB") {
viewModel.isImporting = true
}
}
}
.sheet(isPresented: $viewModel.isImporting) {
DocumentPicker(onPick: { url in
viewModel.isImporting = false
viewModel.importPicked(url: url)
}, onCancel: {
viewModel.isImporting = false
})
}
.alert("Import failed", isPresented: .constant(viewModel.lastErrorMessage != nil), actions: {
Button("OK", role: .cancel) {
viewModel.lastErrorMessage = nil
}
}, message: {
Text(viewModel.lastErrorMessage ?? "")
})
}
}
private var header: some View {
VStack(alignment: .leading, spacing: 8) {
Text("Local EPUB reader")
.font(.title2.weight(.semibold))
Text("On-device, high-quality narration powered by CoreML.")
.foregroundStyle(.secondary)
}
}
private var emptyState: some View {
VStack(alignment: .leading, spacing: 12) {
Text("No books yet")
.font(.headline)
Text("Import an EPUB from Files or iCloud to start preparing narration.")
.foregroundStyle(.secondary)
Button("Import EPUB") {
viewModel.isImporting = true
}
.buttonStyle(.borderedProminent)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(16)
.background(.thinMaterial)
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
}
private var bookList: some View {
List(viewModel.items) { item in
NavigationLink(value: item) {
VStack(alignment: .leading, spacing: 4) {
Text(item.title)
.font(.headline)
Text(item.sourceURL.lastPathComponent)
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
.listStyle(.plain)
.navigationDestination(for: BookItem.self) { item in
ReaderView(item: item)
}
}
}
#Preview {
ContentView()
}