diff --git a/src/screens/Messages/Conversation/MessagesList.tsx b/src/screens/Messages/Conversation/MessagesList.tsx index f99a41b7f1..a92f3d50aa 100644 --- a/src/screens/Messages/Conversation/MessagesList.tsx +++ b/src/screens/Messages/Conversation/MessagesList.tsx @@ -10,7 +10,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context' import {AppBskyRichtextFacet, RichText} from '@atproto/api' import {shortenLinks} from '#/lib/strings/rich-text-manip' -import {isIOS} from '#/platform/detection' +import {isIOS, isNative} from '#/platform/detection' import {useConvo} from '#/state/messages/convo' import {ConvoItem, ConvoStatus} from '#/state/messages/convo/types' import {useAgent} from '#/state/session' @@ -85,7 +85,7 @@ export function MessagesList() { // Instead, we use `onMomentumScrollEnd` and this value to determine if we need to start scrolling or not. const isMomentumScrolling = useSharedValue(false) - const [hasInitiallyScrolled, setHasInitiallyScrolled] = React.useState(false) + const hasInitiallyScrolled = useSharedValue(false) // Every time the content size changes, that means one of two things is happening: // 1. New messages are being added from the log or from a message you have sent @@ -101,7 +101,7 @@ export function MessagesList() { (_: number, height: number) => { // Because web does not have `maintainVisibleContentPosition` support, we will need to manually scroll to the // previous offset whenever we add new content to the previous offset whenever we add new content to the list. - if (isWeb && isAtTop.value && hasInitiallyScrolled) { + if (isWeb && isAtTop.value && hasInitiallyScrolled.value) { flatListRef.current?.scrollToOffset({ animated: false, offset: height - contentHeight.value, @@ -116,7 +116,7 @@ export function MessagesList() { } flatListRef.current?.scrollToOffset({ - animated: hasInitiallyScrolled, + animated: hasInitiallyScrolled.value, offset: height, }) isMomentumScrolling.value = true @@ -133,7 +133,7 @@ export function MessagesList() { // The check for `hasInitiallyScrolled` prevents an initial fetch on mount. FlatList triggers `onStartReached` // immediately on mount, since we are in fact at an offset of zero, so we have to ignore those initial calls. const onStartReached = useCallback(() => { - if (convo.status === ConvoStatus.Ready && hasInitiallyScrolled) { + if (convo.status === ConvoStatus.Ready && hasInitiallyScrolled.value) { convo.fetchMessageHistory() } }, [convo, hasInitiallyScrolled]) @@ -178,8 +178,8 @@ export function MessagesList() { // This number _must_ be the height of the MaybeLoader component. // We don't check for zero, because the `MaybeLoader` component is always present, even when not visible, which // adds a 50 pixel offset. - if (contentHeight.value > 50 && !hasInitiallyScrolled) { - runOnJS(setHasInitiallyScrolled)(true) + if (contentHeight.value > 50 && !hasInitiallyScrolled.value) { + hasInitiallyScrolled.value = true } }, [contentHeight.value, hasInitiallyScrolled, isAtBottom, isAtTop], @@ -228,17 +228,20 @@ export function MessagesList() { data={convo.items} renderItem={renderItem} keyExtractor={keyExtractor} + containWeb={true} + contentContainerStyle={{ + paddingHorizontal: 10, + }} disableVirtualization={true} - initialNumToRender={isWeb ? 50 : 25} - maxToRenderPerBatch={isWeb ? 50 : 25} + initialNumToRender={isNative ? 30 : 60} + maxToRenderPerBatch={isWeb ? 30 : 60} keyboardDismissMode="on-drag" keyboardShouldPersistTaps="handled" maintainVisibleContentPosition={{ minIndexForVisible: 1, }} - containWeb={true} - contentContainerStyle={{paddingHorizontal: 10}} removeClippedSubviews={false} + sideBorders={false} onContentSizeChange={onContentSizeChange} onStartReached={onStartReached} onScrollToIndexFailed={onScrollToIndexFailed} @@ -246,7 +249,6 @@ export function MessagesList() { ListHeaderComponent={ } - sideBorders={false} /> diff --git a/src/screens/Messages/Conversation/index.tsx b/src/screens/Messages/Conversation/index.tsx index af9064cc30..4c8cfe7ed9 100644 --- a/src/screens/Messages/Conversation/index.tsx +++ b/src/screens/Messages/Conversation/index.tsx @@ -22,6 +22,7 @@ import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {ConvoMenu} from '#/components/dms/ConvoMenu' import {Error} from '#/components/Error' import {ListMaybePlaceholder} from '#/components/Lists' +import {Loader} from '#/components/Loader' import {Text} from '#/components/Typography' import {ClipClopGate} from '../gate' @@ -53,20 +54,27 @@ export function MessagesConversationScreen({route}: Props) { } function Inner() { + const t = useTheme() const convo = useConvo() const {_} = useLingui() - if ( - convo.status === ConvoStatus.Uninitialized || - convo.status === ConvoStatus.Initializing - ) { - return ( - -
- - - ) - } + const [hasInitiallyRendered, setHasInitiallyRendered] = React.useState(false) + + // HACK: Because we need to scroll to the bottom of the list once initial items are added to the list, we also have + // to take into account that scrolling to the end of the list on native will happen asynchronously. This will cause + // a little flicker when the items are first renedered at the top and immediately scrolled to the bottom. to prevent + // this, we will wait until the first render has completed to remove the loading overlay. + React.useEffect(() => { + if ( + !hasInitiallyRendered && + convo.status === ConvoStatus.Ready && + !convo.isFetchingHistory + ) { + setTimeout(() => { + setHasInitiallyRendered(true) + }, 15) + } + }, [convo.isFetchingHistory, convo.items, convo.status, hasInitiallyRendered]) if (convo.status === ConvoStatus.Error) { return ( @@ -88,8 +96,30 @@ function Inner() { return ( -
- +
+ + {convo.status !== ConvoStatus.Ready ? ( + + ) : ( + + )} + {!hasInitiallyRendered && ( + + + + + + )} + ) @@ -128,7 +158,8 @@ let Header = ({ a.justify_between, a.align_start, a.gap_lg, - a.px_lg, + a.pl_xl, + a.pr_lg, a.py_sm, ]}> {!gtTablet ? ( @@ -154,12 +185,19 @@ let Header = ({ )} {profile ? ( - <> + - + {profile.displayName} - + + @{profile.handle} + + ) : ( <> + diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index 12e24577e7..6801def751 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -554,7 +554,7 @@ export class Convo { { cursor: nextCursor, convoId: this.convoId, - limit: isNative ? 40 : 60, + limit: isNative ? 30 : 60, }, { headers: {