update nse
This commit is contained in:
@@ -4,6 +4,30 @@ import UIKit
|
|||||||
let APP_GROUP = "group.app.bsky"
|
let APP_GROUP = "group.app.bsky"
|
||||||
typealias ContentHandler = (UNNotificationContent) -> Void
|
typealias ContentHandler = (UNNotificationContent) -> Void
|
||||||
|
|
||||||
|
enum NotificationType: String, CaseIterable {
|
||||||
|
case like
|
||||||
|
case repost
|
||||||
|
case follow
|
||||||
|
case reply
|
||||||
|
case quote
|
||||||
|
case chatMessage = "chat-message"
|
||||||
|
case markReadGeneric = "mark-read-generic"
|
||||||
|
case markReadMessages = "mark-read-messages"
|
||||||
|
case starterPackJoined = "starterpack-joined"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BadgeType: String, CaseIterable {
|
||||||
|
case generic
|
||||||
|
case messages
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BadgeOperation {
|
||||||
|
case increment
|
||||||
|
case decrement
|
||||||
|
}
|
||||||
|
|
||||||
|
let INCREMENTED_FOR_KEY = "incremented-for-convos"
|
||||||
|
|
||||||
// This extension allows us to do some processing of the received notification
|
// This extension allows us to do some processing of the received notification
|
||||||
// data before displaying the notification to the user. In our use case, there
|
// data before displaying the notification to the user. In our use case, there
|
||||||
// are a few particular things that we want to do:
|
// are a few particular things that we want to do:
|
||||||
@@ -30,28 +54,33 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
private var bestAttempt: UNMutableNotificationContent?
|
private var bestAttempt: UNMutableNotificationContent?
|
||||||
|
|
||||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||||
self.contentHandler = contentHandler
|
|
||||||
|
|
||||||
guard let bestAttempt = NSEUtil.createCopy(request.content),
|
guard let bestAttempt = NSEUtil.createCopy(request.content),
|
||||||
let reason = request.content.userInfo["reason"] as? String
|
let reasonString = request.content.userInfo["reason"] as? String,
|
||||||
|
let reason = NotificationType(rawValue: reasonString)
|
||||||
else {
|
else {
|
||||||
contentHandler(request.content)
|
contentHandler(request.content)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.contentHandler = contentHandler
|
||||||
self.bestAttempt = bestAttempt
|
self.bestAttempt = bestAttempt
|
||||||
if reason == "chat-message" {
|
|
||||||
mutateWithChatMessage(bestAttempt)
|
NSEUtil.shared.prefsQueue.sync {
|
||||||
} else {
|
switch reason {
|
||||||
mutateWithBadge(bestAttempt)
|
case .like, .repost, .follow, .reply, .quote, .starterPackJoined:
|
||||||
|
NSEUtil.mutateWithBadge(bestAttempt, badgeType: .generic, operation: .increment)
|
||||||
|
case .chatMessage:
|
||||||
|
NSEUtil.mutateWithChatMessage(bestAttempt)
|
||||||
|
NSEUtil.mutateWithBadge(bestAttempt, badgeType: .messages, operation: .increment)
|
||||||
|
case .markReadGeneric:
|
||||||
|
NSEUtil.mutateWithBadge(bestAttempt, badgeType: .generic, operation: .decrement)
|
||||||
|
case .markReadMessages:
|
||||||
|
NSEUtil.mutateWithBadge(bestAttempt, badgeType: .messages, operation: .decrement)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any image downloading (or other network tasks) should be handled at the end
|
|
||||||
// of this block. Otherwise, if there is a timeout and serviceExtensionTimeWillExpire
|
|
||||||
// gets called, we might not have all the needed mutations completed in time.
|
|
||||||
|
|
||||||
contentHandler(bestAttempt)
|
contentHandler(bestAttempt)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func serviceExtensionTimeWillExpire() {
|
override func serviceExtensionTimeWillExpire() {
|
||||||
guard let contentHandler = self.contentHandler,
|
guard let contentHandler = self.contentHandler,
|
||||||
@@ -60,38 +89,14 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
}
|
}
|
||||||
contentHandler(bestAttempt)
|
contentHandler(bestAttempt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Mutations
|
|
||||||
|
|
||||||
func mutateWithBadge(_ content: UNMutableNotificationContent) {
|
|
||||||
NSEUtil.shared.prefsQueue.sync {
|
|
||||||
var count = NSEUtil.shared.prefs?.integer(forKey: "badgeCount") ?? 0
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
// Set the new badge number for the notification, then store that value for using later
|
|
||||||
content.badge = NSNumber(value: count)
|
|
||||||
NSEUtil.shared.prefs?.setValue(count, forKey: "badgeCount")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mutateWithChatMessage(_ content: UNMutableNotificationContent) {
|
|
||||||
if NSEUtil.shared.prefs?.bool(forKey: "playSoundChat") == true {
|
|
||||||
mutateWithDmSound(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mutateWithDefaultSound(_ content: UNMutableNotificationContent) {
|
|
||||||
content.sound = UNNotificationSound.default
|
|
||||||
}
|
|
||||||
|
|
||||||
func mutateWithDmSound(_ content: UNMutableNotificationContent) {
|
|
||||||
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "dm.aiff"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NSEUtil's purpose is to create a shared instance of `UserDefaults` across
|
// NSEUtil's purpose is to create a shared instance of `UserDefaults` across
|
||||||
// `NotificationService` instances. It also includes a queue so that we can process
|
// `NotificationService` instances. It also includes a queue so that we can process
|
||||||
// updates to `UserDefaults` in parallel.
|
// updates to `UserDefaults` in parallel.
|
||||||
|
//
|
||||||
|
// Any time that you increment or decrement counts for notifications, you should use
|
||||||
|
// the prefsQueue so that things remain in sync.
|
||||||
|
|
||||||
private class NSEUtil {
|
private class NSEUtil {
|
||||||
static let shared = NSEUtil()
|
static let shared = NSEUtil()
|
||||||
@@ -99,7 +104,91 @@ private class NSEUtil {
|
|||||||
var prefs = UserDefaults(suiteName: APP_GROUP)
|
var prefs = UserDefaults(suiteName: APP_GROUP)
|
||||||
var prefsQueue = DispatchQueue(label: "NSEPrefsQueue")
|
var prefsQueue = DispatchQueue(label: "NSEPrefsQueue")
|
||||||
|
|
||||||
|
// MARK: - Utils
|
||||||
|
|
||||||
static func createCopy(_ content: UNNotificationContent) -> UNMutableNotificationContent? {
|
static func createCopy(_ content: UNNotificationContent) -> UNMutableNotificationContent? {
|
||||||
return content.mutableCopy() as? UNMutableNotificationContent
|
return content.mutableCopy() as? UNMutableNotificationContent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func getDecrementedBadgeCount(current: Int, decrementBy by: Int) -> Int {
|
||||||
|
let new = current - by
|
||||||
|
if new < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Mutations
|
||||||
|
|
||||||
|
static func mutateWithBadge(_ content: UNMutableNotificationContent,
|
||||||
|
badgeType type: BadgeType,
|
||||||
|
operation: BadgeOperation) {
|
||||||
|
var genericCount = Self.shared.prefs?.integer(forKey: BadgeType.generic.rawValue) ?? 0
|
||||||
|
var messagesCount = Self.shared.prefs?.integer(forKey: BadgeType.messages.rawValue) ?? 0
|
||||||
|
|
||||||
|
if type == .generic {
|
||||||
|
if operation == .decrement {
|
||||||
|
genericCount = 0
|
||||||
|
} else {
|
||||||
|
genericCount += 1
|
||||||
|
}
|
||||||
|
Self.shared.prefs?.setValue(genericCount, forKey: BadgeType.generic.rawValue)
|
||||||
|
// TEMPORARY - since we have not implemented message count clearing on the server, we'll clear
|
||||||
|
// those here as well.
|
||||||
|
Self.shared.prefs?.setValue(messagesCount, forKey: BadgeType.messages.rawValue)
|
||||||
|
} else if type == .messages {
|
||||||
|
// Not yet implemented, but here's the logic
|
||||||
|
if operation == .decrement,
|
||||||
|
Self.shouldDecrementForConvo(content) {
|
||||||
|
messagesCount = Self.getDecrementedBadgeCount(current: messagesCount, decrementBy: 1)
|
||||||
|
} else if operation == .increment,
|
||||||
|
shouldIncrementForConvo(content) {
|
||||||
|
messagesCount += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func mutateWithChatMessage(_ content: UNMutableNotificationContent) {
|
||||||
|
if Self.shared.prefs?.bool(forKey: "playSoundChat") == true {
|
||||||
|
Self.mutateWithDmSound(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func mutateWithDefaultSound(_ content: UNMutableNotificationContent) {
|
||||||
|
content.sound = UNNotificationSound.default
|
||||||
|
}
|
||||||
|
|
||||||
|
static func mutateWithDmSound(_ content: UNMutableNotificationContent) {
|
||||||
|
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "dm.aiff"))
|
||||||
|
}
|
||||||
|
|
||||||
|
static func shouldIncrementForConvo(_ content: UNMutableNotificationContent) -> Bool {
|
||||||
|
guard let convoId = content.userInfo["convoId"] as? String,
|
||||||
|
var dict = Self.shared.prefs?.dictionary(forKey: INCREMENTED_FOR_KEY) as? [String: Bool] else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if dict["convoId"] == true {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
dict[convoId] = true
|
||||||
|
Self.shared.prefs?.set(dict, forKey: INCREMENTED_FOR_KEY)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
static func shouldDecrementForConvo(_ content: UNMutableNotificationContent) -> Bool {
|
||||||
|
guard let convoId = content.userInfo["convoId"] as? String,
|
||||||
|
var dict = Self.shared.prefs?.dictionary(forKey: INCREMENTED_FOR_KEY) as? [String: Bool] else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if dict["convoId"] != true {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
dict.removeValue(forKey: convoId)
|
||||||
|
Self.shared.prefs?.set(dict, forKey: INCREMENTED_FOR_KEY)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user