Kurdtvs-Live-Kurdish-TV-Kur.../Mastodon/Scene/Search/Search/SearchViewModel.swift

145 lines
6.2 KiB
Swift
Raw Normal View History

2021-03-31 08:28:40 +02:00
//
// SearchViewModel.swift
// Mastodon
//
// Created by sxiaojian on 2021/3/31.
//
import Combine
2021-04-07 13:49:33 +02:00
import CoreData
import CoreDataStack
2021-04-01 14:54:57 +02:00
import Foundation
2021-04-06 09:25:04 +02:00
import GameplayKit
2021-03-31 08:48:34 +02:00
import MastodonSDK
import OSLog
2021-04-01 14:54:57 +02:00
import UIKit
2021-03-31 08:28:40 +02:00
2021-04-07 13:49:33 +02:00
final class SearchViewModel: NSObject {
2021-03-31 08:28:40 +02:00
var disposeBag = Set<AnyCancellable>()
2021-03-31 08:48:34 +02:00
// input
2021-03-31 13:29:54 +02:00
let context: AppContext
weak var coordinator: SceneCoordinator!
2021-03-31 13:29:54 +02:00
2021-04-09 13:39:35 +02:00
let currentMastodonUser = CurrentValueSubject<MastodonUser?, Never>(nil)
let viewDidAppeared = PassthroughSubject<Void, Never>()
2021-04-09 13:39:35 +02:00
2021-03-31 13:29:54 +02:00
// output
2021-07-15 14:28:36 +02:00
// var recommendHashTags = [Mastodon.Entity.Tag]()
var recommendAccounts = [NSManagedObjectID]()
2021-04-21 11:58:56 +02:00
var recommendAccountsFallback = PassthroughSubject<Void, Never>()
2021-03-31 08:28:40 +02:00
2021-04-07 15:01:32 +02:00
var hashtagDiffableDataSource: UICollectionViewDiffableDataSource<RecommendHashTagSection, Mastodon.Entity.Tag>?
var accountDiffableDataSource: UICollectionViewDiffableDataSource<RecommendAccountSection, NSManagedObjectID>?
2021-04-06 09:25:04 +02:00
init(context: AppContext, coordinator: SceneCoordinator) {
self.coordinator = coordinator
2021-04-01 14:54:57 +02:00
self.context = context
2021-04-07 13:49:33 +02:00
super.init()
Publishers.CombineLatest(
context.authenticationService.activeMastodonAuthenticationBox,
viewDidAppeared
)
.compactMap { activeMastodonAuthenticationBox, _ -> MastodonAuthenticationBox? in
return activeMastodonAuthenticationBox
}
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)
.flatMap { box in
context.apiService.recommendTrends(domain: box.domain, query: nil)
.map { response in Result<Mastodon.Response.Content<[Mastodon.Entity.Tag]>, Error> { response } }
.catch { error in Just(Result<Mastodon.Response.Content<[Mastodon.Entity.Tag]>, Error> { throw error }) }
.eraseToAnyPublisher()
}
.receive(on: RunLoop.main)
.sink { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let response):
guard let dataSource = self.hashtagDiffableDataSource else { return }
var snapshot = NSDiffableDataSourceSnapshot<RecommendHashTagSection, Mastodon.Entity.Tag>()
snapshot.appendSections([.main])
snapshot.appendItems(response.value, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: false, completion: nil)
case .failure(let error):
break
2021-04-06 09:25:04 +02:00
}
}
.store(in: &disposeBag)
Publishers.CombineLatest(
context.authenticationService.activeMastodonAuthenticationBox,
viewDidAppeared
)
.compactMap { activeMastodonAuthenticationBox, _ -> MastodonAuthenticationBox? in
return activeMastodonAuthenticationBox
}
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)
.flatMap { box -> AnyPublisher<Result<[Mastodon.Entity.Account.ID], Error>, Never> in
context.apiService.suggestionAccountV2(domain: box.domain, query: nil, mastodonAuthenticationBox: box)
.map { response in Result<[Mastodon.Entity.Account.ID], Error> { response.value.map { $0.account.id } } }
.catch { error -> AnyPublisher<Result<[Mastodon.Entity.Account.ID], Error>, Never> in
if let apiError = error as? Mastodon.API.Error, apiError.httpResponseStatus == .notFound {
return context.apiService.suggestionAccount(domain: box.domain, query: nil, mastodonAuthenticationBox: box)
.map { response in Result<[Mastodon.Entity.Account.ID], Error> { response.value.map { $0.id } } }
.catch { error in Just(Result<[Mastodon.Entity.Account.ID], Error> { throw error }) }
.eraseToAnyPublisher()
} else {
return Just(Result<[Mastodon.Entity.Account.ID], Error> { throw error })
.eraseToAnyPublisher()
2021-04-21 11:58:56 +02:00
}
}
.eraseToAnyPublisher()
}
.receive(on: RunLoop.main)
.sink { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let userIDs):
self.receiveAccounts(ids: userIDs)
case .failure(let error):
break
2021-04-21 11:58:56 +02:00
}
}
.store(in: &disposeBag)
2021-04-01 05:49:38 +02:00
}
2021-04-07 13:49:33 +02:00
func receiveAccounts(ids: [Mastodon.Entity.Account.ID]) {
2021-04-21 11:58:56 +02:00
guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
return
}
let userFetchRequest = MastodonUser.sortedFetchRequest
userFetchRequest.predicate = MastodonUser.predicate(domain: activeMastodonAuthenticationBox.domain, ids: ids)
let mastodonUsers: [MastodonUser]? = {
let userFetchRequest = MastodonUser.sortedFetchRequest
userFetchRequest.predicate = MastodonUser.predicate(domain: activeMastodonAuthenticationBox.domain, ids: ids)
userFetchRequest.returnsObjectsAsFaults = false
do {
return try self.context.managedObjectContext.fetch(userFetchRequest)
} catch {
assertionFailure(error.localizedDescription)
return nil
}
}()
2021-06-30 08:23:26 +02:00
guard let users = mastodonUsers else { return }
let objectIDs: [NSManagedObjectID] = users
.compactMap { object in
ids.firstIndex(of: object.id).map { index in (index, object) }
2021-04-22 04:29:53 +02:00
}
.sorted { $0.0 < $1.0 }
.map { $0.1.objectID }
// append at front
let newObjectIDs = objectIDs.filter { !self.recommendAccounts.contains($0) }
self.recommendAccounts = newObjectIDs + self.recommendAccounts
guard let dataSource = self.accountDiffableDataSource else { return }
var snapshot = NSDiffableDataSourceSnapshot<RecommendAccountSection, NSManagedObjectID>()
snapshot.appendSections([.main])
snapshot.appendItems(self.recommendAccounts, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: false, completion: nil)
2021-04-21 11:58:56 +02:00
}
2021-03-31 08:28:40 +02:00
}