diff options
Diffstat (limited to 'src/view/screens/Home.tsx')
-rw-r--r-- | src/view/screens/Home.tsx | 284 |
1 files changed, 154 insertions, 130 deletions
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index c58175327..e8001e973 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -1,154 +1,178 @@ import React from 'react' -import {useWindowDimensions} from 'react-native' -import {useFocusEffect} from '@react-navigation/native' -import {observer} from 'mobx-react-lite' -import isEqual from 'lodash.isequal' +import {View, ActivityIndicator, StyleSheet} from 'react-native' +import {useFocusEffect, useIsFocused} from '@react-navigation/native' import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types' -import {PostsFeedModel} from 'state/models/feeds/posts' -import {withAuthRequired} from 'view/com/auth/withAuthRequired' +import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' 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, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager' -import {useStores} from 'state/index' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {Pager, RenderTabBarFnProps} from 'view/com/pager/Pager' import {FeedPage} from 'view/com/feeds/FeedPage' import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell' - -export const POLL_FREQ = 30e3 // 30sec +import {usePreferencesQuery} from '#/state/queries/preferences' +import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types' +import {emitSoftReset} from '#/state/events' +import {useSession} from '#/state/session' type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'> -export const HomeScreen = withAuthRequired( - observer(function HomeScreenImpl({}: Props) { - const store = useStores() - const setMinimalShellMode = useSetMinimalShellMode() - const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() - const pagerRef = React.useRef<PagerRef>(null) - const [selectedPage, setSelectedPage] = React.useState(0) - const [customFeeds, setCustomFeeds] = React.useState<PostsFeedModel[]>([]) - const [requestedCustomFeeds, setRequestedCustomFeeds] = React.useState< - string[] - >([]) +export function HomeScreen(props: Props) { + const {data: preferences} = usePreferencesQuery() + + if (preferences) { + return <HomeScreenReady {...props} preferences={preferences} /> + } else { + return ( + <View style={styles.loading}> + <ActivityIndicator size="large" /> + </View> + ) + } +} + +function HomeScreenReady({ + preferences, +}: Props & { + preferences: UsePreferencesQueryResponse +}) { + const {hasSession} = useSession() + const setMinimalShellMode = useSetMinimalShellMode() + const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() + const [selectedPage, setSelectedPage] = React.useState(0) + const isPageFocused = useIsFocused() - React.useEffect(() => { - const pinned = store.preferences.pinnedFeeds + /** + * Used to ensure that we re-compute `customFeeds` AND force a re-render of + * the pager with the new order of feeds. + */ + const pinnedFeedOrderKey = JSON.stringify(preferences.feeds.pinned) - if (isEqual(pinned, requestedCustomFeeds)) { - // no changes - return + const customFeeds = React.useMemo(() => { + const pinned = preferences.feeds.pinned + const feeds: FeedDescriptor[] = [] + for (const uri of pinned) { + if (uri.includes('app.bsky.feed.generator')) { + feeds.push(`feedgen|${uri}`) + } else if (uri.includes('app.bsky.graph.list')) { + feeds.push(`list|${uri}`) } + } + return feeds + }, [preferences.feeds.pinned]) - const feeds = [] - for (const uri of pinned) { - if (uri.includes('app.bsky.feed.generator')) { - const model = new PostsFeedModel(store, 'custom', {feed: uri}) - feeds.push(model) - } else if (uri.includes('app.bsky.graph.list')) { - const model = new PostsFeedModel(store, 'list', {list: uri}) - feeds.push(model) - } + const homeFeedParams = React.useMemo<FeedParams>(() => { + return { + mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled), + mergeFeedSources: preferences.feeds.saved, + } + }, [preferences]) + + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + setDrawerSwipeDisabled(selectedPage > 0) + return () => { + setDrawerSwipeDisabled(false) } - pagerRef.current?.setPage(0) - setCustomFeeds(feeds) - setRequestedCustomFeeds(pinned) - }, [ - store, - store.preferences.pinnedFeeds, - customFeeds, - setCustomFeeds, - pagerRef, - requestedCustomFeeds, - setRequestedCustomFeeds, - ]) + }, [setDrawerSwipeDisabled, selectedPage, setMinimalShellMode]), + ) - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - setDrawerSwipeDisabled(selectedPage > 0) - return () => { - setDrawerSwipeDisabled(false) - } - }, [setDrawerSwipeDisabled, selectedPage, setMinimalShellMode]), - ) + const onPageSelected = React.useCallback( + (index: number) => { + setMinimalShellMode(false) + setSelectedPage(index) + setDrawerSwipeDisabled(index > 0) + }, + [setDrawerSwipeDisabled, setSelectedPage, setMinimalShellMode], + ) + + const onPressSelected = React.useCallback(() => { + emitSoftReset() + }, []) - const onPageSelected = React.useCallback( - (index: number) => { + const onPageScrollStateChanged = React.useCallback( + (state: 'idle' | 'dragging' | 'settling') => { + if (state === 'dragging') { setMinimalShellMode(false) - setSelectedPage(index) - setDrawerSwipeDisabled(index > 0) - }, - [setDrawerSwipeDisabled, setSelectedPage, setMinimalShellMode], - ) + } + }, + [setMinimalShellMode], + ) - const onPressSelected = React.useCallback(() => { - store.emitScreenSoftReset() - }, [store]) + const renderTabBar = React.useCallback( + (props: RenderTabBarFnProps) => { + return ( + <FeedsTabBar + key="FEEDS_TAB_BAR" + selectedPage={props.selectedPage} + onSelect={props.onSelect} + testID="homeScreenFeedTabs" + onPressSelected={onPressSelected} + /> + ) + }, + [onPressSelected], + ) - const renderTabBar = React.useCallback( - (props: RenderTabBarFnProps) => { + const renderFollowingEmptyState = React.useCallback(() => { + return <FollowingEmptyState /> + }, []) + + const renderCustomFeedEmptyState = React.useCallback(() => { + return <CustomFeedEmptyState /> + }, []) + + return hasSession ? ( + <Pager + key={pinnedFeedOrderKey} + testID="homeScreen" + onPageSelected={onPageSelected} + onPageScrollStateChanged={onPageScrollStateChanged} + renderTabBar={renderTabBar} + tabBarPosition="top"> + <FeedPage + key="1" + testID="followingFeedPage" + isPageFocused={selectedPage === 0 && isPageFocused} + feed={homeFeedParams.mergeFeedEnabled ? 'home' : 'following'} + feedParams={homeFeedParams} + renderEmptyState={renderFollowingEmptyState} + renderEndOfFeed={FollowingEndOfFeed} + /> + {customFeeds.map((f, index) => { return ( - <FeedsTabBar - key="FEEDS_TAB_BAR" - selectedPage={props.selectedPage} - onSelect={props.onSelect} - testID="homeScreenFeedTabs" - onPressSelected={onPressSelected} + <FeedPage + key={f} + testID="customFeedPage" + isPageFocused={selectedPage === 1 + index && isPageFocused} + feed={f} + renderEmptyState={renderCustomFeedEmptyState} /> ) - }, - [onPressSelected], - ) - - const renderFollowingEmptyState = React.useCallback(() => { - return <FollowingEmptyState /> - }, []) - - const renderCustomFeedEmptyState = React.useCallback(() => { - return <CustomFeedEmptyState /> - }, []) - - return ( - <Pager - ref={pagerRef} - testID="homeScreen" - onPageSelected={onPageSelected} - renderTabBar={renderTabBar} - tabBarPosition="top"> - <FeedPage - key="1" - testID="followingFeedPage" - isPageFocused={selectedPage === 0} - feed={store.me.mainFeed} - renderEmptyState={renderFollowingEmptyState} - renderEndOfFeed={FollowingEndOfFeed} - /> - {customFeeds.map((f, index) => { - return ( - <FeedPage - key={f.reactKey} - testID="customFeedPage" - isPageFocused={selectedPage === 1 + index} - feed={f} - renderEmptyState={renderCustomFeedEmptyState} - /> - ) - })} - </Pager> - ) - }), -) - -export function useHeaderOffset() { - const {isDesktop, isTablet} = useWebMediaQueries() - const {fontScale} = useWindowDimensions() - if (isDesktop) { - return 0 - } - if (isTablet) { - return 50 - } - // default text takes 44px, plus 34px of pad - // scale the 44px by the font scale - return 34 + 44 * fontScale + })} + </Pager> + ) : ( + <Pager + testID="homeScreen" + onPageSelected={onPageSelected} + onPageScrollStateChanged={onPageScrollStateChanged} + renderTabBar={renderTabBar} + tabBarPosition="top"> + <FeedPage + testID="customFeedPage" + isPageFocused={isPageFocused} + feed={`feedgen|at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot`} + renderEmptyState={renderCustomFeedEmptyState} + /> + </Pager> + ) } + +const styles = StyleSheet.create({ + loading: { + height: '100%', + alignContent: 'center', + justifyContent: 'center', + paddingBottom: 100, + }, +}) |