Account quick switch modal (#1567)
* quick switch menu * Some small tweaks and fixes to the account switch modal * Factor out the account switcher logic to a hook * Add haptic feedback on account switcher open * Fix bad merge --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
parent
3e340b336e
commit
2e5f73ff61
9 changed files with 243 additions and 59 deletions
|
@ -32,6 +32,7 @@ import * as ModerationDetailsModal from './ModerationDetails'
|
|||
import * as BirthDateSettingsModal from './BirthDateSettings'
|
||||
import * as VerifyEmailModal from './VerifyEmail'
|
||||
import * as ChangeEmailModal from './ChangeEmail'
|
||||
import * as SwitchAccountModal from './SwitchAccount'
|
||||
|
||||
const DEFAULT_SNAPPOINTS = ['90%']
|
||||
|
||||
|
@ -144,6 +145,9 @@ export const ModalsContainer = observer(function ModalsContainer() {
|
|||
} else if (activeModal?.name === 'change-email') {
|
||||
snapPoints = ChangeEmailModal.snapPoints
|
||||
element = <ChangeEmailModal.Component />
|
||||
} else if (activeModal?.name === 'switch-account') {
|
||||
snapPoints = SwitchAccountModal.snapPoints
|
||||
element = <SwitchAccountModal.Component />
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
|
136
src/view/com/modals/SwitchAccount.tsx
Normal file
136
src/view/com/modals/SwitchAccount.tsx
Normal file
|
@ -0,0 +1,136 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {useStores} from 'state/index'
|
||||
import {s} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {useAccountSwitcher} from 'lib/hooks/useAccountSwitcher'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
import {AccountDropdownBtn} from '../util/AccountDropdownBtn'
|
||||
import {Link} from '../util/Link'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {BottomSheetScrollView} from '@gorhom/bottom-sheet'
|
||||
import {Haptics} from 'lib/haptics'
|
||||
|
||||
export const snapPoints = ['40%', '90%']
|
||||
|
||||
export function Component({}: {}) {
|
||||
const pal = usePalette('default')
|
||||
const {track} = useAnalytics()
|
||||
|
||||
const store = useStores()
|
||||
const [isSwitching, _, onPressSwitchAccount] = useAccountSwitcher()
|
||||
|
||||
React.useEffect(() => {
|
||||
Haptics.default()
|
||||
})
|
||||
|
||||
const onPressSignout = React.useCallback(() => {
|
||||
track('Settings:SignOutButtonClicked')
|
||||
store.session.logout()
|
||||
}, [track, store])
|
||||
|
||||
return (
|
||||
<View style={[styles.container, pal.view]}>
|
||||
<Text type="title-xl" style={[styles.title, pal.text]}>
|
||||
Switch Account
|
||||
</Text>
|
||||
<BottomSheetScrollView
|
||||
style={styles.container}
|
||||
contentContainerStyle={[styles.innerContainer, pal.view]}>
|
||||
{isSwitching ? (
|
||||
<View style={[pal.view, styles.linkCard]}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
) : (
|
||||
<Link
|
||||
href={makeProfileLink(store.me)}
|
||||
title="Your profile"
|
||||
noFeedback>
|
||||
<View style={[pal.view, styles.linkCard]}>
|
||||
<View style={styles.avi}>
|
||||
<UserAvatar size={40} avatar={store.me.avatar} />
|
||||
</View>
|
||||
<View style={[s.flex1]}>
|
||||
<Text type="md-bold" style={pal.text} numberOfLines={1}>
|
||||
{store.me.displayName || store.me.handle}
|
||||
</Text>
|
||||
<Text type="sm" style={pal.textLight} numberOfLines={1}>
|
||||
{store.me.handle}
|
||||
</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
testID="signOutBtn"
|
||||
onPress={isSwitching ? undefined : onPressSignout}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Sign out"
|
||||
accessibilityHint={`Signs ${store.me.displayName} out of Bluesky`}>
|
||||
<Text type="lg" style={pal.link}>
|
||||
Sign out
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</Link>
|
||||
)}
|
||||
{store.session.switchableAccounts.map(account => (
|
||||
<TouchableOpacity
|
||||
testID={`switchToAccountBtn-${account.handle}`}
|
||||
key={account.did}
|
||||
style={[pal.view, styles.linkCard, isSwitching && styles.dimmed]}
|
||||
onPress={
|
||||
isSwitching ? undefined : () => onPressSwitchAccount(account)
|
||||
}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`Switch to ${account.handle}`}
|
||||
accessibilityHint="Switches the account you are logged in to">
|
||||
<View style={styles.avi}>
|
||||
<UserAvatar size={40} avatar={account.aviUrl} />
|
||||
</View>
|
||||
<View style={[s.flex1]}>
|
||||
<Text type="md-bold" style={pal.text}>
|
||||
{account.displayName || account.handle}
|
||||
</Text>
|
||||
<Text type="sm" style={pal.textLight}>
|
||||
{account.handle}
|
||||
</Text>
|
||||
</View>
|
||||
<AccountDropdownBtn handle={account.handle} />
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</BottomSheetScrollView>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
innerContainer: {
|
||||
paddingBottom: 20,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
marginTop: 12,
|
||||
marginBottom: 12,
|
||||
},
|
||||
linkCard: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 18,
|
||||
marginBottom: 1,
|
||||
},
|
||||
avi: {
|
||||
marginRight: 12,
|
||||
},
|
||||
dimmed: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
})
|
46
src/view/com/util/AccountDropdownBtn.tsx
Normal file
46
src/view/com/util/AccountDropdownBtn.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import React from 'react'
|
||||
import {Pressable} from 'react-native'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {s} from 'lib/styles'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {DropdownItem, NativeDropdown} from './forms/NativeDropdown'
|
||||
import * as Toast from '../../com/util/Toast'
|
||||
|
||||
export function AccountDropdownBtn({handle}: {handle: string}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const items: DropdownItem[] = [
|
||||
{
|
||||
label: 'Remove account',
|
||||
onPress: () => {
|
||||
store.session.removeAccount(handle)
|
||||
Toast.show('Account removed from quick access')
|
||||
},
|
||||
icon: {
|
||||
ios: {
|
||||
name: 'trash',
|
||||
},
|
||||
android: 'ic_delete',
|
||||
web: 'trash',
|
||||
},
|
||||
},
|
||||
]
|
||||
return (
|
||||
<Pressable accessibilityRole="button" style={s.pl10}>
|
||||
<NativeDropdown
|
||||
testID="accountSettingsDropdownBtn"
|
||||
items={items}
|
||||
accessibilityLabel="Account options"
|
||||
accessibilityHint="">
|
||||
<FontAwesomeIcon
|
||||
icon="ellipsis-h"
|
||||
style={pal.textLight as FontAwesomeIconStyle}
|
||||
/>
|
||||
</NativeDropdown>
|
||||
</Pressable>
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue