ReadKeep/readeck/UI/BookmarkDetail/BookmarkDetailView.swift

156 lines
5.6 KiB
Swift

import SwiftUI
import SafariServices
struct BookmarkDetailView: View {
let bookmarkId: String
@State private var viewModel = BookmarkDetailViewModel()
@State private var webViewHeight: CGFloat = 300
@State private var showingFontSettings = false
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
// Header mit Bild
if !viewModel.bookmarkDetail.imageUrl.isEmpty {
AsyncImage(url: URL(string: viewModel.bookmarkDetail.imageUrl)) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
} placeholder: {
Rectangle()
.fill(Color.gray.opacity(0.3))
.frame(height: 200)
}
.frame(height: 200)
.clipped()
}
VStack(alignment: .leading, spacing: 6) {
// Titel
Text(viewModel.bookmarkDetail.title)
.font(.largeTitle)
.fontWeight(.bold)
// Meta-Informationen
metaInfoSection
Divider()
// Artikel-Inhalt mit WebView
if let settings = viewModel.settings, !viewModel.articleContent.isEmpty {
WebView(htmlContent: viewModel.articleContent, settings: settings) { height in
webViewHeight = height
}
.frame(height: webViewHeight)
} else if viewModel.isLoadingArticle {
ProgressView("Lade Artikel...")
.frame(maxWidth: .infinity, alignment: .center)
.padding()
}
}
.padding()
}
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
showingFontSettings = true
}) {
Image(systemName: "textformat")
}
}
}
.sheet(isPresented: $showingFontSettings) {
NavigationView {
FontSettingsView()
.navigationTitle("Schrift-Einstellungen")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Fertig") {
showingFontSettings = false
}
}
}
}
}
.task {
await viewModel.loadBookmarkDetail(id: bookmarkId)
await viewModel.loadArticleContent(id: bookmarkId)
}
}
private var metaInfoSection: some View {
VStack(alignment: .leading, spacing: 8) {
if !viewModel.bookmarkDetail.authors.isEmpty {
HStack {
Image(systemName: "person")
Text(viewModel.bookmarkDetail.authors.joined(separator: ", "))
.font(.subheadline)
.foregroundColor(.secondary)
}
}
HStack {
Image(systemName: "calendar")
Text("Erstellt: \(formatDate(viewModel.bookmarkDetail.created))")
.font(.subheadline)
.foregroundColor(.secondary)
}
HStack {
Image(systemName: "textformat")
Text("\(viewModel.bookmarkDetail.wordCount ?? 0) Wörter • \(viewModel.bookmarkDetail.readingTime ?? 0) min Lesezeit")
.font(.subheadline)
.foregroundColor(.secondary)
}
HStack {
Image(systemName: "safari")
Button(action: {
SafariUtil.openInSafari(url: viewModel.bookmarkDetail.url)
}) {
Text("Original Seite öffnen")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
}
private func formatDate(_ dateString: String) -> String {
// Erstelle einen Formatter für das ISO8601-Format mit Millisekunden
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
// Fallback für Format ohne Millisekunden
let isoFormatterNoMillis = ISO8601DateFormatter()
isoFormatterNoMillis.formatOptions = [.withInternetDateTime]
// Versuche beide Formate
var date: Date?
if let parsedDate = isoFormatter.date(from: dateString) {
date = parsedDate
} else if let parsedDate = isoFormatterNoMillis.date(from: dateString) {
date = parsedDate
}
if let date = date {
let displayFormatter = DateFormatter()
displayFormatter.dateStyle = .medium
displayFormatter.timeStyle = .short
displayFormatter.locale = Locale(identifier: "de_DE")
return displayFormatter.string(from: date)
}
return dateString
}
}
#Preview {
NavigationView {
BookmarkDetailView(bookmarkId: "sample-id")
}
}