diff --git a/.changeset/fix-timeline-blank-on-foreground.md b/.changeset/fix-timeline-blank-on-foreground.md new file mode 100644 index 000000000..a214a478f --- /dev/null +++ b/.changeset/fix-timeline-blank-on-foreground.md @@ -0,0 +1,5 @@ +--- +default: patch +--- + +Fix blank room timeline when app returns from background. When sliding sync delivers an `initial: true` response for the open room, a `TimelineReset` event now correctly shows skeleton placeholders while events reload instead of leaving an empty view. diff --git a/src/app/features/room/RoomTimeline.tsx b/src/app/features/room/RoomTimeline.tsx index 5c61d9dd4..9076d4502 100644 --- a/src/app/features/room/RoomTimeline.tsx +++ b/src/app/features/room/RoomTimeline.tsx @@ -328,6 +328,17 @@ export function RoomTimeline({ [] ); + // If the timeline was blanked while content was already visible — e.g. a + // TimelineReset fired by mx.retryImmediately() when the app comes back from + // background — hide the timeline (opacity 0) and re-arm the initial-scroll so + // it runs again once events refill the live timeline. + useLayoutEffect(() => { + if (!isReady) return; + if (timelineSync.eventsLength > 0) return; + setIsReady(false); + hasInitialScrolledRef.current = false; + }, [isReady, timelineSync.eventsLength]); + const recalcTopSpacer = useCallback(() => { const v = vListRef.current; if (!v) return; @@ -640,7 +651,7 @@ export function RoomTimeline({ const showLoadingPlaceholders = timelineSync.eventsLength === 0 && - (timelineSync.canPaginateBack || timelineSync.backwardStatus === 'loading'); + (!isReady || timelineSync.canPaginateBack || timelineSync.backwardStatus === 'loading'); let backPaginationJSX: ReactNode | undefined; if (timelineSync.canPaginateBack || timelineSync.backwardStatus !== 'idle') { @@ -708,7 +719,7 @@ export function RoomTimeline({ const vListItemCount = timelineSync.eventsLength === 0 && - (timelineSync.canPaginateBack || timelineSync.backwardStatus === 'loading') + (!isReady || timelineSync.canPaginateBack || timelineSync.backwardStatus === 'loading') ? 3 : timelineSync.eventsLength; const vListIndices = useMemo( @@ -840,7 +851,7 @@ export function RoomTimeline({ minHeight: 0, overflow: 'hidden', position: 'relative', - opacity: isReady ? 1 : 0, + opacity: isReady || showLoadingPlaceholders ? 1 : 0, }} >