Files
OrionTV/app/play.tsx
zimplexing 5b4c8db317 Add Prettier configuration and refactor code for consistent formatting
- Introduced a .prettierrc file to standardize code formatting.
- Updated import statements and JSX attributes in NotFoundScreen, HomeScreen, PlayScreen, and PlayerControls for consistent use of double quotes.
- Refactored styles in various components to use double quotes for string values.
- Added SeekingBar component to enhance video playback experience.
2025-07-08 16:58:06 +08:00

112 lines
3.4 KiB
TypeScript

import React, { useEffect, useRef } from "react";
import { View, StyleSheet, TouchableOpacity, ActivityIndicator } from "react-native";
import { useLocalSearchParams } from "expo-router";
import { Video, ResizeMode } from "expo-av";
import { useKeepAwake } from "expo-keep-awake";
import { ThemedView } from "@/components/ThemedView";
import { PlayerControls } from "@/components/PlayerControls";
import { EpisodeSelectionModal } from "@/components/EpisodeSelectionModal";
import { SeekingBar } from "@/components/SeekingBar";
import { NextEpisodeOverlay } from "@/components/NextEpisodeOverlay";
import { LoadingOverlay } from "@/components/LoadingOverlay";
import usePlayerStore from "@/stores/playerStore";
import { useTVRemoteHandler } from "@/hooks/useTVRemoteHandler";
export default function PlayScreen() {
const videoRef = useRef<Video>(null);
useKeepAwake();
const { source, id, episodeIndex, position } = useLocalSearchParams<{
source: string;
id: string;
episodeIndex: string;
position: string;
}>();
const {
detail,
episodes,
currentEpisodeIndex,
isLoading,
showControls,
showEpisodeModal,
showNextEpisodeOverlay,
initialPosition,
setVideoRef,
loadVideo,
playEpisode,
togglePlayPause,
seek,
handlePlaybackStatusUpdate,
setShowControls,
setShowEpisodeModal,
setShowNextEpisodeOverlay,
reset,
} = usePlayerStore();
useEffect(() => {
setVideoRef(videoRef);
if (source && id) {
loadVideo(source, id, parseInt(episodeIndex || "0", 10), parseInt(position || "0", 10));
}
return () => {
reset(); // Reset state when component unmounts
};
}, [source, id, episodeIndex, position, setVideoRef, loadVideo, reset]);
const { onScreenPress } = useTVRemoteHandler();
if (!detail && isLoading) {
return (
<ThemedView style={[styles.container, styles.centered]}>
<ActivityIndicator size="large" color="#fff" />
</ThemedView>
);
}
const currentEpisode = episodes[currentEpisodeIndex];
return (
<ThemedView focusable style={styles.container}>
<TouchableOpacity activeOpacity={1} style={styles.videoContainer} onPress={onScreenPress}>
<Video
ref={videoRef}
style={styles.videoPlayer}
source={{ uri: currentEpisode?.url }}
resizeMode={ResizeMode.CONTAIN}
onPlaybackStatusUpdate={handlePlaybackStatusUpdate}
onLoad={() => {
if (initialPosition > 0) {
videoRef.current?.setPositionAsync(initialPosition);
}
usePlayerStore.setState({ isLoading: false });
}}
onLoadStart={() => usePlayerStore.setState({ isLoading: true })}
useNativeControls={false}
shouldPlay
/>
{showControls && <PlayerControls showControls={showControls} setShowControls={setShowControls} />}
<SeekingBar />
<LoadingOverlay visible={isLoading} />
<NextEpisodeOverlay visible={showNextEpisodeOverlay} onCancel={() => setShowNextEpisodeOverlay(false)} />
</TouchableOpacity>
<EpisodeSelectionModal />
</ThemedView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "black" },
centered: { flex: 1, justifyContent: "center", alignItems: "center" },
videoContainer: {
...StyleSheet.absoluteFillObject,
},
videoPlayer: {
...StyleSheet.absoluteFillObject,
},
});