2021-04-01 08:39:15 +02:00
|
|
|
//
|
|
|
|
// ProfileViewModel.swift
|
|
|
|
// Mastodon
|
|
|
|
//
|
|
|
|
// Created by MainasuK Cirno on 2021-3-29.
|
|
|
|
//
|
|
|
|
|
|
|
|
import os.log
|
|
|
|
import UIKit
|
|
|
|
import Combine
|
|
|
|
import CoreDataStack
|
|
|
|
import MastodonSDK
|
2021-07-23 13:10:27 +02:00
|
|
|
import MastodonMeta
|
2022-01-27 14:23:39 +01:00
|
|
|
import MastodonAsset
|
|
|
|
import MastodonLocalization
|
2022-04-14 15:15:21 +02:00
|
|
|
import MastodonUI
|
2021-04-01 08:39:15 +02:00
|
|
|
|
|
|
|
// please override this base class
|
|
|
|
class ProfileViewModel: NSObject {
|
2022-04-14 15:15:21 +02:00
|
|
|
|
2022-01-27 14:23:39 +01:00
|
|
|
let logger = Logger(subsystem: "ProfileViewModel", category: "ViewModel")
|
|
|
|
|
2021-04-01 08:39:15 +02:00
|
|
|
typealias UserID = String
|
|
|
|
|
|
|
|
var disposeBag = Set<AnyCancellable>()
|
|
|
|
var observations = Set<NSKeyValueObservation>()
|
|
|
|
private var mastodonUserObserver: AnyCancellable?
|
|
|
|
private var currentMastodonUserObserver: AnyCancellable?
|
|
|
|
|
2022-05-13 11:23:35 +02:00
|
|
|
let postsUserTimelineViewModel: UserTimelineViewModel
|
|
|
|
let repliesUserTimelineViewModel: UserTimelineViewModel
|
|
|
|
let mediaUserTimelineViewModel: UserTimelineViewModel
|
|
|
|
let profileAboutViewModel: ProfileAboutViewModel
|
|
|
|
|
2021-04-01 08:39:15 +02:00
|
|
|
// input
|
|
|
|
let context: AppContext
|
2022-02-10 12:30:41 +01:00
|
|
|
@Published var me: MastodonUser?
|
|
|
|
@Published var user: MastodonUser?
|
2022-05-13 11:23:35 +02:00
|
|
|
|
2021-04-01 08:39:15 +02:00
|
|
|
let viewDidAppear = PassthroughSubject<Void, Never>()
|
2022-05-13 11:23:35 +02:00
|
|
|
|
|
|
|
@Published var isEditing = false
|
|
|
|
@Published var isUpdating = false
|
2021-04-01 08:39:15 +02:00
|
|
|
|
|
|
|
// output
|
2022-05-13 11:23:35 +02:00
|
|
|
@Published var userIdentifier: UserIdentifier? = nil
|
|
|
|
|
|
|
|
// let domain: CurrentValueSubject<String?, Never>
|
|
|
|
// let userID: CurrentValueSubject<UserID?, Never>
|
|
|
|
// let bannerImageURL: CurrentValueSubject<URL?, Never>
|
|
|
|
// let avatarImageURL: CurrentValueSubject<URL?, Never>
|
|
|
|
// let name: CurrentValueSubject<String?, Never>
|
|
|
|
// let username: CurrentValueSubject<String?, Never>
|
|
|
|
// let bioDescription: CurrentValueSubject<String?, Never>
|
|
|
|
// let url: CurrentValueSubject<String?, Never>
|
|
|
|
// let statusesCount: CurrentValueSubject<Int?, Never>
|
|
|
|
// let followingCount: CurrentValueSubject<Int?, Never>
|
|
|
|
// let followersCount: CurrentValueSubject<Int?, Never>
|
|
|
|
// let fields: CurrentValueSubject<[MastodonField], Never>
|
|
|
|
// let emojiMeta: CurrentValueSubject<MastodonContent.Emojis, Never>
|
2021-04-01 08:39:15 +02:00
|
|
|
|
2021-06-24 13:20:41 +02:00
|
|
|
// fulfill this before editing
|
|
|
|
let accountForEdit = CurrentValueSubject<Mastodon.Entity.Account?, Never>(nil)
|
|
|
|
|
2022-05-13 11:23:35 +02:00
|
|
|
// let protected: CurrentValueSubject<Bool?, Never>
|
|
|
|
// let suspended: CurrentValueSubject<Bool, Never>
|
2021-04-02 12:13:45 +02:00
|
|
|
|
2022-05-13 11:23:35 +02:00
|
|
|
//
|
|
|
|
// let relationshipActionOptionSet = CurrentValueSubject<RelationshipActionOptionSet, Never>(.none)
|
|
|
|
// let isFollowedBy = CurrentValueSubject<Bool, Never>(false)
|
|
|
|
// let isMuting = CurrentValueSubject<Bool, Never>(false)
|
|
|
|
// let isBlocking = CurrentValueSubject<Bool, Never>(false)
|
|
|
|
// let isBlockedBy = CurrentValueSubject<Bool, Never>(false)
|
|
|
|
//
|
|
|
|
// let isRelationshipActionButtonHidden = CurrentValueSubject<Bool, Never>(true)
|
|
|
|
// let isReplyBarButtonItemHidden = CurrentValueSubject<Bool, Never>(true)
|
|
|
|
// let isMoreMenuBarButtonItemHidden = CurrentValueSubject<Bool, Never>(true)
|
|
|
|
// let isMeBarButtonItemsHidden = CurrentValueSubject<Bool, Never>(true)
|
|
|
|
//
|
|
|
|
// let needsPagePinToTop = CurrentValueSubject<Bool, Never>(false)
|
|
|
|
// let needsPagingEnabled = CurrentValueSubject<Bool, Never>(true)
|
|
|
|
// let needsImageOverlayBlurred = CurrentValueSubject<Bool, Never>(false)
|
2021-04-08 10:53:32 +02:00
|
|
|
|
2021-04-01 08:39:15 +02:00
|
|
|
init(context: AppContext, optionalMastodonUser mastodonUser: MastodonUser?) {
|
|
|
|
self.context = context
|
2022-02-10 12:30:41 +01:00
|
|
|
self.user = mastodonUser
|
2022-05-13 11:23:35 +02:00
|
|
|
// self.domain = CurrentValueSubject(context.authenticationService.activeMastodonAuthenticationBox.value?.domain)
|
|
|
|
// self.userID = CurrentValueSubject(mastodonUser?.id)
|
|
|
|
// self.bannerImageURL = CurrentValueSubject(mastodonUser?.headerImageURL())
|
|
|
|
// self.avatarImageURL = CurrentValueSubject(mastodonUser?.avatarImageURL())
|
|
|
|
// self.name = CurrentValueSubject(mastodonUser?.displayNameWithFallback)
|
|
|
|
// self.username = CurrentValueSubject(mastodonUser?.acctWithDomain)
|
|
|
|
// self.bioDescription = CurrentValueSubject(mastodonUser?.note)
|
|
|
|
// self.url = CurrentValueSubject(mastodonUser?.url)
|
|
|
|
// self.statusesCount = CurrentValueSubject(mastodonUser.flatMap { Int($0.statusesCount) })
|
|
|
|
// self.followingCount = CurrentValueSubject(mastodonUser.flatMap { Int($0.followingCount) })
|
|
|
|
// self.followersCount = CurrentValueSubject(mastodonUser.flatMap { Int($0.followersCount) })
|
|
|
|
// self.protected = CurrentValueSubject(mastodonUser?.locked)
|
|
|
|
// self.suspended = CurrentValueSubject(mastodonUser?.suspended ?? false)
|
|
|
|
// self.fields = CurrentValueSubject(mastodonUser?.fields ?? [])
|
|
|
|
// self.emojiMeta = CurrentValueSubject(mastodonUser?.emojis.asDictionary ?? [:])
|
|
|
|
self.postsUserTimelineViewModel = UserTimelineViewModel(
|
|
|
|
context: context,
|
|
|
|
queryFilter: .init(excludeReplies: true)
|
|
|
|
)
|
|
|
|
self.repliesUserTimelineViewModel = UserTimelineViewModel(
|
|
|
|
context: context,
|
|
|
|
queryFilter: .init(excludeReplies: true)
|
|
|
|
)
|
|
|
|
self.mediaUserTimelineViewModel = UserTimelineViewModel(
|
|
|
|
context: context,
|
|
|
|
queryFilter: .init(onlyMedia: true)
|
|
|
|
)
|
|
|
|
self.profileAboutViewModel = ProfileAboutViewModel(context: context)
|
2021-04-01 08:39:15 +02:00
|
|
|
super.init()
|
2021-04-02 12:13:45 +02:00
|
|
|
|
2022-05-13 11:23:35 +02:00
|
|
|
// bind me
|
2022-02-10 12:30:41 +01:00
|
|
|
context.authenticationService.activeMastodonAuthenticationBox
|
2022-05-13 11:23:35 +02:00
|
|
|
.receive(on: DispatchQueue.main)
|
2022-02-10 12:30:41 +01:00
|
|
|
.sink { [weak self] authenticationBox in
|
2021-04-01 08:39:15 +02:00
|
|
|
guard let self = self else { return }
|
2022-05-13 11:23:35 +02:00
|
|
|
self.me = authenticationBox?.authenticationRecord.object(in: context.managedObjectContext)?.user
|
2021-04-01 08:39:15 +02:00
|
|
|
}
|
|
|
|
.store(in: &disposeBag)
|
2022-05-13 11:23:35 +02:00
|
|
|
|
|
|
|
// bind user
|
|
|
|
$user
|
|
|
|
.map { user -> UserIdentifier? in
|
|
|
|
guard let user = user else { return nil }
|
|
|
|
return MastodonUserIdentifier(domain: user.domain, userID: user.id)
|
|
|
|
}
|
|
|
|
.assign(to: &$userIdentifier)
|
2021-04-01 08:39:15 +02:00
|
|
|
|
2022-05-13 11:23:35 +02:00
|
|
|
$userIdentifier.assign(to: &postsUserTimelineViewModel.$userIdentifier)
|
|
|
|
$userIdentifier.assign(to: &repliesUserTimelineViewModel.$userIdentifier)
|
|
|
|
$userIdentifier.assign(to: &mediaUserTimelineViewModel.$userIdentifier)
|
|
|
|
// $userIdentifier.assign(to: &profileAboutViewModel.$userIdentifier)
|
2022-01-27 14:23:39 +01:00
|
|
|
|
2022-05-13 11:23:35 +02:00
|
|
|
// relationshipActionOptionSet
|
|
|
|
// .compactMap { $0.highPriorityAction(except: []) }
|
|
|
|
// .map { $0 == .none }
|
|
|
|
// .assign(to: \.value, on: isRelationshipActionButtonHidden)
|
|
|
|
// .store(in: &disposeBag)
|
|
|
|
//
|
2021-06-24 09:14:50 +02:00
|
|
|
|
2022-05-13 11:23:35 +02:00
|
|
|
//
|
|
|
|
// // query relationship
|
|
|
|
// let userRecord = $user.map { user -> ManagedObjectRecord<MastodonUser>? in
|
|
|
|
// user.flatMap { ManagedObjectRecord<MastodonUser>(objectID: $0.objectID) }
|
|
|
|
// }
|
|
|
|
// let pendingRetryPublisher = CurrentValueSubject<TimeInterval, Never>(1)
|
|
|
|
//
|
|
|
|
// // observe friendship
|
|
|
|
// Publishers.CombineLatest3(
|
|
|
|
// userRecord,
|
|
|
|
// context.authenticationService.activeMastodonAuthenticationBox,
|
|
|
|
// pendingRetryPublisher
|
|
|
|
// )
|
|
|
|
// .sink { [weak self] userRecord, authenticationBox, _ in
|
|
|
|
// guard let self = self else { return }
|
|
|
|
// guard let userRecord = userRecord,
|
|
|
|
// let authenticationBox = authenticationBox
|
|
|
|
// else { return }
|
|
|
|
// Task {
|
|
|
|
// do {
|
|
|
|
// let response = try await self.updateRelationship(
|
|
|
|
// record: userRecord,
|
|
|
|
// authenticationBox: authenticationBox
|
|
|
|
// )
|
|
|
|
// // there are seconds delay after request follow before requested -> following. Query again when needs
|
|
|
|
// guard let relationship = response.value.first else { return }
|
|
|
|
// if relationship.requested == true {
|
|
|
|
// let delay = pendingRetryPublisher.value
|
|
|
|
// DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
|
|
|
// guard let _ = self else { return }
|
|
|
|
// pendingRetryPublisher.value = min(2 * delay, 60)
|
|
|
|
// os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Relationship] fetch again due to pending", ((#file as NSString).lastPathComponent), #line, #function)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// } catch {
|
|
|
|
// self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Relationship] update user relationship failure: \(error.localizedDescription)")
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// .store(in: &disposeBag)
|
|
|
|
//
|
|
|
|
// let isBlockingOrBlocked = Publishers.CombineLatest(
|
|
|
|
// isBlocking,
|
|
|
|
// isBlockedBy
|
|
|
|
// )
|
|
|
|
// .map { $0 || $1 }
|
|
|
|
// .share()
|
|
|
|
//
|
|
|
|
// isBlockingOrBlocked
|
|
|
|
// .map { !$0 }
|
|
|
|
// .assign(to: \.value, on: needsPagingEnabled)
|
|
|
|
// .store(in: &disposeBag)
|
|
|
|
//
|
|
|
|
// isBlockingOrBlocked
|
|
|
|
// .map { $0 }
|
|
|
|
// .assign(to: \.value, on: needsImageOverlayBlurred)
|
|
|
|
// .store(in: &disposeBag)
|
|
|
|
//
|
|
|
|
// setup()
|
2021-04-01 08:39:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
extension ProfileViewModel {
|
|
|
|
private func setup() {
|
|
|
|
Publishers.CombineLatest(
|
2022-02-10 12:30:41 +01:00
|
|
|
$user,
|
|
|
|
$me
|
2021-04-01 08:39:15 +02:00
|
|
|
)
|
|
|
|
.receive(on: DispatchQueue.main)
|
2022-02-10 12:30:41 +01:00
|
|
|
.sink { [weak self] user, me in
|
2021-04-01 08:39:15 +02:00
|
|
|
guard let self = self else { return }
|
2021-04-02 12:13:45 +02:00
|
|
|
// Update view model attribute
|
2022-02-10 12:30:41 +01:00
|
|
|
self.update(mastodonUser: user)
|
|
|
|
self.update(mastodonUser: user, currentMastodonUser: me)
|
2021-04-01 08:39:15 +02:00
|
|
|
|
2021-04-02 12:13:45 +02:00
|
|
|
// Setup observer for user
|
2022-02-10 12:30:41 +01:00
|
|
|
if let mastodonUser = user {
|
2021-04-01 08:39:15 +02:00
|
|
|
// setup observer
|
|
|
|
self.mastodonUserObserver = ManagedObjectObserver.observe(object: mastodonUser)
|
|
|
|
.sink { completion in
|
|
|
|
switch completion {
|
|
|
|
case .failure(let error):
|
|
|
|
assertionFailure(error.localizedDescription)
|
|
|
|
case .finished:
|
|
|
|
assertionFailure()
|
|
|
|
}
|
|
|
|
} receiveValue: { [weak self] change in
|
|
|
|
guard let self = self else { return }
|
|
|
|
guard let changeType = change.changeType else { return }
|
|
|
|
switch changeType {
|
|
|
|
case .update:
|
|
|
|
self.update(mastodonUser: mastodonUser)
|
2022-02-10 12:30:41 +01:00
|
|
|
self.update(mastodonUser: mastodonUser, currentMastodonUser: me)
|
2021-04-01 08:39:15 +02:00
|
|
|
case .delete:
|
|
|
|
// TODO:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
self.mastodonUserObserver = nil
|
|
|
|
}
|
|
|
|
|
2021-04-02 12:13:45 +02:00
|
|
|
// Setup observer for user
|
2022-02-10 12:30:41 +01:00
|
|
|
if let currentMastodonUser = me {
|
2021-04-01 08:39:15 +02:00
|
|
|
// setup observer
|
|
|
|
self.currentMastodonUserObserver = ManagedObjectObserver.observe(object: currentMastodonUser)
|
|
|
|
.sink { completion in
|
|
|
|
switch completion {
|
|
|
|
case .failure(let error):
|
|
|
|
assertionFailure(error.localizedDescription)
|
|
|
|
case .finished:
|
|
|
|
assertionFailure()
|
|
|
|
}
|
|
|
|
} receiveValue: { [weak self] change in
|
|
|
|
guard let self = self else { return }
|
|
|
|
guard let changeType = change.changeType else { return }
|
|
|
|
switch changeType {
|
|
|
|
case .update:
|
2022-02-10 12:30:41 +01:00
|
|
|
self.update(mastodonUser: user, currentMastodonUser: currentMastodonUser)
|
2021-04-01 08:39:15 +02:00
|
|
|
case .delete:
|
|
|
|
// TODO:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.currentMastodonUserObserver = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.store(in: &disposeBag)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func update(mastodonUser: MastodonUser?) {
|
2022-05-13 11:23:35 +02:00
|
|
|
// self.userID.value = mastodonUser?.id
|
|
|
|
// self.bannerImageURL.value = mastodonUser?.headerImageURL()
|
|
|
|
// self.avatarImageURL.value = mastodonUser?.avatarImageURL()
|
|
|
|
// self.name.value = mastodonUser?.displayNameWithFallback
|
|
|
|
// self.username.value = mastodonUser?.acctWithDomain
|
|
|
|
// self.bioDescription.value = mastodonUser?.note
|
|
|
|
// self.url.value = mastodonUser?.url
|
|
|
|
// self.statusesCount.value = mastodonUser.flatMap { Int($0.statusesCount) }
|
|
|
|
// self.followingCount.value = mastodonUser.flatMap { Int($0.followingCount) }
|
|
|
|
// self.followersCount.value = mastodonUser.flatMap { Int($0.followersCount) }
|
|
|
|
// self.protected.value = mastodonUser?.locked
|
|
|
|
// self.suspended.value = mastodonUser?.suspended ?? false
|
|
|
|
// self.fields.value = mastodonUser?.fields ?? []
|
|
|
|
// self.emojiMeta.value = mastodonUser?.emojis.asDictionary ?? [:]
|
2021-04-01 08:39:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private func update(mastodonUser: MastodonUser?, currentMastodonUser: MastodonUser?) {
|
2022-05-13 11:23:35 +02:00
|
|
|
// guard let mastodonUser = mastodonUser,
|
|
|
|
// let currentMastodonUser = currentMastodonUser else {
|
|
|
|
// // set relationship
|
|
|
|
// self.relationshipActionOptionSet.value = .none
|
|
|
|
// self.isFollowedBy.value = false
|
|
|
|
// self.isMuting.value = false
|
|
|
|
// self.isBlocking.value = false
|
|
|
|
// self.isBlockedBy.value = false
|
|
|
|
//
|
|
|
|
// // set bar button item state
|
|
|
|
// self.isReplyBarButtonItemHidden.value = true
|
|
|
|
// self.isMoreMenuBarButtonItemHidden.value = true
|
|
|
|
// self.isMeBarButtonItemsHidden.value = true
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if mastodonUser == currentMastodonUser {
|
|
|
|
// self.relationshipActionOptionSet.value = [.edit]
|
|
|
|
// // set bar button item state
|
|
|
|
// self.isReplyBarButtonItemHidden.value = true
|
|
|
|
// self.isMoreMenuBarButtonItemHidden.value = true
|
|
|
|
// self.isMeBarButtonItemsHidden.value = false
|
|
|
|
// } else {
|
|
|
|
// // set with follow action default
|
|
|
|
// var relationshipActionSet = RelationshipActionOptionSet([.follow])
|
|
|
|
//
|
|
|
|
// if mastodonUser.locked {
|
|
|
|
// relationshipActionSet.insert(.request)
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if mastodonUser.suspended {
|
|
|
|
// relationshipActionSet.insert(.suspended)
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// let isFollowing = mastodonUser.followingBy.contains(currentMastodonUser)
|
|
|
|
// if isFollowing {
|
|
|
|
// relationshipActionSet.insert(.following)
|
|
|
|
// }
|
|
|
|
// os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Relationship] update %s isFollowing: %s", ((#file as NSString).lastPathComponent), #line, #function, mastodonUser.id, isFollowing.description)
|
|
|
|
//
|
|
|
|
// let isPending = mastodonUser.followRequestedBy.contains(currentMastodonUser)
|
|
|
|
// if isPending {
|
|
|
|
// relationshipActionSet.insert(.pending)
|
|
|
|
// }
|
|
|
|
// os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Relationship] update %s isPending: %s", ((#file as NSString).lastPathComponent), #line, #function, mastodonUser.id, isPending.description)
|
|
|
|
//
|
|
|
|
// let isFollowedBy = currentMastodonUser.followingBy.contains(mastodonUser)
|
|
|
|
// self.isFollowedBy.value = isFollowedBy
|
|
|
|
// os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Relationship] update %s isFollowedBy: %s", ((#file as NSString).lastPathComponent), #line, #function, mastodonUser.id, isFollowedBy.description)
|
|
|
|
//
|
|
|
|
// let isMuting = mastodonUser.mutingBy.contains(currentMastodonUser)
|
|
|
|
// if isMuting {
|
|
|
|
// relationshipActionSet.insert(.muting)
|
|
|
|
// }
|
|
|
|
// self.isMuting.value = isMuting
|
|
|
|
// os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Relationship] update %s isMuting: %s", ((#file as NSString).lastPathComponent), #line, #function, mastodonUser.id, isMuting.description)
|
|
|
|
//
|
|
|
|
// let isBlocking = mastodonUser.blockingBy.contains(currentMastodonUser)
|
|
|
|
// if isBlocking {
|
|
|
|
// relationshipActionSet.insert(.blocking)
|
|
|
|
// }
|
|
|
|
// self.isBlocking.value = isBlocking
|
|
|
|
// os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Relationship] update %s isBlocking: %s", ((#file as NSString).lastPathComponent), #line, #function, mastodonUser.id, isBlocking.description)
|
|
|
|
//
|
|
|
|
// let isBlockedBy = currentMastodonUser.blockingBy.contains(mastodonUser)
|
|
|
|
// if isBlockedBy {
|
|
|
|
// relationshipActionSet.insert(.blocked)
|
|
|
|
// }
|
|
|
|
// self.isBlockedBy.value = isBlockedBy
|
|
|
|
// os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Relationship] update %s isBlockedBy: %s", ((#file as NSString).lastPathComponent), #line, #function, mastodonUser.id, isBlockedBy.description)
|
|
|
|
//
|
|
|
|
// self.relationshipActionOptionSet.value = relationshipActionSet
|
|
|
|
//
|
|
|
|
// // set bar button item state
|
|
|
|
// self.isReplyBarButtonItemHidden.value = isBlocking || isBlockedBy
|
|
|
|
// self.isMoreMenuBarButtonItemHidden.value = false
|
|
|
|
// self.isMeBarButtonItemsHidden.value = true
|
|
|
|
// }
|
2021-04-01 08:39:15 +02:00
|
|
|
}
|
|
|
|
|
2021-04-02 12:13:45 +02:00
|
|
|
}
|
|
|
|
|
2021-06-24 13:20:41 +02:00
|
|
|
extension ProfileViewModel {
|
|
|
|
|
|
|
|
// fetch profile info before edit
|
|
|
|
func fetchEditProfileInfo() -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> {
|
2022-02-10 12:30:41 +01:00
|
|
|
guard let me = me,
|
|
|
|
let mastodonAuthentication = me.mastodonAuthentication
|
|
|
|
else {
|
2021-06-24 13:20:41 +02:00
|
|
|
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
|
|
|
|
}
|
|
|
|
|
|
|
|
let authorization = Mastodon.API.OAuth.Authorization(accessToken: mastodonAuthentication.userAccessToken)
|
2022-02-10 12:30:41 +01:00
|
|
|
return context.apiService.accountVerifyCredentials(domain: me.domain, authorization: authorization)
|
2022-01-27 14:23:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private func updateRelationship(
|
|
|
|
record: ManagedObjectRecord<MastodonUser>,
|
|
|
|
authenticationBox: MastodonAuthenticationBox
|
|
|
|
) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Relationship]> {
|
|
|
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Relationship] update user relationship...")
|
|
|
|
let response = try await context.apiService.relationship(
|
|
|
|
records: [record],
|
|
|
|
authenticationBox: authenticationBox
|
|
|
|
)
|
|
|
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Relationship] did update MastodonUser relationship")
|
|
|
|
return response
|
2021-06-24 13:20:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-01-27 14:23:39 +01:00
|
|
|
extension ProfileViewModel {
|
|
|
|
func updateProfileInfo(
|
|
|
|
headerProfileInfo: ProfileHeaderViewModel.ProfileInfo,
|
|
|
|
aboutProfileInfo: ProfileAboutViewModel.ProfileInfo
|
|
|
|
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Account> {
|
|
|
|
guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
|
|
|
|
throw APIService.APIError.implicit(.badRequest)
|
|
|
|
}
|
|
|
|
|
|
|
|
let domain = authenticationBox.domain
|
|
|
|
let authorization = authenticationBox.userAuthorization
|
|
|
|
|
|
|
|
let _image: UIImage? = {
|
|
|
|
guard let image = headerProfileInfo.avatarImage else { return nil }
|
|
|
|
guard image.size.width <= ProfileHeaderViewModel.avatarImageMaxSizeInPixel.width else {
|
|
|
|
return image.af.imageScaled(to: ProfileHeaderViewModel.avatarImageMaxSizeInPixel)
|
|
|
|
}
|
|
|
|
return image
|
|
|
|
}()
|
|
|
|
|
|
|
|
let fieldsAttributes = aboutProfileInfo.fields.map { field in
|
|
|
|
Mastodon.Entity.Field(name: field.name.value, value: field.value.value)
|
|
|
|
}
|
|
|
|
|
|
|
|
let query = Mastodon.API.Account.UpdateCredentialQuery(
|
|
|
|
discoverable: nil,
|
|
|
|
bot: nil,
|
|
|
|
displayName: headerProfileInfo.name,
|
|
|
|
note: headerProfileInfo.note,
|
|
|
|
avatar: _image.flatMap { Mastodon.Query.MediaAttachment.png($0.pngData()) },
|
|
|
|
header: nil,
|
|
|
|
locked: nil,
|
|
|
|
source: nil,
|
|
|
|
fieldsAttributes: fieldsAttributes
|
|
|
|
)
|
|
|
|
return try await context.apiService.accountUpdateCredentials(
|
|
|
|
domain: domain,
|
|
|
|
query: query,
|
|
|
|
authorization: authorization
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|