mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
Merge branch 'develop' into ios-192-profile-about
# Conflicts: # Mastodon/Scene/Profile/UserList/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift # Mastodon/Scene/Profile/UserList/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift # Mastodon/Scene/Profile/UserList/UserListViewModel+Diffable.swift # Mastodon/Scene/Profile/UserList/UserListViewModel+State.swift
This commit is contained in:
commit
58501da5fa
@ -2278,7 +2278,7 @@
|
||||
path = FamiliarFollowers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB5B54A42833BD1D00DEF8B2 /* UserLIst */ = {
|
||||
DB5B54A42833BD1D00DEF8B2 /* UserList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB5B54A22833BD1A00DEF8B2 /* UserListViewModel.swift */,
|
||||
@ -2287,7 +2287,7 @@
|
||||
DB5B54A92833BFAC00DEF8B2 /* FavoritedBy */,
|
||||
DB5B54AC2833C12D00DEF8B2 /* RebloggedBy */,
|
||||
);
|
||||
path = UserLIst;
|
||||
path = UserList;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB5B54A92833BFAC00DEF8B2 /* FavoritedBy */ = {
|
||||
@ -2746,7 +2746,7 @@
|
||||
DB6B74F0272FB55400C70B6E /* Follower */,
|
||||
DB5B7296273112B400081888 /* Following */,
|
||||
DB5B549B2833A60600DEF8B2 /* FamiliarFollowers */,
|
||||
DB5B54A42833BD1D00DEF8B2 /* UserLIst */,
|
||||
DB5B54A42833BD1D00DEF8B2 /* UserList */,
|
||||
DBFEEC97279BDC6A004F81DD /* About */,
|
||||
DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */,
|
||||
DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */,
|
||||
|
@ -21,10 +21,10 @@ extension FavoritedByViewController: DataSourceProvider {
|
||||
}
|
||||
|
||||
switch item {
|
||||
case .bottomHeader(_), .bottomLoader:
|
||||
return nil
|
||||
case .account(let account, let relationship):
|
||||
return .account(account: account, relationship: relationship)
|
||||
case .bottomHeader(_), .bottomLoader:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,10 @@ extension RebloggedByViewController: DataSourceProvider {
|
||||
}
|
||||
|
||||
switch item {
|
||||
case .bottomHeader(_), .bottomLoader:
|
||||
return nil
|
||||
case .account(let account, let relationship):
|
||||
return .account(account: account, relationship: relationship)
|
||||
case .bottomHeader(_), .bottomLoader:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ extension UserListViewModel {
|
||||
$accounts
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] accounts in
|
||||
guard let self = self else { return }
|
||||
guard let self else { return }
|
||||
guard let diffableDataSource = self.diffableDataSource else { return }
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<UserSection, UserItem>()
|
||||
@ -52,7 +52,7 @@ extension UserListViewModel {
|
||||
|
||||
let items = accountsWithRelationship.map { UserItem.account(account: $0.account, relationship: $0.relationship) }
|
||||
snapshot.appendItems(items, toSection: .main)
|
||||
|
||||
|
||||
if let currentState = self.stateMachine.currentState {
|
||||
switch currentState {
|
||||
case is State.Initial, is State.Idle, is State.Reloading, is State.Loading, is State.Fail:
|
@ -56,7 +56,8 @@ extension UserListViewModel.State {
|
||||
|
||||
// reset
|
||||
viewModel.accounts = []
|
||||
|
||||
viewModel.relationships = []
|
||||
|
||||
stateMachine.enter(Loading.self)
|
||||
}
|
||||
}
|
||||
@ -124,23 +125,23 @@ extension UserListViewModel.State {
|
||||
|
||||
Task {
|
||||
do {
|
||||
let response: Mastodon.Response.Content<[Mastodon.Entity.Account]>
|
||||
let accountResponse: Mastodon.Response.Content<[Mastodon.Entity.Account]>
|
||||
switch viewModel.kind {
|
||||
case .favoritedBy(let status):
|
||||
response = try await viewModel.context.apiService.favoritedBy(
|
||||
accountResponse = try await viewModel.context.apiService.favoritedBy(
|
||||
status: status,
|
||||
query: .init(maxID: maxID, limit: nil),
|
||||
authenticationBox: authenticationBox
|
||||
)
|
||||
case .rebloggedBy(let status):
|
||||
response = try await viewModel.context.apiService.rebloggedBy(
|
||||
accountResponse = try await viewModel.context.apiService.rebloggedBy(
|
||||
status: status,
|
||||
query: .init(maxID: maxID, limit: nil),
|
||||
authenticationBox: authenticationBox
|
||||
)
|
||||
}
|
||||
|
||||
if response.value.isEmpty {
|
||||
if accountResponse.value.isEmpty {
|
||||
await enter(state: NoMore.self)
|
||||
|
||||
viewModel.accounts = []
|
||||
@ -148,17 +149,15 @@ extension UserListViewModel.State {
|
||||
return
|
||||
}
|
||||
|
||||
let newRelationships = try await viewModel.context.apiService.relationship(
|
||||
forAccounts: response.value,
|
||||
authenticationBox: authenticationBox
|
||||
)
|
||||
|
||||
var hasNewAppend = false
|
||||
var accounts = viewModel.accounts
|
||||
for account in response.value {
|
||||
guard !accounts.contains(account) else { continue }
|
||||
|
||||
accounts.append(account)
|
||||
let newRelationships = try await viewModel.context.apiService.relationship(forAccounts: accountResponse.value, authenticationBox: viewModel.authContext.mastodonAuthenticationBox)
|
||||
|
||||
var accounts = viewModel.accounts
|
||||
|
||||
for user in accountResponse.value {
|
||||
guard accounts.contains(user) == false else { continue }
|
||||
accounts.append(user)
|
||||
hasNewAppend = true
|
||||
}
|
||||
|
||||
@ -169,16 +168,17 @@ extension UserListViewModel.State {
|
||||
relationships.append(relationship)
|
||||
}
|
||||
|
||||
let maxID = response.link?.maxID
|
||||
|
||||
let maxID = accountResponse.link?.maxID
|
||||
|
||||
if hasNewAppend, maxID != nil {
|
||||
await enter(state: Idle.self)
|
||||
} else {
|
||||
await enter(state: NoMore.self)
|
||||
}
|
||||
self.maxID = maxID
|
||||
viewModel.relationships = relationships
|
||||
|
||||
viewModel.accounts = accounts
|
||||
viewModel.relationships = relationships
|
||||
self.maxID = maxID
|
||||
|
||||
} catch {
|
||||
await enter(state: Fail.self)
|
@ -1,111 +0,0 @@
|
||||
//
|
||||
// UserFetchedResultsController.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-7.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
import CoreData
|
||||
import CoreDataStack
|
||||
import MastodonSDK
|
||||
|
||||
public final class UserFetchedResultsController: NSObject {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
let fetchedResultsController: NSFetchedResultsController<MastodonUser>
|
||||
|
||||
// input
|
||||
@Published public var domain: String? = nil
|
||||
@Published public var userIDs: [Mastodon.Entity.Account.ID] = []
|
||||
@Published public var additionalPredicate: NSPredicate?
|
||||
|
||||
// output
|
||||
let _objectIDs = CurrentValueSubject<[NSManagedObjectID], Never>([])
|
||||
@Published public private(set) var records: [ManagedObjectRecord<MastodonUser>] = []
|
||||
|
||||
public init(
|
||||
managedObjectContext: NSManagedObjectContext,
|
||||
domain: String?,
|
||||
additionalPredicate: NSPredicate?
|
||||
) {
|
||||
self.domain = domain ?? ""
|
||||
self.fetchedResultsController = {
|
||||
let fetchRequest = MastodonUser.sortedFetchRequest
|
||||
fetchRequest.predicate = MastodonUser.predicate(domain: domain ?? "", ids: [])
|
||||
fetchRequest.returnsObjectsAsFaults = false
|
||||
fetchRequest.fetchBatchSize = 20
|
||||
let controller = NSFetchedResultsController(
|
||||
fetchRequest: fetchRequest,
|
||||
managedObjectContext: managedObjectContext,
|
||||
sectionNameKeyPath: nil,
|
||||
cacheName: nil
|
||||
)
|
||||
|
||||
return controller
|
||||
}()
|
||||
self.additionalPredicate = additionalPredicate
|
||||
super.init()
|
||||
|
||||
// debounce output to prevent UI update issues
|
||||
_objectIDs
|
||||
.throttle(for: 0.1, scheduler: DispatchQueue.main, latest: true)
|
||||
.map { objectIDs in objectIDs.map { ManagedObjectRecord(objectID: $0) } }
|
||||
.assign(to: &$records)
|
||||
|
||||
fetchedResultsController.delegate = self
|
||||
|
||||
Publishers.CombineLatest3(
|
||||
self.$domain.removeDuplicates(),
|
||||
self.$userIDs.removeDuplicates(),
|
||||
self.$additionalPredicate.removeDuplicates()
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] domain, ids, additionalPredicate in
|
||||
guard let self = self else { return }
|
||||
var predicates = [MastodonUser.predicate(domain: domain ?? "", ids: ids)]
|
||||
if let additionalPredicate = additionalPredicate {
|
||||
predicates.append(additionalPredicate)
|
||||
}
|
||||
self.fetchedResultsController.fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
|
||||
do {
|
||||
try self.fetchedResultsController.performFetch()
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UserFetchedResultsController {
|
||||
|
||||
public func append(userIDs: [Mastodon.Entity.Account.ID]) {
|
||||
var result = self.userIDs
|
||||
for userID in userIDs where !result.contains(userID) {
|
||||
result.append(userID)
|
||||
}
|
||||
self.userIDs = result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - NSFetchedResultsControllerDelegate
|
||||
extension UserFetchedResultsController: NSFetchedResultsControllerDelegate {
|
||||
public func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
||||
|
||||
let indexes = userIDs
|
||||
let objects = fetchedResultsController.fetchedObjects ?? []
|
||||
|
||||
let items: [NSManagedObjectID] = objects
|
||||
.compactMap { object in
|
||||
indexes.firstIndex(of: object.id).map { index in (index, object) }
|
||||
}
|
||||
.sorted { $0.0 < $1.0 }
|
||||
.map { $0.1.objectID }
|
||||
self._objectIDs.value = items
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user