feat: add remote profile load logic for profile scene
This commit is contained in:
parent
3b576badeb
commit
2f89471c78
|
@ -266,6 +266,7 @@
|
||||||
DBAE3F942616E28B004B8251 /* APIService+Follow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3F932616E28B004B8251 /* APIService+Follow.swift */; };
|
DBAE3F942616E28B004B8251 /* APIService+Follow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3F932616E28B004B8251 /* APIService+Follow.swift */; };
|
||||||
DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */; };
|
DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */; };
|
||||||
DBAE3FA92617106E004B8251 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */; };
|
DBAE3FA92617106E004B8251 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */; };
|
||||||
|
DBAE3FAF26172FC0004B8251 /* RemoteProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */; };
|
||||||
DBB525082611EAC0002F1F29 /* Tabman in Frameworks */ = {isa = PBXBuildFile; productRef = DBB525072611EAC0002F1F29 /* Tabman */; };
|
DBB525082611EAC0002F1F29 /* Tabman in Frameworks */ = {isa = PBXBuildFile; productRef = DBB525072611EAC0002F1F29 /* Tabman */; };
|
||||||
DBB5250E2611EBAF002F1F29 /* ProfileSegmentedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */; };
|
DBB5250E2611EBAF002F1F29 /* ProfileSegmentedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */; };
|
||||||
DBB525212611EBD6002F1F29 /* ProfilePagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */; };
|
DBB525212611EBD6002F1F29 /* ProfilePagingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */; };
|
||||||
|
@ -618,6 +619,7 @@
|
||||||
DBAE3F932616E28B004B8251 /* APIService+Follow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Follow.swift"; sourceTree = "<group>"; };
|
DBAE3F932616E28B004B8251 /* APIService+Follow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Follow.swift"; sourceTree = "<group>"; };
|
||||||
DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Mute.swift"; sourceTree = "<group>"; };
|
DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Mute.swift"; sourceTree = "<group>"; };
|
||||||
DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = "<group>"; };
|
DBAE3FA82617106E004B8251 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = "<group>"; };
|
||||||
|
DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteProfileViewModel.swift; sourceTree = "<group>"; };
|
||||||
DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSegmentedViewController.swift; sourceTree = "<group>"; };
|
DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSegmentedViewController.swift; sourceTree = "<group>"; };
|
||||||
DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewController.swift; sourceTree = "<group>"; };
|
DBB525202611EBD6002F1F29 /* ProfilePagingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewController.swift; sourceTree = "<group>"; };
|
||||||
DBB5252F2611EBF3002F1F29 /* ProfilePagingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewModel.swift; sourceTree = "<group>"; };
|
DBB5252F2611EBF3002F1F29 /* ProfilePagingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePagingViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1524,6 +1526,7 @@
|
||||||
DBAE3F812615DDA3004B8251 /* ProfileViewController+UserProvider.swift */,
|
DBAE3F812615DDA3004B8251 /* ProfileViewController+UserProvider.swift */,
|
||||||
DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */,
|
DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */,
|
||||||
DBCC3B8E26148F7B0045B23D /* CachedProfileViewModel.swift */,
|
DBCC3B8E26148F7B0045B23D /* CachedProfileViewModel.swift */,
|
||||||
|
DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */,
|
||||||
DBB525632612C988002F1F29 /* MeProfileViewModel.swift */,
|
DBB525632612C988002F1F29 /* MeProfileViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = Profile;
|
path = Profile;
|
||||||
|
@ -2098,6 +2101,7 @@
|
||||||
DB55D33025FB630A0002F825 /* TwitterTextEditor+String.swift in Sources */,
|
DB55D33025FB630A0002F825 /* TwitterTextEditor+String.swift in Sources */,
|
||||||
2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */,
|
2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */,
|
||||||
DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */,
|
DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */,
|
||||||
|
DBAE3FAF26172FC0004B8251 /* RemoteProfileViewModel.swift in Sources */,
|
||||||
DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */,
|
DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */,
|
||||||
DB9E0D6F25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift in Sources */,
|
DB9E0D6F25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift in Sources */,
|
||||||
2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */,
|
2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */,
|
||||||
|
|
|
@ -24,6 +24,10 @@ extension StatusTableViewCellDelegate where Self: StatusProvider {
|
||||||
StatusProviderFacade.coordinateToStatusAuthorProfileScene(for: .primary, provider: self, cell: cell)
|
StatusProviderFacade.coordinateToStatusAuthorProfileScene(for: .primary, provider: self, cell: cell)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
|
||||||
|
StatusProviderFacade.responseToStatusActiveLabelAction(provider: self, cell: cell, activeLabel: activeLabel, didTapEntity: entity)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ActionToolbarContainerDelegate
|
// MARK: - ActionToolbarContainerDelegate
|
||||||
|
|
|
@ -62,6 +62,68 @@ extension StatusProviderFacade {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension StatusProviderFacade {
|
||||||
|
|
||||||
|
static func responseToStatusActiveLabelAction(provider: StatusProvider, cell: UITableViewCell, activeLabel: ActiveLabel, didTapEntity entity: ActiveEntity) {
|
||||||
|
switch entity.type {
|
||||||
|
case .hashtag(let text, let userInfo):
|
||||||
|
break
|
||||||
|
case .mention(let text, let userInfo):
|
||||||
|
coordinateToStatusMentionProfileScene(for: .primary, provider: provider, cell: cell, mention: text)
|
||||||
|
case .url(_, _, let url, _):
|
||||||
|
guard let url = URL(string: url) else { return }
|
||||||
|
provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func coordinateToStatusMentionProfileScene(for target: Target, provider: StatusProvider, cell: UITableViewCell, mention: String) {
|
||||||
|
guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return }
|
||||||
|
let domain = activeMastodonAuthenticationBox.domain
|
||||||
|
|
||||||
|
provider.status(for: cell, indexPath: nil)
|
||||||
|
.sink { [weak provider] status in
|
||||||
|
guard let provider = provider else { return }
|
||||||
|
let _status: Status? = {
|
||||||
|
switch target {
|
||||||
|
case .primary: return status?.reblog ?? status
|
||||||
|
case .secondary: return status
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
guard let status = _status else { return }
|
||||||
|
|
||||||
|
// cannot continue without meta
|
||||||
|
guard let mentionMeta = (status.mentions ?? Set()).first(where: { $0.username == mention }) else { return }
|
||||||
|
|
||||||
|
let userID = mentionMeta.id
|
||||||
|
|
||||||
|
let profileViewModel: ProfileViewModel = {
|
||||||
|
// check if self
|
||||||
|
guard userID != activeMastodonAuthenticationBox.userID else {
|
||||||
|
return MeProfileViewModel(context: provider.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = MastodonUser.sortedFetchRequest
|
||||||
|
request.fetchLimit = 1
|
||||||
|
request.predicate = MastodonUser.predicate(domain: domain, id: userID)
|
||||||
|
let mastodonUser = provider.context.managedObjectContext.safeFetch(request).first
|
||||||
|
|
||||||
|
if let mastodonUser = mastodonUser {
|
||||||
|
return CachedProfileViewModel(context: provider.context, mastodonUser: mastodonUser)
|
||||||
|
} else {
|
||||||
|
return RemoteProfileViewModel(context: provider.context, userID: userID)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
provider.coordinator.present(scene: .profile(viewModel: profileViewModel), from: provider, transition: .show)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &provider.disposeBag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension StatusProviderFacade {
|
extension StatusProviderFacade {
|
||||||
|
|
||||||
static func responseToStatusLikeAction(provider: StatusProvider) {
|
static func responseToStatusLikeAction(provider: StatusProvider) {
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
//
|
||||||
|
// RemoteProfileViewModel.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by MainasuK Cirno on 2021-4-2.
|
||||||
|
//
|
||||||
|
|
||||||
|
import os.log
|
||||||
|
import Foundation
|
||||||
|
import CoreDataStack
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
|
final class RemoteProfileViewModel: ProfileViewModel {
|
||||||
|
|
||||||
|
convenience init(context: AppContext, userID: Mastodon.Entity.Account.ID) {
|
||||||
|
self.init(context: context, optionalMastodonUser: nil)
|
||||||
|
|
||||||
|
guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let domain = activeMastodonAuthenticationBox.domain
|
||||||
|
let authorization = activeMastodonAuthenticationBox.userAuthorization
|
||||||
|
context.apiService.accountInfo(
|
||||||
|
domain: domain,
|
||||||
|
userID: userID,
|
||||||
|
authorization: authorization
|
||||||
|
)
|
||||||
|
.retry(3)
|
||||||
|
.sink { completion in
|
||||||
|
switch completion {
|
||||||
|
case .failure(let error):
|
||||||
|
// TODO: handle error
|
||||||
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: remote user %s fetch failed: %s", ((#file as NSString).lastPathComponent), #line, #function, userID, error.localizedDescription)
|
||||||
|
case .finished:
|
||||||
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: remote user %s fetched", ((#file as NSString).lastPathComponent), #line, #function, userID)
|
||||||
|
}
|
||||||
|
} receiveValue: { [weak self] response in
|
||||||
|
guard let self = self else { return }
|
||||||
|
let managedObjectContext = context.managedObjectContext
|
||||||
|
let request = MastodonUser.sortedFetchRequest
|
||||||
|
request.fetchLimit = 1
|
||||||
|
request.predicate = MastodonUser.predicate(domain: domain, id: response.value.id)
|
||||||
|
guard let mastodonUser = managedObjectContext.safeFetch(request).first else {
|
||||||
|
assertionFailure()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.mastodonUser.value = mastodonUser
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ protocol StatusViewDelegate: class {
|
||||||
func statusView(_ statusView: StatusView, contentWarningActionButtonPressed button: UIButton)
|
func statusView(_ statusView: StatusView, contentWarningActionButtonPressed button: UIButton)
|
||||||
func statusView(_ statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
func statusView(_ statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||||
func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton)
|
func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton)
|
||||||
|
func statusView(_ statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class StatusView: UIView {
|
final class StatusView: UIView {
|
||||||
|
@ -402,6 +403,7 @@ extension StatusView {
|
||||||
statusContentWarningContainerStackView.isHidden = true
|
statusContentWarningContainerStackView.isHidden = true
|
||||||
statusContentWarningContainerStackViewBottomLayoutConstraint.isActive = false
|
statusContentWarningContainerStackViewBottomLayoutConstraint.isActive = false
|
||||||
|
|
||||||
|
activeTextLabel.delegate = self
|
||||||
playerContainerView.delegate = self
|
playerContainerView.delegate = self
|
||||||
|
|
||||||
headerInfoLabelTapGestureRecognizer.addTarget(self, action: #selector(StatusView.headerInfoLabelTapGestureRecognizerHandler(_:)))
|
headerInfoLabelTapGestureRecognizer.addTarget(self, action: #selector(StatusView.headerInfoLabelTapGestureRecognizerHandler(_:)))
|
||||||
|
@ -475,6 +477,14 @@ extension StatusView {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - ActiveLabelDelegate
|
||||||
|
extension StatusView: ActiveLabelDelegate {
|
||||||
|
func activeLabel(_ activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
|
||||||
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select entity: %s", ((#file as NSString).lastPathComponent), #line, #function, entity.primaryText)
|
||||||
|
delegate?.statusView(self, activeLabel: activeLabel, didSelectActiveEntity: entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - PlayerContainerViewDelegate
|
// MARK: - PlayerContainerViewDelegate
|
||||||
extension StatusView: PlayerContainerViewDelegate {
|
extension StatusView: PlayerContainerViewDelegate {
|
||||||
func playerContainerView(_ playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) {
|
func playerContainerView(_ playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import AVKit
|
||||||
import Combine
|
import Combine
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import ActiveLabel
|
||||||
|
|
||||||
protocol StatusTableViewCellDelegate: class {
|
protocol StatusTableViewCellDelegate: class {
|
||||||
var context: AppContext! { get }
|
var context: AppContext! { get }
|
||||||
|
@ -18,18 +19,22 @@ protocol StatusTableViewCellDelegate: class {
|
||||||
|
|
||||||
func parent() -> UIViewController
|
func parent() -> UIViewController
|
||||||
var playerViewControllerDelegate: AVPlayerViewControllerDelegate? { get }
|
var playerViewControllerDelegate: AVPlayerViewControllerDelegate? { get }
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, playerViewControllerDidPressed playerViewController: AVPlayerViewController)
|
|
||||||
|
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, headerInfoLabelDidPressed label: UILabel)
|
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, headerInfoLabelDidPressed label: UILabel)
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, avatarButtonDidPressed button: UIButton)
|
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, avatarButtonDidPressed button: UIButton)
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, contentWarningActionButtonPressed button: UIButton)
|
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, contentWarningActionButtonPressed button: UIButton)
|
||||||
|
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton)
|
||||||
|
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity)
|
||||||
|
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, didTapImageView imageView: UIImageView, atIndex index: Int)
|
func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, didTapImageView imageView: UIImageView, atIndex index: Int)
|
||||||
|
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
func statusTableViewCell(_ cell: StatusTableViewCell, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||||
|
func statusTableViewCell(_ cell: StatusTableViewCell, playerViewControllerDidPressed playerViewController: AVPlayerViewController)
|
||||||
|
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, reblogButtonDidPressed sender: UIButton)
|
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, reblogButtonDidPressed sender: UIButton)
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton)
|
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton)
|
||||||
|
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton)
|
|
||||||
func statusTableViewCell(_ cell: StatusTableViewCell, pollTableView: PollTableView, didSelectRowAt indexPath: IndexPath)
|
func statusTableViewCell(_ cell: StatusTableViewCell, pollTableView: PollTableView, didSelectRowAt indexPath: IndexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +221,10 @@ extension StatusTableViewCell: StatusViewDelegate {
|
||||||
delegate?.statusTableViewCell(self, statusView: statusView, pollVoteButtonPressed: button)
|
delegate?.statusTableViewCell(self, statusView: statusView, pollVoteButtonPressed: button)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func statusView(_ statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
|
||||||
|
delegate?.statusTableViewCell(self, statusView: statusView, activeLabel: activeLabel, didSelectActiveEntity: entity)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MosaicImageViewDelegate
|
// MARK: - MosaicImageViewDelegate
|
||||||
|
|
|
@ -10,6 +10,52 @@ import Combine
|
||||||
import CommonOSLog
|
import CommonOSLog
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
|
||||||
|
extension APIService {
|
||||||
|
|
||||||
|
func accountInfo(
|
||||||
|
domain: String,
|
||||||
|
userID: Mastodon.Entity.Account.ID,
|
||||||
|
authorization: Mastodon.API.OAuth.Authorization
|
||||||
|
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> {
|
||||||
|
return Mastodon.API.Account.accountInfo(
|
||||||
|
session: session,
|
||||||
|
domain: domain,
|
||||||
|
userID: userID,
|
||||||
|
authorization: authorization
|
||||||
|
)
|
||||||
|
.flatMap { response -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> in
|
||||||
|
let log = OSLog.api
|
||||||
|
let account = response.value
|
||||||
|
|
||||||
|
return self.backgroundManagedObjectContext.performChanges {
|
||||||
|
let (mastodonUser, isCreated) = APIService.CoreData.createOrMergeMastodonUser(
|
||||||
|
into: self.backgroundManagedObjectContext,
|
||||||
|
for: nil,
|
||||||
|
in: domain,
|
||||||
|
entity: account,
|
||||||
|
userCache: nil,
|
||||||
|
networkDate: response.networkDate,
|
||||||
|
log: log
|
||||||
|
)
|
||||||
|
let flag = isCreated ? "+" : "-"
|
||||||
|
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: fetch mastodon user [%s](%s)%s", ((#file as NSString).lastPathComponent), #line, #function, flag, mastodonUser.id, mastodonUser.username)
|
||||||
|
}
|
||||||
|
.setFailureType(to: Error.self)
|
||||||
|
.tryMap { result -> Mastodon.Response.Content<Mastodon.Entity.Account> in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
return response
|
||||||
|
case .failure(let error):
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
extension APIService {
|
extension APIService {
|
||||||
|
|
||||||
func accountVerifyCredentials(
|
func accountVerifyCredentials(
|
||||||
|
@ -33,12 +79,20 @@ extension APIService {
|
||||||
entity: account,
|
entity: account,
|
||||||
userCache: nil,
|
userCache: nil,
|
||||||
networkDate: response.networkDate,
|
networkDate: response.networkDate,
|
||||||
log: log)
|
log: log
|
||||||
|
)
|
||||||
let flag = isCreated ? "+" : "-"
|
let flag = isCreated ? "+" : "-"
|
||||||
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: mastodon user [%s](%s)%s verifed", ((#file as NSString).lastPathComponent), #line, #function, flag, mastodonUser.id, mastodonUser.username)
|
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: mastodon user [%s](%s)%s verifed", ((#file as NSString).lastPathComponent), #line, #function, flag, mastodonUser.id, mastodonUser.username)
|
||||||
}
|
}
|
||||||
.setFailureType(to: Error.self)
|
.setFailureType(to: Error.self)
|
||||||
.map { _ in return response }
|
.tryMap { result -> Mastodon.Response.Content<Mastodon.Entity.Account> in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
return response
|
||||||
|
case .failure(let error):
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
|
@ -72,7 +126,14 @@ extension APIService {
|
||||||
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: mastodon user [%s](%s)%s verifed", ((#file as NSString).lastPathComponent), #line, #function, flag, mastodonUser.id, mastodonUser.username)
|
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: mastodon user [%s](%s)%s verifed", ((#file as NSString).lastPathComponent), #line, #function, flag, mastodonUser.id, mastodonUser.username)
|
||||||
}
|
}
|
||||||
.setFailureType(to: Error.self)
|
.setFailureType(to: Error.self)
|
||||||
.map { _ in return response }
|
.tryMap { result -> Mastodon.Response.Content<Mastodon.Entity.Account> in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
return response
|
||||||
|
case .failure(let error):
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
|
|
Loading…
Reference in New Issue