mirror of
https://github.com/yattee/yattee.git
synced 2025-08-09 20:24:06 +00:00
Channels search, add SDWebImage framework
This commit is contained in:
102
Model/Search/SearchModel.swift
Normal file
102
Model/Search/SearchModel.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
Model/Search/SearchQuery.swift
Normal file
77
Model/Search/SearchQuery.swift
Normal 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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user