Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make convo menu lazy #7604

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
278 changes: 154 additions & 124 deletions src/components/dms/ConvoMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble'
import {ReportDialog} from './ReportDialog'

let ConvoMenu = ({
convo: initialConvo,
convo,
profile,
control,
currentScreen,
Expand All @@ -61,51 +61,14 @@ let ConvoMenu = ({
latestReportableMessage?: ChatBskyConvoDefs.MessageView
style?: ViewStyleProp['style']
}): React.ReactNode => {
const navigation = useNavigation<NavigationProp>()
const {_} = useLingui()
const t = useTheme()

const leaveConvoControl = Prompt.usePromptControl()
const reportControl = Prompt.usePromptControl()
const blockedByListControl = Prompt.usePromptControl()
const {mutate: markAsRead} = useMarkAsReadMutation()

const {listBlocks, userBlock} = blockInfo
const isBlocking = userBlock || !!listBlocks.length
const isDeletedAccount = profile.handle === 'missing.invalid'

const {data: convo} = useConvoQuery(initialConvo)

const onNavigateToProfile = useCallback(() => {
navigation.navigate('Profile', {name: profile.did})
}, [navigation, profile.did])

const {mutate: muteConvo} = useMuteConvo(convo?.id, {
onSuccess: data => {
if (data.convo.muted) {
Toast.show(_(msg`Chat muted`))
} else {
Toast.show(_(msg`Chat unmuted`))
}
},
onError: () => {
Toast.show(_(msg`Could not mute chat`), 'xmark')
},
})

const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)

const toggleBlock = React.useCallback(() => {
if (listBlocks.length) {
blockedByListControl.open()
return
}

if (userBlock) {
queueUnblock()
} else {
queueBlock()
}
}, [userBlock, listBlocks, blockedByListControl, queueBlock, queueUnblock])
const {listBlocks} = blockInfo

return (
<>
Expand All @@ -118,7 +81,6 @@ let ConvoMenu = ({
{...props}
onPress={() => {
Keyboard.dismiss()

props.onPress()
}}
style={[
Expand All @@ -135,89 +97,17 @@ let ConvoMenu = ({
</View>
)}

{isDeletedAccount ? (
<Menu.Outer>
<Menu.Item
label={_(msg`Leave conversation`)}
onPress={() => leaveConvoControl.open()}>
<Menu.ItemText>
<Trans>Leave conversation</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={ArrowBoxLeft} />
</Menu.Item>
</Menu.Outer>
) : (
<Menu.Outer>
<Menu.Group>
{showMarkAsRead && (
<Menu.Item
label={_(msg`Mark as read`)}
onPress={() =>
markAsRead({
convoId: convo?.id,
})
}>
<Menu.ItemText>
<Trans>Mark as read</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={Bubble} />
</Menu.Item>
)}
<Menu.Item
label={_(msg`Go to user's profile`)}
onPress={onNavigateToProfile}>
<Menu.ItemText>
<Trans>Go to profile</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={Person} />
</Menu.Item>
<Menu.Item
label={_(msg`Mute conversation`)}
onPress={() => muteConvo({mute: !convo?.muted})}>
<Menu.ItemText>
{convo?.muted ? (
<Trans>Unmute conversation</Trans>
) : (
<Trans>Mute conversation</Trans>
)}
</Menu.ItemText>
<Menu.ItemIcon icon={convo?.muted ? Unmute : Mute} />
</Menu.Item>
</Menu.Group>
<Menu.Divider />
<Menu.Group>
<Menu.Item
label={
isBlocking ? _(msg`Unblock account`) : _(msg`Block account`)
}
onPress={toggleBlock}>
<Menu.ItemText>
{isBlocking ? _(msg`Unblock account`) : _(msg`Block account`)}
</Menu.ItemText>
<Menu.ItemIcon icon={isBlocking ? PersonCheck : PersonX} />
</Menu.Item>
<Menu.Item
label={_(msg`Report conversation`)}
onPress={() => reportControl.open()}>
<Menu.ItemText>
<Trans>Report conversation</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={Flag} />
</Menu.Item>
</Menu.Group>
<Menu.Divider />
<Menu.Group>
<Menu.Item
label={_(msg`Leave conversation`)}
onPress={() => leaveConvoControl.open()}>
<Menu.ItemText>
<Trans>Leave conversation</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={ArrowBoxLeft} />
</Menu.Item>
</Menu.Group>
</Menu.Outer>
)}
<Menu.Outer>
<MenuContent
profile={profile}
showMarkAsRead={showMarkAsRead}
blockInfo={blockInfo}
convo={convo}
leaveConvoControl={leaveConvoControl}
reportControl={reportControl}
blockedByListControl={blockedByListControl}
/>
</Menu.Outer>
</Menu.Root>

<LeaveConvoPrompt
Expand Down Expand Up @@ -248,4 +138,144 @@ let ConvoMenu = ({
}
ConvoMenu = React.memo(ConvoMenu)

function MenuContent({
convo: initialConvo,
profile,
showMarkAsRead,
blockInfo,
leaveConvoControl,
reportControl,
blockedByListControl,
}: {
convo: ChatBskyConvoDefs.ConvoView
profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
showMarkAsRead?: boolean
blockInfo: {
listBlocks: ModerationCause[]
userBlock?: ModerationCause
}
leaveConvoControl: Prompt.PromptControlProps
reportControl: Prompt.PromptControlProps
blockedByListControl: Prompt.PromptControlProps
}) {
const navigation = useNavigation<NavigationProp>()
const {_} = useLingui()
const {mutate: markAsRead} = useMarkAsReadMutation()

const {listBlocks, userBlock} = blockInfo
const isBlocking = userBlock || !!listBlocks.length
const isDeletedAccount = profile.handle === 'missing.invalid'

const convoId = initialConvo.id
const {data: convo} = useConvoQuery(convoId, initialConvo)

const onNavigateToProfile = useCallback(() => {
navigation.navigate('Profile', {name: profile.did})
}, [navigation, profile.did])

const {mutate: muteConvo} = useMuteConvo(convoId, {
onSuccess: data => {
if (data.convo.muted) {
Toast.show(_(msg`Chat muted`))
} else {
Toast.show(_(msg`Chat unmuted`))
}
},
onError: () => {
Toast.show(_(msg`Could not mute chat`), 'xmark')
},
})

const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)

const toggleBlock = React.useCallback(() => {
if (listBlocks.length) {
blockedByListControl.open()
return
}

if (userBlock) {
queueUnblock()
} else {
queueBlock()
}
}, [userBlock, listBlocks, blockedByListControl, queueBlock, queueUnblock])

return isDeletedAccount ? (
<Menu.Item
label={_(msg`Leave conversation`)}
onPress={() => leaveConvoControl.open()}>
<Menu.ItemText>
<Trans>Leave conversation</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={ArrowBoxLeft} />
</Menu.Item>
) : (
<>
<Menu.Group>
{showMarkAsRead && (
<Menu.Item
label={_(msg`Mark as read`)}
onPress={() => markAsRead({convoId})}>
<Menu.ItemText>
<Trans>Mark as read</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={Bubble} />
</Menu.Item>
)}
<Menu.Item
label={_(msg`Go to user's profile`)}
onPress={onNavigateToProfile}>
<Menu.ItemText>
<Trans>Go to profile</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={Person} />
</Menu.Item>
<Menu.Item
label={_(msg`Mute conversation`)}
onPress={() => muteConvo({mute: !convo?.muted})}>
<Menu.ItemText>
{convo?.muted ? (
<Trans>Unmute conversation</Trans>
) : (
<Trans>Mute conversation</Trans>
)}
</Menu.ItemText>
<Menu.ItemIcon icon={convo?.muted ? Unmute : Mute} />
</Menu.Item>
</Menu.Group>
<Menu.Divider />
<Menu.Group>
<Menu.Item
label={isBlocking ? _(msg`Unblock account`) : _(msg`Block account`)}
onPress={toggleBlock}>
<Menu.ItemText>
{isBlocking ? _(msg`Unblock account`) : _(msg`Block account`)}
</Menu.ItemText>
<Menu.ItemIcon icon={isBlocking ? PersonCheck : PersonX} />
</Menu.Item>
<Menu.Item
label={_(msg`Report conversation`)}
onPress={() => reportControl.open()}>
<Menu.ItemText>
<Trans>Report conversation</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={Flag} />
</Menu.Item>
</Menu.Group>
<Menu.Divider />
<Menu.Group>
<Menu.Item
label={_(msg`Leave conversation`)}
onPress={() => leaveConvoControl.open()}>
<Menu.ItemText>
<Trans>Leave conversation</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={ArrowBoxLeft} />
</Menu.Item>
</Menu.Group>
</>
)
}

export {ConvoMenu}
21 changes: 14 additions & 7 deletions src/components/dms/MessagesListBlockedFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import {View} from 'react-native'
import {AppBskyActorDefs, ModerationCause} from '@atproto/api'
import {AppBskyActorDefs, ModerationDecision} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'

Expand All @@ -19,15 +19,12 @@ export function MessagesListBlockedFooter({
recipient: initialRecipient,
convoId,
hasMessages,
blockInfo,
moderation,
}: {
recipient: AppBskyActorDefs.ProfileViewBasic
convoId: string
hasMessages: boolean
blockInfo: {
listBlocks: ModerationCause[]
userBlock: ModerationCause | undefined
}
moderation: ModerationDecision
}) {
const t = useTheme()
const {gtMobile} = useBreakpoints()
Expand All @@ -39,7 +36,17 @@ export function MessagesListBlockedFooter({
const reportControl = useDialogControl()
const blockedByListControl = useDialogControl()

const {listBlocks, userBlock} = blockInfo
const {listBlocks, userBlock} = React.useMemo(() => {
const modui = moderation.ui('profileView')
const blocks = modui.alerts.filter(alert => alert.type === 'blocking')
const listBlocks = blocks.filter(alert => alert.source.type === 'list')
const userBlock = blocks.find(alert => alert.source.type === 'user')
return {
listBlocks,
userBlock,
}
}, [moderation])

const isBlocking = !!userBlock || !!listBlocks.length

const onUnblockPress = React.useCallback(() => {
Expand Down
17 changes: 12 additions & 5 deletions src/components/dms/MessagesListHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,27 @@ const PFP_SIZE = isWeb ? 40 : 34
export let MessagesListHeader = ({
profile,
moderation,
blockInfo,
}: {
profile?: AppBskyActorDefs.ProfileViewBasic
moderation?: ModerationDecision
blockInfo?: {
listBlocks: ModerationCause[]
userBlock?: ModerationCause
}
}): React.ReactNode => {
const t = useTheme()
const {_} = useLingui()
const {gtTablet} = useBreakpoints()
const navigation = useNavigation<NavigationProp>()

const blockInfo = React.useMemo(() => {
if (!moderation) return
const modui = moderation.ui('profileView')
const blocks = modui.alerts.filter(alert => alert.type === 'blocking')
const listBlocks = blocks.filter(alert => alert.source.type === 'list')
const userBlock = blocks.find(alert => alert.source.type === 'user')
return {
listBlocks,
userBlock,
}
}, [moderation])

const onPressBack = useCallback(() => {
if (isWeb) {
navigation.replace('Messages', {})
Expand Down
Loading
Loading