diff --git a/package.json b/package.json index 10eec8f..728bc22 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "@react-native-community/masked-view": "0.1.6", "@react-navigation/bottom-tabs": "^5.1.1", "@react-navigation/drawer": "^5.1.1", - "@react-navigation/material-bottom-tabs": "^5.1.1", "@react-navigation/native": "^5.0.9", "@react-navigation/stack": "^5.1.1", "expo": "^37.0.0", diff --git a/src/components/Sidebar/Sidebar.js b/src/components/Sidebar/Sidebar.js index 7068c44..8368b14 100644 --- a/src/components/Sidebar/Sidebar.js +++ b/src/components/Sidebar/Sidebar.js @@ -192,7 +192,7 @@ class SideBar extends React.Component { try { const state = event.data.state.routes[0].state; // Get the Drawer's state if it exists // Get the current route name. This will only show Drawer routes. - // Tab routes will be shown as 'Main' + // Tabbar routes will be shown as 'Main' const routeName = state.routeNames[state.index]; if (this.state.activeRoute !== routeName) this.setState({activeRoute: routeName}); diff --git a/src/components/Tabbar/CustomTabBar.js b/src/components/Tabbar/CustomTabBar.js new file mode 100644 index 0000000..c3829b4 --- /dev/null +++ b/src/components/Tabbar/CustomTabBar.js @@ -0,0 +1,81 @@ +import * as React from 'react'; +import {View} from "react-native"; +import {withTheme} from 'react-native-paper'; +import TabIcon from "./TabIcon"; +import TabHomeIcon from "./TabHomeIcon"; + +type Props = { + state: Object, + descriptors: Object, + navigation: Object, + theme: Object, +} + +const TAB_BAR_HEIGHT = 48; + +/** + * Abstraction layer for Agenda component, using custom configuration + */ +class CustomTabBar extends React.Component { + + render() { + const state = this.props.state; + const descriptors = this.props.descriptors; + const navigation = this.props.navigation; + return ( + + {state.routes.map((route, index) => { + const {options} = descriptors[route.key]; + const label = + options.tabBarLabel !== undefined + ? options.tabBarLabel + : options.title !== undefined + ? options.title + : route.name; + + const isFocused = state.index === index; + + const onPress = () => { + const event = navigation.emit({ + type: 'tabPress', + target: route.key, + canPreventDefault: true, + }); + + if (!isFocused && !event.defaultPrevented) { + navigation.navigate(route.name); + } + }; + + const onLongPress = () => { + navigation.emit({ + type: 'tabLongPress', + target: route.key, + }); + }; + + const color = isFocused ? options.activeColor : options.inactiveColor; + const iconData = {focused: isFocused, color: color}; + if (route.name !== "home") { + return + } else + return + })} + + ); + } +} + +export default withTheme(CustomTabBar); diff --git a/src/components/Tabbar/TabHomeIcon.js b/src/components/Tabbar/TabHomeIcon.js new file mode 100644 index 0000000..27ac954 --- /dev/null +++ b/src/components/Tabbar/TabHomeIcon.js @@ -0,0 +1,79 @@ +// @flow + +import * as React from 'react'; +import {View} from "react-native"; +import {FAB, withTheme} from 'react-native-paper'; +import * as Animatable from "react-native-animatable"; + +type Props = { + focused: boolean, + onPress: Function, + onLongPress: Function, + theme: Object, +} + +const AnimatedFAB = Animatable.createAnimatableComponent(FAB); + +/** + * Abstraction layer for Agenda component, using custom configuration + */ +class TabHomeIcon extends React.Component { + + focusedIcon = require('../../../assets/tab-icon.png'); + unFocusedIcon = require('../../../assets/tab-icon-outline.png'); + + constructor(props) { + super(props); + Animatable.initializeRegistryWithDefinitions({ + fabFocusIn: { + "0": { + scale: 1, translateY: 0 + }, + "0.9": { + scale: 1.4, translateY: -6 + }, + "1": { + scale: 1.3, translateY: -5 + }, + }, + fabFocusOut: { + "0": { + scale: 1.3, translateY: -5 + }, + "1": { + scale: 1, translateY: 0 + }, + } + }); + } + + shouldComponentUpdate(nextProps: Props): boolean { + return (nextProps.focused !== this.props.focused); + } + + render(): React$Node { + const props = this.props; + return ( + + + + ); + } + +} + +export default withTheme(TabHomeIcon); \ No newline at end of file diff --git a/src/components/Tabbar/TabIcon.js b/src/components/Tabbar/TabIcon.js new file mode 100644 index 0000000..d65f925 --- /dev/null +++ b/src/components/Tabbar/TabIcon.js @@ -0,0 +1,111 @@ +// @flow + +import * as React from 'react'; +import {View} from "react-native"; +import {TouchableRipple, withTheme} from 'react-native-paper'; +import {MaterialCommunityIcons} from "@expo/vector-icons"; +import * as Animatable from "react-native-animatable"; + +type Props = { + focused: boolean, + color: string, + label: string, + icon: string, + onPress: Function, + onLongPress: Function, + theme: Object, +} + +const AnimatedIcon = Animatable.createAnimatableComponent(MaterialCommunityIcons); + + +/** + * Abstraction layer for Agenda component, using custom configuration + */ +class TabIcon extends React.Component { + + firstRender: boolean; + + constructor(props) { + super(props); + Animatable.initializeRegistryWithDefinitions({ + focusIn: { + "0": { + scale: 1, translateY: 0 + }, + "0.9": { + scale: 1.6, translateY: 6 + }, + "1": { + scale: 1.5, translateY: 5 + }, + }, + focusOut: { + "0": { + scale: 1.5, translateY: 5 + }, + "1": { + scale: 1, translateY: 0 + }, + } + }); + this.firstRender = true; + } + + componentDidMount() { + this.firstRender = false; + } + + shouldComponentUpdate(nextProps: Props): boolean { + return (nextProps.focused !== this.props.focused) + || (nextProps.theme.dark !== this.props.theme.dark); + } + + render(): React$Node { + const props = this.props; + return ( + + + + + + + {props.label} + + + + ); + } +} + +export default withTheme(TabIcon); \ No newline at end of file diff --git a/src/navigation/MainTabNavigator.js b/src/navigation/MainTabNavigator.js index 26a826e..a7a4b10 100644 --- a/src/navigation/MainTabNavigator.js +++ b/src/navigation/MainTabNavigator.js @@ -1,6 +1,6 @@ import * as React from 'react'; import {createStackNavigator, TransitionPresets} from '@react-navigation/stack'; -import {createMaterialBottomTabNavigator} from "@react-navigation/material-bottom-tabs"; +import {createBottomTabNavigator} from "@react-navigation/bottom-tabs"; import HomeScreen from '../screens/HomeScreen'; import PlanningScreen from '../screens/Planning/PlanningScreen'; @@ -11,9 +11,8 @@ import ProximoMainScreen from '../screens/Proximo/ProximoMainScreen'; import ProximoListScreen from "../screens/Proximo/ProximoListScreen"; import ProximoAboutScreen from "../screens/Proximo/ProximoAboutScreen"; import PlanexScreen from '../screens/Websites/PlanexScreen'; -import {MaterialCommunityIcons} from "@expo/vector-icons"; import AsyncStorageManager from "../managers/AsyncStorageManager"; -import {FAB, useTheme, withTheme} from 'react-native-paper'; +import {useTheme, withTheme} from 'react-native-paper'; import i18n from "i18n-js"; import ClubDisplayScreen from "../screens/Amicale/Clubs/ClubDisplayScreen"; import ScannerScreen from "../screens/ScannerScreen"; @@ -21,6 +20,7 @@ import MaterialHeaderButtons, {Item} from "../components/Custom/HeaderButton"; import FeedItemScreen from "../screens/FeedItemScreen"; import {createCollapsibleStack} from "react-navigation-collapsible"; import GroupSelectionScreen from "../screens/GroupSelectionScreen"; +import CustomTabBar from "../components/Tabbar/CustomTabBar"; const TAB_ICONS = { home: 'triangle', @@ -306,7 +306,7 @@ function PlanexStackComponent() { ); } -const Tab = createMaterialBottomTabNavigator(); +const Tab = createBottomTabNavigator(); type Props = { defaultRoute: string | null, @@ -329,16 +329,6 @@ class TabNavigator extends React.Component { this.createHomeStackComponent = () => HomeStackComponent(props.defaultRoute, props.defaultData); } - getHomeButton(focused: boolean) { - let icon = focused ? require('../../assets/tab-icon.png') : require('../../assets/tab-icon-outline.png') - return ( - - ); - } - render() { return ( { let icon = TAB_ICONS[route.name]; icon = focused ? icon : icon + ('-outline'); if (route.name !== "home") - return ; + return icon; else - return this.getHomeButton(focused); + return null; }, - tabBarLabel: route.name !== 'home' ? undefined : '' + tabBarLabel: route.name !== 'home' ? undefined : '', + activeColor: this.props.theme.colors.primary, + inactiveColor: this.props.theme.colors.tabIcon })} - activeColor={this.props.theme.colors.primary} - inactiveColor={this.props.theme.colors.tabIcon} + tabBar={props => } >