Rework: create a new moderation screen and move everything related under it
This commit is contained in:
@@ -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
@@ -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} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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}>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
+5
-2
@@ -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()
|
||||
@@ -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>
|
||||
|
||||
@@ -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={
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user