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.
This commit is contained in:
zimplexing
2025-07-08 16:58:06 +08:00
parent bd22fa2996
commit 5b4c8db317
9 changed files with 333 additions and 268 deletions

View File

@@ -1,8 +1,8 @@
import { create } from 'zustand';
import { AVPlaybackStatus, Video } from 'expo-av';
import { RefObject } from 'react';
import { api, VideoDetail as ApiVideoDetail } from '@/services/api';
import { PlayRecordManager } from '@/services/storage';
import { create } from "zustand";
import { AVPlaybackStatus, Video } from "expo-av";
import { RefObject } from "react";
import { api, VideoDetail as ApiVideoDetail } from "@/services/api";
import { PlayRecordManager } from "@/services/storage";
interface Episode {
url: string;
@@ -10,7 +10,7 @@ interface Episode {
}
interface VideoDetail {
videoInfo: ApiVideoDetail['videoInfo'];
videoInfo: ApiVideoDetail["videoInfo"];
episodes: Episode[];
}
@@ -32,13 +32,14 @@ interface PlayerState {
loadVideo: (source: string, id: string, episodeIndex: number, position?: number) => Promise<void>;
playEpisode: (index: number) => void;
togglePlayPause: () => void;
seek: (forward: boolean) => void;
seek: (duration: number) => void;
handlePlaybackStatusUpdate: (newStatus: AVPlaybackStatus) => void;
setLoading: (loading: boolean) => void;
setShowControls: (show: boolean) => void;
setShowEpisodeModal: (show: boolean) => void;
setShowNextEpisodeOverlay: (show: boolean) => void;
reset: () => void;
_seekTimeout?: NodeJS.Timeout;
}
const usePlayerStore = create<PlayerState>((set, get) => ({
@@ -48,13 +49,14 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
currentEpisodeIndex: 0,
status: null,
isLoading: true,
showControls: true,
showControls: false,
showEpisodeModal: false,
showNextEpisodeOverlay: false,
isSeeking: false,
seekPosition: 0,
progressPosition: 0,
initialPosition: 0,
_seekTimeout: undefined,
setVideoRef: (ref) => set({ videoRef: ref }),
@@ -84,7 +86,13 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
playEpisode: (index) => {
const { episodes, videoRef } = get();
if (index >= 0 && index < episodes.length) {
set({ currentEpisodeIndex: index, showNextEpisodeOverlay: false, initialPosition: 0 });
set({
currentEpisodeIndex: index,
showNextEpisodeOverlay: false,
initialPosition: 0,
progressPosition: 0,
seekPosition: 0,
});
videoRef?.current?.replayAsync();
}
},
@@ -100,39 +108,49 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
}
},
seek: (forward) => {
seek: (duration) => {
const { status, videoRef } = get();
if (status?.isLoaded) {
const newPosition = status.positionMillis + (forward ? 15000 : -15000);
videoRef?.current?.setPositionAsync(Math.max(0, newPosition));
if (!status?.isLoaded || !status.durationMillis) return;
const newPosition = Math.max(0, Math.min(status.positionMillis + duration, status.durationMillis));
videoRef?.current?.setPositionAsync(newPosition);
set({
isSeeking: true,
seekPosition: newPosition / status.durationMillis,
});
if (get()._seekTimeout) {
clearTimeout(get()._seekTimeout);
}
const timeoutId = setTimeout(() => set({ isSeeking: false }), 1000);
set({ _seekTimeout: timeoutId });
},
handlePlaybackStatusUpdate: (newStatus) => {
set({ status: newStatus });
if (!newStatus.isLoaded) {
if (newStatus.error) {
console.error(`Playback Error: ${newStatus.error}`);
}
set({ status: newStatus });
return;
}
const progressPosition = newStatus.durationMillis ? newStatus.positionMillis / newStatus.durationMillis : 0;
set({ status: newStatus, progressPosition });
const { detail, currentEpisodeIndex, episodes } = get();
if (detail && newStatus.durationMillis) {
const { videoInfo } = detail;
PlayRecordManager.save(
videoInfo.source,
videoInfo.id,
{
title: videoInfo.title,
cover: videoInfo.cover || '',
index: currentEpisodeIndex,
total_episodes: episodes.length,
play_time: newStatus.positionMillis,
total_time: newStatus.durationMillis,
source_name: videoInfo.source_name,
}
);
PlayRecordManager.save(videoInfo.source, videoInfo.id, {
title: videoInfo.title,
cover: videoInfo.cover || "",
index: currentEpisodeIndex,
total_episodes: episodes.length,
play_time: newStatus.positionMillis,
total_time: newStatus.durationMillis,
source_name: videoInfo.source_name,
});
const isNearEnd = newStatus.positionMillis / newStatus.durationMillis > 0.95;
if (isNearEnd && currentEpisodeIndex < episodes.length - 1) {
@@ -142,13 +160,13 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
}
}
if (newStatus.didJustFinish) {
const { playEpisode, currentEpisodeIndex, episodes } = get();
if (currentEpisodeIndex < episodes.length - 1) {
playEpisode(currentEpisodeIndex + 1);
}
const { playEpisode, currentEpisodeIndex, episodes } = get();
if (currentEpisodeIndex < episodes.length - 1) {
playEpisode(currentEpisodeIndex + 1);
}
}
},
setLoading: (loading) => set({ isLoading: loading }),
setShowControls: (show) => set({ showControls: show }),
setShowEpisodeModal: (show) => set({ showEpisodeModal: show }),
@@ -161,7 +179,7 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
currentEpisodeIndex: 0,
status: null,
isLoading: true,
showControls: true,
showControls: false,
showEpisodeModal: false,
showNextEpisodeOverlay: false,
initialPosition: 0,
@@ -169,4 +187,4 @@ const usePlayerStore = create<PlayerState>((set, get) => ({
},
}));
export default usePlayerStore;
export default usePlayerStore;