Application Android et IOS pour l'amicale des élèves
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AnimatedBottomBar.tsx 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import * as React from 'react';
  20. import {
  21. NativeScrollEvent,
  22. NativeSyntheticEvent,
  23. StyleSheet,
  24. View,
  25. } from 'react-native';
  26. import {FAB, IconButton, Surface, withTheme} from 'react-native-paper';
  27. import * as Animatable from 'react-native-animatable';
  28. import {StackNavigationProp} from '@react-navigation/stack';
  29. import AutoHideHandler from '../../utils/AutoHideHandler';
  30. import CustomTabBar from '../Tabbar/CustomTabBar';
  31. const AnimatedFAB = Animatable.createAnimatableComponent(FAB);
  32. type PropsType = {
  33. navigation: StackNavigationProp<any>;
  34. theme: ReactNativePaper.Theme;
  35. onPress: (action: string, data?: string) => void;
  36. seekAttention: boolean;
  37. };
  38. type StateType = {
  39. currentMode: string;
  40. };
  41. const DISPLAY_MODES = {
  42. DAY: 'agendaDay',
  43. WEEK: 'agendaWeek',
  44. MONTH: 'month',
  45. };
  46. const styles = StyleSheet.create({
  47. container: {
  48. position: 'absolute',
  49. left: '5%',
  50. width: '90%',
  51. },
  52. surface: {
  53. position: 'relative',
  54. flexDirection: 'row',
  55. justifyContent: 'space-between',
  56. alignItems: 'center',
  57. borderRadius: 50,
  58. elevation: 2,
  59. },
  60. fabContainer: {
  61. position: 'absolute',
  62. left: 0,
  63. right: 0,
  64. alignItems: 'center',
  65. width: '100%',
  66. height: '100%',
  67. },
  68. fab: {
  69. position: 'absolute',
  70. alignSelf: 'center',
  71. top: '-25%',
  72. },
  73. });
  74. class AnimatedBottomBar extends React.Component<PropsType, StateType> {
  75. ref: {current: null | (Animatable.View & View)};
  76. hideHandler: AutoHideHandler;
  77. displayModeIcons: {[key: string]: string};
  78. constructor(props: PropsType) {
  79. super(props);
  80. this.state = {
  81. currentMode: DISPLAY_MODES.WEEK,
  82. };
  83. this.ref = React.createRef();
  84. this.hideHandler = new AutoHideHandler(false);
  85. this.hideHandler.addListener(this.onHideChange);
  86. this.displayModeIcons = {};
  87. this.displayModeIcons[DISPLAY_MODES.DAY] = 'calendar-text';
  88. this.displayModeIcons[DISPLAY_MODES.WEEK] = 'calendar-week';
  89. this.displayModeIcons[DISPLAY_MODES.MONTH] = 'calendar-range';
  90. }
  91. shouldComponentUpdate(nextProps: PropsType, nextState: StateType): boolean {
  92. const {props, state} = this;
  93. return (
  94. nextProps.seekAttention !== props.seekAttention ||
  95. nextState.currentMode !== state.currentMode
  96. );
  97. }
  98. onHideChange = (shouldHide: boolean) => {
  99. const ref = this.ref;
  100. if (ref && ref.current && ref.current.fadeOutDown && ref.current.fadeInUp) {
  101. if (shouldHide) {
  102. ref.current.fadeOutDown(500);
  103. } else {
  104. ref.current.fadeInUp(500);
  105. }
  106. }
  107. };
  108. onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
  109. this.hideHandler.onScroll(event);
  110. };
  111. changeDisplayMode = () => {
  112. const {props, state} = this;
  113. let newMode;
  114. switch (state.currentMode) {
  115. case DISPLAY_MODES.DAY:
  116. newMode = DISPLAY_MODES.WEEK;
  117. break;
  118. case DISPLAY_MODES.WEEK:
  119. newMode = DISPLAY_MODES.MONTH;
  120. break;
  121. case DISPLAY_MODES.MONTH:
  122. newMode = DISPLAY_MODES.DAY;
  123. break;
  124. default:
  125. newMode = DISPLAY_MODES.WEEK;
  126. break;
  127. }
  128. this.setState({currentMode: newMode});
  129. props.onPress('changeView', newMode);
  130. };
  131. render() {
  132. const {props, state} = this;
  133. const buttonColor = props.theme.colors.primary;
  134. return (
  135. <Animatable.View
  136. ref={this.ref}
  137. useNativeDriver
  138. style={{
  139. ...styles.container,
  140. bottom: 10 + CustomTabBar.TAB_BAR_HEIGHT,
  141. }}>
  142. <Surface style={styles.surface}>
  143. <View style={styles.fabContainer}>
  144. <AnimatedFAB
  145. animation={props.seekAttention ? 'bounce' : undefined}
  146. easing="ease-out"
  147. iterationDelay={500}
  148. iterationCount="infinite"
  149. useNativeDriver
  150. style={styles.fab}
  151. icon="account-clock"
  152. onPress={(): void => props.navigation.navigate('group-select')}
  153. />
  154. </View>
  155. <View style={{flexDirection: 'row'}}>
  156. <IconButton
  157. icon={this.displayModeIcons[state.currentMode]}
  158. color={buttonColor}
  159. onPress={this.changeDisplayMode}
  160. />
  161. <IconButton
  162. icon="clock-in"
  163. color={buttonColor}
  164. style={{marginLeft: 5}}
  165. onPress={(): void => props.onPress('today')}
  166. />
  167. </View>
  168. <View style={{flexDirection: 'row'}}>
  169. <IconButton
  170. icon="chevron-left"
  171. color={buttonColor}
  172. onPress={(): void => props.onPress('prev')}
  173. />
  174. <IconButton
  175. icon="chevron-right"
  176. color={buttonColor}
  177. style={{marginLeft: 5}}
  178. onPress={(): void => props.onPress('next')}
  179. />
  180. </View>
  181. </Surface>
  182. </Animatable.View>
  183. );
  184. }
  185. }
  186. export default withTheme(AnimatedBottomBar);