diff --git a/Mastodon/In Progress New Layout and Datamodel/NotificationRowView.swift b/Mastodon/In Progress New Layout and Datamodel/NotificationRowView.swift index 99b74b07e..812856f14 100644 --- a/Mastodon/In Progress New Layout and Datamodel/NotificationRowView.swift +++ b/Mastodon/In Progress New Layout and Datamodel/NotificationRowView.swift @@ -571,17 +571,10 @@ struct NotificationRowView: View { // VSTACK OF HEADER AND CONTENT COMPONENT VIEWS VStack(spacing: 4) { if let actionSuperheader = viewModel.actionSuperheader { - HStack { - componentView(.weightedText(actionSuperheader.text, .bold)) - .font(.subheadline) - .foregroundColor(actionSuperheader.color) - .frame(height: actionSuperheaderHeight) - if let timestamp = viewModel.timestamp { - Spacer().frame(maxWidth: .infinity) - componentView(.timeSinceLabel(timestamp)) - .foregroundColor(actionSuperheader.color) - } - } + componentView(.weightedText(actionSuperheader.text, .bold)) + .font(.subheadline) + .foregroundColor(actionSuperheader.color) + .frame(height: actionSuperheaderHeight) } ForEach(viewModel.headerComponents) { @@ -612,6 +605,7 @@ struct NotificationRowView: View { .font(.subheadline) .frame(height: actionSuperheaderHeight) .fixedSize(horizontal: true, vertical: false) + .foregroundColor(.secondary) case .weightedText(let string, let weight): textComponent(string, fontWeight: weight) case .status(let statusViewModel): @@ -629,6 +623,16 @@ struct NotificationRowView: View { .tint(Color(asset: Asset.Colors.accent)) case ._other(let string): Text(string) + case .textAndTimeLabel(let string, let date): + HStack(alignment: .top, spacing: 2) { + Text(string) + .frame(maxWidth: .infinity, alignment: .leading) + Text(date.localizedAbbreviatedSlowedTimeAgoSinceNow) + .font(.subheadline) + .frame(height: actionSuperheaderHeight) + .fixedSize(horizontal: true, vertical: false) + .foregroundColor(.secondary) + } } } @@ -746,6 +750,7 @@ func textComponent(_ string: String, fontWeight: SwiftUICore.Font.Weight?) enum NotificationViewComponent: Identifiable { case avatarRow(NotificationSourceAccounts, RelationshipElement) case text(AttributedString) + case textAndTimeLabel(AttributedString, Date) case timeSinceLabel(Date) case weightedText(String, SwiftUICore.Font.Weight) case status(Mastodon.Entity.Status.ViewModel) @@ -768,6 +773,8 @@ enum NotificationViewComponent: Identifiable { return text case ._other(let string): return string + case .textAndTimeLabel(let string, _): + return string.description + "+date" } } } diff --git a/Mastodon/In Progress New Layout and Datamodel/NotificationRowViewModel.swift b/Mastodon/In Progress New Layout and Datamodel/NotificationRowViewModel.swift index 5d7310849..ec89cb374 100644 --- a/Mastodon/In Progress New Layout and Datamodel/NotificationRowViewModel.swift +++ b/Mastodon/In Progress New Layout and Datamodel/NotificationRowViewModel.swift @@ -84,12 +84,21 @@ class NotificationRowViewModel: ObservableObject { .primaryAuthorAccount? .displayNameWithFallback) != nil { - headerTextComponents = [ - .text( - notificationInfo.groupedNotificationType - .actionSummaryLabel(notificationInfo.sourceAccounts) + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) + ?? "", timestamp) + ] + } else { + headerTextComponents = [ + .text( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) ?? "") - ] + ] + } } case .mention, .status: // TODO: eventually make this full status style, not inline @@ -97,12 +106,21 @@ class NotificationRowViewModel: ObservableObject { notificationInfo.statusViewModel { actionSuperheader = NotificationRowViewModel.actionSuperheader(notificationInfo.groupedNotificationType, isReply: statusViewModel.isReplyToMe, isPrivateStatus: statusViewModel.visibility == .direct) - headerTextComponents = [ - .text( - notificationInfo.groupedNotificationType - .actionSummaryLabel(notificationInfo.sourceAccounts) + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) + ?? "", timestamp) + ] + } else { + headerTextComponents = [ + .text( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) ?? "") - ] + ] + } contentComponents = [.status(statusViewModel)] needsPrivateBackground = statusViewModel.visibility == .direct } else { @@ -115,12 +133,21 @@ class NotificationRowViewModel: ObservableObject { avatarRow = .avatarRow( notificationInfo.sourceAccounts, .noneNeeded) - headerTextComponents = [ - .text( - notificationInfo.groupedNotificationType - .actionSummaryLabel(notificationInfo.sourceAccounts) + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) + ?? "", timestamp) + ] + } else { + headerTextComponents = [ + .text( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) ?? "") - ] + ] + } contentComponents = [.status(statusViewModel)] needsPrivateBackground = statusViewModel.visibility == .direct } else { @@ -133,12 +160,21 @@ class NotificationRowViewModel: ObservableObject { if let statusViewModel = notificationInfo.statusViewModel { - headerTextComponents = [ - .text( - notificationInfo.groupedNotificationType - .actionSummaryLabel(notificationInfo.sourceAccounts) + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) + ?? "", timestamp) + ] + } else { + headerTextComponents = [ + .text( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) ?? "") - ] + ] + } contentComponents = [.status(statusViewModel)] needsPrivateBackground = statusViewModel.visibility == .direct } else { @@ -151,15 +187,33 @@ class NotificationRowViewModel: ObservableObject { avatarRow = .avatarRow( notificationInfo.sourceAccounts, .noneNeeded) - headerTextComponents = [ - .text( - notificationInfo.groupedNotificationType.actionSummaryLabel( - notificationInfo.sourceAccounts) ?? "") - ] + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) + ?? "", timestamp) + ] + } else { + headerTextComponents = [ + .text( + notificationInfo.groupedNotificationType + .actionSummaryLabel(notificationInfo.sourceAccounts) + ?? "") + ] + } case .adminReport(let report): actionSuperheader = NotificationRowViewModel.actionSuperheader(notificationInfo.groupedNotificationType, isReply: false, isPrivateStatus: false) if let summary = report?.summary { - headerTextComponents = [.text(summary)] + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel(summary, timestamp) + ] + } else { + headerTextComponents = [ + .text(summary) + ] + } } if let comment = report? .displayableComment @@ -170,7 +224,15 @@ class NotificationRowViewModel: ObservableObject { actionSuperheader = NotificationRowViewModel.actionSuperheader(notificationInfo.groupedNotificationType, isReply: false, isPrivateStatus: false) if let summary = severanceEvent?.summary(myDomain: myAccountDomain) { - headerTextComponents = [.text(summary)] + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel(summary, timestamp) + ] + } else { + headerTextComponents = [ + .text(summary) + ] + } } else { headerTextComponents = [ ._other( @@ -187,11 +249,18 @@ class NotificationRowViewModel: ObservableObject { ] case .moderationWarning(let accountWarning): actionSuperheader = NotificationRowViewModel.actionSuperheader(notificationInfo.groupedNotificationType, isReply: false, isPrivateStatus: false) - headerTextComponents = [ - .weightedText( - (accountWarning?.action ?? .none).actionDescription, - .regular) - ] + if let timestamp = notificationInfo.timestamp { + headerTextComponents = [ + .textAndTimeLabel( + AttributedString((accountWarning?.action ?? .none).actionDescription), timestamp) + ] + } else { + headerTextComponents = [ + .weightedText( + (accountWarning?.action ?? .none).actionDescription, + .regular) + ] + } let learnMoreButton = NotificationViewComponent.hyperlinkButton( L10n.Scene.Notification.Warning.learnMore, @@ -252,7 +321,7 @@ class NotificationRowViewModel: ObservableObject { default: break } - case .text, .weightedText, .status, .hyperlinkButton, ._other, .timeSinceLabel: + case .text, .weightedText, .status, .hyperlinkButton, ._other, .timeSinceLabel, .textAndTimeLabel: break } }