Skip to content

Commit

Permalink
Add some wee animation
Browse files Browse the repository at this point in the history
  • Loading branch information
jonyardley committed Jun 14, 2018
1 parent 4ab0a28 commit 162fbe8
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 96 deletions.
4 changes: 4 additions & 0 deletions src/components/EventList.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class EventList extends Component<Props, State> {
sectionSeparator = () => <View style={styles.sectionSeparator} />;

keyExtractor = getId;
sectionList = null;

renderItem = ({ item }: RenderItemInfo) => {
const {
Expand Down Expand Up @@ -168,6 +169,9 @@ class EventList extends Component<Props, State> {
refreshing={refreshing}
onRefresh={onRefresh}
windowSize={10}
ref={sectionList => {
this.sectionList = sectionList;
}}
/>
);
}
Expand Down
33 changes: 12 additions & 21 deletions src/screens/EventsScreen/FilterHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from "../../constants/colors";
import text from "../../constants/text";
import { formatDateRange } from "../../data/formatters";
import ResetAllFiltersButton from "./ResetAllFiltersButton";

export type Props = {
onFilterCategoriesPress: Function,
Expand All @@ -21,7 +22,8 @@ export type Props = {
onDateFilterButtonPress: () => void,
selectedCategories: Set<EventCategoryName>,
numTagFiltersSelected: number,
resetAllFiltersPress: () => void
resetAllFiltersPress: () => void,
scrollEventListToTop: () => void
};

class FilterHeader extends React.PureComponent<Props> {
Expand All @@ -37,7 +39,8 @@ class FilterHeader extends React.PureComponent<Props> {
onFilterButtonPress,
onDateFilterButtonPress,
numTagFiltersSelected,
resetAllFiltersPress
resetAllFiltersPress,
scrollEventListToTop
} = this.props;
const formattedDateFilter = dateFilter
? formatDateRange(dateFilter)
Expand All @@ -50,17 +53,13 @@ class FilterHeader extends React.PureComponent<Props> {
<View accessibilityTraits={["header"]} style={styles.container}>
<ContentPadding>
<View>
{anyAppliedFilters && (
<View style={styles.clearAllWrapper}>
<FilterHeaderButton
active={false}
text="Reset all filters"
label="Reset all filters"
style={styles.clearAll}
onPress={resetAllFiltersPress}
/>
</View>
)}
<ResetAllFiltersButton
visible={anyAppliedFilters}
onPress={() => {
resetAllFiltersPress();
scrollEventListToTop();
}}
/>
<View testID="event-filter-header" style={styles.content}>
<FilterHeaderCategories
onFilterPress={onFilterCategoriesPress}
Expand Down Expand Up @@ -115,14 +114,6 @@ const styles = StyleSheet.create({
borderLeftWidth: StyleSheet.hairlineWidth,
borderColor: whiteColor,
opacity: 0.4
},
clearAll: {
minHeight: 0,
paddingTop: 16
},
clearAllWrapper: {
flexDirection: "row",
justifyContent: "flex-end"
}
});

Expand Down
27 changes: 18 additions & 9 deletions src/screens/EventsScreen/FilterHeader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const render = (
onFilterButtonPress: () => {},
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
}
) => shallow(<FilterHeader {...props} />);

Expand All @@ -27,7 +28,8 @@ describe("renders correctly", () => {
onFilterButtonPress: () => {},
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
});
expect(output).toMatchSnapshot();
});
Expand All @@ -40,7 +42,8 @@ describe("renders correctly", () => {
onFilterButtonPress: () => {},
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
});
expect(output).toMatchSnapshot();
});
Expand All @@ -53,7 +56,8 @@ describe("renders correctly", () => {
onFilterButtonPress: () => {},
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
});
expect(output).toMatchSnapshot();
});
Expand All @@ -69,7 +73,8 @@ describe("renders correctly", () => {
onFilterButtonPress: () => {},
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
});
expect(output).toMatchSnapshot();
});
Expand All @@ -82,7 +87,8 @@ describe("renders correctly", () => {
onFilterButtonPress: () => {},
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 2
numTagFiltersSelected: 2,
scrollEventListToTop: () => {}
});
expect(output).toMatchSnapshot();
});
Expand All @@ -98,7 +104,8 @@ describe("filter buttons", () => {
onFilterButtonPress: () => {},
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
});
output.find(FilterHeaderCategories).prop("onFilterPress")();

Expand All @@ -114,7 +121,8 @@ describe("filter buttons", () => {
onFilterButtonPress: () => {},
onDateFilterButtonPress: mock,
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
});
const button = output.find(FilterHeaderButton).at(0);
button.simulate("press");
Expand All @@ -131,7 +139,8 @@ describe("filter buttons", () => {
onFilterButtonPress: mock,
onDateFilterButtonPress: () => {},
resetAllFiltersPress: () => {},
numTagFiltersSelected: 0
numTagFiltersSelected: 0,
scrollEventListToTop: () => {}
});
const button = output.find(FilterHeaderButton).at(1);
button.simulate("press");
Expand Down
100 changes: 100 additions & 0 deletions src/screens/EventsScreen/ResetAllFiltersButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// @flow
import React from "react";
import { Animated, StyleSheet, Easing } from "react-native";
import type { ViewLayoutEvent } from "react-native/Libraries/Components/View/ViewPropTypes";
import FilterHeaderButton from "./FilterHeaderButton";

