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,
|
||||||
|
|||||||
+150
-147
@@ -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,159 +23,161 @@ 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,
|
({
|
||||||
style,
|
listsList,
|
||||||
showPostFollowBtn,
|
style,
|
||||||
scrollElRef,
|
showPostFollowBtn,
|
||||||
onPressTryAgain,
|
scrollElRef,
|
||||||
renderEmptyState,
|
onPressTryAgain,
|
||||||
testID,
|
renderEmptyState,
|
||||||
headerOffset = 0,
|
testID,
|
||||||
}: {
|
headerOffset = 0,
|
||||||
listsList: ListsListModel
|
}: {
|
||||||
style?: StyleProp<ViewStyle>
|
listsList: ListsListModel
|
||||||
showPostFollowBtn?: boolean
|
style?: StyleProp<ViewStyle>
|
||||||
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
showPostFollowBtn?: boolean
|
||||||
onPressTryAgain?: () => void
|
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
||||||
renderEmptyState?: () => JSX.Element
|
onPressTryAgain?: () => void
|
||||||
testID?: string
|
renderEmptyState?: () => JSX.Element
|
||||||
headerOffset?: number
|
testID?: string
|
||||||
}) {
|
headerOffset?: number
|
||||||
const pal = usePalette('default')
|
}) => {
|
||||||
const {track} = useAnalytics()
|
const pal = usePalette('default')
|
||||||
const [isRefreshing, setIsRefreshing] = React.useState(false)
|
const {track} = useAnalytics()
|
||||||
|
const [isRefreshing, setIsRefreshing] = React.useState(false)
|
||||||
|
|
||||||
const data = React.useMemo(() => {
|
const data = React.useMemo(() => {
|
||||||
let items: any[] = []
|
let items: any[] = []
|
||||||
if (listsList.hasLoaded) {
|
if (listsList.hasLoaded) {
|
||||||
if (listsList.hasError) {
|
if (listsList.hasError) {
|
||||||
items = items.concat([ERROR_ITEM])
|
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 <View />
|
if (listsList.isEmpty) {
|
||||||
} else if (item === ERROR_ITEM) {
|
items = items.concat([EMPTY_ITEM])
|
||||||
return (
|
} else {
|
||||||
<ErrorMessage
|
items = items.concat(listsList.lists)
|
||||||
message={listsList.error}
|
}
|
||||||
onPressTryAgain={onPressTryAgain}
|
if (listsList.loadMoreError) {
|
||||||
/>
|
items = items.concat([LOAD_MORE_ERROR_ITEM])
|
||||||
)
|
}
|
||||||
} else if (item === LOAD_MORE_ERROR_ITEM) {
|
} else if (listsList.isLoading) {
|
||||||
return (
|
items = items.concat([LOADING_ITEM])
|
||||||
<LoadMoreRetryBtn
|
|
||||||
label="There was an issue fetching your lists. Tap here to try again."
|
|
||||||
onPress={onPressRetryLoadMore}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
} else if (item === LOADING_ITEM) {
|
|
||||||
return <ProfileCardFeedLoadingPlaceholder />
|
|
||||||
}
|
}
|
||||||
return <ListCard list={item} />
|
return items
|
||||||
},
|
}, [
|
||||||
[listsList, onPressTryAgain, onPressRetryLoadMore, showPostFollowBtn],
|
listsList.hasError,
|
||||||
)
|
listsList.hasLoaded,
|
||||||
|
listsList.isLoading,
|
||||||
|
listsList.isEmpty,
|
||||||
|
listsList.lists,
|
||||||
|
listsList.loadMoreError,
|
||||||
|
])
|
||||||
|
|
||||||
const Footer = React.useCallback(
|
// events
|
||||||
() =>
|
// =
|
||||||
listsList.isLoading ? (
|
|
||||||
<View style={styles.feedFooter}>
|
|
||||||
<ActivityIndicator />
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<View />
|
|
||||||
),
|
|
||||||
[listsList],
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
const onRefresh = React.useCallback(async () => {
|
||||||
<View testID={testID} style={style}>
|
track('Lists:onRefresh')
|
||||||
{data.length > 0 && (
|
setIsRefreshing(true)
|
||||||
<FlatList
|
try {
|
||||||
testID={testID ? `${testID}-flatlist` : undefined}
|
await listsList.refresh()
|
||||||
ref={scrollElRef}
|
} catch (err) {
|
||||||
data={data}
|
listsList.rootStore.log.error('Failed to refresh lists', err)
|
||||||
keyExtractor={item => item._reactKey}
|
}
|
||||||
renderItem={renderItem}
|
setIsRefreshing(false)
|
||||||
ListFooterComponent={Footer}
|
}, [listsList, track, setIsRefreshing])
|
||||||
refreshControl={
|
|
||||||
<RefreshControl
|
const onEndReached = React.useCallback(async () => {
|
||||||
refreshing={isRefreshing}
|
track('Lists:onEndReached')
|
||||||
onRefresh={onRefresh}
|
try {
|
||||||
tintColor={pal.colors.text}
|
await listsList.loadMore()
|
||||||
titleColor={pal.colors.text}
|
} catch (err) {
|
||||||
progressViewOffset={headerOffset}
|
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()
|
||||||
}
|
}
|
||||||
contentContainerStyle={s.contentContainer}
|
return <View />
|
||||||
style={{paddingTop: headerOffset}}
|
} else if (item === ERROR_ITEM) {
|
||||||
onEndReached={onEndReached}
|
return (
|
||||||
onEndReachedThreshold={0.6}
|
<ErrorMessage
|
||||||
removeClippedSubviews={true}
|
message={listsList.error}
|
||||||
contentOffset={{x: 0, y: headerOffset * -1}}
|
onPressTryAgain={onPressTryAgain}
|
||||||
// @ts-ignore our .web version only -prf
|
/>
|
||||||
desktopFixedHeight
|
)
|
||||||
/>
|
} else if (item === LOAD_MORE_ERROR_ITEM) {
|
||||||
)}
|
return (
|
||||||
</View>
|
<LoadMoreRetryBtn
|
||||||
)
|
label="There was an issue fetching your lists. Tap here to try again."
|
||||||
}
|
onPress={onPressRetryLoadMore}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
} else if (item === LOADING_ITEM) {
|
||||||
|
return <ProfileCardFeedLoadingPlaceholder />
|
||||||
|
}
|
||||||
|
return <ListCard list={item} />
|
||||||
|
},
|
||||||
|
[listsList, onPressTryAgain, onPressRetryLoadMore, showPostFollowBtn],
|
||||||
|
)
|
||||||
|
|
||||||
|
const Footer = React.useCallback(
|
||||||
|
() =>
|
||||||
|
listsList.isLoading ? (
|
||||||
|
<View style={styles.feedFooter}>
|
||||||
|
<ActivityIndicator />
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View />
|
||||||
|
),
|
||||||
|
[listsList],
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View testID={testID} style={style}>
|
||||||
|
{data.length > 0 && (
|
||||||
|
<FlatList
|
||||||
|
testID={testID ? `${testID}-flatlist` : undefined}
|
||||||
|
ref={scrollElRef}
|
||||||
|
data={data}
|
||||||
|
keyExtractor={item => item._reactKey}
|
||||||
|
renderItem={renderItem}
|
||||||
|
ListFooterComponent={Footer}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl
|
||||||
|
refreshing={isRefreshing}
|
||||||
|
onRefresh={onRefresh}
|
||||||
|
tintColor={pal.colors.text}
|
||||||
|
titleColor={pal.colors.text}
|
||||||
|
progressViewOffset={headerOffset}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
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
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</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
|
||||||
|
other users' lists on their profiles.
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<View style={styles.btns}>
|
||||||
type="inverted"
|
<Button type="inverted" style={styles.btn} onPress={onPressCreateList}>
|
||||||
style={styles.emptyBtn}
|
<FontAwesomeIcon
|
||||||
onPress={onPressFindAccounts}>
|
icon="plus"
|
||||||
<Text type="lg-medium" style={palInverted.text}>
|
style={palInverted.text as FontAwesomeIconStyle}
|
||||||
Find accounts to follow
|
size={14}
|
||||||
|
/>
|
||||||
|
<Text type="lg-medium" style={palInverted.text}>
|
||||||
|
New blocklist
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</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>
|
</Text>
|
||||||
<FontAwesomeIcon
|
</View>
|
||||||
icon="angle-right"
|
|
||||||
style={palInverted.text as FontAwesomeIconStyle}
|
|
||||||
size={14}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</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
|
||||||
|
they include. Blocklists and your subscriptions are public.
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<View style={styles.btns}>
|
||||||
type="inverted"
|
<Button type="inverted" style={styles.btn} onPress={onPressCreateList}>
|
||||||
style={styles.emptyBtn}
|
<FontAwesomeIcon
|
||||||
onPress={onPressFindAccounts}>
|
icon="plus"
|
||||||
<Text type="lg-medium" style={palInverted.text}>
|
style={palInverted.text as FontAwesomeIconStyle}
|
||||||
Find accounts to follow
|
size={14}
|
||||||
</Text>
|
/>
|
||||||
<FontAwesomeIcon
|
<Text type="lg-medium" style={palInverted.text}>
|
||||||
icon="angle-right"
|
New blocklist
|
||||||
style={palInverted.text as FontAwesomeIconStyle}
|
</Text>
|
||||||
size={14}
|
</Button>
|
||||||
/>
|
</View>
|
||||||
</Button>
|
|
||||||
</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