Use a custom tabbar

This commit is contained in:
2024-01-04 15:26:28 +01:00
committed by Clément Le Bihan
parent 42a947dfb0
commit 038918c212
5 changed files with 72 additions and 70 deletions

View File

@@ -35,13 +35,16 @@ import DiscoveryView from './views/V2/DiscoveryView';
import MusicView from './views/MusicView';
import Leaderboardiew from './views/LeaderboardView';
import { LinearGradient } from 'expo-linear-gradient';
import ScaffoldMobileCC from './components/UI/ScaffoldMobileCC';
const Stack = createNativeStackNavigator<AppRouteParams & { Loading: never; Oops: never }>();
const Tab = createBottomTabNavigator<AppRouteParams & { Loading: never; Oops: never }>();
const Tabs = () => {
return (
<Tab.Navigator>
<Tab.Navigator
tabBar={ScaffoldMobileCC}
>
{Object.entries(tabRoutes).map(([name, route], routeIndex) => (
<Tab.Screen
key={'route-' + routeIndex}

View File

@@ -11,6 +11,7 @@ interface ButtonProps {
title?: string;
style?: StyleProp<ViewStyle>;
onPress?: () => void | Promise<void>;
onLongPress?: () => void | Promise<void>;
isDisabled?: boolean;
icon?: Icon;
iconVariant?: 'Bold' | 'Outline';
@@ -22,6 +23,7 @@ const ButtonBase: React.FC<ButtonProps> = ({
title,
style,
onPress,
onLongPress,
isDisabled,
icon,
iconImage,
@@ -123,6 +125,18 @@ const ButtonBase: React.FC<ButtonProps> = ({
}
}
}}
onLongPress={async () => {
if (onLongPress && !isDisabled) {
setLoading(true);
try {
await onLongPress();
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
}}
isDisabled={isDisabled}
isOutlined={type === 'outlined'}
>

View File

@@ -5,6 +5,7 @@ import { Animated, StyleProp, ViewStyle } from 'react-native';
interface InteractiveBaseProps {
children?: React.ReactNode;
onPress?: () => Promise<void>;
onLongPress?: () => Promise<void>;
isDisabled?: boolean;
isOutlined?: boolean;
focusable?: boolean;
@@ -44,6 +45,7 @@ interface InteractiveBaseProps {
const InteractiveBase: React.FC<InteractiveBaseProps> = ({
children,
onPress,
onLongPress,
style,
styleAnimate,
isDisabled = false,
@@ -183,10 +185,6 @@ const InteractiveBase: React.FC<InteractiveBaseProps> = ({
useNativeDriver: false,
}),
]).start();
if (onPress && !isDisabled) {
onPress();
}
};
// Mouse Leave
const handleMouseLeave = () => {
@@ -248,6 +246,8 @@ const InteractiveBase: React.FC<InteractiveBaseProps> = ({
onPressIn={handlePressIn}
onPressOut={handlePressOut}
onHoverOut={handleMouseLeave}
onPress={onPress}
onLongPress={onLongPress}
>
{children}
</Pressable>

View File

@@ -28,8 +28,6 @@ type ScaffoldCCProps = {
const ScaffoldCC = ({
children,
routeName,
withPadding = true,
enableScroll = true,
}: ScaffoldCCProps) => {
const userQuery = useQuery(API.getUserInfo);
const screenSize = useBreakpointValue({ base: 'small', md: 'big' });
@@ -48,12 +46,8 @@ const ScaffoldCC = ({
<Flex style={{ flex: 1, backgroundColor: '#cdd4fd' }}>
{screenSize === 'small' ? (
<ScaffoldMobileCC
enableScroll={enableScroll}
user={userQuery.data}
logo={logo?.at(0)?.uri ?? ''}
routeName={routeName}
menu={menu}
widthPadding={withPadding}
>
{children}
</ScaffoldMobileCC>
@@ -63,7 +57,7 @@ const ScaffoldCC = ({
logo={logo?.at(0)?.uri ?? ''}
routeName={routeName}
menu={menu}
widthPadding={withPadding}
widthPadding={true}
>
{children}
</ScaffoldDesktopCC>

View File

@@ -1,79 +1,70 @@
/* eslint-disable no-mixed-spaces-and-tabs */
import { View } from 'react-native';
import { Flex, useMediaQuery, useTheme } from 'native-base';
import ButtonBase from './ButtonBase';
import { Icon } from 'iconsax-react-native';
import { useNavigation } from '../../Navigation';
import User from '../../models/User';
import { Discover } from 'iconsax-react-native';
import { translate } from '../../i18n/i18n';
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import { ComponentProps } from 'react';
type ScaffoldMobileCCProps = {
children?: React.ReactNode;
user: User;
logo: string;
routeName: string;
widthPadding: boolean;
enableScroll: boolean;
menu: readonly {
type: 'main' | 'sub';
title:
| 'menuDiscovery'
| 'menuProfile'
| 'menuMusic'
| 'menuSearch'
| 'menuLeaderBoard'
| 'menuSettings';
icon: Icon;
link: string;
}[];
};
const ScaffoldMobileCC = (props: ScaffoldMobileCCProps) => {
const navigation = useNavigation();
const ScaffoldMobileCC = ({ state, descriptors, navigation }: BottomTabBarProps) => {
const [isSmallScreen] = useMediaQuery({ maxWidth: 400 });
const { colors } = useTheme();
return (
<View style={{ height: '100%', flexDirection: 'column', overflow: 'hidden' }}>
<View
<View style={{ padding: 8, paddingTop: 0 }}>
<Flex
style={{
flex: 1,
maxHeight: '100%',
padding: props.widthPadding ? 8 : 0,
width: '100%',
flexDirection: 'row',
backgroundColor: colors.coolGray[500],
padding: 8,
justifyContent: 'space-between',
borderRadius: 8,
}}
>
{props.children}
</View>
<View style={{ padding: 8, paddingTop: 0 }}>
<Flex
style={{
width: '100%',
flexDirection: 'row',
backgroundColor: colors.coolGray[500],
padding: 8,
justifyContent: 'space-between',
borderRadius: 8,
}}
>
{props.menu.map((value) => (
{state.routes.map((route, index) => {
const { options } = descriptors[route.key]!;
const label = options.title !== undefined ? options.title : route.name;
const isFocused = state.index === index;
return (
<ButtonBase
key={'key-menu-link-' + value.title}
key={'key-menu-link-' + label}
type="menu"
icon={value.icon}
icon={Discover}
title={
props.routeName === value.link && !isSmallScreen
? translate(value.title)
: undefined
isFocused && !isSmallScreen ? translate(label as any) : undefined
}
isDisabled={props.routeName === value.link}
iconVariant={props.routeName === value.link ? 'Bold' : 'Outline'}
onPress={async () => navigation.navigate(value.link as never)}
isDisabled={isFocused}
iconVariant={isFocused ? 'Bold' : 'Outline'}
onPress={() => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name, route.params);
}
}}
onLongPress={() => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
}}
/>
))}
</Flex>
</View>
);
})}
</Flex>
</View>
);
};
export default ScaffoldMobileCC;
// This is needed to bypass a bug in react-navigation that calls custom tabBars weirdly
const Wrapper = (props: ComponentProps<typeof ScaffoldMobileCC>) => {
return <ScaffoldMobileCC {...props} />;
}
export default Wrapper;