76 lines
2.1 KiB
Swift
76 lines
2.1 KiB
Swift
import Foundation
|
|
|
|
@Observable
|
|
final class SearchViewModel {
|
|
var query = ""
|
|
var results: [ContentItem] = []
|
|
var isSearching = false
|
|
var isLoadingMore = false
|
|
var currentPage = 1
|
|
var totalPages = 1
|
|
var error: String?
|
|
var hasSearched = false
|
|
|
|
@MainActor
|
|
func search() async {
|
|
let trimmed = query.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard !trimmed.isEmpty else { return }
|
|
|
|
isSearching = true
|
|
error = nil
|
|
hasSearched = true
|
|
currentPage = 1
|
|
totalPages = 1
|
|
results = []
|
|
|
|
do {
|
|
let html = try await APIClient.shared.fetchSearchPage(query: trimmed)
|
|
let items = try HTMLParser.parseContentList(html: html)
|
|
let pagination = try HTMLParser.parsePagination(html: html)
|
|
|
|
self.results = items
|
|
self.currentPage = pagination.current
|
|
self.totalPages = pagination.total
|
|
} catch is CancellationError {
|
|
} catch let error as URLError where error.code == .cancelled {
|
|
} catch {
|
|
self.error = error.localizedDescription
|
|
}
|
|
|
|
isSearching = false
|
|
}
|
|
|
|
@MainActor
|
|
func loadMore() async {
|
|
guard !isSearching, !isLoadingMore, currentPage < totalPages else { return }
|
|
isLoadingMore = true
|
|
|
|
let nextPage = currentPage + 1
|
|
do {
|
|
let html = try await APIClient.shared.fetchSearchPage(query: query, page: nextPage)
|
|
let items = try HTMLParser.parseContentList(html: html)
|
|
let pagination = try HTMLParser.parsePagination(html: html)
|
|
|
|
self.results.append(contentsOf: items)
|
|
self.currentPage = pagination.current
|
|
self.totalPages = pagination.total
|
|
} catch is CancellationError {
|
|
} catch let error as URLError where error.code == .cancelled {
|
|
} catch {
|
|
// 静默处理
|
|
}
|
|
|
|
isLoadingMore = false
|
|
}
|
|
|
|
@MainActor
|
|
func clear() {
|
|
query = ""
|
|
results = []
|
|
hasSearched = false
|
|
error = nil
|
|
currentPage = 1
|
|
totalPages = 1
|
|
}
|
|
}
|