Remove user from UserItem-lists (IOS-192)
Also: Remove CoreData and replace User with Account in several places
This commit is contained in:
parent
3abb80a5df
commit
f373506aa3
|
@ -11,7 +11,6 @@ import CoreDataStack
|
|||
import MastodonSDK
|
||||
|
||||
enum UserItem: Hashable {
|
||||
case user(record: ManagedObjectRecord<MastodonUser>)
|
||||
case account(account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?)
|
||||
case bottomLoader
|
||||
case bottomHeader(text: String)
|
||||
|
|
|
@ -37,7 +37,7 @@ extension UserSection {
|
|||
case .account(let account, let relationship):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell
|
||||
|
||||
guard let me = authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext) else { return cell }
|
||||
guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return cell }
|
||||
|
||||
cell.userView.setButtonState(.loading)
|
||||
cell.configure(
|
||||
|
@ -48,27 +48,6 @@ extension UserSection {
|
|||
delegate: userTableViewCellDelegate
|
||||
)
|
||||
|
||||
return cell
|
||||
|
||||
case .user(let record):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell
|
||||
context.managedObjectContext.performAndWait {
|
||||
guard let user = record.object(in: context.managedObjectContext) else { return }
|
||||
configure(
|
||||
context: context,
|
||||
authContext: authContext,
|
||||
tableView: tableView,
|
||||
cell: cell,
|
||||
viewModel: UserTableViewCell.ViewModel(
|
||||
user: user,
|
||||
followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(),
|
||||
blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(),
|
||||
followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()
|
||||
),
|
||||
userTableViewCellDelegate: userTableViewCellDelegate
|
||||
)
|
||||
}
|
||||
|
||||
return cell
|
||||
case .bottomLoader:
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
|
||||
|
@ -82,23 +61,3 @@ extension UserSection {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UserSection {
|
||||
|
||||
static func configure(
|
||||
context: AppContext,
|
||||
authContext: AuthContext,
|
||||
tableView: UITableView,
|
||||
cell: UserTableViewCell,
|
||||
viewModel: UserTableViewCell.ViewModel,
|
||||
userTableViewCellDelegate: UserTableViewCellDelegate?
|
||||
) {
|
||||
cell.configure(
|
||||
me: authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext),
|
||||
tableView: tableView,
|
||||
viewModel: viewModel,
|
||||
delegate: userTableViewCellDelegate
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import MastodonSDK
|
|||
extension DataSourceFacade {
|
||||
static func responseToUserBlockAction(
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
user: ManagedObjectRecord<MastodonUser>
|
||||
account: Mastodon.Entity.Account
|
||||
) async throws {
|
||||
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
|
||||
await selectionFeedbackGenerator.selectionChanged()
|
||||
|
@ -22,7 +22,7 @@ extension DataSourceFacade {
|
|||
let authBox = dependency.authContext.mastodonAuthenticationBox
|
||||
|
||||
_ = try await apiService.toggleBlock(
|
||||
user: user,
|
||||
account: account,
|
||||
authenticationBox: authBox
|
||||
)
|
||||
|
||||
|
|
|
@ -15,27 +15,13 @@ import MastodonLocalization
|
|||
extension DataSourceFacade {
|
||||
static func responseToUserFollowAction(
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
user: ManagedObjectRecord<MastodonUser>
|
||||
) async throws {
|
||||
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
|
||||
await selectionFeedbackGenerator.selectionChanged()
|
||||
|
||||
_ = try await dependency.context.apiService.toggleFollow(
|
||||
user: user,
|
||||
authenticationBox: dependency.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
dependency.context.authenticationService.fetchFollowingAndBlockedAsync()
|
||||
}
|
||||
|
||||
static func responseToUserFollowAction(
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
user: Mastodon.Entity.Account
|
||||
account: Mastodon.Entity.Account
|
||||
) async throws -> Mastodon.Entity.Relationship {
|
||||
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
|
||||
await selectionFeedbackGenerator.selectionChanged()
|
||||
|
||||
let response = try await dependency.context.apiService.toggleFollow(
|
||||
user: user,
|
||||
account: account,
|
||||
authenticationBox: dependency.authContext.mastodonAuthenticationBox
|
||||
).value
|
||||
|
||||
|
@ -118,22 +104,12 @@ extension DataSourceFacade {
|
|||
}
|
||||
|
||||
extension DataSourceFacade {
|
||||
static func responseToShowHideReblogAction(
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
account: Mastodon.Entity.Account
|
||||
) async throws {
|
||||
#warning("TODO: Implement")
|
||||
// _ = try await dependency.context.apiService.toggleShowReblogs(
|
||||
// for: user,
|
||||
// authenticationBox: dependency.authContext.mastodonAuthenticationBox)
|
||||
}
|
||||
|
||||
static func responseToShowHideReblogAction(
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
user: Mastodon.Entity.Account
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
account: Mastodon.Entity.Account
|
||||
) async throws {
|
||||
_ = try await dependency.context.apiService.toggleShowReblogs(
|
||||
for: user,
|
||||
authenticationBox: dependency.authContext.mastodonAuthenticationBox)
|
||||
_ = try await dependency.context.apiService.toggleShowReblogs(
|
||||
for: account,
|
||||
authenticationBox: dependency.authContext.mastodonAuthenticationBox)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,20 +144,8 @@ extension DataSourceFacade {
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
#warning("TODO: Implement")
|
||||
await DataSourceFacade.coordinateToProfileScene(provider: provider, domain: "", accountID: mention.id)
|
||||
// let profileViewModel = ProfileViewModel(
|
||||
// context: provider.context,
|
||||
// authContext: provider.authContext,
|
||||
// account: status.entity.account
|
||||
// )
|
||||
//
|
||||
// _ = provider.coordinator.present(
|
||||
// scene: .profile(viewModel: profileViewModel),
|
||||
// from: provider,
|
||||
// transition: .show
|
||||
// )
|
||||
|
||||
await DataSourceFacade.coordinateToProfileScene(provider: provider, domain: domain, accountID: mention.id)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -354,7 +354,7 @@ extension DataSourceFacade {
|
|||
break
|
||||
case .followUser(_):
|
||||
try await DataSourceFacade.responseToUserFollowAction(dependency: dependency,
|
||||
user: menuContext.author)
|
||||
account: menuContext.author)
|
||||
}
|
||||
} // end func
|
||||
}
|
||||
|
|
|
@ -9,105 +9,46 @@ import MastodonSDK
|
|||
extension DataSourceFacade {
|
||||
static func responseToUserViewButtonAction(
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
user: ManagedObjectRecord<MastodonUser>,
|
||||
buttonState: UserView.ButtonState
|
||||
) async throws {
|
||||
switch buttonState {
|
||||
case .follow:
|
||||
try await DataSourceFacade.responseToUserFollowAction(
|
||||
dependency: dependency,
|
||||
user: user
|
||||
)
|
||||
|
||||
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,
|
||||
user: user
|
||||
)
|
||||
if let userObject = user.object(in: dependency.context.managedObjectContext) {
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.removeAll(where: { $0 == userObject.id })
|
||||
}
|
||||
case .blocked:
|
||||
try await DataSourceFacade.responseToUserBlockAction(
|
||||
dependency: dependency,
|
||||
user: user
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
static func responseToUserViewButtonAction(
|
||||
dependency: NeedsDependency & AuthContextProvider,
|
||||
user: Mastodon.Entity.Account,
|
||||
account: Mastodon.Entity.Account,
|
||||
buttonState: UserView.ButtonState
|
||||
) async throws {
|
||||
switch buttonState {
|
||||
case .follow:
|
||||
_ = try await DataSourceFacade.responseToUserFollowAction(
|
||||
dependency: dependency,
|
||||
user: user
|
||||
account: account
|
||||
)
|
||||
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.append(user.id)
|
||||
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.append(account.id)
|
||||
case .request:
|
||||
_ = try await DataSourceFacade.responseToUserFollowAction(
|
||||
dependency: dependency,
|
||||
user: user
|
||||
account: account
|
||||
)
|
||||
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.append(user.id)
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.append(account.id)
|
||||
case .unfollow:
|
||||
_ = try await DataSourceFacade.responseToUserFollowAction(
|
||||
dependency: dependency,
|
||||
user: user
|
||||
account: account
|
||||
)
|
||||
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.removeAll(where: { $0 == user.id })
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.removeAll(where: { $0 == account.id })
|
||||
case .blocked:
|
||||
try await DataSourceFacade.responseToUserBlockAction(
|
||||
dependency: dependency,
|
||||
user: user
|
||||
account: account
|
||||
)
|
||||
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.blockedUserIds.append(user.id)
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.blockedUserIds.append(account.id)
|
||||
|
||||
case .pending:
|
||||
_ = try await DataSourceFacade.responseToUserFollowAction(
|
||||
dependency: dependency,
|
||||
user: user
|
||||
account: account
|
||||
)
|
||||
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.removeAll(where: { $0 == user.id })
|
||||
dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.removeAll(where: { $0 == account.id })
|
||||
case .none, .loading:
|
||||
break //no-op
|
||||
}
|
||||
|
|
|
@ -99,9 +99,7 @@ extension DiscoveryForYouViewController: UITableViewDelegate {
|
|||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
guard case let .account(account, _) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return }
|
||||
|
||||
Task {
|
||||
await DataSourceFacade.coordinateToProfileScene(provider: self, account: account)
|
||||
}
|
||||
DataSourceFacade.coordinateToProfileScene(provider: self, account: account)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -119,7 +117,7 @@ extension DiscoveryForYouViewController: ProfileCardTableViewCellDelegate {
|
|||
cell.profileCardView.setButtonState(.loading)
|
||||
|
||||
Task {
|
||||
let newRelationship = try await DataSourceFacade.responseToUserFollowAction(dependency: self, user: account)
|
||||
let newRelationship = try await DataSourceFacade.responseToUserFollowAction(dependency: self, account: account)
|
||||
|
||||
let isMe = (account.id == authContext.mastodonAuthenticationBox.userID)
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ extension FavoritedByViewController: DataSourceProvider {
|
|||
}
|
||||
|
||||
switch item {
|
||||
case .user(_), .bottomHeader(_), .bottomLoader:
|
||||
case .bottomHeader(_), .bottomLoader:
|
||||
return nil
|
||||
case .account(let account, let relationship):
|
||||
return .account(account: account, relationship: relationship)
|
||||
|
|
|
@ -22,7 +22,7 @@ extension RebloggedByViewController: DataSourceProvider {
|
|||
}
|
||||
|
||||
switch item {
|
||||
case .user(_), .bottomHeader(_), .bottomLoader:
|
||||
case .bottomHeader(_), .bottomLoader:
|
||||
return nil
|
||||
case .account(let account, let relationship):
|
||||
return .account(account: account, relationship: relationship)
|
||||
|
|
|
@ -90,7 +90,7 @@ extension ReportResultViewController {
|
|||
do {
|
||||
try await DataSourceFacade.responseToUserFollowAction(
|
||||
dependency: self,
|
||||
user: self.viewModel.account
|
||||
account: self.viewModel.account
|
||||
)
|
||||
} catch {
|
||||
// handle error
|
||||
|
|
|
@ -44,7 +44,7 @@ extension SearchResultSection {
|
|||
case .account(let account, let relationship):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: UserTableViewCell.reuseIdentifier, for: indexPath) as! UserTableViewCell
|
||||
|
||||
guard let me = authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext) else { return cell }
|
||||
guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return cell }
|
||||
|
||||
cell.userView.setButtonState(.loading)
|
||||
cell.configure(
|
||||
|
@ -110,21 +110,4 @@ extension SearchResultSection {
|
|||
delegate: configuration.statusViewTableViewCellDelegate
|
||||
)
|
||||
}
|
||||
|
||||
static func configure(
|
||||
context: AppContext,
|
||||
authContext: AuthContext,
|
||||
tableView: UITableView,
|
||||
cell: UserTableViewCell,
|
||||
viewModel: UserTableViewCell.ViewModel,
|
||||
configuration: Configuration
|
||||
) {
|
||||
cell.configure(
|
||||
me: authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext),
|
||||
tableView: tableView,
|
||||
viewModel: viewModel,
|
||||
delegate: configuration.userTableViewCellDelegate
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,61 +17,9 @@ import MastodonSDK
|
|||
import MastodonAsset
|
||||
|
||||
extension UserView {
|
||||
public func configure(user: MastodonUser, delegate: UserViewDelegate?) {
|
||||
self.delegate = delegate
|
||||
viewModel.user = user
|
||||
viewModel.account = nil
|
||||
viewModel.relationship = nil
|
||||
|
||||
Publishers.CombineLatest(
|
||||
user.publisher(for: \.avatar),
|
||||
UserDefaults.shared.publisher(for: \.preferredStaticAvatar)
|
||||
)
|
||||
.map { _ in user.avatarImageURL() }
|
||||
.assign(to: \.authorAvatarImageURL, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// author name
|
||||
Publishers.CombineLatest(
|
||||
user.publisher(for: \.displayName),
|
||||
user.publisher(for: \.emojis)
|
||||
)
|
||||
.map { _, emojis in
|
||||
do {
|
||||
let content = MastodonContent(content: user.displayNameWithFallback, emojis: emojis.asDictionary)
|
||||
let metaContent = try MastodonMetaContent.convert(document: content)
|
||||
return metaContent
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
return PlaintextMetaContent(string: user.displayNameWithFallback)
|
||||
}
|
||||
}
|
||||
.assign(to: \.authorName, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
// author username
|
||||
user.publisher(for: \.acct)
|
||||
.map { $0 as String? }
|
||||
.assign(to: \.authorUsername, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
user.publisher(for: \.followersCount)
|
||||
.map { Int($0) }
|
||||
.assign(to: \.authorFollowers, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
user.publisher(for: \.fields)
|
||||
.map { fields in
|
||||
let firstVerified = fields.first(where: { $0.verifiedAt != nil })
|
||||
return firstVerified?.value
|
||||
}
|
||||
.assign(to: \.authorVerifiedLink, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
func configure(with account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?, delegate: UserViewDelegate?) {
|
||||
viewModel.account = account
|
||||
viewModel.relationship = relationship
|
||||
viewModel.user = nil
|
||||
self.delegate = delegate
|
||||
|
||||
let authorUsername = PlaintextMetaContent(string: "@\(account.username)")
|
||||
|
|
|
@ -14,14 +14,14 @@ import MastodonSDK
|
|||
|
||||
extension UserTableViewCell {
|
||||
final class ViewModel {
|
||||
let user: MastodonUser
|
||||
|
||||
let account: Mastodon.Entity.Account
|
||||
|
||||
let followedUsers: AnyPublisher<[String], Never>
|
||||
let blockedUsers: AnyPublisher<[String], Never>
|
||||
let followRequestedUsers: AnyPublisher<[String], Never>
|
||||
|
||||
init(user: MastodonUser, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) {
|
||||
self.user = user
|
||||
init(account: Mastodon.Entity.Account, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) {
|
||||
self.account = account
|
||||
self.followedUsers = followedUsers
|
||||
self.followRequestedUsers = followRequestedUsers
|
||||
self.blockedUsers = blockedUsers
|
||||
|
@ -32,7 +32,7 @@ extension UserTableViewCell {
|
|||
extension UserTableViewCell {
|
||||
|
||||
func configure(
|
||||
me: MastodonUser,
|
||||
me: Mastodon.Entity.Account,
|
||||
tableView: UITableView,
|
||||
account: Mastodon.Entity.Account,
|
||||
relationship: Mastodon.Entity.Relationship?,
|
||||
|
@ -45,69 +45,16 @@ extension UserTableViewCell {
|
|||
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
func configure(
|
||||
me: MastodonUser? = nil,
|
||||
tableView: UITableView,
|
||||
viewModel: ViewModel,
|
||||
delegate: UserTableViewCellDelegate?
|
||||
) {
|
||||
userView.configure(user: viewModel.user, delegate: delegate)
|
||||
|
||||
guard let me = me else {
|
||||
return userView.setButtonState(.none)
|
||||
}
|
||||
|
||||
if viewModel.user == me {
|
||||
userView.setButtonState(.none)
|
||||
} else {
|
||||
userView.setButtonState(.loading)
|
||||
}
|
||||
|
||||
Publishers.CombineLatest3(
|
||||
viewModel.followedUsers,
|
||||
viewModel.followRequestedUsers,
|
||||
viewModel.blockedUsers
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] followed, requested, blocked in
|
||||
if viewModel.user == me {
|
||||
self?.userView.setButtonState(.none)
|
||||
} else if blocked.contains(viewModel.user.id) {
|
||||
self?.userView.setButtonState(.blocked)
|
||||
} else if followed.contains(viewModel.user.id) {
|
||||
self?.userView.setButtonState(.unfollow)
|
||||
} else if requested.contains(viewModel.user.id) {
|
||||
self?.userView.setButtonState(.pending)
|
||||
} else if viewModel.user.locked {
|
||||
self?.userView.setButtonState(.request)
|
||||
} else if viewModel.user != me {
|
||||
self?.userView.setButtonState(.follow)
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
self.delegate = delegate
|
||||
}
|
||||
}
|
||||
|
||||
extension UserTableViewCellDelegate where Self: NeedsDependency & AuthContextProvider {
|
||||
func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: MastodonUser) {
|
||||
Task {
|
||||
try await DataSourceFacade.responseToUserViewButtonAction(
|
||||
dependency: self,
|
||||
user: user.asRecord,
|
||||
buttonState: state
|
||||
)
|
||||
}
|
||||
}
|
||||
func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for account: Mastodon.Entity.Account, me: MastodonUser?) {
|
||||
func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for account: Mastodon.Entity.Account, me: Mastodon.Entity.Account?) {
|
||||
Task {
|
||||
await MainActor.run { view.setButtonState(.loading) }
|
||||
|
||||
try await DataSourceFacade.responseToUserViewButtonAction(
|
||||
dependency: self,
|
||||
user: account,
|
||||
account: account,
|
||||
buttonState: state
|
||||
)
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ final class SuggestionAccountViewModel: NSObject {
|
|||
taskGroup.addTask {
|
||||
try? await DataSourceFacade.responseToUserViewButtonAction(
|
||||
dependency: dependency,
|
||||
user: account,
|
||||
account: account,
|
||||
buttonState: .follow
|
||||
)
|
||||
}
|
||||
|
|
|
@ -61,40 +61,22 @@ extension APIService {
|
|||
}
|
||||
|
||||
public func toggleBlock(
|
||||
user: ManagedObjectRecord<MastodonUser>,
|
||||
account: Mastodon.Entity.Account,
|
||||
authenticationBox: MastodonAuthenticationBox
|
||||
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Relationship> {
|
||||
|
||||
let managedObjectContext = backgroundManagedObjectContext
|
||||
let blockContext: MastodonBlockContext = try await managedObjectContext.performChanges {
|
||||
let authentication = authenticationBox.authentication
|
||||
|
||||
guard
|
||||
let user = user.object(in: managedObjectContext),
|
||||
let me = authentication.user(in: managedObjectContext)
|
||||
else {
|
||||
throw APIError.implicit(.badRequest)
|
||||
}
|
||||
|
||||
let isBlocking = user.blockingBy.contains(me)
|
||||
let isFollowing = user.followingBy.contains(me)
|
||||
// toggle block state
|
||||
user.update(isBlocking: !isBlocking, by: me)
|
||||
// update follow state implicitly
|
||||
if !isBlocking {
|
||||
// will do block action. set to unfollow
|
||||
user.update(isFollowing: false, by: me)
|
||||
}
|
||||
guard let me = authenticationBox.authentication.account(),
|
||||
let relationship = try await relationship(forAccounts: [account], authenticationBox: authenticationBox).value.first
|
||||
else { throw APIError.implicit(.badRequest) }
|
||||
|
||||
let blockContext = MastodonBlockContext(
|
||||
sourceUserID: me.id,
|
||||
targetUserID: account.id,
|
||||
targetUsername: account.username,
|
||||
isBlocking: relationship.blocking,
|
||||
isFollowing: relationship.following
|
||||
)
|
||||
|
||||
return MastodonBlockContext(
|
||||
sourceUserID: me.id,
|
||||
targetUserID: user.id,
|
||||
targetUsername: user.username,
|
||||
isBlocking: isBlocking,
|
||||
isFollowing: isFollowing
|
||||
)
|
||||
}
|
||||
|
||||
let result: Result<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error>
|
||||
do {
|
||||
if blockContext.isBlocking {
|
||||
|
@ -117,34 +99,7 @@ extension APIService {
|
|||
} catch {
|
||||
result = .failure(error)
|
||||
}
|
||||
|
||||
try await managedObjectContext.performChanges {
|
||||
let authentication = authenticationBox.authentication
|
||||
|
||||
guard
|
||||
let user = user.object(in: managedObjectContext),
|
||||
let me = authentication.user(in: managedObjectContext)
|
||||
else { return }
|
||||
|
||||
|
||||
switch result {
|
||||
case .success(let response):
|
||||
let relationship = response.value
|
||||
Persistence.MastodonUser.update(
|
||||
mastodonUser: user,
|
||||
context: Persistence.MastodonUser.RelationshipContext(
|
||||
entity: relationship,
|
||||
me: me,
|
||||
networkDate: response.networkDate
|
||||
)
|
||||
)
|
||||
case .failure:
|
||||
// rollback
|
||||
user.update(isBlocking: blockContext.isBlocking, by: me)
|
||||
user.update(isFollowing: blockContext.isFollowing, by: me)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let response = try result.get()
|
||||
return response
|
||||
}
|
||||
|
|
|
@ -30,95 +30,11 @@ extension APIService {
|
|||
/// - activeMastodonAuthenticationBox: `AuthenticationService.MastodonAuthenticationBox`
|
||||
/// - Returns: publisher for `Relationship`
|
||||
public func toggleFollow(
|
||||
user: ManagedObjectRecord<MastodonUser>,
|
||||
account: Mastodon.Entity.Account,
|
||||
authenticationBox: MastodonAuthenticationBox
|
||||
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Relationship> {
|
||||
|
||||
let managedObjectContext = backgroundManagedObjectContext
|
||||
let _followContext: MastodonFollowContext? = try await managedObjectContext.performChanges {
|
||||
guard let me = authenticationBox.authentication.user(in: managedObjectContext) else { return nil }
|
||||
guard let user = user.object(in: managedObjectContext) else { return nil }
|
||||
|
||||
let isFollowing = user.followingBy.contains(me)
|
||||
let isPending = user.followRequestedBy.contains(me)
|
||||
let needsUnfollow = isFollowing || isPending
|
||||
|
||||
if needsUnfollow {
|
||||
// unfollow
|
||||
user.update(isFollowing: false, by: me)
|
||||
user.update(isFollowRequested: false, by: me)
|
||||
} else {
|
||||
// follow
|
||||
if user.locked {
|
||||
user.update(isFollowing: false, by: me)
|
||||
user.update(isFollowRequested: true, by: me)
|
||||
} else {
|
||||
user.update(isFollowing: true, by: me)
|
||||
user.update(isFollowRequested: false, by: me)
|
||||
}
|
||||
}
|
||||
let context = MastodonFollowContext(
|
||||
sourceUserID: me.id,
|
||||
targetUserID: user.id,
|
||||
isFollowing: isFollowing,
|
||||
isPending: isPending,
|
||||
needsUnfollow: needsUnfollow
|
||||
)
|
||||
return context
|
||||
}
|
||||
|
||||
guard let followContext = _followContext else {
|
||||
throw APIError.implicit(.badRequest)
|
||||
}
|
||||
|
||||
// request follow or unfollow
|
||||
let result: Result<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error>
|
||||
do {
|
||||
let response = try await Mastodon.API.Account.follow(
|
||||
session: session,
|
||||
domain: authenticationBox.domain,
|
||||
accountID: followContext.targetUserID,
|
||||
followQueryType: followContext.needsUnfollow ? .unfollow : .follow(query: .init()),
|
||||
authorization: authenticationBox.userAuthorization
|
||||
).singleOutput()
|
||||
result = .success(response)
|
||||
} catch {
|
||||
result = .failure(error)
|
||||
}
|
||||
|
||||
// update friendship state
|
||||
try await managedObjectContext.performChanges {
|
||||
guard let me = authenticationBox.authentication.user(in: managedObjectContext),
|
||||
let user = user.object(in: managedObjectContext)
|
||||
else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let response):
|
||||
Persistence.MastodonUser.update(
|
||||
mastodonUser: user,
|
||||
context: Persistence.MastodonUser.RelationshipContext(
|
||||
entity: response.value,
|
||||
me: me,
|
||||
networkDate: response.networkDate
|
||||
)
|
||||
)
|
||||
case .failure:
|
||||
// rollback
|
||||
user.update(isFollowing: followContext.isFollowing, by: me)
|
||||
user.update(isFollowRequested: followContext.isPending, by: me)
|
||||
}
|
||||
}
|
||||
|
||||
let response = try result.get()
|
||||
return response
|
||||
}
|
||||
|
||||
public func toggleFollow(
|
||||
user: Mastodon.Entity.Account,
|
||||
authenticationBox: MastodonAuthenticationBox
|
||||
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Relationship> {
|
||||
|
||||
guard let relationship = try await relationship(forAccounts: [user], authenticationBox: authenticationBox).value.first else {
|
||||
guard let relationship = try await relationship(forAccounts: [account], authenticationBox: authenticationBox).value.first else {
|
||||
throw APIError.implicit(.badRequest)
|
||||
}
|
||||
|
||||
|
@ -129,14 +45,14 @@ extension APIService {
|
|||
response = try await Mastodon.API.Account.unfollow(
|
||||
session: session,
|
||||
domain: authenticationBox.domain,
|
||||
accountID: user.id,
|
||||
accountID: account.id,
|
||||
authorization: authenticationBox.userAuthorization
|
||||
).singleOutput()
|
||||
} else {
|
||||
response = try await Mastodon.API.Account.follow(
|
||||
session: session,
|
||||
domain: authenticationBox.domain,
|
||||
accountID: user.id,
|
||||
accountID: account.id,
|
||||
followQueryType: .follow(query: .init()),
|
||||
authorization: authenticationBox.userAuthorization
|
||||
).singleOutput()
|
||||
|
|
|
@ -32,28 +32,7 @@ extension APIService {
|
|||
query: query,
|
||||
authorization: authorization
|
||||
).singleOutput()
|
||||
|
||||
let managedObjectContext = self.backgroundManagedObjectContext
|
||||
try await managedObjectContext.performChanges {
|
||||
let me = authenticationBox.authentication.user(in: managedObjectContext)
|
||||
|
||||
for entity in response.value {
|
||||
let result = Persistence.MastodonUser.createOrMerge(
|
||||
in: managedObjectContext,
|
||||
context: Persistence.MastodonUser.PersistContext(
|
||||
domain: domain,
|
||||
entity: entity,
|
||||
cache: nil,
|
||||
networkDate: response.networkDate
|
||||
)
|
||||
)
|
||||
|
||||
let user = result.user
|
||||
me?.update(isFollowing: true, by: user)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ extension UserView {
|
|||
@Published public var authorUsername: String?
|
||||
@Published public var authorFollowers: Int?
|
||||
@Published public var authorVerifiedLink: String?
|
||||
@Published public var user: MastodonUser?
|
||||
@Published public var account: Mastodon.Entity.Account?
|
||||
@Published public var relationship: Mastodon.Entity.Relationship?
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@ import CoreDataStack
|
|||
import MastodonSDK
|
||||
|
||||
public protocol UserViewDelegate: AnyObject {
|
||||
func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: MastodonUser)
|
||||
func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: Mastodon.Entity.Account, me: MastodonUser?)
|
||||
func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: Mastodon.Entity.Account, me: Mastodon.Entity.Account?)
|
||||
}
|
||||
|
||||
public final class UserView: UIView {
|
||||
|
@ -255,9 +254,7 @@ public extension UserView {
|
|||
}
|
||||
|
||||
@objc private func didTapFollowButton() {
|
||||
if let user = viewModel.user {
|
||||
delegate?.userView(self, didTapButtonWith: currentButtonState, for: user)
|
||||
} else if let account = viewModel.account {
|
||||
if let account = viewModel.account {
|
||||
delegate?.userView(self, didTapButtonWith: currentButtonState, for: account, me: nil)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue