diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx
index 3f7694a342..9178652457 100644
--- a/src/components/dms/MessagesListHeader.tsx
+++ b/src/components/dms/MessagesListHeader.tsx
@@ -5,18 +5,19 @@ import {
type ModerationCause,
type ModerationDecision,
} from '@atproto/api'
-import {msg} from '@lingui/core/macro'
-import {useLingui} from '@lingui/react'
+import {useLingui} from '@lingui/react/macro'
import {makeProfileLink} from '#/lib/routes/links'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {type Shadow} from '#/state/cache/profile-shadow'
import {isConvoActive, useConvo} from '#/state/messages/convo'
import {type ConvoItem} from '#/state/messages/convo/types'
+import {useSession} from '#/state/session'
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
-import {atoms as a, useTheme, web} from '#/alf'
+import {atoms as a, useTheme} from '#/alf'
+import {AvatarBubbles} from '#/components/AvatarBubbles'
import {ConvoMenu} from '#/components/dms/ConvoMenu'
-import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2'
+import {Bell2Off_Filled_Corner0_Rounded as BellOffIcon} from '#/components/icons/Bell2'
import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link'
import {PostAlerts} from '#/components/moderation/PostAlerts'
@@ -34,6 +35,7 @@ export function MessagesListHeader({
moderation?: ModerationDecision
}) {
const t = useTheme()
+ const convoState = useConvo()
const blockInfo = useMemo(() => {
if (!moderation) return
@@ -78,13 +80,15 @@ export function MessagesListHeader({
a.mt_xs,
]}
/>
-
+ {!convoState.isGroup?.() && (
+
+ )}
@@ -108,22 +112,28 @@ function HeaderReady({
userBlock?: ModerationCause
}
}) {
- const {_} = useLingui()
+ const {t: l} = useLingui()
const t = useTheme()
const convoState = useConvo()
+ const {currentAccount} = useSession()
+
+ const groupInfo = convoState.getGroupInfo?.()
+ const isGroupChat = groupInfo != null
const isDeletedAccount = profile?.handle === 'missing.invalid'
- const displayName = isDeletedAccount
- ? _(msg`Deleted Account`)
- : sanitizeDisplayName(
- profile.displayName || profile.handle,
- moderation.ui('displayName'),
- )
+ const displayName = isGroupChat
+ ? (groupInfo.name ?? l`${profile.handle}'s group chat`)
+ : isDeletedAccount
+ ? l`Deleted Account`
+ : sanitizeDisplayName(
+ profile.displayName || profile.handle,
+ moderation.ui('displayName'),
+ )
- // @ts-ignore findLast is polyfilled - esb
const latestMessageFromOther = convoState.items.findLast(
(item: ConvoItem) =>
- item.type === 'message' && item.message.sender.did === profile.did,
+ item.type === 'message' &&
+ item.message.sender.did !== currentAccount?.did,
)
const latestReportableMessage =
@@ -134,54 +144,58 @@ function HeaderReady({
return (
-
-
-
-
-
- {displayName}
-
-
-
- {!isDeletedAccount && (
-
- @{profile.handle}
- {convoState.convo?.muted && (
- <>
- {' '}
- ·{' '}
-
- >
- )}
-
- )}
+ {isGroupChat ? (
+
+
+
+ {displayName}
+
-
+ ) : (
+
+
+
+
+
+ {displayName}
+
+
+
+ {!isDeletedAccount && (
+
+ @{profile.handle}
+ {convoState.convo?.muted && (
+ <>
+ {' '}
+ ·{' '}
+
+ >
+ )}
+
+ )}
+
+
+ )}
diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx
index 509907b331..9582386a96 100644
--- a/src/screens/Messages/Conversation.tsx
+++ b/src/screens/Messages/Conversation.tsx
@@ -101,7 +101,7 @@ function Inner() {
const moderationOpts = useModerationOpts()
const {data: recipientUnshadowed} = useProfileQuery({
- did: convoState.recipients?.[0].did,
+ did: convoState.getPrimaryMember?.()?.did,
})
const recipient = useMaybeProfileShadow(recipientUnshadowed)
@@ -135,7 +135,7 @@ function Inner() {
<>
{moderation ? (
-
+
) : (
)}
@@ -156,7 +156,7 @@ function Inner() {
{isFocused && IS_WEB && }
{!readyToShow &&
(moderation ? (
-
+
) : (
))}
diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts
index 93726833f1..4e0530b050 100644
--- a/src/state/messages/convo/agent.ts
+++ b/src/state/messages/convo/agent.ts
@@ -37,6 +37,7 @@ import {
import {type MessagesEventBus} from '#/state/messages/events/agent'
import {type MessagesEventBusError} from '#/state/messages/events/types'
import {IS_NATIVE} from '#/env'
+import * as bsky from '#/types/bsky'
const logger = Logger.create(Logger.Context.ConversationAgent)
@@ -112,6 +113,9 @@ export class Convo {
this.markConvoAccepted = this.markConvoAccepted.bind(this)
this.addReaction = this.addReaction.bind(this)
this.removeReaction = this.removeReaction.bind(this)
+ this.isGroup = this.isGroup.bind(this)
+ this.getGroupInfo = this.getGroupInfo.bind(this)
+ this.getPrimaryMember = this.getPrimaryMember.bind(this)
}
private commit() {
@@ -155,6 +159,9 @@ export class Convo {
markConvoAccepted: undefined,
addReaction: undefined,
removeReaction: undefined,
+ isGroup: this.isGroup,
+ getGroupInfo: this.getGroupInfo,
+ getPrimaryMember: this.getPrimaryMember,
}
}
case ConvoStatus.Disabled:
@@ -175,6 +182,9 @@ export class Convo {
markConvoAccepted: this.markConvoAccepted,
addReaction: this.addReaction,
removeReaction: this.removeReaction,
+ isGroup: this.isGroup,
+ getGroupInfo: this.getGroupInfo,
+ getPrimaryMember: this.getPrimaryMember,
}
}
case ConvoStatus.Error: {
@@ -192,6 +202,9 @@ export class Convo {
markConvoAccepted: undefined,
addReaction: undefined,
removeReaction: undefined,
+ isGroup: undefined,
+ getGroupInfo: undefined,
+ getPrimaryMember: undefined,
}
}
default: {
@@ -209,6 +222,9 @@ export class Convo {
markConvoAccepted: undefined,
addReaction: undefined,
removeReaction: undefined,
+ isGroup: this.isGroup,
+ getGroupInfo: this.getGroupInfo,
+ getPrimaryMember: this.getPrimaryMember,
}
}
}
@@ -1332,4 +1348,34 @@ export class Convo {
throw error
}
}
+
+ // Group utilities
+
+ isGroup(): boolean | undefined {
+ if (!this.convo) return undefined
+ return this.convo.kind === 'group'
+ }
+
+ getGroupInfo(): ChatBskyConvoDefs.GroupConvoData | undefined {
+ if (
+ this.convo &&
+ bsky.dangerousIsType(
+ this.convo.kindData,
+ ChatBskyConvoDefs.isGroupConvoData,
+ )
+ ) {
+ return this.convo.kindData
+ }
+ return undefined
+ }
+
+ getPrimaryMember(): ChatBskyActorDefs.ProfileViewBasic | undefined {
+ if (this.convo?.kind === 'group') {
+ return (
+ this.recipients?.find(r => r.role === 'owner') ?? this.recipients?.[0]
+ )
+ } else {
+ return this.recipients?.find(r => r.did !== this.senderUserDid)
+ }
+ }
}
diff --git a/src/state/messages/convo/types.ts b/src/state/messages/convo/types.ts
index 7053877935..3ea9443543 100644
--- a/src/state/messages/convo/types.ts
+++ b/src/state/messages/convo/types.ts
@@ -144,6 +144,9 @@ type FetchMessageHistory = () => Promise
type MarkConvoAccepted = () => void
type AddReaction = (messageId: string, reaction: string) => Promise
type RemoveReaction = (messageId: string, reaction: string) => Promise
+type IsGroup = () => boolean | undefined
+type GetGroupInfo = () => ChatBskyConvoDefs.GroupConvoData | undefined
+type GetPrimaryMember = () => ChatBskyActorDefs.ProfileViewBasic | undefined
export type ConvoStateUninitialized = {
status: ConvoStatus.Uninitialized
@@ -159,6 +162,9 @@ export type ConvoStateUninitialized = {
markConvoAccepted: undefined
addReaction: undefined
removeReaction: undefined
+ isGroup: IsGroup
+ getGroupInfo: GetGroupInfo
+ getPrimaryMember: GetPrimaryMember
}
export type ConvoStateInitializing = {
status: ConvoStatus.Initializing
@@ -174,6 +180,9 @@ export type ConvoStateInitializing = {
markConvoAccepted: undefined
addReaction: undefined
removeReaction: undefined
+ isGroup: IsGroup
+ getGroupInfo: GetGroupInfo
+ getPrimaryMember: GetPrimaryMember
}
export type ConvoStateReady = {
status: ConvoStatus.Ready
@@ -189,6 +198,9 @@ export type ConvoStateReady = {
markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction
removeReaction: RemoveReaction
+ isGroup: IsGroup
+ getGroupInfo: GetGroupInfo
+ getPrimaryMember: GetPrimaryMember
}
export type ConvoStateBackgrounded = {
status: ConvoStatus.Backgrounded
@@ -204,6 +216,9 @@ export type ConvoStateBackgrounded = {
markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction
removeReaction: RemoveReaction
+ isGroup: IsGroup
+ getGroupInfo: GetGroupInfo
+ getPrimaryMember: GetPrimaryMember
}
export type ConvoStateSuspended = {
status: ConvoStatus.Suspended
@@ -219,6 +234,9 @@ export type ConvoStateSuspended = {
markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction
removeReaction: RemoveReaction
+ isGroup: IsGroup
+ getGroupInfo: GetGroupInfo
+ getPrimaryMember: GetPrimaryMember
}
export type ConvoStateError = {
status: ConvoStatus.Error
@@ -234,6 +252,9 @@ export type ConvoStateError = {
markConvoAccepted: undefined
addReaction: undefined
removeReaction: undefined
+ isGroup: undefined
+ getGroupInfo: undefined
+ getPrimaryMember: undefined
}
export type ConvoStateDisabled = {
status: ConvoStatus.Disabled
@@ -249,6 +270,9 @@ export type ConvoStateDisabled = {
markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction
removeReaction: RemoveReaction
+ isGroup: IsGroup
+ getGroupInfo: GetGroupInfo
+ getPrimaryMember: GetPrimaryMember
}
export type ConvoState =
| ConvoStateUninitialized