import React from 'react' import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' import {useNavigation} from '@react-navigation/native' import {useAnalytics} from 'lib/analytics/analytics' import {useQueryClient} from '@tanstack/react-query' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import {MainScrollProvider} from '../util/MainScrollProvider' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useSetMinimalShellMode} from '#/state/shell' import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' import {ComposeIcon2} from 'lib/icons' import {colors, s} from 'lib/styles' import {View, useWindowDimensions} from 'react-native' import {ListMethods} from '../util/List' import {Feed} from '../posts/Feed' import {TextLink} from '../util/Link' import {FAB} from '../util/fab/FAB' import {LoadLatestBtn} from '../util/load-latest/LoadLatestBtn' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useSession} from '#/state/session' import {useComposerControls} from '#/state/shell/composer' import {listenSoftReset, emitSoftReset} from '#/state/events' import {truncateAndInvalidate} from '#/state/queries/util' import {TabState, getTabState, getRootNavigation} from '#/lib/routes/helpers' import {isNative} from '#/platform/detection' const POLL_FREQ = 60e3 // 60sec export function FeedPage({ testID, isPageFocused, feed, feedParams, renderEmptyState, renderEndOfFeed, }: { testID?: string feed: FeedDescriptor feedParams?: FeedParams isPageFocused: boolean renderEmptyState: () => JSX.Element renderEndOfFeed?: () => JSX.Element }) { const {isSandbox, hasSession} = useSession() const pal = usePalette('default') const {_} = useLingui() const navigation = useNavigation() const {isDesktop} = useWebMediaQueries() const queryClient = useQueryClient() const {openComposer} = useComposerControls() const [isScrolledDown, setIsScrolledDown] = React.useState(false) const setMinimalShellMode = useSetMinimalShellMode() const {screen, track} = useAnalytics() const headerOffset = useHeaderOffset() const scrollElRef = React.useRef(null) const [hasNew, setHasNew] = React.useState(false) const scrollToTop = React.useCallback(() => { scrollElRef.current?.scrollToOffset({ animated: isNative, offset: -headerOffset, }) setMinimalShellMode(false) }, [headerOffset, setMinimalShellMode]) const onSoftReset = React.useCallback(() => { const isScreenFocused = getTabState(getRootNavigation(navigation).getState(), 'Home') === TabState.InsideAtRoot if (isScreenFocused && isPageFocused) { scrollToTop() truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) setHasNew(false) } }, [navigation, isPageFocused, scrollToTop, queryClient, feed, setHasNew]) // fires when page within screen is activated/deactivated React.useEffect(() => { if (!isPageFocused) { return } screen('Feed') return listenSoftReset(onSoftReset) }, [onSoftReset, screen, isPageFocused]) const onPressCompose = React.useCallback(() => { track('HomeScreen:PressCompose') openComposer({}) }, [openComposer, track]) const onPressLoadLatest = React.useCallback(() => { scrollToTop() truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) setHasNew(false) }, [scrollToTop, feed, queryClient, setHasNew]) const ListHeaderComponent = React.useCallback(() => { if (isDesktop) { return ( {isSandbox ? 'SANDBOX' : 'Bluesky'}{' '} {hasNew && ( )} } onPress={emitSoftReset} /> {hasSession && ( } /> )} ) } return <> }, [ isDesktop, pal.view, pal.text, pal.textLight, hasNew, _, isSandbox, hasSession, ]) return ( {(isScrolledDown || hasNew) && ( )} {hasSession && ( } accessibilityRole="button" accessibilityLabel={_(msg({message: `New post`, context: 'action'}))} accessibilityHint="" /> )} ) } function useHeaderOffset() { const {isDesktop, isTablet} = useWebMediaQueries() const {fontScale} = useWindowDimensions() const {hasSession} = useSession() if (isDesktop || isTablet) { return 0 } if (hasSession) { const navBarPad = 16 const navBarText = 21 * fontScale const tabBarPad = 20 + 3 // nav bar padding + border const tabBarText = 16 * fontScale const magic = 7 * fontScale return navBarPad + navBarText + tabBarPad + tabBarText + magic } else { const navBarPad = 16 const navBarText = 21 * fontScale const magic = 4 * fontScale return navBarPad + navBarText + magic } }