107 lines
4.0 KiB
Swift
107 lines
4.0 KiB
Swift
//
|
|
// https://mczachurski.dev
|
|
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
|
// Licensed under the Apache License 2.0.
|
|
//
|
|
|
|
import Foundation
|
|
import SwiftData
|
|
import PixelfedKit
|
|
import ClientKit
|
|
import ServicesKit
|
|
import Nuke
|
|
import OSLog
|
|
import EnvironmentKit
|
|
import Semaphore
|
|
import UserNotifications
|
|
|
|
/// Service responsible for managing notifications.
|
|
@MainActor
|
|
public class NotificationsService {
|
|
public static let shared = NotificationsService()
|
|
private init() { }
|
|
|
|
private let semaphore = AsyncSemaphore(value: 1)
|
|
|
|
public func newNotificationsHasBeenAdded(for account: AccountModel, modelContext: ModelContext) async -> Bool {
|
|
await semaphore.wait()
|
|
defer { semaphore.signal() }
|
|
|
|
guard let accessToken = account.accessToken else {
|
|
return false
|
|
}
|
|
|
|
// Get maximimum downloaded stauts id.
|
|
guard let lastSeenNotificationId = self.getLastSeenNotificationId(accountId: account.id, modelContext: modelContext) else {
|
|
return false
|
|
}
|
|
|
|
let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken)
|
|
|
|
do {
|
|
let linkableNotifications = try await client.notifications(minId: lastSeenNotificationId, limit: 5)
|
|
return linkableNotifications.data.first(where: { $0.id != lastSeenNotificationId }) != nil
|
|
} catch {
|
|
ErrorService.shared.handle(error, message: "notifications.error.loadingNotificationsFailed")
|
|
return false
|
|
}
|
|
}
|
|
|
|
public func amountOfNewNotifications(for account: AccountModel, modelContext: ModelContext) async -> Int {
|
|
await semaphore.wait()
|
|
defer { semaphore.signal() }
|
|
|
|
guard let accessToken = account.accessToken else {
|
|
return 0
|
|
}
|
|
|
|
// Get maximimum downloaded stauts id.
|
|
guard let lastSeenNotificationId = self.getLastSeenNotificationId(accountId: account.id, modelContext: modelContext) else {
|
|
return 0
|
|
}
|
|
|
|
let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken)
|
|
var notifications: [PixelfedKit.Notification] = []
|
|
var newestNotificationId = lastSeenNotificationId
|
|
|
|
// There can be more then 80 newest notifications, that's why we have to sometimes send more then one request.
|
|
while true {
|
|
do {
|
|
let downloadedNotifications = try await client.notifications(minId: newestNotificationId, limit: 80)
|
|
|
|
guard let firstNotification = downloadedNotifications.data.first else {
|
|
break
|
|
}
|
|
|
|
let visibleNotifications = downloadedNotifications.data.filter({ $0.id != lastSeenNotificationId })
|
|
|
|
notifications.append(contentsOf: visibleNotifications)
|
|
newestNotificationId = firstNotification.id
|
|
} catch {
|
|
ErrorService.shared.handle(error, message: "global.error.errorDuringDownloadingNewStatuses")
|
|
break
|
|
}
|
|
}
|
|
|
|
// Return number of new notifications not visible yet on the timeline.
|
|
return notifications.count
|
|
}
|
|
|
|
/// Function sets application badge counts when notifications (and badge) are enabled.
|
|
public func setBadgeCount(_ count: Int) async throws {
|
|
let center = UNUserNotificationCenter.current()
|
|
let settings = await center.notificationSettings()
|
|
|
|
guard (settings.authorizationStatus == .authorized) || (settings.authorizationStatus == .provisional) else { return }
|
|
|
|
if settings.badgeSetting == .enabled {
|
|
try await center.setBadgeCount(count)
|
|
}
|
|
}
|
|
|
|
private func getLastSeenNotificationId(accountId: String, modelContext: ModelContext) -> String? {
|
|
let accountData = AccountDataHandler.shared.getAccountData(accountId: accountId, modelContext: modelContext)
|
|
return accountData?.lastSeenNotificationId
|
|
}
|
|
}
|