- API-Klasse mit allen CRUD-Operationen für Bookmarks - Login/Authentifizierung mit Bearer Token - Bookmarks abrufen (Liste und Details) - Artikel-Inhalt abrufen - DTO-Strukturen in separate Dateien aufgeteilt - UserDto für Authentifizierung - BookmarkDto für Bookmark-Listen - BookmarkDetailDto mit vollständigen Metadaten - MVVM-Architektur mit @Observable - SettingsViewModel für Anmeldung - BookmarksViewModel für Bookmark-Verwaltung - SwiftUI Views mit modernem Design - SettingsView mit Eingabefeldern und Validierung - BookmarksView mit Pull-to-Refresh und Leerzustand - MainTabView als Navigation - Use Case Pattern implementiert - LoginUseCase für Authentifizierung - GetBookmarksUseCase für Datenabfrage - DefaultUseCaseFactory für Dependency Injection - Fehlerbehandlung und Loading States - Protocol-basierte Architektur für bessere Testbarkeit
62 lines
1.9 KiB
Swift
62 lines
1.9 KiB
Swift
import SwiftUI
|
|
|
|
struct BookmarksView: View {
|
|
@State private var viewModel = BookmarksViewModel()
|
|
|
|
var body: some View {
|
|
NavigationView {
|
|
ZStack {
|
|
if viewModel.isLoading {
|
|
ProgressView()
|
|
} else {
|
|
List(viewModel.bookmarks, id: \.id) { bookmark in
|
|
BookmarkRow(bookmark: bookmark)
|
|
}
|
|
.refreshable {
|
|
await viewModel.loadBookmarks()
|
|
}
|
|
.overlay {
|
|
if viewModel.bookmarks.isEmpty && !viewModel.isLoading {
|
|
ContentUnavailableView(
|
|
"Keine Bookmarks",
|
|
systemImage: "bookmark",
|
|
description: Text("Es wurden noch keine Bookmarks gespeichert.")
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.navigationTitle("Meine Bookmarks")
|
|
.alert("Fehler", isPresented: .constant(viewModel.errorMessage != nil)) {
|
|
Button("OK", role: .cancel) { }
|
|
} message: {
|
|
Text(viewModel.errorMessage ?? "")
|
|
}
|
|
.task {
|
|
await viewModel.loadBookmarks()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unterkomponente für die Darstellung eines einzelnen Bookmarks
|
|
private struct BookmarkRow: View {
|
|
let bookmark: Bookmark
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
Text(bookmark.title)
|
|
.font(.headline)
|
|
|
|
Text(bookmark.url)
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
|
|
Text(bookmark.createdAt)
|
|
.font(.caption2)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
.padding(.vertical, 4)
|
|
}
|
|
}
|