diff options
Diffstat (limited to 'src/screens')
-rw-r--r-- | src/screens/Messages/ChatList.tsx | 18 | ||||
-rw-r--r-- | src/screens/Messages/Conversation.tsx | 17 | ||||
-rw-r--r-- | src/screens/Messages/Inbox.tsx | 33 | ||||
-rw-r--r-- | src/screens/Messages/Settings.tsx | 18 | ||||
-rw-r--r-- | src/screens/Moderation/index.tsx | 59 | ||||
-rw-r--r-- | src/screens/Settings/AboutSettings.tsx | 16 | ||||
-rw-r--r-- | src/screens/Settings/AccountSettings.tsx | 22 | ||||
-rw-r--r-- | src/screens/Settings/Settings.tsx | 3 |
8 files changed, 147 insertions, 39 deletions
diff --git a/src/screens/Messages/ChatList.tsx b/src/screens/Messages/ChatList.tsx index 388d23ec2..e13f0617b 100644 --- a/src/screens/Messages/ChatList.tsx +++ b/src/screens/Messages/ChatList.tsx @@ -23,6 +23,8 @@ import {useSession} from '#/state/session' import {List, type ListRef} from '#/view/com/util/List' import {ChatListLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen' +import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {type DialogControlProps, useDialogControl} from '#/components/Dialog' import {NewChat} from '#/components/dms/dialogs/NewChatDialog' @@ -64,7 +66,21 @@ function keyExtractor(item: ListItem) { } type Props = NativeStackScreenProps<MessagesTabNavigatorParams, 'Messages'> -export function MessagesScreen({navigation, route}: Props) { + +export function MessagesScreen(props: Props) { + const {_} = useLingui() + const aaCopy = useAgeAssuranceCopy() + + return ( + <AgeRestrictedScreen + screenTitle={_(msg`Chats`)} + infoText={aaCopy.chatsInfoText}> + <MessagesScreenInner {...props} /> + </AgeRestrictedScreen> + ) +} + +export function MessagesScreenInner({navigation, route}: Props) { const {_} = useLingui() const t = useTheme() const {currentAccount} = useSession() diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx index 90547a8d4..7f3b53b94 100644 --- a/src/screens/Messages/Conversation.tsx +++ b/src/screens/Messages/Conversation.tsx @@ -32,6 +32,8 @@ import {useProfileQuery} from '#/state/queries/profile' import {useSetMinimalShellMode} from '#/state/shell' import {MessagesList} from '#/screens/Messages/components/MessagesList' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' +import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen' +import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' import { EmailDialogScreenID, useEmailDialogControl, @@ -46,7 +48,20 @@ type Props = NativeStackScreenProps< CommonNavigatorParams, 'MessagesConversation' > -export function MessagesConversationScreen({route}: Props) { + +export function MessagesConversationScreen(props: Props) { + const {_} = useLingui() + const aaCopy = useAgeAssuranceCopy() + return ( + <AgeRestrictedScreen + screenTitle={_(msg`Conversation`)} + infoText={aaCopy.chatsInfoText}> + <MessagesConversationScreenInner {...props} /> + </AgeRestrictedScreen> + ) +} + +export function MessagesConversationScreenInner({route}: Props) { const {gtMobile} = useBreakpoints() const setMinimalShellMode = useSetMinimalShellMode() diff --git a/src/screens/Messages/Inbox.tsx b/src/screens/Messages/Inbox.tsx index 0f64d2014..8765cf0ba 100644 --- a/src/screens/Messages/Inbox.tsx +++ b/src/screens/Messages/Inbox.tsx @@ -1,17 +1,23 @@ import {useCallback, useMemo, useState} from 'react' import {View} from 'react-native' -import {ChatBskyConvoDefs, ChatBskyConvoListConvos} from '@atproto/api' +import { + type ChatBskyConvoDefs, + type ChatBskyConvoListConvos, +} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect, useNavigation} from '@react-navigation/native' -import {InfiniteData, UseInfiniteQueryResult} from '@tanstack/react-query' +import { + type InfiniteData, + type UseInfiniteQueryResult, +} from '@tanstack/react-query' import {useAppState} from '#/lib/hooks/useAppState' import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' import { - CommonNavigatorParams, - NativeStackScreenProps, - NavigationProp, + type CommonNavigatorParams, + type NativeStackScreenProps, + type NavigationProp, } from '#/lib/routes/types' import {cleanError} from '#/lib/strings/errors' import {logger} from '#/logger' @@ -26,6 +32,8 @@ import {List} from '#/view/com/util/List' import {ChatListLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import * as Toast from '#/view/com/util/Toast' import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen' +import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useRefreshOnFocus} from '#/components/hooks/useRefreshOnFocus' import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow' @@ -39,7 +47,20 @@ import {Text} from '#/components/Typography' import {RequestListItem} from './components/RequestListItem' type Props = NativeStackScreenProps<CommonNavigatorParams, 'MessagesInbox'> -export function MessagesInboxScreen({}: Props) { + +export function MessagesInboxScreen(props: Props) { + const {_} = useLingui() + const aaCopy = useAgeAssuranceCopy() + return ( + <AgeRestrictedScreen + screenTitle={_(msg`Chat requests`)} + infoText={aaCopy.chatsInfoText}> + <MessagesInboxScreenInner {...props} /> + </AgeRestrictedScreen> + ) +} + +export function MessagesInboxScreenInner({}: Props) { const {gtTablet} = useBreakpoints() const listConvosQuery = useListConvosQuery({status: 'request'}) diff --git a/src/screens/Messages/Settings.tsx b/src/screens/Messages/Settings.tsx index 0b8c88b9d..6015c07cd 100644 --- a/src/screens/Messages/Settings.tsx +++ b/src/screens/Messages/Settings.tsx @@ -12,6 +12,8 @@ import {useSession} from '#/state/session' import * as Toast from '#/view/com/util/Toast' import {atoms as a} from '#/alf' import {Admonition} from '#/components/Admonition' +import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen' +import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' import {Divider} from '#/components/Divider' import * as Toggle from '#/components/forms/Toggle' import * as Layout from '#/components/Layout' @@ -21,7 +23,21 @@ import {useBackgroundNotificationPreferences} from '../../../modules/expo-backgr type AllowIncoming = 'all' | 'none' | 'following' type Props = NativeStackScreenProps<CommonNavigatorParams, 'MessagesSettings'> -export function MessagesSettingsScreen({}: Props) { + +export function MessagesSettingsScreen(props: Props) { + const {_} = useLingui() + const aaCopy = useAgeAssuranceCopy() + + return ( + <AgeRestrictedScreen + screenTitle={_(msg`Chat Settings`)} + infoText={aaCopy.chatsInfoText}> + <MessagesSettingsScreenInner {...props} /> + </AgeRestrictedScreen> + ) +} + +export function MessagesSettingsScreenInner({}: Props) { const {_} = useLingui() const {currentAccount} = useSession() const {data: profile} = useProfileQuery({ diff --git a/src/screens/Moderation/index.tsx b/src/screens/Moderation/index.tsx index 78b0a6ae9..a7b434e52 100644 --- a/src/screens/Moderation/index.tsx +++ b/src/screens/Moderation/index.tsx @@ -12,6 +12,7 @@ import { } from '#/lib/routes/types' import {logger} from '#/logger' import {isIOS} from '#/platform/detection' +import {useAgeAssurance} from '#/state/ageAssurance/useAgeAssurance' import { useMyLabelersQuery, usePreferencesQuery, @@ -20,8 +21,8 @@ import { } from '#/state/queries/preferences' import {isNonConfigurableModerationAuthority} from '#/state/session/additional-moderation-authorities' import {useSetMinimalShellMode} from '#/state/shell' -import {ViewHeader} from '#/view/com/util/ViewHeader' import {atoms as a, useBreakpoints, useTheme, type ViewStyleProp} from '#/alf' +import {AgeAssuranceAdmonition} from '#/components/ageAssurance/AgeAssuranceAdmonition' import {Button, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' @@ -84,13 +85,22 @@ export function ModerationScreen( error: preferencesError, data: preferences, } = usePreferencesQuery() + const {isReady: isAgeInfoReady} = useAgeAssurance() - const isLoading = isPreferencesLoading + const isLoading = isPreferencesLoading || !isAgeInfoReady const error = preferencesError return ( <Layout.Screen testID="moderationScreen"> - <ViewHeader title={_(msg`Moderation`)} showOnDesktop /> + <Layout.Header.Outer> + <Layout.Header.BackButton /> + <Layout.Header.Content> + <Layout.Header.TitleText> + <Trans>Moderation</Trans> + </Layout.Header.TitleText> + </Layout.Header.Content> + <Layout.Header.Slot /> + </Layout.Header.Outer> <Layout.Content> {isLoading ? ( <ListMaybePlaceholder isLoading={true} sideBorders={false} /> @@ -157,6 +167,7 @@ export function ModerationScreenInner({ data: labelers, error: labelersError, } = useMyLabelersQuery() + const {declaredAge, isDeclaredUnderage, isAgeRestricted} = useAgeAssurance() useFocusEffect( useCallback(() => { @@ -170,8 +181,6 @@ export function ModerationScreenInner({ (optimisticAdultContent && optimisticAdultContent.enabled) || (!optimisticAdultContent && preferences.moderationPrefs.adultContentEnabled) ) - const ageNotSet = !preferences.userAge - const isUnderage = (preferences.userAge || 0) < 18 const onToggleAdultContentEnabled = useCallback( async (selected: boolean) => { @@ -306,8 +315,14 @@ export function ModerationScreenInner({ <Trans>Content filters</Trans> </Text> + <AgeAssuranceAdmonition style={[a.pb_md]}> + <Trans> + You must complete age assurance in order to access the settings below. + </Trans> + </AgeAssuranceAdmonition> + <View style={[a.gap_md]}> - {ageNotSet && ( + {declaredAge === undefined && ( <> <Button label={_(msg`Confirm your birthdate`)} @@ -336,7 +351,7 @@ export function ModerationScreenInner({ a.overflow_hidden, t.atoms.bg_contrast_25, ]}> - {!ageNotSet && !isUnderage && ( + {!isDeclaredUnderage && !isAgeRestricted && ( <> <View style={[ @@ -389,21 +404,25 @@ export function ModerationScreenInner({ </View> )} <Divider /> + + {adultContentEnabled && ( + <> + <GlobalLabelPreference labelDefinition={LABELS.porn} /> + <Divider /> + <GlobalLabelPreference labelDefinition={LABELS.sexual} /> + <Divider /> + <GlobalLabelPreference + labelDefinition={LABELS['graphic-media']} + /> + <Divider /> + </> + )} </> )} - {!isUnderage && adultContentEnabled && ( - <> - <GlobalLabelPreference labelDefinition={LABELS.porn} /> - <Divider /> - <GlobalLabelPreference labelDefinition={LABELS.sexual} /> - <Divider /> - <GlobalLabelPreference - labelDefinition={LABELS['graphic-media']} - /> - <Divider /> - </> - )} - <GlobalLabelPreference labelDefinition={LABELS.nudity} /> + <GlobalLabelPreference + disabled={isDeclaredUnderage || isAgeRestricted} + labelDefinition={LABELS.nudity} + /> </View> </View> diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx index 0ce127ff3..6be881a88 100644 --- a/src/screens/Settings/AboutSettings.tsx +++ b/src/screens/Settings/AboutSettings.tsx @@ -20,9 +20,11 @@ import {BroomSparkle_Stroke2_Corner2_Rounded as BroomSparkleIcon} from '#/compon import {CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon} from '#/components/icons/CodeLines' import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' import {Newspaper_Stroke2_Corner2_Rounded as NewspaperIcon} from '#/components/icons/Newspaper' +import {ShieldCheck_Stroke2_Corner0_Rounded as Shield} from '#/components/icons/Shield' import {Wrench_Stroke2_Corner2_Rounded as WrenchIcon} from '#/components/icons/Wrench' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' +import {device} from '#/storage' import {useDemoMode} from '#/storage/hooks/demo-mode' import {useDevMode} from '#/storage/hooks/dev-mode' import {OTAInfo} from './components/OTAInfo' @@ -179,6 +181,20 @@ export function AboutSettingsScreen({}: Props) { </SettingsList.ItemText> </SettingsList.PressableItem> )} + + <SettingsList.PressableItem + onPress={() => { + device.set(['geolocation'], { + countryCode: 'GB', + isAgeRestrictedGeo: true, + }) + }} + label="Simulate age restriction"> + <SettingsList.ItemIcon icon={Shield} /> + <SettingsList.ItemText> + Simulate age restriction + </SettingsList.ItemText> + </SettingsList.PressableItem> </> )} </SettingsList.Container> diff --git a/src/screens/Settings/AccountSettings.tsx b/src/screens/Settings/AccountSettings.tsx index 393bad2f8..86652d277 100644 --- a/src/screens/Settings/AccountSettings.tsx +++ b/src/screens/Settings/AccountSettings.tsx @@ -7,6 +7,7 @@ import {useModalControls} from '#/state/modals' import {useSession} from '#/state/session' import * as SettingsList from '#/screens/Settings/components/SettingsList' import {atoms as a, useTheme} from '#/alf' +import {AgeAssuranceAccountCard} from '#/components/ageAssurance/AgeAssuranceAccountCard' import {useDialogControl} from '#/components/Dialog' import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' import { @@ -114,16 +115,6 @@ export function AccountSettingsScreen({}: Props) { <SettingsList.Chevron /> </SettingsList.PressableItem> <SettingsList.Divider /> - <SettingsList.Item> - <SettingsList.ItemIcon icon={BirthdayCakeIcon} /> - <SettingsList.ItemText> - <Trans>Birthday</Trans> - </SettingsList.ItemText> - <SettingsList.BadgeButton - label={_(msg`Edit`)} - onPress={() => birthdayControl.open()} - /> - </SettingsList.Item> <SettingsList.PressableItem label={_(msg`Password`)} onPress={() => openModal({name: 'change-password'})}> @@ -143,6 +134,17 @@ export function AccountSettingsScreen({}: Props) { </SettingsList.ItemText> <SettingsList.Chevron /> </SettingsList.PressableItem> + <SettingsList.Item> + <SettingsList.ItemIcon icon={BirthdayCakeIcon} /> + <SettingsList.ItemText> + <Trans>Birthday</Trans> + </SettingsList.ItemText> + <SettingsList.BadgeButton + label={_(msg`Edit`)} + onPress={() => birthdayControl.open()} + /> + </SettingsList.Item> + <AgeAssuranceAccountCard style={[a.px_xl, a.pt_xs, a.pb_md]} /> <SettingsList.Divider /> <SettingsList.PressableItem label={_(msg`Export my data`)} diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx index aaba0b4b5..4d10a9d0d 100644 --- a/src/screens/Settings/Settings.tsx +++ b/src/screens/Settings/Settings.tsx @@ -32,6 +32,7 @@ import * as Toast from '#/view/com/util/Toast' import {UserAvatar} from '#/view/com/util/UserAvatar' import * as SettingsList from '#/screens/Settings/components/SettingsList' import {atoms as a, platform, tokens, useBreakpoints, useTheme} from '#/alf' +import {AgeAssuranceDismissibleNotice} from '#/components/ageAssurance/AgeAssuranceDismissibleNotice' import {AvatarStackWithFetch} from '#/components/AvatarStack' import {useDialogControl} from '#/components/Dialog' import {SwitchAccountDialog} from '#/components/dialogs/SwitchAccount' @@ -96,6 +97,8 @@ export function SettingsScreen({}: Props) { </Layout.Header.Outer> <Layout.Content> <SettingsList.Container> + <AgeAssuranceDismissibleNotice style={[a.px_lg, a.pt_xs, a.pb_xl]} /> + <View style={[ a.px_xl, |