Added infinite scrolling to BookmarksView with dynamic loading of bookmarks on
This commit is contained in:
parent
789d581705
commit
601f81dc9f
@ -174,7 +174,10 @@
|
||||
},
|
||||
"subpath" : "Yams"
|
||||
}
|
||||
],
|
||||
"prebuilts" : [
|
||||
|
||||
]
|
||||
},
|
||||
"version" : 6
|
||||
"version" : 7
|
||||
}
|
||||
@ -10,7 +10,7 @@ import Foundation
|
||||
protocol PAPI {
|
||||
var tokenProvider: TokenProvider { get }
|
||||
func login(username: String, password: String) async throws -> UserDto
|
||||
func getBookmarks(state: BookmarkState?) async throws -> [BookmarkDto]
|
||||
func getBookmarks(state: BookmarkState?, limit: Int?, offset: Int?, search: String?) async throws -> [BookmarkDto]
|
||||
func getBookmark(id: String) async throws -> BookmarkDetailDto
|
||||
func getBookmarkArticle(id: String) async throws -> String
|
||||
func createBookmark(createRequest: CreateBookmarkRequestDto) async throws -> CreateBookmarkResponseDto
|
||||
@ -131,21 +131,39 @@ class API: PAPI {
|
||||
return userDto
|
||||
}
|
||||
|
||||
func getBookmarks(state: BookmarkState? = nil) async throws -> [BookmarkDto] {
|
||||
func getBookmarks(state: BookmarkState? = nil, limit: Int? = nil, offset: Int? = nil, search: String? = nil) async throws -> [BookmarkDto] {
|
||||
var endpoint = "/api/bookmarks"
|
||||
var queryItems: [URLQueryItem] = []
|
||||
|
||||
// Query-Parameter basierend auf State hinzufügen
|
||||
if let state = state {
|
||||
switch state {
|
||||
case .unread:
|
||||
endpoint += "?is_archived=false&is_marked=false"
|
||||
queryItems.append(URLQueryItem(name: "is_archived", value: "false"))
|
||||
queryItems.append(URLQueryItem(name: "is_marked", value: "false"))
|
||||
case .favorite:
|
||||
endpoint += "?is_marked=true"
|
||||
queryItems.append(URLQueryItem(name: "is_marked", value: "true"))
|
||||
case .archived:
|
||||
endpoint += "?is_archived=true"
|
||||
queryItems.append(URLQueryItem(name: "is_archived", value: "true"))
|
||||
}
|
||||
}
|
||||
|
||||
if let limit = limit {
|
||||
queryItems.append(URLQueryItem(name: "limit", value: "\(limit)"))
|
||||
}
|
||||
if let offset = offset {
|
||||
queryItems.append(URLQueryItem(name: "offset", value: "\(offset)"))
|
||||
}
|
||||
|
||||
if let search = search {
|
||||
queryItems.append(URLQueryItem(name: "search", value: search))
|
||||
}
|
||||
|
||||
if !queryItems.isEmpty {
|
||||
let queryString = queryItems.map { "\($0.name)=\($0.value ?? "")" }.joined(separator: "&")
|
||||
endpoint += "?\(queryString)"
|
||||
}
|
||||
|
||||
return try await makeJSONRequest(
|
||||
endpoint: endpoint,
|
||||
responseType: [BookmarkDto].self
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
protocol PBookmarksRepository {
|
||||
func fetchBookmarks(state: BookmarkState?) async throws -> [Bookmark]
|
||||
func fetchBookmarks(state: BookmarkState?, limit: Int?, offset: Int?, search: String?) async throws -> [Bookmark]
|
||||
func fetchBookmark(id: String) async throws -> BookmarkDetail
|
||||
func fetchBookmarkArticle(id: String) async throws -> String
|
||||
func createBookmark(createRequest: CreateBookmarkRequest) async throws -> String
|
||||
@ -16,8 +16,8 @@ class BookmarksRepository: PBookmarksRepository {
|
||||
self.api = api
|
||||
}
|
||||
|
||||
func fetchBookmarks(state: BookmarkState? = nil) async throws -> [Bookmark] {
|
||||
let bookmarkDtos = try await api.getBookmarks(state: state)
|
||||
func fetchBookmarks(state: BookmarkState? = nil, limit: Int? = nil, offset: Int? = nil, search: String? = nil) async throws -> [Bookmark] {
|
||||
let bookmarkDtos = try await api.getBookmarks(state: state, limit: limit, offset: offset, search: search)
|
||||
return bookmarkDtos.map { $0.toDomain() }
|
||||
}
|
||||
|
||||
|
||||
@ -7,8 +7,8 @@ class GetBookmarksUseCase {
|
||||
self.repository = repository
|
||||
}
|
||||
|
||||
func execute(state: BookmarkState? = nil) async throws -> [Bookmark] {
|
||||
let allBookmarks = try await repository.fetchBookmarks(state: state)
|
||||
func execute(state: BookmarkState? = nil, limit: Int? = nil, offset: Int? = nil, search: String? = nil) async throws -> [Bookmark] {
|
||||
let allBookmarks = try await repository.fetchBookmarks(state: state, limit: limit, offset: offset, search: search)
|
||||
|
||||
// Fallback-Filterung auf Client-Seite falls API keine Query-Parameter unterstützt
|
||||
if let state = state {
|
||||
|
||||
@ -40,6 +40,13 @@ struct BookmarksView: View {
|
||||
}
|
||||
}
|
||||
)
|
||||
.onAppear {
|
||||
if bookmark.id == viewModel.bookmarks.last?.id {
|
||||
Task {
|
||||
await viewModel.loadMoreBookmarks()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
|
||||
@ -60,6 +67,7 @@ struct BookmarksView: View {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// FAB Button - nur bei "Ungelesen" anzeigen
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
@Observable
|
||||
class BookmarksViewModel {
|
||||
@ -18,6 +19,11 @@ class BookmarksViewModel {
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
// Pagination-Variablen
|
||||
private var limit = 20
|
||||
private var offset = 0
|
||||
private var hasMoreData = true
|
||||
|
||||
init() {
|
||||
setupNotificationObserver()
|
||||
}
|
||||
@ -52,12 +58,35 @@ class BookmarksViewModel {
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
currentState = state
|
||||
offset = 0 // Offset zurücksetzen
|
||||
hasMoreData = true // Pagination zurücksetzen
|
||||
|
||||
do {
|
||||
bookmarks = try await getBooksmarksUseCase.execute(state: state)
|
||||
let newBookmarks = try await getBooksmarksUseCase.execute(state: state, limit: limit, offset: offset)
|
||||
bookmarks = newBookmarks
|
||||
hasMoreData = newBookmarks.count == limit // Prüfen, ob weitere Daten verfügbar sind
|
||||
} catch {
|
||||
errorMessage = "Fehler beim Laden der Bookmarks"
|
||||
bookmarks = []
|
||||
bookmarks = []
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func loadMoreBookmarks() async {
|
||||
guard !isLoading && hasMoreData else { return } // Verhindern, dass mehrfach geladen wird
|
||||
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
|
||||
do {
|
||||
offset += limit // Offset erhöhen
|
||||
let newBookmarks = try await getBooksmarksUseCase.execute(state: currentState, limit: limit, offset: offset)
|
||||
bookmarks.append(contentsOf: newBookmarks) // Neue Bookmarks hinzufügen
|
||||
hasMoreData = newBookmarks.count == limit // Prüfen, ob weitere Daten verfügbar sind
|
||||
} catch {
|
||||
errorMessage = "Fehler beim Nachladen der Bookmarks"
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
|
||||
7
readeck/UI/Bookmarks/File.swift
Normal file
7
readeck/UI/Bookmarks/File.swift
Normal file
@ -0,0 +1,7 @@
|
||||
//
|
||||
// File.swift
|
||||
// readeck
|
||||
//
|
||||
// Created by Ilyas Hallak on 25.06.25.
|
||||
//
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user