Rework: create a new moderation screen and move everything related under it

This commit is contained in:
Paul Frazee
2023-05-05 13:32:02 -05:00
parent caf289d1d5
commit 32a0d75a23
13 changed files with 195 additions and 87 deletions
+4 -3
View File
@@ -100,11 +100,12 @@ func serve(cctx *cli.Context) error {
// generic routes
e.GET("/search", server.WebGeneric)
e.GET("/notifications", server.WebGeneric)
e.GET("/lists", server.WebGeneric)
e.GET("/moderation", server.WebGeneric)
e.GET("/moderation/mute-lists", server.WebGeneric)
e.GET("/moderation/muted-accounts", server.WebGeneric)
e.GET("/moderation/blocked-accounts", server.WebGeneric)
e.GET("/settings", server.WebGeneric)
e.GET("/settings/app-passwords", server.WebGeneric)
e.GET("/settings/muted-accounts", server.WebGeneric)
e.GET("/settings/blocked-accounts", server.WebGeneric)
e.GET("/sys/debug", server.WebGeneric)
e.GET("/sys/log", server.WebGeneric)
e.GET("/support", server.WebGeneric)
+17 -6
View File
@@ -33,7 +33,8 @@ import {useStores} from './state'
import {HomeScreen} from './view/screens/Home'
import {SearchScreen} from './view/screens/Search'
import {NotificationsScreen} from './view/screens/Notifications'
import {ListsScreen} from './view/screens/Lists'
import {ModerationScreen} from './view/screens/Moderation'
import {ModerationMuteListsScreen} from './view/screens/ModerationMuteLists'
import {NotFoundScreen} from './view/screens/NotFound'
import {SettingsScreen} from './view/screens/Settings'
import {ProfileScreen} from './view/screens/Profile'
@@ -51,8 +52,8 @@ import {TermsOfServiceScreen} from './view/screens/TermsOfService'
import {CommunityGuidelinesScreen} from './view/screens/CommunityGuidelines'
import {CopyrightPolicyScreen} from './view/screens/CopyrightPolicy'
import {AppPasswords} from 'view/screens/AppPasswords'
import {MutedAccounts} from 'view/screens/MutedAccounts'
import {BlockedAccounts} from 'view/screens/BlockedAccounts'
import {ModerationMutedAccounts} from 'view/screens/ModerationMutedAccounts'
import {ModerationBlockedAccounts} from 'view/screens/ModerationBlockedAccounts'
import {getRoutingInstrumentation} from 'lib/sentry'
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
@@ -72,7 +73,19 @@ function commonScreens(Stack: typeof HomeTab) {
return (
<>
<Stack.Screen name="NotFound" component={NotFoundScreen} />
<Stack.Screen name="Lists" component={ListsScreen} />
<Stack.Screen name="Moderation" component={ModerationScreen} />
<Stack.Screen
name="ModerationMuteLists"
component={ModerationMuteListsScreen}
/>
<Stack.Screen
name="ModerationMutedAccounts"
component={ModerationMutedAccounts}
/>
<Stack.Screen
name="ModerationBlockedAccounts"
component={ModerationBlockedAccounts}
/>
<Stack.Screen name="Settings" component={SettingsScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen
@@ -95,8 +108,6 @@ function commonScreens(Stack: typeof HomeTab) {
/>
<Stack.Screen name="CopyrightPolicy" component={CopyrightPolicyScreen} />
<Stack.Screen name="AppPasswords" component={AppPasswords} />
<Stack.Screen name="MutedAccounts" component={MutedAccounts} />
<Stack.Screen name="BlockedAccounts" component={BlockedAccounts} />
</>
)
}
+4 -3
View File
@@ -5,7 +5,10 @@ export type {NativeStackScreenProps} from '@react-navigation/native-stack'
export type CommonNavigatorParams = {
NotFound: undefined
Lists: undefined
Moderation: undefined
ModerationMuteLists: undefined
ModerationMutedAccounts: undefined
ModerationBlockedAccounts: undefined
Settings: undefined
Profile: {name: string; hideBackButton?: boolean}
ProfileFollowers: {name: string}
@@ -22,8 +25,6 @@ export type CommonNavigatorParams = {
CommunityGuidelines: undefined
CopyrightPolicy: undefined
AppPasswords: undefined
MutedAccounts: undefined
BlockedAccounts: undefined
}
export type BottomTabNavigatorParams = CommonNavigatorParams & {
+4 -3
View File
@@ -4,8 +4,11 @@ export const router = new Router({
Home: '/',
Search: '/search',
Notifications: '/notifications',
Lists: '/lists',
Settings: '/settings',
Moderation: '/moderation',
ModerationMuteLists: '/moderation/mute-lists',
ModerationMutedAccounts: '/moderation/muted-accounts',
ModerationBlockedAccounts: '/moderation/blocked-accounts',
Profile: '/profile/:name',
ProfileFollowers: '/profile/:name/followers',
ProfileFollows: '/profile/:name/follows',
@@ -16,8 +19,6 @@ export const router = new Router({
Debug: '/sys/debug',
Log: '/sys/log',
AppPasswords: '/settings/app-passwords',
MutedAccounts: '/settings/muted-accounts',
BlockedAccounts: '/settings/blocked-accounts',
Support: '/support',
PrivacyPolicy: '/support/privacy',
TermsOfService: '/support/tos',
@@ -28,7 +28,8 @@ export function SubscribedMutelistsEmptyState() {
</View>
<Text type="xl-medium" style={[s.textCenter, pal.text]}>
You can subscribe to mutelists to automatically mute all of the users
they include. Mutelists are public but your subscription is not.
they include. Mutelists are public but your subscription to a mutelist
is private.
</Text>
<View style={styles.btns}>
<Button type="inverted" style={styles.btn} onPress={onPressCreateList}>
+8
View File
@@ -37,6 +37,8 @@ import {faEye} from '@fortawesome/free-solid-svg-icons/faEye'
import {faEyeSlash as farEyeSlash} from '@fortawesome/free-regular-svg-icons/faEyeSlash'
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe'
import {faHand} from '@fortawesome/free-solid-svg-icons/faHand'
import {faHand as farHand} from '@fortawesome/free-regular-svg-icons/faHand'
import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart'
import {faHeart as fasHeart} from '@fortawesome/free-solid-svg-icons/faHeart'
import {faHouse} from '@fortawesome/free-solid-svg-icons/faHouse'
@@ -67,8 +69,10 @@ import {faRss} from '@fortawesome/free-solid-svg-icons/faRss'
import {faUser} from '@fortawesome/free-regular-svg-icons/faUser'
import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers'
import {faUserCheck} from '@fortawesome/free-solid-svg-icons/faUserCheck'
import {faUserSlash} from '@fortawesome/free-solid-svg-icons/faUserSlash'
import {faUserPlus} from '@fortawesome/free-solid-svg-icons/faUserPlus'
import {faUserXmark} from '@fortawesome/free-solid-svg-icons/faUserXmark'
import {faUsersSlash} from '@fortawesome/free-solid-svg-icons/faUsersSlash'
import {faTicket} from '@fortawesome/free-solid-svg-icons/faTicket'
import {faTrashCan} from '@fortawesome/free-regular-svg-icons/faTrashCan'
import {faX} from '@fortawesome/free-solid-svg-icons/faX'
@@ -115,6 +119,8 @@ export function setup() {
farEyeSlash,
faGear,
faGlobe,
faHand,
farHand,
faHeart,
fasHeart,
faHouse,
@@ -145,8 +151,10 @@ export function setup() {
faUser,
faUsers,
faUserCheck,
faUserSlash,
faUserPlus,
faUserXmark,
faUsersSlash,
faTicket,
faTrashCan,
faX,
+128
View File
@@ -0,0 +1,128 @@
import React from 'react'
import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {observer} from 'mobx-react-lite'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
import {useStores} from 'state/index'
import {s} from 'lib/styles'
import {CenteredView, ScrollView} from '../com/util/Views'
import {ViewHeader} from '../com/util/ViewHeader'
import {Link} from '../com/util/Link'
import {Text} from '../com/util/text/Text'
import {usePalette} from 'lib/hooks/usePalette'
import {useAnalytics} from 'lib/analytics'
import {isDesktopWeb} from 'platform/detection'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Moderation'>
export const ModerationScreen = withAuthRequired(
observer(function Moderation({}: Props) {
const pal = usePalette('default')
const store = useStores()
const {screen, track} = useAnalytics()
useFocusEffect(
React.useCallback(() => {
screen('Moderation')
store.shell.setMinimalShellMode(false)
}, [screen, store]),
)
const onPressContentFiltering = React.useCallback(() => {
track('Moderation:ContentfilteringButtonClicked')
store.shell.openModal({name: 'content-filtering-settings'})
}, [track, store])
return (
<View
style={[s.hContentRegion, !isDesktopWeb && pal.viewLight]}
testID="moderationScreen">
<ViewHeader title="Moderation" showOnDesktop />
<View style={styles.spacer} />
<TouchableOpacity
testID="contentFilteringBtn"
style={[styles.linkCard, pal.view]}
onPress={onPressContentFiltering}
accessibilityHint="Content filtering"
accessibilityLabel="Opens configurable content filtering settings">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="eye"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Content filtering
</Text>
</TouchableOpacity>
<Link
testID="mutelistsBtn"
style={[styles.linkCard, pal.view]}
href="/moderation/mute-lists">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="users-slash"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Mutelist subscriptions
</Text>
</Link>
<Link
testID="mutedAccountsBtn"
style={[styles.linkCard, pal.view]}
href="/moderation/muted-accounts">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="user-slash"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Muted accounts
</Text>
</Link>
<Link
testID="blockedAccountsBtn"
style={[styles.linkCard, pal.view]}
href="/moderation/blocked-accounts">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="ban"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Blocked accounts
</Text>
</Link>
</View>
)
}),
)
const styles = StyleSheet.create({
spacer: {
height: 6,
},
linkCard: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 12,
paddingHorizontal: 18,
marginBottom: 1,
},
iconContainer: {
alignItems: 'center',
justifyContent: 'center',
width: 40,
height: 40,
borderRadius: 30,
marginRight: 12,
},
})
@@ -22,8 +22,11 @@ import {ViewHeader} from '../com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views'
import {ProfileCard} from 'view/com/profile/ProfileCard'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'BlockedAccounts'>
export const BlockedAccounts = withAuthRequired(
type Props = NativeStackScreenProps<
CommonNavigatorParams,
'ModerationBlockedAccounts'
>
export const ModerationBlockedAccounts = withAuthRequired(
observer(({}: Props) => {
const pal = usePalette('default')
const store = useStores()
@@ -11,8 +11,11 @@ import {ListsListModel} from 'state/models/lists/lists-list'
import {ListsList} from 'view/com/lists/ListsList'
import {usePalette} from 'lib/hooks/usePalette'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'>
export const ListsScreen = withAuthRequired(({route}: Props) => {
type Props = NativeStackScreenProps<
CommonNavigatorParams,
'ModerationMuteLists'
>
export const ModerationMuteListsScreen = withAuthRequired(({route}: Props) => {
const pal = usePalette('default')
const store = useStores()
const [selectedPage, setSelectedPage] = React.useState(0)
@@ -22,8 +22,11 @@ import {ViewHeader} from '../com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views'
import {ProfileCard} from 'view/com/profile/ProfileCard'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'MutedAccounts'>
export const MutedAccounts = withAuthRequired(
type Props = NativeStackScreenProps<
CommonNavigatorParams,
'ModerationMutedAccounts'
>
export const ModerationMutedAccounts = withAuthRequired(
observer(({}: Props) => {
const pal = usePalette('default')
const store = useStores()
+2 -53
View File
@@ -126,11 +126,6 @@ export const SettingsScreen = withAuthRequired(
store.shell.openModal({name: 'invite-codes'})
}, [track, store])
const onPressContentFiltering = React.useCallback(() => {
track('Settings:ContentfilteringButtonClicked')
store.shell.openModal({name: 'content-filtering-settings'})
}, [track, store])
const onPressContentLanguages = React.useCallback(() => {
track('Settings:ContentlanguagesButtonClicked')
store.shell.openModal({name: 'content-languages-settings'})
@@ -234,7 +229,9 @@ export const SettingsScreen = withAuthRequired(
Add account
</Text>
</TouchableOpacity>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Invite a friend
</Text>
@@ -269,54 +266,6 @@ export const SettingsScreen = withAuthRequired(
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Moderation
</Text>
<TouchableOpacity
testID="contentFilteringBtn"
style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
onPress={isSwitching ? undefined : onPressContentFiltering}
accessibilityHint="Content moderation"
accessibilityLabel="Opens configurable content moderation settings">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="eye"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Content moderation
</Text>
</TouchableOpacity>
<Link
testID="mutedAccountsBtn"
style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
href="/settings/muted-accounts">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon={['far', 'eye-slash']}
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Muted accounts
</Text>
</Link>
<Link
testID="blockedAccountsBtn"
style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
href="/settings/blocked-accounts">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="ban"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Blocked accounts
</Text>
</Link>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Advanced
</Text>
+7 -8
View File
@@ -94,9 +94,9 @@ export const DrawerContent = observer(() => {
onPressTab('MyProfile')
}, [onPressTab])
const onPressLists = React.useCallback(() => {
track('Menu:ItemClicked', {url: 'Lists'})
navigation.navigate('Lists')
const onPressModeration = React.useCallback(() => {
track('Menu:ItemClicked', {url: 'Moderation'})
navigation.navigate('Moderation')
store.shell.closeDrawer()
}, [navigation, track, store.shell])
@@ -227,18 +227,17 @@ export const DrawerContent = observer(() => {
onPress={onPressNotifications}
/>
<MenuItem
href="/lists"
icon={
<FontAwesomeIcon
icon="list-ul"
icon={['far', 'hand']}
style={pal.text as FontAwesomeIconStyle}
size={20}
/>
}
label="Lists"
accessibilityLabel="Lists"
label="Moderation"
accessibilityLabel="Moderation"
accessibilityHint=""
onPress={onPressLists}
onPress={onPressModeration}
/>
<MenuItem
icon={
+4 -4
View File
@@ -202,22 +202,22 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
label="Notifications"
/>
<NavItem
href="/lists"
href="/moderation"
icon={
<FontAwesomeIcon
icon="list-ul"
icon={['far', 'hand']}
style={pal.text as FontAwesomeIconStyle}
size={20}
/>
}
iconFilled={
<FontAwesomeIcon
icon="list-ul"
icon="hand"
style={pal.text as FontAwesomeIconStyle}
size={20}
/>
}
label="Lists"
label="Moderation"
/>
{store.session.hasSession && (
<NavItem