mirror of
https://codeberg.org/secana/Forji.git
synced 2026-07-04 09:45:46 -07:00
Mark notification thread as read when opened
Opening a notification did not clear it because the unread badge is driven by the server's unread count and the open paths never called markAsRead. This marks the thread read on open in three navigation paths: NotificationsOverviewView (tapping a row), MergedNotificationsOverviewView (multi-instance list), and AppDelegate.didReceive (system notification default action). Rows update in place so navigation isn't interrupted; the now-read row leaves the Unread filter on the next refresh. Swipe-to-read and swipe-to-dismiss are unchanged. Fixes #32. Generated with Claude Opus 4.8 (1M)
This commit is contained in:
parent
992c628abd
commit
d69674b3ab
3 changed files with 28 additions and 4 deletions
|
|
@ -59,6 +59,8 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
|
|||
if response.actionIdentifier == "MARK_READ" {
|
||||
await markNotificationAsRead(userInfo: userInfo, serverURL: serverURL, username: username)
|
||||
} else {
|
||||
// Opening the notification clears it, the same as tapping it inside the app.
|
||||
await markNotificationAsRead(userInfo: userInfo, serverURL: serverURL, username: username)
|
||||
await MainActor.run {
|
||||
NavigationState.shared.navigateToNotifications(serverURL: serverURL, username: username)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ struct MergedNotificationsOverviewView: View {
|
|||
NavigationLink { destination } label: {
|
||||
MergedNotificationRow(notification: notification, instanceName: tagged.instanceName)
|
||||
}
|
||||
.simultaneousGesture(TapGesture().onEnded {
|
||||
Task { await markReadOnOpen(tagged) }
|
||||
})
|
||||
} else {
|
||||
MergedNotificationRow(notification: notification, instanceName: tagged.instanceName)
|
||||
}
|
||||
|
|
@ -193,14 +196,22 @@ struct MergedNotificationsOverviewView: View {
|
|||
await setNotificationRead(tagged)
|
||||
}
|
||||
|
||||
private func setNotificationRead(_ tagged: TaggedItem<NotificationThread>) async {
|
||||
/// Marks a notification read when the user opens it, mirroring Mail and News.
|
||||
/// The row is updated in place rather than removed so navigation into the
|
||||
/// detail view is not interrupted while the list is mutating.
|
||||
private func markReadOnOpen(_ tagged: TaggedItem<NotificationThread>) async {
|
||||
guard tagged.item.unread else { return }
|
||||
await setNotificationRead(tagged, removeFromUnread: false)
|
||||
}
|
||||
|
||||
private func setNotificationRead(_ tagged: TaggedItem<NotificationThread>, removeFromUnread: Bool = true) async {
|
||||
guard let client = tagged.authService.client else { return }
|
||||
let service = NotificationService(client: client)
|
||||
let notification = tagged.item
|
||||
do {
|
||||
try await service.markAsRead(id: notification.id)
|
||||
withAnimation {
|
||||
if statusFilter == "unread" {
|
||||
if removeFromUnread, statusFilter == "unread" {
|
||||
pagination.items.removeAll { $0.id == tagged.id }
|
||||
} else if let index = pagination.items.firstIndex(where: { $0.id == tagged.id }) {
|
||||
let updated = NotificationThread(
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ struct NotificationsOverviewView: View {
|
|||
NavigationLink { destination } label: {
|
||||
NotificationRow(notification: notification)
|
||||
}
|
||||
.simultaneousGesture(TapGesture().onEnded {
|
||||
Task { await markReadOnOpen(notification) }
|
||||
})
|
||||
} else {
|
||||
NotificationRow(notification: notification)
|
||||
}
|
||||
|
|
@ -182,12 +185,20 @@ struct NotificationsOverviewView: View {
|
|||
await setNotificationRead(notification)
|
||||
}
|
||||
|
||||
private func setNotificationRead(_ notification: NotificationThread) async {
|
||||
/// Marks a notification read when the user opens it, mirroring Mail and News.
|
||||
/// The row is updated in place rather than removed so navigation into the
|
||||
/// detail view is not interrupted while the list is mutating.
|
||||
private func markReadOnOpen(_ notification: NotificationThread) async {
|
||||
guard notification.unread else { return }
|
||||
await setNotificationRead(notification, removeFromUnread: false)
|
||||
}
|
||||
|
||||
private func setNotificationRead(_ notification: NotificationThread, removeFromUnread: Bool = true) async {
|
||||
guard let notificationService else { return }
|
||||
do {
|
||||
try await notificationService.markAsRead(id: notification.id)
|
||||
withAnimation {
|
||||
if statusFilter == "unread" {
|
||||
if removeFromUnread, statusFilter == "unread" {
|
||||
pagination.items.removeAll { $0.id == notification.id }
|
||||
} else if let index = pagination.items.firstIndex(where: { $0.id == notification.id }) {
|
||||
pagination.items[index] = NotificationThread(
|
||||
|
|
|
|||
Loading…
Reference in a new issue