/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see .
*/
import * as React from 'react';
import {Animated} from 'react-native';
import {withTheme} from 'react-native-paper';
import {Collapsible} from 'react-navigation-collapsible';
import TabIcon from './TabIcon';
import TabHomeIcon from './TabHomeIcon';
import {BottomTabBarProps} from '@react-navigation/bottom-tabs';
import {NavigationState} from '@react-navigation/native';
import {
PartialState,
Route,
} from '@react-navigation/routers/lib/typescript/src/types';
type RouteType = Route & {
state?: NavigationState | PartialState;
};
interface PropsType extends BottomTabBarProps {
theme: ReactNativePaper.Theme;
}
type StateType = {
translateY: any;
};
type validRoutes = 'proxiwash' | 'services' | 'planning' | 'planex';
const TAB_ICONS = {
proxiwash: 'tshirt-crew',
services: 'account-circle',
planning: 'calendar-range',
planex: 'clock',
};
class CustomTabBar extends React.Component {
static TAB_BAR_HEIGHT = 48;
constructor(props: PropsType) {
super(props);
this.state = {
translateY: new Animated.Value(0),
};
}
/**
* Navigates to the given route if it is different from the current one
*
* @param route Destination route
* @param currentIndex The current route index
* @param destIndex The destination route index
*/
onItemPress(route: RouteType, currentIndex: number, destIndex: number) {
const {navigation} = this.props;
if (currentIndex !== destIndex) {
navigation.navigate(route.name);
}
}
/**
* Navigates to tetris screen on home button long press
*
* @param route
*/
onItemLongPress(route: RouteType) {
const {navigation} = this.props;
if (route.name === 'home') {
navigation.navigate('game-start');
}
}
/**
* Finds the active route and syncs the tab bar animation with the header bar
*/
onRouteChange = () => {
const {props} = this;
props.state.routes.map(this.syncTabBar);
};
/**
* Gets an icon for the given route if it is not the home one as it uses a custom button
*
* @param route
* @param focused
* @returns {null}
*/
getTabBarIcon = (route: RouteType, focused: boolean) => {
let icon = TAB_ICONS[route.name as validRoutes];
icon = focused ? icon : `${icon}-outline`;
if (route.name !== 'home') {
return icon;
}
return '';
};
/**
* Gets a tab icon render.
* If the given route is focused, it syncs the tab bar and header bar animations together
*
* @param route The route for the icon
* @param index The index of the current route
* @returns {*}
*/
getRenderIcon = (route: RouteType, index: number) => {
const {props} = this;
const {state} = props;
const {options} = props.descriptors[route.key];
let label;
if (options.tabBarLabel != null) {
label = options.tabBarLabel;
} else if (options.title != null) {
label = options.title;
} else {
label = route.name;
}
const onPress = () => {
this.onItemPress(route, state.index, index);
};
const onLongPress = () => {
this.onItemLongPress(route);
};
const isFocused = state.index === index;
const color = isFocused
? props.theme.colors.primary
: props.theme.colors.tabIcon;
if (route.name !== 'home') {
return (
index}
key={route.key}
/>
);
}
return (
);
};
getIcons() {
const {props} = this;
return props.state.routes.map(this.getRenderIcon);
}
syncTabBar = (route: RouteType, index: number) => {
const {state} = this.props;
const isFocused = state.index === index;
if (isFocused) {
const stackState = route.state;
const stackRoute =
stackState && stackState.index
? stackState.routes[stackState.index]
: null;
const params: {collapsible: Collapsible} | null | undefined = stackRoute
? (stackRoute.params as {collapsible: Collapsible})
: null;
const collapsible = params != null ? params.collapsible : null;
if (collapsible != null) {
this.setState({
translateY: Animated.multiply(-1.5, collapsible.translateY), // Hide tab bar faster than header bar
});
}
}
};
render() {
const {props, state} = this;
props.navigation.addListener('state', this.onRouteChange);
const icons = this.getIcons();
return (
{icons}
);
}
}
export default withTheme(CustomTabBar);