From c73784aa81af5025a5805c7d50cf64c1af1752de Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Mon, 1 Apr 2024 19:51:57 -0400 Subject: [PATCH] Mark notifications on Mastodon web frontend as read once displayed Fixes #357 --- ...otificationsCollectionViewController.swift | 50 +++++++++++++++++++ .../NotificationsPageViewController.swift | 1 + 2 files changed, 51 insertions(+) diff --git a/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift b/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift index 54d93899..b9129385 100644 --- a/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift @@ -12,6 +12,9 @@ import Combine #if canImport(Sentry) import Sentry #endif +import OSLog + +private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "NotificationsCVC") class NotificationsCollectionViewController: UIViewController, TimelineLikeCollectionViewController, CollectionViewController { @@ -32,6 +35,9 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle private var newer: RequestRange? private var older: RequestRange? + var updatesNotificationsMarker: Bool = false + private var newestDisplayedNotification: Item? + init(allowedTypes: [Pachyderm.Notification.Kind], mastodonController: MastodonController) { self.allowedTypes = allowedTypes self.mastodonController = mastodonController @@ -205,6 +211,12 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle } } + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + updateNotificationsMarkerIfNecessary() + } + @objc func refresh() { Task { @MainActor in if case .notLoadedInitial = controller.state { @@ -311,6 +323,23 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle await apply(snapshot, animatingDifferences: true) } + private func updateNotificationsMarkerIfNecessary() { + guard updatesNotificationsMarker, + case let .group(group, _, _) = newestDisplayedNotification, + let notification = group.notifications.first else { + return + } + logger.debug("Updating notifications marker with \(notification.id)") + Task { + let req = TimelineMarkers.update(timeline: .notifications, lastReadID: notification.id) + do { + _ = try await mastodonController.run(req) + } catch { + logger.error("Failed to update notifications marker: \(String(describing: error))") + } + } + } + } extension NotificationsCollectionViewController { @@ -545,6 +574,21 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate { guard case .notifications = dataSource.sectionIdentifier(for: indexPath.section) else { return } + + if updatesNotificationsMarker { + let shouldUpdateNewestDisplayedNotification: Bool + if let newestDisplayedNotification, + let currentNewestIndexPath = dataSource.indexPath(for: newestDisplayedNotification) { + shouldUpdateNewestDisplayedNotification = indexPath < currentNewestIndexPath + } else { + shouldUpdateNewestDisplayedNotification = true + } + if shouldUpdateNewestDisplayedNotification, + let item = dataSource.itemIdentifier(for: indexPath) { + newestDisplayedNotification = item + } + } + let itemsInSection = collectionView.numberOfItems(inSection: indexPath.section) if indexPath.row == itemsInSection - 1 { Task { @@ -765,3 +809,9 @@ extension NotificationsCollectionViewController: StatusBarTappableViewController return .stop } } + +extension NotificationsCollectionViewController: BackgroundableViewController { + func sceneDidEnterBackground() { + updateNotificationsMarkerIfNecessary() + } +} diff --git a/Tusker/Screens/Notifications/NotificationsPageViewController.swift b/Tusker/Screens/Notifications/NotificationsPageViewController.swift index 1c870288..e8f2122c 100644 --- a/Tusker/Screens/Notifications/NotificationsPageViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsPageViewController.swift @@ -24,6 +24,7 @@ class NotificationsPageViewController: SegmentedPageViewController