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,
} from 'react-native'
import {observer} from 'mobx-react-lite'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
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 {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
import {ListsListModel} from 'state/models/lists/lists-list'
import {useAnalytics} from 'lib/analytics'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {isDesktopWeb} from 'platform/detection'
const LOADING_ITEM = {_reactKey: '__loading__'}
const CREATENEW_ITEM = {_reactKey: '__loading__'}
const EMPTY_ITEM = {_reactKey: '__empty__'}
const ERROR_ITEM = {_reactKey: '__error__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
@@ -27,17 +35,17 @@ export const ListsList = observer(
({
listsList,
style,
showPostFollowBtn,
scrollElRef,
onPressTryAgain,
onPressCreateNew,
renderEmptyState,
testID,
headerOffset = 0,
}: {
listsList: ListsListModel
style?: StyleProp<ViewStyle>
showPostFollowBtn?: boolean
scrollElRef?: MutableRefObject<FlatList<any> | null>
onPressCreateNew: () => void
onPressTryAgain?: () => void
renderEmptyState?: () => JSX.Element
testID?: string
@@ -56,6 +64,9 @@ export const ListsList = observer(
if (listsList.isEmpty) {
items = items.concat([EMPTY_ITEM])
} else {
if (isDesktopWeb) {
items = items.concat([CREATENEW_ITEM])
}
items = items.concat(listsList.lists)
}
if (listsList.loadMoreError) {
@@ -111,6 +122,8 @@ export const ListsList = observer(
return renderEmptyState()
}
return <View />
} else if (item === CREATENEW_ITEM) {
return <CreateNewItem onPress={onPressCreateNew} />
} else if (item === ERROR_ITEM) {
return (
<ErrorMessage
@@ -130,7 +143,7 @@ export const ListsList = observer(
}
return <ListCard list={item} />
},
[listsList, onPressTryAgain, onPressRetryLoadMore, showPostFollowBtn],
[listsList, onPressTryAgain, onPressRetryLoadMore, onPressCreateNew],
)
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({
createNewContainer: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 16,
paddingHorizontal: 18,
},
createNewButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
feedFooter: {paddingTop: 20},
})
+7 -1
View File
@@ -23,6 +23,7 @@ import {usePalette} from 'lib/hooks/usePalette'
import {useTheme} from 'lib/ThemeContext'
import {useAnalytics} from 'lib/analytics'
import {cleanError, isNetworkError} from 'lib/strings/errors'
import {isDesktopWeb} from 'platform/detection'
const MAX_NAME = 64 // todo
const MAX_DESCRIPTION = 300 // todo
@@ -104,7 +105,9 @@ export function Component({onCreate}: {onCreate?: (uri: string) => void}) {
return (
<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>
{error !== '' && (
<View style={styles.errorContainer}>
@@ -190,6 +193,9 @@ export function Component({onCreate}: {onCreate?: (uri: string) => void}) {
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: isDesktopWeb ? 0 : 16,
},
title: {
textAlign: 'center',
fontWeight: 'bold',
+1 -1
View File
@@ -68,7 +68,7 @@ export const ModalsContainer = observer(function ModalsContainer() {
snapPoints = ReportAccountModal.snapPoints
element = <ReportAccountModal.Component {...activeModal} />
} else if (activeModal?.name === 'create-mute-list') {
snapPoints = ReportAccountModal.snapPoints
snapPoints = CreateMuteListModal.snapPoints
element = <CreateMuteListModal.Component {...activeModal} />
} else if (activeModal?.name === 'delete-account') {
snapPoints = DeleteAccountModal.snapPoints
+7 -1
View File
@@ -20,11 +20,13 @@ export const ViewHeader = observer(function ({
canGoBack,
hideOnScroll,
showOnDesktop,
renderButton,
}: {
title: string
canGoBack?: boolean
hideOnScroll?: boolean
showOnDesktop?: boolean
renderButton?: () => JSX.Element
}) {
const pal = usePalette('default')
const store = useStores()
@@ -79,7 +81,11 @@ export const ViewHeader = observer(function ({
{title}
</Text>
</View>
<View style={canGoBack ? styles.backBtn : styles.backBtnWide} />
{renderButton ? (
renderButton()
) : (
<View style={canGoBack ? styles.backBtn : styles.backBtnWide} />
)}
</Container>
)
}
+33 -37
View File
@@ -1,10 +1,10 @@
import React from 'react'
import {StyleSheet} from 'react-native'
import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {
useFocusEffect,
useNavigation,
StackActions,
} from '@react-navigation/native'
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {AtUri} from '@atproto/api'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
@@ -12,6 +12,7 @@ import {EmptyStateWithButton} from 'view/com/util/EmptyStateWithButton'
import {useStores} from 'state/index'
import {ListsListModel} from 'state/models/lists/lists-list'
import {ListsList} from 'view/com/lists/ListsList'
import {Button} from 'view/com/util/forms/Button'
import {NavigationProp} from 'lib/routes/types'
import {usePalette} from 'lib/hooks/usePalette'
import {CenteredView} from 'view/com/util/Views'
@@ -65,6 +66,22 @@ export const ModerationMuteListsScreen = withAuthRequired(({route}: Props) => {
)
}, [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 (
<CenteredView
style={[
@@ -74,8 +91,16 @@ export const ModerationMuteListsScreen = withAuthRequired(({route}: Props) => {
pal.border,
]}
testID="moderationMutelistsScreen">
<ViewHeader title="Mute-list Subscriptions" showOnDesktop />
<ListsList listsList={mutelists} renderEmptyState={renderEmptyState} />
<ViewHeader
title="Mute-lists"
showOnDesktop
renderButton={renderHeaderButton}
/>
<ListsList
listsList={mutelists}
renderEmptyState={renderEmptyState}
onPressCreateNew={onPressNewMuteList}
/>
</CenteredView>
)
})
@@ -89,36 +114,7 @@ const styles = StyleSheet.create({
borderLeftWidth: 1,
borderRightWidth: 1,
},
title: {
textAlign: 'center',
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,
createBtn: {
width: 40,
},
})