Bluesky app fork with some witchin' additions 💫

clean up logic for showing request buttons (#7964)

authored by samuel.fm and committed by

GitHub e7212f99 490e3812

+85 -49
+85 -49
src/screens/Messages/components/MessagesList.tsx
··· 1 - import React, {useCallback, useRef} from 'react' 1 + import {useCallback, useEffect, useRef, useState} from 'react' 2 2 import {LayoutChangeEvent, View} from 'react-native' 3 3 import {useKeyboardHandler} from 'react-native-keyboard-controller' 4 4 import Animated, { ··· 25 25 import {logger} from '#/logger' 26 26 import {isNative} from '#/platform/detection' 27 27 import {isWeb} from '#/platform/detection' 28 - import {isConvoActive, useConvoActive} from '#/state/messages/convo' 29 - import {ConvoItem, ConvoStatus} from '#/state/messages/convo/types' 28 + import { 29 + ActiveConvoStates, 30 + isConvoActive, 31 + useConvoActive, 32 + } from '#/state/messages/convo' 33 + import {ConvoItem, ConvoState, ConvoStatus} from '#/state/messages/convo/types' 30 34 import {useGetPost} from '#/state/queries/post' 31 35 import {useAgent} from '#/state/session' 32 36 import {useShellLayout} from '#/state/shell/shell-layout' ··· 100 104 101 105 const flatListRef = useAnimatedRef<ListMethods>() 102 106 103 - const [newMessagesPill, setNewMessagesPill] = React.useState({ 107 + const [newMessagesPill, setNewMessagesPill] = useState({ 104 108 show: false, 105 109 startContentOffset: 0, 106 110 }) 107 111 108 - const [emojiPickerState, setEmojiPickerState] = 109 - React.useState<EmojiPickerState>({ 110 - isOpen: false, 111 - pos: {top: 0, left: 0, right: 0, bottom: 0, nextFocusRef: null}, 112 - }) 112 + const [emojiPickerState, setEmojiPickerState] = useState<EmojiPickerState>({ 113 + isOpen: false, 114 + pos: {top: 0, left: 0, right: 0, bottom: 0, nextFocusRef: null}, 115 + }) 113 116 114 117 // We need to keep track of when the scroll offset is at the bottom of the list to know when to scroll as new items 115 118 // are added to the list. For example, if the user is scrolled up to 1iew older messages, we don't want to scroll to ··· 126 129 127 130 // -- Keep track of background state and positioning for new pill 128 131 const layoutHeight = useSharedValue(0) 129 - const didBackground = React.useRef(false) 130 - React.useEffect(() => { 132 + const didBackground = useRef(false) 133 + useEffect(() => { 131 134 if (convoState.status === ConvoStatus.Backgrounded) { 132 135 didBackground.current = true 133 136 } ··· 218 221 } 219 222 }, [convoState, hasScrolled, layoutHeight]) 220 223 221 - const onScroll = React.useCallback( 224 + const onScroll = useCallback( 222 225 (e: ReanimatedScrollEvent) => { 223 226 'worklet' 224 227 layoutHeight.set(e.layoutMeasurement.height) ··· 376 379 ) 377 380 378 381 // -- List layout changes (opening emoji keyboard, etc.) 379 - const onListLayout = React.useCallback( 382 + const onListLayout = useCallback( 380 383 (e: LayoutChangeEvent) => { 381 384 layoutHeight.set(e.nativeEvent.layout.height) 382 385 ··· 395 398 ], 396 399 ) 397 400 398 - const scrollToEndOnPress = React.useCallback(() => { 401 + const scrollToEndOnPress = useCallback(() => { 399 402 flatListRef.current?.scrollToOffset({ 400 403 offset: prevContentHeight.current, 401 404 animated: true, 402 405 }) 403 406 }, [flatListRef]) 404 407 408 + const onOpenEmojiPicker = useCallback((pos: any) => { 409 + setEmojiPickerState({isOpen: true, pos}) 410 + }, []) 411 + 405 412 return ( 406 413 <> 407 414 {/* Custom scroll provider so that we can use the `onScroll` event in our custom List implementation */} ··· 440 447 ) : blocked ? ( 441 448 footer 442 449 ) : ( 443 - isConvoActive(convoState) && 444 - !convoState.isFetchingHistory && ( 445 - <> 446 - {convoState.items.length === 0 ? ( 447 - <> 448 - <ChatEmptyPill /> 449 - <MessageInput 450 - onSendMessage={onSendMessage} 451 - hasEmbed={!!embedUri} 452 - setEmbed={setEmbed} 453 - openEmojiPicker={pos => 454 - setEmojiPickerState({isOpen: true, pos}) 455 - }> 456 - <MessageInputEmbed 457 - embedUri={embedUri} 458 - setEmbed={setEmbed} 459 - /> 460 - </MessageInput> 461 - </> 462 - ) : convoState.convo.status === 'request' && 463 - !hasAcceptOverride ? ( 464 - <ChatStatusInfo convoState={convoState} /> 465 - ) : ( 466 - <MessageInput 467 - onSendMessage={onSendMessage} 468 - hasEmbed={!!embedUri} 469 - setEmbed={setEmbed} 470 - openEmojiPicker={pos => 471 - setEmojiPickerState({isOpen: true, pos}) 472 - }> 473 - <MessageInputEmbed embedUri={embedUri} setEmbed={setEmbed} /> 474 - </MessageInput> 475 - )} 476 - </> 477 - ) 450 + <ConversationFooter 451 + convoState={convoState} 452 + hasAcceptOverride={hasAcceptOverride}> 453 + <MessageInput 454 + onSendMessage={onSendMessage} 455 + hasEmbed={!!embedUri} 456 + setEmbed={setEmbed} 457 + openEmojiPicker={onOpenEmojiPicker}> 458 + <MessageInputEmbed embedUri={embedUri} setEmbed={setEmbed} /> 459 + </MessageInput> 460 + </ConversationFooter> 478 461 )} 479 462 </Animated.View> 480 463 ··· 490 473 </> 491 474 ) 492 475 } 476 + 477 + type FooterState = 'loading' | 'new-chat' | 'request' | 'standard' 478 + 479 + function getFooterState( 480 + convoState: ActiveConvoStates, 481 + hasAcceptOverride?: boolean, 482 + ): FooterState { 483 + if (convoState.items.length === 0) { 484 + if (convoState.isFetchingHistory) { 485 + return 'loading' 486 + } else { 487 + return 'new-chat' 488 + } 489 + } 490 + 491 + if (convoState.convo.status === 'request' && !hasAcceptOverride) { 492 + return 'request' 493 + } 494 + 495 + return 'standard' 496 + } 497 + 498 + function ConversationFooter({ 499 + convoState, 500 + hasAcceptOverride, 501 + children, 502 + }: { 503 + convoState: ConvoState 504 + hasAcceptOverride?: boolean 505 + children?: React.ReactNode // message input 506 + }) { 507 + if (!isConvoActive(convoState)) { 508 + return null 509 + } 510 + 511 + const footerState = getFooterState(convoState, hasAcceptOverride) 512 + 513 + switch (footerState) { 514 + case 'loading': 515 + return null 516 + case 'new-chat': 517 + return ( 518 + <> 519 + <ChatEmptyPill /> 520 + {children} 521 + </> 522 + ) 523 + case 'request': 524 + return <ChatStatusInfo convoState={convoState} /> 525 + case 'standard': 526 + return children 527 + } 528 + }