diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-03-17 14:03:16 -0500 |
---|---|---|
committer | Paul Frazee <pfrazee@gmail.com> | 2023-03-17 14:03:16 -0500 |
commit | c3ed0dc44cf36d1f2275735f7c69ac010c5ecff8 (patch) | |
tree | 67b5c93c0f5a6852232b6d6cd76426ccc3585bd5 /src | |
parent | 244b06c19d57901b1fee04a742396f6c360339d9 (diff) | |
download | voidsky-c3ed0dc44cf36d1f2275735f7c69ac010c5ecff8.tar.zst |
Move the feed selector to the footer
Diffstat (limited to 'src')
-rw-r--r-- | src/view/com/profile/FollowButton.tsx | 6 | ||||
-rw-r--r-- | src/view/com/util/Pager.tsx | 17 | ||||
-rw-r--r-- | src/view/com/util/PostMeta.tsx | 1 | ||||
-rw-r--r-- | src/view/com/util/TabBar.tsx | 28 | ||||
-rw-r--r-- | src/view/screens/Home.tsx | 87 | ||||
-rw-r--r-- | src/view/shell/BottomBar.tsx | 22 |
6 files changed, 121 insertions, 40 deletions
diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx index 7a194cee9..5204f5a40 100644 --- a/src/view/com/profile/FollowButton.tsx +++ b/src/view/com/profile/FollowButton.tsx @@ -1,16 +1,18 @@ import React from 'react' import {observer} from 'mobx-react-lite' -import {Button} from '../util/forms/Button' +import {Button, ButtonType} from '../util/forms/Button' import {useStores} from 'state/index' import * as apilib from 'lib/api/index' import * as Toast from '../util/Toast' const FollowButton = observer( ({ + type = 'inverted', did, declarationCid, onToggleFollow, }: { + type?: ButtonType did: string declarationCid: string onToggleFollow?: (v: boolean) => void @@ -42,7 +44,7 @@ const FollowButton = observer( return ( <Button - type={isFollowing ? 'default' : 'inverted'} + type={isFollowing ? 'default' : type} onPress={onToggleFollowInner} label={isFollowing ? 'Unfollow' : 'Follow'} /> diff --git a/src/view/com/util/Pager.tsx b/src/view/com/util/Pager.tsx index 9ce5006cd..89ba59e85 100644 --- a/src/view/com/util/Pager.tsx +++ b/src/view/com/util/Pager.tsx @@ -15,11 +15,13 @@ export interface TabBarProps { } interface Props { + tabBarPosition?: 'top' | 'bottom' renderTabBar: (props: TabBarProps) => JSX.Element onPageSelected?: (e: PageSelectedEvent) => void } export const Pager = ({ children, + tabBarPosition = 'top', renderTabBar, onPageSelected, }: React.PropsWithChildren<Props>) => { @@ -45,7 +47,13 @@ export const Pager = ({ return ( <View> - {renderTabBar({selectedPage, position, offset, onSelect: onTabBarSelect})} + {tabBarPosition === 'top' && + renderTabBar({ + selectedPage, + position, + offset, + onSelect: onTabBarSelect, + })} <AnimatedPagerView ref={pagerView} style={s.h100pct} @@ -64,6 +72,13 @@ export const Pager = ({ )}> {children} </AnimatedPagerView> + {tabBarPosition === 'bottom' && + renderTabBar({ + selectedPage, + position, + offset, + onSelect: onTabBarSelect, + })} </View> ) } diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index 1a36a72e8..c53de5c1f 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -77,6 +77,7 @@ export const PostMeta = observer(function (opts: PostMetaOpts) { <View> <FollowButton + type="default" did={opts.did} declarationCid={opts.declarationCid} onToggleFollow={onToggleFollow} diff --git a/src/view/com/util/TabBar.tsx b/src/view/com/util/TabBar.tsx index 666ad5811..ac1814685 100644 --- a/src/view/com/util/TabBar.tsx +++ b/src/view/com/util/TabBar.tsx @@ -18,12 +18,16 @@ export function TabBar({ items, position, offset, + indicatorPosition = 'bottom', + indicatorColor, onSelect, }: { selectedPage: number items: string[] position: Animated.Value offset: Animated.Value + indicatorPosition?: 'top' | 'bottom' + indicatorColor?: string onSelect?: (index: number) => void }) { const pal = usePalette('default') @@ -36,8 +40,10 @@ export function TabBar({ ) const panX = Animated.add(position, offset) - const underlineStyle = { - backgroundColor: pal.colors.link, + const indicatorStyle = { + backgroundColor: indicatorColor || pal.colors.link, + bottom: indicatorPosition === 'bottom' ? -1 : undefined, + top: indicatorPosition === 'top' ? -1 : undefined, left: panX.interpolate({ inputRange: items.map((_item, i) => i), outputRange: itemLayouts.map(l => l.x), @@ -72,12 +78,16 @@ export function TabBar({ return ( <View style={[pal.view, styles.outer]} onLayout={onLayout}> - <Animated.View style={[styles.underline, underlineStyle]} /> + <Animated.View style={[styles.indicator, indicatorStyle]} /> {items.map((item, i) => { const selected = i === selectedPage return ( <TouchableWithoutFeedback key={i} onPress={() => onPressItem(i)}> - <View style={styles.item} ref={itemRefs[i]}> + <View + style={ + indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom + } + ref={itemRefs[i]}> <Text type="xl-bold" style={selected ? pal.text : pal.textLight}> {item} </Text> @@ -94,15 +104,19 @@ const styles = StyleSheet.create({ flexDirection: 'row', paddingHorizontal: 14, }, - item: { + itemTop: { + paddingTop: 10, + paddingBottom: 10, + marginRight: 24, + }, + itemBottom: { paddingTop: 8, paddingBottom: 12, marginRight: 24, }, - underline: { + indicator: { position: 'absolute', height: 3, - bottom: -1, borderRadius: 4, }, }) diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index b38e1cc36..390746eb3 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -1,8 +1,8 @@ import React from 'react' import { + Animated, FlatList, StyleSheet, - TouchableOpacity, View, useWindowDimensions, } from 'react-native' @@ -15,7 +15,6 @@ import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {Feed} from '../com/posts/Feed' import {LoadLatestBtn} from '../com/util/LoadLatestBtn' import {WelcomeBanner} from '../com/util/WelcomeBanner' -import {UserAvatar} from 'view/com/util/UserAvatar' import {TabBar} from 'view/com/util/TabBar' import {Pager, PageSelectedEvent, TabBarProps} from 'view/com/util/Pager' import {FAB} from '../com/util/FAB' @@ -23,15 +22,18 @@ import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {s} from 'lib/styles' import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' +import {useSafeAreaInsets} from 'react-native-safe-area-context' +import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' import {useAnalytics} from 'lib/analytics' import {ComposeIcon2} from 'lib/icons' +import {clamp} from 'lodash' const TAB_BAR_HEIGHT = 82 +const BOTTOM_BAR_HEIGHT = 48 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'> export const HomeScreen = withAuthRequired((_opts: Props) => { const store = useStores() - const pal = usePalette('default') const [selectedPage, setSelectedPage] = React.useState(0) useFocusEffect( @@ -51,26 +53,15 @@ export const HomeScreen = withAuthRequired((_opts: Props) => { [store], ) - const onPressAvi = React.useCallback(() => { - store.shell.openDrawer() - }, [store]) - - const renderTabBar = React.useCallback( - (props: TabBarProps) => { - return ( - <View style={[pal.view, pal.border, styles.tabBar]}> - <TouchableOpacity style={styles.tabBarAvi} onPress={onPressAvi}> - <UserAvatar avatar={store.me.avatar} size={32} /> - </TouchableOpacity> - <TabBar items={['Suggested', 'Following']} {...props} /> - </View> - ) - }, - [store.me.avatar, pal, onPressAvi], - ) + const renderTabBar = React.useCallback((props: TabBarProps) => { + return <FloatingTabBar {...props} /> + }, []) return ( - <Pager onPageSelected={onPageSelected} renderTabBar={renderTabBar}> + <Pager + onPageSelected={onPageSelected} + renderTabBar={renderTabBar} + tabBarPosition="bottom"> <AlgoView key="1" /> <View key="2"> <FollowingView /> @@ -79,6 +70,46 @@ export const HomeScreen = withAuthRequired((_opts: Props) => { ) }) +const FloatingTabBar = observer((props: TabBarProps) => { + const store = useStores() + const safeAreaInsets = useSafeAreaInsets() + const pal = usePalette('default') + const interp = useAnimatedValue(0) + + const pad = React.useMemo( + () => ({ + paddingBottom: clamp(safeAreaInsets.bottom, 15, 20), + }), + [safeAreaInsets], + ) + + React.useEffect(() => { + Animated.timing(interp, { + toValue: store.shell.minimalShellMode ? 0 : 1, + duration: 100, + useNativeDriver: true, + isInteraction: false, + }).start() + }, [interp, store.shell.minimalShellMode]) + const transform = { + transform: [ + {translateY: Animated.multiply(interp, -1 * BOTTOM_BAR_HEIGHT)}, + ], + } + + return ( + <Animated.View + style={[pal.view, pal.border, styles.tabBar, pad, transform]}> + <TabBar + items={['Suggested', 'Following']} + {...props} + indicatorPosition="top" + indicatorColor={pal.colors.link} + /> + </Animated.View> + ) +}) + const AlgoView = observer(() => { const store = useStores() const onMainScroll = useOnMainScroll(store) @@ -270,13 +301,19 @@ const FollowingView = observer(() => { const styles = StyleSheet.create({ tabBar: { + position: 'absolute', + left: 0, + right: 0, + bottom: 0, flexDirection: 'row', alignItems: 'center', - paddingHorizontal: 18, - borderBottomWidth: 1, + paddingHorizontal: 8, + borderTopWidth: 1, + paddingTop: 0, + paddingBottom: 30, + // height: 100, }, tabBarAvi: { - marginRight: 16, - paddingBottom: 2, + marginRight: 4, }, }) diff --git a/src/view/shell/BottomBar.tsx b/src/view/shell/BottomBar.tsx index c59d8c675..1cbf2de86 100644 --- a/src/view/shell/BottomBar.tsx +++ b/src/view/shell/BottomBar.tsx @@ -34,16 +34,24 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => { const minimalShellInterp = useAnimatedValue(0) const safeAreaInsets = useSafeAreaInsets() const {track} = useAnalytics() - const {isAtHome, isAtSearch, isAtNotifications} = useNavigationState( - state => { - return { + const {isAtHome, isAtSearch, isAtNotifications, noBorder} = + useNavigationState(state => { + const res = { isAtHome: getTabState(state, 'Home') !== TabState.Outside, isAtSearch: getTabState(state, 'Search') !== TabState.Outside, isAtNotifications: getTabState(state, 'Notifications') !== TabState.Outside, + noBorder: getTabState(state, 'Home') === TabState.InsideAtRoot, } - }, - ) + 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 + res.noBorder = true + } + return res + }) React.useEffect(() => { if (store.shell.minimalShellMode) { @@ -99,6 +107,7 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => { <Animated.View style={[ styles.bottomBar, + noBorder && styles.noBorder, pal.view, pal.border, {paddingBottom: clamp(safeAreaInsets.bottom, 15, 30)}, @@ -213,6 +222,9 @@ const styles = StyleSheet.create({ paddingLeft: 5, paddingRight: 10, }, + noBorder: { + borderTopWidth: 0, + }, ctrl: { flex: 1, paddingTop: 13, |