krz/hutch
an ios client for sourcehut
clone: git clone https://gitbay.org/krz/hutch.git
eff81f34bb51ecc6e0aa5d831567db2cea0527a9
verified · cmc
author: Christian Cleberg <hello@cleberg.net> · 2026-07-16T00:31:17Z
Hutch/App/RootView.swift | 6 +++--- Hutch/Models/Inbox.swift | 5 ++++- Hutch/Views/Home/HomeViewModel.swift | 6 +++--- Hutch/Views/Lookup/LookupView.swift | 6 +++--- Hutch/Views/Projects/ProjectMailingListView.swift | 6 +++--- 5 files changed, 16 insertions(+), 13 deletions(-) @@ -476,15 +476,15 @@ private struct MoreNavigationRoot: View { ThreadDetailView( thread: thread, onViewed: { - InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.id, defaults: appState.accountDefaults) + InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.threadGroupingKey, defaults: appState.accountDefaults) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: -1, accountID: appState.activeAccountID) }, onMarkRead: { - InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.id, defaults: appState.accountDefaults) + InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.threadGroupingKey, defaults: appState.accountDefaults) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: -1, accountID: appState.activeAccountID) }, onMarkUnread: { - InboxReadStateStore.markUnread(for: thread.id, defaults: appState.accountDefaults) + InboxReadStateStore.markUnread(for: thread.threadGroupingKey, defaults: appState.accountDefaults) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: 1, accountID: appState.activeAccountID) } ) @@ -17,8 +17,11 @@ struct InboxThreadSummary: Identifiable, Hashable, Sendable { let containsPatch: Bool let isUnread: Bool + /// Identity is per-thread, keyed on the root Message-ID. It deliberately differs + /// from ``threadGroupingKey``, which is subject-based so replies collapse into + /// one conversation — two unrelated threads can share a subject on the same list. var id: String { - threadGroupingKey + "\(listRID)#\(rootMessageID)" } var listDisplayName: String { @@ -622,7 +622,7 @@ final class HomeViewModel { } func markInboxThreadRead(_ thread: InboxThreadSummary) { - InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.id, defaults: defaults) + InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.threadGroupingKey, defaults: defaults) unreadInboxThreads.removeAll { $0.id == thread.id } unreadInboxThreadCount = max((unreadInboxThreadCount ?? 1) - 1, 0) hasUnreadInboxThreads = (unreadInboxThreadCount ?? 0) > 0 @@ -634,7 +634,7 @@ final class HomeViewModel { let viewedAt = Date() for thread in unreadInboxThreads { - InboxReadStateStore.markViewed(max(viewedAt, thread.lastActivityAt), for: thread.id, defaults: defaults) + InboxReadStateStore.markViewed(max(viewedAt, thread.lastActivityAt), for: thread.threadGroupingKey, defaults: defaults) } unreadInboxThreads = [] @@ -644,7 +644,7 @@ final class HomeViewModel { } func markInboxThreadUnread(_ thread: InboxThreadSummary) { - InboxReadStateStore.markUnread(for: thread.id, defaults: defaults) + InboxReadStateStore.markUnread(for: thread.threadGroupingKey, defaults: defaults) if unreadInboxThreads.contains(where: { $0.id == thread.id }) == false { unreadInboxThreads.append( InboxThreadSummary( @@ -469,15 +469,15 @@ struct LookupView: View { ThreadDetailView( thread: thread, onViewed: { - InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.id, defaults: appState.accountDefaults) + InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.threadGroupingKey, defaults: appState.accountDefaults) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: -1, accountID: appState.activeAccountID) }, onMarkRead: { - InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.id, defaults: appState.accountDefaults) + InboxReadStateStore.markViewed(max(Date(), thread.lastActivityAt), for: thread.threadGroupingKey, defaults: appState.accountDefaults) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: -1, accountID: appState.activeAccountID) }, onMarkUnread: { - InboxReadStateStore.markUnread(for: thread.id, defaults: appState.accountDefaults) + InboxReadStateStore.markUnread(for: thread.threadGroupingKey, defaults: appState.accountDefaults) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: 1, accountID: appState.activeAccountID) } ) @@ -94,13 +94,13 @@ final class MailingListDetailViewModel { func markThreadRead(_ thread: InboxThreadSummary) { let viewedAt = max(Date(), thread.lastActivityAt) - InboxReadStateStore.markViewed(viewedAt, for: thread.id, defaults: defaults) + InboxReadStateStore.markViewed(viewedAt, for: thread.threadGroupingKey, defaults: defaults) updateThread(thread, isUnread: false) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: -1, accountID: accountID) } func markThreadUnread(_ thread: InboxThreadSummary) { - InboxReadStateStore.markUnread(for: thread.id, defaults: defaults) + InboxReadStateStore.markUnread(for: thread.threadGroupingKey, defaults: defaults) updateThread(thread, isUnread: true) NeedsAttentionSnapshotStore.adjustUnreadInboxThreads(by: 1, accountID: accountID) } @@ -111,7 +111,7 @@ final class MailingListDetailViewModel { let viewedAt = Date() for thread in unreadThreads { - InboxReadStateStore.markViewed(max(viewedAt, thread.lastActivityAt), for: thread.id, defaults: defaults) + InboxReadStateStore.markViewed(max(viewedAt, thread.lastActivityAt), for: thread.threadGroupingKey, defaults: defaults) } threads = threads.map { thread in