yattee/Model/Search/SearchModel.swift

112 lines
3.1 KiB
Swift
Raw Normal View History

2021-07-29 22:34:13 +00:00
import Defaults
import Siesta
import SwiftUI
2021-09-25 08:18:22 +00:00
final class SearchModel: ObservableObject {
@Published var store = Store<[ContentItem]>()
2021-09-13 20:41:16 +00:00
2021-10-16 22:48:58 +00:00
var accounts = AccountsModel()
2021-09-25 08:18:22 +00:00
@Published var query = SearchQuery()
2021-09-19 12:42:47 +00:00
@Published var queryText = ""
2021-09-13 20:41:16 +00:00
@Published var querySuggestions = Store<[String]>()
2021-12-06 18:12:33 +00:00
@Published var suggestionsText = ""
2021-09-13 20:41:16 +00:00
2021-11-28 14:37:55 +00:00
@Published var fieldIsFocused = false
2021-07-29 22:34:13 +00:00
private var previousResource: Resource?
private var resource: Resource!
var isLoading: Bool {
2021-09-25 12:17:58 +00:00
resource?.isLoading ?? false
2021-09-13 20:41:16 +00:00
}
2021-07-29 22:34:13 +00:00
func changeQuery(_ changeHandler: @escaping (SearchQuery) -> Void = { _ in }) {
changeHandler(query)
2021-10-20 22:21:50 +00:00
let newResource = accounts.api.search(query)
2021-07-29 22:34:13 +00:00
guard newResource != previousResource else {
return
}
previousResource?.removeObservers(ownedBy: store)
previousResource = newResource
2021-09-19 11:06:54 +00:00
resource = newResource
resource.addObserver(store)
if !query.isEmpty {
loadResourceIfNeededAndReplaceStore()
}
2021-09-19 11:06:54 +00:00
}
func resetQuery(_ query: SearchQuery = SearchQuery()) {
2021-09-19 11:06:54 +00:00
self.query = query
2021-10-20 22:21:50 +00:00
let newResource = accounts.api.search(query)
2021-09-19 11:06:54 +00:00
guard newResource != previousResource else {
return
}
store.replace([])
previousResource?.removeObservers(ownedBy: store)
previousResource = newResource
2021-07-29 22:34:13 +00:00
resource = newResource
resource.addObserver(store)
if !query.isEmpty {
loadResourceIfNeededAndReplaceStore()
}
2021-07-29 22:34:13 +00:00
}
func loadResourceIfNeededAndReplaceStore() {
let currentResource = resource!
if let request = resource.loadIfNeeded() {
request.onSuccess { response in
if let results: [ContentItem] = response.typedContent() {
self.replace(results, for: currentResource)
2021-07-29 22:34:13 +00:00
}
}
} else {
replace(store.collection, for: currentResource)
}
}
func replace(_ videos: [ContentItem], for resource: Resource) {
2021-07-29 22:34:13 +00:00
if self.resource == resource {
store = Store<[ContentItem]>(videos)
2021-07-29 22:34:13 +00:00
}
}
2021-09-25 12:17:58 +00:00
private var suggestionsDebounceTimer: Timer?
func loadSuggestions(_ query: String) {
2021-11-28 14:37:55 +00:00
guard !query.isEmpty else {
return
}
2021-09-25 12:17:58 +00:00
suggestionsDebounceTimer?.invalidate()
2021-12-06 18:12:33 +00:00
suggestionsDebounceTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { _ in
2021-10-20 22:21:50 +00:00
let resource = self.accounts.api.searchSuggestions(query: query)
2021-09-25 12:17:58 +00:00
resource.addObserver(self.querySuggestions)
resource.loadIfNeeded()
if let request = resource.loadIfNeeded() {
request.onSuccess { response in
if let suggestions: [String] = response.typedContent() {
self.querySuggestions = Store<[String]>(suggestions)
}
2021-12-06 18:12:33 +00:00
self.suggestionsText = query
2021-09-25 12:17:58 +00:00
}
} else {
self.querySuggestions = Store<[String]>(self.querySuggestions.collection)
2021-12-06 18:12:33 +00:00
self.suggestionsText = query
2021-09-25 12:17:58 +00:00
}
}
}
2021-07-29 22:34:13 +00:00
}