Keep pager feeds in sync with the right pane (#2775)
* Hoist selected feed state * Seed state from params * Refine and fix logic * Fix scroll restoration * Soft reset on second click
This commit is contained in:
parent
80c482b026
commit
06f81d6948
6 changed files with 148 additions and 63 deletions
|
@ -31,7 +31,7 @@ export const Pager = React.forwardRef(function PagerImpl(
|
|||
const anchorRef = React.useRef(null)
|
||||
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
setPage: (index: number) => setSelectedPage(index),
|
||||
setPage: (index: number) => onTabBarSelect(index),
|
||||
}))
|
||||
|
||||
const onTabBarSelect = React.useCallback(
|
||||
|
|
|
@ -7,7 +7,7 @@ import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
|
|||
import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
|
||||
import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
|
||||
import {FeedsTabBar} from '../com/pager/FeedsTabBar'
|
||||
import {Pager, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||
import {Pager, RenderTabBarFnProps, PagerRef} from 'view/com/pager/Pager'
|
||||
import {FeedPage} from 'view/com/feeds/FeedPage'
|
||||
import {HomeLoggedOutCTA} from '../com/auth/HomeLoggedOutCTA'
|
||||
import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell'
|
||||
|
@ -16,25 +16,19 @@ import {usePinnedFeedsInfos, FeedSourceInfo} from '#/state/queries/feed'
|
|||
import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import * as persisted from '#/state/persisted'
|
||||
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
|
||||
|
||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||
export function HomeScreen(props: Props) {
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const {feeds: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
|
||||
usePinnedFeedsInfos()
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
const [rawInitialFeed] = React.useState<string>(
|
||||
() => persisted.get('lastSelectedHomeFeed') ?? 'home',
|
||||
)
|
||||
if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
|
||||
return (
|
||||
<HomeScreenReady
|
||||
{...props}
|
||||
preferences={preferences}
|
||||
pinnedFeedInfos={pinnedFeedInfos}
|
||||
rawInitialFeed={isDesktop ? 'home' : rawInitialFeed}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
|
@ -49,11 +43,9 @@ export function HomeScreen(props: Props) {
|
|||
function HomeScreenReady({
|
||||
preferences,
|
||||
pinnedFeedInfos,
|
||||
rawInitialFeed,
|
||||
}: Props & {
|
||||
preferences: UsePreferencesQueryResponse
|
||||
pinnedFeedInfos: FeedSourceInfo[]
|
||||
rawInitialFeed: string
|
||||
}) {
|
||||
const allFeeds = React.useMemo(() => {
|
||||
const feeds: FeedDescriptor[] = []
|
||||
|
@ -68,12 +60,24 @@ function HomeScreenReady({
|
|||
return feeds
|
||||
}, [pinnedFeedInfos])
|
||||
|
||||
const [rawSelectedFeed, setSelectedFeed] =
|
||||
React.useState<string>(rawInitialFeed)
|
||||
const rawSelectedFeed = useSelectedFeed()
|
||||
const setSelectedFeed = useSetSelectedFeed()
|
||||
const maybeFoundIndex = allFeeds.indexOf(rawSelectedFeed as FeedDescriptor)
|
||||
const selectedIndex = Math.max(0, maybeFoundIndex)
|
||||
const selectedFeed = allFeeds[selectedIndex]
|
||||
|
||||
const pagerRef = React.useRef<PagerRef>(null)
|
||||
const lastPagerReportedIndexRef = React.useRef(selectedIndex)
|
||||
React.useLayoutEffect(() => {
|
||||
// Since the pager is not a controlled component, adjust it imperatively
|
||||
// if the selected index gets out of sync with what it last reported.
|
||||
// This is supposed to only happen on the web when you use the right nav.
|
||||
if (selectedIndex !== lastPagerReportedIndexRef.current) {
|
||||
lastPagerReportedIndexRef.current = selectedIndex
|
||||
pagerRef.current?.setPage(selectedIndex)
|
||||
}
|
||||
}, [selectedIndex])
|
||||
|
||||
const {hasSession} = useSession()
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
|
||||
|
@ -93,7 +97,7 @@ function HomeScreenReady({
|
|||
setDrawerSwipeDisabled(index > 0)
|
||||
const feed = allFeeds[index]
|
||||
setSelectedFeed(feed)
|
||||
persisted.write('lastSelectedHomeFeed', feed)
|
||||
lastPagerReportedIndexRef.current = index
|
||||
},
|
||||
[setDrawerSwipeDisabled, setSelectedFeed, setMinimalShellMode, allFeeds],
|
||||
)
|
||||
|
@ -147,6 +151,7 @@ function HomeScreenReady({
|
|||
return hasSession ? (
|
||||
<Pager
|
||||
key={allFeeds.join(',')}
|
||||
ref={pagerRef}
|
||||
testID="homeScreen"
|
||||
initialPage={selectedIndex}
|
||||
onPageSelected={onPageSelected}
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
import React from 'react'
|
||||
import {View, StyleSheet} from 'react-native'
|
||||
import {useNavigationState} from '@react-navigation/native'
|
||||
import {useNavigationState, useNavigation} from '@react-navigation/native'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {TextLink} from 'view/com/util/Link'
|
||||
import {getCurrentRoute} from 'lib/routes/helpers'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {usePinnedFeedsInfos} from '#/state/queries/feed'
|
||||
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
|
||||
import {FeedDescriptor} from '#/state/queries/post-feed'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
|
||||
export function DesktopFeeds() {
|
||||
const pal = usePalette('default')
|
||||
const {_} = useLingui()
|
||||
const {feeds} = usePinnedFeedsInfos()
|
||||
|
||||
const {feeds: pinnedFeedInfos} = usePinnedFeedsInfos()
|
||||
const selectedFeed = useSelectedFeed()
|
||||
const setSelectedFeed = useSetSelectedFeed()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const route = useNavigationState(state => {
|
||||
if (!state) {
|
||||
return {name: 'Home'}
|
||||
|
@ -22,30 +28,34 @@ export function DesktopFeeds() {
|
|||
|
||||
return (
|
||||
<View style={[styles.container, pal.view]}>
|
||||
<FeedItem href="/" title="Following" current={route.name === 'Home'} />
|
||||
{feeds
|
||||
.filter(f => f.displayName !== 'Following')
|
||||
.map(feed => {
|
||||
try {
|
||||
const params = route.params as Record<string, string>
|
||||
const routeName =
|
||||
feed.type === 'feed' ? 'ProfileFeed' : 'ProfileList'
|
||||
return (
|
||||
<FeedItem
|
||||
key={feed.uri}
|
||||
href={feed.route.href}
|
||||
title={feed.displayName}
|
||||
current={
|
||||
route.name === routeName &&
|
||||
params.name === feed.route.params.name &&
|
||||
params.rkey === feed.route.params.rkey
|
||||
}
|
||||
/>
|
||||
)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
})}
|
||||
{pinnedFeedInfos.map(feedInfo => {
|
||||
const uri = feedInfo.uri
|
||||
let feed: FeedDescriptor
|
||||
if (!uri) {
|
||||
feed = 'home'
|
||||
} else if (uri.includes('app.bsky.feed.generator')) {
|
||||
feed = `feedgen|${uri}`
|
||||
} else if (uri.includes('app.bsky.graph.list')) {
|
||||
feed = `list|${uri}`
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<FeedItem
|
||||
key={feed}
|
||||
href={'/?' + new URLSearchParams([['feed', feed]])}
|
||||
title={feedInfo.displayName}
|
||||
current={route.name === 'Home' && feed === selectedFeed}
|
||||
onPress={() => {
|
||||
setSelectedFeed(feed)
|
||||
navigation.navigate('Home')
|
||||
if (feed === selectedFeed) {
|
||||
emitSoftReset()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
<View style={{paddingTop: 8, paddingBottom: 6}}>
|
||||
<TextLink
|
||||
type="lg"
|
||||
|
@ -62,10 +72,12 @@ function FeedItem({
|
|||
title,
|
||||
href,
|
||||
current,
|
||||
onPress,
|
||||
}: {
|
||||
title: string
|
||||
href: string
|
||||
current: boolean
|
||||
onPress: () => void
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
|
@ -74,6 +86,7 @@ function FeedItem({
|
|||
type="xl"
|
||||
href={href}
|
||||
text={title}
|
||||
onPress={onPress}
|
||||
style={[
|
||||
current ? pal.text : pal.textLight,
|
||||
{letterSpacing: 0.15, fontWeight: current ? '500' : 'normal'},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue