Don't use publisher for most properties in NotificationView (IOS-192)

Timestamp and A11y are still missing (and A11y is broken atm)
This commit is contained in:
Nathan Mattes 2024-01-20 20:03:45 +01:00
parent ab2f54307f
commit 018cf54084
4 changed files with 52 additions and 109 deletions

View File

@ -73,7 +73,6 @@ extension NotificationSection {
viewModel: NotificationTableViewCell.ViewModel,
configuration: Configuration
) {
cell.notificationView.viewModel.context = context
cell.notificationView.viewModel.authContext = configuration.authContext
StatusSection.setupStatusPollDataSource(

View File

@ -64,23 +64,32 @@ extension NotificationView {
let author = notification.account
// author avatar
viewModel.authorAvatarImageURL = author.avatarImageURL()
let configuration = AvatarImageView.Configuration(url: author.avatarImageURL())
avatarButton.avatarImageView.configure(configuration: configuration)
avatarButton.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 12)))
// author name
let metaAuthorName: MetaContent
do {
let content = MastodonContent(content: author.displayNameWithFallback, emojis: author.emojis.asDictionary)
viewModel.authorName = try MastodonMetaContent.convert(document: content)
metaAuthorName = try MastodonMetaContent.convert(document: content)
} catch {
assertionFailure(error.localizedDescription)
viewModel.authorName = PlaintextMetaContent(string: author.displayNameWithFallback)
metaAuthorName = PlaintextMetaContent(string: author.displayNameWithFallback)
}
authorNameLabel.configure(content: metaAuthorName)
// username
let metaUsername = PlaintextMetaContent(string: "@\(author.acct)")
authorUsernameLabel.configure(content: metaUsername)
viewModel.authorUsername = author.acct
viewModel.timestamp = notification.entity.createdAt
viewModel.visibility = notification.entity.status?.mastodonVisibility ?? ._other("")
let visibility = notification.entity.status?.mastodonVisibility ?? ._other("")
visibilityIconImageView.image = visibility.image
// notification type indicator
let notificationIndicatorText: MetaContent?
if let type = MastodonNotificationType(rawValue: notification.entity.type.rawValue) {
self.viewModel.type = type
@ -92,64 +101,81 @@ extension NotificationView {
}
return metaContent
}
switch type {
case .follow:
self.viewModel.notificationIndicatorText = createMetaContent(
notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.followedYou,
emojis: author.emojis.asDictionary
)
case .followRequest:
self.viewModel.notificationIndicatorText = createMetaContent(
notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.requestToFollowYou,
emojis: author.emojis.asDictionary
)
case .mention:
self.viewModel.notificationIndicatorText = createMetaContent(
notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.mentionedYou,
emojis: author.emojis.asDictionary
)
case .reblog:
self.viewModel.notificationIndicatorText = createMetaContent(
notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.rebloggedYourPost,
emojis: author.emojis.asDictionary
)
case .favourite:
self.viewModel.notificationIndicatorText = createMetaContent(
notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.favoritedYourPost,
emojis: author.emojis.asDictionary
)
case .poll:
self.viewModel.notificationIndicatorText = createMetaContent(
notificationIndicatorText = createMetaContent(
text: L10n.Scene.Notification.NotificationDescription.pollHasEnded,
emojis: author.emojis.asDictionary
)
case .status:
self.viewModel.notificationIndicatorText = createMetaContent(
notificationIndicatorText = createMetaContent(
text: .empty,
emojis: author.emojis.asDictionary
)
case ._other:
self.viewModel.notificationIndicatorText = nil
notificationIndicatorText = nil
}
} else {
self.viewModel.notificationIndicatorText = nil
notificationIndicatorText = nil
}
if let notificationIndicatorText {
notificationTypeIndicatorLabel.configure(content: notificationIndicatorText)
} else {
notificationTypeIndicatorLabel.reset()
}
if let me = viewModel.authContext?.mastodonAuthenticationBox.authentication.account() {
viewModel.isMyself = (author == me)
let isMyself = (author == me)
let isMuting: Bool
let isBlocking: Bool
if let relationship = notification.relationship {
viewModel.isMuting = relationship.muting
viewModel.isBlocking = relationship.blocking || relationship.domainBlocking
viewModel.isFollowed = relationship.following
isMuting = relationship.muting
isBlocking = relationship.blocking || relationship.domainBlocking
} else {
viewModel.isMuting = false
viewModel.isBlocking = false
viewModel.isFollowed = false
isMuting = false
isBlocking = false
}
let menuContext = NotificationView.AuthorMenuContext(name: metaAuthorName.string, isMuting: isMuting, isBlocking: isBlocking, isMyself: isMyself)
let (menu, actions) = setupAuthorMenu(menuContext: menuContext)
menuButton.menu = menu
authorActions = actions
menuButton.showsMenuAsPrimaryAction = true
menuButton.isHidden = menuContext.isMyself
}
viewModel.followRequestState = notification.followRequestState
viewModel.transientFollowRequestState = notification.transientFollowRequestState
}

