diff --git a/src/state/models/lists/lists-list.ts b/src/state/models/lists/lists-list.ts
new file mode 100644
index 0000000000..598652b122
--- /dev/null
+++ b/src/state/models/lists/lists-list.ts
@@ -0,0 +1,133 @@
+import {makeAutoObservable} from 'mobx'
+import {
+ AppBskyGraphGetLists as GetLists,
+ AppBskyGraphGetListBlocks as GetListBlocks,
+ AppBskyGraphDefs as GraphDefs,
+} from '@atproto/api'
+import {RootStoreModel} from '../root-store'
+import {cleanError} from 'lib/strings/errors'
+import {bundleAsync} from 'lib/async/bundle'
+
+const PAGE_SIZE = 30
+
+export class ListsListModel {
+ // state
+ isLoading = false
+ isRefreshing = false
+ hasLoaded = false
+ error = ''
+ loadMoreError = ''
+ hasMore = true
+ loadMoreCursor?: string
+
+ // data
+ lists: GraphDefs.ListView[] = []
+
+ constructor(
+ public rootStore: RootStoreModel,
+ public source: 'blocklists' | string,
+ ) {
+ makeAutoObservable(
+ this,
+ {
+ rootStore: false,
+ },
+ {autoBind: true},
+ )
+ }
+
+ get hasContent() {
+ return this.lists.length > 0
+ }
+
+ get hasError() {
+ return this.error !== ''
+ }
+
+ get isEmpty() {
+ return this.hasLoaded && !this.hasContent
+ }
+
+ // public api
+ // =
+
+ async refresh() {
+ return this.loadMore(true)
+ }
+
+ loadMore = bundleAsync(async (replace: boolean = false) => {
+ if (!replace && !this.hasMore) {
+ return
+ }
+ this._xLoading(replace)
+ try {
+ let res
+ if (this.source === 'mine') {
+ res = await this.rootStore.agent.app.bsky.graph.getListBlocks({
+ limit: PAGE_SIZE,
+ cursor: replace ? undefined : this.loadMoreCursor,
+ })
+ } else {
+ res = await this.rootStore.agent.app.bsky.graph.getLists({
+ actor: this.source,
+ limit: PAGE_SIZE,
+ cursor: replace ? undefined : this.loadMoreCursor,
+ })
+ }
+ if (replace) {
+ this._replaceAll(res)
+ } else {
+ this._appendAll(res)
+ }
+ this._xIdle()
+ } catch (e: any) {
+ this._xIdle(replace ?? e, !replace ?? e)
+ }
+ })
+
+ /**
+ * Attempt to load more again after a failure
+ */
+ async retryLoadMore() {
+ this.loadMoreError = ''
+ this.hasMore = true
+ return this.loadMore()
+ }
+
+ // state transitions
+ // =
+
+ _xLoading(isRefreshing = false) {
+ this.isLoading = true
+ this.isRefreshing = isRefreshing
+ this.error = ''
+ }
+
+ _xIdle(err?: any, loadMoreErr?: any) {
+ this.isLoading = false
+ this.isRefreshing = false
+ this.hasLoaded = true
+ this.error = cleanError(err)
+ this.loadMoreError = cleanError(loadMoreErr)
+ if (err) {
+ this.rootStore.log.error('Failed to fetch user lists', err)
+ }
+ if (loadMoreErr) {
+ this.rootStore.log.error('Failed to fetch user lists', loadMoreErr)
+ }
+ }
+
+ // helper functions
+ // =
+
+ _replaceAll(res: GetLists.Response | GetListBlocks.Response) {
+ this.lists = []
+ this._appendAll(res)
+ }
+
+ _appendAll(res: GetLists.Response | GetListBlocks.Response) {
+ this.loadMoreCursor = res.data.cursor
+ this.hasMore = !!this.loadMoreCursor
+ this.lists = this.lists.concat(res.data.lists)
+ }
+}
diff --git a/src/state/models/ui/profile.ts b/src/state/models/ui/profile.ts
index d06a196f3d..a4bff69de0 100644
--- a/src/state/models/ui/profile.ts
+++ b/src/state/models/ui/profile.ts
@@ -2,13 +2,19 @@ import {makeAutoObservable} from 'mobx'
import {RootStoreModel} from '../root-store'
import {ProfileModel} from '../content/profile'
import {PostsFeedModel} from '../feeds/posts'
+import {ListsListModel} from '../lists/lists-list'
export enum Sections {
Posts = 'Posts',
PostsWithReplies = 'Posts & replies',
+ Lists = 'Lists',
}
-const USER_SELECTOR_ITEMS = [Sections.Posts, Sections.PostsWithReplies]
+const USER_SELECTOR_ITEMS = [
+ Sections.Posts,
+ Sections.PostsWithReplies,
+ Sections.Lists,
+]
export interface ProfileUiParams {
user: string
@@ -22,6 +28,7 @@ export class ProfileUiModel {
// data
profile: ProfileModel
feed: PostsFeedModel
+ lists: ListsListModel
// ui state
selectedViewIndex = 0
@@ -43,14 +50,17 @@ export class ProfileUiModel {
actor: params.user,
limit: 10,
})
+ this.lists = new ListsListModel(rootStore, params.user)
}
- get currentView(): PostsFeedModel {
+ get currentView(): PostsFeedModel | ListsListModel {
if (
this.selectedView === Sections.Posts ||
this.selectedView === Sections.PostsWithReplies
) {
return this.feed
+ } else if (this.selectedView === Sections.Lists) {
+ return this.lists
}
throw new Error(`Invalid selector value: ${this.selectedViewIndex}`)
}
@@ -100,6 +110,12 @@ export class ProfileUiModel {
} else if (this.feed.isEmpty) {
arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
}
+ } else if (this.selectedView === Sections.Lists) {
+ if (this.lists.hasContent) {
+ arr = this.lists.lists
+ } else if (this.lists.isEmpty) {
+ arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
+ }
} else {
arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
}
@@ -113,6 +129,8 @@ export class ProfileUiModel {
this.selectedView === Sections.PostsWithReplies
) {
return this.feed.hasContent && this.feed.hasMore && this.feed.isLoading
+ } else if (this.selectedView === Sections.Lists) {
+ return this.lists.hasContent && this.lists.hasMore && this.lists.isLoading
}
return false
}
@@ -133,6 +151,9 @@ export class ProfileUiModel {
.setup()
.catch(err => this.rootStore.log.error('Failed to fetch feed', err)),
])
+ this.lists
+ .loadMore()
+ .catch(err => this.rootStore.log.error('Failed to fetch lists', err))
}
async update() {
diff --git a/src/view/com/lists/ListCard.tsx b/src/view/com/lists/ListCard.tsx
new file mode 100644
index 0000000000..fe1c2238d1
--- /dev/null
+++ b/src/view/com/lists/ListCard.tsx
@@ -0,0 +1,170 @@
+import React from 'react'
+import {StyleSheet, View} from 'react-native'
+import {AppBskyGraphDefs, RichText} from '@atproto/api'
+import {Link} from '../util/Link'
+import {Text} from '../util/text/Text'
+import {RichText as RichTextCom} from '../util/text/RichText'
+import {UserAvatar} from '../util/UserAvatar'
+import {s} from 'lib/styles'
+import {usePalette} from 'lib/hooks/usePalette'
+import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {
+ getProfileViewBasicLabelInfo,
+ getProfileModeration,
+} from 'lib/labeling/helpers'
+import {ModerationBehaviorCode} from 'lib/labeling/types'
+
+export const ListCard = ({
+ testID,
+ list,
+ noBg,
+ noBorder,
+ renderButton,
+}: {
+ testID?: string
+ list: AppBskyGraphDefs.ListView
+ noBg?: boolean
+ noBorder?: boolean
+ renderButton?: () => JSX.Element
+}) => {
+ const pal = usePalette('default')
+
+ const descriptionRichText = React.useMemo(() => {
+ if (list.description) {
+ return new RichText({
+ text: list.description,
+ facets: list.descriptionFacets,
+ })
+ }
+ return undefined
+ }, [list])
+
+ return (
+
+
+
+
+
+
+
+ {sanitizeDisplayName(list.name)}
+
+
+ {list.purpose === 'app.bsky.graph.defs#blocklist' && 'Block list'}{' '}
+ by @TODO
+
+ {!!list.viewer?.blocked && (
+
+
+
+ Subscribed
+
+
+
+ )}
+
+ {renderButton ? (
+ {renderButton()}
+ ) : undefined}
+
+ {descriptionRichText ? (
+
+
+
+ ) : undefined}
+
+ )
+}
+
+const styles = StyleSheet.create({
+ outer: {
+ borderTopWidth: 1,
+ paddingHorizontal: 6,
+ },
+ outerNoBorder: {
+ borderTopWidth: 0,
+ },
+ layout: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ layoutAvi: {
+ width: 54,
+ paddingLeft: 4,
+ paddingTop: 8,
+ paddingBottom: 10,
+ },
+ avi: {
+ width: 40,
+ height: 40,
+ borderRadius: 20,
+ resizeMode: 'cover',
+ },
+ layoutContent: {
+ flex: 1,
+ paddingRight: 10,
+ paddingTop: 10,
+ paddingBottom: 10,
+ },
+ layoutButton: {
+ paddingRight: 10,
+ },
+ details: {
+ paddingLeft: 54,
+ paddingRight: 10,
+ paddingBottom: 10,
+ },
+ pill: {
+ borderRadius: 4,
+ paddingHorizontal: 6,
+ paddingVertical: 2,
+ },
+ btn: {
+ paddingVertical: 7,
+ borderRadius: 50,
+ marginLeft: 6,
+ paddingHorizontal: 14,
+ },
+
+ followedBy: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingLeft: 54,
+ paddingRight: 20,
+ marginBottom: 10,
+ marginTop: -6,
+ },
+ followedByAviContainer: {
+ width: 24,
+ height: 36,
+ },
+ followedByAvi: {
+ width: 36,
+ height: 36,
+ borderRadius: 18,
+ padding: 2,
+ },
+ followsByDesc: {
+ flex: 1,
+ paddingRight: 10,
+ },
+})
diff --git a/src/view/com/lists/ListItems.tsx b/src/view/com/lists/ListItems.tsx
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/view/com/lists/ListsList.tsx b/src/view/com/lists/ListsList.tsx
new file mode 100644
index 0000000000..c936839aca
--- /dev/null
+++ b/src/view/com/lists/ListsList.tsx
@@ -0,0 +1,181 @@
+import React, {MutableRefObject} from 'react'
+import {
+ ActivityIndicator,
+ RefreshControl,
+ StyleProp,
+ StyleSheet,
+ View,
+ ViewStyle,
+} from 'react-native'
+import {FlatList} from '../util/Views'
+import {ListCard} from './ListCard'
+import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
+import {ErrorMessage} from '../util/error/ErrorMessage'
+import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
+import {ListsListModel} from 'state/models/lists/lists-list'
+import {useAnalytics} from 'lib/analytics'
+import {usePalette} from 'lib/hooks/usePalette'
+import {s} from 'lib/styles'
+
+const LOADING_ITEM = {_reactKey: '__loading__'}
+const EMPTY_ITEM = {_reactKey: '__empty__'}
+const ERROR_ITEM = {_reactKey: '__error__'}
+const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
+
+export function ListsList({
+ listsList,
+ style,
+ showPostFollowBtn,
+ scrollElRef,
+ onPressTryAgain,
+ renderEmptyState,
+ testID,
+ headerOffset = 0,
+}: {
+ listsList: ListsListModel
+ style?: StyleProp
+ showPostFollowBtn?: boolean
+ scrollElRef?: MutableRefObject | null>
+ onPressTryAgain?: () => void
+ renderEmptyState?: () => JSX.Element
+ testID?: string
+ headerOffset?: number
+}) {
+ const pal = usePalette('default')
+ const {track} = useAnalytics()
+ const [isRefreshing, setIsRefreshing] = React.useState(false)
+
+ const data = React.useMemo(() => {
+ let items: any[] = []
+ if (listsList.hasLoaded) {
+ if (listsList.hasError) {
+ items = items.concat([ERROR_ITEM])
+ }
+ if (listsList.isEmpty) {
+ items = items.concat([EMPTY_ITEM])
+ } else {
+ items = items.concat(listsList.lists)
+ }
+ if (listsList.loadMoreError) {
+ items = items.concat([LOAD_MORE_ERROR_ITEM])
+ }
+ } else if (listsList.isLoading) {
+ items = items.concat([LOADING_ITEM])
+ }
+ return items
+ }, [
+ listsList.hasError,
+ listsList.hasLoaded,
+ listsList.isLoading,
+ listsList.isEmpty,
+ listsList.lists,
+ listsList.loadMoreError,
+ ])
+
+ // events
+ // =
+
+ const onRefresh = React.useCallback(async () => {
+ track('Lists:onRefresh')
+ setIsRefreshing(true)
+ try {
+ await listsList.refresh()
+ } catch (err) {
+ listsList.rootStore.log.error('Failed to refresh lists', err)
+ }
+ setIsRefreshing(false)
+ }, [listsList, track, setIsRefreshing])
+
+ const onEndReached = React.useCallback(async () => {
+ track('Lists:onEndReached')
+ try {
+ await listsList.loadMore()
+ } catch (err) {
+ listsList.rootStore.log.error('Failed to load more lists', err)
+ }
+ }, [listsList, track])
+
+ const onPressRetryLoadMore = React.useCallback(() => {
+ listsList.retryLoadMore()
+ }, [listsList])
+
+ // rendering
+ // =
+
+ const renderItem = React.useCallback(
+ ({item}: {item: any}) => {
+ if (item === EMPTY_ITEM) {
+ if (renderEmptyState) {
+ return renderEmptyState()
+ }
+ return
+ } else if (item === ERROR_ITEM) {
+ return (
+
+ )
+ } else if (item === LOAD_MORE_ERROR_ITEM) {
+ return (
+
+ )
+ } else if (item === LOADING_ITEM) {
+ return
+ }
+ return
+ },
+ [listsList, onPressTryAgain, onPressRetryLoadMore, showPostFollowBtn],
+ )
+
+ const Footer = React.useCallback(
+ () =>
+ listsList.isLoading ? (
+
+
+
+ ) : (
+
+ ),
+ [listsList],
+ )
+
+ return (
+
+ {data.length > 0 && (
+ item._reactKey}
+ renderItem={renderItem}
+ ListFooterComponent={Footer}
+ refreshControl={
+
+ }
+ contentContainerStyle={s.contentContainer}
+ style={{paddingTop: headerOffset}}
+ onEndReached={onEndReached}
+ onEndReachedThreshold={0.6}
+ removeClippedSubviews={true}
+ contentOffset={{x: 0, y: headerOffset * -1}}
+ // @ts-ignore our .web version only -prf
+ desktopFixedHeight
+ />
+ )}
+
+ )
+}
+
+const styles = StyleSheet.create({
+ feedFooter: {paddingTop: 20},
+})
diff --git a/src/view/com/lists/MyListsEmptyState.tsx b/src/view/com/lists/MyListsEmptyState.tsx
new file mode 100644
index 0000000000..2751e10808
--- /dev/null
+++ b/src/view/com/lists/MyListsEmptyState.tsx
@@ -0,0 +1,80 @@
+import React from 'react'
+import {StyleSheet, View} from 'react-native'
+import {useNavigation} from '@react-navigation/native'
+import {
+ FontAwesomeIcon,
+ FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
+import {Text} from '../util/text/Text'
+import {Button} from '../util/forms/Button'
+import {MagnifyingGlassIcon} from 'lib/icons'
+import {NavigationProp} from 'lib/routes/types'
+import {usePalette} from 'lib/hooks/usePalette'
+import {s} from 'lib/styles'
+
+export function MyListsEmptyState() {
+ const pal = usePalette('default')
+ const palInverted = usePalette('inverted')
+ const navigation = useNavigation()
+
+ const onPressFindAccounts = React.useCallback(() => {
+ navigation.navigate('SearchTab')
+ navigation.popToTop()
+ }, [navigation])
+
+ return (
+
+
+
+
+
+ Your following feed is empty! Find some accounts to follow to fix this.
+
+
+
+ )
+}
+const styles = StyleSheet.create({
+ emptyContainer: {
+ height: '100%',
+ paddingVertical: 40,
+ paddingHorizontal: 30,
+ },
+ emptyIconContainer: {
+ marginBottom: 16,
+ },
+ emptyIcon: {
+ marginLeft: 'auto',
+ marginRight: 'auto',
+ },
+ emptyBtn: {
+ marginVertical: 20,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ paddingVertical: 18,
+ paddingHorizontal: 24,
+ borderRadius: 30,
+ },
+
+ feedsTip: {
+ position: 'absolute',
+ left: 22,
+ },
+ feedsTipArrow: {
+ marginLeft: 32,
+ marginTop: 8,
+ },
+})
diff --git a/src/view/com/lists/SubscribedBlocklistsEmptyState.tsx b/src/view/com/lists/SubscribedBlocklistsEmptyState.tsx
new file mode 100644
index 0000000000..977fc10765
--- /dev/null
+++ b/src/view/com/lists/SubscribedBlocklistsEmptyState.tsx
@@ -0,0 +1,80 @@
+import React from 'react'
+import {StyleSheet, View} from 'react-native'
+import {useNavigation} from '@react-navigation/native'
+import {
+ FontAwesomeIcon,
+ FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
+import {Text} from '../util/text/Text'
+import {Button} from '../util/forms/Button'
+import {MagnifyingGlassIcon} from 'lib/icons'
+import {NavigationProp} from 'lib/routes/types'
+import {usePalette} from 'lib/hooks/usePalette'
+import {s} from 'lib/styles'
+
+export function SubscribedBlocklistsEmptyState() {
+ const pal = usePalette('default')
+ const palInverted = usePalette('inverted')
+ const navigation = useNavigation()
+
+ const onPressFindAccounts = React.useCallback(() => {
+ navigation.navigate('SearchTab')
+ navigation.popToTop()
+ }, [navigation])
+
+ return (
+
+
+
+
+
+ Your following feed is empty! Find some accounts to follow to fix this.
+
+
+
+ )
+}
+const styles = StyleSheet.create({
+ emptyContainer: {
+ height: '100%',
+ paddingVertical: 40,
+ paddingHorizontal: 30,
+ },
+ emptyIconContainer: {
+ marginBottom: 16,
+ },
+ emptyIcon: {
+ marginLeft: 'auto',
+ marginRight: 'auto',
+ },
+ emptyBtn: {
+ marginVertical: 20,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ paddingVertical: 18,
+ paddingHorizontal: 24,
+ borderRadius: 30,
+ },
+
+ feedsTip: {
+ position: 'absolute',
+ left: 22,
+ },
+ feedsTipArrow: {
+ marginLeft: 32,
+ marginTop: 8,
+ },
+})
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index 628128e8f1..1f202762af 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -4,6 +4,7 @@ import {Text} from '../util/text/Text'
import {PressableWithHover} from '../util/PressableWithHover'
import {usePalette} from 'lib/hooks/usePalette'
import {isDesktopWeb} from 'platform/detection'
+import {CenteredView} from '../util/Views'
interface Layout {
x: number
@@ -65,7 +66,7 @@ export function TabBar({
],
}
- const onLayout = () => {
+ const onLayout = React.useCallback(() => {
const promises = []
for (let i = 0; i < items.length; i++) {
promises.push(
@@ -86,14 +87,17 @@ export function TabBar({
Promise.all(promises).then((layouts: Layout[]) => {
setItemLayouts(layouts)
})
- }
+ }, [containerRef, itemRefs, setItemLayouts])
- const onPressItem = (index: number) => {
- onSelect?.(index)
- if (index === selectedPage) {
- onPressSelected?.()
- }
- }
+ const onPressItem = React.useCallback(
+ (index: number) => {
+ onSelect?.(index)
+ if (index === selectedPage) {
+ onPressSelected?.()
+ }
+ },
+ [onSelect, onPressSelected, selectedPage],
+ )
return (
0)
},
- [store],
+ [store, setSelectedPage],
)
const onPressSelected = React.useCallback(() => {
diff --git a/src/view/screens/Lists.tsx b/src/view/screens/Lists.tsx
index 55861e1cb6..6380c38d52 100644
--- a/src/view/screens/Lists.tsx
+++ b/src/view/screens/Lists.tsx
@@ -1,24 +1,85 @@
import React from 'react'
-import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
-import {ViewHeader} from '../com/util/ViewHeader'
+import {TabBar} from '../com/pager/TabBar'
+import {Pager, RenderTabBarFnProps} from 'view/com/pager/Pager'
+import {MyListsEmptyState} from 'view/com/lists/MyListsEmptyState'
+import {SubscribedBlocklistsEmptyState} from 'view/com/lists/SubscribedBlocklistsEmptyState'
import {useStores} from 'state/index'
+import {ListsListModel} from 'state/models/lists/lists-list'
+import {ListsList} from 'view/com/lists/ListsList'
+import {usePalette} from 'lib/hooks/usePalette'
type Props = NativeStackScreenProps
export const ListsScreen = withAuthRequired(({route}: Props) => {
+ const pal = usePalette('default')
const store = useStores()
+ const [selectedPage, setSelectedPage] = React.useState(0)
+
+ const mine: ListsListModel = React.useMemo(() => {
+ const list = new ListsListModel(store, store.me.did)
+ list.loadMore()
+ return list
+ }, [store])
+
+ const blocklists: ListsListModel = React.useMemo(() => {
+ const list = new ListsListModel(store, 'blocklists')
+ list.loadMore()
+ return list
+ }, [store])
useFocusEffect(
React.useCallback(() => {
store.shell.setMinimalShellMode(false)
- }, [store]),
+ }, [store, selectedPage]),
)
+ const onPageSelected = React.useCallback(
+ (index: number) => {
+ setSelectedPage(index)
+ },
+ [store, setSelectedPage],
+ )
+
+ const renderTabBar = React.useCallback((props: RenderTabBarFnProps) => {
+ return (
+
+ )
+ }, [])
+
+ const renderMineEmptyState = React.useCallback(() => {
+ return
+ }, [])
+
+ const renderBlockliststEmptyState = React.useCallback(() => {
+ return
+ }, [])
+
return (
-
-
-
+
+
+
+
)
})
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index 5fb212554b..117829296d 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -7,12 +7,16 @@ import {withAuthRequired} from 'view/com/auth/withAuthRequired'
import {ViewSelector} from '../com/util/ViewSelector'
import {CenteredView} from '../com/util/Views'
import {ScreenHider} from 'view/com/util/moderation/ScreenHider'
-import {ProfileUiModel} from 'state/models/ui/profile'
+import {ProfileUiModel, Sections} from 'state/models/ui/profile'
import {useStores} from 'state/index'
import {PostsFeedSliceModel} from 'state/models/feeds/posts'
import {ProfileHeader} from '../com/profile/ProfileHeader'
import {FeedSlice} from '../com/posts/FeedSlice'
-import {PostFeedLoadingPlaceholder} from '../com/util/LoadingPlaceholder'
+import {ListCard} from 'view/com/lists/ListCard'
+import {
+ PostFeedLoadingPlaceholder,
+ ProfileCardFeedLoadingPlaceholder,
+} from '../com/util/LoadingPlaceholder'
import {ErrorScreen} from '../com/util/error/ErrorScreen'
import {ErrorMessage} from '../com/util/error/ErrorMessage'
import {EmptyState} from '../com/util/EmptyState'
@@ -111,52 +115,80 @@ export const ProfileScreen = withAuthRequired(
}, [uiState.showLoadingMoreFooter])
const renderItem = React.useCallback(
(item: any) => {
- if (item === ProfileUiModel.END_ITEM) {
- return - end of feed -
- } else if (item === ProfileUiModel.LOADING_ITEM) {
- return
- } else if (item._reactKey === '__error__') {
- if (uiState.feed.isBlocking) {
+ if (uiState.selectedView === Sections.Lists) {
+ if (item === ProfileUiModel.LOADING_ITEM) {
+ return
+ } else if (item._reactKey === '__error__') {
+ return (
+
+
+
+ )
+ } else if (item === ProfileUiModel.EMPTY_ITEM) {
return (
)
+ } else {
+ return
}
- if (uiState.feed.isBlockedBy) {
+ } else {
+ if (item === ProfileUiModel.END_ITEM) {
+ return - end of feed -
+ } else if (item === ProfileUiModel.LOADING_ITEM) {
+ return
+ } else if (item._reactKey === '__error__') {
+ if (uiState.feed.isBlocking) {
+ return (
+
+ )
+ }
+ if (uiState.feed.isBlockedBy) {
+ return (
+
+ )
+ }
+ return (
+
+
+
+ )
+ } else if (item === ProfileUiModel.EMPTY_ITEM) {
return (
)
+ } else if (item instanceof PostsFeedSliceModel) {
+ return (
+
+ )
}
- return (
-
-
-
- )
- } else if (item === ProfileUiModel.EMPTY_ITEM) {
- return (
-
- )
- } else if (item instanceof PostsFeedSliceModel) {
- return
}
return
},
[
onPressTryAgain,
+ uiState.selectedView,
uiState.profile.did,
uiState.feed.isBlocking,
uiState.feed.isBlockedBy,