diff --git a/Mastodon/Service/NotificationService.swift b/Mastodon/Service/NotificationService.swift index e4e7508a3..0d12d54ab 100644 --- a/Mastodon/Service/NotificationService.swift +++ b/Mastodon/Service/NotificationService.swift @@ -12,9 +12,12 @@ import CoreData import CoreDataStack import MastodonSDK import AppShared +import MastodonLocalization final class NotificationService { + public static let unreadShortcutItemIdentifier = "org.joinmastodon.app.NotificationService.unread-shortcut" + var disposeBag = Set() let workingQueue = DispatchQueue(label: "org.joinmastodon.app.NotificationService.working-queue") @@ -74,6 +77,9 @@ final class NotificationService { UserDefaults.shared.notificationBadgeCount = count UIApplication.shared.applicationIconBadgeNumber = count + Task { @MainActor in + UIApplication.shared.shortcutItems = try? await self.unreadApplicationShortcutItems() + } self.unreadNotificationCountDidUpdate.send() } @@ -100,6 +106,38 @@ extension NotificationService { } } +extension NotificationService { + public func unreadApplicationShortcutItems() async throws -> [UIApplicationShortcutItem] { + guard let authenticationService = self.authenticationService else { return [] } + let managedObjectContext = authenticationService.managedObjectContext + return try await managedObjectContext.perform { + var items: [UIApplicationShortcutItem] = [] + for object in authenticationService.mastodonAuthentications.value { + guard let authentication = managedObjectContext.object(with: object.objectID) as? MastodonAuthentication else { continue } + + let accessToken = authentication.userAccessToken + let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken) + guard count > 0 else { continue } + + let title = "@\(authentication.user.acctWithDomain)" + let subtitle = L10n.A11y.Plural.Count.Unread.notification(count) + + let item = UIApplicationShortcutItem( + type: NotificationService.unreadShortcutItemIdentifier, + localizedTitle: title, + localizedSubtitle: subtitle, + icon: nil, + userInfo: [ + "accessToken": accessToken as NSSecureCoding + ] + ) + items.append(item) + } + return items + } + } +} + extension NotificationService { func dequeueNotificationViewModel( diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift index 54b1fd57e..9801b025c 100644 --- a/Mastodon/Supporting Files/SceneDelegate.swift +++ b/Mastodon/Supporting Files/SceneDelegate.swift @@ -142,6 +142,8 @@ extension SceneDelegate { logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(shortcutItem.type)") switch shortcutItem.type { + case NotificationService.unreadShortcutItemIdentifier: + coordinator?.switchToTabBar(tab: .notification) case "org.joinmastodon.app.new-post": if coordinator?.tabBarController.topMost is ComposeViewController { logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): composing…")