Created
February 13, 2020 20:09
-
-
Save daveham/e3860b18fba64d9dbf26b55790d025cb to your computer and use it in GitHub Desktop.
My animation attempt at TextNumbers/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// External Dependencies | |
import { ActivityIndicator, Divider } from 'react-native-paper'; | |
import { Animated, StyleSheet, View } from 'react-native'; | |
import { DrawerItems } from 'react-navigation-drawer'; | |
import { NavigationContext } from 'react-navigation'; | |
import React, { useContext, useEffect, useRef, useState } from 'react'; | |
import { useSelector, useDispatch } from 'react-redux'; | |
// Internal Dependencies | |
import { changeParamsConversations } from '../state/conversations/actions'; | |
import { changeParamsTextNumbers } from '../state/text-numbers/actions'; | |
import { | |
isGetting as isGettingTextNumbersSelector, | |
textNumbers as textNumbersSelector, | |
textNumbersData as textNumbersDataSelector, | |
} from '../state/text-numbers/selectors'; | |
import ListItem from '../shared/ListItem'; | |
import ListSubheader from '../shared/ListSubheader'; | |
import { theme } from '../shared'; | |
import usePrevious from '../shared/usePreviousHook'; | |
// local variables | |
const itemHeight = 48.5; | |
// Component Definition | |
const TextNumbers = (props) => { | |
const dispatch = useDispatch(); | |
const navigation = useContext(NavigationContext); | |
const emptyNumbers = []; | |
const textNumbers = useSelector(textNumbersSelector) || emptyNumbers; | |
const textNumbersData = useSelector(textNumbersDataSelector); | |
const isGettingTextNumbers = useSelector(isGettingTextNumbersSelector); | |
const [isShowingMore, setIsShowingMore] = useState(false); | |
const lowerSizeLimit = useRef(0); | |
const upperSizeLimit = useRef(0); | |
// Keep a separate copy of the text numbers for when we need to render | |
// prior batch while animating "out" of view. | |
const [renderedNumbers, setRenderedNumbers] = useState(textNumbers); | |
const textNumbersLength = textNumbers.length; | |
const previousNumbersLength = usePrevious(textNumbersLength); | |
const animation = useRef(new Animated.Value(0)).current; | |
useEffect(() => { | |
if (textNumbersLength === previousNumbersLength) { | |
return; | |
} | |
if (isShowingMore) { | |
if (textNumbersLength) { | |
upperSizeLimit.current = textNumbers.length * itemHeight; | |
} else { | |
upperSizeLimit.current = lowerSizeLimit.current; | |
} | |
setRenderedNumbers([...textNumbers]); | |
animation.setValue(lowerSizeLimit.current); | |
// Animated.spring(animation, { | |
// toValue: upperSizeLimit.current, | |
// overshootClamping: true, | |
// bounciness: 6, | |
// speed: 4, | |
// }).start(); | |
Animated.timing(animation, { | |
duration: 350, | |
toValue: upperSizeLimit.current, | |
}).start(); | |
} else { | |
if (textNumbersLength) { | |
lowerSizeLimit.current = textNumbers.length * itemHeight; | |
} | |
if (!renderedNumbers.length) { | |
setRenderedNumbers([...textNumbers]); | |
} | |
animation.setValue(upperSizeLimit.current); | |
// Animated.spring(animation, { | |
// toValue: lowerSizeLimit.current, | |
// overshootClamping: true, | |
// bounciness: 6, | |
// speed: 4, | |
// }).start(() => { | |
// setRenderedNumbers([...textNumbers]); | |
// }); | |
Animated.timing(animation, { | |
duration: 350, | |
toValue: lowerSizeLimit.current, | |
}).start(() => { | |
setRenderedNumbers([...textNumbers]); | |
}); | |
} | |
}, [isShowingMore, textNumbers]); | |
const handleNavigate = (route, params) => () => { | |
// TODO: Once more routes are create, create a default function that | |
// calls the 'navigate' function | |
dispatch(changeParamsConversations(params)); | |
return navigation.closeDrawer(); | |
}; | |
const renderTextNumbers = () => { | |
if (!textNumbers) return null; | |
return renderedNumbers.map((textNumber) => ( | |
<ListItem | |
key={textNumber.TextNumberID} | |
label={textNumber.Name || textNumber.TextPhoneNumber} | |
leftIcon={textNumber.FlatRateConversation ? 'infinity' : 'deskphone'} | |
count={textNumber.UnreadCount > 99 ? '99+' : textNumber.UnreadCount} | |
onPress={handleNavigate('Home', { | |
textNumberId: textNumber.TextNumberID, | |
})} | |
style={styles.item} | |
/> | |
)); | |
}; | |
const toggleShowMore = () => { | |
if (isShowingMore) { | |
setIsShowingMore(false); | |
dispatch(changeParamsTextNumbers({ pagesize: 5 })); | |
} else { | |
setIsShowingMore(true); | |
dispatch(changeParamsTextNumbers({ pagesize: textNumbersData.Size })); | |
} | |
}; | |
const renderListItem = () => { | |
if (!textNumbersData || textNumbersData.Size < 4) return null; | |
// this is the value as measured from phone number items in the list | |
return isGettingTextNumbers ? ( | |
<ActivityIndicator | |
animating | |
color={theme.colors.primary} | |
style={styles.item} | |
/> | |
) : ( | |
<ListItem | |
iconSize={24} | |
label={isShowingMore ? 'Show Less' : 'Show More'} | |
leftIcon={isShowingMore ? 'chevron-up' : 'chevron-down'} | |
onPress={() => toggleShowMore()} | |
style={styles.item} | |
/> | |
); | |
}; | |
// eslint-disable-next-line | |
const navigationDrawerItems = <DrawerItems {...props} />; | |
return ( | |
<View> | |
<Divider /> | |
<ListSubheader text="Text Numbers" /> | |
<Animated.View style={[styles.numbersContainer, { height: animation }]}> | |
{renderTextNumbers()} | |
</Animated.View> | |
{renderListItem()} | |
<Divider /> | |
</View> | |
); | |
}; | |
const styles = StyleSheet.create({ | |
item: { | |
height: itemHeight, | |
}, | |
numbersContainer: { | |
overflow: 'hidden', | |
backgroundColor: theme.colors.surface, | |
}, | |
}); | |
export default TextNumbers; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment