Add empty states to the lists screen

This commit is contained in:
Paul Frazee
2023-05-05 11:40:56 -05:00
parent 5e723b0821
commit 806e52705d
5 changed files with 236 additions and 226 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ export class ListsListModel {
this._xLoading(replace) this._xLoading(replace)
try { try {
let res let res
if (this.source === 'mine') { if (this.source === 'blocklists') {
res = await this.rootStore.agent.app.bsky.graph.getListBlocks({ res = await this.rootStore.agent.app.bsky.graph.getListBlocks({
limit: PAGE_SIZE, limit: PAGE_SIZE,
cursor: replace ? undefined : this.loadMoreCursor, cursor: replace ? undefined : this.loadMoreCursor,
+6 -3
View File
@@ -7,6 +7,7 @@ import {
View, View,
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {observer} from 'mobx-react-lite'
import {FlatList} from '../util/Views' import {FlatList} from '../util/Views'
import {ListCard} from './ListCard' import {ListCard} from './ListCard'
import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
@@ -22,7 +23,8 @@ const EMPTY_ITEM = {_reactKey: '__empty__'}
const ERROR_ITEM = {_reactKey: '__error__'} const ERROR_ITEM = {_reactKey: '__error__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
export function ListsList({ export const ListsList = observer(
({
listsList, listsList,
style, style,
showPostFollowBtn, showPostFollowBtn,
@@ -40,7 +42,7 @@ export function ListsList({
renderEmptyState?: () => JSX.Element renderEmptyState?: () => JSX.Element
testID?: string testID?: string
headerOffset?: number headerOffset?: number
}) { }) => {
const pal = usePalette('default') const pal = usePalette('default')
const {track} = useAnalytics() const {track} = useAnalytics()
const [isRefreshing, setIsRefreshing] = React.useState(false) const [isRefreshing, setIsRefreshing] = React.useState(false)
@@ -174,7 +176,8 @@ export function ListsList({
)} )}
</View> </View>
) )
} },
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
feedFooter: {paddingTop: 20}, feedFooter: {paddingTop: 20},
+41 -34
View File
@@ -1,80 +1,87 @@
import React from 'react' import React from 'react'
import {StyleSheet, View} from 'react-native' import {StyleSheet, View} from 'react-native'
import {useNavigation} from '@react-navigation/native'
import { import {
FontAwesomeIcon, FontAwesomeIcon,
FontAwesomeIconStyle, FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome' } from '@fortawesome/react-native-fontawesome'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {Button} from '../util/forms/Button' import {Button} from '../util/forms/Button'
import {MagnifyingGlassIcon} from 'lib/icons'
import {NavigationProp} from 'lib/routes/types'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles' import {s} from 'lib/styles'
export function MyListsEmptyState() { export function MyListsEmptyState() {
const pal = usePalette('default') const pal = usePalette('default')
const palInverted = usePalette('inverted') const palInverted = usePalette('inverted')
const navigation = useNavigation<NavigationProp>()
const onPressFindAccounts = React.useCallback(() => { const onPressCreateList = React.useCallback(() => {
navigation.navigate('SearchTab') // TODO
navigation.popToTop() }, [])
}, [navigation])
return ( return (
<View style={styles.emptyContainer}> <View style={styles.container}>
<View style={styles.emptyIconContainer}> <View style={styles.iconContainer}>
<MagnifyingGlassIcon style={[styles.emptyIcon, pal.text]} size={62} /> <FontAwesomeIcon
icon="list-ul"
style={[styles.icon, pal.text]}
size={62}
/>
</View> </View>
<Text type="xl-medium" style={[s.textCenter, pal.text]}> <Text type="xl-medium" style={[s.textCenter, pal.text]}>
Your following feed is empty! Find some accounts to follow to fix this. Lists are public collections of users. You can create a list or find
</Text> other users' lists on their profiles.
<Button
type="inverted"
style={styles.emptyBtn}
onPress={onPressFindAccounts}>
<Text type="lg-medium" style={palInverted.text}>
Find accounts to follow
</Text> </Text>
<View style={styles.btns}>
<Button type="inverted" style={styles.btn} onPress={onPressCreateList}>
<FontAwesomeIcon <FontAwesomeIcon
icon="angle-right" icon="plus"
style={palInverted.text as FontAwesomeIconStyle} style={palInverted.text as FontAwesomeIconStyle}
size={14} size={14}
/> />
<Text type="lg-medium" style={palInverted.text}>
New blocklist
</Text>
</Button> </Button>
</View> </View>
<View style={[pal.viewLight, styles.notice]}>
<Text type="lg" style={[pal.textLight, s.textCenter]}>
Currently only "blocklists" are available, which is kind of weird but
we wanted to prioritize user safety. Feedlists will be implemented
soon!
</Text>
</View>
</View>
) )
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
emptyContainer: { container: {
height: '100%', height: '100%',
paddingVertical: 40, paddingVertical: 40,
paddingHorizontal: 30, paddingHorizontal: 30,
}, },
emptyIconContainer: { iconContainer: {
marginBottom: 16, marginBottom: 16,
}, },
emptyIcon: { icon: {
marginLeft: 'auto', marginLeft: 'auto',
marginRight: 'auto', marginRight: 'auto',
}, },
emptyBtn: { btns: {
flexDirection: 'row',
justifyContent: 'center',
},
btn: {
gap: 10,
marginVertical: 20, marginVertical: 20,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', paddingVertical: 14,
paddingVertical: 18,
paddingHorizontal: 24, paddingHorizontal: 24,
borderRadius: 30, borderRadius: 30,
}, },
notice: {
feedsTip: { borderRadius: 12,
position: 'absolute', paddingHorizontal: 12,
left: 22, paddingVertical: 10,
}, marginHorizontal: 30,
feedsTipArrow: {
marginLeft: 32,
marginTop: 8,
}, },
}) })
@@ -1,80 +1,80 @@
import React from 'react' import React from 'react'
import {StyleSheet, View} from 'react-native' import {StyleSheet, View} from 'react-native'
import {useNavigation} from '@react-navigation/native'
import { import {
FontAwesomeIcon, FontAwesomeIcon,
FontAwesomeIconStyle, FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome' } from '@fortawesome/react-native-fontawesome'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {Button} from '../util/forms/Button' import {Button} from '../util/forms/Button'
import {MagnifyingGlassIcon} from 'lib/icons'
import {NavigationProp} from 'lib/routes/types'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles' import {s} from 'lib/styles'
export function SubscribedBlocklistsEmptyState() { export function SubscribedBlocklistsEmptyState() {
const pal = usePalette('default') const pal = usePalette('default')
const palInverted = usePalette('inverted') const palInverted = usePalette('inverted')
const navigation = useNavigation<NavigationProp>()
const onPressFindAccounts = React.useCallback(() => { const onPressCreateList = React.useCallback(() => {
navigation.navigate('SearchTab') // TODO
navigation.popToTop() }, [])
}, [navigation])
return ( return (
<View style={styles.emptyContainer}> <View style={styles.container}>
<View style={styles.emptyIconContainer}> <View style={styles.iconContainer}>
<MagnifyingGlassIcon style={[styles.emptyIcon, pal.text]} size={62} /> <FontAwesomeIcon
icon="list-ul"
style={[styles.icon, pal.text]}
size={62}
/>
</View> </View>
<Text type="xl-medium" style={[s.textCenter, pal.text]}> <Text type="xl-medium" style={[s.textCenter, pal.text]}>
Your following feed is empty! Find some accounts to follow to fix this. You can subscribe to blocklists to automatically block all of the users
</Text> they include. Blocklists and your subscriptions are public.
<Button
type="inverted"
style={styles.emptyBtn}
onPress={onPressFindAccounts}>
<Text type="lg-medium" style={palInverted.text}>
Find accounts to follow
</Text> </Text>
<View style={styles.btns}>
<Button type="inverted" style={styles.btn} onPress={onPressCreateList}>
<FontAwesomeIcon <FontAwesomeIcon
icon="angle-right" icon="plus"
style={palInverted.text as FontAwesomeIconStyle} style={palInverted.text as FontAwesomeIconStyle}
size={14} size={14}
/> />
<Text type="lg-medium" style={palInverted.text}>
New blocklist
</Text>
</Button> </Button>
</View> </View>
</View>
) )
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
emptyContainer: { container: {
height: '100%', height: '100%',
paddingVertical: 40, paddingVertical: 40,
paddingHorizontal: 30, paddingHorizontal: 30,
}, },
emptyIconContainer: { iconContainer: {
marginBottom: 16, marginBottom: 16,
}, },
emptyIcon: { icon: {
marginLeft: 'auto', marginLeft: 'auto',
marginRight: 'auto', marginRight: 'auto',
}, },
emptyBtn: { btns: {
flexDirection: 'row',
justifyContent: 'center',
},
btn: {
gap: 10,
marginVertical: 20, marginVertical: 20,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', paddingVertical: 14,
paddingVertical: 18,
paddingHorizontal: 24, paddingHorizontal: 24,
borderRadius: 30, borderRadius: 30,
}, },
notice: {
feedsTip: { borderRadius: 12,
position: 'absolute', paddingHorizontal: 12,
left: 22, paddingVertical: 10,
}, marginHorizontal: 30,
feedsTipArrow: {
marginLeft: 32,
marginTop: 8,
}, },
}) })
+1 -1
View File
@@ -46,7 +46,7 @@ export const ListsScreen = withAuthRequired(({route}: Props) => {
return ( return (
<TabBar <TabBar
{...props} {...props}
items={['Mine', 'Subscribed Blocklists']} items={['My Lists', 'Blocklists']}
indicatorColor={pal.colors.link} indicatorColor={pal.colors.link}
indicatorPosition="bottom" indicatorPosition="bottom"
testID="tabs" testID="tabs"