Make settings account buttons a little nicer (#4980)

* Replace account dropdown with Menu

* Replace card row and add interaction state

* Remove testID copy pasta

* Sanitize handle

* Remove hover from row
zio/stable
Eric Bailey 2024-08-22 20:09:55 -05:00 committed by GitHub
parent 990bf306c5
commit 5ec8761b29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 83 additions and 66 deletions

View File

@ -1,53 +1,59 @@
import React from 'react' import React from 'react'
import {Pressable} from 'react-native' import {msg, Trans} from '@lingui/macro'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {SessionAccount, useSessionApi} from '#/state/session' import {SessionAccount, useSessionApi} from '#/state/session'
import {usePalette} from 'lib/hooks/usePalette' import {HITSLOP_10} from 'lib/constants'
import {s} from 'lib/styles' import {Button, ButtonIcon} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {DotGrid_Stroke2_Corner0_Rounded as Ellipsis} from '#/components/icons/DotGrid'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import * as Menu from '#/components/Menu'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import * as Toast from '../../com/util/Toast' import * as Toast from '../../com/util/Toast'
import {DropdownItem, NativeDropdown} from './forms/NativeDropdown'
export function AccountDropdownBtn({account}: {account: SessionAccount}) { export function AccountDropdownBtn({account}: {account: SessionAccount}) {
const pal = usePalette('default') const {_} = useLingui()
const {removeAccount} = useSessionApi() const {removeAccount} = useSessionApi()
const removePromptControl = useDialogControl() const removePromptControl = useDialogControl()
const {_} = useLingui()
const items: DropdownItem[] = [
{
label: _(msg`Remove account`),
onPress: removePromptControl.open,
icon: {
ios: {
name: 'trash',
},
android: 'ic_delete',
web: ['far', 'trash-can'],
},
},
]
return ( return (
<> <>
<Pressable accessibilityRole="button" style={s.pl10}> <Menu.Root>
<NativeDropdown <Menu.Trigger label={_(`Account options`)}>
testID="accountSettingsDropdownBtn" {({props}) => {
items={items} return (
accessibilityLabel={_(msg`Account options`)} <Button
accessibilityHint=""> {...props}
<FontAwesomeIcon testID="accountSettingsDropdownBtn"
icon="ellipsis-h" label={_(`Account options`)}
style={pal.textLight as FontAwesomeIconStyle} hitSlop={HITSLOP_10}
/> size="xsmall"
</NativeDropdown> shape="round"
</Pressable> color="secondary"
variant="ghost">
<ButtonIcon icon={Ellipsis} size="sm" />
</Button>
)
}}
</Menu.Trigger>
<Menu.Outer style={{minWidth: 170}}>
<Menu.Group>
<Menu.Item
label={_(msg`Remove account`)}
onPress={() => {
removePromptControl.open()
}}>
<Menu.ItemText>
<Trans>Remove account</Trans>
</Menu.ItemText>
<Menu.ItemIcon icon={Trash} />
</Menu.Item>
</Menu.Group>
</Menu.Outer>
</Menu.Root>
<Prompt.Basic <Prompt.Basic
control={removePromptControl} control={removePromptControl}
title={_(msg`Remove from quick access?`)} title={_(msg`Remove from quick access?`)}

View File

@ -18,6 +18,7 @@ import {useLingui} from '@lingui/react'
import {useFocusEffect, useNavigation} from '@react-navigation/native' import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {sanitizeHandle} from '#/lib/strings/handles'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {clearStorage} from '#/state/persisted' import {clearStorage} from '#/state/persisted'
@ -55,8 +56,11 @@ import {UserAvatar} from 'view/com/util/UserAvatar'
import {ScrollView} from 'view/com/util/Views' import {ScrollView} from 'view/com/util/Views'
import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateAccountDialog' import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateAccountDialog'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonContext} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
import {Link as NewLink} from '#/components/Link'
import {Text as NewText} from '#/components/Typography'
import {Email2FAToggle} from './Email2FAToggle' import {Email2FAToggle} from './Email2FAToggle'
import {ExportCarDialog} from './ExportCarDialog' import {ExportCarDialog} from './ExportCarDialog'
@ -72,62 +76,69 @@ function SettingsAccountCard({
logContext: 'Settings', logContext: 'Settings',
) => void ) => void
}) { }) {
const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const t = useTheme() const t = useTheme()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const {data: profile} = useProfileQuery({did: account.did}) const {data: profile} = useProfileQuery({did: account.did})
const isCurrentAccount = account.did === currentAccount?.did const isCurrentAccount = account.did === currentAccount?.did
const contents = ( const contents = (ctx: ButtonContext) => (
<View <View
style={[ style={[
pal.view, a.w_full,
styles.linkCard, a.flex_row,
account.did === pendingDid && t.atoms.bg_contrast_25, a.align_center,
a.gap_md,
a.py_md,
t.atoms.bg,
{
paddingHorizontal: 18,
marginBottom: 1,
},
account.did === pendingDid && [t.atoms.bg_contrast_25],
ctx.pressed && [t.atoms.bg_contrast_25],
]}> ]}>
<View style={styles.avi}> <UserAvatar
<UserAvatar size={40}
size={40} avatar={profile?.avatar}
avatar={profile?.avatar} type={profile?.associated?.labeler ? 'labeler' : 'user'}
type={profile?.associated?.labeler ? 'labeler' : 'user'} />
/> <View style={[a.flex_1]}>
</View> <NewText
<View style={[s.flex1]}> style={[a.text_md, a.font_bold, a.leading_tight]}
<Text type="md-bold" style={[pal.text, a.self_start]} numberOfLines={1}> numberOfLines={1}>
{profile?.displayName || account.handle} {profile?.displayName || account.handle}
</Text> </NewText>
<Text type="sm" style={pal.textLight} numberOfLines={1}> <NewText
{account.handle} style={[t.atoms.text_contrast_medium, a.leading_tight]}
</Text> numberOfLines={1}>
{sanitizeHandle(account.handle, '@')}
</NewText>
</View> </View>
<AccountDropdownBtn account={account} /> <AccountDropdownBtn account={account} />
</View> </View>
) )
return isCurrentAccount ? ( return isCurrentAccount ? (
<Link <NewLink
href={makeProfileLink({ to={makeProfileLink({
did: currentAccount?.did, did: currentAccount?.did,
handle: currentAccount?.handle, handle: currentAccount?.handle,
})} })}
title={_(msg`Your profile`)} label={_(msg`Your profile`)}
noFeedback> style={[a.w_full]}>
{contents} {contents}
</Link> </NewLink>
) : ( ) : (
<TouchableOpacity <Button
testID={`switchToAccountBtn-${account.handle}`} testID={`switchToAccountBtn-${account.handle}`}
key={account.did}
onPress={ onPress={
pendingDid ? undefined : () => onPressSwitchAccount(account, 'Settings') pendingDid ? undefined : () => onPressSwitchAccount(account, 'Settings')
} }
accessibilityRole="button" label={_(msg`Switch to ${account.handle}`)}
accessibilityLabel={_(msg`Switch to ${account.handle}`)} style={[a.w_full]}>
accessibilityHint={_(msg`Switches the account you are logged in to`)}
activeOpacity={0.8}>
{contents} {contents}
</TouchableOpacity> </Button>
) )
} }