Files
OrionTV/components/EpisodeSelectionModal.tsx

119 lines
3.7 KiB
TypeScript

import React, { useState } from "react";
import { View, Text, StyleSheet, Modal, FlatList } from "react-native";
import { StyledButton } from "./StyledButton";
import usePlayerStore from "@/stores/playerStore";
interface EpisodeSelectionModalProps {}
export const EpisodeSelectionModal: React.FC<EpisodeSelectionModalProps> = () => {
const { showEpisodeModal, episodes, currentEpisodeIndex, playEpisode, setShowEpisodeModal } = usePlayerStore();
const [episodeGroupSize] = useState(30);
const [selectedEpisodeGroup, setSelectedEpisodeGroup] = useState(Math.floor(currentEpisodeIndex / episodeGroupSize));
const onSelectEpisode = (index: number) => {
playEpisode(index);
setShowEpisodeModal(false);
};
const onClose = () => {
setShowEpisodeModal(false);
};
return (
<Modal visible={showEpisodeModal} transparent={true} animationType="slide" onRequestClose={onClose}>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}></Text>
{episodes.length > episodeGroupSize && (
<View style={styles.episodeGroupContainer}>
{Array.from({ length: Math.ceil(episodes.length / episodeGroupSize) }, (_, groupIndex) => (
<StyledButton
key={groupIndex}
text={`${groupIndex * episodeGroupSize + 1}-${Math.min(
(groupIndex + 1) * episodeGroupSize,
episodes.length
)}`}
onPress={() => setSelectedEpisodeGroup(groupIndex)}
isSelected={selectedEpisodeGroup === groupIndex}
style={styles.episodeGroupButton}
textStyle={styles.episodeGroupButtonText}
/>
))}
</View>
)}
<FlatList
data={episodes.slice(
selectedEpisodeGroup * episodeGroupSize,
(selectedEpisodeGroup + 1) * episodeGroupSize
)}
numColumns={5}
contentContainerStyle={styles.episodeList}
keyExtractor={(_, index) => `episode-${selectedEpisodeGroup * episodeGroupSize + index}`}
renderItem={({ item, index }) => {
const absoluteIndex = selectedEpisodeGroup * episodeGroupSize + index;
return (
<StyledButton
text={item.title || `${absoluteIndex + 1}`}
onPress={() => onSelectEpisode(absoluteIndex)}
isSelected={currentEpisodeIndex === absoluteIndex}
hasTVPreferredFocus={currentEpisodeIndex === absoluteIndex}
style={styles.episodeItem}
textStyle={styles.episodeItemText}
/>
);
}}
/>
</View>
</View>
</Modal>
);
};
const styles = StyleSheet.create({
modalContainer: {
flex: 1,
flexDirection: "row",
justifyContent: "flex-end",
backgroundColor: "transparent",
},
modalContent: {
width: 600,
height: "100%",
backgroundColor: "rgba(0, 0, 0, 0.85)",
padding: 20,
},
modalTitle: {
color: "white",
marginBottom: 12,
textAlign: "center",
fontSize: 18,
fontWeight: "bold",
},
episodeList: {
justifyContent: "flex-start",
},
episodeItem: {
paddingVertical: 2,
margin: 4,
width: "18%",
},
episodeItemText: {
fontSize: 14,
},
episodeGroupContainer: {
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "center",
paddingHorizontal: 10,
},
episodeGroupButton: {
paddingHorizontal: 6,
margin: 8,
},
episodeGroupButtonText: {
fontSize: 12,
},
});