Add the ability to create new mutelists

This commit is contained in:
Paul Frazee
2023-05-07 12:06:14 -05:00
parent 2e2fc76256
commit 1befc04dcb
5 changed files with 93 additions and 43 deletions
+45 -3
View File
@@ -8,17 +8,25 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
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'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
import {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
import {ListsListModel} from 'state/models/lists/lists-list' import {ListsListModel} from 'state/models/lists/lists-list'
import {useAnalytics} from 'lib/analytics' import {useAnalytics} from 'lib/analytics'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {isDesktopWeb} from 'platform/detection'
const LOADING_ITEM = {_reactKey: '__loading__'} const LOADING_ITEM = {_reactKey: '__loading__'}
const CREATENEW_ITEM = {_reactKey: '__loading__'}
const EMPTY_ITEM = {_reactKey: '__empty__'} 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__'}
@@ -27,17 +35,17 @@ export const ListsList = observer(
({ ({
listsList, listsList,
style, style,
showPostFollowBtn,
scrollElRef, scrollElRef,
onPressTryAgain, onPressTryAgain,
onPressCreateNew,
renderEmptyState, renderEmptyState,
testID, testID,
headerOffset = 0, headerOffset = 0,
}: { }: {
listsList: ListsListModel listsList: ListsListModel
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
showPostFollowBtn?: boolean
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: MutableRefObject<FlatList<any> | null>
onPressCreateNew: () => void
onPressTryAgain?: () => void onPressTryAgain?: () => void
renderEmptyState?: () => JSX.Element renderEmptyState?: () => JSX.Element
testID?: string testID?: string
@@ -56,6 +64,9 @@ export const ListsList = observer(
if (listsList.isEmpty) { if (listsList.isEmpty) {
items = items.concat([EMPTY_ITEM]) items = items.concat([EMPTY_ITEM])
} else { } else {
if (isDesktopWeb) {
items = items.concat([CREATENEW_ITEM])
}
items = items.concat(listsList.lists) items = items.concat(listsList.lists)
} }
if (listsList.loadMoreError) { if (listsList.loadMoreError) {
@@ -111,6 +122,8 @@ export const ListsList = observer(
return renderEmptyState() return renderEmptyState()
} }
return <View /> return <View />
} else if (item === CREATENEW_ITEM) {
return <CreateNewItem onPress={onPressCreateNew} />
} else if (item === ERROR_ITEM) { } else if (item === ERROR_ITEM) {
return ( return (
<ErrorMessage <ErrorMessage
@@ -130,7 +143,7 @@ export const ListsList = observer(
} }
return <ListCard list={item} /> return <ListCard list={item} />
}, },
[listsList, onPressTryAgain, onPressRetryLoadMore, showPostFollowBtn], [listsList, onPressTryAgain, onPressRetryLoadMore, onPressCreateNew],
) )
const Footer = React.useCallback( const Footer = React.useCallback(
@@ -179,6 +192,35 @@ export const ListsList = observer(
}, },
) )
function CreateNewItem({onPress}: {onPress: () => void}) {
const palInverted = usePalette('inverted')
return (
<View style={[styles.createNewContainer]}>
<Button type="inverted" onPress={onPress} style={styles.createNewButton}>
<FontAwesomeIcon
icon="plus"
style={palInverted.text as FontAwesomeIconStyle}
/>
<Text type="button" style={palInverted.text}>
New Mute-list
</Text>
</Button>
</View>
)
}
const styles = StyleSheet.create({ const styles = StyleSheet.create({
createNewContainer: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 16,
paddingHorizontal: 18,
},
createNewButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
feedFooter: {paddingTop: 20}, feedFooter: {paddingTop: 20},
}) })
+7 -1
View File
@@ -23,6 +23,7 @@ import {usePalette} from 'lib/hooks/usePalette'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {useAnalytics} from 'lib/analytics' import {useAnalytics} from 'lib/analytics'
import {cleanError, isNetworkError} from 'lib/strings/errors' import {cleanError, isNetworkError} from 'lib/strings/errors'
import {isDesktopWeb} from 'platform/detection'
const MAX_NAME = 64 // todo const MAX_NAME = 64 // todo
const MAX_DESCRIPTION = 300 // todo const MAX_DESCRIPTION = 300 // todo
@@ -104,7 +105,9 @@ export function Component({onCreate}: {onCreate?: (uri: string) => void}) {
return ( return (
<KeyboardAvoidingView behavior="height"> <KeyboardAvoidingView behavior="height">
<ScrollView style={[pal.view]} testID="createMuteListModal"> <ScrollView
style={[pal.view, styles.container]}
testID="createMuteListModal">
<Text style={[styles.title, pal.text]}>New Mute List</Text> <Text style={[styles.title, pal.text]}>New Mute List</Text>
{error !== '' && ( {error !== '' && (
<View style={styles.errorContainer}> <View style={styles.errorContainer}>
@@ -190,6 +193,9 @@ export function Component({onCreate}: {onCreate?: (uri: string) => void}) {
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: {
paddingHorizontal: isDesktopWeb ? 0 : 16,
},
title: { title: {
textAlign: 'center', textAlign: 'center',
fontWeight: 'bold', fontWeight: 'bold',
+1 -1
View File
@@ -68,7 +68,7 @@ export const ModalsContainer = observer(function ModalsContainer() {
snapPoints = ReportAccountModal.snapPoints snapPoints = ReportAccountModal.snapPoints
element = <ReportAccountModal.Component {...activeModal} /> element = <ReportAccountModal.Component {...activeModal} />
} else if (activeModal?.name === 'create-mute-list') { } else if (activeModal?.name === 'create-mute-list') {
snapPoints = ReportAccountModal.snapPoints snapPoints = CreateMuteListModal.snapPoints
element = <CreateMuteListModal.Component {...activeModal} /> element = <CreateMuteListModal.Component {...activeModal} />
} else if (activeModal?.name === 'delete-account') { } else if (activeModal?.name === 'delete-account') {
snapPoints = DeleteAccountModal.snapPoints snapPoints = DeleteAccountModal.snapPoints
+7 -1
View File
@@ -20,11 +20,13 @@ export const ViewHeader = observer(function ({
canGoBack, canGoBack,
hideOnScroll, hideOnScroll,
showOnDesktop, showOnDesktop,
renderButton,
}: { }: {
title: string title: string
canGoBack?: boolean canGoBack?: boolean
hideOnScroll?: boolean hideOnScroll?: boolean
showOnDesktop?: boolean showOnDesktop?: boolean
renderButton?: () => JSX.Element
}) { }) {
const pal = usePalette('default') const pal = usePalette('default')
const store = useStores() const store = useStores()
@@ -79,7 +81,11 @@ export const ViewHeader = observer(function ({
{title} {title}
</Text> </Text>
</View> </View>
<View style={canGoBack ? styles.backBtn : styles.backBtnWide} /> {renderButton ? (
renderButton()
) : (
<View style={canGoBack ? styles.backBtn : styles.backBtnWide} />
)}
</Container> </Container>
) )
} }
+33 -37
View File
@@ -1,10 +1,10 @@
import React from 'react' import React from 'react'
import {StyleSheet} from 'react-native' import {StyleSheet} from 'react-native'
import {useFocusEffect, useNavigation} from '@react-navigation/native'
import { import {
useFocusEffect, FontAwesomeIcon,
useNavigation, FontAwesomeIconStyle,
StackActions, } from '@fortawesome/react-native-fontawesome'
} from '@react-navigation/native'
import {AtUri} from '@atproto/api' import {AtUri} from '@atproto/api'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {withAuthRequired} from 'view/com/auth/withAuthRequired'
@@ -12,6 +12,7 @@ import {EmptyStateWithButton} from 'view/com/util/EmptyStateWithButton'
import {useStores} from 'state/index' import {useStores} from 'state/index'
import {ListsListModel} from 'state/models/lists/lists-list' import {ListsListModel} from 'state/models/lists/lists-list'
import {ListsList} from 'view/com/lists/ListsList' import {ListsList} from 'view/com/lists/ListsList'
import {Button} from 'view/com/util/forms/Button'
import {NavigationProp} from 'lib/routes/types' import {NavigationProp} from 'lib/routes/types'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from 'view/com/util/Views'
@@ -65,6 +66,22 @@ export const ModerationMuteListsScreen = withAuthRequired(({route}: Props) => {
) )
}, [onPressNewMuteList]) }, [onPressNewMuteList])
const renderHeaderButton = React.useCallback(
() => (
<Button
type="primary-light"
onPress={onPressNewMuteList}
style={styles.createBtn}>
<FontAwesomeIcon
icon="plus"
style={pal.link as FontAwesomeIconStyle}
size={18}
/>
</Button>
),
[onPressNewMuteList, pal],
)
return ( return (
<CenteredView <CenteredView
style={[ style={[
@@ -74,8 +91,16 @@ export const ModerationMuteListsScreen = withAuthRequired(({route}: Props) => {
pal.border, pal.border,
]} ]}
testID="moderationMutelistsScreen"> testID="moderationMutelistsScreen">
<ViewHeader title="Mute-list Subscriptions" showOnDesktop /> <ViewHeader
<ListsList listsList={mutelists} renderEmptyState={renderEmptyState} /> title="Mute-lists"
showOnDesktop
renderButton={renderHeaderButton}
/>
<ListsList
listsList={mutelists}
renderEmptyState={renderEmptyState}
onPressCreateNew={onPressNewMuteList}
/>
</CenteredView> </CenteredView>
) )
}) })
@@ -89,36 +114,7 @@ const styles = StyleSheet.create({
borderLeftWidth: 1, borderLeftWidth: 1,
borderRightWidth: 1, borderRightWidth: 1,
}, },
title: { createBtn: {
textAlign: 'center', width: 40,
marginTop: 12,
marginBottom: 12,
},
description: {
textAlign: 'center',
paddingHorizontal: 30,
marginBottom: 14,
},
descriptionDesktop: {
marginTop: 14,
},
flex1: {
flex: 1,
},
empty: {
paddingHorizontal: 20,
paddingVertical: 20,
borderRadius: 16,
marginHorizontal: 24,
marginTop: 10,
},
emptyText: {
textAlign: 'center',
},
footer: {
height: 200,
paddingTop: 20,
}, },
}) })