ReadKeep/readeck/UI/Bookmarks/BookmarksView.swift
Ilyas Hallak 98a914cb2e feat: Implementierung der Readeck API mit kompletter Architektur
- 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
2025-06-11 11:02:19 +02:00

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)
}
}