- API uç noktasını yeni IP adresine güncelle - Docker yapılandırmasında node_modules için adlandırılmış volume ekle - Arama işlemlerinde iptal durumlarını yoksay ve hata mesajı gösterme - NetworkErrorView'da wifi ikonunu kaldır
106 lines
3.0 KiB
Swift
106 lines
3.0 KiB
Swift
import Foundation
|
|
|
|
@MainActor
|
|
final class AddBooksViewModel: ObservableObject {
|
|
enum Mode: String, CaseIterable {
|
|
case title
|
|
case scan
|
|
case filter
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .title: return String(localized: "add.searchByTitle")
|
|
case .scan: return String(localized: "add.scanBarcode")
|
|
case .filter: return String(localized: "add.filter")
|
|
}
|
|
}
|
|
}
|
|
|
|
@Published var mode: Mode = .title
|
|
@Published var titleQuery = ""
|
|
@Published var filterTitle = ""
|
|
@Published var filterYear = ""
|
|
@Published var results: [BookRemote] = []
|
|
@Published var isLoading = false
|
|
@Published var errorMessage: String?
|
|
|
|
private var debounceTask: Task<Void, Never>?
|
|
private let booksService: BooksServiceProtocol
|
|
|
|
init(booksService: BooksServiceProtocol) {
|
|
self.booksService = booksService
|
|
}
|
|
|
|
func titleChanged() {
|
|
debounceTask?.cancel()
|
|
|
|
let query = titleQuery.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard query.count >= 2 else {
|
|
results = []
|
|
return
|
|
}
|
|
|
|
debounceTask = Task {
|
|
try? await Task.sleep(for: .milliseconds(400))
|
|
await searchByTitle(query)
|
|
}
|
|
}
|
|
|
|
func searchByTitle(_ query: String? = nil) async {
|
|
let value = query ?? titleQuery
|
|
guard !value.isEmpty else { return }
|
|
isLoading = true
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
results = try await booksService.searchByTitle(value, locales: "tr,en")
|
|
errorMessage = nil
|
|
} catch {
|
|
guard !isIgnorable(error) else { return }
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
}
|
|
|
|
func searchByISBN(_ isbn: String) async {
|
|
guard !isbn.isEmpty else { return }
|
|
isLoading = true
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
results = try await booksService.searchByISBN(isbn, locales: "tr,en")
|
|
errorMessage = nil
|
|
} catch {
|
|
guard !isIgnorable(error) else { return }
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
}
|
|
|
|
func applyFilter() async {
|
|
guard !filterTitle.isEmpty, !filterYear.isEmpty else { return }
|
|
isLoading = true
|
|
defer { isLoading = false }
|
|
|
|
do {
|
|
results = try await booksService.filter(title: filterTitle, year: filterYear, locales: "tr,en")
|
|
errorMessage = nil
|
|
} catch {
|
|
guard !isIgnorable(error) else { return }
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
}
|
|
|
|
private func isIgnorable(_ error: Error) -> Bool {
|
|
if error is CancellationError {
|
|
return true
|
|
}
|
|
|
|
let nsError = error as NSError
|
|
if nsError.domain == NSURLErrorDomain, nsError.code == NSURLErrorCancelled {
|
|
return true
|
|
}
|
|
|
|
let message = error.localizedDescription.lowercased()
|
|
return message.contains("cancelled") || message.contains("vazgeç")
|
|
}
|
|
}
|