mirror of
https://github.com/zimplexing/OrionTV.git
synced 2026-02-04 03:36:29 +08:00
119 lines
3.7 KiB
TypeScript
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,
|
|
},
|
|
});
|