Channels search, add SDWebImage framework

This commit is contained in:
Arkadiusz Fal
2021-10-22 01:29:10 +02:00
parent bb8a8dee05
commit 0e54cbcad0
35 changed files with 859 additions and 431 deletions

View File

@@ -0,0 +1,102 @@
import Defaults
import Siesta
import SwiftUI
final class SearchModel: ObservableObject {
@Published var store = Store<[ContentItem]>()
var accounts = AccountsModel()
@Published var query = SearchQuery()
@Published var queryText = ""
@Published var querySuggestions = Store<[String]>()
private var previousResource: Resource?
private var resource: Resource!
var isLoading: Bool {
resource?.isLoading ?? false
}
func changeQuery(_ changeHandler: @escaping (SearchQuery) -> Void = { _ in }) {
changeHandler(query)
let newResource = accounts.api.search(query)
guard newResource != previousResource else {
return
}
previousResource?.removeObservers(ownedBy: store)
previousResource = newResource
resource = newResource
resource.addObserver(store)
if !query.isEmpty {
loadResourceIfNeededAndReplaceStore()
}
}
func resetQuery(_ query: SearchQuery = SearchQuery()) {
self.query = query
let newResource = accounts.api.search(query)
guard newResource != previousResource else {
return
}
store.replace([])
previousResource?.removeObservers(ownedBy: store)
previousResource = newResource
resource = newResource
resource.addObserver(store)
if !query.isEmpty {
loadResourceIfNeededAndReplaceStore()
}
}
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)
}
}
} else {
replace(store.collection, for: currentResource)
}
}
func replace(_ videos: [ContentItem], for resource: Resource) {
if self.resource == resource {
store = Store<[ContentItem]>(videos)
}
}
private var suggestionsDebounceTimer: Timer?
func loadSuggestions(_ query: String) {
suggestionsDebounceTimer?.invalidate()
suggestionsDebounceTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
let resource = self.accounts.api.searchSuggestions(query: query)
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)
}
}
} else {
self.querySuggestions = Store<[String]>(self.querySuggestions.collection)
}
}
}
}

View File

@@ -0,0 +1,77 @@
import Defaults
import Foundation
final class SearchQuery: ObservableObject {
enum Date: String, CaseIterable, Identifiable, DefaultsSerializable {
case any, hour, today, week, month, year
var id: SearchQuery.Date.RawValue {
rawValue
}
var name: String {
rawValue.capitalized
}
}
enum Duration: String, CaseIterable, Identifiable, DefaultsSerializable {
case any, short, long
var id: SearchQuery.Duration.RawValue {
rawValue
}
var name: String {
rawValue.capitalized
}
}
enum SortOrder: String, CaseIterable, Identifiable, DefaultsSerializable {
case relevance, rating, uploadDate, viewCount
var id: SearchQuery.SortOrder.RawValue {
rawValue
}
var name: String {
switch self {
case .uploadDate:
return "Date"
case .viewCount:
return "Views"
default:
return rawValue.capitalized
}
}
var parameter: String {
switch self {
case .uploadDate:
return "upload_date"
case .viewCount:
return "view_count"
default:
return rawValue
}
}
}
@Published var query: String
@Published var sortBy: SearchQuery.SortOrder = .relevance
@Published var date: SearchQuery.Date? = .month
@Published var duration: SearchQuery.Duration?
@Published var page = 1
init(query: String = "", page: Int = 1, sortBy: SearchQuery.SortOrder = .relevance, date: SearchQuery.Date? = nil, duration: SearchQuery.Duration? = nil) {
self.query = query
self.page = page
self.sortBy = sortBy
self.date = date
self.duration = duration
}
var isEmpty: Bool {
query.isEmpty
}
}