[Chat] Keep track of relatedProfiles in Convo agent (#10354)
This commit is contained in:
@@ -4,23 +4,29 @@ import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {atoms as a} from '#/alf'
|
||||
import {MessageContextMenu} from '#/components/dms/MessageContextMenu'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function ActionsWrapper({
|
||||
message,
|
||||
isFromSelf,
|
||||
senderProfile,
|
||||
children,
|
||||
onTap,
|
||||
}: {
|
||||
message: ChatBskyConvoDefs.MessageView
|
||||
hasReactions?: boolean
|
||||
isFromSelf: boolean
|
||||
senderProfile?: bsky.profile.AnyProfileView
|
||||
children: React.ReactNode
|
||||
onTap?: () => void
|
||||
}) {
|
||||
const {t: l} = useLingui()
|
||||
|
||||
return (
|
||||
<MessageContextMenu message={message} onTap={onTap}>
|
||||
<MessageContextMenu
|
||||
message={message}
|
||||
senderProfile={senderProfile}
|
||||
onTap={onTap}>
|
||||
{trigger =>
|
||||
// will always be true, since this file is platform split
|
||||
trigger.IS_NATIVE && (
|
||||
|
||||
@@ -10,6 +10,7 @@ import {MessageContextMenu} from '#/components/dms/MessageContextMenu'
|
||||
import {DotGrid3x1_Stroke2_Corner0_Rounded as DotsHorizontalIcon} from '#/components/icons/DotGrid'
|
||||
import {EmojiSmile_Stroke2_Corner0_Rounded as EmojiSmileIcon} from '#/components/icons/Emoji'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {EmojiReactionPicker} from './EmojiReactionPicker'
|
||||
import {hasReachedReactionLimit} from './util'
|
||||
|
||||
@@ -17,12 +18,14 @@ export function ActionsWrapper({
|
||||
message,
|
||||
hasReactions,
|
||||
isFromSelf,
|
||||
senderProfile,
|
||||
children,
|
||||
onTap,
|
||||
}: {
|
||||
message: ChatBskyConvoDefs.MessageView
|
||||
hasReactions?: boolean
|
||||
isFromSelf: boolean
|
||||
senderProfile?: bsky.profile.AnyProfileView
|
||||
children: React.ReactNode
|
||||
onTap?: () => void
|
||||
}) {
|
||||
@@ -114,7 +117,7 @@ export function ActionsWrapper({
|
||||
)
|
||||
}}
|
||||
</EmojiReactionPicker>
|
||||
<MessageContextMenu message={message}>
|
||||
<MessageContextMenu message={message} senderProfile={senderProfile}>
|
||||
{({props, state, IS_NATIVE, control}) => {
|
||||
// always false, file is platform split
|
||||
if (IS_NATIVE) return null
|
||||
|
||||
@@ -4,7 +4,7 @@ import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {subDays} from 'date-fns'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Text} from '../Typography'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {localDateString} from './util'
|
||||
|
||||
const timeFormatter = new Intl.DateTimeFormat(undefined, {
|
||||
|
||||
@@ -25,15 +25,18 @@ import {usePromptControl} from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {EmojiReactionPicker} from './EmojiReactionPicker'
|
||||
import {hasReachedReactionLimit} from './util'
|
||||
|
||||
export let MessageContextMenu = ({
|
||||
message,
|
||||
senderProfile,
|
||||
children,
|
||||
onTap,
|
||||
}: {
|
||||
message: ChatBskyConvoDefs.MessageView
|
||||
senderProfile?: bsky.profile.AnyProfileView
|
||||
children: TriggerProps['children']
|
||||
onTap?: () => void
|
||||
}): React.ReactNode => {
|
||||
@@ -110,9 +113,7 @@ export let MessageContextMenu = ({
|
||||
[l, convo, message, currentAccount?.did],
|
||||
)
|
||||
|
||||
const sender = convo.convo.members.find(
|
||||
member => member.did === message.sender.did,
|
||||
)
|
||||
const sender = senderProfile
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -30,7 +30,6 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {useConvoActive} from '#/state/messages/convo'
|
||||
import {type ConvoItem} from '#/state/messages/convo/types'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache'
|
||||
@@ -43,7 +42,6 @@ import {InlineLinkText, Link} from '#/components/Link'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import {Text} from '#/components/Typography'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {DateDivider} from './DateDivider'
|
||||
import {useDateDividerToggle} from './DateDividerToggle'
|
||||
import {MessageItemEmbed} from './MessageItemEmbed'
|
||||
@@ -93,19 +91,18 @@ function isWithinClusterBoundary({
|
||||
let MessageItem = ({
|
||||
item,
|
||||
isGroupChat = false,
|
||||
profile,
|
||||
}: {
|
||||
item: ConvoItem & {type: 'message' | 'pending-message'}
|
||||
isGroupChat?: boolean
|
||||
profile?: bsky.profile.AnyProfileView
|
||||
}): React.ReactNode => {
|
||||
const t = useTheme()
|
||||
const {currentAccount} = useSession()
|
||||
const {t: l} = useLingui()
|
||||
const {convo} = useConvoActive()
|
||||
const moderationOpts = useModerationOpts()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const profile = item.relatedProfiles.get(item.message.sender.did)
|
||||
|
||||
const reactionsControl = useDialogControl()
|
||||
const reactionTapRef = useRef(false)
|
||||
|
||||
@@ -277,9 +274,7 @@ let MessageItem = ({
|
||||
return l`You reacted ${reaction.value}`
|
||||
} else {
|
||||
const senderDid = reaction.sender.did
|
||||
const memberSender = convo.members.find(
|
||||
member => member.did === senderDid,
|
||||
)
|
||||
const memberSender = item.relatedProfiles.get(senderDid)
|
||||
if (memberSender) {
|
||||
return l`${createSanitizedDisplayName(memberSender)} reacted ${reaction.value}`
|
||||
}
|
||||
@@ -290,7 +285,13 @@ let MessageItem = ({
|
||||
one: '# person',
|
||||
other: '# people',
|
||||
})} reacted – ${groupedReactions.map(g => g.value).join(' ')}`
|
||||
}, [reactions, groupedReactions, currentAccount?.did, convo.members, l])
|
||||
}, [
|
||||
reactions,
|
||||
groupedReactions,
|
||||
currentAccount?.did,
|
||||
item.relatedProfiles,
|
||||
l,
|
||||
])
|
||||
|
||||
const appliedReactions = (
|
||||
<LayoutAnimationConfig skipEntering skipExiting>
|
||||
@@ -375,7 +376,7 @@ let MessageItem = ({
|
||||
) : null}
|
||||
<ReactionsDialog
|
||||
control={reactionsControl}
|
||||
members={convo.members}
|
||||
relatedProfiles={item.relatedProfiles}
|
||||
message={message}
|
||||
reactions={message.reactions}
|
||||
groupedReactions={groupedReactions}
|
||||
@@ -391,11 +392,13 @@ let MessageItem = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{(hasLargeGapFromPrev || isDateDividerToggled) && (
|
||||
<Animated.View entering={native(FadeIn)} exiting={native(FadeOut)}>
|
||||
<DateDivider date={message.sentAt} />
|
||||
</Animated.View>
|
||||
)}
|
||||
<LayoutAnimationConfig skipExiting skipEntering>
|
||||
{(hasLargeGapFromPrev || isDateDividerToggled) && (
|
||||
<Animated.View entering={native(FadeIn)} exiting={native(FadeOut)}>
|
||||
<DateDivider date={message.sentAt} />
|
||||
</Animated.View>
|
||||
)}
|
||||
</LayoutAnimationConfig>
|
||||
<View style={[messageInset, effectiveFirstInCluster && a.mt_md]}>
|
||||
<View style={[a.relative]}>
|
||||
{showAvatar ? (
|
||||
@@ -434,6 +437,7 @@ let MessageItem = ({
|
||||
hasReactions={hasReactions}
|
||||
isFromSelf={isFromSelf}
|
||||
message={message}
|
||||
senderProfile={profile}
|
||||
onTap={() => {
|
||||
if (reactionTapRef.current) return
|
||||
if (!hasLargeGapFromPrev) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
View,
|
||||
} from 'react-native'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {type ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {type ChatBskyActorDefs, type ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
@@ -33,13 +33,13 @@ type Reaction = {
|
||||
|
||||
export function ReactionsDialog({
|
||||
control,
|
||||
members,
|
||||
relatedProfiles,
|
||||
message,
|
||||
reactions,
|
||||
groupedReactions,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
members: bsky.profile.AnyProfileView[]
|
||||
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
|
||||
message: ChatBskyConvoDefs.MessageView
|
||||
reactions?: ChatBskyConvoDefs.ReactionView[]
|
||||
groupedReactions?: Reaction[]
|
||||
@@ -100,7 +100,7 @@ export function ReactionsDialog({
|
||||
return 0
|
||||
})
|
||||
.map(reaction => {
|
||||
const sender = members.find(m => m.did === reaction.sender.did)
|
||||
const sender = relatedProfiles.get(reaction.sender.did)
|
||||
if (!sender) return null
|
||||
return (
|
||||
<ReactionRow
|
||||
|
||||
@@ -23,15 +23,15 @@ export type SystemMessageInfo = {
|
||||
|
||||
function getReferredDisplayName(
|
||||
user: ChatBskyConvoDefs.SystemMessageReferredUser,
|
||||
relatedProfiles: ChatBskyActorDefs.ProfileViewBasic[],
|
||||
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>,
|
||||
): string | null {
|
||||
const profile = relatedProfiles.find(p => p.did === user.did)
|
||||
const profile = relatedProfiles.get(user.did)
|
||||
return profile ? createSanitizedDisplayName(profile) : null
|
||||
}
|
||||
|
||||
export function getSystemMessageInfo(
|
||||
data: ChatBskyConvoDefs.SystemMessageView['data'],
|
||||
relatedProfiles: ChatBskyActorDefs.ProfileViewBasic[],
|
||||
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>,
|
||||
): SystemMessageInfo | null {
|
||||
if (ChatBskyConvoDefs.isSystemMessageDataAddMember(data)) {
|
||||
const name = getReferredDisplayName(data.member, relatedProfiles)
|
||||
|
||||
@@ -298,7 +298,10 @@ function BaseChatItem({
|
||||
|
||||
// System message
|
||||
if (ChatBskyConvoDefs.isSystemMessageView(convo.lastMessage)) {
|
||||
const info = getSystemMessageInfo(convo.lastMessage.data, convo.members)
|
||||
const info = getSystemMessageInfo(
|
||||
convo.lastMessage.data,
|
||||
new Map(convo.members.map(m => [m.did, m])),
|
||||
)
|
||||
if (info) {
|
||||
lastMessage = i18n._(info.message)
|
||||
lastMessageSentAt = convo.lastMessage.sentAt
|
||||
|
||||
@@ -374,9 +374,6 @@ export function MessagesList({
|
||||
return (
|
||||
<MessageItem
|
||||
item={item}
|
||||
profile={convoState.convo.members.find(
|
||||
member => member.did === item.message.sender.did,
|
||||
)}
|
||||
isGroupChat={convoState.convo.kind === 'group'}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -107,10 +107,8 @@ export class Convo {
|
||||
{id: string; message: ChatBskyConvoSendMessage.InputSchema['message']}
|
||||
> = new Map()
|
||||
private deletedMessages: Set<string> = new Set()
|
||||
private systemMessageProfiles: Map<
|
||||
string,
|
||||
ChatBskyActorDefs.ProfileViewBasic
|
||||
> = new Map()
|
||||
private relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic> =
|
||||
new Map()
|
||||
|
||||
private isProcessingPendingMessages = false
|
||||
|
||||
@@ -483,7 +481,7 @@ export class Convo {
|
||||
this.newMessages = new Map()
|
||||
this.pendingMessages = new Map()
|
||||
this.deletedMessages = new Set()
|
||||
this.systemMessageProfiles = new Map()
|
||||
this.relatedProfiles = new Map()
|
||||
|
||||
this.pendingMessageFailure = null
|
||||
this.fetchMessageHistoryError = undefined
|
||||
@@ -510,6 +508,11 @@ export class Convo {
|
||||
|
||||
private setConvo(convo: ChatBskyConvoDefs.ConvoView) {
|
||||
this.convo = parseConvoView(convo, this.senderUserDid) ?? this.convo
|
||||
if (this.convo) {
|
||||
for (const member of this.convo.members) {
|
||||
this.relatedProfiles.set(member.did, member)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateConvo(convo: Partial<ChatBskyConvoDefs.ConvoView>) {
|
||||
@@ -517,6 +520,9 @@ export class Convo {
|
||||
this.convo =
|
||||
parseConvoView({...this.convo.view, ...convo}, this.senderUserDid) ??
|
||||
this.convo
|
||||
for (const member of this.convo.members) {
|
||||
this.relatedProfiles.set(member.did, member)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +710,7 @@ export class Convo {
|
||||
|
||||
if (relatedProfiles) {
|
||||
for (const profile of relatedProfiles) {
|
||||
this.systemMessageProfiles.set(profile.did, profile)
|
||||
this.relatedProfiles.set(profile.did, profile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,6 +830,12 @@ export class Convo {
|
||||
*/
|
||||
this.latestRev = ev.rev
|
||||
|
||||
if ('relatedProfiles' in ev && Array.isArray(ev.relatedProfiles)) {
|
||||
for (const profile of ev.relatedProfiles) {
|
||||
this.relatedProfiles.set(profile.did, profile)
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
ChatBskyConvoDefs.isLogCreateMessage(ev) &&
|
||||
ChatBskyConvoDefs.isMessageView(ev.message)
|
||||
@@ -876,14 +888,6 @@ export class Convo {
|
||||
const systemView = toSystemMessageView(ev)
|
||||
if (systemView) {
|
||||
this.newMessages.set(systemView.id, systemView)
|
||||
if (
|
||||
'relatedProfiles' in ev &&
|
||||
Array.isArray(ev.relatedProfiles)
|
||||
) {
|
||||
for (const profile of ev.relatedProfiles) {
|
||||
this.systemMessageProfiles.set(profile.did, profile)
|
||||
}
|
||||
}
|
||||
needsCommit = true
|
||||
}
|
||||
}
|
||||
@@ -1180,6 +1184,7 @@ export class Convo {
|
||||
type: 'message',
|
||||
key: m.id,
|
||||
message: m,
|
||||
relatedProfiles: this.relatedProfiles,
|
||||
nextMessage: null,
|
||||
prevMessage: null,
|
||||
})
|
||||
@@ -1188,6 +1193,7 @@ export class Convo {
|
||||
type: 'deleted-message',
|
||||
key: m.id,
|
||||
message: m,
|
||||
relatedProfiles: this.relatedProfiles,
|
||||
nextMessage: null,
|
||||
prevMessage: null,
|
||||
})
|
||||
@@ -1196,7 +1202,7 @@ export class Convo {
|
||||
type: 'system-message',
|
||||
key: m.id,
|
||||
message: m,
|
||||
relatedProfiles: Array.from(this.systemMessageProfiles.values()),
|
||||
relatedProfiles: this.relatedProfiles,
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1218,6 +1224,7 @@ export class Convo {
|
||||
type: 'message',
|
||||
key: m.id,
|
||||
message: m,
|
||||
relatedProfiles: this.relatedProfiles,
|
||||
nextMessage: null,
|
||||
prevMessage: null,
|
||||
})
|
||||
@@ -1226,6 +1233,7 @@ export class Convo {
|
||||
type: 'deleted-message',
|
||||
key: m.id,
|
||||
message: m,
|
||||
relatedProfiles: this.relatedProfiles,
|
||||
nextMessage: null,
|
||||
prevMessage: null,
|
||||
})
|
||||
@@ -1234,7 +1242,7 @@ export class Convo {
|
||||
type: 'system-message',
|
||||
key: m.id,
|
||||
message: m,
|
||||
relatedProfiles: Array.from(this.systemMessageProfiles.values()),
|
||||
relatedProfiles: this.relatedProfiles,
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1255,6 +1263,7 @@ export class Convo {
|
||||
did: this.senderUserDid,
|
||||
},
|
||||
},
|
||||
relatedProfiles: this.relatedProfiles,
|
||||
nextMessage: null,
|
||||
prevMessage: null,
|
||||
failed: this.pendingMessageFailure !== null,
|
||||
|
||||
@@ -59,34 +59,20 @@ export enum ConvoDispatchEvent {
|
||||
}
|
||||
|
||||
export type ConvoDispatch =
|
||||
| {
|
||||
event: ConvoDispatchEvent.Init
|
||||
}
|
||||
| {
|
||||
event: ConvoDispatchEvent.Ready
|
||||
}
|
||||
| {
|
||||
event: ConvoDispatchEvent.Resume
|
||||
}
|
||||
| {
|
||||
event: ConvoDispatchEvent.Background
|
||||
}
|
||||
| {
|
||||
event: ConvoDispatchEvent.Suspend
|
||||
}
|
||||
| {
|
||||
event: ConvoDispatchEvent.Error
|
||||
payload: ConvoError
|
||||
}
|
||||
| {
|
||||
event: ConvoDispatchEvent.Disable
|
||||
}
|
||||
| {event: ConvoDispatchEvent.Init}
|
||||
| {event: ConvoDispatchEvent.Ready}
|
||||
| {event: ConvoDispatchEvent.Resume}
|
||||
| {event: ConvoDispatchEvent.Background}
|
||||
| {event: ConvoDispatchEvent.Suspend}
|
||||
| {event: ConvoDispatchEvent.Error; payload: ConvoError}
|
||||
| {event: ConvoDispatchEvent.Disable}
|
||||
|
||||
export type ConvoItem =
|
||||
| {
|
||||
type: 'message'
|
||||
key: string
|
||||
message: ChatBskyConvoDefs.MessageView
|
||||
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
|
||||
nextMessage:
|
||||
| ChatBskyConvoDefs.MessageView
|
||||
| ChatBskyConvoDefs.DeletedMessageView
|
||||
@@ -100,6 +86,7 @@ export type ConvoItem =
|
||||
type: 'pending-message'
|
||||
key: string
|
||||
message: ChatBskyConvoDefs.MessageView
|
||||
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
|
||||
nextMessage:
|
||||
| ChatBskyConvoDefs.MessageView
|
||||
| ChatBskyConvoDefs.DeletedMessageView
|
||||
@@ -118,6 +105,7 @@ export type ConvoItem =
|
||||
type: 'deleted-message'
|
||||
key: string
|
||||
message: ChatBskyConvoDefs.DeletedMessageView
|
||||
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
|
||||
nextMessage:
|
||||
| ChatBskyConvoDefs.MessageView
|
||||
| ChatBskyConvoDefs.DeletedMessageView
|
||||
@@ -131,7 +119,7 @@ export type ConvoItem =
|
||||
type: 'system-message'
|
||||
key: string
|
||||
message: ChatBskyConvoDefs.SystemMessageView
|
||||
relatedProfiles: ChatBskyActorDefs.ProfileViewBasic[]
|
||||
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
|
||||
}
|
||||
| {
|
||||
type: 'error'
|
||||
|
||||
Reference in New Issue
Block a user