diff options
Diffstat (limited to 'src/screens/Messages')
-rw-r--r-- | src/screens/Messages/ChatList.tsx | 2 | ||||
-rw-r--r-- | src/screens/Messages/Conversation.tsx | 26 | ||||
-rw-r--r-- | src/screens/Messages/Settings.tsx | 2 | ||||
-rw-r--r-- | src/screens/Messages/components/ChatDisabled.tsx | 2 | ||||
-rw-r--r-- | src/screens/Messages/components/MessageInput.tsx | 21 | ||||
-rw-r--r-- | src/screens/Messages/components/MessageInput.web.tsx | 4 | ||||
-rw-r--r-- | src/screens/Messages/components/MessageInputEmbed.tsx | 2 | ||||
-rw-r--r-- | src/screens/Messages/components/MessagesList.tsx | 36 |
8 files changed, 63 insertions, 32 deletions
diff --git a/src/screens/Messages/ChatList.tsx b/src/screens/Messages/ChatList.tsx index 45b3bf14f..4f2bd251f 100644 --- a/src/screens/Messages/ChatList.tsx +++ b/src/screens/Messages/ChatList.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useMemo, useState} from 'react' +import {useCallback, useEffect, useMemo, useState} from 'react' import {View} from 'react-native' import {ChatBskyConvoDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx index e2e646a3d..ee09adaf0 100644 --- a/src/screens/Messages/Conversation.tsx +++ b/src/screens/Messages/Conversation.tsx @@ -4,10 +4,11 @@ import {useKeyboardController} from 'react-native-keyboard-controller' import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useFocusEffect} from '@react-navigation/native' +import {useFocusEffect, useNavigation} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' -import {CommonNavigatorParams} from '#/lib/routes/types' +import {useEmail} from '#/lib/hooks/useEmail' +import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types' import {isWeb} from '#/platform/detection' import {useProfileShadow} from '#/state/cache/profile-shadow' import {ConvoProvider, isConvoActive, useConvo} from '#/state/messages/convo' @@ -19,6 +20,8 @@ import {useSetMinimalShellMode} from '#/state/shell' import {CenteredView} from '#/view/com/util/Views' import {MessagesList} from '#/screens/Messages/components/MessagesList' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' +import {useDialogControl} from '#/components/Dialog' +import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog' import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter' import {MessagesListHeader} from '#/components/dms/MessagesListHeader' import {Error} from '#/components/Error' @@ -161,8 +164,12 @@ function InnerReady({ hasScrolled: boolean setHasScrolled: React.Dispatch<React.SetStateAction<boolean>> }) { + const {_} = useLingui() const convoState = useConvo() + const navigation = useNavigation<NavigationProp>() const recipient = useProfileShadow(recipientUnshadowed) + const verifyEmailControl = useDialogControl() + const {needsEmailVerification} = useEmail() const moderation = React.useMemo(() => { return moderateProfile(recipient, moderationOpts) @@ -179,6 +186,12 @@ function InnerReady({ } }, [moderation]) + React.useEffect(() => { + if (needsEmailVerification) { + verifyEmailControl.open() + } + }, [needsEmailVerification, verifyEmailControl]) + return ( <> <MessagesListHeader @@ -201,6 +214,15 @@ function InnerReady({ } /> )} + <VerifyEmailDialog + reasonText={_( + msg`Before you may message another user, you must first verify your email.`, + )} + control={verifyEmailControl} + onCloseWithoutVerifying={() => { + navigation.navigate('Home') + }} + /> </> ) } diff --git a/src/screens/Messages/Settings.tsx b/src/screens/Messages/Settings.tsx index 93e3bc400..50b1c4cc9 100644 --- a/src/screens/Messages/Settings.tsx +++ b/src/screens/Messages/Settings.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react' +import {useCallback} from 'react' import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' diff --git a/src/screens/Messages/components/ChatDisabled.tsx b/src/screens/Messages/components/ChatDisabled.tsx index c768d2504..5e9f57fa5 100644 --- a/src/screens/Messages/components/ChatDisabled.tsx +++ b/src/screens/Messages/components/ChatDisabled.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useState} from 'react' +import {useCallback, useState} from 'react' import {View} from 'react-native' import {ComAtprotoModerationDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' diff --git a/src/screens/Messages/components/MessageInput.tsx b/src/screens/Messages/components/MessageInput.tsx index 21d6e574e..85509211b 100644 --- a/src/screens/Messages/components/MessageInput.tsx +++ b/src/screens/Messages/components/MessageInput.tsx @@ -18,6 +18,7 @@ import Graphemer from 'graphemer' import {HITSLOP_10, MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants' import {useHaptics} from '#/lib/haptics' +import {useEmail} from '#/lib/hooks/useEmail' import {isIOS} from '#/platform/detection' import { useMessageDraft, @@ -61,10 +62,15 @@ export function MessageInput({ const [message, setMessage] = React.useState(getDraft) const inputRef = useAnimatedRef<TextInput>() + const {needsEmailVerification} = useEmail() + useSaveMessageDraft(message) useExtractEmbedFromFacets(message, setEmbed) const onSubmit = React.useCallback(() => { + if (needsEmailVerification) { + return + } if (!hasEmbed && message.trim() === '') { return } @@ -84,6 +90,7 @@ export function MessageInput({ inputRef.current?.focus() }, 100) }, [ + needsEmailVerification, hasEmbed, message, clearDraft, @@ -101,22 +108,22 @@ export function MessageInput({ const measurement = measure(inputRef) if (!measurement) return - const max = windowHeight - -keyboardHeight.value - topInset - 150 + const max = windowHeight - -keyboardHeight.get() - topInset - 150 const availableSpace = max - measurement.height - maxHeight.value = max - isInputScrollable.value = availableSpace < 30 + maxHeight.set(max) + isInputScrollable.set(availableSpace < 30) }, }, [windowHeight, topInset], ) const animatedStyle = useAnimatedStyle(() => ({ - maxHeight: maxHeight.value, + maxHeight: maxHeight.get(), })) const animatedProps = useAnimatedProps(() => ({ - scrollEnabled: isInputScrollable.value, + scrollEnabled: isInputScrollable.get(), })) return ( @@ -159,6 +166,7 @@ export function MessageInput({ ref={inputRef} hitSlop={HITSLOP_10} animatedProps={animatedProps} + editable={!needsEmailVerification} /> <Pressable accessibilityRole="button" @@ -171,7 +179,8 @@ export function MessageInput({ a.justify_center, {height: 30, width: 30, backgroundColor: t.palette.primary_500}, ]} - onPress={onSubmit}> + onPress={onSubmit} + disabled={needsEmailVerification}> <PaperPlane fill={t.palette.white} style={[a.relative, {left: 1}]} /> </Pressable> </View> diff --git a/src/screens/Messages/components/MessageInput.web.tsx b/src/screens/Messages/components/MessageInput.web.tsx index b15cd2492..72e0382a9 100644 --- a/src/screens/Messages/components/MessageInput.web.tsx +++ b/src/screens/Messages/components/MessageInput.web.tsx @@ -38,7 +38,7 @@ export function MessageInput({ children?: React.ReactNode openEmojiPicker?: (pos: EmojiPickerPosition) => void }) { - const {isTabletOrDesktop} = useWebMediaQueries() + const {isMobile} = useWebMediaQueries() const {_} = useLingui() const t = useTheme() const {getDraft, clearDraft} = useMessageDraft() @@ -212,7 +212,7 @@ export function MessageInput({ onChange={onChange} // On mobile web phones, we want to keep the same behavior as the native app. Do not submit the message // in these cases. - onKeyDown={isTouchDevice && isTabletOrDesktop ? undefined : onKeyDown} + onKeyDown={isTouchDevice && isMobile ? undefined : onKeyDown} /> <Pressable accessibilityRole="button" diff --git a/src/screens/Messages/components/MessageInputEmbed.tsx b/src/screens/Messages/components/MessageInputEmbed.tsx index 2d1551019..6df0ef2fc 100644 --- a/src/screens/Messages/components/MessageInputEmbed.tsx +++ b/src/screens/Messages/components/MessageInputEmbed.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useMemo, useState} from 'react' +import {useCallback, useEffect, useMemo, useState} from 'react' import {LayoutAnimation, View} from 'react-native' import { AppBskyFeedPost, diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx index 9db4f07b6..9f67929a3 100644 --- a/src/screens/Messages/components/MessagesList.tsx +++ b/src/screens/Messages/components/MessagesList.tsx @@ -145,7 +145,7 @@ export function MessagesList({ (_: number, height: number) => { // Because web does not have `maintainVisibleContentPosition` support, we will need to manually scroll to the // previous off whenever we add new content to the previous offset whenever we add new content to the list. - if (isWeb && isAtTop.value && hasScrolled) { + if (isWeb && isAtTop.get() && hasScrolled) { flatListRef.current?.scrollToOffset({ offset: height - prevContentHeight.current, animated: false, @@ -153,7 +153,7 @@ export function MessagesList({ } // This number _must_ be the height of the MaybeLoader component - if (height > 50 && isAtBottom.value) { + if (height > 50 && isAtBottom.get()) { // If the size of the content is changing by more than the height of the screen, then we don't // want to scroll further than the start of all the new content. Since we are storing the previous offset, // we can just scroll the user to that offset and add a little bit of padding. We'll also show the pill @@ -161,7 +161,7 @@ export function MessagesList({ if ( didBackground.current && hasScrolled && - height - prevContentHeight.current > layoutHeight.value - 50 && + height - prevContentHeight.current > layoutHeight.get() - 50 && convoState.items.length - prevItemCount.current > 1 ) { flatListRef.current?.scrollToOffset({ @@ -209,7 +209,7 @@ export function MessagesList({ ) const onStartReached = useCallback(() => { - if (hasScrolled && prevContentHeight.current > layoutHeight.value) { + if (hasScrolled && prevContentHeight.current > layoutHeight.get()) { convoState.fetchMessageHistory() } }, [convoState, hasScrolled, layoutHeight]) @@ -217,18 +217,18 @@ export function MessagesList({ const onScroll = React.useCallback( (e: ReanimatedScrollEvent) => { 'worklet' - layoutHeight.value = e.layoutMeasurement.height + layoutHeight.set(e.layoutMeasurement.height) const bottomOffset = e.contentOffset.y + e.layoutMeasurement.height // Most apps have a little bit of space the user can scroll past while still automatically scrolling ot the bottom // when a new message is added, hence the 100 pixel offset - isAtBottom.value = e.contentSize.height - 100 < bottomOffset - isAtTop.value = e.contentOffset.y <= 1 + isAtBottom.set(e.contentSize.height - 100 < bottomOffset) + isAtTop.set(e.contentOffset.y <= 1) if ( newMessagesPill.show && (e.contentOffset.y > newMessagesPill.startContentOffset + 200 || - isAtBottom.value) + isAtBottom.get()) ) { runOnJS(setNewMessagesPill)({ show: false, @@ -256,28 +256,28 @@ export function MessagesList({ // Immediate updates - like opening the emoji picker - will have a duration of zero. In those cases, we should // just update the height here instead of having the `onMove` event do it (that event will not fire!) if (e.duration === 0) { - layoutScrollWithoutAnimation.value = true - keyboardHeight.value = e.height + layoutScrollWithoutAnimation.set(true) + keyboardHeight.set(e.height) } else { - keyboardIsOpening.value = true + keyboardIsOpening.set(true) } }, onMove: e => { 'worklet' - keyboardHeight.value = e.height + keyboardHeight.set(e.height) if (e.height > bottomOffset) { scrollTo(flatListRef, 0, 1e7, false) } }, onEnd: () => { 'worklet' - keyboardIsOpening.value = false + keyboardIsOpening.set(false) }, }) const animatedListStyle = useAnimatedStyle(() => ({ marginBottom: - keyboardHeight.value > bottomOffset ? keyboardHeight.value : bottomOffset, + keyboardHeight.get() > bottomOffset ? keyboardHeight.get() : bottomOffset, })) // -- Message sending @@ -363,13 +363,13 @@ export function MessagesList({ // -- List layout changes (opening emoji keyboard, etc.) const onListLayout = React.useCallback( (e: LayoutChangeEvent) => { - layoutHeight.value = e.nativeEvent.layout.height + layoutHeight.set(e.nativeEvent.layout.height) - if (isWeb || !keyboardIsOpening.value) { + if (isWeb || !keyboardIsOpening.get()) { flatListRef.current?.scrollToEnd({ - animated: !layoutScrollWithoutAnimation.value, + animated: !layoutScrollWithoutAnimation.get(), }) - layoutScrollWithoutAnimation.value = false + layoutScrollWithoutAnimation.set(false) } }, [ |