Files
bsky-social-app/src/view/screens/Home.tsx
T
Paul Frazee 075ffdf583 PWI behavior updates (#2207)
* Enable PWI

* Disable access to feeds on PWI

* Remove feeds nav item from drawer when signed out

* Replace discover feed on home with a CTA

* Wire up the sign in and create account buttons to go straight to their respective screens

* Give a custom ScreenHider interface for no-pwi

* Add side borders on desktop to the screen hider

* Filter accounts in the autocomplete according to mod settings

* Trim replies in the post thread that are pwi opt-out

* Show 'learn more' on the content hider when no-override is enabled

* Apply the moderation filter on profile cards

* Disable post search on logged-out view

* Update locale files

* Bump api pkg

* Ensure feeds with no posts don't show as NSFPublic

* Fix types

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2023-12-14 10:31:49 -08:00

216 lines
6.3 KiB
TypeScript

import React from 'react'
import {View, ActivityIndicator, StyleSheet} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types'
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, RenderTabBarFnProps} from 'view/com/pager/Pager'
import {FeedPage} from 'view/com/feeds/FeedPage'
import {HomeLoggedOutCTA} from '../com/auth/HomeLoggedOutCTA'
import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
import {emitSoftReset} from '#/state/events'
import {useSession} from '#/state/session'
import {loadString, saveString} from '#/lib/storage'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
export function HomeScreen(props: Props) {
const {data: preferences} = usePreferencesQuery()
const {isDesktop} = useWebMediaQueries()
const [initialPage, setInitialPage] = React.useState<string | undefined>(
undefined,
)
React.useEffect(() => {
const loadLastActivePage = async () => {
try {
const lastActivePage =
(await loadString('lastActivePage')) ?? 'Following'
setInitialPage(lastActivePage)
} catch {
setInitialPage('Following')
}
}
loadLastActivePage()
}, [])
if (preferences && initialPage !== undefined) {
return (
<HomeScreenReady
{...props}
preferences={preferences}
initialPage={isDesktop ? 'Following' : initialPage}
/>
)
} else {
return (
<View style={styles.loading}>
<ActivityIndicator size="large" />
</View>
)
}
}
function HomeScreenReady({
preferences,
initialPage,
}: Props & {
preferences: UsePreferencesQueryResponse
initialPage: string
}) {
const {hasSession} = useSession()
const setMinimalShellMode = useSetMinimalShellMode()
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
const [selectedPage, setSelectedPage] = React.useState<string>(initialPage)
/**
* 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)
const selectedPageIndex = React.useMemo(() => {
const index = ['Following', ...preferences.feeds.pinned].indexOf(
selectedPage,
)
return Math.max(index, 0)
}, [preferences.feeds.pinned, selectedPage])
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 homeFeedParams = React.useMemo<FeedParams>(() => {
return {
mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled),
mergeFeedSources: preferences.feeds.saved,
}
}, [preferences])
useFocusEffect(
React.useCallback(() => {
setMinimalShellMode(false)
setDrawerSwipeDisabled(selectedPageIndex > 0)
return () => {
setDrawerSwipeDisabled(false)
}
}, [setDrawerSwipeDisabled, selectedPageIndex, setMinimalShellMode]),
)
const onPageSelected = React.useCallback(
(index: number) => {
setMinimalShellMode(false)
setDrawerSwipeDisabled(index > 0)
const page = ['Following', ...preferences.feeds.pinned][index]
setSelectedPage(page)
saveString('lastActivePage', page)
},
[
setDrawerSwipeDisabled,
setSelectedPage,
setMinimalShellMode,
preferences.feeds.pinned,
],
)
const onPressSelected = React.useCallback(() => {
emitSoftReset()
}, [])
const onPageScrollStateChanged = React.useCallback(
(state: 'idle' | 'dragging' | 'settling') => {
if (state === 'dragging') {
setMinimalShellMode(false)
}
},
[setMinimalShellMode],
)
const renderTabBar = React.useCallback(
(props: RenderTabBarFnProps) => {
return (
<FeedsTabBar
key="FEEDS_TAB_BAR"
selectedPage={props.selectedPage}
onSelect={props.onSelect}
testID="homeScreenFeedTabs"
onPressSelected={onPressSelected}
/>
)
},
[onPressSelected],
)
const renderFollowingEmptyState = React.useCallback(() => {
return <FollowingEmptyState />
}, [])
const renderCustomFeedEmptyState = React.useCallback(() => {
return <CustomFeedEmptyState />
}, [])
return hasSession ? (
<Pager
key={pinnedFeedOrderKey}
testID="homeScreen"
initialPage={selectedPageIndex}
onPageSelected={onPageSelected}
onPageScrollStateChanged={onPageScrollStateChanged}
renderTabBar={renderTabBar}
tabBarPosition="top">
<FeedPage
key="1"
testID="followingFeedPage"
isPageFocused={selectedPageIndex === 0}
feed="home"
feedParams={homeFeedParams}
renderEmptyState={renderFollowingEmptyState}
renderEndOfFeed={FollowingEndOfFeed}
/>
{customFeeds.map((f, index) => {
return (
<FeedPage
key={f}
testID="customFeedPage"
isPageFocused={selectedPageIndex === 1 + index}
feed={f}
renderEmptyState={renderCustomFeedEmptyState}
/>
)
})}
</Pager>
) : (
<Pager
testID="homeScreen"
onPageSelected={onPageSelected}
onPageScrollStateChanged={onPageScrollStateChanged}
renderTabBar={renderTabBar}
tabBarPosition="top">
<HomeLoggedOutCTA />
</Pager>
)
}
const styles = StyleSheet.create({
loading: {
height: '100%',
alignContent: 'center',
justifyContent: 'center',
paddingBottom: 100,
},
})