fix(mobile): preserve social timeline scroll reset

This commit is contained in:
DIYgod 2026-06-05 10:26:09 +08:00
parent 31c10ea635
commit 4e8cf33941
3 changed files with 47 additions and 3 deletions

View File

@ -11,6 +11,7 @@ import { View } from "react-native"
import { useActionLanguage, useGeneralSettingKey } from "@/src/atoms/settings/general"
import { useEntries } from "../screen/atoms"
import { getResetScrollSignalForContent } from "../screen/scroll-reset"
import { TimelineSelectorList } from "../screen/TimelineSelectorList"
import { EntryListEndScrollSpacer } from "./EntryListEndScrollSpacer"
import { EntryListFooter } from "./EntryListFooter"
@ -92,6 +93,13 @@ export const EntryListContentSocial = ({
mode: translationMode,
})
const contentResetScrollSignal = getResetScrollSignalForContent({
entryCount: entryIds?.length ?? 0,
hasScrollableSkeleton: true,
isReady,
resetScrollSignal,
})
// Show loading skeleton when entries are not ready and no data yet
if (!isReady && (!entryIds || entryIds.length === 0)) {
return (
@ -99,7 +107,7 @@ export const EntryListContentSocial = ({
onRefresh={() => {}}
isRefetching={false}
onResetScrollSignalConsumed={onResetScrollSignalConsumed}
resetScrollSignal={resetScrollSignal}
resetScrollSignal={contentResetScrollSignal}
data={Array.from({ length: 5 }).map((_, index) => `skeleton-${index}`)}
keyExtractor={(id) => id}
renderItem={EntryItemSkeleton}
@ -116,7 +124,7 @@ export const EntryListContentSocial = ({
}}
isRefetching={isRefetching}
onResetScrollSignalConsumed={onResetScrollSignalConsumed}
resetScrollSignal={resetScrollSignal}
resetScrollSignal={contentResetScrollSignal}
data={entryIds}
extraData={extraData}
keyExtractor={(id) => id}

View File

@ -1,6 +1,10 @@
import { describe, expect, test } from "vitest"
import { shouldApplyScrollResetSignal, shouldSuspendMarkReadForScrollReset } from "./scroll-reset"
import {
getResetScrollSignalForContent,
shouldApplyScrollResetSignal,
shouldSuspendMarkReadForScrollReset,
} from "./scroll-reset"
describe("shouldApplyScrollResetSignal", () => {
test("applies a new reset signal that has not been flushed yet", () => {
@ -34,4 +38,24 @@ describe("shouldApplyScrollResetSignal", () => {
}),
).toBe(false)
})
test("does not forward reset signal to scrollable loading skeletons", () => {
expect(
getResetScrollSignalForContent({
entryCount: 0,
hasScrollableSkeleton: true,
isReady: false,
resetScrollSignal: 1,
}),
).toBeUndefined()
expect(
getResetScrollSignalForContent({
entryCount: 1,
hasScrollableSkeleton: true,
isReady: true,
resetScrollSignal: 1,
}),
).toBe(1)
})
})

View File

@ -9,3 +9,15 @@ export const shouldApplyScrollResetSignal = ({
}: ScrollResetSignalState) => resetSignal !== undefined && resetSignal !== appliedResetSignal
export const shouldSuspendMarkReadForScrollReset = shouldApplyScrollResetSignal
export const getResetScrollSignalForContent = ({
entryCount,
hasScrollableSkeleton,
isReady,
resetScrollSignal,
}: {
entryCount: number
hasScrollableSkeleton: boolean
isReady: boolean
resetScrollSignal?: number
}) => (!isReady && entryCount === 0 && hasScrollableSkeleton ? undefined : resetScrollSignal)