Trigger a notifee card on new notifications
This commit is contained in:
@@ -587,7 +587,7 @@ export const mockedMeStore = {
|
|||||||
clear: jest.fn(),
|
clear: jest.fn(),
|
||||||
load: jest.fn(),
|
load: jest.fn(),
|
||||||
clearNotificationCount: jest.fn(),
|
clearNotificationCount: jest.fn(),
|
||||||
fetchStateUpdate: jest.fn(),
|
fetchNotifications: jest.fn(),
|
||||||
refreshMemberships: jest.fn(),
|
refreshMemberships: jest.fn(),
|
||||||
} as MeModel
|
} as MeModel
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ describe('MeModel', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
await meModel.fetchStateUpdate()
|
await meModel.fetchNotifications()
|
||||||
expect(meModel.notificationCount).toBe(1)
|
expect(meModel.notificationCount).toBe(1)
|
||||||
expect(meModel.notifications.refresh).toHaveBeenCalled()
|
expect(meModel.notifications.refresh).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import * as view from './view/index'
|
|||||||
import {RootStoreModel, setupState, RootStoreProvider} from './state'
|
import {RootStoreModel, setupState, RootStoreProvider} from './state'
|
||||||
import {MobileShell} from './view/shell/mobile'
|
import {MobileShell} from './view/shell/mobile'
|
||||||
import {s} from './view/lib/styles'
|
import {s} from './view/lib/styles'
|
||||||
|
import notifee, {EventType} from '@notifee/react-native'
|
||||||
|
|
||||||
const App = observer(() => {
|
const App = observer(() => {
|
||||||
const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
|
const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
|
||||||
@@ -43,6 +44,13 @@ const App = observer(() => {
|
|||||||
Linking.addEventListener('url', ({url}) => {
|
Linking.addEventListener('url', ({url}) => {
|
||||||
store.nav.handleLink(url)
|
store.nav.handleLink(url)
|
||||||
})
|
})
|
||||||
|
notifee.onForegroundEvent(async ({type}: {type: EventType}) => {
|
||||||
|
store.log.debug('Notifee foreground event', {type})
|
||||||
|
if (type === EventType.PRESS) {
|
||||||
|
store.log.debug('User pressed a notifee, opening notifications')
|
||||||
|
store.nav.switchTo(1, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|||||||
+12
-2
@@ -118,7 +118,7 @@ export class MeModel {
|
|||||||
notifee.setBadgeCount(0)
|
notifee.setBadgeCount(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchStateUpdate() {
|
async fetchNotifications() {
|
||||||
const res = await this.rootStore.api.app.bsky.notification.getCount()
|
const res = await this.rootStore.api.app.bsky.notification.getCount()
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
const newNotifications = this.notificationCount !== res.data.count
|
const newNotifications = this.notificationCount !== res.data.count
|
||||||
@@ -126,7 +126,17 @@ export class MeModel {
|
|||||||
notifee.setBadgeCount(this.notificationCount)
|
notifee.setBadgeCount(this.notificationCount)
|
||||||
if (newNotifications) {
|
if (newNotifications) {
|
||||||
// trigger pre-emptive fetch on new notifications
|
// trigger pre-emptive fetch on new notifications
|
||||||
this.notifications.refresh()
|
let oldMostRecent = this.notifications.mostRecentNotification
|
||||||
|
this.notifications.refresh().then(() => {
|
||||||
|
// if a new most recent notification is found, trigger a notification card
|
||||||
|
const mostRecent = this.notifications.mostRecentNotification
|
||||||
|
if (mostRecent && oldMostRecent?.uri !== mostRecent?.uri) {
|
||||||
|
const notifeeOpts = mostRecent.toNotifeeOpts()
|
||||||
|
if (notifeeOpts) {
|
||||||
|
notifee.displayNotification(notifeeOpts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
AppBskyFeedVote,
|
AppBskyFeedVote,
|
||||||
AppBskyGraphAssertion,
|
AppBskyGraphAssertion,
|
||||||
AppBskyGraphFollow,
|
AppBskyGraphFollow,
|
||||||
|
AppBskyEmbedImages,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {RootStoreModel} from './root-store'
|
import {RootStoreModel} from './root-store'
|
||||||
import {PostThreadViewModel} from './post-thread-view'
|
import {PostThreadViewModel} from './post-thread-view'
|
||||||
@@ -179,6 +180,42 @@ export class NotificationsViewItemModel {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toNotifeeOpts() {
|
||||||
|
let author = this.author.displayName || this.author.handle
|
||||||
|
let title: string
|
||||||
|
let body: string = ''
|
||||||
|
if (this.isUpvote) {
|
||||||
|
title = `${author} liked your post`
|
||||||
|
body = this.additionalPost?.thread?.postRecord?.text || ''
|
||||||
|
} else if (this.isRepost) {
|
||||||
|
title = `${author} reposted your post`
|
||||||
|
body = this.additionalPost?.thread?.postRecord?.text || ''
|
||||||
|
} else if (this.isReply) {
|
||||||
|
title = `${author} replied to your post`
|
||||||
|
body = this.additionalPost?.thread?.postRecord?.text || ''
|
||||||
|
} else if (this.isFollow) {
|
||||||
|
title = `${author} followed you`
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
let ios
|
||||||
|
if (
|
||||||
|
AppBskyEmbedImages.isPresented(this.additionalPost?.thread?.post.embed) &&
|
||||||
|
this.additionalPost?.thread?.post.embed.images[0]?.thumb
|
||||||
|
) {
|
||||||
|
ios = {
|
||||||
|
attachments: [
|
||||||
|
{url: this.additionalPost.thread.post.embed.images[0].thumb},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
ios,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotificationsViewModel {
|
export class NotificationsViewModel {
|
||||||
@@ -197,6 +234,9 @@ export class NotificationsViewModel {
|
|||||||
// data
|
// data
|
||||||
notifications: NotificationsViewItemModel[] = []
|
notifications: NotificationsViewItemModel[] = []
|
||||||
|
|
||||||
|
// this is used to trigger push notifications
|
||||||
|
mostRecentNotification: NotificationsViewItemModel | undefined
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public rootStore: RootStoreModel,
|
public rootStore: RootStoreModel,
|
||||||
params: ListNotifications.QueryParams,
|
params: ListNotifications.QueryParams,
|
||||||
@@ -388,6 +428,16 @@ export class NotificationsViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _replaceAll(res: ListNotifications.Response) {
|
private async _replaceAll(res: ListNotifications.Response) {
|
||||||
|
if (res.data.notifications[0]) {
|
||||||
|
this.mostRecentNotification = new NotificationsViewItemModel(
|
||||||
|
this.rootStore,
|
||||||
|
'mostRecent',
|
||||||
|
res.data.notifications[0],
|
||||||
|
)
|
||||||
|
await this.mostRecentNotification.fetchAdditionalData()
|
||||||
|
} else {
|
||||||
|
this.mostRecentNotification = undefined
|
||||||
|
}
|
||||||
return this._appendAll(res, true)
|
return this._appendAll(res, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export class RootStoreModel {
|
|||||||
if (!this.session.online) {
|
if (!this.session.online) {
|
||||||
await this.session.connect()
|
await this.session.connect()
|
||||||
}
|
}
|
||||||
await this.me.fetchStateUpdate()
|
await this.me.fetchNotifications()
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (isNetworkError(e)) {
|
if (isNetworkError(e)) {
|
||||||
this.session.setOnline(false) // connection lost
|
this.session.setOnline(false) // connection lost
|
||||||
|
|||||||
Reference in New Issue
Block a user