metatext/ViewModels/Sources/ViewModels/StatusViewModel.swift

201 lines
7.1 KiB
Swift
Raw Normal View History

2020-08-21 02:29:01 +00:00
// Copyright © 2020 Metabolist. All rights reserved.
import Combine
2020-09-05 02:31:43 +00:00
import Foundation
2020-08-30 23:33:11 +00:00
import Mastodon
2020-08-31 18:57:02 +00:00
import ServiceLayer
2020-08-21 02:29:01 +00:00
2020-10-05 06:36:22 +00:00
public struct StatusViewModel: CollectionItemViewModel {
2020-09-01 07:33:49 +00:00
public let content: NSAttributedString
public let contentEmoji: [Emoji]
public let displayName: String
public let displayNameEmoji: [Emoji]
public let spoilerText: String
public let isReblog: Bool
public let rebloggedByDisplayName: String
public let rebloggedByDisplayNameEmoji: [Emoji]
public let attachmentViewModels: [AttachmentViewModel]
public let pollOptionTitles: [String]
public let pollEmoji: [Emoji]
2020-10-06 00:33:58 +00:00
public var configuration = CollectionItem.StatusConfiguration.default
2020-10-15 07:44:01 +00:00
public let identification: Identification
2020-09-25 05:39:06 +00:00
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
2020-08-21 02:29:01 +00:00
private let statusService: StatusService
2020-09-25 05:39:06 +00:00
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
2020-08-21 02:29:01 +00:00
2020-10-07 21:06:26 +00:00
init(statusService: StatusService, identification: Identification) {
2020-08-21 02:29:01 +00:00
self.statusService = statusService
2020-10-07 21:06:26 +00:00
self.identification = identification
2020-08-21 02:29:01 +00:00
content = statusService.status.displayStatus.content.attributed
contentEmoji = statusService.status.displayStatus.emojis
displayName = statusService.status.displayStatus.account.displayName == ""
? statusService.status.displayStatus.account.username
: statusService.status.displayStatus.account.displayName
displayNameEmoji = statusService.status.displayStatus.account.emojis
spoilerText = statusService.status.displayStatus.spoilerText
isReblog = statusService.status.reblog != nil
rebloggedByDisplayName = statusService.status.account.displayName == ""
? statusService.status.account.username
: statusService.status.account.displayName
rebloggedByDisplayNameEmoji = statusService.status.account.emojis
2020-08-28 19:56:28 +00:00
attachmentViewModels = statusService.status.displayStatus.mediaAttachments
2020-10-22 05:05:50 +00:00
.map { AttachmentViewModel(attachment: $0, status: statusService.status) }
2020-08-21 02:29:01 +00:00
pollOptionTitles = statusService.status.displayStatus.poll?.options.map { $0.title } ?? []
pollEmoji = statusService.status.displayStatus.poll?.emojis ?? []
2020-09-14 23:32:34 +00:00
events = eventsSubject.eraseToAnyPublisher()
}
}
2020-09-01 07:33:49 +00:00
public extension StatusViewModel {
2020-10-14 00:03:01 +00:00
var shouldShowContent: Bool {
2020-10-11 00:02:02 +00:00
guard spoilerText != "" else { return true }
2020-10-07 21:06:26 +00:00
if identification.identity.preferences.readingExpandSpoilers {
2020-10-14 00:03:01 +00:00
return !configuration.showContentToggled
2020-08-21 02:29:01 +00:00
} else {
2020-10-14 00:03:01 +00:00
return configuration.showContentToggled
2020-08-21 02:29:01 +00:00
}
}
2020-10-14 00:03:01 +00:00
var shouldShowAttachments: Bool {
switch identification.identity.preferences.readingExpandMedia {
case .default, .unknown:
return !sensitive || configuration.showAttachmentsToggled
case .showAll:
return !configuration.showAttachmentsToggled
case .hideAll:
return configuration.showAttachmentsToggled
}
}
var shouldShowHideAttachmentsButton: Bool {
sensitive || identification.identity.preferences.readingExpandMedia == .hideAll
}
2020-08-21 02:29:01 +00:00
var accountName: String { "@" + statusService.status.displayStatus.account.acct }
var avatarURL: URL { statusService.status.displayStatus.account.avatar }
2020-10-15 07:44:01 +00:00
var avatarStaticURL: URL { statusService.status.displayStatus.account.avatarStatic }
2020-08-21 02:29:01 +00:00
var time: String? { statusService.status.displayStatus.createdAt.timeAgo }
var contextParentTime: String {
Self.contextParentDateFormatter.string(from: statusService.status.displayStatus.createdAt)
}
var applicationName: String? { statusService.status.displayStatus.application?.name }
var applicationURL: URL? {
guard let website = statusService.status.displayStatus.application?.website else { return nil }
return URL(string: website)
}
var repliesCount: Int { statusService.status.displayStatus.repliesCount }
var reblogsCount: Int { statusService.status.displayStatus.reblogsCount }
var favoritesCount: Int { statusService.status.displayStatus.favouritesCount }
2020-08-24 02:50:54 +00:00
var reblogged: Bool { statusService.status.displayStatus.reblogged }
2020-08-21 02:29:01 +00:00
2020-08-24 02:50:54 +00:00
var favorited: Bool { statusService.status.displayStatus.favourited }
2020-08-21 02:29:01 +00:00
var sensitive: Bool { statusService.status.displayStatus.sensitive }
var sharingURL: URL? { statusService.status.displayStatus.url }
2020-09-29 01:14:43 +00:00
var cardViewModel: CardViewModel? {
if let card = statusService.status.displayStatus.card {
return CardViewModel(card: card)
} else {
return nil
}
}
2020-08-21 02:29:01 +00:00
var canBeReblogged: Bool {
switch statusService.status.displayStatus.visibility {
case .direct, .private:
return false
default:
return true
}
}
2020-08-24 02:50:54 +00:00
2020-10-14 00:03:01 +00:00
func toggleShowContent() {
eventsSubject.send(
statusService.toggleShowContent()
2020-10-20 06:41:10 +00:00
.map { _ in .ignorableOutput }
2020-10-14 00:03:01 +00:00
.eraseToAnyPublisher())
}
func toggleShowAttachments() {
2020-10-07 21:06:26 +00:00
eventsSubject.send(
2020-10-14 00:03:01 +00:00
statusService.toggleShowAttachments()
2020-10-20 06:41:10 +00:00
.map { _ in .ignorableOutput }
2020-10-07 21:06:26 +00:00
.eraseToAnyPublisher())
}
2020-09-15 01:39:35 +00:00
func urlSelected(_ url: URL) {
eventsSubject.send(
2020-09-25 05:39:06 +00:00
statusService.navigationService.item(url: url)
2020-10-20 06:41:10 +00:00
.map { .navigation($0) }
2020-09-15 01:39:35 +00:00
.setFailureType(to: Error.self)
.eraseToAnyPublisher())
}
2020-09-22 06:53:11 +00:00
func accountSelected() {
eventsSubject.send(
2020-10-20 06:41:10 +00:00
Just(.navigation(
2020-09-27 02:03:53 +00:00
.profile(
statusService.navigationService.profileService(
account: statusService.status.displayStatus.account))))
2020-09-22 06:53:11 +00:00
.setFailureType(to: Error.self)
.eraseToAnyPublisher())
}
2020-09-28 23:23:41 +00:00
func rebloggedBySelected() {
eventsSubject.send(
2020-10-20 06:41:10 +00:00
Just(.navigation(.collection(statusService.rebloggedByService())))
2020-09-28 23:23:41 +00:00
.setFailureType(to: Error.self)
.eraseToAnyPublisher())
}
2020-09-23 01:00:56 +00:00
func favoritedBySelected() {
2020-09-25 05:39:06 +00:00
eventsSubject.send(
2020-10-20 06:41:10 +00:00
Just(.navigation(.collection(statusService.favoritedByService())))
2020-09-25 05:39:06 +00:00
.setFailureType(to: Error.self)
.eraseToAnyPublisher())
2020-09-23 01:00:56 +00:00
}
2020-08-24 02:50:54 +00:00
func toggleFavorited() {
2020-09-25 05:39:06 +00:00
eventsSubject.send(
statusService.toggleFavorited()
2020-10-20 06:41:10 +00:00
.map { _ in .ignorableOutput }
2020-09-25 05:39:06 +00:00
.eraseToAnyPublisher())
2020-09-14 23:32:34 +00:00
}
2020-10-20 06:41:10 +00:00
func attachmentSelected(viewModel: AttachmentViewModel) {
eventsSubject.send(Just(.attachment(viewModel, self)).setFailureType(to: Error.self).eraseToAnyPublisher())
}
2020-09-14 23:32:34 +00:00
func shareStatus() {
guard let url = statusService.status.displayStatus.url else { return }
2020-10-20 06:41:10 +00:00
eventsSubject.send(Just(.share(url)).setFailureType(to: Error.self).eraseToAnyPublisher())
2020-08-24 02:50:54 +00:00
}
2020-08-21 02:29:01 +00:00
}
private extension StatusViewModel {
private static let contextParentDateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .short
return dateFormatter
}()
}