diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-03-15 15:46:39 -0500 |
---|---|---|
committer | Paul Frazee <pfrazee@gmail.com> | 2023-03-15 15:46:39 -0500 |
commit | 474b4b7840ce1ee625f19ff02f15ca12b3879c55 (patch) | |
tree | f8e27a2ecb4b07c65f348e206a014a5f0ba06f29 | |
parent | 8a279b8d2cd003755200426e2ab32d0522783744 (diff) | |
download | voidsky-474b4b7840ce1ee625f19ff02f15ca12b3879c55.tar.zst |
Optimize and refactor profile rendering a bit
-rw-r--r-- | src/state/models/ui/profile.ts | 49 | ||||
-rw-r--r-- | src/view/screens/Profile.tsx | 117 |
2 files changed, 90 insertions, 76 deletions
diff --git a/src/state/models/ui/profile.ts b/src/state/models/ui/profile.ts index 1d4fe28cd..eb38509fb 100644 --- a/src/state/models/ui/profile.ts +++ b/src/state/models/ui/profile.ts @@ -15,6 +15,10 @@ export interface ProfileUiParams { } export class ProfileUiModel { + static LOADING_ITEM = {_reactKey: '__loading__'} + static END_ITEM = {_reactKey: '__end__'} + static EMPTY_ITEM = {_reactKey: '__empty__'} + // data profile: ProfileViewModel feed: FeedModel @@ -76,6 +80,51 @@ export class ProfileUiModel { return this.selectorItems[this.selectedViewIndex] } + get uiItems() { + let arr: any[] = [] + if (this.isInitialLoading) { + arr = arr.concat([ProfileUiModel.LOADING_ITEM]) + } else if (this.currentView.hasError) { + arr = arr.concat([ + { + _reactKey: '__error__', + error: this.currentView.error, + }, + ]) + } else { + if ( + this.selectedView === Sections.Posts || + this.selectedView === Sections.PostsWithReplies + ) { + if (this.feed.hasContent) { + if (this.selectedView === Sections.Posts) { + arr = this.feed.nonReplyFeed + } else { + arr = this.feed.feed.slice() + } + if (!this.feed.hasMore) { + arr = arr.concat([ProfileUiModel.END_ITEM]) + } + } else if (this.feed.isEmpty) { + arr = arr.concat([ProfileUiModel.EMPTY_ITEM]) + } + } else { + arr = arr.concat([ProfileUiModel.EMPTY_ITEM]) + } + } + return arr + } + + get showLoadingMoreFooter() { + if ( + this.selectedView === Sections.Posts || + this.selectedView === Sections.PostsWithReplies + ) { + return this.feed.hasContent && this.feed.hasMore && this.feed.isLoading + } + return false + } + // public api // = diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index c686bd266..a27fa6b82 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -8,6 +8,7 @@ import {ViewSelector} from '../com/util/ViewSelector' import {CenteredView} from '../com/util/Views' import {ProfileUiModel, Sections} from 'state/models/ui/profile' import {useStores} from 'state/index' +import {FeedItemModel} from 'state/models/feed-view' import {ProfileHeader} from '../com/profile/ProfileHeader' import {FeedItem} from '../com/posts/FeedItem' import {PostFeedLoadingPlaceholder} from '../com/util/LoadingPlaceholder' @@ -21,10 +22,6 @@ import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' import {useAnalytics} from 'lib/analytics' import {ComposeIcon2} from 'lib/icons' -const LOADING_ITEM = {_reactKey: '__loading__'} -const END_ITEM = {_reactKey: '__end__'} -const EMPTY_ITEM = {_reactKey: '__empty__'} - type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'> export const ProfileScreen = withAuthRequired( observer(({route}: Props) => { @@ -73,98 +70,66 @@ export const ProfileScreen = withAuthRequired( const onSelectView = (index: number) => { uiState.setSelectedViewIndex(index) } - const onRefresh = () => { + const onRefresh = React.useCallback(() => { uiState .refresh() .catch((err: any) => store.log.error('Failed to refresh user profile', err), ) - } - const onEndReached = () => { + }, [uiState, store]) + const onEndReached = React.useCallback(() => { uiState .loadMore() .catch((err: any) => store.log.error('Failed to load more entries in user profile', err), ) - } - const onPressTryAgain = () => { + }, [uiState, store]) + const onPressTryAgain = React.useCallback(() => { uiState.setup() - } + }, [uiState]) // rendering // = - const renderHeader = () => { + const renderHeader = React.useCallback(() => { if (!uiState) { return <View /> } return <ProfileHeader view={uiState.profile} onRefreshAll={onRefresh} /> - } - let renderItem - let Footer - let items: any[] = [] - if (uiState) { - if (uiState.isInitialLoading) { - items = items.concat([LOADING_ITEM]) - renderItem = () => <PostFeedLoadingPlaceholder /> - } else if (uiState.currentView.hasError) { - items = items.concat([ - { - _reactKey: '__error__', - error: uiState.currentView.error, - }, - ]) - renderItem = (item: any) => ( - <View style={s.p5}> - <ErrorMessage - message={item.error} - onPressTryAgain={onPressTryAgain} - /> - </View> - ) - } else { - if ( - uiState.selectedView === Sections.Posts || - uiState.selectedView === Sections.PostsWithReplies - ) { - if (uiState.feed.hasContent) { - if (uiState.selectedView === Sections.Posts) { - items = uiState.feed.nonReplyFeed - } else { - items = uiState.feed.feed.slice() - } - if (!uiState.feed.hasMore) { - items = items.concat([END_ITEM]) - } else if (uiState.feed.isLoading) { - Footer = LoadingMoreFooter - } - renderItem = (item: any) => { - if (item === END_ITEM) { - return <Text style={styles.endItem}>- end of feed -</Text> - } - return ( - <FeedItem item={item} ignoreMuteFor={uiState.profile.did} /> - ) - } - } else if (uiState.feed.isEmpty) { - items = items.concat([EMPTY_ITEM]) - renderItem = () => ( - <EmptyState - icon={['far', 'message']} - message="No posts yet!" - style={styles.emptyState} + }, [uiState, onRefresh]) + const Footer = React.useMemo(() => { + return uiState.showLoadingMoreFooter ? LoadingMoreFooter : undefined + }, [uiState.showLoadingMoreFooter]) + const renderItem = React.useCallback( + (item: any) => { + 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__') { + return ( + <View style={s.p5}> + <ErrorMessage + message={item.error} + onPressTryAgain={onPressTryAgain} /> - ) - } - } else { - items = items.concat([EMPTY_ITEM]) - renderItem = () => <Text>TODO</Text> + </View> + ) + } else if (item === ProfileUiModel.EMPTY_ITEM) { + return ( + <EmptyState + icon={['far', 'message']} + message="No posts yet!" + style={styles.emptyState} + /> + ) + } else if (item instanceof FeedItemModel) { + return <FeedItem item={item} ignoreMuteFor={uiState.profile.did} /> } - } - } - if (!renderItem) { - renderItem = () => <View /> - } + return <View /> + }, + [onPressTryAgain, uiState.profile.did], + ) return ( <View testID="profileView" style={styles.container}> @@ -180,7 +145,7 @@ export const ProfileScreen = withAuthRequired( <ViewSelector swipeEnabled={false} sections={uiState.selectorItems} - items={items} + items={uiState.uiItems} renderHeader={renderHeader} renderItem={renderItem} ListFooterComponent={Footer} |