diff options
2 files changed, 102 insertions, 7 deletions
diff --git a/modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt b/modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt index 7c1494c70..9fdfcfd89 100644 --- a/modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt +++ b/modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt @@ -15,6 +15,8 @@ class BackgroundNotificationHandler( if (remoteMessage.data["reason"] == "chat-message") { mutateWithChatMessage(remoteMessage) + } else { + mutateWithOtherReason(remoteMessage) } notifInterface.showMessage(remoteMessage) @@ -39,4 +41,17 @@ class BackgroundNotificationHandler( // TODO - Remove this once we have more backend capability remoteMessage.data["badge"] = null } + + private fun mutateWithOtherReason(remoteMessage: RemoteMessage) { + // If oreo or higher + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + // If one of "like", "repost", "follow", "mention", "reply", "quote", "like-via-repost", "repost-via-repost" + // assign to it's eponymous channel. otherwise do nothing, let expo handle it + when (remoteMessage.data["reason"]) { + "like", "repost", "follow", "mention", "reply", "quote", "like-via-repost", "repost-via-repost" -> { + remoteMessage.data["channelId"] = remoteMessage.data["reason"] + } + } + } + } } diff --git a/src/lib/hooks/useNotificationHandler.ts b/src/lib/hooks/useNotificationHandler.ts index b1bfe6018..3a3d0156e 100644 --- a/src/lib/hooks/useNotificationHandler.ts +++ b/src/lib/hooks/useNotificationHandler.ts @@ -1,5 +1,8 @@ -import React from 'react' +import {useEffect} from 'react' import * as Notifications from 'expo-notifications' +import {type AppBskyNotificationListNotifications} from '@atproto/api' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' import {CommonActions, useNavigation} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' @@ -25,6 +28,10 @@ export type NotificationReason = | 'quote' | 'chat-message' | 'starterpack-joined' + | 'like-via-repost' + | 'repost-via-repost' + | 'verified' + | 'unverified' /** * Manually overridden type, but retains the possibility of @@ -66,34 +73,103 @@ export function useNotificationsHandler() { const {currentConvoId} = useCurrentConvoId() const {setShowLoggedOut} = useLoggedOutViewControls() const closeAllActiveElements = useCloseAllActiveElements() + const {_} = useLingui() // On Android, we cannot control which sound is used for a notification on Android // 28 or higher. Instead, we have to configure a notification channel ahead of time // which has the sounds we want in the configuration for that channel. These two // channels allow for the mute/unmute functionality we want for the background // handler. - React.useEffect(() => { + useEffect(() => { if (!isAndroid) return + // assign both chat notifications to a group + // NOTE: I don't think that it will retroactively move them into the group + // if the channels already exist. no big deal imo -sfn + const CHAT_GROUP = 'chat' + Notifications.setNotificationChannelGroupAsync(CHAT_GROUP, { + name: _(msg`Chat`), + description: _( + msg`You can choose whether chat notifications have sound in the chat settings within the app`, + ), + }) Notifications.setNotificationChannelAsync('chat-messages', { - name: 'Chat', + name: _(msg`Chat messages - sound`), + groupId: CHAT_GROUP, importance: Notifications.AndroidImportance.MAX, sound: 'dm.mp3', showBadge: true, vibrationPattern: [250], lockscreenVisibility: Notifications.AndroidNotificationVisibility.PRIVATE, }) - Notifications.setNotificationChannelAsync('chat-messages-muted', { - name: 'Chat - Muted', + name: _(msg`Chat messages - silent`), + groupId: CHAT_GROUP, importance: Notifications.AndroidImportance.MAX, sound: null, showBadge: true, vibrationPattern: [250], lockscreenVisibility: Notifications.AndroidNotificationVisibility.PRIVATE, }) - }, []) - React.useEffect(() => { + Notifications.setNotificationChannelAsync( + 'like' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`Likes`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + Notifications.setNotificationChannelAsync( + 'repost' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`Reposts`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + Notifications.setNotificationChannelAsync( + 'reply' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`Replies`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + Notifications.setNotificationChannelAsync( + 'mention' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`Mentions`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + Notifications.setNotificationChannelAsync( + 'quote' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`Quotes`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + Notifications.setNotificationChannelAsync( + 'follow' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`New followers`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + Notifications.setNotificationChannelAsync( + 'like-via-repost' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`Likes of your reposts`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + Notifications.setNotificationChannelAsync( + 'repost-via-repost' satisfies AppBskyNotificationListNotifications.Notification['reason'], + { + name: _(msg`Reposts of your reposts`), + importance: Notifications.AndroidImportance.HIGH, + }, + ) + }, [_]) + + useEffect(() => { const handleNotification = (payload?: NotificationPayload) => { if (!payload) return @@ -151,6 +227,10 @@ export function useNotificationsHandler() { case 'quote': case 'reply': case 'starterpack-joined': + case 'like-via-repost': + case 'repost-via-repost': + case 'verified': + case 'unverified': resetToTab('NotificationsTab') break // TODO implement these after we have an idea of how to handle each individual case |