mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
Initial display of grouped notifications
Contributes to IOS-253 Contributes to IOS-355
This commit is contained in:
parent
12d737c4e1
commit
6ec1d9a591
@ -97,7 +97,7 @@ extension DataSourceFacade {
|
||||
notification.transientFollowRequestState = .init(state: .isRejecting)
|
||||
}
|
||||
|
||||
await notificationView.configure(notification: notification, authenticationBox: dependency.authenticationBox)
|
||||
await notificationView.configure(notification: notification)
|
||||
|
||||
do {
|
||||
let newRelationship = try await APIService.shared.followRequest(
|
||||
@ -118,11 +118,11 @@ extension DataSourceFacade {
|
||||
UserInfoKey.relationship: newRelationship
|
||||
])
|
||||
|
||||
await notificationView.configure(notification: notification, authenticationBox: dependency.authenticationBox)
|
||||
await notificationView.configure(notification: notification)
|
||||
} catch {
|
||||
// reset state when failure
|
||||
notification.transientFollowRequestState = .init(state: .none)
|
||||
await notificationView.configure(notification: notification, authenticationBox: dependency.authenticationBox)
|
||||
await notificationView.configure(notification: notification)
|
||||
|
||||
if let error = error as? Mastodon.API.Error {
|
||||
switch error.httpResponseStatus {
|
||||
|
@ -46,7 +46,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Aut
|
||||
completion: { (newRelationship: Mastodon.Entity.Relationship) in
|
||||
notification.relationship = newRelationship
|
||||
Task { @MainActor in
|
||||
notificationView.configure(notification: notification, authenticationBox: self.authenticationBox)
|
||||
notificationView.configure(notification: notification)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -34,13 +34,22 @@ extension NotificationTimelineViewController: DataSourceProvider {
|
||||
case .notification, .notificationGroup:
|
||||
let item: DataSourceItem? = {
|
||||
// guard feed.kind == .notificationAll || feed.kind == .notificationMentions else { return nil }
|
||||
|
||||
if let notification = MastodonFeedItemCacheManager.shared.cachedItem(notificationItem) as? Mastodon.Entity.Notification {
|
||||
let mastodonNotification = MastodonNotification.fromEntity(notification, relationship: nil)
|
||||
return .notification(record: mastodonNotification)
|
||||
} else {
|
||||
return nil
|
||||
if let cachedItem = MastodonFeedItemCacheManager.shared.cachedItem(notificationItem) {
|
||||
if let notification = cachedItem as? Mastodon.Entity.Notification {
|
||||
let mastodonNotification = MastodonNotification.fromEntity(notification, relationship: nil)
|
||||
return .notification(record: mastodonNotification)
|
||||
} else if let notificationGroup = cachedItem as? Mastodon.Entity.NotificationGroup {
|
||||
if let statusID = notificationGroup.statusID, let statusEntity = MastodonFeedItemCacheManager.shared.cachedItem(.status(id: statusID)) as? Mastodon.Entity.Status {
|
||||
let status = MastodonStatus.fromEntity(statusEntity)
|
||||
return .status(record: status)
|
||||
}/* else if notificationGroup.type == .follow {
|
||||
return .followers
|
||||
} */ else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
return item
|
||||
case .status:
|
||||
|
@ -24,12 +24,7 @@ extension NotificationView {
|
||||
return
|
||||
}
|
||||
|
||||
let entity = MastodonNotification.fromEntity(
|
||||
notification,
|
||||
relationship: feed.relationship
|
||||
)
|
||||
|
||||
configure(notification: entity, authenticationBox: authenticationBox)
|
||||
configure(notification: notification)
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,25 +32,39 @@ extension NotificationView {
|
||||
|
||||
public func configure(notificationItem: MastodonFeedItemIdentifier) {
|
||||
let item = MastodonFeedItemCacheManager.shared.cachedItem(notificationItem)
|
||||
guard let notification = item as? Mastodon.Entity.Notification, let authBox = AuthenticationServiceProvider.shared.currentActiveUser.value else { assert(false); return }
|
||||
if let notification = item as? Mastodon.Entity.Notification {
|
||||
configure(notificationType: notification.type, status: notification.status)
|
||||
configure(notification: notification)
|
||||
} else if let notificationGroup = item as? Mastodon.Entity.NotificationGroup {
|
||||
let status: Mastodon.Entity.Status?
|
||||
if let statusID = notificationGroup.statusID {
|
||||
status = MastodonFeedItemCacheManager.shared.cachedItem(.status(id: statusID)) as? Mastodon.Entity.Status
|
||||
} else {
|
||||
status = nil
|
||||
}
|
||||
configure(notificationType: notificationGroup.type, status: status)
|
||||
configure(notificationGroup: notificationGroup)
|
||||
}
|
||||
}
|
||||
|
||||
private func configure(notificationType: Mastodon.Entity.NotificationType, status: Mastodon.Entity.Status?) {
|
||||
func contentDisplayMode(_ status: Mastodon.Entity.Status) -> StatusView.ContentDisplayMode {
|
||||
let contentDisplayModel = StatusView.ContentConcealViewModel(status: status, filterBox: StatusFilterService.shared.activeFilterBox, filterContext: .notifications, showDespiteFilter: MastodonFeedItemCacheManager.shared.shouldShowDespiteFilter(statusID: status.id), showDespiteContentWarning: MastodonFeedItemCacheManager.shared.shouldShowDespiteContentWarning(statusID: status.id))
|
||||
return contentDisplayModel.effectiveDisplayMode
|
||||
}
|
||||
|
||||
switch notification.type {
|
||||
switch notificationType {
|
||||
case .follow:
|
||||
setAuthorContainerBottomPaddingViewDisplay(isHidden: true)
|
||||
case .followRequest:
|
||||
setFollowRequestAdaptiveMarginContainerViewDisplay(isHidden: true)
|
||||
case .mention, .status:
|
||||
if let status = notification.status {
|
||||
if let status {
|
||||
statusView.configure(status: status, contentDisplayMode: contentDisplayMode(status))
|
||||
setStatusViewDisplay()
|
||||
}
|
||||
case .reblog, .favourite, .poll:
|
||||
if let status = notification.status {
|
||||
if let status {
|
||||
quoteStatusView.configure(status: status, contentDisplayMode: contentDisplayMode(status))
|
||||
setQuoteStatusViewDisplay()
|
||||
}
|
||||
@ -66,12 +75,10 @@ extension NotificationView {
|
||||
setAuthorContainerBottomPaddingViewDisplay()
|
||||
assertionFailure()
|
||||
}
|
||||
|
||||
configure(notification: notification, authenticationBox: authBox)
|
||||
}
|
||||
|
||||
public func configure(notification: Mastodon.Entity.Notification, authenticationBox: MastodonAuthenticationBox) {
|
||||
configureAuthor(notification: notification, authenticationBox: authenticationBox)
|
||||
public func configure(notification: Mastodon.Entity.Notification) {
|
||||
configureAuthor(notification: notification)
|
||||
|
||||
func contentDisplayMode(_ status: Mastodon.Entity.Status) -> StatusView.ContentDisplayMode {
|
||||
let contentDisplayModel = StatusView.ContentConcealViewModel(status: status, filterBox: StatusFilterService.shared.activeFilterBox, filterContext: .notifications, showDespiteFilter: MastodonFeedItemCacheManager.shared.shouldShowDespiteFilter(statusID: status.id), showDespiteContentWarning: MastodonFeedItemCacheManager.shared.shouldShowDespiteContentWarning(statusID: status.id))
|
||||
@ -103,8 +110,41 @@ extension NotificationView {
|
||||
|
||||
}
|
||||
|
||||
public func configure(notification: MastodonNotification, authenticationBox: MastodonAuthenticationBox) {
|
||||
configureAuthor(notification: notification, authenticationBox: authenticationBox)
|
||||
public func configure(notificationGroup: Mastodon.Entity.NotificationGroup) {
|
||||
configureAuthors(notificationGroup: notificationGroup)
|
||||
|
||||
func contentDisplayMode(_ status: Mastodon.Entity.Status) -> StatusView.ContentDisplayMode {
|
||||
let contentDisplayModel = StatusView.ContentConcealViewModel(status: status, filterBox: StatusFilterService.shared.activeFilterBox, filterContext: .notifications, showDespiteFilter: MastodonFeedItemCacheManager.shared.shouldShowDespiteFilter(statusID: status.id), showDespiteContentWarning: MastodonFeedItemCacheManager.shared.shouldShowDespiteContentWarning(statusID: status.id))
|
||||
return contentDisplayModel.effectiveDisplayMode
|
||||
}
|
||||
|
||||
switch notificationGroup.type {
|
||||
case .follow:
|
||||
setAuthorContainerBottomPaddingViewDisplay(isHidden: true)
|
||||
case .followRequest:
|
||||
setFollowRequestAdaptiveMarginContainerViewDisplay(isHidden: false)
|
||||
case .mention, .status:
|
||||
if let statusID = notificationGroup.statusID, let status = MastodonFeedItemCacheManager.shared.cachedItem(.status(id: statusID)) as? Mastodon.Entity.Status {
|
||||
statusView.configure(status: status, contentDisplayMode: contentDisplayMode(status))
|
||||
setStatusViewDisplay()
|
||||
}
|
||||
case .reblog, .favourite, .poll:
|
||||
if let statusID = notificationGroup.statusID, let status = MastodonFeedItemCacheManager.shared.cachedItem(.status(id: statusID)) as? Mastodon.Entity.Status {
|
||||
quoteStatusView.configure(status: status, contentDisplayMode: contentDisplayMode(status))
|
||||
setQuoteStatusViewDisplay()
|
||||
}
|
||||
case .moderationWarning:
|
||||
// case handled in `AccountWarningNotificationCell.swift`
|
||||
break
|
||||
case ._other:
|
||||
setAuthorContainerBottomPaddingViewDisplay()
|
||||
assertionFailure()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public func configure(notification: MastodonNotification) {
|
||||
configureAuthor(notification: notification.entity)
|
||||
|
||||
func contentDisplayMode(_ status: MastodonStatus) -> StatusView.ContentDisplayMode {
|
||||
let contentDisplayModel = StatusView.ContentConcealViewModel(status: status, filterBox: StatusFilterService.shared.activeFilterBox, filterContext: .notifications)
|
||||
@ -136,21 +176,33 @@ extension NotificationView {
|
||||
|
||||
}
|
||||
|
||||
private func configureAuthor(notification: Mastodon.Entity.Notification, authenticationBox: MastodonAuthenticationBox) {
|
||||
private func configureAuthors(notificationGroup: Mastodon.Entity.NotificationGroup) {
|
||||
let sampleAuthors: [NotificationAuthor] = notificationGroup.sampleAccountIDs.compactMap { MastodonFeedItemCacheManager.shared.fullAccount($0) ?? MastodonFeedItemCacheManager.shared.partialAccount($0) }
|
||||
configureAuthors(sampleAuthors, notificationID: notificationGroup.id, notificationType: notificationGroup.type, notificationDate: notificationGroup.latestPageNotificationAt)
|
||||
}
|
||||
|
||||
private func configureAuthor(notification: Mastodon.Entity.Notification) {
|
||||
let author = notification.account
|
||||
configureAuthors([author], notificationID: notification.id, notificationType: notification.type, notificationDate: notification.createdAt)
|
||||
}
|
||||
|
||||
private func configureAuthors(_ authors: [NotificationAuthor], notificationID: String, notificationType: Mastodon.Entity.NotificationType, notificationDate: Date?) {
|
||||
guard let author = authors.first as? Mastodon.Entity.Account else { return }
|
||||
let authorsCount = authors.count
|
||||
|
||||
// author avatar
|
||||
avatarButton.avatarImageView.configure(with: author.avatarImageURL())
|
||||
avatarButton.avatarImageView.configure(with: author.avatarURL)
|
||||
avatarButton.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 12)))
|
||||
|
||||
// author name
|
||||
let metaAuthorName: MetaContent
|
||||
let andOthers = authorsCount > 1 ? " and \(authorsCount - 1) others" : ""
|
||||
do {
|
||||
let content = MastodonContent(content: author.displayNameWithFallback, emojis: author.emojis.asDictionary)
|
||||
let content = MastodonContent(content: author.displayNameWithFallback + andOthers, emojis: author.emojis.asDictionary)
|
||||
metaAuthorName = try MastodonMetaContent.convert(document: content)
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
metaAuthorName = PlaintextMetaContent(string: author.displayNameWithFallback)
|
||||
metaAuthorName = PlaintextMetaContent(string: author.displayNameWithFallback + andOthers)
|
||||
}
|
||||
authorNameLabel.configure(content: metaAuthorName)
|
||||
|
||||
@ -160,115 +212,112 @@ extension NotificationView {
|
||||
|
||||
// notification type indicator
|
||||
let notificationIndicatorText: MetaContent?
|
||||
if let type = MastodonNotificationType(rawValue: notification.type.rawValue) {
|
||||
// TODO: fix the i18n. The subject should assert place at the string beginning
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
switch type {
|
||||
case .follow:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.followedYou,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .followRequest:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.requestToFollowYou,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .mention:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.mentionedYou,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .reblog:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.rebloggedYourPost,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .favourite:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.favoritedYourPost,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .poll:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.pollHasEnded,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .status:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: .empty,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case ._other:
|
||||
notificationIndicatorText = nil
|
||||
}
|
||||
|
||||
var actions = [UIAccessibilityCustomAction]()
|
||||
|
||||
// these notifications can be directly actioned to view the profile
|
||||
if type != .follow, type != .followRequest {
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Status.showUserProfile,
|
||||
image: nil
|
||||
) { [weak self] _ in
|
||||
guard let self, let delegate = self.delegate else { return false }
|
||||
delegate.notificationView(self, authorAvatarButtonDidPressed: self.avatarButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if type == .followRequest {
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Actions.confirm,
|
||||
image: Asset.Editing.checkmark20.image
|
||||
) { [weak self] _ in
|
||||
guard let self, let delegate = self.delegate else { return false }
|
||||
delegate.notificationView(self, acceptFollowRequestButtonDidPressed: self.acceptFollowRequestButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Actions.delete,
|
||||
image: Asset.Circles.forbidden20.image
|
||||
) { [weak self] _ in
|
||||
guard let self, let delegate = self.delegate else { return false }
|
||||
delegate.notificationView(self, rejectFollowRequestButtonDidPressed: self.rejectFollowRequestButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
notificationActions = actions
|
||||
|
||||
} else {
|
||||
notificationIndicatorText = nil
|
||||
notificationActions = []
|
||||
return metaContent
|
||||
}
|
||||
|
||||
|
||||
switch notificationType {
|
||||
case .follow:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.followedYou,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .followRequest:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.requestToFollowYou,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .mention:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.mentionedYou,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .reblog:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.rebloggedYourPost,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .favourite:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.favoritedYourPost,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .poll:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: L10n.Scene.Notification.NotificationDescription.pollHasEnded,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .status:
|
||||
notificationIndicatorText = createMetaContent(
|
||||
text: .empty,
|
||||
emojis: author.emojis.asDictionary
|
||||
)
|
||||
case .moderationWarning:
|
||||
#warning("Not implemented")
|
||||
notificationIndicatorText = createMetaContent(text: "Moderation Warning", emojis: author.emojis.asDictionary)
|
||||
case ._other:
|
||||
notificationIndicatorText = nil
|
||||
}
|
||||
|
||||
var actions = [UIAccessibilityCustomAction]()
|
||||
|
||||
// these notifications can be directly actioned to view the profile
|
||||
if notificationType != .follow, notificationType != .followRequest {
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Status.showUserProfile,
|
||||
image: nil
|
||||
) { [weak self] _ in
|
||||
guard let self, let delegate = self.delegate else { return false }
|
||||
delegate.notificationView(self, authorAvatarButtonDidPressed: self.avatarButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if notificationType == .followRequest {
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Actions.confirm,
|
||||
image: Asset.Editing.checkmark20.image
|
||||
) { [weak self] _ in
|
||||
guard let self, let delegate = self.delegate else { return false }
|
||||
delegate.notificationView(self, acceptFollowRequestButtonDidPressed: self.acceptFollowRequestButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
|
||||
actions.append(
|
||||
UIAccessibilityCustomAction(
|
||||
name: L10n.Common.Controls.Actions.delete,
|
||||
image: Asset.Circles.forbidden20.image
|
||||
) { [weak self] _ in
|
||||
guard let self, let delegate = self.delegate else { return false }
|
||||
delegate.notificationView(self, rejectFollowRequestButtonDidPressed: self.rejectFollowRequestButton)
|
||||
return true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
notificationActions = actions
|
||||
|
||||
if let notificationIndicatorText {
|
||||
notificationTypeIndicatorLabel.configure(content: notificationIndicatorText)
|
||||
} else {
|
||||
notificationTypeIndicatorLabel.reset()
|
||||
}
|
||||
|
||||
if let me = authenticationBox.cachedAccount {
|
||||
|
||||
if let me = AuthenticationServiceProvider.shared.currentActiveUser.value?.cachedAccount {
|
||||
let isMyself = (author == me)
|
||||
let isMuting: Bool
|
||||
let isBlocking: Bool
|
||||
|
||||
if let relationship = MastodonFeedItemCacheManager.shared.currentRelationship(toAccount: notification.account.id) {
|
||||
if let relationship = MastodonFeedItemCacheManager.shared.currentRelationship(toAccount: notificationID) {
|
||||
isMuting = relationship.muting
|
||||
isBlocking = relationship.blocking || relationship.domainBlocking
|
||||
} else {
|
||||
@ -285,32 +334,34 @@ extension NotificationView {
|
||||
menuButton.isHidden = menuContext.isMyself
|
||||
}
|
||||
|
||||
timestampUpdatePublisher
|
||||
.prepend(Date())
|
||||
.eraseToAnyPublisher()
|
||||
.sink { [weak self] now in
|
||||
guard let self, let type = MastodonNotificationType(rawValue: notification.type.rawValue) else { return }
|
||||
|
||||
let formattedTimestamp = notification.createdAt.localizedAbbreviatedSlowedTimeAgoSinceNow
|
||||
dateLabel.configure(content: PlaintextMetaContent(string: formattedTimestamp))
|
||||
|
||||
self.accessibilityLabel = [
|
||||
"\(author.displayNameWithFallback) \(type)",
|
||||
author.acct,
|
||||
formattedTimestamp
|
||||
].joined(separator: ", ")
|
||||
if self.statusView.isHidden == false {
|
||||
self.accessibilityLabel! += ", " + (self.statusView.accessibilityLabel ?? "")
|
||||
if let notificationDate {
|
||||
timestampUpdatePublisher
|
||||
.prepend(Date())
|
||||
.eraseToAnyPublisher()
|
||||
.sink { [weak self] now in
|
||||
guard let self else { return }
|
||||
|
||||
let formattedTimestamp = notificationDate.localizedAbbreviatedSlowedTimeAgoSinceNow
|
||||
dateLabel.configure(content: PlaintextMetaContent(string: formattedTimestamp))
|
||||
|
||||
self.accessibilityLabel = [
|
||||
"\(author.displayNameWithFallback) \(notificationType)",
|
||||
author.acct,
|
||||
formattedTimestamp
|
||||
].joined(separator: ", ")
|
||||
if self.statusView.isHidden == false {
|
||||
self.accessibilityLabel! += ", " + (self.statusView.accessibilityLabel ?? "")
|
||||
}
|
||||
if self.quoteStatusViewContainerView.isHidden == false {
|
||||
self.accessibilityLabel! += ", " + (self.quoteStatusView.accessibilityLabel ?? "")
|
||||
}
|
||||
|
||||
}
|
||||
if self.quoteStatusViewContainerView.isHidden == false {
|
||||
self.accessibilityLabel! += ", " + (self.quoteStatusView.accessibilityLabel ?? "")
|
||||
}
|
||||
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
if notification.type == .followRequest {
|
||||
let followRequestState = MastodonFeedItemCacheManager.shared.followRequestState(forFollowRequestNotification: notification.id).state
|
||||
if notificationType == .followRequest {
|
||||
let followRequestState = MastodonFeedItemCacheManager.shared.followRequestState(forFollowRequestNotification: notificationID).state
|
||||
switch followRequestState {
|
||||
case .none:
|
||||
break
|
||||
@ -576,3 +627,15 @@ extension MastodonFollowRequestState.State {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protocol NotificationAuthor {
|
||||
var avatarURL: URL? { get }
|
||||
}
|
||||
|
||||
extension Mastodon.Entity.Account: NotificationAuthor {
|
||||
var avatarURL: URL? { avatarImageURL() }
|
||||
}
|
||||
|
||||
extension Mastodon.Entity.PartialAccountWithAvatar: NotificationAuthor {
|
||||
var avatarURL: URL? { URL(string: avatar) }
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ extension SearchResultViewController {
|
||||
)
|
||||
case .notification, .notificationBanner(_):
|
||||
assertionFailure()
|
||||
break
|
||||
} // end switch
|
||||
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
@ -56,7 +56,7 @@ extension Mastodon.Entity {
|
||||
public let id: ID
|
||||
public let notificationsCount: Int
|
||||
public let type: NotificationType
|
||||
public let mostRecentNotificationID: ID
|
||||
public let mostRecentNotificationID: Int
|
||||
public let pageOldestID: ID? // ID of the oldest notification from this group represented within the current page. This is only returned when paginating through notification groups. Useful when polling new notifications.
|
||||
public let pageNewestID: ID? // ID of the newest notification from this group represented within the current page. This is only returned when paginating through notification groups. Useful when polling new notifications.
|
||||
public let latestPageNotificationAt: Date? // Date at which the most recent notification from this group within the current page has been created. This is only returned when paginating through notification groups.
|
||||
|
@ -209,13 +209,11 @@ public class MastodonFeedItemCacheManager {
|
||||
}
|
||||
|
||||
public func partialAccount(_ id: String) -> Mastodon.Entity.PartialAccountWithAvatar? {
|
||||
assertionFailure("not implemented")
|
||||
return nil
|
||||
return partialAccountsCache[id]
|
||||
}
|
||||
|
||||
public func fullAccount(_ id: String) -> Mastodon.Entity.Account? {
|
||||
assertionFailure("not implemented")
|
||||
return nil
|
||||
return fullAccountsCache[id]
|
||||
}
|
||||
|
||||
private func contentStatusID(forStatus statusID: String) -> String {
|
||||
|
Loading…
x
Reference in New Issue
Block a user