diff options
author | John Fawcett <jrf0110@gmail.com> | 2023-04-12 20:27:55 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-12 18:27:55 -0700 |
commit | f6769b283fe83d7abbc0545077b3dca978184eed (patch) | |
tree | fab3973591fd0514d290de18f37280baca5563f9 /src/view/shell/bottom-bar/BottomBar.tsx | |
parent | 2fed6c402159c6084dd481ab87c5e8b034e910ac (diff) | |
download | voidsky-f6769b283fe83d7abbc0545077b3dca978184eed.tar.zst |
Mobile Web (#427)
* WIP * WIP * Fix header offset on web * Remove debug * Fix web mobile feed and FAB layout * Fix modals on mobile web * Remove dead code * Remove ios config that shouldnt be committed now * Move bottom bar into its own folder * Fix web drawer navigation and state behaviors * Remove dark mode toggle from web drawer for now * Fix search on mobile web * Fix the logged out splash screen on mobile web * Fixes to detox simulator --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Diffstat (limited to 'src/view/shell/bottom-bar/BottomBar.tsx')
-rw-r--r-- | src/view/shell/bottom-bar/BottomBar.tsx | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx new file mode 100644 index 000000000..59b21968d --- /dev/null +++ b/src/view/shell/bottom-bar/BottomBar.tsx @@ -0,0 +1,198 @@ +import React from 'react' +import { + Animated, + GestureResponderEvent, + TouchableOpacity, + View, +} from 'react-native' +import {StackActions, useNavigationState} from '@react-navigation/native' +import {BottomTabBarProps} from '@react-navigation/bottom-tabs' +import {useSafeAreaInsets} from 'react-native-safe-area-context' +import {observer} from 'mobx-react-lite' +import {Text} from 'view/com/util/text/Text' +import {useStores} from 'state/index' +import {useAnalytics} from 'lib/analytics' +import {clamp} from 'lib/numbers' +import { + HomeIcon, + HomeIconSolid, + MagnifyingGlassIcon2, + MagnifyingGlassIcon2Solid, + BellIcon, + BellIconSolid, + UserIcon, +} 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' + +export const BottomBar = observer(({navigation}: BottomTabBarProps) => { + const store = useStores() + const pal = usePalette('default') + const safeAreaInsets = useSafeAreaInsets() + const {track} = useAnalytics() + const {isAtHome, isAtSearch, isAtNotifications} = useNavigationState( + state => { + const res = { + isAtHome: getTabState(state, 'Home') !== TabState.Outside, + isAtSearch: getTabState(state, 'Search') !== TabState.Outside, + isAtNotifications: + getTabState(state, 'Notifications') !== TabState.Outside, + } + if (!res.isAtHome && !res.isAtNotifications && !res.isAtSearch) { + // HACK for some reason useNavigationState will give us pre-hydration results + // and not update after, so we force isAtHome if all came back false + // -prf + res.isAtHome = true + } + return res + }, + ) + + const {footerMinimalShellTransform} = useMinimalShellMode() + + const onPressTab = React.useCallback( + (tab: string) => { + track(`MobileShell:${tab}ButtonPressed`) + const state = navigation.getState() + const tabState = getTabState(state, tab) + if (tabState === TabState.InsideAtRoot) { + store.emitScreenSoftReset() + } else if (tabState === TabState.Inside) { + navigation.dispatch(StackActions.popToTop()) + } else { + navigation.navigate(`${tab}Tab`) + } + }, + [store, track, navigation], + ) + const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab]) + const onPressSearch = React.useCallback( + () => onPressTab('Search'), + [onPressTab], + ) + const onPressNotifications = React.useCallback( + () => onPressTab('Notifications'), + [onPressTab], + ) + const onPressProfile = React.useCallback(() => { + track('MobileShell:ProfileButtonPressed') + navigation.navigate('Profile', {name: store.me.handle}) + }, [navigation, track, store.me.handle]) + + return ( + <Animated.View + style={[ + styles.bottomBar, + pal.view, + pal.border, + {paddingBottom: clamp(safeAreaInsets.bottom, 15, 30)}, + footerMinimalShellTransform, + ]}> + <Btn + testID="bottomBarHomeBtn" + icon={ + isAtHome ? ( + <HomeIconSolid + strokeWidth={4} + size={24} + style={[styles.ctrlIcon, pal.text, styles.homeIcon]} + /> + ) : ( + <HomeIcon + strokeWidth={4} + size={24} + style={[styles.ctrlIcon, pal.text, styles.homeIcon]} + /> + ) + } + onPress={onPressHome} + /> + <Btn + testID="bottomBarSearchBtn" + icon={ + isAtSearch ? ( + <MagnifyingGlassIcon2Solid + size={25} + style={[styles.ctrlIcon, pal.text, styles.searchIcon]} + strokeWidth={1.8} + /> + ) : ( + <MagnifyingGlassIcon2 + size={25} + style={[styles.ctrlIcon, pal.text, styles.searchIcon]} + strokeWidth={1.8} + /> + ) + } + onPress={onPressSearch} + /> + <Btn + testID="bottomBarNotificationsBtn" + icon={ + isAtNotifications ? ( + <BellIconSolid + size={24} + strokeWidth={1.9} + style={[styles.ctrlIcon, pal.text, styles.bellIcon]} + /> + ) : ( + <BellIcon + size={24} + strokeWidth={1.9} + style={[styles.ctrlIcon, pal.text, styles.bellIcon]} + /> + ) + } + onPress={onPressNotifications} + notificationCount={ + store.me.notifications.unreadCount + store.invitedUsers.numNotifs + } + /> + <Btn + testID="bottomBarProfileBtn" + icon={ + <View style={styles.ctrlIconSizingWrapper}> + <UserIcon + size={28} + strokeWidth={1.5} + style={[styles.ctrlIcon, pal.text, styles.profileIcon]} + /> + </View> + } + onPress={onPressProfile} + /> + </Animated.View> + ) +}) + +function Btn({ + testID, + icon, + notificationCount, + onPress, + onLongPress, +}: { + testID?: string + icon: JSX.Element + notificationCount?: number + onPress?: (event: GestureResponderEvent) => void + onLongPress?: (event: GestureResponderEvent) => void +}) { + return ( + <TouchableOpacity + testID={testID} + style={styles.ctrl} + onPress={onLongPress ? onPress : undefined} + onPressIn={onLongPress ? undefined : onPress} + onLongPress={onLongPress}> + {notificationCount ? ( + <View style={[styles.notificationCount]}> + <Text style={styles.notificationCountLabel}>{notificationCount}</Text> + </View> + ) : undefined} + {icon} + </TouchableOpacity> + ) +} |