// // 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) } }