diff --git a/Music/ViewModels/LibraryViewModel.swift b/Music/ViewModels/LibraryViewModel.swift new file mode 100644 index 0000000..aa705ff --- /dev/null +++ b/Music/ViewModels/LibraryViewModel.swift @@ -0,0 +1,63 @@ +import Foundation +import Observation +import GRDB + +@Observable +final class LibraryViewModel { + var tracks: [Track] = [] + var searchText = "" + var sortColumn = "title" + var sortAscending = true + var trackCount = 0 + + private let db: DatabaseService + private var cancellable: AnyDatabaseCancellable? + private var searchTask: Task? + + init(db: DatabaseService) { + self.db = db + updateQuery() + } + + func search(_ text: String) { + searchText = text + searchTask?.cancel() + searchTask = Task { @MainActor [weak self] in + try? await Task.sleep(for: .milliseconds(150)) + guard !Task.isCancelled else { return } + self?.updateQuery() + } + } + + func sort(by column: String) { + if sortColumn == column { + sortAscending.toggle() + } else { + sortColumn = column + sortAscending = true + } + updateQuery() + } + + private func updateQuery() { + cancellable?.cancel() + let search = searchText + let col = sortColumn + let asc = sortAscending + + let observation = ValueObservation.tracking { [db] dbAccess in + try db.fetchTracks(db: dbAccess, search: search, sortColumn: col, ascending: asc) + } + + cancellable = observation.start( + in: db.dbPool, + onError: { error in + print("Library observation error: \(error)") + }, + onChange: { [weak self] tracks in + self?.tracks = tracks + self?.trackCount = tracks.count + } + ) + } +}