Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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 { TAB_BAR_HEIGHT } 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. side: {
  74. flexDirection: 'row',
  75. },
  76. icon: {
  77. marginLeft: 5,
  78. },
  79. });
  80. class AnimatedBottomBar extends React.Component<PropsType, StateType> {
  81. ref: { current: null | (Animatable.View & View) };
  82. hideHandler: AutoHideHandler;
  83. displayModeIcons: { [key: string]: string };
  84. constructor(props: PropsType) {
  85. super(props);
  86. this.state = {
  87. currentMode: DISPLAY_MODES.WEEK,
  88. };
  89. this.ref = React.createRef();
  90. this.hideHandler = new AutoHideHandler(false);
  91. this.hideHandler.addListener(this.onHideChange);
  92. this.displayModeIcons = {};
  93. this.displayModeIcons[DISPLAY_MODES.DAY] = 'calendar-text';
  94. this.displayModeIcons[DISPLAY_MODES.WEEK] = 'calendar-week';
  95. this.displayModeIcons[DISPLAY_MODES.MONTH] = 'calendar-range';
  96. }
  97. shouldComponentUpdate(nextProps: PropsType, nextState: StateType): boolean {
  98. const { props, state } = this;
  99. return (
  100. nextProps.seekAttention !== props.seekAttention ||
  101. nextState.currentMode !== state.currentMode
  102. );
  103. }
  104. onHideChange = (shouldHide: boolean) => {
  105. const ref = this.ref;
  106. if (ref && ref.current && ref.current.fadeOutDown && ref.current.fadeInUp) {
  107. if (shouldHide) {
  108. ref.current.fadeOutDown(500);
  109. } else {
  110. ref.current.fadeInUp(500);
  111. }
  112. }
  113. };
  114. onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
  115. this.hideHandler.onScroll(event);
  116. };
  117. changeDisplayMode = () => {
  118. const { props, state } = this;
  119. let newMode;
  120. switch (state.currentMode) {
  121. case DISPLAY_MODES.DAY:
  122. newMode = DISPLAY_MODES.WEEK;
  123. break;
  124. case DISPLAY_MODES.WEEK:
  125. newMode = DISPLAY_MODES.MONTH;
  126. break;
  127. case DISPLAY_MODES.MONTH:
  128. newMode = DISPLAY_MODES.DAY;
  129. break;
  130. default:
  131. newMode = DISPLAY_MODES.WEEK;
  132. break;
  133. }
  134. this.setState({ currentMode: newMode });
  135. props.onPress('changeView', newMode);
  136. };
  137. render() {
  138. const { props, state } = this;
  139. const buttonColor = props.theme.colors.primary;
  140. return (
  141. <Animatable.View
  142. ref={this.ref}
  143. useNativeDriver
  144. style={{
  145. ...styles.container,
  146. bottom: 10 + TAB_BAR_HEIGHT,
  147. }}
  148. >
  149. <Surface style={styles.surface}>
  150. <View style={styles.fabContainer}>
  151. <AnimatedFAB
  152. animation={props.seekAttention ? 'bounce' : undefined}
  153. easing="ease-out"
  154. iterationDelay={500}
  155. iterationCount="infinite"
  156. useNativeDriver
  157. style={styles.fab}
  158. icon="account-clock"
  159. onPress={() => props.navigation.navigate('group-select')}
  160. />
  161. </View>
  162. <View style={styles.side}>
  163. <IconButton
  164. icon={this.displayModeIcons[state.currentMode]}
  165. color={buttonColor}
  166. onPress={this.changeDisplayMode}
  167. />
  168. <IconButton
  169. icon="clock-in"
  170. color={buttonColor}
  171. style={styles.icon}
  172. onPress={() => props.onPress('today')}
  173. />
  174. </View>
  175. <View style={styles.side}>
  176. <IconButton
  177. icon="chevron-left"
  178. color={buttonColor}
  179. onPress={() => props.onPress('prev')}
  180. />
  181. <IconButton
  182. icon="chevron-right"
  183. color={buttonColor}
  184. style={styles.icon}
  185. onPress={() => props.onPress('next')}
  186. />
  187. </View>
  188. </Surface>
  189. </Animatable.View>
  190. );
  191. }
  192. }
  193. export default withTheme(AnimatedBottomBar);