Add request-follow/pending-states to follow-button (IOS-157, IOS-140)

This commit is contained in:
Nathan Mattes 2023-05-17 11:35:02 +02:00
parent b3309b4bd0
commit 44f6fc9a5c
8 changed files with 77 additions and 21 deletions

View File

@ -32,7 +32,12 @@ extension SearchHistorySection {
guard let user = item.object(in: context.managedObjectContext) else { return }
cell.configure(
me: authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)?.user,
viewModel: .init(value: user, followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(), blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher()),
viewModel: SearchHistoryUserCollectionViewCell.ViewModel(
value: user,
followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(),
blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(),
followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()
),
delegate: configuration.searchHistorySectionHeaderCollectionReusableViewDelegate
)
}

View File

@ -53,7 +53,10 @@ extension SearchResultSection {
authContext: authContext,
tableView: tableView,
cell: cell,
viewModel: .init(value: .user(user), followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(), blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher()),
viewModel: UserTableViewCell.ViewModel(value: .user(user),
followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(),
blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(),
followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()),
configuration: configuration
)
}

View File

@ -48,7 +48,11 @@ extension UserSection {
authContext: authContext,
tableView: tableView,
cell: cell,
viewModel: .init(value: .user(user), followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(), blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher()),
viewModel: UserTableViewCell.ViewModel(value: .user(user),
followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(),
blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(),
followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()
),
configuration: configuration
)
}

View File

@ -22,6 +22,17 @@ extension DataSourceFacade {
if let userObject = user.object(in: dependency.context.managedObjectContext) {
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.append(userObject.id)
}
case .request:
try await DataSourceFacade.responseToUserFollowAction(
dependency: dependency,
user: user
)
if let userObject = user.object(in: dependency.context.managedObjectContext) {
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.append(userObject.id)
}
case .unfollow:
try await DataSourceFacade.responseToUserFollowAction(
dependency: dependency,
@ -39,6 +50,16 @@ extension DataSourceFacade {
if let userObject = user.object(in: dependency.context.managedObjectContext) {
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.blockedUserIds.append(userObject.id)
}
case .pending:
try await DataSourceFacade.responseToUserFollowAction(
dependency: dependency,
user: user
)
if let userObject = user.object(in: dependency.context.managedObjectContext) {
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.removeAll(where: { $0 == userObject.id })
}
case .none, .loading:
break //no-op
}

View File

@ -16,10 +16,12 @@ extension SearchHistoryUserCollectionViewCell {
let followedUsers: AnyPublisher<[String], Never>
let blockedUsers: AnyPublisher<[String], Never>
init(value: MastodonUser, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>) {
let followRequestedUsers: AnyPublisher<[String], Never>
init(value: MastodonUser, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) {
self.value = value
self.followedUsers = followedUsers
self.followRequestedUsers = followRequestedUsers
self.blockedUsers = blockedUsers
}
}
@ -45,25 +47,26 @@ extension SearchHistoryUserCollectionViewCell {
userView.setButtonState(.loading)
}
Publishers.CombineLatest(
Publishers.CombineLatest3(
viewModel.followedUsers,
viewModel.followRequestedUsers,
viewModel.blockedUsers
)
.receive(on: DispatchQueue.main)
.sink { [weak self] followed, blocked in
if blocked.contains(where: { $0 == user.id }) {
.sink { [weak self] followed, requested, blocked in
if blocked.contains(user.id) {
self?.userView.setButtonState(.blocked)
} else if followed.contains(where: { $0 == user.id }) {
} else if followed.contains(user.id) {
self?.userView.setButtonState(.unfollow)
} else {
} else if requested.contains(user.id) {
self?.userView.setButtonState(.pending)
} else if user.locked {
self?.userView.setButtonState(.request)
} else if user != me {
self?.userView.setButtonState(.follow)
}
self?.setNeedsLayout()
self?.setNeedsUpdateConstraints()
self?.layoutIfNeeded()
}
.store(in: &_disposeBag)
}
}

View File

@ -16,10 +16,12 @@ extension UserTableViewCell {
let followedUsers: AnyPublisher<[String], Never>
let blockedUsers: AnyPublisher<[String], Never>
let followRequestedUsers: AnyPublisher<[String], Never>
init(value: Value, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>) {
init(value: Value, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) {
self.value = value
self.followedUsers = followedUsers
self.followRequestedUsers = followRequestedUsers
self.blockedUsers = blockedUsers
}
@ -52,20 +54,24 @@ extension UserTableViewCell {
userView.setButtonState(.loading)
}
Publishers.CombineLatest(
Publishers.CombineLatest3(
viewModel.followedUsers,
viewModel.followRequestedUsers,
viewModel.blockedUsers
)
.receive(on: DispatchQueue.main)
.sink { [weak self] followed, blocked in
.sink { [weak self] followed, requested, blocked in
if blocked.contains(user.id) {
self?.userView.setButtonState(.blocked)
} else if followed.contains(user.id) {
self?.userView.setButtonState(.unfollow)
} else if requested.contains(user.id) {
self?.userView.setButtonState(.pending)
} else if user.locked {
self?.userView.setButtonState(.request)
} else if user != me {
self?.userView.setButtonState(.follow)
}
}
.store(in: &disposeBag)

View File

@ -52,6 +52,7 @@ extension MastodonAuthenticationBox {
public class MastodonAccountInMemoryCache {
@Published public var followingUserIds: [String] = []
@Published public var blockedUserIds: [String] = []
@Published public var followRequestedUserIDs: [String] = []
static var sharedCaches = [String: MastodonAccountInMemoryCache]()

View File

@ -20,7 +20,7 @@ public protocol UserViewDelegate: AnyObject {
public final class UserView: UIView {
public enum ButtonState {
case none, loading, follow, unfollow, blocked
case none, loading, follow, request, pending, unfollow, blocked
}
private var currentButtonState: ButtonState = .none
@ -291,6 +291,7 @@ public extension UserView {
prepareButtonStateLayout(for: state)
switch state {
case .loading:
followButton.isHidden = false
followButton.setTitle(nil, for: .normal)
@ -301,7 +302,19 @@ public extension UserView {
followButton.setTitle(L10n.Common.Controls.Friendship.follow, for: .normal)
followButton.setBackgroundColor(Asset.Colors.Button.userFollow.color, for: .normal)
followButton.setTitleColor(.white, for: .normal)
case .request:
followButton.isHidden = false
followButton.setTitle(L10n.Common.Controls.Friendship.request, for: .normal)
followButton.setBackgroundColor(Asset.Colors.Button.userFollow.color, for: .normal)
followButton.setTitleColor(.white, for: .normal)
case .pending:
followButton.isHidden = false
followButton.setTitle(L10n.Common.Controls.Friendship.pending, for: .normal)
followButton.setTitleColor(Asset.Colors.Button.userFollowingTitle.color, for: .normal)
followButton.setBackgroundColor(Asset.Colors.Button.userFollowing.color, for: .normal)
case .unfollow:
followButton.isHidden = false
followButton.setTitle(L10n.Common.Controls.Friendship.following, for: .normal)