View File

@ -21,25 +21,15 @@ extension NotificationView {
public final class ViewModel: ObservableObject {
public var disposeBag = Set<AnyCancellable>()
@Published public var context: AppContext?
@Published public var authContext: AuthContext?
@Published public var type: MastodonNotificationType?
@Published public var notificationIndicatorText: MetaContent?
@Published public var authorAvatarImageURL: URL?
@Published public var authorName: MetaContent?
@Published public var authorUsername: String?
@Published public var isMyself = false
@Published public var isMuting = false
@Published public var isBlocking = false
@Published public var isTranslated = false
@Published public var isFollowed = false
@Published public var timestamp: Date?
@Published public var visibility: MastodonVisibility = .public
@Published public var followRequestState = MastodonFollowRequestState(state: .none)
@Published public var transientFollowRequestState = MastodonFollowRequestState(state: .none)
@ -54,12 +44,8 @@ extension NotificationView {
extension NotificationView.ViewModel {
func bind(notificationView: NotificationView) {
bindAuthor(notificationView: notificationView)
bindAuthorMenu(notificationView: notificationView)
bindFollowRequest(notificationView: notificationView)
$context
.assign(to: \.context, on: notificationView.statusView.viewModel)
.store(in: &disposeBag)
$authContext
.assign(to: \.authContext, on: notificationView.statusView.viewModel)
.store(in: &disposeBag)
@ -69,33 +55,6 @@ extension NotificationView.ViewModel {
}
private func bindAuthor(notificationView: NotificationView) {
// avatar
$authorAvatarImageURL
.sink { url in
let configuration = AvatarImageView.Configuration(url: url)
notificationView.avatarButton.avatarImageView.configure(configuration: configuration)
notificationView.avatarButton.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 12)))
}
.store(in: &disposeBag)
// name
$authorName
.sink { metaContent in
let metaContent = metaContent ?? PlaintextMetaContent(string: " ")
notificationView.authorNameLabel.configure(content: metaContent)
}
.store(in: &disposeBag)
// username
$authorUsername
.map { text -> String in
guard let text = text else { return "" }
return "@\(text)"
}
.sink { username in
let metaContent = PlaintextMetaContent(string: username)
notificationView.authorUsernameLabel.configure(content: metaContent)
}
.store(in: &disposeBag)
// timestamp
let formattedTimestamp = Publishers.CombineLatest(
$timestamp,
@ -112,23 +71,6 @@ extension NotificationView.ViewModel {
}
.store(in: &disposeBag)
$visibility
.sink { visibility in
notificationView.visibilityIconImageView.image = visibility.image
}
.store(in: &disposeBag)
// notification type indicator
$notificationIndicatorText
.sink { text in
if let text = text {
notificationView.notificationTypeIndicatorLabel.configure(content: text)
} else {
notificationView.notificationTypeIndicatorLabel.reset()
}
}
.store(in: &disposeBag)
Publishers.CombineLatest4(
$authorName,
$authorUsername,
@ -197,30 +139,6 @@ extension NotificationView.ViewModel {
.store(in: &disposeBag)
}
private func bindAuthorMenu(notificationView: NotificationView) {
Publishers.CombineLatest4(
$authorName,
$isMuting,
$isBlocking,
$isMyself
)
.sink { [weak self] authorName, isMuting, isBlocking, isMyself in
guard let name = authorName?.string else {
notificationView.menuButton.menu = nil
return
}
let menuContext = NotificationView.AuthorMenuContext(name: name, isMuting: isMuting, isBlocking: isBlocking, isMyself: isMyself)
let (menu, actions) = notificationView.setupAuthorMenu(menuContext: menuContext)
notificationView.menuButton.menu = menu
notificationView.authorActions = actions
notificationView.menuButton.showsMenuAsPrimaryAction = true
notificationView.menuButton.isHidden = menuContext.isMyself
}
.store(in: &disposeBag)
}
private func bindFollowRequest(notificationView: NotificationView) {
Publishers.CombineLatest(
$followRequestState,

View File

@ -181,7 +181,7 @@ public final class NotificationView: UIView {
disposeBag.removeAll()
viewModel.authContext = nil
viewModel.authorAvatarImageURL = nil
avatarButton.avatarImageView.image = nil
avatarButton.avatarImageView.cancelTask()
authorContainerViewBottomPaddingView.isHidden = true