mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
Enhance AndroidVideoPlayer component with dynamic resize mode support
This update introduces a new optional prop for resize mode in the AndroidVideoPlayer component, allowing users to specify how the video should be displayed. The default resize mode is set to 'contain', and the component now supports cycling through various resize modes. Additionally, the PlayerControls component has been updated to reflect the current resize mode, improving user interaction and experience.
This commit is contained in:
parent
0ab9ce19c0
commit
1605d5251e
6 changed files with 40 additions and 30 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
import Video, { VideoRef, SelectedTrack, BufferingStrategyType } from 'react-native-video';
|
||||
import Video, { VideoRef, SelectedTrack, BufferingStrategyType, ResizeMode } from 'react-native-video';
|
||||
|
||||
interface VideoPlayerProps {
|
||||
src: string;
|
||||
|
|
@ -9,6 +9,7 @@ interface VideoPlayerProps {
|
|||
currentTime: number;
|
||||
selectedAudioTrack?: SelectedTrack;
|
||||
selectedTextTrack?: SelectedTrack;
|
||||
resizeMode?: ResizeMode;
|
||||
onProgress?: (data: { currentTime: number; playableDuration: number }) => void;
|
||||
onLoad?: (data: { duration: number }) => void;
|
||||
onError?: (error: any) => void;
|
||||
|
|
@ -24,6 +25,7 @@ export const AndroidVideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||
currentTime,
|
||||
selectedAudioTrack,
|
||||
selectedTextTrack,
|
||||
resizeMode = 'contain' as ResizeMode,
|
||||
onProgress,
|
||||
onLoad,
|
||||
onError,
|
||||
|
|
@ -93,7 +95,7 @@ export const AndroidVideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||
onBuffer={handleBuffer}
|
||||
onError={handleError}
|
||||
onEnd={handleEnd}
|
||||
resizeMode="contain"
|
||||
resizeMode={resizeMode}
|
||||
controls={false}
|
||||
playInBackground={false}
|
||||
playWhenInactive={false}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
const [selectedAudioTrack, setSelectedAudioTrack] = useState<number | null>(null);
|
||||
const [textTracks, setTextTracks] = useState<TextTrack[]>([]);
|
||||
const [selectedTextTrack, setSelectedTextTrack] = useState<number>(-1);
|
||||
const [resizeMode, setResizeMode] = useState<ResizeModeType>('stretch');
|
||||
const [resizeMode, setResizeMode] = useState<ResizeModeType>('contain');
|
||||
const [buffered, setBuffered] = useState(0);
|
||||
const [seekTime, setSeekTime] = useState<number | null>(null);
|
||||
const videoRef = useRef<VideoRef>(null);
|
||||
|
|
@ -526,13 +526,14 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
};
|
||||
|
||||
const cycleAspectRatio = () => {
|
||||
const newZoom = zoomScale === 1.1 ? 1 : 1.1;
|
||||
setZoomScale(newZoom);
|
||||
setZoomTranslateX(0);
|
||||
setZoomTranslateY(0);
|
||||
setLastZoomScale(newZoom);
|
||||
setLastTranslateX(0);
|
||||
setLastTranslateY(0);
|
||||
// Android: cycle through native resize modes
|
||||
const resizeModes: ResizeModeType[] = ['contain', 'cover', 'stretch', 'none'];
|
||||
const currentIndex = resizeModes.indexOf(resizeMode);
|
||||
const nextIndex = (currentIndex + 1) % resizeModes.length;
|
||||
setResizeMode(resizeModes[nextIndex]);
|
||||
if (DEBUG_MODE) {
|
||||
logger.log(`[AndroidVideoPlayer] Resize mode changed to: ${resizeModes[nextIndex]}`);
|
||||
}
|
||||
};
|
||||
|
||||
const enableImmersiveMode = () => {
|
||||
|
|
@ -1081,6 +1082,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
currentTime={currentTime}
|
||||
duration={duration}
|
||||
zoomScale={zoomScale}
|
||||
currentResizeMode={resizeMode}
|
||||
vlcAudioTracks={rnVideoAudioTracks}
|
||||
selectedAudioTrack={selectedAudioTrack}
|
||||
availableStreams={availableStreams}
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ const VideoPlayer: React.FC = () => {
|
|||
isSeeking.current = false;
|
||||
if (DEBUG_MODE) {
|
||||
logger.log(`[VideoPlayer] Android seek completed to ${timeInSeconds.toFixed(2)}s`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
} else {
|
||||
|
|
@ -659,11 +659,11 @@ const VideoPlayer: React.FC = () => {
|
|||
|
||||
// If video is already loaded and ready, seek immediately
|
||||
if (isPlayerReady && duration > 0 && vlcRef.current) {
|
||||
seekToTime(resumePosition);
|
||||
seekToTime(resumePosition);
|
||||
} else {
|
||||
// Otherwise, set initial position for when video loads
|
||||
setInitialPosition(resumePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ interface PlayerControlsProps {
|
|||
currentTime: number;
|
||||
duration: number;
|
||||
zoomScale: number;
|
||||
currentResizeMode?: string;
|
||||
vlcAudioTracks: Array<{id: number, name: string, language?: string}>;
|
||||
selectedAudioTrack: number | null;
|
||||
availableStreams?: { [providerId: string]: { streams: any[]; addonName: string } };
|
||||
|
|
@ -55,6 +56,7 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
|
|||
currentTime,
|
||||
duration,
|
||||
zoomScale,
|
||||
currentResizeMode,
|
||||
vlcAudioTracks,
|
||||
selectedAudioTrack,
|
||||
availableStreams,
|
||||
|
|
@ -178,7 +180,11 @@ export const PlayerControls: React.FC<PlayerControlsProps> = ({
|
|||
<TouchableOpacity style={styles.bottomButton} onPress={cycleAspectRatio}>
|
||||
<Ionicons name="resize" size={20} color="white" />
|
||||
<Text style={[styles.bottomButtonText, { fontSize: 14, textAlign: 'center' }]}>
|
||||
{zoomScale === 1.1 ? 'Fill' : 'Cover'}
|
||||
{currentResizeMode ?
|
||||
(currentResizeMode === 'none' ? 'Original' :
|
||||
currentResizeMode.charAt(0).toUpperCase() + currentResizeMode.slice(1)) :
|
||||
(zoomScale === 1.1 ? 'Fill' : 'Cover')
|
||||
}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
|
|
|
|||
|
|
@ -369,10 +369,10 @@ export function useTraktIntegration() {
|
|||
|
||||
updatePromises.push(
|
||||
storageService.mergeWithTraktProgress(
|
||||
id,
|
||||
type,
|
||||
item.progress,
|
||||
item.paused_at,
|
||||
id,
|
||||
type,
|
||||
item.progress,
|
||||
item.paused_at,
|
||||
episodeId,
|
||||
exactTime
|
||||
)
|
||||
|
|
@ -391,10 +391,10 @@ export function useTraktIntegration() {
|
|||
|
||||
updatePromises.push(
|
||||
storageService.mergeWithTraktProgress(
|
||||
id,
|
||||
'movie',
|
||||
100, // 100% progress for watched items
|
||||
watchedAt
|
||||
id,
|
||||
'movie',
|
||||
100, // 100% progress for watched items
|
||||
watchedAt
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ class StorageService {
|
|||
|
||||
// Only notify if we have subscribers
|
||||
if (this.watchProgressSubscribers.length > 0) {
|
||||
this.watchProgressSubscribers.forEach(callback => callback());
|
||||
this.watchProgressSubscribers.forEach(callback => callback());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,16 +394,16 @@ class StorageService {
|
|||
}
|
||||
}
|
||||
|
||||
const updatedProgress: WatchProgress = {
|
||||
const updatedProgress: WatchProgress = {
|
||||
...localProgress,
|
||||
currentTime,
|
||||
duration,
|
||||
lastUpdated: traktTimestamp,
|
||||
traktSynced: true,
|
||||
traktLastSynced: Date.now(),
|
||||
traktProgress
|
||||
};
|
||||
await this.setWatchProgress(id, type, updatedProgress, episodeId);
|
||||
lastUpdated: traktTimestamp,
|
||||
traktSynced: true,
|
||||
traktLastSynced: Date.now(),
|
||||
traktProgress
|
||||
};
|
||||
await this.setWatchProgress(id, type, updatedProgress, episodeId);
|
||||
|
||||
// Only log significant changes
|
||||
if (progressDiff > 10 || traktProgress === 100) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue