fix: recommend request publisher logic issue
This commit is contained in:
parent
0dd2aaa068
commit
17bdce1321
|
@ -7,17 +7,17 @@
|
||||||
<key>AppShared.xcscheme_^#shared#^_</key>
|
<key>AppShared.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>26</integer>
|
<integer>19</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>21</integer>
|
<integer>20</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>2</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>22</integer>
|
<integer>18</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
|
|
@ -30,6 +30,23 @@ extension UserProviderFacade {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func toggleUserFollowRelationship(
|
||||||
|
provider: UserProvider,
|
||||||
|
mastodonUser: MastodonUser
|
||||||
|
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||||
|
// prepare authentication
|
||||||
|
guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||||
|
assertionFailure()
|
||||||
|
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
return _toggleUserFollowRelationship(
|
||||||
|
context: provider.context,
|
||||||
|
activeMastodonAuthenticationBox: activeMastodonAuthenticationBox,
|
||||||
|
mastodonUser: Just(mastodonUser).eraseToAnyPublisher()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private static func _toggleUserFollowRelationship(
|
private static func _toggleUserFollowRelationship(
|
||||||
context: AppContext,
|
context: AppContext,
|
||||||
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
|
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
|
||||||
|
@ -52,6 +69,22 @@ extension UserProviderFacade {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UserProviderFacade {
|
extension UserProviderFacade {
|
||||||
|
static func toggleUserBlockRelationship(
|
||||||
|
provider: UserProvider,
|
||||||
|
mastodonUser: MastodonUser
|
||||||
|
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||||
|
// prepare authentication
|
||||||
|
guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||||
|
assertionFailure()
|
||||||
|
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
return _toggleUserBlockRelationship(
|
||||||
|
context: provider.context,
|
||||||
|
activeMastodonAuthenticationBox: activeMastodonAuthenticationBox,
|
||||||
|
mastodonUser: Just(mastodonUser).eraseToAnyPublisher()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
static func toggleUserBlockRelationship(
|
static func toggleUserBlockRelationship(
|
||||||
provider: UserProvider,
|
provider: UserProvider,
|
||||||
cell: UITableViewCell?
|
cell: UITableViewCell?
|
||||||
|
@ -98,6 +131,23 @@ extension UserProviderFacade {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UserProviderFacade {
|
extension UserProviderFacade {
|
||||||
|
|
||||||
|
static func toggleUserMuteRelationship(
|
||||||
|
provider: UserProvider,
|
||||||
|
mastodonUser: MastodonUser
|
||||||
|
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||||
|
// prepare authentication
|
||||||
|
guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||||
|
assertionFailure()
|
||||||
|
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
return _toggleUserMuteRelationship(
|
||||||
|
context: provider.context,
|
||||||
|
activeMastodonAuthenticationBox: activeMastodonAuthenticationBox,
|
||||||
|
mastodonUser: Just(mastodonUser).eraseToAnyPublisher()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
static func toggleUserMuteRelationship(
|
static func toggleUserMuteRelationship(
|
||||||
provider: UserProvider,
|
provider: UserProvider,
|
||||||
cell: UITableViewCell?
|
cell: UITableViewCell?
|
||||||
|
|
|
@ -20,14 +20,13 @@ extension SearchViewController: UserProvider {
|
||||||
|
|
||||||
func mastodonUser() -> Future<MastodonUser?, Never> {
|
func mastodonUser() -> Future<MastodonUser?, Never> {
|
||||||
Future { promise in
|
Future { promise in
|
||||||
promise(.success(self.viewModel.mastodonUser.value))
|
promise(.success(nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegate {
|
extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegate {
|
||||||
func followButtonDidPressed(clickedUser: MastodonUser) {
|
func followButtonDidPressed(clickedUser: MastodonUser) {
|
||||||
viewModel.mastodonUser.value = clickedUser
|
|
||||||
guard let currentMastodonUser = viewModel.currentMastodonUser.value else {
|
guard let currentMastodonUser = viewModel.currentMastodonUser.value else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -36,17 +35,17 @@ extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegat
|
||||||
case .none:
|
case .none:
|
||||||
break
|
break
|
||||||
case .follow, .following:
|
case .follow, .following:
|
||||||
UserProviderFacade.toggleUserFollowRelationship(provider: self)
|
UserProviderFacade.toggleUserFollowRelationship(provider: self, mastodonUser: clickedUser)
|
||||||
.sink { _ in
|
.sink { _ in
|
||||||
|
// error handling
|
||||||
} receiveValue: { _ in
|
} receiveValue: { _ in
|
||||||
|
// success
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
case .pending:
|
case .pending:
|
||||||
break
|
break
|
||||||
case .muting:
|
case .muting:
|
||||||
guard let mastodonUser = viewModel.mastodonUser.value else { return }
|
let name = clickedUser.displayNameWithFallback
|
||||||
let name = mastodonUser.displayNameWithFallback
|
|
||||||
let alertController = UIAlertController(
|
let alertController = UIAlertController(
|
||||||
title: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.title,
|
title: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.title,
|
||||||
message: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.message(name),
|
message: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.message(name),
|
||||||
|
@ -54,7 +53,7 @@ extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegat
|
||||||
)
|
)
|
||||||
let unmuteAction = UIAlertAction(title: L10n.Common.Controls.Friendship.unmute, style: .default) { [weak self] _ in
|
let unmuteAction = UIAlertAction(title: L10n.Common.Controls.Friendship.unmute, style: .default) { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
UserProviderFacade.toggleUserMuteRelationship(provider: self, cell: nil)
|
UserProviderFacade.toggleUserMuteRelationship(provider: self, mastodonUser: clickedUser)
|
||||||
.sink { _ in
|
.sink { _ in
|
||||||
// do nothing
|
// do nothing
|
||||||
} receiveValue: { _ in
|
} receiveValue: { _ in
|
||||||
|
@ -67,8 +66,7 @@ extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegat
|
||||||
alertController.addAction(cancelAction)
|
alertController.addAction(cancelAction)
|
||||||
present(alertController, animated: true, completion: nil)
|
present(alertController, animated: true, completion: nil)
|
||||||
case .blocking:
|
case .blocking:
|
||||||
guard let mastodonUser = viewModel.mastodonUser.value else { return }
|
let name = clickedUser.displayNameWithFallback
|
||||||
let name = mastodonUser.displayNameWithFallback
|
|
||||||
let alertController = UIAlertController(
|
let alertController = UIAlertController(
|
||||||
title: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.title,
|
title: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.title,
|
||||||
message: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.message(name),
|
message: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockUsre.message(name),
|
||||||
|
@ -76,7 +74,7 @@ extension SearchViewController: SearchRecommendAccountsCollectionViewCellDelegat
|
||||||
)
|
)
|
||||||
let unblockAction = UIAlertAction(title: L10n.Common.Controls.Friendship.unblock, style: .default) { [weak self] _ in
|
let unblockAction = UIAlertAction(title: L10n.Common.Controls.Friendship.unblock, style: .default) { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
UserProviderFacade.toggleUserBlockRelationship(provider: self, cell: nil)
|
UserProviderFacade.toggleUserBlockRelationship(provider: self, mastodonUser: clickedUser)
|
||||||
.sink { _ in
|
.sink { _ in
|
||||||
// do nothing
|
// do nothing
|
||||||
} receiveValue: { _ in
|
} receiveValue: { _ in
|
||||||
|
|
|
@ -21,7 +21,6 @@ final class SearchViewModel: NSObject {
|
||||||
let context: AppContext
|
let context: AppContext
|
||||||
weak var coordinator: SceneCoordinator!
|
weak var coordinator: SceneCoordinator!
|
||||||
|
|
||||||
let mastodonUser = CurrentValueSubject<MastodonUser?, Never>(nil)
|
|
||||||
let currentMastodonUser = CurrentValueSubject<MastodonUser?, Never>(nil)
|
let currentMastodonUser = CurrentValueSubject<MastodonUser?, Never>(nil)
|
||||||
let viewDidAppeared = PassthroughSubject<Void, Never>()
|
let viewDidAppeared = PassthroughSubject<Void, Never>()
|
||||||
|
|
||||||
|
@ -33,7 +32,7 @@ final class SearchViewModel: NSObject {
|
||||||
|
|
||||||
let searchResult = CurrentValueSubject<Mastodon.Entity.SearchResult?, Never>(nil)
|
let searchResult = CurrentValueSubject<Mastodon.Entity.SearchResult?, Never>(nil)
|
||||||
|
|
||||||
var recommendHashTags = [Mastodon.Entity.Tag]()
|
// var recommendHashTags = [Mastodon.Entity.Tag]()
|
||||||
var recommendAccounts = [NSManagedObjectID]()
|
var recommendAccounts = [NSManagedObjectID]()
|
||||||
var recommendAccountsFallback = PassthroughSubject<Void, Never>()
|
var recommendAccountsFallback = PassthroughSubject<Void, Never>()
|
||||||
|
|
||||||
|
@ -62,10 +61,6 @@ final class SearchViewModel: NSObject {
|
||||||
self.context = context
|
self.context = context
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind active authentication
|
// bind active authentication
|
||||||
context.authenticationService.activeMastodonAuthentication
|
context.authenticationService.activeMastodonAuthentication
|
||||||
.sink { [weak self] activeMastodonAuthentication in
|
.sink { [weak self] activeMastodonAuthentication in
|
||||||
|
@ -86,23 +81,40 @@ final class SearchViewModel: NSObject {
|
||||||
.filter { text, _ in
|
.filter { text, _ in
|
||||||
!text.isEmpty
|
!text.isEmpty
|
||||||
}
|
}
|
||||||
.flatMap { (text, scope) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.SearchResult>, Error> in
|
.compactMap { (text, scope) -> AnyPublisher<Result<Mastodon.Response.Content<Mastodon.Entity.SearchResult>, Error>, Never>? in
|
||||||
|
guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return nil }
|
||||||
let query = Mastodon.API.V2.Search.Query(q: text,
|
let query = Mastodon.API.V2.Search.Query(
|
||||||
type: scope,
|
q: text,
|
||||||
accountID: nil,
|
type: scope,
|
||||||
maxID: nil,
|
accountID: nil,
|
||||||
minID: nil,
|
maxID: nil,
|
||||||
excludeUnreviewed: nil,
|
minID: nil,
|
||||||
resolve: nil,
|
excludeUnreviewed: nil,
|
||||||
limit: nil,
|
resolve: nil,
|
||||||
offset: nil,
|
limit: nil,
|
||||||
following: nil)
|
offset: nil,
|
||||||
return context.apiService.search(domain: activeMastodonAuthenticationBox.domain, query: query, mastodonAuthenticationBox: activeMastodonAuthenticationBox)
|
following: nil
|
||||||
|
)
|
||||||
|
return context.apiService.search(
|
||||||
|
domain: activeMastodonAuthenticationBox.domain,
|
||||||
|
query: query,
|
||||||
|
mastodonAuthenticationBox: activeMastodonAuthenticationBox
|
||||||
|
)
|
||||||
|
// .retry(3) // iOS 14.0 SDK may not works here. needs testing before add this
|
||||||
|
.map { response in Result<Mastodon.Response.Content<Mastodon.Entity.SearchResult>, Error> { response } }
|
||||||
|
.catch { error in Just(Result<Mastodon.Response.Content<Mastodon.Entity.SearchResult>, Error> { throw error }) }
|
||||||
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
.sink { _ in
|
.switchToLatest()
|
||||||
} receiveValue: { [weak self] result in
|
.sink { [weak self] result in
|
||||||
self?.searchResult.value = result.value
|
guard let self = self else { return }
|
||||||
|
switch result {
|
||||||
|
case .success(let response):
|
||||||
|
guard self.isSearching.value else { return }
|
||||||
|
self.searchResult.value = response.value
|
||||||
|
case .failure(let error):
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
@ -147,48 +159,71 @@ final class SearchViewModel: NSObject {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
viewDidAppeared
|
Publishers.CombineLatest(
|
||||||
.compactMap { _ in self.requestRecommendHashTags() }
|
context.authenticationService.activeMastodonAuthenticationBox,
|
||||||
.receive(on: RunLoop.main)
|
viewDidAppeared
|
||||||
.sink { [weak self] _ in
|
)
|
||||||
guard let self = self else { return }
|
.compactMap { activeMastodonAuthenticationBox, _ -> AuthenticationService.MastodonAuthenticationBox? in
|
||||||
if !self.recommendHashTags.isEmpty {
|
return activeMastodonAuthenticationBox
|
||||||
guard let dataSource = self.hashtagDiffableDataSource else { return }
|
}
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<RecommendHashTagSection, Mastodon.Entity.Tag>()
|
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)
|
||||||
snapshot.appendSections([.main])
|
.flatMap { box in
|
||||||
snapshot.appendItems(self.recommendHashTags, toSection: .main)
|
context.apiService.recommendTrends(domain: box.domain, query: nil)
|
||||||
dataSource.apply(snapshot, animatingDifferences: false, completion: 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 }) }
|
||||||
} receiveValue: { _ in
|
.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
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
}
|
||||||
viewDidAppeared
|
.store(in: &disposeBag)
|
||||||
.compactMap { _ in self.requestRecommendAccountsV2() }
|
|
||||||
.receive(on: RunLoop.main)
|
|
||||||
.sink { [weak self] _ in
|
|
||||||
guard let self = self else { return }
|
|
||||||
if !self.recommendAccounts.isEmpty {
|
|
||||||
self.applyDataSource()
|
|
||||||
}
|
|
||||||
} receiveValue: { _ in
|
|
||||||
}
|
|
||||||
.store(in: &disposeBag)
|
|
||||||
|
|
||||||
recommendAccountsFallback
|
Publishers.CombineLatest(
|
||||||
.receive(on: RunLoop.main)
|
context.authenticationService.activeMastodonAuthenticationBox,
|
||||||
.sink { [weak self] _ in
|
viewDidAppeared
|
||||||
guard let self = self else { return }
|
)
|
||||||
self.requestRecommendAccounts()
|
.compactMap { activeMastodonAuthenticationBox, _ -> AuthenticationService.MastodonAuthenticationBox? in
|
||||||
.sink { [weak self] _ in
|
return activeMastodonAuthenticationBox
|
||||||
guard let self = self else { return }
|
}
|
||||||
if !self.recommendAccounts.isEmpty {
|
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)
|
||||||
self.applyDataSource()
|
.flatMap { box -> AnyPublisher<Result<[Mastodon.Entity.Account.ID], Error>, Never> in
|
||||||
}
|
context.apiService.suggestionAccountV2(domain: box.domain, query: nil, mastodonAuthenticationBox: box)
|
||||||
} receiveValue: { _ in
|
.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()
|
||||||
}
|
}
|
||||||
.store(in: &self.disposeBag)
|
}
|
||||||
|
.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
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
searchResult
|
searchResult
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
|
@ -217,30 +252,6 @@ final class SearchViewModel: NSObject {
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestRecommendHashTags() -> Future<Void, Error> {
|
|
||||||
Future { promise in
|
|
||||||
guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else {
|
|
||||||
promise(.failure(APIService.APIError.implicit(APIService.APIError.ErrorReason.authenticationMissing)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.context.apiService.recommendTrends(domain: activeMastodonAuthenticationBox.domain, query: nil)
|
|
||||||
.sink { completion in
|
|
||||||
switch completion {
|
|
||||||
case .failure(let error):
|
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: recommendHashTags request fail: %s", (#file as NSString).lastPathComponent, #line, #function, error.localizedDescription)
|
|
||||||
promise(.failure(error))
|
|
||||||
case .finished:
|
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: recommendHashTags request success", (#file as NSString).lastPathComponent, #line, #function)
|
|
||||||
promise(.success(()))
|
|
||||||
}
|
|
||||||
} receiveValue: { [weak self] tags in
|
|
||||||
guard let self = self else { return }
|
|
||||||
self.recommendHashTags = tags.value
|
|
||||||
}
|
|
||||||
.store(in: &self.disposeBag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func requestRecommendAccountsV2() -> Future<Void, Error> {
|
func requestRecommendAccountsV2() -> Future<Void, Error> {
|
||||||
Future { promise in
|
Future { promise in
|
||||||
guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else {
|
guard let activeMastodonAuthenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||||
|
@ -296,17 +307,7 @@ final class SearchViewModel: NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyDataSource() {
|
func receiveAccounts(ids: [Mastodon.Entity.Account.ID]) {
|
||||||
DispatchQueue.main.async {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func receiveAccounts(ids: [String]) {
|
|
||||||
guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
|
guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -323,12 +324,23 @@ final class SearchViewModel: NSObject {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if let users = mastodonUsers {
|
guard let mastodonUsers = mastodonUsers else { return }
|
||||||
let sortedUsers = users.sorted { (user1, user2) -> Bool in
|
let objectIDs = mastodonUsers
|
||||||
(ids.firstIndex(of: user1.id) ?? 0) < (ids.firstIndex(of: user2.id) ?? 0)
|
.compactMap { object in
|
||||||
|
ids.firstIndex(of: object.id).map { index in (index, object) }
|
||||||
}
|
}
|
||||||
recommendAccounts = sortedUsers.map(\.objectID)
|
.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func accountCollectionViewItemDidSelected(mastodonUser: MastodonUser, from: UIViewController) {
|
func accountCollectionViewItemDidSelected(mastodonUser: MastodonUser, from: UIViewController) {
|
||||||
|
|
Loading…
Reference in New Issue