diff --git a/src/screens/Messages/components/ChatListItem.tsx b/src/screens/Messages/components/ChatListItem.tsx index 11c071082b..2ed247e4e6 100644 --- a/src/screens/Messages/components/ChatListItem.tsx +++ b/src/screens/Messages/components/ChatListItem.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useState} from 'react' +import React, {useCallback, useMemo, useState} from 'react' import {GestureResponderEvent, View} from 'react-native' import { AppBskyActorDefs, @@ -27,12 +27,15 @@ import {TimeElapsed} from '#/view/com/util/TimeElapsed' import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' import * as tokens from '#/alf/tokens' +import {useDialogControl} from '#/components/Dialog' import {ConvoMenu} from '#/components/dms/ConvoMenu' +import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt' import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2' import {Link} from '#/components/Link' import {useMenuControl} from '#/components/Menu' import {PostAlerts} from '#/components/moderation/PostAlerts' import {Text} from '#/components/Typography' +import {SwipeableRow} from './SwipeableRow' export let ChatListItem = ({ convo, @@ -74,6 +77,7 @@ function ChatListItemReady({ const {_} = useLingui() const {currentAccount} = useSession() const menuControl = useMenuControl() + const leaveConvoControl = useDialogControl() const {gtMobile} = useBreakpoints() const profile = useProfileShadow(profileUnshadowed) const moderation = React.useMemo( @@ -82,7 +86,7 @@ function ChatListItemReady({ ) const playHaptic = useHaptics() - const blockInfo = React.useMemo(() => { + const blockInfo = useMemo(() => { const modui = moderation.ui('profileView') const blocks = modui.alerts.filter(alert => alert.type === 'blocking') const listBlocks = blocks.filter(alert => alert.source.type === 'list') @@ -103,7 +107,7 @@ function ChatListItemReady({ const isDimStyle = convo.muted || moderation.blocked || isDeletedAccount - const {lastMessage, lastMessageSentAt} = React.useMemo(() => { + const {lastMessage, lastMessageSentAt} = useMemo(() => { let lastMessage = _(msg`No messages yet`) let lastMessageSentAt: string | null = null @@ -197,182 +201,190 @@ function ChatListItemReady({ }, [playHaptic, menuControl]) return ( - + - - + // @ts-expect-error web only + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} + onFocus={onFocus} + onBlur={onMouseLeave} + style={[a.relative, t.atoms.bg]}> + + + - - {({hovered, pressed, focused}) => ( - - {/* Avatar goes here */} - + + {({hovered, pressed, focused}) => ( + + {/* Avatar goes here */} + + + + + + + {displayName} + + + {lastMessageSentAt && ( + + {({timeElapsed}) => ( + + {' '} + · {timeElapsed} + + )} + + )} + {(convo.muted || moderation.blocked) && ( + + {' '} + ·{' '} + + + )} + + + {!isDeletedAccount && ( + + @{profile.handle} + + )} - - - - {displayName} - + emoji + numberOfLines={2} + style={[ + a.text_sm, + a.leading_snug, + convo.unreadCount > 0 + ? a.font_bold + : t.atoms.text_contrast_high, + isDimStyle && t.atoms.text_contrast_medium, + ]}> + {lastMessage} - {lastMessageSentAt && ( - - {({timeElapsed}) => ( - - {' '} - · {timeElapsed} - - )} - - )} - {(convo.muted || moderation.blocked) && ( - - {' '} - ·{' '} - - - )} + + - {!isDeletedAccount && ( - - @{profile.handle} - + {convo.unreadCount > 0 && ( + )} - - 0 - ? a.font_bold - : t.atoms.text_contrast_high, - isDimStyle && t.atoms.text_contrast_medium, - ]}> - {lastMessage} - - - + )} + - {convo.unreadCount > 0 && ( - - )} - - )} - - - 0} - hideTrigger={isNative} - blockInfo={blockInfo} - style={[ - a.absolute, - a.h_full, - a.self_end, - a.justify_center, - { - right: tokens.space.lg, - opacity: !gtMobile || showActions || menuControl.isOpen ? 1 : 0, - }, - ]} - /> - + 0} + hideTrigger={isNative} + blockInfo={blockInfo} + style={[ + a.absolute, + a.h_full, + a.self_end, + a.justify_center, + { + right: tokens.space.lg, + opacity: !gtMobile || showActions || menuControl.isOpen ? 1 : 0, + }, + ]} + /> + + + ) } diff --git a/src/screens/Messages/components/SwipeableRow.tsx b/src/screens/Messages/components/SwipeableRow.tsx new file mode 100644 index 0000000000..b3faea9e20 --- /dev/null +++ b/src/screens/Messages/components/SwipeableRow.tsx @@ -0,0 +1,45 @@ +import React, {useCallback} from 'react' +import {View} from 'react-native' +// TODO: replace with ReanimatedSwipeable when we next upgrade RNGH -sfn +import Swipeable from 'react-native-gesture-handler/Swipeable' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {atoms as a, useTheme} from '#/alf' +import {Button} from '#/components/Button' +import {Trash_Stroke2_Corner2_Rounded as TrashIcon} from '#/components/icons/Trash' + +export function SwipeableRow({ + children, + onDelete, +}: { + children: React.ReactNode + onDelete: () => void +}) { + const {_} = useLingui() + const t = useTheme() + + const renderActions = useCallback(() => { + return ( + + ) + }, [_, t, onDelete]) + + return ( + + {children} + + ) +} diff --git a/src/screens/Messages/components/SwipeableRow.web.tsx b/src/screens/Messages/components/SwipeableRow.web.tsx new file mode 100644 index 0000000000..5464fbba41 --- /dev/null +++ b/src/screens/Messages/components/SwipeableRow.web.tsx @@ -0,0 +1 @@ +export {View as SwipeableRow} from 'react-native'