diff options
Diffstat (limited to 'src/screens/Messages/Conversation/index.tsx')
-rw-r--r-- | src/screens/Messages/Conversation/index.tsx | 228 |
1 files changed, 61 insertions, 167 deletions
diff --git a/src/screens/Messages/Conversation/index.tsx b/src/screens/Messages/Conversation/index.tsx index 2c42ed16d..0fe4138bb 100644 --- a/src/screens/Messages/Conversation/index.tsx +++ b/src/screens/Messages/Conversation/index.tsx @@ -1,35 +1,28 @@ import React, {useCallback} from 'react' -import {TouchableOpacity, View} from 'react-native' +import {View} from 'react-native' import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useFocusEffect, useNavigation} from '@react-navigation/native' +import {useFocusEffect} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' -import {makeProfileLink} from '#/lib/routes/links' -import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types' +import {CommonNavigatorParams} from '#/lib/routes/types' import {useGate} from '#/lib/statsig/statsig' -import {useProfileShadow} from '#/state/cache/profile-shadow' import {useCurrentConvoId} from '#/state/messages/current-convo-id' import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useProfileQuery} from '#/state/queries/profile' -import {BACK_HITSLOP} from 'lib/constants' -import {sanitizeDisplayName} from 'lib/strings/display-names' import {isWeb} from 'platform/detection' +import {useProfileShadow} from 'state/cache/profile-shadow' import {ConvoProvider, isConvoActive, useConvo} from 'state/messages/convo' import {ConvoStatus} from 'state/messages/convo/types' import {useSetMinimalShellMode} from 'state/shell' -import {PreviewableUserAvatar} from 'view/com/util/UserAvatar' import {CenteredView} from 'view/com/util/Views' import {MessagesList} from '#/screens/Messages/Conversation/MessagesList' -import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' -import {ConvoMenu} from '#/components/dms/ConvoMenu' +import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter' +import {MessagesListHeader} from '#/components/dms/MessagesListHeader' import {Error} from '#/components/Error' -import {Link} from '#/components/Link' -import {ListMaybePlaceholder} from '#/components/Lists' import {Loader} from '#/components/Loader' -import {Text} from '#/components/Typography' import {ClipClopGate} from '../gate' type Props = NativeStackScreenProps< @@ -73,6 +66,11 @@ function Inner() { const convoState = useConvo() const {_} = useLingui() + const moderationOpts = useModerationOpts() + const {data: recipient} = useProfileQuery({ + did: convoState.recipients?.[0].did, + }) + // Because we want to give the list a chance to asynchronously scroll to the end before it is visible to the user, // we use `hasScrolled` to determine when to render. With that said however, there is a chance that the chat will be // empty. So, we also check for that possible state as well and render once we can. @@ -86,7 +84,7 @@ function Inner() { if (convoState.status === ConvoStatus.Error) { return ( <CenteredView style={a.flex_1} sideBorders> - <Header /> + <MessagesListHeader /> <Error title={_(msg`Something went wrong`)} message={_(msg`We couldn't load this conversation`)} @@ -96,20 +94,21 @@ function Inner() { ) } - /* - * Any other convo states (atm) are "ready" states - */ return ( <CenteredView style={[a.flex_1]} sideBorders> - <Header profile={convoState.recipients?.[0]} /> + {!readyToShow && <MessagesListHeader />} <View style={[a.flex_1]}> - {isConvoActive(convoState) ? ( - <MessagesList + {moderationOpts && recipient ? ( + <InnerReady + moderationOpts={moderationOpts} + recipient={recipient} hasScrolled={hasScrolled} setHasScrolled={setHasScrolled} /> ) : ( - <ListMaybePlaceholder isLoading /> + <> + <View style={[a.align_center, a.gap_sm, a.flex_1]} /> + </> )} {!readyToShow && ( <View @@ -132,160 +131,55 @@ function Inner() { ) } -const PFP_SIZE = isWeb ? 40 : 34 - -let Header = ({ - profile: initialProfile, -}: { - profile?: AppBskyActorDefs.ProfileViewBasic -}): React.ReactNode => { - const t = useTheme() - const {_} = useLingui() - const {gtTablet} = useBreakpoints() - const navigation = useNavigation<NavigationProp>() - const moderationOpts = useModerationOpts() - const {data: profile} = useProfileQuery({did: initialProfile?.did}) - - const onPressBack = useCallback(() => { - if (isWeb) { - navigation.replace('Messages') - } else { - navigation.goBack() - } - }, [navigation]) - - return ( - <View - style={[ - t.atoms.bg, - t.atoms.border_contrast_low, - a.border_b, - a.flex_row, - a.align_center, - a.gap_sm, - gtTablet ? a.pl_lg : a.pl_xl, - a.pr_lg, - a.py_sm, - ]}> - {!gtTablet && ( - <TouchableOpacity - testID="conversationHeaderBackBtn" - onPress={onPressBack} - hitSlop={BACK_HITSLOP} - style={{width: 30, height: 30}} - accessibilityRole="button" - accessibilityLabel={_(msg`Back`)} - accessibilityHint=""> - <FontAwesomeIcon - size={18} - icon="angle-left" - style={{ - marginTop: 6, - }} - color={t.atoms.text.color} - /> - </TouchableOpacity> - )} - - {profile && moderationOpts ? ( - <HeaderReady profile={profile} moderationOpts={moderationOpts} /> - ) : ( - <> - <View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}> - <View - style={[ - {width: PFP_SIZE, height: PFP_SIZE}, - a.rounded_full, - t.atoms.bg_contrast_25, - ]} - /> - <View style={a.gap_xs}> - <View - style={[ - {width: 120, height: 16}, - a.rounded_xs, - t.atoms.bg_contrast_25, - a.mt_xs, - ]} - /> - <View - style={[ - {width: 175, height: 12}, - a.rounded_xs, - t.atoms.bg_contrast_25, - ]} - /> - </View> - </View> - - <View style={{width: 30}} /> - </> - )} - </View> - ) -} -Header = React.memo(Header) - -function HeaderReady({ - profile: profileUnshadowed, +function InnerReady({ moderationOpts, + recipient: recipientUnshadowed, + hasScrolled, + setHasScrolled, }: { - profile: AppBskyActorDefs.ProfileViewBasic moderationOpts: ModerationOpts + recipient: AppBskyActorDefs.ProfileViewBasic + hasScrolled: boolean + setHasScrolled: React.Dispatch<React.SetStateAction<boolean>> }) { - const t = useTheme() const convoState = useConvo() - const profile = useProfileShadow(profileUnshadowed) - const moderation = React.useMemo( - () => moderateProfile(profile, moderationOpts), - [profile, moderationOpts], - ) - - const isDeletedAccount = profile?.handle === 'missing.invalid' - const displayName = isDeletedAccount - ? 'Deleted Account' - : sanitizeDisplayName( - profile.displayName || profile.handle, - moderation.ui('displayName'), - ) + const recipient = useProfileShadow(recipientUnshadowed) + + const moderation = React.useMemo(() => { + return moderateProfile(recipient, moderationOpts) + }, [recipient, moderationOpts]) + + const blockInfo = React.useMemo(() => { + const modui = moderation.ui('profileView') + const blocks = modui.alerts.filter(alert => alert.type === 'blocking') + const listBlocks = blocks.filter(alert => alert.source.type === 'list') + const userBlock = blocks.find(alert => alert.source.type === 'user') + return { + listBlocks, + userBlock, + } + }, [moderation]) return ( <> - <Link - style={[a.flex_row, a.align_center, a.gap_md, a.flex_1, a.pr_md]} - to={makeProfileLink(profile)}> - <PreviewableUserAvatar - size={PFP_SIZE} - profile={profile} - moderation={moderation.ui('avatar')} - disableHoverCard={moderation.blocked} - /> - <View style={a.flex_1}> - <Text - style={[a.text_md, a.font_bold, web(a.leading_normal)]} - numberOfLines={1}> - {displayName} - </Text> - {!isDeletedAccount && ( - <Text - style={[ - t.atoms.text_contrast_medium, - a.text_sm, - web([a.leading_normal, {marginTop: -2}]), - ]} - numberOfLines={1}> - @{profile.handle} - </Text> - )} - </View> - </Link> - + <MessagesListHeader + profile={recipient} + moderation={moderation} + blockInfo={blockInfo} + /> {isConvoActive(convoState) && ( - <ConvoMenu - convo={convoState.convo} - profile={profile} - currentScreen="conversation" - moderation={moderation} + <MessagesList + hasScrolled={hasScrolled} + setHasScrolled={setHasScrolled} + blocked={moderation?.blocked} + footer={ + <MessagesListBlockedFooter + recipient={recipient} + convoId={convoState.convo.id} + hasMessages={convoState.items.length > 0} + blockInfo={blockInfo} + /> + } /> )} </> |