diff --git a/src/components/AccountList.tsx b/src/components/AccountList.tsx
new file mode 100644
index 00000000..169e7b84
--- /dev/null
+++ b/src/components/AccountList.tsx
@@ -0,0 +1,141 @@
+import React, {useCallback} from 'react'
+import {View} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useProfileQuery} from '#/state/queries/profile'
+import {type SessionAccount, useSession} from '#/state/session'
+import {UserAvatar} from '#/view/com/util/UserAvatar'
+import {atoms as a, useTheme} from '#/alf'
+import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
+import {ChevronRight_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron'
+import {Button} from './Button'
+import {Text} from './Typography'
+
+export function AccountList({
+ onSelectAccount,
+ onSelectOther,
+ otherLabel,
+}: {
+ onSelectAccount: (account: SessionAccount) => void
+ onSelectOther: () => void
+ otherLabel?: string
+}) {
+ const {isSwitchingAccounts, currentAccount, accounts} = useSession()
+ const t = useTheme()
+ const {_} = useLingui()
+
+ const onPressAddAccount = useCallback(() => {
+ onSelectOther()
+ }, [onSelectOther])
+
+ return (
+
+ {accounts.map(account => (
+
+
+
+
+ ))}
+
+
+ )
+}
+
+function AccountItem({
+ account,
+ onSelect,
+ isCurrentAccount,
+}: {
+ account: SessionAccount
+ onSelect: (account: SessionAccount) => void
+ isCurrentAccount: boolean
+}) {
+ const t = useTheme()
+ const {_} = useLingui()
+ const {data: profile} = useProfileQuery({did: account.did})
+
+ const onPress = React.useCallback(() => {
+ onSelect(account)
+ }, [account, onSelect])
+
+ return (
+
+ )
+}
diff --git a/src/components/dialogs/BirthDateSettings.tsx b/src/components/dialogs/BirthDateSettings.tsx
index 4a3e96e5..d831c600 100644
--- a/src/components/dialogs/BirthDateSettings.tsx
+++ b/src/components/dialogs/BirthDateSettings.tsx
@@ -1,23 +1,23 @@
import React from 'react'
-import {useLingui} from '@lingui/react'
-import {Trans, msg} from '@lingui/macro'
import {View} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
-import * as Dialog from '#/components/Dialog'
-import {Text} from '../Typography'
-import {DateInput} from '#/view/com/util/forms/DateInput'
+import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
+import {isIOS, isWeb} from '#/platform/detection'
import {
usePreferencesQuery,
- usePreferencesSetBirthDateMutation,
UsePreferencesQueryResponse,
+ usePreferencesSetBirthDateMutation,
} from '#/state/queries/preferences'
-import {Button, ButtonIcon, ButtonText} from '../Button'
-import {atoms as a, useTheme} from '#/alf'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
-import {cleanError} from '#/lib/strings/errors'
-import {isIOS, isWeb} from '#/platform/detection'
+import {DateInput} from '#/view/com/util/forms/DateInput'
+import {atoms as a, useTheme} from '#/alf'
+import * as Dialog from '#/components/Dialog'
import {Loader} from '#/components/Loader'
+import {Button, ButtonIcon, ButtonText} from '../Button'
+import {Text} from '../Typography'
export function BirthDateSettingsDialog({
control,
diff --git a/src/components/dialogs/SwitchAccount.tsx b/src/components/dialogs/SwitchAccount.tsx
new file mode 100644
index 00000000..645113d4
--- /dev/null
+++ b/src/components/dialogs/SwitchAccount.tsx
@@ -0,0 +1,61 @@
+import React, {useCallback} from 'react'
+import {View} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
+import {type SessionAccount, useSession} from '#/state/session'
+import {useLoggedOutViewControls} from '#/state/shell/logged-out'
+import {useCloseAllActiveElements} from '#/state/util'
+import {atoms as a} from '#/alf'
+import * as Dialog from '#/components/Dialog'
+import {AccountList} from '../AccountList'
+import {Text} from '../Typography'
+
+export function SwitchAccountDialog({
+ control,
+}: {
+ control: Dialog.DialogControlProps
+}) {
+ const {_} = useLingui()
+ const {currentAccount} = useSession()
+ const {onPressSwitchAccount} = useAccountSwitcher()
+ const {setShowLoggedOut} = useLoggedOutViewControls()
+ const closeAllActiveElements = useCloseAllActiveElements()
+
+ const onSelectAccount = useCallback(
+ (account: SessionAccount) => {
+ if (account.did === currentAccount?.did) {
+ control.close()
+ } else {
+ onPressSwitchAccount(account, 'SwitchAccount')
+ }
+ },
+ [currentAccount, control, onPressSwitchAccount],
+ )
+
+ const onPressAddAccount = useCallback(() => {
+ setShowLoggedOut(true)
+ closeAllActiveElements()
+ }, [setShowLoggedOut, closeAllActiveElements])
+
+ return (
+
+
+
+
+
+
+ Switch Account
+
+
+
+
+
+
+ )
+}
diff --git a/src/screens/Login/ChooseAccountForm.tsx b/src/screens/Login/ChooseAccountForm.tsx
index d0d4c784..15c06dbe 100644
--- a/src/screens/Login/ChooseAccountForm.tsx
+++ b/src/screens/Login/ChooseAccountForm.tsx
@@ -5,76 +5,15 @@ import {useLingui} from '@lingui/react'
import {useAnalytics} from '#/lib/analytics/analytics'
import {logEvent} from '#/lib/statsig/statsig'
-import {colors} from '#/lib/styles'
-import {useProfileQuery} from '#/state/queries/profile'
import {SessionAccount, useSession, useSessionApi} from '#/state/session'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import * as Toast from '#/view/com/util/Toast'
-import {UserAvatar} from '#/view/com/util/UserAvatar'
-import {atoms as a, useTheme} from '#/alf'
+import {atoms as a} from '#/alf'
+import {AccountList} from '#/components/AccountList'
import {Button} from '#/components/Button'
import * as TextField from '#/components/forms/TextField'
-import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
-import {ChevronRight_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron'
-import {Text} from '#/components/Typography'
import {FormContainer} from './FormContainer'
-function AccountItem({
- account,
- onSelect,
- isCurrentAccount,
-}: {
- account: SessionAccount
- onSelect: (account: SessionAccount) => void
- isCurrentAccount: boolean
-}) {
- const t = useTheme()
- const {_} = useLingui()
- const {data: profile} = useProfileQuery({did: account.did})
-
- const onPress = React.useCallback(() => {
- onSelect(account)
- }, [account, onSelect])
-
- return (
-
- )
-}
export const ChooseAccountForm = ({
onSelectAccount,
onPressBack,
@@ -84,8 +23,7 @@ export const ChooseAccountForm = ({
}) => {
const {track, screen} = useAnalytics()
const {_} = useLingui()
- const t = useTheme()
- const {accounts, currentAccount} = useSession()
+ const {currentAccount} = useSession()
const {initSession} = useSessionApi()
const {setShowLoggedOut} = useLoggedOutViewControls()
@@ -125,52 +63,10 @@ export const ChooseAccountForm = ({
Sign in as...
-
- {accounts.map(account => (
-
-
-
-
- ))}
-
-
+ onSelectAccount()}
+ />
- } else if (activeModal?.name === 'switch-account') {
- snapPoints = SwitchAccountModal.snapPoints
- element =
} else if (activeModal?.name === 'link-warning') {
snapPoints = LinkWarningModal.snapPoints
element =
diff --git a/src/view/com/modals/SwitchAccount.tsx b/src/view/com/modals/SwitchAccount.tsx
deleted file mode 100644
index 03bef719..00000000
--- a/src/view/com/modals/SwitchAccount.tsx
+++ /dev/null
@@ -1,169 +0,0 @@
-import React from 'react'
-import {
- ActivityIndicator,
- StyleSheet,
- TouchableOpacity,
- View,
-} from 'react-native'
-import {BottomSheetScrollView} from '@discord/bottom-sheet/src'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {useProfileQuery} from '#/state/queries/profile'
-import {SessionAccount, useSession, useSessionApi} from '#/state/session'
-import {useCloseAllActiveElements} from '#/state/util'
-import {useAnalytics} from 'lib/analytics/analytics'
-import {Haptics} from 'lib/haptics'
-import {useAccountSwitcher} from 'lib/hooks/useAccountSwitcher'
-import {usePalette} from 'lib/hooks/usePalette'
-import {makeProfileLink} from 'lib/routes/links'
-import {s} from 'lib/styles'
-import {AccountDropdownBtn} from '../util/AccountDropdownBtn'
-import {Link} from '../util/Link'
-import {Text} from '../util/text/Text'
-import {UserAvatar} from '../util/UserAvatar'
-
-export const snapPoints = ['40%', '90%']
-
-function SwitchAccountCard({account}: {account: SessionAccount}) {
- const pal = usePalette('default')
- const {_} = useLingui()
- const {track} = useAnalytics()
- const {isSwitchingAccounts, currentAccount} = useSession()
- const {logout} = useSessionApi()
- const {data: profile} = useProfileQuery({did: account.did})
- const isCurrentAccount = account.did === currentAccount?.did
- const {onPressSwitchAccount} = useAccountSwitcher()
- const closeAllActiveElements = useCloseAllActiveElements()
-
- const onPressSignout = React.useCallback(() => {
- track('Settings:SignOutButtonClicked')
- closeAllActiveElements()
- // needs to be in timeout or the modal re-opens
- setTimeout(() => logout('SwitchAccount'), 0)
- }, [track, logout, closeAllActiveElements])
-
- const contents = (
-
-
-
-
-
-
- {profile?.displayName || account?.handle}
-
-
- {account?.handle}
-
-
-
- {isCurrentAccount ? (
-
-
- Sign out
-
-
- ) : (
-
- )}
-
- )
-
- return isCurrentAccount ? (
-
- {contents}
-
- ) : (
- onPressSwitchAccount(account, 'SwitchAccount')
- }
- accessibilityRole="button"
- accessibilityLabel={_(msg`Switch to ${account.handle}`)}
- accessibilityHint={_(msg`Switches the account you are logged in to`)}>
- {contents}
-
- )
-}
-
-export function Component({}: {}) {
- const pal = usePalette('default')
- const {isSwitchingAccounts, currentAccount, accounts} = useSession()
-
- React.useEffect(() => {
- Haptics.default()
- })
-
- return (
-
-
- Switch Account
-
-
- {isSwitchingAccounts || !currentAccount ? (
-
-
-
- ) : (
-
- )}
-
- {accounts
- .filter(a => a.did !== currentAccount?.did)
- .map(account => (
-
- ))}
-
- )
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- innerContainer: {
- paddingBottom: 40,
- },
- 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,
- },
-})
diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx
index 8a19a0b4..f41631a9 100644
--- a/src/view/shell/bottom-bar/BottomBar.tsx
+++ b/src/view/shell/bottom-bar/BottomBar.tsx
@@ -1,47 +1,49 @@
import React, {ComponentProps} from 'react'
import {GestureResponderEvent, TouchableOpacity, View} from 'react-native'
import Animated from 'react-native-reanimated'
-import {StackActions} from '@react-navigation/native'
-import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
-import {Text} from 'view/com/util/text/Text'
-import {useAnalytics} from 'lib/analytics/analytics'
-import {clamp} from 'lib/numbers'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
+import {StackActions} from '@react-navigation/native'
+
+import {useAnalytics} from '#/lib/analytics/analytics'
+import {Haptics} from '#/lib/haptics'
+import {useDedupe} from '#/lib/hooks/useDedupe'
+import {useMinimalShellMode} from '#/lib/hooks/useMinimalShellMode'
+import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState'
+import {usePalette} from '#/lib/hooks/usePalette'
import {
+ BellIcon,
+ BellIconSolid,
+ HashtagIcon,
HomeIcon,
HomeIconSolid,
MagnifyingGlassIcon2,
MagnifyingGlassIcon2Solid,
- HashtagIcon,
- BellIcon,
- BellIconSolid,
-} from 'lib/icons'
-import {usePalette} from 'lib/hooks/usePalette'
-import {getTabState, TabState} from 'lib/routes/helpers'
-import {styles} from './BottomBarStyles'
-import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
-import {useNavigationTabState} from 'lib/hooks/useNavigationTabState'
-import {UserAvatar} from 'view/com/util/UserAvatar'
-import {useLingui} from '@lingui/react'
-import {msg, Trans} from '@lingui/macro'
-import {useModalControls} from '#/state/modals'
-import {useShellLayout} from '#/state/shell/shell-layout'
-import {useUnreadNotifications} from '#/state/queries/notifications/unread'
+} from '#/lib/icons'
+import {clamp} from '#/lib/numbers'
+import {getTabState, TabState} from '#/lib/routes/helpers'
+import {s} from '#/lib/styles'
import {emitSoftReset} from '#/state/events'
-import {useSession} from '#/state/session'
+import {useUnreadNotifications} from '#/state/queries/notifications/unread'
import {useProfileQuery} from '#/state/queries/profile'
+import {useSession} from '#/state/session'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
+import {useShellLayout} from '#/state/shell/shell-layout'
import {useCloseAllActiveElements} from '#/state/util'
import {Button} from '#/view/com/util/forms/Button'
-import {s} from 'lib/styles'
+import {Text} from '#/view/com/util/text/Text'
+import {UserAvatar} from '#/view/com/util/UserAvatar'
import {Logo} from '#/view/icons/Logo'
import {Logotype} from '#/view/icons/Logotype'
-import {useDedupe} from 'lib/hooks/useDedupe'
+import {useDialogControl} from '#/components/Dialog'
+import {SwitchAccountDialog} from '#/components/dialogs/SwitchAccount'
+import {styles} from './BottomBarStyles'
type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds'
export function BottomBar({navigation}: BottomTabBarProps) {
- const {openModal} = useModalControls()
const {hasSession, currentAccount} = useSession()
const pal = usePalette('default')
const {_} = useLingui()
@@ -56,6 +58,7 @@ export function BottomBar({navigation}: BottomTabBarProps) {
const {requestSwitchToAccount} = useLoggedOutViewControls()
const closeAllActiveElements = useCloseAllActiveElements()
const dedupe = useDedupe()
+ const accountSwitchControl = useDialogControl()
const showSignIn = React.useCallback(() => {
closeAllActiveElements()
@@ -99,204 +102,213 @@ export function BottomBar({navigation}: BottomTabBarProps) {
const onPressProfile = React.useCallback(() => {
onPressTab('MyProfile')
}, [onPressTab])
+
const onLongPressProfile = React.useCallback(() => {
- openModal({name: 'switch-account'})
- }, [openModal])
+ Haptics.default()
+ accountSwitchControl.open()
+ }, [accountSwitchControl])
return (
- {
- footerHeight.value = e.nativeEvent.layout.height
- }}>
- {hasSession ? (
- <>
-
- ) : (
-
- )
- }
- onPress={onPressHome}
- accessibilityRole="tab"
- accessibilityLabel={_(msg`Home`)}
- accessibilityHint=""
- />
-
- ) : (
-
- )
- }
- onPress={onPressSearch}
- accessibilityRole="search"
- accessibilityLabel={_(msg`Search`)}
- accessibilityHint=""
- />
-
- ) : (
-
- )
- }
- onPress={onPressFeeds}
- accessibilityRole="tab"
- accessibilityLabel={_(msg`Feeds`)}
- accessibilityHint=""
- />
-
- ) : (
-
- )
- }
- onPress={onPressNotifications}
- notificationCount={numUnreadNotifications}
- accessible={true}
- accessibilityRole="tab"
- accessibilityLabel={_(msg`Notifications`)}
- accessibilityHint={
- numUnreadNotifications === ''
- ? ''
- : `${numUnreadNotifications} unread`
- }
- />
-
- {isAtMyProfile ? (
-
-
-
+ <>
+
+
+ {
+ footerHeight.value = e.nativeEvent.layout.height
+ }}>
+ {hasSession ? (
+ <>
+
) : (
-
-
-
- )}
+
+ )
+ }
+ onPress={onPressHome}
+ accessibilityRole="tab"
+ accessibilityLabel={_(msg`Home`)}
+ accessibilityHint=""
+ />
+
+ ) : (
+
+ )
+ }
+ onPress={onPressSearch}
+ accessibilityRole="search"
+ accessibilityLabel={_(msg`Search`)}
+ accessibilityHint=""
+ />
+
+ ) : (
+
+ )
+ }
+ onPress={onPressFeeds}
+ accessibilityRole="tab"
+ accessibilityLabel={_(msg`Feeds`)}
+ accessibilityHint=""
+ />
+
+ ) : (
+
+ )
+ }
+ onPress={onPressNotifications}
+ notificationCount={numUnreadNotifications}
+ accessible={true}
+ accessibilityRole="tab"
+ accessibilityLabel={_(msg`Notifications`)}
+ accessibilityHint={
+ numUnreadNotifications === ''
+ ? ''
+ : `${numUnreadNotifications} unread`
+ }
+ />
+
+ {isAtMyProfile ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+ }
+ onPress={onPressProfile}
+ onLongPress={onLongPressProfile}
+ accessibilityRole="tab"
+ accessibilityLabel={_(msg`Profile`)}
+ accessibilityHint=""
+ />
+ >
+ ) : (
+ <>
+
+
+
+
+
+
- }
- onPress={onPressProfile}
- onLongPress={onLongPressProfile}
- accessibilityRole="tab"
- accessibilityLabel={_(msg`Profile`)}
- accessibilityHint=""
- />
- >
- ) : (
- <>
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
- >
- )}
-
+ >
+ )}
+
+ >
)
}