Files
OrionTV/components/EpisodeSelectionModal.tsx
zimplexing 08e24dd748 Refactor components to use Zustand for state management
- Updated EpisodeSelectionModal to utilize Zustand for episode selection state.
- Refactored PlayerControls to manage playback state and controls using Zustand.
- Simplified SettingsModal to handle settings state with Zustand.
- Introduced homeStore for managing home screen categories and content data.
- Created playerStore for managing video playback and episode details.
- Added settingsStore for managing API settings and modal visibility.
- Updated package.json to include Zustand as a dependency.
- Cleaned up code formatting and improved readability across components.
2025-07-06 20:45:42 +08:00

159 lines
4.7 KiB
TypeScript

import React from 'react';
import { View, Text, StyleSheet, Modal, FlatList, Pressable, TouchableOpacity } from 'react-native';
import usePlayerStore from '@/stores/playerStore';
import { useState } from 'react';
interface Episode {
title?: string;
url: string;
}
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) => (
<TouchableOpacity
key={groupIndex}
style={[
styles.episodeGroupButton,
selectedEpisodeGroup === groupIndex && styles.episodeGroupButtonSelected,
]}
onPress={() => setSelectedEpisodeGroup(groupIndex)}
>
<Text style={styles.episodeGroupButtonText}>
{`${groupIndex * episodeGroupSize + 1}-${Math.min(
(groupIndex + 1) * episodeGroupSize,
episodes.length
)}`}
</Text>
</TouchableOpacity>
))}
</View>
)}
<FlatList
data={episodes.slice(
selectedEpisodeGroup * episodeGroupSize,
(selectedEpisodeGroup + 1) * episodeGroupSize
)}
numColumns={5}
keyExtractor={(_, index) => `episode-${selectedEpisodeGroup * episodeGroupSize + index}`}
renderItem={({ item, index }) => {
const absoluteIndex = selectedEpisodeGroup * episodeGroupSize + index;
return (
<Pressable
style={({ focused }) => [
styles.episodeItem,
currentEpisodeIndex === absoluteIndex && styles.episodeItemSelected,
focused && styles.focusedButton,
]}
onPress={() => onSelectEpisode(absoluteIndex)}
hasTVPreferredFocus={currentEpisodeIndex === absoluteIndex}
>
<Text style={styles.episodeItemText}>{item.title || `${absoluteIndex + 1}`}</Text>
</Pressable>
);
}}
/>
<Pressable style={({ focused }) => [styles.closeButton, focused && styles.focusedButton]} onPress={onClose}>
<Text style={{ color: 'white' }}></Text>
</Pressable>
</View>
</View>
</Modal>
);
};
const styles = StyleSheet.create({
modalContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
backgroundColor: 'transparent',
},
modalContent: {
width: 400,
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.85)',
padding: 20,
},
modalTitle: {
color: 'white',
marginBottom: 20,
textAlign: 'center',
fontSize: 18,
fontWeight: 'bold',
},
episodeItem: {
backgroundColor: '#333',
paddingVertical: 12,
borderRadius: 8,
margin: 4,
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
episodeItemSelected: {
backgroundColor: '#007bff',
},
episodeItemText: {
color: 'white',
fontSize: 14,
},
episodeGroupContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
marginBottom: 15,
paddingHorizontal: 10,
},
episodeGroupButton: {
backgroundColor: '#444',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 15,
margin: 5,
},
episodeGroupButtonSelected: {
backgroundColor: '#007bff',
},
episodeGroupButtonText: {
color: 'white',
fontSize: 12,
},
closeButton: {
backgroundColor: '#333',
padding: 15,
borderRadius: 8,
alignItems: 'center',
marginTop: 20,
},
focusedButton: {
backgroundColor: 'rgba(119, 119, 119, 0.9)',
transform: [{ scale: 1.1 }],
},
});