This commit is contained in:
Dan Abramov
2023-11-07 00:56:20 +00:00
parent a4baf14e4b
commit c61da0f351
+76 -148
View File
@@ -8,10 +8,12 @@ import {ViewSelector, ViewSelectorHandle} from '../com/util/ViewSelector'
import {CenteredView} from '../com/util/Views'
import {ScreenHider} from 'view/com/util/moderation/ScreenHider'
import {ProfileUiModel, Sections} from 'state/models/ui/profile'
import {Feed} from 'view/com/posts/Feed'
import {useStores} from 'state/index'
import {PostsFeedSliceModel} from 'state/models/feeds/posts-slice'
import {ProfileHeader} from '../com/profile/ProfileHeader'
import {FeedSlice} from '../com/posts/FeedSlice'
import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
import {ListCard} from 'view/com/lists/ListCard'
import {
PostFeedLoadingPlaceholder,
@@ -31,6 +33,8 @@ import {useSetTitle} from 'lib/hooks/useSetTitle'
import {combinedDisplayName} from 'lib/strings/display-names'
import {logger} from '#/logger'
const SECTION_TITLES_PROFILE = ['Posts', 'Posts & Replies'] // TODO: Other sections
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
export const ProfileScreen = withAuthRequired(
observer(function ProfileScreenImpl({route}: Props) {
@@ -99,12 +103,7 @@ export const ProfileScreen = withAuthRequired(
: uiState.profile.handle
store.shell.openComposer({mention})
}, [store, track, uiState])
const onSelectView = React.useCallback(
(index: number) => {
uiState.setSelectedViewIndex(index)
},
[uiState],
)
const onRefresh = React.useCallback(() => {
uiState
.refresh()
@@ -112,13 +111,7 @@ export const ProfileScreen = withAuthRequired(
logger.error('Failed to refresh user profile', {error: err}),
)
}, [uiState])
const onEndReached = React.useCallback(() => {
uiState.loadMore().catch((err: any) =>
logger.error('Failed to load more entries in user profile', {
error: err,
}),
)
}, [uiState])
const onPressTryAgain = React.useCallback(() => {
uiState.setup()
}, [uiState])
@@ -139,126 +132,6 @@ export const ProfileScreen = withAuthRequired(
)
}, [uiState, onRefresh, route.params.hideBackButton])
const Footer = React.useMemo(() => {
return uiState.showLoadingMoreFooter ? LoadingMoreFooter : undefined
}, [uiState.showLoadingMoreFooter])
const renderItem = React.useCallback(
(item: any) => {
// if section is lists
if (uiState.selectedView === Sections.Lists) {
if (item === ProfileUiModel.LOADING_ITEM) {
return <ProfileCardFeedLoadingPlaceholder />
} else if (item._reactKey === '__error__') {
return (
<View style={s.p5}>
<ErrorMessage
message={item.error}
onPressTryAgain={onPressTryAgain}
/>
</View>
)
} else if (item === ProfileUiModel.EMPTY_ITEM) {
return (
<EmptyState
testID="listsEmpty"
icon="list-ul"
message="No lists yet!"
style={styles.emptyState}
/>
)
} else {
return <ListCard testID={`list-${item.name}`} list={item} />
}
// if section is custom algorithms
} else if (uiState.selectedView === Sections.CustomAlgorithms) {
if (item === ProfileUiModel.LOADING_ITEM) {
return <ProfileCardFeedLoadingPlaceholder />
} else if (item._reactKey === '__error__') {
return (
<View style={s.p5}>
<ErrorMessage
message={item.error}
onPressTryAgain={onPressTryAgain}
/>
</View>
)
} else if (item === ProfileUiModel.EMPTY_ITEM) {
return (
<EmptyState
testID="customAlgorithmsEmpty"
icon="list-ul"
message="No custom algorithms yet!"
style={styles.emptyState}
/>
)
} else if (item instanceof FeedSourceModel) {
return (
<FeedSourceCard
item={item}
showSaveBtn
showLikes
showDescription
/>
)
}
// if section is posts or posts & replies
} else {
if (item === ProfileUiModel.END_ITEM) {
return <Text style={styles.endItem}>- end of feed -</Text>
} else if (item === ProfileUiModel.LOADING_ITEM) {
return <PostFeedLoadingPlaceholder />
} else if (item._reactKey === '__error__') {
if (uiState.feed.isBlocking) {
return (
<EmptyState
icon="ban"
message="Posts hidden"
style={styles.emptyState}
/>
)
}
if (uiState.feed.isBlockedBy) {
return (
<EmptyState
icon="ban"
message="Posts hidden"
style={styles.emptyState}
/>
)
}
return (
<View style={s.p5}>
<ErrorMessage
message={item.error}
onPressTryAgain={onPressTryAgain}
/>
</View>
)
} else if (item === ProfileUiModel.EMPTY_ITEM) {
return (
<EmptyState
icon={['far', 'message']}
message="No posts yet!"
style={styles.emptyState}
/>
)
} else if (item instanceof PostsFeedSliceModel) {
return (
<FeedSlice slice={item} ignoreFilterFor={uiState.profile.did} />
)
}
}
return <View />
},
[
onPressTryAgain,
uiState.selectedView,
uiState.profile.did,
uiState.feed.isBlocking,
uiState.feed.isBlockedBy,
],
)
return (
<ScreenHider
testID="profileView"
@@ -272,22 +145,35 @@ export const ProfileScreen = withAuthRequired(
message={uiState.profile.error}
onPressTryAgain={onPressTryAgain}
/>
) : uiState.profile.hasLoaded ? (
<ViewSelector
ref={viewSelectorRef}
swipeEnabled={false}
sections={uiState.selectorItems}
items={uiState.uiItems}
renderHeader={renderHeader}
renderItem={renderItem}
ListFooterComponent={Footer}
refreshing={uiState.isRefreshing || false}
onSelectView={onSelectView}
onRefresh={onRefresh}
onEndReached={onEndReached}
/>
) : (
<CenteredView>{renderHeader()}</CenteredView>
<View
style={{
flex: 1,
}}>
<PagerWithHeader
isHeaderReady={uiState.profile.hasLoaded}
items={SECTION_TITLES_PROFILE}
renderHeader={renderHeader}>
{({onScroll, headerHeight, isScrolledDown}) => (
<FeedSection
ref={null}
feed={uiState.feed}
onScroll={onScroll}
headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
/>
)}
{({onScroll, headerHeight, isScrolledDown}) => (
<FeedSection
ref={null}
feed={uiState.feed}
onScroll={onScroll}
headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
/>
)}
</PagerWithHeader>
</View>
)}
<FAB
testID="composeFAB"
@@ -302,6 +188,48 @@ export const ProfileScreen = withAuthRequired(
}),
)
interface FeedSectionProps {
feed: PostsFeedModel
onScroll: OnScrollCb
headerHeight: number
isScrolledDown: boolean
}
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
function FeedSectionImpl(
{feed, onScroll, headerHeight, isScrolledDown},
ref,
) {
const hasNew = feed.hasNewLatest && !feed.isRefreshing
const scrollElRef = React.useRef<FlatList>(null)
const onScrollToTop = React.useCallback(() => {
scrollElRef.current?.scrollToOffset({offset: -headerHeight})
feed.refresh()
}, [feed, scrollElRef, headerHeight])
React.useImperativeHandle(ref, () => ({
scrollToTop: onScrollToTop,
}))
const renderPostsEmpty = React.useCallback(() => {
return <EmptyState icon="feed" message="This feed is empty!" />
}, [])
return (
<View>
<Feed
testID="listFeed"
feed={feed}
scrollElRef={scrollElRef}
onScroll={onScroll}
scrollEventThrottle={1}
renderEmptyState={renderPostsEmpty}
headerOffset={headerHeight}
/>
</View>
)
},
)
function LoadingMoreFooter() {
return (
<View style={styles.loadingMoreFooter}>