mastodon-ios/Mastodon/Scene/Share/View/Content/NotificationView+Configurat...

200 lines
7.4 KiB
Swift

//
// NotificationView+Configuration.swift
// Mastodon
//
// Created by MainasuK on 2022-1-21.
//
import UIKit
import Combine
import MastodonUI
import CoreDataStack
import MetaTextKit
import MastodonMeta
import Meta
import MastodonAsset
import MastodonLocalization
import class CoreDataStack.Notification
extension NotificationView {
public func configure(feed: Feed) {
guard let notification = feed.notification else {
assertionFailure()
return
}
configure(notification: notification)
}
}
extension NotificationView {
public func configure(notification: Notification) {
configureAuthor(notification: notification)
guard let type = MastodonNotificationType(rawValue: notification.typeRaw) else {
assertionFailure()
return
}
if let status = notification.status {
switch type {
case .follow, .followRequest:
setAuthorContainerBottomPaddingViewDisplay()
case .mention, .status:
statusView.configure(status: status)
setStatusViewDisplay()
case .reblog, .favourite, .poll:
quoteStatusView.configure(status: status)
setQuoteStatusViewDisplay()
case ._other:
setAuthorContainerBottomPaddingViewDisplay()
assertionFailure()
}
} else {
setAuthorContainerBottomPaddingViewDisplay()
}
}
}
extension NotificationView {
private func configureAuthor(notification: Notification) {
let author = notification.account
// author avatar
Publishers.CombineLatest(
author.publisher(for: \.avatar),
UserDefaults.shared.publisher(for: \.preferredStaticAvatar)
)
.map { _ in author.avatarImageURL() }
.assign(to: \.authorAvatarImageURL, on: viewModel)
.store(in: &disposeBag)
// author name
Publishers.CombineLatest(
author.publisher(for: \.displayName),
author.publisher(for: \.emojis)
)
.map { _, emojis in
do {
let content = MastodonContent(content: author.displayNameWithFallback, emojis: emojis.asDictionary)
let metaContent = try MastodonMetaContent.convert(document: content)
return metaContent
} catch {
assertionFailure(error.localizedDescription)
return PlaintextMetaContent(string: author.displayNameWithFallback)
}
}
.assign(to: \.authorName, on: viewModel)
.store(in: &disposeBag)
// author username
author.publisher(for: \.acct)
.map { $0 as String? }
.assign(to: \.authorUsername, on: viewModel)
.store(in: &disposeBag)
// timestamp
viewModel.timestamp = notification.createAt
// notification type indicator
Publishers.CombineLatest3(
notification.publisher(for: \.typeRaw),
author.publisher(for: \.displayName),
author.publisher(for: \.emojis)
)
.sink { [weak self] typeRaw, _, emojis in
guard let self = self else { return }
guard let type = MastodonNotificationType(rawValue: typeRaw) else {
self.viewModel.notificationIndicatorText = nil
return
}
func createMetaContent(text: String, emojis: MastodonContent.Emojis) -> MetaContent {
let content = MastodonContent(content: text, emojis: emojis)
guard let metaContent = try? MastodonMetaContent.convert(document: content) else {
return PlaintextMetaContent(string: text)
}
return metaContent
}
// TODO: fix the i18n. The subject should assert place at the string beginning
switch type {
case .follow:
self.viewModel.notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.followedYou,
emojis: emojis.asDictionary
)
case .followRequest:
self.viewModel.notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.requestToFollowYou,
emojis: emojis.asDictionary
)
case .mention:
self.viewModel.notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.mentionedYou,
emojis: emojis.asDictionary
)
case .reblog:
self.viewModel.notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.rebloggedYourPost,
emojis: emojis.asDictionary
)
case .favourite:
self.viewModel.notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.favoritedYourPost,
emojis: emojis.asDictionary
)
case .poll:
self.viewModel.notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.pollHasEnded,
emojis: emojis.asDictionary
)
case .status:
self.viewModel.notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.mentionedYou,
emojis: emojis.asDictionary
)
case ._other:
self.viewModel.notificationIndicatorText = nil
}
}
.store(in: &disposeBag)
// isMuting
Publishers.CombineLatest(
viewModel.$userIdentifier,
author.publisher(for: \.mutingBy)
)
.map { userIdentifier, mutingBy in
guard let userIdentifier = userIdentifier else { return false }
return mutingBy.contains(where: {
$0.id == userIdentifier.userID && $0.domain == userIdentifier.domain
})
}
.assign(to: \.isMuting, on: viewModel)
.store(in: &disposeBag)
// isBlocking
Publishers.CombineLatest(
viewModel.$userIdentifier,
author.publisher(for: \.blockingBy)
)
.map { userIdentifier, blockingBy in
guard let userIdentifier = userIdentifier else { return false }
return blockingBy.contains(where: {
$0.id == userIdentifier.userID && $0.domain == userIdentifier.domain
})
}
.assign(to: \.isBlocking, on: viewModel)
.store(in: &disposeBag)
// isMyself
Publishers.CombineLatest3(
viewModel.$userIdentifier,
author.publisher(for: \.domain),
author.publisher(for: \.id)
)
.map { userIdentifier, domain, id in
guard let userIdentifier = userIdentifier else { return false }
return userIdentifier.domain == domain
&& userIdentifier.userID == id
}
.assign(to: \.isMyself, on: viewModel)
.store(in: &disposeBag)
}
}