Add empty states to the lists screen
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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},
|
||||||
|
|||||||
@@ -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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user