- Add BookmarkState enum with unread, favorite, and archived states - Extend API layer with query parameter filtering for bookmark states - Update Bookmark domain model to match complete API response schema - Implement BookmarkListView with card-based UI and preview images - Add BookmarkListViewModel with state management and error handling - Enhance BookmarkDetailView with meta information and WebView rendering - Create comprehensive DTO mapping for all bookmark fields - Add TabView with state-based bookmark filtering - Implement date formatting utilities for ISO8601 timestamps - Add progress indicators and pull-to-refresh functionality
84 lines
2.3 KiB
Swift
84 lines
2.3 KiB
Swift
import Foundation
|
|
|
|
@Observable
|
|
class BookmarkDetailViewModel {
|
|
private let getBookmarkUseCase: GetBookmarkUseCase
|
|
private let getBookmarkArticleUseCase: GetBookmarkArticleUseCase
|
|
|
|
var bookmarkDetail: BookmarkDetail = BookmarkDetail.empty
|
|
var articleContent: String = ""
|
|
var articleParagraphs: [String] = []
|
|
var bookmark: Bookmark? = nil
|
|
var isLoading = false
|
|
var isLoadingArticle = false
|
|
var errorMessage: String?
|
|
|
|
init() {
|
|
let factory = DefaultUseCaseFactory.shared
|
|
self.getBookmarkUseCase = factory.makeGetBookmarkUseCase()
|
|
self.getBookmarkArticleUseCase = factory.makeGetBookmarkArticleUseCase()
|
|
}
|
|
|
|
@MainActor
|
|
func loadBookmarkDetail(id: String) async {
|
|
isLoading = true
|
|
errorMessage = nil
|
|
|
|
do {
|
|
bookmarkDetail = try await getBookmarkUseCase.execute(id: id)
|
|
|
|
// Auch das vollständige Bookmark für readProgress laden
|
|
// (Falls GetBookmarkUseCase nur BookmarkDetail zurückgibt)
|
|
// Du könntest einen separaten UseCase für das vollständige Bookmark erstellen
|
|
|
|
} catch {
|
|
errorMessage = "Fehler beim Laden des Bookmarks"
|
|
}
|
|
|
|
isLoading = false
|
|
}
|
|
|
|
@MainActor
|
|
func loadArticleContent(id: String) async {
|
|
isLoadingArticle = true
|
|
|
|
do {
|
|
articleContent = try await getBookmarkArticleUseCase.execute(id: id)
|
|
processArticleContent()
|
|
} catch {
|
|
errorMessage = "Fehler beim Laden des Artikels"
|
|
}
|
|
|
|
isLoadingArticle = false
|
|
}
|
|
|
|
private func processArticleContent() {
|
|
// HTML in Paragraphen aufteilen
|
|
let paragraphs = articleContent
|
|
.components(separatedBy: .newlines)
|
|
.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }
|
|
|
|
articleParagraphs = paragraphs
|
|
}
|
|
}
|
|
|
|
extension BookmarkDetail {
|
|
static let empty = BookmarkDetail(
|
|
id: "",
|
|
title: "",
|
|
url: "",
|
|
description: "",
|
|
siteName: "",
|
|
authors: [],
|
|
created: "",
|
|
updated: "",
|
|
wordCount: 0,
|
|
readingTime: 0,
|
|
hasArticle: false,
|
|
isMarked: false,
|
|
isArchived: false,
|
|
thumbnailUrl: "",
|
|
imageUrl: ""
|
|
)
|
|
}
|