about summary refs log tree commit diff
path: root/src/lib/notifications
diff options
context:
space:
mode:
authorAnsh <anshnanda10@gmail.com>2023-08-23 16:28:51 -0700
committerGitHub <noreply@github.com>2023-08-23 16:28:51 -0700
commit8ab5eb6583b6ddd4ed03ef2b1a55ef83fa0c0625 (patch)
tree06ab22c1f0faf121f1de89247ccc43bf353408c7 /src/lib/notifications
parent32b9648931589311667423ce377ee42a1c78a84f (diff)
downloadvoidsky-8ab5eb6583b6ddd4ed03ef2b1a55ef83fa0c0625.tar.zst
[APP-786] Native notifications (#1095)
* move `notifee.ts` to notifications folder

* install expo notifications

* add UIBackgroundMode `remote-notifications` to app.json

* fix notifee import in Debug.tsx

* add `google-services.json`

* add `development-device` class to eas.json

* Add `notifications.ts` for native notification handling

* send push token to server

* update `@atproto/api`

* fix putting notif token to server

* fix how push token is uploaded

* fix lint

* enable debug appview proxy header on all platforms

* setup `notifications.ts` to work with app view notifs

* clean up notification handler

* add comments

* update packages to correct versions

* remove notifee

* clean up code a lil

* rename push token endpoint

* remove unnecessary comments

* fix comments

* Remove old background scheduler

* Fixes to push notifications API use

* Bump @atproto/api@0.6.6

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Diffstat (limited to 'src/lib/notifications')
-rw-r--r--src/lib/notifications/notifications.ts101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/lib/notifications/notifications.ts b/src/lib/notifications/notifications.ts
new file mode 100644
index 000000000..b517b40bf
--- /dev/null
+++ b/src/lib/notifications/notifications.ts
@@ -0,0 +1,101 @@
+import * as Notifications from 'expo-notifications'
+import {RootStoreModel} from '../../state'
+import {resetToTab} from '../../Navigation'
+import {devicePlatform, isIOS} from 'platform/detection'
+
+// TODO prod did = did:web:api.bsky.app
+
+export function init(store: RootStoreModel) {
+  store.onUnreadNotifications(count => Notifications.setBadgeCountAsync(count))
+
+  store.onSessionLoaded(async () => {
+    // request notifications permission once the user has logged in
+    const perms = await Notifications.getPermissionsAsync()
+    if (!perms.granted) {
+      await Notifications.requestPermissionsAsync()
+    }
+
+    // register the push token with the server
+    const token = await getPushToken()
+    if (token) {
+      try {
+        await store.agent.api.app.bsky.notification.registerPush({
+          serviceDid: 'did:web:api.staging.bsky.dev',
+          platform: devicePlatform,
+          token: token.data,
+          appId: 'xyz.blueskyweb.app',
+        })
+        store.log.debug('Notifications: Sent push token (init)', {
+          type: token.type,
+          token: token.data,
+        })
+      } catch (error) {
+        store.log.error('Notifications: Failed to set push token', error)
+      }
+    }
+
+    // listens for new changes to the push token
+    // In rare situations, a push token may be changed by the push notification service while the app is running. When a token is rolled, the old one becomes invalid and sending notifications to it will fail. A push token listener will let you handle this situation gracefully by registering the new token with your backend right away.
+    Notifications.addPushTokenListener(async ({data: t, type}) => {
+      store.log.debug('Notifications: Push token changed', {t, type})
+      if (t) {
+        try {
+          await store.agent.api.app.bsky.notification.registerPush({
+            serviceDid: 'did:web:api.staging.bsky.dev',
+            platform: devicePlatform,
+            token: t,
+            appId: 'xyz.blueskyweb.app',
+          })
+          store.log.debug('Notifications: Sent push token (event)', {
+            type,
+            token: t,
+          })
+        } catch (error) {
+          store.log.error('Notifications: Failed to set push token', error)
+        }
+      }
+    })
+  })
+
+  // handle notifications that are tapped on, regardless of whether the app is in the foreground or background
+  Notifications.addNotificationReceivedListener(event => {
+    store.log.debug('Notifications: received', event)
+    if (event.request.trigger.type === 'push') {
+      let payload
+      if (isIOS) {
+        payload = event.request.trigger.payload
+      } else {
+        // TODO: handle android payload deeplink
+      }
+      if (payload) {
+        store.log.debug('Notifications: received payload', payload)
+        // TODO: deeplink notif here
+      }
+    }
+  })
+
+  const sub = Notifications.addNotificationResponseReceivedListener(
+    response => {
+      store.log.debug(
+        'Notifications: response received',
+        response.actionIdentifier,
+      )
+      if (
+        response.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER
+      ) {
+        store.log.debug(
+          'User pressed a notification, opening notifications tab',
+        )
+        resetToTab('NotificationsTab')
+      }
+    },
+  )
+
+  return () => {
+    sub.remove()
+  }
+}
+
+export function getPushToken() {
+  return Notifications.getDevicePushTokenAsync()
+}