Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Clean up minor issues in MessgeItem (#10338)

authored by

DS Boyce and committed by
GitHub
6fc31eeb bf371d7e

+69 -81
+69 -81
src/components/dms/MessageItem.tsx
··· 1 - import {memo, useCallback, useEffect, useMemo, useRef} from 'react' 1 + import {memo, useEffect, useMemo, useRef} from 'react' 2 2 import { 3 3 type GestureResponderEvent, 4 4 LayoutAnimation, ··· 28 28 import {Trans, useLingui} from '@lingui/react/macro' 29 29 import {useQueryClient} from '@tanstack/react-query' 30 30 31 + import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name' 31 32 import {makeProfileLink} from '#/lib/routes/links' 32 - import {sanitizeDisplayName} from '#/lib/strings/display-names' 33 - import {sanitizeHandle} from '#/lib/strings/handles' 34 33 import {useConvoActive} from '#/state/messages/convo' 35 34 import {type ConvoItem} from '#/state/messages/convo/types' 36 35 import {useModerationOpts} from '#/state/preferences/moderation-opts' ··· 59 58 const CLUSTERED_MESSAGE_THRESHOLD_MS = 5 * 60 * 1000 60 59 const MESSAGE_GAP_THRESHOLD_MS = 60 * 60 * 1000 61 60 62 - function isWithinCluster({ 61 + const TAP_AND_DRAG_DELAY_MS = 100 62 + 63 + function isWithinClusterBoundary({ 63 64 isPending, 64 65 adjacentMessage, 65 66 isFromSameSender, ··· 111 112 const {message, nextMessage, prevMessage} = item 112 113 const isPending = item.type === 'pending-message' 113 114 114 - const displayName = sanitizeDisplayName( 115 - profile?.displayName || sanitizeHandle(profile?.handle ?? ''), 116 - ) 115 + const displayName = profile ? createSanitizedDisplayName(profile) : null 117 116 118 - const isFromSelf = message.sender?.did === currentAccount?.did 117 + const isFromSelf = 118 + message.sender?.did != null && message.sender.did === currentAccount?.did 119 119 120 120 const prevIsMessage = ChatBskyConvoDefs.isMessageView(prevMessage) 121 121 const nextIsMessage = ChatBskyConvoDefs.isMessageView(nextMessage) 122 122 123 123 const isPrevFromSameSender = 124 - prevIsMessage && prevMessage.sender?.did === message.sender?.did 124 + prevIsMessage && 125 + prevMessage.sender?.did === message.sender?.did && 126 + message.sender?.did != null 125 127 const isNextFromSameSender = 126 - nextIsMessage && nextMessage.sender?.did === message.sender?.did 128 + nextIsMessage && 129 + nextMessage.sender?.did === message.sender?.did && 130 + message.sender?.did != null 127 131 128 - const isFirstInCluster = useMemo( 129 - () => 130 - isWithinCluster({ 131 - isPending, 132 - adjacentMessage: prevMessage, 133 - isFromSameSender: isPrevFromSameSender, 134 - currentSentAt: message.sentAt, 135 - direction: 'prev', 136 - }), 137 - [isPending, prevMessage, isPrevFromSameSender, message.sentAt], 138 - ) 132 + const isFirstInCluster = isWithinClusterBoundary({ 133 + isPending, 134 + adjacentMessage: prevMessage, 135 + isFromSameSender: isPrevFromSameSender, 136 + currentSentAt: message.sentAt, 137 + direction: 'prev', 138 + }) 139 139 140 - const isLastInCluster = useMemo( 141 - () => 142 - isWithinCluster({ 143 - isPending, 144 - adjacentMessage: nextMessage, 145 - isFromSameSender: isNextFromSameSender, 146 - currentSentAt: message.sentAt, 147 - direction: 'next', 148 - }), 149 - [isPending, nextMessage, isNextFromSameSender, message.sentAt], 150 - ) 140 + const isLastInCluster = isWithinClusterBoundary({ 141 + isPending, 142 + adjacentMessage: nextMessage, 143 + isFromSameSender: isNextFromSameSender, 144 + currentSentAt: message.sentAt, 145 + direction: 'next', 146 + }) 151 147 152 148 const hasLargeGapFromPrev = 153 149 !ChatBskyConvoDefs.isMessageView(prevMessage) || ··· 159 155 const isDateDividerToggled = isDividerToggled(message.id) 160 156 const isNextDateDividerToggled = 161 157 nextMessage != null && isDividerToggled(nextMessage.id) 162 - const showDateDivider = hasLargeGapFromPrev 163 158 164 159 const effectiveFirstInCluster = isFirstInCluster || isDateDividerToggled 165 160 const effectiveLastInCluster = isLastInCluster || isNextDateDividerToggled ··· 169 164 170 165 const hasReactions = message.reactions && message.reactions.length > 0 171 166 const prevHasReactions = 172 - prevIsMessage && 173 - prevMessage.reactions != null && 174 - prevMessage.reactions.length > 0 167 + prevIsMessage && prevMessage.reactions && prevMessage.reactions.length > 0 175 168 const squaredBottomCorner = 176 169 !hasReactions && 177 170 isInCluster && ··· 183 176 184 177 const pendingColor = t.palette.primary_300 185 178 186 - const rt = useMemo(() => { 187 - return new RichTextAPI({text: message.text, facets: message.facets}) 188 - }, [message.text, message.facets]) 179 + const rt = new RichTextAPI({text: message.text, facets: message.facets}) 189 180 190 181 const hasEmbedAndText = 191 182 AppBskyEmbedRecord.isView(message.embed) && rt.text.length > 0 ··· 225 216 }, 226 217 ) 227 218 228 - const avatar = profile ? ( 229 - <Link 230 - label={l`${sanitizeDisplayName( 231 - profile.displayName || sanitizeHandle(profile.handle), 232 - )}’s avatar`} 233 - accessibilityHint={l`Opens this profile`} 234 - to={makeProfileLink({ 235 - did: profile.did, 236 - handle: profile.handle, 237 - })} 238 - onPress={() => unstableCacheProfileView(queryClient, profile)}> 239 - <ProfileCard.Avatar 240 - profile={profile} 241 - size={AVATAR_SIZE} 242 - moderationOpts={moderationOpts!} 243 - disabledPreview 244 - /> 245 - </Link> 246 - ) : ( 247 - <ProfileCard.AvatarPlaceholder size={AVATAR_SIZE} /> 248 - ) 219 + const avatar = 220 + profile && moderationOpts ? ( 221 + <Link 222 + label={l`${createSanitizedDisplayName(profile)}’s avatar`} 223 + accessibilityHint={l`Opens this profile`} 224 + to={makeProfileLink({ 225 + did: profile.did, 226 + handle: profile.handle, 227 + })} 228 + onPress={() => unstableCacheProfileView(queryClient, profile)}> 229 + <ProfileCard.Avatar 230 + profile={profile} 231 + size={AVATAR_SIZE} 232 + moderationOpts={moderationOpts} 233 + disabledPreview 234 + /> 235 + </Link> 236 + ) : ( 237 + <ProfileCard.AvatarPlaceholder size={AVATAR_SIZE} /> 238 + ) 249 239 250 240 const groupedReactions = useMemo(() => { 251 241 const reactions = message.reactions ?? [] ··· 287 277 return l`You reacted ${reaction.value}` 288 278 } else { 289 279 const senderDid = reaction.sender.did 290 - const sender = convo.members.find(member => member.did === senderDid) 291 - if (sender) { 292 - return l`${sanitizeDisplayName( 293 - sender.displayName || sender.handle, 294 - )} reacted ${reaction.value}` 280 + const memberSender = convo.members.find( 281 + member => member.did === senderDid, 282 + ) 283 + if (memberSender) { 284 + return l`${createSanitizedDisplayName(memberSender)} reacted ${reaction.value}` 295 285 } 296 286 return l`Someone reacted ${reaction.value}` 297 287 } ··· 343 333 // Include a delay here to account for tap-and-drag before release. 344 334 setTimeout(() => { 345 335 reactionTapRef.current = false 346 - }, 100) 336 + }, TAP_AND_DRAG_DELAY_MS) 347 337 }} 348 - onPress={() => (isGroupChat ? reactionsControl.open() : undefined)}> 338 + onPress={isGroupChat ? reactionsControl.open : undefined}> 349 339 {groupedReactions.map(group => ( 350 340 <Animated.View 351 341 entering={native(ZoomIn.springify(200).delay(400))} 352 342 exiting={ 353 - groupedReactions.length > 1 && native(ZoomOut.delay(200)) 343 + groupedReactions.length > 1 344 + ? native(ZoomOut.delay(200)) 345 + : undefined 354 346 } 355 347 layout={native(LinearTransition.delay(300))} 356 348 key={group.value} ··· 399 391 400 392 return ( 401 393 <> 402 - {(showDateDivider || isDateDividerToggled) && ( 394 + {(hasLargeGapFromPrev || isDateDividerToggled) && ( 403 395 <Animated.View entering={native(FadeIn)} exiting={native(FadeOut)}> 404 396 <DateDivider date={message.sentAt} /> 405 397 </Animated.View> ··· 424 416 a.flex_grow, 425 417 !isFromSelf && isGroupChat && {paddingLeft: AVATAR_SIZE}, 426 418 ]}> 427 - {showDisplayName ? ( 419 + {displayName && showDisplayName ? ( 428 420 <Text 429 421 style={[ 430 422 a.text_xs, ··· 459 451 ...(isOnlyEmoji(message.text) 460 452 ? [] 461 453 : [ 462 - a.rounded_md, 463 454 a.rounded_xl, 464 455 a.py_sm, 465 456 a.px_md, ··· 538 529 const t = useTheme() 539 530 const {t: l} = useLingui() 540 531 541 - const handleRetry = useCallback( 542 - (e: GestureResponderEvent) => { 543 - if (item.type === 'pending-message' && item.retry) { 544 - e.preventDefault() 545 - item.retry() 546 - return false 547 - } 548 - }, 549 - [item], 550 - ) 532 + const handleRetry = (e: GestureResponderEvent) => { 533 + if (item.type === 'pending-message' && item.retry) { 534 + e.preventDefault() 535 + item.retry() 536 + return false 537 + } 538 + } 551 539 552 540 const errorColor = t.palette.negative_400 553 541