2
2
mirror of https://github.com/mastodon/mastodon-ios synced 2025-04-11 22:58:02 +02:00

Move timestamp to action summary line

Contributes to #399 [BUG] Multiple interactions do not collapse into a single notification
This commit is contained in:
shannon 2025-03-05 17:47:48 -05:00
parent 11fa1c1a90
commit 41c0ae0b13
2 changed files with 120 additions and 44 deletions

View File

@ -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"
}
}
}

View File

@ -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
}
}