Update custom tab bar to use TypeScript
This commit is contained in:
parent
e4adcd0057
commit
5261e85254
3 changed files with 63 additions and 77 deletions
|
@ -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,
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in a new issue