Multiple notifications fixes (#2154)

* Dont reset notifications feed on push notification event

* Dont separate notifications by read state to avoid jank

* On notifications screen focus, check latest and only rerender if not scrolled down

* Reuse the cached notifs page when its not stale

* Bump ios build number

* Improve comments

* Change the 'mark all read' condition to avoid firing too early
This commit is contained in:
Paul Frazee 2023-12-09 15:09:31 -08:00 committed by GitHub
parent d854e88218
commit 6b3eb401b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 162 additions and 146 deletions

View file

@ -16,7 +16,7 @@
* 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead.
*/
import {useEffect} from 'react'
import {useEffect, useRef} from 'react'
import {AppBskyFeedDefs} from '@atproto/api'
import {
useInfiniteQuery,
@ -49,6 +49,8 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
const threadMutes = useMutedThreads()
const unreads = useUnreadNotificationsApi()
const enabled = opts?.enabled !== false
// state tracked across page fetches
const pageState = useRef({pageNum: 0, hasMarkedRead: false})
const query = useInfiniteQuery<
FeedPage,
@ -60,17 +62,44 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
staleTime: STALE.INFINITY,
queryKey: RQKEY(),
async queryFn({pageParam}: {pageParam: RQPageParam}) {
let page = await fetchPage({
limit: PAGE_SIZE,
cursor: pageParam,
queryClient,
moderationOpts,
threadMutes,
})
let page
if (!pageParam) {
// for the first page, we check the cached page held by the unread-checker first
page = unreads.getCachedUnreadPage()
// reset the page state
pageState.current = {pageNum: 0, hasMarkedRead: false}
}
if (!page) {
page = await fetchPage({
limit: PAGE_SIZE,
cursor: pageParam,
queryClient,
moderationOpts,
threadMutes,
})
}
// if the first page has an unread, mark all read
if (!pageParam && page.items[0] && !page.items[0].notification.isRead) {
unreads.markAllRead()
// NOTE
// this section checks to see if we need to mark notifs read
// we want to wait until we've seen a read notification because
// of a timing challenge; marking read on the first page would
// cause subsequent pages of unread notifs to incorrectly come
// back as "read". we use page 6 as an abort condition, which means
// after ~180 notifs we give up on tracking unread state correctly
// -prf
if (!pageState.current.hasMarkedRead) {
let hasMarkedRead = false
if (
pageState.current.pageNum > 5 ||
page.items.some(item => item.notification.isRead)
) {
unreads.markAllRead()
hasMarkedRead = true
}
pageState.current = {
pageNum: pageState.current.pageNum + 1,
hasMarkedRead,
}
}
return page