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:
1 parent
963565b316
commit
a4d9831691
11 files changed
+263
-12
No files matched your search
@@ -72,6 +72,9 @@ public static class APIs
|
||||
public static string GET_M_ListTimeline(string listId) => $"api/v1/timelines/list/{Uri.EscapeDataString(listId)}";
|
||||
public const string GET_ScheduledStatuses = "api/v1/scheduled_statuses";
|
||||
public const string GET_FollowedTags = "api/v1/followed_tags";
|
||||
public const string GET_GroupedNotifications = "api/v2/notifications";
|
||||
public const string GET_UnreadNotifications = "api/v2/notifications/unread_count";
|
||||
public const string POST_Markers = "api/v1/markers";
|
||||
public const string GET_TrendingTags = "api/v1/trends/tags";
|
||||
public const string GET_TrendingStatuses = "api/v1/trends/statuses";
|
||||
public const string GET_TrendingLinks = "api/v1/trends/links";
|
||||
|
||||
+33
-3
@@ -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,
|
||||
|
||||
@@ -12,6 +12,45 @@ public class Notification
|
||||
public Account Account { get; set; }
|
||||
public Status Status { get; set; }
|
||||
public string Emoji { get; set; }
|
||||
/// <summary>The group it belongs to (likes and boosts of one post, follows within an hour), or ungrouped-{id}.</summary>
|
||||
public string GroupKey { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>/api/v2/notifications: notifications folded into groups, with the accounts and posts they name.</summary>
|
||||
public class GroupedNotifications
|
||||
{
|
||||
public List<Account> Accounts { get; set; } = [];
|
||||
public List<Status> Statuses { get; set; } = [];
|
||||
public List<NotificationGroup> NotificationGroups { get; set; } = [];
|
||||
}
|
||||
|
||||
public class NotificationGroup
|
||||
{
|
||||
public string GroupKey { get; set; }
|
||||
public int NotificationsCount { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string MostRecentNotificationId { get; set; }
|
||||
public string PageMinId { get; set; }
|
||||
public string PageMaxId { get; set; }
|
||||
public DateTime LatestPageNotificationAt { get; set; }
|
||||
public List<string> SampleAccountIds { get; set; } = [];
|
||||
public string StatusId { get; set; }
|
||||
public string Emoji { get; set; }
|
||||
}
|
||||
|
||||
public class MarkersForm
|
||||
{
|
||||
public MarkerForm Notifications { get; set; }
|
||||
}
|
||||
|
||||
public class MarkerForm
|
||||
{
|
||||
public string LastReadId { get; set; }
|
||||
}
|
||||
|
||||
public class UnreadCount
|
||||
{
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>A direct conversation: its participants and its last post.</summary>
|
||||
|
||||
Reference in new issue
Block a user