Update custom tab bar to use TypeScript

This commit is contained in:
Arnaud Vergnet 2020-09-22 15:16:25 +02:00
parent e4adcd0057
commit 5261e85254
3 changed files with 63 additions and 77 deletions

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {Animated} from 'react-native'; import {Animated} from 'react-native';
import {withTheme} from 'react-native-paper'; import {withTheme} from 'react-native-paper';
@ -26,40 +24,40 @@ import {Collapsible} from 'react-navigation-collapsible';
import {StackNavigationProp} from '@react-navigation/stack'; import {StackNavigationProp} from '@react-navigation/stack';
import TabIcon from './TabIcon'; import TabIcon from './TabIcon';
import TabHomeIcon from './TabHomeIcon'; import TabHomeIcon from './TabHomeIcon';
import type {CustomThemeType} from '../../managers/ThemeManager';
type RouteType = { type RouteType = {
name: string, name: string;
key: string, key: string;
params: {collapsible: Collapsible}, params: {collapsible: Collapsible};
state: { state: {
index: number, index: number;
routes: Array<RouteType>, routes: Array<RouteType>;
}, };
}; };
type PropsType = { type PropsType = {
state: { state: {
index: number, index: number;
routes: Array<RouteType>, routes: Array<RouteType>;
}, };
descriptors: { descriptors: {
[key: string]: { [key: string]: {
options: { options: {
tabBarLabel: string, tabBarLabel: string;
title: string, title: string;
}, };
}, };
}, };
navigation: StackNavigationProp, navigation: StackNavigationProp<any>;
theme: CustomThemeType, theme: ReactNativePaper.Theme;
}; };
type StateType = { type StateType = {
// eslint-disable-next-line flowtype/no-weak-types translateY: any;
translateY: any,
}; };
type validRoutes = 'proxiwash' | 'services' | 'planning' | 'planex';
const TAB_ICONS = { const TAB_ICONS = {
proxiwash: 'tshirt-crew', proxiwash: 'tshirt-crew',
services: 'account-circle', services: 'account-circle',
@ -70,8 +68,8 @@ const TAB_ICONS = {
class CustomTabBar extends React.Component<PropsType, StateType> { class CustomTabBar extends React.Component<PropsType, StateType> {
static TAB_BAR_HEIGHT = 48; static TAB_BAR_HEIGHT = 48;
constructor() { constructor(props: PropsType) {
super(); super(props);
this.state = { this.state = {
translateY: new Animated.Value(0), translateY: new Animated.Value(0),
}; };
@ -86,13 +84,9 @@ class CustomTabBar extends React.Component<PropsType, StateType> {
*/ */
onItemPress(route: RouteType, currentIndex: number, destIndex: number) { onItemPress(route: RouteType, currentIndex: number, destIndex: number) {
const {navigation} = this.props; const {navigation} = this.props;
const event = navigation.emit({ if (currentIndex !== destIndex) {
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (currentIndex !== destIndex && !event.defaultPrevented)
navigation.navigate(route.name); navigation.navigate(route.name);
}
} }
/** /**
@ -102,13 +96,9 @@ class CustomTabBar extends React.Component<PropsType, StateType> {
*/ */
onItemLongPress(route: RouteType) { onItemLongPress(route: RouteType) {
const {navigation} = this.props; const {navigation} = this.props;
const event = navigation.emit({ if (route.name === 'home') {
type: 'tabLongPress',
target: route.key,
canPreventDefault: true,
});
if (route.name === 'home' && !event.defaultPrevented)
navigation.navigate('game-start'); navigation.navigate('game-start');
}
} }
/** /**
@ -126,11 +116,13 @@ class CustomTabBar extends React.Component<PropsType, StateType> {
* @param focused * @param focused
* @returns {null} * @returns {null}
*/ */
getTabBarIcon = (route: RouteType, focused: boolean): React.Node => { getTabBarIcon = (route: RouteType, focused: boolean) => {
let icon = TAB_ICONS[route.name]; let icon = TAB_ICONS[route.name as validRoutes];
icon = focused ? icon : `${icon}-outline`; icon = focused ? icon : `${icon}-outline`;
if (route.name !== 'home') return icon; if (route.name !== 'home') {
return null; return icon;
}
return '';
}; };
/** /**
@ -141,14 +133,18 @@ class CustomTabBar extends React.Component<PropsType, StateType> {
* @param index The index of the current route * @param index The index of the current route
* @returns {*} * @returns {*}
*/ */
getRenderIcon = (route: RouteType, index: number): React.Node => { getRenderIcon = (route: RouteType, index: number) => {
const {props} = this; const {props} = this;
const {state} = props; const {state} = props;
const {options} = props.descriptors[route.key]; const {options} = props.descriptors[route.key];
let label; let label;
if (options.tabBarLabel != null) label = options.tabBarLabel; if (options.tabBarLabel != null) {
else if (options.title != null) label = options.title; label = options.tabBarLabel;
else label = route.name; } else if (options.title != null) {
label = options.title;
} else {
label = route.name;
}
const onPress = () => { const onPress = () => {
this.onItemPress(route, state.index, index); this.onItemPress(route, state.index, index);
@ -186,7 +182,7 @@ class CustomTabBar extends React.Component<PropsType, StateType> {
); );
}; };
getIcons(): React.Node { getIcons() {
const {props} = this; const {props} = this;
return props.state.routes.map(this.getRenderIcon); return props.state.routes.map(this.getRenderIcon);
} }
@ -209,14 +205,12 @@ class CustomTabBar extends React.Component<PropsType, StateType> {
} }
}; };
render(): React.Node { render() {
const {props, state} = this; const {props, state} = this;
props.navigation.addListener('state', this.onRouteChange); props.navigation.addListener('state', this.onRouteChange);
const icons = this.getIcons(); const icons = this.getIcons();
return ( return (
// $FlowFixMe
<Animated.View <Animated.View
useNativeDriver
style={{ style={{
flexDirection: 'row', flexDirection: 'row',
height: CustomTabBar.TAB_BAR_HEIGHT, height: CustomTabBar.TAB_BAR_HEIGHT,

View file

@ -17,20 +17,18 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {Image, View} from 'react-native'; import {Image, View} from 'react-native';
import {FAB} from 'react-native-paper'; import {FAB} from 'react-native-paper';
import * as Animatable from 'react-native-animatable'; import * as Animatable from 'react-native-animatable';
import FOCUSED_ICON from '../../../assets/tab-icon.png'; const FOCUSED_ICON = require('../../../assets/tab-icon.png');
import UNFOCUSED_ICON from '../../../assets/tab-icon-outline.png'; const UNFOCUSED_ICON = require('../../../assets/tab-icon-outline.png');
type PropsType = { type PropsType = {
focused: boolean, focused: boolean;
onPress: () => void, onPress: () => void;
onLongPress: () => void, onLongPress: () => void;
tabBarHeight: number, tabBarHeight: number;
}; };
const AnimatedFAB = Animatable.createAnimatableComponent(FAB); const AnimatedFAB = Animatable.createAnimatableComponent(FAB);
@ -44,6 +42,7 @@ class TabHomeIcon extends React.Component<PropsType> {
Animatable.initializeRegistryWithDefinitions({ Animatable.initializeRegistryWithDefinitions({
fabFocusIn: { fabFocusIn: {
'0': { '0': {
// @ts-ignore
scale: 1, scale: 1,
translateY: 0, translateY: 0,
}, },
@ -58,6 +57,7 @@ class TabHomeIcon extends React.Component<PropsType> {
}, },
fabFocusOut: { fabFocusOut: {
'0': { '0': {
// @ts-ignore
scale: 1.1, scale: 1.1,
translateY: -6, translateY: -6,
}, },
@ -74,13 +74,7 @@ class TabHomeIcon extends React.Component<PropsType> {
return nextProps.focused !== focused; return nextProps.focused !== focused;
} }
getIconRender = ({ getIconRender = ({size, color}: {size: number; color: string}) => {
size,
color,
}: {
size: number,
color: string,
}): React.Node => {
const {focused} = this.props; const {focused} = this.props;
return ( return (
<Image <Image
@ -94,7 +88,7 @@ class TabHomeIcon extends React.Component<PropsType> {
); );
}; };
render(): React.Node { render() {
const {props} = this; const {props} = this;
return ( return (
<View <View

View file

@ -17,25 +17,21 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {View} from 'react-native'; import {View} from 'react-native';
import {TouchableRipple, withTheme} from 'react-native-paper'; import {TouchableRipple, withTheme} from 'react-native-paper';
import type {MaterialCommunityIconsGlyphs} from 'react-native-vector-icons/MaterialCommunityIcons';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import * as Animatable from 'react-native-animatable'; import * as Animatable from 'react-native-animatable';
import type {CustomThemeType} from '../../managers/ThemeManager';
type PropsType = { type PropsType = {
focused: boolean, focused: boolean;
color: string, color: string;
label: string, label: string;
icon: MaterialCommunityIconsGlyphs, icon: string;
onPress: () => void, onPress: () => void;
onLongPress: () => void, onLongPress: () => void;
theme: CustomThemeType, theme: ReactNativePaper.Theme;
extraData: null | boolean | number | string, extraData: null | boolean | number | string;
}; };
/** /**
@ -49,6 +45,7 @@ class TabIcon extends React.Component<PropsType> {
Animatable.initializeRegistryWithDefinitions({ Animatable.initializeRegistryWithDefinitions({
focusIn: { focusIn: {
'0': { '0': {
// @ts-ignore
scale: 1, scale: 1,
translateY: 0, translateY: 0,
}, },
@ -63,6 +60,7 @@ class TabIcon extends React.Component<PropsType> {
}, },
focusOut: { focusOut: {
'0': { '0': {
// @ts-ignore
scale: 1.2, scale: 1.2,
translateY: 6, translateY: 6,
}, },
@ -88,7 +86,7 @@ class TabIcon extends React.Component<PropsType> {
); );
} }
render(): React.Node { render() {
const {props} = this; const {props} = this;
return ( return (
<TouchableRipple <TouchableRipple
@ -99,7 +97,7 @@ class TabIcon extends React.Component<PropsType> {
style={{ style={{
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
borderRadius: 10 borderRadius: 10,
}}> }}>
<View> <View>
<Animatable.View <Animatable.View