[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>
This commit is contained in:
Ansh 2023-08-23 16:28:51 -07:00 committed by GitHub
parent 32b9648931
commit 8ab5eb6583
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 253 additions and 260 deletions

View file

@ -478,36 +478,6 @@ export class NotificationsFeedModel {
}
}
/**
* Used in background fetch to trigger notifications
*/
async getNewMostRecent(): Promise<NotificationsFeedItemModel | undefined> {
let old = this.mostRecentNotificationUri
const res = await this.rootStore.agent.listNotifications({
limit: 1,
})
if (!res.data.notifications[0] || old === res.data.notifications[0].uri) {
return
}
this.mostRecentNotificationUri = res.data.notifications[0].uri
const notif = new NotificationsFeedItemModel(
this.rootStore,
'mostRecent',
res.data.notifications[0],
)
const addedUri = notif.additionalDataUri
if (addedUri) {
const postsRes = await this.rootStore.agent.app.bsky.feed.getPosts({
uris: [addedUri],
})
const post = postsRes.data.posts[0]
notif.setAdditionalData(post)
this.rootStore.posts.set(post.uri, post)
}
const filtered = this._filterNotifications([notif])
return filtered[0]
}
// state transitions
// =

View file

@ -6,7 +6,6 @@ import {makeAutoObservable} from 'mobx'
import {BskyAgent} from '@atproto/api'
import {createContext, useContext} from 'react'
import {DeviceEventEmitter, EmitterSubscription} from 'react-native'
import * as BgScheduler from 'lib/bg-scheduler'
import {z} from 'zod'
import {isObj, hasProp} from 'lib/type-guards'
import {LogModel} from './log'
@ -16,7 +15,6 @@ import {HandleResolutionsCache} from './cache/handle-resolutions'
import {ProfilesCache} from './cache/profiles-view'
import {PostsCache} from './cache/posts'
import {LinkMetasCache} from './cache/link-metas'
import {NotificationsFeedItemModel} from './feeds/notifications'
import {MeModel} from './me'
import {InvitedUsers} from './invited-users'
import {PreferencesModel} from './ui/preferences'
@ -61,7 +59,6 @@ export class RootStoreModel {
serialize: false,
hydrate: false,
})
this.initBgFetch()
}
setAppInfo(info: AppInfo) {
@ -249,62 +246,6 @@ export class RootStoreModel {
emitUnreadNotifications(count: number) {
DeviceEventEmitter.emit('unread-notifications', count)
}
// a notification has been queued for push
onPushNotification(
handler: (notif: NotificationsFeedItemModel) => void,
): EmitterSubscription {
return DeviceEventEmitter.addListener('push-notification', handler)
}
emitPushNotification(notif: NotificationsFeedItemModel) {
DeviceEventEmitter.emit('push-notification', notif)
}
// background fetch
// =
// - we use this to poll for unread notifications, which is not "ideal" behavior but
// gives us a solution for push-notifications that work against any pds
initBgFetch() {
// NOTE
// background fetch runs every 15 minutes *at most* and will get slowed down
// based on some heuristics run by iOS, meaning it is not a reliable form of delivery
// -prf
BgScheduler.configure(
this.onBgFetch.bind(this),
this.onBgFetchTimeout.bind(this),
).then(status => {
this.log.debug(`Background fetch initiated, status: ${status}`)
})
}
async onBgFetch(taskId: string) {
this.log.debug(`Background fetch fired for task ${taskId}`)
if (this.session.hasSession) {
const res = await this.agent.countUnreadNotifications()
const hasNewNotifs = this.me.notifications.unreadCount !== res.data.count
this.emitUnreadNotifications(res.data.count)
this.log.debug(
`Background fetch received unread count = ${res.data.count}`,
)
if (hasNewNotifs) {
this.log.debug(
'Background fetch detected potentially a new notification',
)
const mostRecent = await this.me.notifications.getNewMostRecent()
if (mostRecent) {
this.log.debug('Got the notification, triggering a push')
this.emitPushNotification(mostRecent)
}
}
}
BgScheduler.finish(taskId)
}
onBgFetchTimeout(taskId: string) {
this.log.debug(`Background fetch timed out for task ${taskId}`)
BgScheduler.finish(taskId)
}
}
const throwawayInst = new RootStoreModel(