Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/features/followingV2/home/PostFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,9 @@ let PostFeed = ({
/*
* Anchored Following's checks, made by the view on screen only. Each one
* that finds newer posts stages them above the reader at rest (see
* `usePostFeedPrepend`) and lights the Home dot. Only one on a significant
* return to the app, or one that joins a restore's prepend, offers them with
* the pill. With no boundary to fetch above, as for an empty feed, it peeks
* `usePostFeedPrepend`) and lights the Home dot. A significant return or a
* restore puts the pill up for them, and while it's up every check's find
* joins it. With no boundary to fetch above, as for an empty feed, it peeks
* for the Home dot instead, as other feeds do.
*/
useNewPostsCheck({
Expand Down Expand Up @@ -980,6 +980,7 @@ let PostFeed = ({
enabled: isAnchored && enabled !== false,
prepend,
top: data?.pages[0],
pill,
onHasNew,
})
/**
Expand Down
13 changes: 11 additions & 2 deletions src/features/followingV2/home/anchoredFollowing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,27 @@ export function useFollowingListReports(
enabled,
prepend,
top,
pill,
onHasNew,
}: {
/** Whether the feed settles at the top (see `useSettleAtTop`). */
enabled: boolean
prepend: Pick<Prepend, 'staged' | 'markRead' | 'onBeginDrag' | 'onPageSeen'>
/** The feed's top page as it renders. */
top: FeedPage | undefined
/** The new posts pill (see `usePrependPill`). */
pill: {dismiss: () => void}
/** Puts the Home dot out. */
onHasNew?: (hasNew: boolean) => void
},
): {reports: ListScrollReports; onRowSeen: (row: Row) => void} {
const settleAtTop = useSettleAtTop(feed, params, {
enabled,
// At the newest post, nothing is new to the reader any more.
onRestAtTop: () => onHasNew?.(false),
onRestAtTop: () => {
onHasNew?.(false)
pill.dismiss()
},
})
const onRowSeen = useNonReactiveCallback((row: Row) => {
if (
Expand All @@ -97,7 +103,10 @@ export function useFollowingListReports(
prepend.onBeginDrag()
},
// At the top, the reader has passed everything staged above them.
onReachTop: prepend.markRead,
onReachTop: () => {
prepend.markRead()
pill.dismiss()
},
},
onRowSeen,
}
Expand Down
46 changes: 41 additions & 5 deletions src/features/followingV2/home/queries/postFeed.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1106,10 +1106,10 @@ describe('usePostFeedPrepend', () => {
{cursor: 'start:1'},
{cursor: 'timeline:1'},
])
// Still offered, as the restore's page was.
// Not offered: the pill takes a replacement in itself while it's up.
expect(hook.result.current.prepend.staged).toEqual({
fetchedAt: cached().pages[0].fetchedAt,
offered: true,
offered: false,
isFull: false,
})
})
Expand Down Expand Up @@ -1813,7 +1813,7 @@ describe('staging new posts on Home Following', () => {
const {reports, onRowSeen: onItemSeen} = useFollowingListReports(
'following',
undefined,
{enabled: true, prepend, top: pages?.[0], onHasNew},
{enabled: true, prepend, top: pages?.[0], pill, onHasNew},
)
const scrollHandlers = useSettleScrollHandlers(
listRest.scrollHandlers,
Expand Down Expand Up @@ -2235,17 +2235,53 @@ describe('staging new posts on Home Following', () => {
expect(latest.pill).toMatchObject({visible: true, count: 3})
})

it('hides the pill once the reader sees a staged post after a drag', async () => {
it('keeps the pill up once the reader sees a staged post, until they reach the true top', async () => {
const {latest, list} = renderHome()
newest = 14
await warmOpen()

list.beginDrag(400)
list.see(13)
list.endDrag(300)
// Seeing a staged post reads the page, but the pill stays up.
expect(latest.staged).toBeUndefined()
expect(latest.pill).toMatchObject({visible: true, count: 2})

list.beginDrag(300)
list.scroll(0)
expect(latest.pill.visible).toBe(false)
})

it('takes what later checks stage above into the pill, while it is up', async () => {
const {latest, cached, list} = renderHome()
newest = 14
await warmOpen()
list.beginDrag(400)
list.see(13)
list.endDrag(300)

newest = 16
await anInterval()
expect(postsOf(cached())[0]).toEqual(['p16', 'p15'])
expect(latest.pill).toMatchObject({visible: true, count: 4})

newest = 17
await quickHop()
expect(postsOf(cached())[0]).toEqual(['p17', 'p16', 'p15'])
expect(latest.pill).toMatchObject({visible: true, count: 5})
})

it('hides the pill once the reader comes to rest at the true top', async () => {
const {latest, list} = renderHome()
newest = 14
await warmOpen()

// The list never reported leaving the top, so only the rest says so.
list.beginDrag(0)
list.endDrag(0)
await wait(SETTLE_QUIET_MS)

expect(latest.pill.visible).toBe(false)
expect(latest.staged).toBeUndefined()
})
})

Expand Down
18 changes: 10 additions & 8 deletions src/features/followingV2/home/queries/postFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,10 @@ export type PrependTrigger = 'restore' | NewPostsCheckTrigger
export type StagedPage = {
/** The page's `fetchedAt`. */
fetchedAt: number
/** Whether the pill offers its posts. */
/**
* Whether a restore or a significant return to the app offered it, which
* puts the pill up (see `usePrependPill`).
*/
offered: boolean
/**
* Whether more posts than fit on a page were newer than where it was
Expand Down Expand Up @@ -625,9 +628,9 @@ function isSameFeedItem(
* While a page is staged, the next prepend fetches from the same `since` as it
* did and replaces it, so however long the reader stays put, what's above them
* is one page of at most {@link PREPEND_LIMIT} posts. Once it's read, the next
* one goes above it. `staged` is the page for the pill, which offers it if a
* restore or a significant return to the app put it there, or `check` has
* offered it since.
* one goes above it. The pill goes up for a `staged` page that a restore or a
* significant return put there, or that `check` has offered since, and takes
* in every page staged while it's up (see `usePrependPill`).
*
* A page only ever replaces the staged one if it has all of its posts, as
* the list holds the reader's place only for posts added above the others:
Expand Down Expand Up @@ -771,10 +774,9 @@ export function usePostFeedPrepend(
return undefined
}
await listAtRest()
const wasStaged = stagedRef.current
if (
isRefreshing() ||
(replacing && wasStaged?.fetchedAt !== replacing.fetchedAt)
(replacing && stagedRef.current?.fetchedAt !== replacing.fetchedAt)
) {
return undefined
}
Expand All @@ -794,8 +796,8 @@ export function usePostFeedPrepend(
}
setStaged({
fetchedAt: page.fetchedAt,
// A page offered by the pill stays offered when it's replaced.
offered: isOffering.current || (!!replacing && !!wasStaged?.offered),
// A replacement isn't offered. The pill takes it in itself if it's up.
offered: isOffering.current,
isFull,
})
return page
Expand Down
Loading
Loading