Bluesky app fork with some witchin' additions 馃挮
at main 119 lines 3.4 kB view raw
1import {useCallback, useEffect, useImperativeHandle, useState} from 'react' 2import {View} from 'react-native' 3import {msg} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {Trans} from '@lingui/react/macro' 6import {useIsFocused} from '@react-navigation/native' 7import {useQueryClient} from '@tanstack/react-query' 8 9import {listenSoftReset} from '#/state/events' 10import { 11 type FeedDescriptor, 12 RQKEY as FEED_RQKEY, 13} from '#/state/queries/post-feed' 14import {PostFeed} from '#/view/com/posts/PostFeed' 15import {EmptyState} from '#/view/com/util/EmptyState' 16import {type ListRef} from '#/view/com/util/List' 17import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 18import {atoms as a} from '#/alf' 19import {Button, ButtonIcon, ButtonText} from '#/components/Button' 20import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 21import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 22import {IS_NATIVE} from '#/env' 23 24interface SectionRef { 25 scrollToTop: () => void 26} 27 28interface FeedSectionProps { 29 ref?: React.Ref<SectionRef> 30 feed: FeedDescriptor 31 headerHeight: number 32 scrollElRef: ListRef 33 isFocused: boolean 34 isOwner: boolean 35 onPressAddUser: () => void 36} 37 38export function FeedSection({ 39 ref, 40 feed, 41 scrollElRef, 42 headerHeight, 43 isFocused, 44 isOwner, 45 onPressAddUser, 46}: FeedSectionProps) { 47 const queryClient = useQueryClient() 48 const [hasNew, setHasNew] = useState(false) 49 const [isScrolledDown, setIsScrolledDown] = useState(false) 50 const isScreenFocused = useIsFocused() 51 const {_} = useLingui() 52 53 const onScrollToTop = useCallback(() => { 54 scrollElRef.current?.scrollToOffset({ 55 animated: IS_NATIVE, 56 offset: -headerHeight, 57 }) 58 queryClient.resetQueries({queryKey: FEED_RQKEY(feed)}) 59 setHasNew(false) 60 }, [scrollElRef, headerHeight, queryClient, feed, setHasNew]) 61 useImperativeHandle(ref, () => ({ 62 scrollToTop: onScrollToTop, 63 })) 64 65 useEffect(() => { 66 if (!isScreenFocused) { 67 return 68 } 69 return listenSoftReset(onScrollToTop) 70 }, [onScrollToTop, isScreenFocused]) 71 72 const renderPostsEmpty = useCallback(() => { 73 return ( 74 <View style={[a.gap_xl, a.align_center]}> 75 <EmptyState 76 icon={HashtagWideIcon} 77 iconSize="2xl" 78 message={_(msg`This feed is empty.`)} 79 /> 80 {isOwner && ( 81 <Button 82 label={_(msg`Start adding people`)} 83 onPress={onPressAddUser} 84 color="primary" 85 size="small"> 86 <ButtonIcon icon={PersonPlusIcon} /> 87 <ButtonText> 88 <Trans>Start adding people!</Trans> 89 </ButtonText> 90 </Button> 91 )} 92 </View> 93 ) 94 }, [_, onPressAddUser, isOwner]) 95 96 return ( 97 <View> 98 <PostFeed 99 testID="listFeed" 100 enabled={isFocused} 101 feed={feed} 102 pollInterval={60e3} 103 disablePoll={hasNew} 104 scrollElRef={scrollElRef} 105 onHasNew={setHasNew} 106 onScrolledDownChange={setIsScrolledDown} 107 renderEmptyState={renderPostsEmpty} 108 headerOffset={headerHeight} 109 /> 110 {(isScrolledDown || hasNew) && ( 111 <LoadLatestBtn 112 onPress={onScrollToTop} 113 label={_(msg`Load new posts`)} 114 showIndicator={hasNew} 115 /> 116 )} 117 </View> 118 ) 119}