Files
jellyfin-audio-player/src/components/AlphabetScroller.tsx

93 lines
3.0 KiB
TypeScript
Raw Normal View History

import React, { useCallback, useState } from 'react';
2020-06-25 18:07:44 +02:00
import styled from 'styled-components/native';
import { ALPHABET_LETTERS } from '@/CONSTANTS';
2020-06-25 18:07:44 +02:00
import { View, LayoutChangeEvent } from 'react-native';
import {
PanGestureHandler,
PanGestureHandlerGestureEvent,
TapGestureHandler,
TapGestureHandlerGestureEvent
} from 'react-native-gesture-handler';
import useDefaultStyles from './Colors';
2025-05-24 00:32:50 +02:00
import { useNavigationOffsets } from './SafeNavigatorView';
2020-06-25 18:07:44 +02:00
// interface LetterContainerProps {
// onPress: (letter: string) => void;
// letter: string;
// }
2020-06-25 18:07:44 +02:00
const Container = styled.View`
position: absolute;
2025-05-24 00:32:50 +02:00
right: 0;
2020-06-25 18:07:44 +02:00
z-index: 10;
margin: auto 0;
2025-05-24 00:32:50 +02:00
justify-content: center;
align-items: center;
2020-06-25 18:07:44 +02:00
`;
2025-05-24 00:32:50 +02:00
const Letter = styled.Text<{ isSelected?: boolean }>`
2020-06-25 18:07:44 +02:00
text-align: center;
2025-05-24 00:32:50 +02:00
padding: 1.5px 10px;
2020-07-05 22:26:36 +02:00
font-size: 12px;
2020-06-25 18:07:44 +02:00
`;
interface Props {
onSelect: (selected: { index: number, letter: string }) => void;
2020-06-25 18:07:44 +02:00
}
/**
* 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 styles = useDefaultStyles();
2020-06-25 18:07:44 +02:00
const [ height, setHeight ] = useState(0);
const [ index, setIndex ] = useState<number>();
2025-05-24 00:32:50 +02:00
const { top, bottom } = useNavigationOffsets();
2020-06-25 18:07:44 +02:00
// 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) => {
2025-05-24 00:32:50 +02:00
const { y } = event.nativeEvent;
const newIndex = Math.min(
Math.max(0, Math.floor(y / height)),
ALPHABET_LETTERS.length - 1
);
2020-06-25 18:07:44 +02:00
if (newIndex !== index) {
setIndex(newIndex);
onSelect({ index: newIndex, letter: ALPHABET_LETTERS[newIndex] });
2020-06-25 18:07:44 +02:00
}
2020-07-05 22:26:36 +02:00
}, [height, index, onSelect]);
2020-06-25 18:07:44 +02:00
return (
2025-05-24 00:32:50 +02:00
<Container style={{ top, bottom }}>
2020-06-25 18:07:44 +02:00
<TapGestureHandler onHandlerStateChange={handleGestureEvent}>
<PanGestureHandler onGestureEvent={handleGestureEvent}>
<View>
{ALPHABET_LETTERS.split('').map((l, i) => (
<View
key={l}
onLayout={i === 0 ? handleLayout : undefined}
>
2025-05-24 00:32:50 +02:00
<Letter
style={styles.themeColor}
isSelected={i === index}
>
{l}
</Letter>
2020-06-25 18:07:44 +02:00
</View>
))}
</View>
</PanGestureHandler>
</TapGestureHandler>
</Container>
);
};
export default AlphabetScroller;