type Props = {
visible: boolean,
onPress: () => void
};

type State = {
isAnimating: boolean
};

const DEFAULT_HEIGHT = 120;
const DEFAULT_FADE_VALUE = 1;
const DEFAULT_TOP_OFFSET_VALUE = 1;

class ResetAllFiltersButton extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
isAnimating: false
};
}

setButtonHeight = (e: ViewLayoutEvent): void => {
const { height } = e.nativeEvent.layout;
this.height = height;
};

fadeOut(): void {
this.props.onPress();
this.setState({ isAnimating: true });

Animated.parallel([
Animated.timing(this.fadeValue, {
toValue: 0,
duration: 200
}),
Animated.timing(this.topOffset, {
toValue: -this.height,
duration: 400,
easing: Easing.out(Easing.quad),
delay: 50
})
]).start(this.animationFinished);
}

reset(): void {
this.topOffset = new Animated.Value(DEFAULT_TOP_OFFSET_VALUE);
this.fadeValue = new Animated.Value(DEFAULT_FADE_VALUE);
}

animationFinished = (): void => {
this.setState({ isAnimating: false });
this.reset();
};

topOffset: Animated.Value = new Animated.Value(DEFAULT_TOP_OFFSET_VALUE);
fadeValue: Animated.Value = new Animated.Value(DEFAULT_FADE_VALUE);
height: number = DEFAULT_HEIGHT;

render() {
const isVisible: boolean = this.state.isAnimating || this.props.visible;
return (
isVisible && (
<Animated.View
onLayout={this.setButtonHeight}
style={[
styles.clearAllWrapper,
{ opacity: this.fadeValue, marginTop: this.topOffset }
]}
>
<FilterHeaderButton
active={false}
text="Reset all filters"
label="Reset all filters"
style={styles.clearAll}
onPress={() => this.fadeOut()}
/>
</Animated.View>
)
);
}
}

const styles = StyleSheet.create({
clearAll: {
minHeight: 0,
paddingTop: 16
},
clearAllWrapper: {
flexDirection: "row",
justifyContent: "flex-end"
}
});

export default ResetAllFiltersButton;
86 changes: 20 additions & 66 deletions src/screens/EventsScreen/__snapshots__/FilterHeader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ exports[`renders correctly with any date and any time (empty time set) 1`] = `
style={Object {}}
>
<Component>
<ResetAllFiltersButton
onPress={[Function]}
visible={false}
/>
<Component
style={
Object {
Expand Down Expand Up @@ -99,6 +103,10 @@ exports[`renders correctly with any date and any time 1`] = `
style={Object {}}
>
<Component>
<ResetAllFiltersButton
onPress={[Function]}
visible={false}
/>
<Component
style={
Object {
Expand Down Expand Up @@ -180,28 +188,10 @@ exports[`renders correctly with date range and two times 1`] = `
style={Object {}}
>
<Component>
<Component
style={
Object {
"flexDirection": "row",
"justifyContent": "flex-end",
}
}
>
<FilterHeaderButton
active={false}
badgeValue={null}
label="Reset all filters"
onPress={[Function]}
style={
Object {
"minHeight": 0,
"paddingTop": 16,
}
}
text="Reset all filters"
/>
</Component>
<ResetAllFiltersButton
onPress={[Function]}
visible={true}
/>
<Component
style={
Object {
Expand Down Expand Up @@ -283,28 +273,10 @@ exports[`renders correctly with single date and single time 1`] = `
style={Object {}}
>
<Component>
<Component
style={
Object {
"flexDirection": "row",
"justifyContent": "flex-end",
}
}
>
<FilterHeaderButton
active={false}
badgeValue={null}
label="Reset all filters"
onPress={[Function]}
style={
Object {
"minHeight": 0,
"paddingTop": 16,
}
}
text="Reset all filters"
/>
</Component>
<ResetAllFiltersButton
onPress={[Function]}
visible={true}
/>
<Component
style={
Object {
Expand Down Expand Up @@ -386,28 +358,10 @@ exports[`renders correctly with tag filters selected 1`] = `
style={Object {}}
>
<Component>
<Component
style={
Object {
"flexDirection": "row",
"justifyContent": "flex-end",
}
}
>
<FilterHeaderButton
active={false}
badgeValue={null}
label="Reset all filters"
onPress={[Function]}
style={
Object {
"minHeight": 0,
"paddingTop": 16,
}
}
text="Reset all filters"
/>
</Component>
<ResetAllFiltersButton
onPress={[Function]}
visible={true}
/>
<Component
style={
Object {
Expand Down
Loading

0 comments on commit 162fbe8

Please sign in to comment.