Add "performant" recent album view
This commit is contained in:
87
src/components/AlphabetScroller.tsx
Normal file
87
src/components/AlphabetScroller.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import { ALPHABET_LETTERS } from 'CONSTANTS';
|
||||
import { View, LayoutChangeEvent } from 'react-native';
|
||||
import { TouchableWithoutFeedback, PanGestureHandler, PanGestureHandlerGestureEvent, TapGestureHandler, TapGestureHandlerGestureEvent } from 'react-native-gesture-handler';
|
||||
|
||||
interface LetterContainerProps {
|
||||
onPress: (letter: string) => void;
|
||||
letter: string;
|
||||
}
|
||||
|
||||
const LetterContainer: React.FC<LetterContainerProps> = ({ children, letter, onPress }) => {
|
||||
const handlePress = useCallback(() => {
|
||||
onPress(letter);
|
||||
}, [letter, onPress]);
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={handlePress}>
|
||||
{children}
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
};
|
||||
|
||||
const Container = styled.View`
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
padding: 5px;
|
||||
margin: auto 0;
|
||||
justify-content: space-around;
|
||||
`;
|
||||
|
||||
const Letter = styled.Text`
|
||||
text-align: center;
|
||||
padding: 1px 0;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
onSelect: (index: number) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic component that introduces a scrolling bar on the right side of the
|
||||
* screen with all letters of the Alphabet.
|
||||
*/
|
||||
const AlphabetScroller: React.FC<Props> = ({ onSelect }) => {
|
||||
const [ height, setHeight ] = useState(0);
|
||||
const [ index, setIndex ] = useState<number>();
|
||||
|
||||
// Handler for setting the correct height for a single alphabet item
|
||||
const handleLayout = useCallback((event: LayoutChangeEvent) => {
|
||||
setHeight(event.nativeEvent.layout.height);
|
||||
}, []);
|
||||
|
||||
// Handler for passing on a new index when it is tapped or swiped
|
||||
const handleGestureEvent = useCallback((event: PanGestureHandlerGestureEvent | TapGestureHandlerGestureEvent) => {
|
||||
const newIndex = Math.floor(event.nativeEvent.y / height);
|
||||
|
||||
if (newIndex !== index) {
|
||||
setIndex(newIndex);
|
||||
onSelect(newIndex);
|
||||
}
|
||||
}, [height, index]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<TapGestureHandler onHandlerStateChange={handleGestureEvent}>
|
||||
<PanGestureHandler onGestureEvent={handleGestureEvent}>
|
||||
<View>
|
||||
{ALPHABET_LETTERS.split('').map((l, i) => (
|
||||
<View
|
||||
key={l}
|
||||
onLayout={i === 0 ? handleLayout : undefined}
|
||||
>
|
||||
<Letter>{l}</Letter>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</PanGestureHandler>
|
||||
</TapGestureHandler>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default AlphabetScroller;
|
||||
Reference in New Issue
Block a user