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