From 9d92a886278ba1cf25c483d12ae8134981d8554a Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Mon, 3 Aug 2020 16:45:10 +0200 Subject: [PATCH] Improve animated components to match linter --- .../Animations/AnimatedAccordion.js | 171 +++++----- .../Animations/AnimatedBottomBar.js | 318 +++++++++--------- src/components/Animations/AnimatedFAB.js | 109 +++--- 3 files changed, 308 insertions(+), 290 deletions(-) diff --git a/src/components/Animations/AnimatedAccordion.js b/src/components/Animations/AnimatedAccordion.js index 9cc7dba..18e324c 100644 --- a/src/components/Animations/AnimatedAccordion.js +++ b/src/components/Animations/AnimatedAccordion.js @@ -1,101 +1,114 @@ // @flow import * as React from 'react'; -import {View} from "react-native"; +import {View} from 'react-native'; import {List, withTheme} from 'react-native-paper'; -import Collapsible from "react-native-collapsible"; -import * as Animatable from "react-native-animatable"; -import type {CustomTheme} from "../../managers/ThemeManager"; +import Collapsible from 'react-native-collapsible'; +import * as Animatable from 'react-native-animatable'; +import type {CustomTheme} from '../../managers/ThemeManager'; -type Props = { - theme: CustomTheme, - title: string, - subtitle?: string, - left?: (props: { [keys: string]: any }) => React.Node, - opened?: boolean, - unmountWhenCollapsed: boolean, - children?: React.Node, -} +type PropsType = { + theme: CustomTheme, + title: string, + subtitle?: string, + left?: () => React.Node, + opened?: boolean, + unmountWhenCollapsed?: boolean, + children?: React.Node, +}; -type State = { - expanded: boolean, -} +type StateType = { + expanded: boolean, +}; const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon); -class AnimatedAccordion extends React.Component { +class AnimatedAccordion extends React.Component { + static defaultProps = { + subtitle: '', + left: null, + opened: null, + unmountWhenCollapsed: false, + children: null, + }; - static defaultProps = { - unmountWhenCollapsed: false, - } - chevronRef: { current: null | AnimatedListIcon }; - chevronIcon: string; - animStart: string; - animEnd: string; + chevronRef: {current: null | AnimatedListIcon}; - state = { - expanded: this.props.opened != null ? this.props.opened : false, - } + chevronIcon: string; - constructor(props) { - super(props); - this.chevronRef = React.createRef(); - this.setupChevron(); - } + animStart: string; - setupChevron() { - if (this.state.expanded) { - this.chevronIcon = "chevron-up"; - this.animStart = "180deg"; - this.animEnd = "0deg"; - } else { - this.chevronIcon = "chevron-down"; - this.animStart = "0deg"; - this.animEnd = "180deg"; - } - } + animEnd: string; - toggleAccordion = () => { - if (this.chevronRef.current != null) { - this.chevronRef.current.transitionTo({rotate: this.state.expanded ? this.animStart : this.animEnd}); - this.setState({expanded: !this.state.expanded}) - } + constructor(props: PropsType) { + super(props); + this.state = { + expanded: props.opened != null ? props.opened : false, }; + this.chevronRef = React.createRef(); + this.setupChevron(); + } - shouldComponentUpdate(nextProps: Props, nextState: State): boolean { - if (nextProps.opened != null && nextProps.opened !== this.props.opened) - this.state.expanded = nextProps.opened; - return true; + shouldComponentUpdate(nextProps: PropsType): boolean { + const {state, props} = this; + if (nextProps.opened != null && nextProps.opened !== props.opened) + state.expanded = nextProps.opened; + return true; + } + + setupChevron() { + const {state} = this; + if (state.expanded) { + this.chevronIcon = 'chevron-up'; + this.animStart = '180deg'; + this.animEnd = '0deg'; + } else { + this.chevronIcon = 'chevron-down'; + this.animStart = '0deg'; + this.animEnd = '180deg'; } + } - render() { - const colors = this.props.theme.colors; - return ( - - } - left={this.props.left} - /> - - {!this.props.unmountWhenCollapsed || (this.props.unmountWhenCollapsed && this.state.expanded) - ? this.props.children - : null} - - - ); + toggleAccordion = () => { + const {state} = this; + if (this.chevronRef.current != null) { + this.chevronRef.current.transitionTo({ + rotate: state.expanded ? this.animStart : this.animEnd, + }); + this.setState({expanded: !state.expanded}); } + }; + render(): React.Node { + const {props, state} = this; + const {colors} = props.theme; + return ( + + ( + + )} + left={props.left} + /> + + {!props.unmountWhenCollapsed || + (props.unmountWhenCollapsed && state.expanded) + ? props.children + : null} + + + ); + } } -export default withTheme(AnimatedAccordion); \ No newline at end of file +export default withTheme(AnimatedAccordion); diff --git a/src/components/Animations/AnimatedBottomBar.js b/src/components/Animations/AnimatedBottomBar.js index 6f37815..1471171 100644 --- a/src/components/Animations/AnimatedBottomBar.js +++ b/src/components/Animations/AnimatedBottomBar.js @@ -1,170 +1,178 @@ // @flow import * as React from 'react'; -import {StyleSheet, View} from "react-native"; -import {FAB, IconButton, Surface, withTheme} from "react-native-paper"; -import AutoHideHandler from "../../utils/AutoHideHandler"; +import {StyleSheet, View} from 'react-native'; +import {FAB, IconButton, Surface, withTheme} from 'react-native-paper'; import * as Animatable from 'react-native-animatable'; -import CustomTabBar from "../Tabbar/CustomTabBar"; -import {StackNavigationProp} from "@react-navigation/stack"; -import type {CustomTheme} from "../../managers/ThemeManager"; +import {StackNavigationProp} from '@react-navigation/stack'; +import AutoHideHandler from '../../utils/AutoHideHandler'; +import CustomTabBar from '../Tabbar/CustomTabBar'; +import type {CustomTheme} from '../../managers/ThemeManager'; const AnimatedFAB = Animatable.createAnimatableComponent(FAB); -type Props = { - navigation: StackNavigationProp, - theme: CustomTheme, - onPress: (action: string, data: any) => void, - seekAttention: boolean, -} +type PropsType = { + navigation: StackNavigationProp, + theme: CustomTheme, + onPress: (action: string, data?: string) => void, + seekAttention: boolean, +}; -type State = { - currentMode: string, -} +type StateType = { + currentMode: string, +}; const DISPLAY_MODES = { - DAY: "agendaDay", - WEEK: "agendaWeek", - MONTH: "month", -} - -class AnimatedBottomBar extends React.Component { - - ref: { current: null | Animatable.View }; - hideHandler: AutoHideHandler; - - displayModeIcons: { [key: string]: string }; - - state = { - currentMode: DISPLAY_MODES.WEEK, - } - - constructor() { - super(); - this.ref = React.createRef(); - this.hideHandler = new AutoHideHandler(false); - this.hideHandler.addListener(this.onHideChange); - - this.displayModeIcons = {}; - this.displayModeIcons[DISPLAY_MODES.DAY] = "calendar-text"; - this.displayModeIcons[DISPLAY_MODES.WEEK] = "calendar-week"; - this.displayModeIcons[DISPLAY_MODES.MONTH] = "calendar-range"; - } - - shouldComponentUpdate(nextProps: Props, nextState: State) { - return (nextProps.seekAttention !== this.props.seekAttention) - || (nextState.currentMode !== this.state.currentMode); - } - - onHideChange = (shouldHide: boolean) => { - if (this.ref.current != null) { - if (shouldHide) - this.ref.current.fadeOutDown(500); - else - this.ref.current.fadeInUp(500); - } - } - - onScroll = (event: SyntheticEvent) => { - this.hideHandler.onScroll(event); - }; - - changeDisplayMode = () => { - let newMode; - switch (this.state.currentMode) { - case DISPLAY_MODES.DAY: - newMode = DISPLAY_MODES.WEEK; - break; - case DISPLAY_MODES.WEEK: - newMode = DISPLAY_MODES.MONTH; - - break; - case DISPLAY_MODES.MONTH: - newMode = DISPLAY_MODES.DAY; - break; - } - this.setState({currentMode: newMode}); - this.props.onPress("changeView", newMode); - }; - - render() { - const buttonColor = this.props.theme.colors.primary; - return ( - - - - this.props.navigation.navigate('group-select')} - /> - - - - this.props.onPress('today', undefined)}/> - - - this.props.onPress('prev', undefined)}/> - this.props.onPress('next', undefined)}/> - - - - ); - } -} + DAY: 'agendaDay', + WEEK: 'agendaWeek', + MONTH: 'month', +}; const styles = StyleSheet.create({ - container: { - position: 'absolute', - left: '5%', - width: '90%', - }, - surface: { - position: 'relative', - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - borderRadius: 50, - elevation: 2, - }, - fabContainer: { - position: "absolute", - left: 0, - right: 0, - alignItems: "center", - width: '100%', - height: '100%' - }, - fab: { - position: 'absolute', - alignSelf: 'center', - top: '-25%', - } + container: { + position: 'absolute', + left: '5%', + width: '90%', + }, + surface: { + position: 'relative', + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + borderRadius: 50, + elevation: 2, + }, + fabContainer: { + position: 'absolute', + left: 0, + right: 0, + alignItems: 'center', + width: '100%', + height: '100%', + }, + fab: { + position: 'absolute', + alignSelf: 'center', + top: '-25%', + }, }); +class AnimatedBottomBar extends React.Component { + ref: {current: null | Animatable.View}; + + hideHandler: AutoHideHandler; + + displayModeIcons: {[key: string]: string}; + + constructor() { + super(); + this.state = { + currentMode: DISPLAY_MODES.WEEK, + }; + this.ref = React.createRef(); + this.hideHandler = new AutoHideHandler(false); + this.hideHandler.addListener(this.onHideChange); + + this.displayModeIcons = {}; + this.displayModeIcons[DISPLAY_MODES.DAY] = 'calendar-text'; + this.displayModeIcons[DISPLAY_MODES.WEEK] = 'calendar-week'; + this.displayModeIcons[DISPLAY_MODES.MONTH] = 'calendar-range'; + } + + shouldComponentUpdate(nextProps: PropsType, nextState: StateType): boolean { + const {props, state} = this; + return ( + nextProps.seekAttention !== props.seekAttention || + nextState.currentMode !== state.currentMode + ); + } + + onHideChange = (shouldHide: boolean) => { + if (this.ref.current != null) { + if (shouldHide) this.ref.current.fadeOutDown(500); + else this.ref.current.fadeInUp(500); + } + }; + + onScroll = (event: SyntheticEvent) => { + this.hideHandler.onScroll(event); + }; + + changeDisplayMode = () => { + const {props, state} = this; + let newMode; + switch (state.currentMode) { + case DISPLAY_MODES.DAY: + newMode = DISPLAY_MODES.WEEK; + break; + case DISPLAY_MODES.WEEK: + newMode = DISPLAY_MODES.MONTH; + break; + case DISPLAY_MODES.MONTH: + newMode = DISPLAY_MODES.DAY; + break; + default: + newMode = DISPLAY_MODES.WEEK; + break; + } + this.setState({currentMode: newMode}); + props.onPress('changeView', newMode); + }; + + render(): React.Node { + const {props, state} = this; + const buttonColor = props.theme.colors.primary; + return ( + + + + props.navigation.navigate('group-select')} + /> + + + + props.onPress('today')} + /> + + + props.onPress('prev')} + /> + props.onPress('next')} + /> + + + + ); + } +} + export default withTheme(AnimatedBottomBar); diff --git a/src/components/Animations/AnimatedFAB.js b/src/components/Animations/AnimatedFAB.js index 24ff02f..8af28fc 100644 --- a/src/components/Animations/AnimatedFAB.js +++ b/src/components/Animations/AnimatedFAB.js @@ -1,66 +1,63 @@ // @flow import * as React from 'react'; -import {StyleSheet} from "react-native"; -import {FAB} from "react-native-paper"; -import AutoHideHandler from "../../utils/AutoHideHandler"; +import {StyleSheet} from 'react-native'; +import {FAB} from 'react-native-paper'; import * as Animatable from 'react-native-animatable'; -import CustomTabBar from "../Tabbar/CustomTabBar"; -import {StackNavigationProp} from "@react-navigation/stack"; +import AutoHideHandler from '../../utils/AutoHideHandler'; +import CustomTabBar from '../Tabbar/CustomTabBar'; -type Props = { - navigation: StackNavigationProp, - icon: string, - onPress: () => void, -} +type PropsType = { + icon: string, + onPress: () => void, +}; const AnimatedFab = Animatable.createAnimatableComponent(FAB); -export default class AnimatedFAB extends React.Component { - - ref: { current: null | Animatable.View }; - hideHandler: AutoHideHandler; - - constructor() { - super(); - this.ref = React.createRef(); - this.hideHandler = new AutoHideHandler(false); - this.hideHandler.addListener(this.onHideChange); - } - - onScroll = (event: SyntheticEvent) => { - this.hideHandler.onScroll(event); - }; - - onHideChange = (shouldHide: boolean) => { - if (this.ref.current != null) { - if (shouldHide) - this.ref.current.bounceOutDown(1000); - else - this.ref.current.bounceInUp(1000); - } - } - - render() { - return ( - - ); - } -} - const styles = StyleSheet.create({ - fab: { - position: 'absolute', - margin: 16, - right: 0, - }, + fab: { + position: 'absolute', + margin: 16, + right: 0, + }, }); + +export default class AnimatedFAB extends React.Component { + ref: {current: null | Animatable.View}; + + hideHandler: AutoHideHandler; + + constructor() { + super(); + this.ref = React.createRef(); + this.hideHandler = new AutoHideHandler(false); + this.hideHandler.addListener(this.onHideChange); + } + + onScroll = (event: SyntheticEvent) => { + this.hideHandler.onScroll(event); + }; + + onHideChange = (shouldHide: boolean) => { + if (this.ref.current != null) { + if (shouldHide) this.ref.current.bounceOutDown(1000); + else this.ref.current.bounceInUp(1000); + } + }; + + render(): React.Node { + const {props} = this; + return ( + + ); + } +}