Enable access for group clip clops with no messages (#10276)

This commit is contained in:
DS Boyce
2026-04-17 10:40:37 -07:00
committed by GitHub
parent 226a321a27
commit 9e9ff70682
2 changed files with 157 additions and 110 deletions
+141 -92
View File
@@ -13,7 +13,11 @@ import {makeProfileLink} from '#/lib/routes/links'
import {type NavigationProp} from '#/lib/routes/types'
import {logger} from '#/logger'
import {type Shadow} from '#/state/cache/profile-shadow'
import {isConvoActive, useConvo} from '#/state/messages/convo'
import {
type ActiveConvoStates,
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'
@@ -36,10 +40,13 @@ export function MessagesListHeader({
moderation,
}: {
profile?: Shadow<AppBskyActorDefs.ProfileViewDetailed>
moderation?: ModerationDecision
moderation?: ModerationDecision | null
}) {
const t = useTheme()
const convoState = useConvo()
const isGroupChat = convoState?.isGroup?.()
const blockInfo = useMemo(() => {
if (!moderation) return
const modui = moderation.ui('profileView')
@@ -58,12 +65,21 @@ export function MessagesListHeader({
<View style={[{minHeight: PFP_SIZE}, a.justify_center]}>
<Layout.Header.BackButton />
</View>
{profile && moderation && blockInfo ? (
<HeaderReady
profile={profile}
moderation={moderation}
blockInfo={blockInfo}
/>
{isConvoActive(convoState) ? (
moderation && blockInfo && profile && !isGroupChat ? (
<ProfileHeaderReady
convoState={convoState}
profile={profile}
moderation={moderation}
blockInfo={blockInfo}
/>
) : (
<GroupHeaderReady
convoState={convoState}
profile={profile}
moderation={moderation}
/>
)
) : (
<>
<View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}>
@@ -94,11 +110,13 @@ export function MessagesListHeader({
)
}
function HeaderReady({
function ProfileHeaderReady({
convoState,
profile,
moderation,
blockInfo,
}: {
convoState: ActiveConvoStates
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
moderation: ModerationDecision
blockInfo: {
@@ -107,21 +125,12 @@ function HeaderReady({
}
}) {
const {t: l} = useLingui()
const t = useTheme()
const convoState = useConvo()
const {currentAccount} = useSession()
const navigation = useNavigation<NavigationProp>()
const groupInfo = convoState.getGroupInfo?.()
const isGroupChat = groupInfo != null
const isDeletedAccount = profile?.handle === 'missing.invalid'
const displayName = isGroupChat
? (groupInfo.name ?? l`${profile.handle}'s group chat`)
: isDeletedAccount
? l`Deleted Account`
: createSanitizedDisplayName(profile, true, moderation.ui('displayName'))
const displayName = isDeletedAccount
? l`Deleted Account`
: createSanitizedDisplayName(profile, true, moderation.ui('displayName'))
const latestMessageFromOther = convoState.items.findLast(
(item: ConvoItem) =>
@@ -134,6 +143,63 @@ function HeaderReady({
? latestMessageFromOther.message
: undefined
return (
<Wrapper
heading={
<Link
label={l`View ${displayName}s profile`}
style={[a.flex_row, a.gap_md, a.flex_1, a.pr_md]}
to={makeProfileLink(profile)}>
<PreviewableUserAvatar
size={PFP_SIZE}
profile={profile}
moderation={moderation.ui('avatar')}
disableHoverCard={moderation.blocked}
/>
<ProfileBadges profile={profile} size="md" style={[a.pl_xs]} />
</Link>
}
muted={convoState.convo?.muted}
settings={
isConvoActive(convoState) ? (
<ConvoMenu
convo={convoState.convo}
profile={profile}
currentScreen="conversation"
blockInfo={blockInfo}
latestReportableMessage={latestReportableMessage}
/>
) : null
}
/>
)
}
function GroupHeaderReady({
convoState,
profile,
moderation,
}: {
convoState: ActiveConvoStates
profile?: Shadow<AppBskyActorDefs.ProfileViewDetailed>
moderation?: ModerationDecision | null
}) {
const {t: l} = useLingui()
const navigation = useNavigation<NavigationProp>()
const groupInfo = convoState.getGroupInfo?.()
const isDeletedAccount = profile?.handle === 'missing.invalid'
const displayName = isDeletedAccount
? l`Deleted Account`
: profile
? createSanitizedDisplayName(profile, true, moderation?.ui('displayName'))
: undefined
const groupName =
groupInfo?.name ??
(displayName ? l`${displayName}s group chat` : l`Group chat`)
const handleNavigateToSettings = () => {
const convoId = convoState.convo?.id
if (convoId) {
@@ -145,84 +211,67 @@ function HeaderReady({
}
}
return (
<Wrapper
heading={
<>
<AvatarBubbles size="small" profiles={convoState.recipients ?? []} />
<Text style={[a.text_md, a.font_semi_bold]} numberOfLines={1}>
{groupName}
</Text>
</>
}
muted={convoState.convo?.muted}
settings={
isConvoActive(convoState) ? (
<Button
label={l`Open group chat settings`}
size="small"
color="secondary"
shape="round"
variant="ghost"
style={[a.bg_transparent]}
onPress={handleNavigateToSettings}>
<ButtonIcon icon={DotsHorizontalIcon} size="md" />
</Button>
) : null
}
/>
)
}
function Wrapper({
heading,
muted,
settings,
}: {
heading: React.ReactNode
muted: boolean
settings: React.ReactNode
}) {
return (
<View style={[a.flex_1]}>
<View style={[a.w_full, a.flex_row, a.align_center, a.justify_between]}>
{isGroupChat ? (
<View
style={[a.flex_row, a.align_center, a.gap_md, a.flex_1, a.pr_md]}>
<AvatarBubbles
size="small"
profiles={convoState.recipients ?? []}
/>
<Text style={[a.text_md, a.font_semi_bold]} numberOfLines={1}>
{displayName}
</Text>
</View>
) : (
<Link
label={l`View ${displayName}'s profile`}
style={[a.flex_row, a.gap_md, a.flex_1, a.pr_md]}
to={makeProfileLink(profile)}>
<PreviewableUserAvatar
size={PFP_SIZE}
profile={profile}
moderation={moderation.ui('avatar')}
disableHoverCard={moderation.blocked}
/>
<View style={[a.flex_1]}>
<View style={[a.flex_row, a.align_center]}>
<Text
emoji
style={[a.text_md, a.font_semi_bold, a.self_start]}
numberOfLines={1}>
{displayName}
</Text>
<ProfileBadges profile={profile} size="md" style={[a.pl_xs]} />
{convoState.convo?.muted && (
<>
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
{' '}
&middot;{' '}
</Text>
<BellOffIcon
size="sm"
style={t.atoms.text_contrast_medium}
/>
</>
)}
</View>
</View>
</Link>
)}
<View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1, a.pr_md]}>
{heading}
<MuteStatus muted={muted} />
</View>
<View style={[{minHeight: PFP_SIZE}, a.justify_center]}>
<Layout.Header.Slot>
{isConvoActive(convoState) ? (
isGroupChat ? (
<Button
label={l`Open group chat settings`}
size="small"
color="secondary"
shape="round"
variant="ghost"
style={[a.bg_transparent]}
onPress={handleNavigateToSettings}>
<ButtonIcon icon={DotsHorizontalIcon} size="md" />
</Button>
) : (
<ConvoMenu
convo={convoState.convo}
profile={profile}
currentScreen="conversation"
blockInfo={blockInfo}
latestReportableMessage={latestReportableMessage}
/>
)
) : null}
</Layout.Header.Slot>
<Layout.Header.Slot>{settings}</Layout.Header.Slot>
</View>
</View>
</View>
)
}
function MuteStatus({muted}: {muted: boolean}) {
const t = useTheme()
return muted ? (
<>
<Text style={[a.text_md, t.atoms.text_contrast_medium]}> &middot; </Text>
<BellOffIcon size="sm" style={t.atoms.text_contrast_medium} />
</>
) : undefined
}
+16 -18
View File
@@ -173,16 +173,12 @@ function Inner() {
</View>
)}
<View style={[a.flex_1]}>
{moderation && recipient ? (
<InnerReady
moderation={moderation}
recipient={recipient}
hasScrolled={hasScrolled}
setHasScrolled={setHasScrolled}
/>
) : (
<View style={[a.align_center, a.gap_sm, a.flex_1]} />
)}
<InnerReady
moderation={moderation}
recipient={recipient}
hasScrolled={hasScrolled}
setHasScrolled={setHasScrolled}
/>
{!readyToShow && (
<View
style={[
@@ -210,8 +206,8 @@ function InnerReady({
hasScrolled,
setHasScrolled,
}: {
moderation: ModerationDecision
recipient: Shadow<AppBskyActorDefs.ProfileViewDetailed>
moderation: ModerationDecision | null
recipient: Shadow<AppBskyActorDefs.ProfileViewDetailed> | undefined
hasScrolled: boolean
setHasScrolled: React.Dispatch<React.SetStateAction<boolean>>
}) {
@@ -289,12 +285,14 @@ function InnerReady({
hasAcceptOverride={!!params.accept}
transparentHeaderHeight={IS_LIQUID_GLASS ? headerHeight : 0}
footer={
<MessagesListBlockedFooter
recipient={recipient}
convoId={convoState.convo.id}
hasMessages={convoState.items.length > 0}
moderation={moderation}
/>
moderation && recipient ? (
<MessagesListBlockedFooter
recipient={recipient}
convoId={convoState.convo.id}
hasMessages={convoState.items.length > 0}
moderation={moderation}
/>
) : null
}
/>
)}