add support for mark-read-generic and mark-read-messages
update kotlin stub update js types update the correct badge count clamp single decrements too clamp decrement future proof with `decrementBy` add support for `mark-read-generic` and `mark-read-messages` do nothing when receiving `mark-read-*` is received simplify swift update android with new types add types to `NotificationReason` add logic for decrementing the badge add decrement mutation
This commit is contained in:
@@ -3,21 +3,51 @@ import UIKit
|
|||||||
|
|
||||||
let APP_GROUP = "group.app.bsky"
|
let APP_GROUP = "group.app.bsky"
|
||||||
|
|
||||||
|
enum NotificationType: String {
|
||||||
|
case Like = "like"
|
||||||
|
case Repost = "repost"
|
||||||
|
case Follow = "follow"
|
||||||
|
case Reply = "reply"
|
||||||
|
case Quote = "quote"
|
||||||
|
case ChatMessage = "chat-message"
|
||||||
|
case MarkReadGeneric = "mark-read-generic"
|
||||||
|
case MarkReadMessages = "mark-read-messages"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BadgeType: String {
|
||||||
|
case Generic = "badgeCountGeneric"
|
||||||
|
case Messages = "badgeCountMessages"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BadgeOperation {
|
||||||
|
case Increment
|
||||||
|
case Decrement
|
||||||
|
}
|
||||||
|
|
||||||
class NotificationService: UNNotificationServiceExtension {
|
class NotificationService: UNNotificationServiceExtension {
|
||||||
var prefs = UserDefaults(suiteName: APP_GROUP)
|
var prefs = UserDefaults(suiteName: APP_GROUP)
|
||||||
|
|
||||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||||
guard let bestAttempt = createCopy(request.content),
|
guard let bestAttempt = 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
|
||||||
}
|
}
|
||||||
|
|
||||||
if reason == "chat-message" {
|
switch reason {
|
||||||
|
case NotificationType.Like, NotificationType.Repost, NotificationType.Follow, NotificationType.Reply, NotificationType.Quote:
|
||||||
|
mutateWithBadge(bestAttempt, badgeType: BadgeType.Generic, operation: BadgeOperation.Increment)
|
||||||
|
|
||||||
|
case NotificationType.ChatMessage:
|
||||||
mutateWithChatMessage(bestAttempt)
|
mutateWithChatMessage(bestAttempt)
|
||||||
} else {
|
|
||||||
mutateWithBadge(bestAttempt)
|
case NotificationType.MarkReadGeneric:
|
||||||
|
mutateWithBadge(bestAttempt, badgeType: BadgeType.Generic, operation: BadgeOperation.Decrement)
|
||||||
|
|
||||||
|
case NotificationType.MarkReadMessages:
|
||||||
|
mutateWithBadge(bestAttempt, badgeType: BadgeType.Messages, operation: BadgeOperation.Decrement)
|
||||||
}
|
}
|
||||||
|
|
||||||
contentHandler(bestAttempt)
|
contentHandler(bestAttempt)
|
||||||
@@ -31,13 +61,43 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
return content.mutableCopy() as? UNMutableNotificationContent
|
return content.mutableCopy() as? UNMutableNotificationContent
|
||||||
}
|
}
|
||||||
|
|
||||||
func mutateWithBadge(_ content: UNMutableNotificationContent) {
|
func getDecrementedBadgeCount(current: Int, decrementBy by: Int) -> Int {
|
||||||
var count = prefs?.integer(forKey: "badgeCount") ?? 0
|
let new = current - by
|
||||||
count += 1
|
if new < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
// Set the new badge number for the notification, then store that value for using later
|
func mutateWithBadge(_ content: UNMutableNotificationContent, badgeType type: BadgeType, operation: BadgeOperation) {
|
||||||
content.badge = NSNumber(value: count)
|
var genericCount = prefs?.integer(forKey: BadgeType.Generic.rawValue) ?? 0
|
||||||
prefs?.setValue(count, forKey: "badgeCount")
|
var messagesCount = prefs?.integer(forKey: BadgeType.Messages.rawValue) ?? 0
|
||||||
|
|
||||||
|
if type == BadgeType.Generic {
|
||||||
|
if operation == BadgeOperation.Decrement {
|
||||||
|
if let decrementBy = content.userInfo["decrementBy"] as? Int {
|
||||||
|
genericCount = getDecrementedBadgeCount(current: genericCount, decrementBy: decrementBy)
|
||||||
|
} else {
|
||||||
|
genericCount = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
genericCount += 1
|
||||||
|
}
|
||||||
|
prefs?.setValue(genericCount, forKey: BadgeType.Generic.rawValue)
|
||||||
|
} else if type == BadgeType.Messages {
|
||||||
|
if operation == BadgeOperation.Decrement {
|
||||||
|
if let decrementBy = content.userInfo["decrementBy"] as? Int {
|
||||||
|
messagesCount = getDecrementedBadgeCount(current: messagesCount, decrementBy: decrementBy)
|
||||||
|
} else {
|
||||||
|
messagesCount = getDecrementedBadgeCount(current: messagesCount, decrementBy: 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
genericCount += 1
|
||||||
|
}
|
||||||
|
prefs?.setValue(messagesCount, forKey: BadgeType.Generic.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
content.badge = NSNumber(value: genericCount + messagesCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mutateWithChatMessage(_ content: UNMutableNotificationContent) {
|
func mutateWithChatMessage(_ content: UNMutableNotificationContent) {
|
||||||
|
|||||||
+16
-1
@@ -3,6 +3,17 @@ package expo.modules.backgroundnotificationhandler
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.google.firebase.messaging.RemoteMessage
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
|
|
||||||
|
enum class NotificationType(val type: String) {
|
||||||
|
Like("like"),
|
||||||
|
Repost("repost"),
|
||||||
|
Follow("follow"),
|
||||||
|
Reply("reply"),
|
||||||
|
Quote("quote"),
|
||||||
|
ChatMessage("chat-message"),
|
||||||
|
MarkReadGeneric("mark-read-generic"),
|
||||||
|
MarkReadMessages("mark-read-messages"),
|
||||||
|
}
|
||||||
|
|
||||||
class BackgroundNotificationHandler(
|
class BackgroundNotificationHandler(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val notifInterface: BackgroundNotificationHandlerInterface
|
private val notifInterface: BackgroundNotificationHandlerInterface
|
||||||
@@ -13,8 +24,12 @@ class BackgroundNotificationHandler(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteMessage.data["reason"] == "chat-message") {
|
val type = NotificationType.valueOf(remoteMessage.data["reason"] ?: return)
|
||||||
|
|
||||||
|
if (type == NotificationType.ChatMessage) {
|
||||||
mutateWithChatMessage(remoteMessage)
|
mutateWithChatMessage(remoteMessage)
|
||||||
|
} else if (type == NotificationType.MarkReadGeneric || type == NotificationType.MarkReadMessages) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
notifInterface.showMessage(remoteMessage)
|
notifInterface.showMessage(remoteMessage)
|
||||||
|
|||||||
+1
-1
@@ -67,7 +67,7 @@ class ExpoBackgroundNotificationHandlerModule : Module() {
|
|||||||
NotificationPrefs(appContext.reactContext).removeManyFromStringArray(forKey, strings)
|
NotificationPrefs(appContext.reactContext).removeManyFromStringArray(forKey, strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncFunction("setBadgeCountAsync") { _: Int ->
|
AsyncFunction("setBadgeCountAsync") { _: String, _: Int ->
|
||||||
// This does nothing on Android
|
// This does nothing on Android
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -114,8 +114,22 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncFunction("setBadgeCountAsync") { (count: Int) in
|
AsyncFunction("setBadgeCountAsync") { (type: BadgeCountType, count: Int) in
|
||||||
userDefaults?.setValue(count, forKey: "badgeCount")
|
userDefaults?.setValue(count, forKey: type.toKeyName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BadgeCountType : String, Enumerable {
|
||||||
|
case generic
|
||||||
|
case messages
|
||||||
|
|
||||||
|
func toKeyName() -> String {
|
||||||
|
switch self {
|
||||||
|
case .generic:
|
||||||
|
return "badgeCountGeneric"
|
||||||
|
case .messages:
|
||||||
|
return "badgeCountMessages"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -31,7 +31,10 @@ export type ExpoBackgroundNotificationHandlerModule = {
|
|||||||
forKey: keyof BackgroundNotificationHandlerPreferences,
|
forKey: keyof BackgroundNotificationHandlerPreferences,
|
||||||
value: string[],
|
value: string[],
|
||||||
) => Promise<void>
|
) => Promise<void>
|
||||||
setBadgeCountAsync: (count: number) => Promise<void>
|
setBadgeCountAsync: (
|
||||||
|
type: 'generic' | 'messages',
|
||||||
|
count: number,
|
||||||
|
) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO there are more preferences in the native code, however they have not been added here yet.
|
// TODO there are more preferences in the native code, however they have not been added here yet.
|
||||||
|
|||||||
+1
-1
@@ -24,5 +24,5 @@ export const BackgroundNotificationHandler = {
|
|||||||
removeFromStringArrayAsync: async (_: string, __: string) => {},
|
removeFromStringArrayAsync: async (_: string, __: string) => {},
|
||||||
addManyToStringArrayAsync: async (_: string, __: string[]) => {},
|
addManyToStringArrayAsync: async (_: string, __: string[]) => {},
|
||||||
removeManyFromStringArrayAsync: async (_: string, __: string[]) => {},
|
removeManyFromStringArrayAsync: async (_: string, __: string[]) => {},
|
||||||
setBadgeCountAsync: async (_: number) => {},
|
setBadgeCountAsync: async (_: 'generic' | 'messages', __: number) => {},
|
||||||
} as ExpoBackgroundNotificationHandlerModule
|
} as ExpoBackgroundNotificationHandlerModule
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ type NotificationReason =
|
|||||||
| 'reply'
|
| 'reply'
|
||||||
| 'quote'
|
| 'quote'
|
||||||
| 'chat-message'
|
| 'chat-message'
|
||||||
|
| 'mark-read-generic'
|
||||||
|
| 'mark-read-messages'
|
||||||
|
|
||||||
type NotificationPayload =
|
type NotificationPayload =
|
||||||
| {
|
| {
|
||||||
@@ -194,6 +196,20 @@ export function useNotificationsHandler() {
|
|||||||
shouldPlaySound: false,
|
shouldPlaySound: false,
|
||||||
shouldSetBadge: false,
|
shouldSetBadge: false,
|
||||||
}
|
}
|
||||||
|
} else if (
|
||||||
|
payload.reason === 'mark-read-generic' ||
|
||||||
|
payload.reason === 'mark-read-messages'
|
||||||
|
) {
|
||||||
|
logger.debug(
|
||||||
|
`Notifications: ${payload.reason}`,
|
||||||
|
{},
|
||||||
|
logger.DebugContext.notifications,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
shouldShowAlert: false,
|
||||||
|
shouldPlaySound: false,
|
||||||
|
shouldSetBadge: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any notification other than a chat message should invalidate the unread page
|
// Any notification other than a chat message should invalidate the unread page
|
||||||
|
|||||||
Reference in New Issue
Block a user