Notifications in groups, and what is unread

The Notifications tab reads grouped notifications (/api/v2/notifications):
likes and boosts of one post, or follows of one hour, are one card naming
both accounts of a pair, or the newest and how many others, with their
avatars. A notification the stream tells joins its group and waits on top.
The tab's badge counts what is unread; opening the tab moves the
notifications marker to the newest shown, which reads it on PrivaPub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-05 04:35:23 +02:00
1 parent 963565b316
commit a4d9831691
11 files changed
+263 -12

No files matched your search

+33 -3
View File
@@ -17,7 +17,11 @@ public class FeedPost
/// <summary>The post shown; null for a notification without one (a follow).</summary>
public Status Status { get; set; }
public Account BoostedBy { get; init; }
public Notification Notification { get; init; }
public Notification Notification { get; set; }
/// <summary>For a notification standing for a group (likes of one post, follows of one hour): how many, and a few of
/// the accounts, newest first.</summary>
public int GroupCount { get; set; } = 1;
public List<Account> GroupAccounts { get; set; } = [];
public Conversation Conversation { get; init; }
/// <summary>A located post: within its range of the reader, never on the Mastodon API.</summary>
public bool Located { get; init; }
@@ -43,12 +47,38 @@ public class FeedPost
public static FeedPost Of(Notification notification) => new()
{
Key = notification.Id,
Key = notification.GroupKey ?? notification.Id,
CursorId = notification.Id,
Status = notification.Status?.Reblog ?? notification.Status,
Notification = notification
Notification = notification,
GroupAccounts = notification.Account is null ? [] : [notification.Account]
};
/// <summary>A group of notifications as one item: its newest notification, how many it holds, and a few accounts.</summary>
public static FeedPost Of(NotificationGroup group, IReadOnlyDictionary<string, Account> accounts, IReadOnlyDictionary<string, Status> statuses)
{
var sample = group.SampleAccountIds.Select(accounts.GetValueOrDefault).Where(a => a is not null).ToList();
var status = group.StatusId is null ? null : statuses.GetValueOrDefault(group.StatusId);
return new()
{
Key = group.GroupKey,
CursorId = group.MostRecentNotificationId,
Status = status?.Reblog ?? status,
Notification = new Notification
{
Id = group.MostRecentNotificationId,
Type = group.Type,
CreatedAt = group.LatestPageNotificationAt,
Account = sample.FirstOrDefault(),
Status = status,
Emoji = group.Emoji,
GroupKey = group.GroupKey
},
GroupCount = Math.Max(1, group.NotificationsCount),
GroupAccounts = sample
};
}
public static FeedPost Of(Conversation conversation) => new()
{
Key = conversation.Id,