chore(sample): refactor sample code to follow rn best practices (#3990)
Co-authored-by: Olivier Bouillet <62574056+freeboub@users.noreply.github.com>
This commit is contained in:
parent
8ef2df1bac
commit
7611da155f
@ -1,39 +1,39 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React, {FC, useCallback, useRef, useState} from 'react';
|
import React, {type FC, useCallback, useRef, useState} from 'react';
|
||||||
|
|
||||||
import {TouchableOpacity, View} from 'react-native';
|
import {Platform, TouchableOpacity, View} from 'react-native';
|
||||||
|
|
||||||
import Video, {
|
import Video, {
|
||||||
AudioTrack,
|
|
||||||
OnAudioTracksData,
|
|
||||||
OnLoadData,
|
|
||||||
OnProgressData,
|
|
||||||
OnTextTracksData,
|
|
||||||
OnVideoAspectRatioData,
|
|
||||||
TextTrack,
|
|
||||||
OnBufferData,
|
|
||||||
OnAudioFocusChangedData,
|
|
||||||
OnVideoErrorData,
|
|
||||||
VideoRef,
|
VideoRef,
|
||||||
OnTextTrackDataChangedData,
|
|
||||||
OnSeekData,
|
|
||||||
OnPlaybackStateChangedData,
|
|
||||||
OnPlaybackRateChangeData,
|
|
||||||
OnVideoTracksData,
|
|
||||||
SelectedVideoTrackType,
|
SelectedVideoTrackType,
|
||||||
BufferingStrategyType,
|
BufferingStrategyType,
|
||||||
ReactVideoSource,
|
|
||||||
SelectedTrackType,
|
SelectedTrackType,
|
||||||
TextTracks,
|
|
||||||
ResizeMode,
|
ResizeMode,
|
||||||
VideoTrack,
|
type AudioTrack,
|
||||||
SelectedTrack,
|
type OnAudioTracksData,
|
||||||
SelectedVideoTrack,
|
type OnLoadData,
|
||||||
EnumValues,
|
type OnProgressData,
|
||||||
|
type OnTextTracksData,
|
||||||
|
type OnVideoAspectRatioData,
|
||||||
|
type TextTrack,
|
||||||
|
type OnBufferData,
|
||||||
|
type OnAudioFocusChangedData,
|
||||||
|
type OnVideoErrorData,
|
||||||
|
type OnTextTrackDataChangedData,
|
||||||
|
type OnSeekData,
|
||||||
|
type OnPlaybackStateChangedData,
|
||||||
|
type OnPlaybackRateChangeData,
|
||||||
|
type OnVideoTracksData,
|
||||||
|
type ReactVideoSource,
|
||||||
|
type TextTracks,
|
||||||
|
type VideoTrack,
|
||||||
|
type SelectedTrack,
|
||||||
|
type SelectedVideoTrack,
|
||||||
|
type EnumValues,
|
||||||
} from 'react-native-video';
|
} from 'react-native-video';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import {AdditionalSourceInfo} from './types';
|
import {type AdditionalSourceInfo} from './types';
|
||||||
import {bufferConfig, srcList, textTracksSelectionBy} from './constants';
|
import {bufferConfig, srcList, textTracksSelectionBy} from './constants';
|
||||||
import {Overlay, toast} from './components';
|
import {Overlay, toast} from './components';
|
||||||
|
|
||||||
@ -58,7 +58,6 @@ const VideoPlayer: FC<Props> = ({}) => {
|
|||||||
const [_, setVideoSize] = useState({videoWidth: 0, videoHeight: 0});
|
const [_, setVideoSize] = useState({videoWidth: 0, videoHeight: 0});
|
||||||
const [paused, setPaused] = useState(false);
|
const [paused, setPaused] = useState(false);
|
||||||
const [fullscreen, setFullscreen] = useState(true);
|
const [fullscreen, setFullscreen] = useState(true);
|
||||||
const [decoration, setDecoration] = useState(true);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);
|
const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);
|
||||||
const [textTracks, setTextTracks] = useState<TextTrack[]>([]);
|
const [textTracks, setTextTracks] = useState<TextTrack[]>([]);
|
||||||
@ -87,6 +86,31 @@ const VideoPlayer: FC<Props> = ({}) => {
|
|||||||
const currentSrc = srcList[srcListId];
|
const currentSrc = srcList[srcListId];
|
||||||
const additional = currentSrc as AdditionalSourceInfo;
|
const additional = currentSrc as AdditionalSourceInfo;
|
||||||
|
|
||||||
|
const goToChannel = useCallback((channel: number) => {
|
||||||
|
setSrcListId(channel);
|
||||||
|
setDuration(0);
|
||||||
|
setCurrentTime(0);
|
||||||
|
setVideoSize({videoWidth: 0, videoHeight: 0});
|
||||||
|
setIsLoading(false);
|
||||||
|
setAudioTracks([]);
|
||||||
|
setTextTracks([]);
|
||||||
|
setSelectedAudioTrack(undefined);
|
||||||
|
setSelectedTextTrack(undefined);
|
||||||
|
setSelectedVideoTrack({
|
||||||
|
type: SelectedVideoTrackType.AUTO,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const channelUp = useCallback(() => {
|
||||||
|
console.log('channel up');
|
||||||
|
goToChannel((srcListId + 1) % srcList.length);
|
||||||
|
}, [goToChannel, srcListId]);
|
||||||
|
|
||||||
|
const channelDown = useCallback(() => {
|
||||||
|
console.log('channel down');
|
||||||
|
goToChannel((srcListId + srcList.length - 1) % srcList.length);
|
||||||
|
}, [goToChannel, srcListId]);
|
||||||
|
|
||||||
const onAudioTracks = (data: OnAudioTracksData) => {
|
const onAudioTracks = (data: OnAudioTracksData) => {
|
||||||
const selectedTrack = data.audioTracks?.find((x: AudioTrack) => {
|
const selectedTrack = data.audioTracks?.find((x: AudioTrack) => {
|
||||||
return x.selected;
|
return x.selected;
|
||||||
@ -197,31 +221,11 @@ const VideoPlayer: FC<Props> = ({}) => {
|
|||||||
console.log('onPlaybackStateChanged', data);
|
console.log('onPlaybackStateChanged', data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const goToChannel = (channel: number) => {
|
const onFullScreenExit = () => {
|
||||||
setSrcListId(channel);
|
// iOS pauses video on exit from full screen
|
||||||
setDuration(0);
|
Platform.OS === 'ios' && setPaused(true);
|
||||||
setCurrentTime(0);
|
|
||||||
setVideoSize({videoWidth: 0, videoHeight: 0});
|
|
||||||
setIsLoading(false);
|
|
||||||
setAudioTracks([]);
|
|
||||||
setTextTracks([]);
|
|
||||||
setSelectedAudioTrack(undefined);
|
|
||||||
setSelectedTextTrack(undefined);
|
|
||||||
setSelectedVideoTrack({
|
|
||||||
type: SelectedVideoTrackType.AUTO,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const channelUp = useCallback(() => {
|
|
||||||
console.log('channel up');
|
|
||||||
goToChannel((srcListId + 1) % srcList.length);
|
|
||||||
}, [srcListId]);
|
|
||||||
|
|
||||||
const channelDown = useCallback(() => {
|
|
||||||
console.log('channel down');
|
|
||||||
goToChannel((srcListId + srcList.length - 1) % srcList.length);
|
|
||||||
}, [srcListId]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{(srcList[srcListId] as AdditionalSourceInfo)?.noView ? null : (
|
{(srcList[srcListId] as AdditionalSourceInfo)?.noView ? null : (
|
||||||
@ -241,6 +245,7 @@ const VideoPlayer: FC<Props> = ({}) => {
|
|||||||
fullscreen={fullscreen}
|
fullscreen={fullscreen}
|
||||||
controls={controls}
|
controls={controls}
|
||||||
resizeMode={resizeMode}
|
resizeMode={resizeMode}
|
||||||
|
onFullscreenPlayerWillDismiss={onFullScreenExit}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
onAudioTracks={onAudioTracks}
|
onAudioTracks={onAudioTracks}
|
||||||
onTextTracks={onTextTracks}
|
onTextTracks={onTextTracks}
|
||||||
@ -293,14 +298,11 @@ const VideoPlayer: FC<Props> = ({}) => {
|
|||||||
currentTime={currentTime}
|
currentTime={currentTime}
|
||||||
setMuted={setMuted}
|
setMuted={setMuted}
|
||||||
muted={muted}
|
muted={muted}
|
||||||
fullscreen={fullscreen}
|
|
||||||
duration={duration}
|
duration={duration}
|
||||||
decoration={decoration}
|
|
||||||
paused={paused}
|
paused={paused}
|
||||||
volume={volume}
|
volume={volume}
|
||||||
setControls={setControls}
|
setControls={setControls}
|
||||||
poster={poster}
|
poster={poster}
|
||||||
setDecoration={setDecoration}
|
|
||||||
rate={rate}
|
rate={rate}
|
||||||
setFullscreen={setFullscreen}
|
setFullscreen={setFullscreen}
|
||||||
setPaused={setPaused}
|
setPaused={setPaused}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {Picker} from '@react-native-picker/picker';
|
import {Picker} from '@react-native-picker/picker';
|
||||||
import {Text} from 'react-native';
|
import {Text} from 'react-native';
|
||||||
import {AudioTrack, SelectedTrack} from 'react-native-video';
|
import type {AudioTrack, SelectedTrack} from 'react-native-video';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import React, {forwardRef, memo, useCallback} from 'react';
|
import React, {
|
||||||
|
forwardRef,
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
type Dispatch,
|
||||||
|
type SetStateAction,
|
||||||
|
} from 'react';
|
||||||
import {Indicator} from './Indicator.tsx';
|
import {Indicator} from './Indicator.tsx';
|
||||||
import {View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
import styles from '../styles.tsx';
|
import styles from '../styles.tsx';
|
||||||
@ -9,19 +15,21 @@ import {
|
|||||||
samplePoster,
|
samplePoster,
|
||||||
textTracksSelectionBy,
|
textTracksSelectionBy,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import MultiValueControl from '../MultiValueControl.tsx';
|
import MultiValueControl, {
|
||||||
|
type MultiValueControlPropType,
|
||||||
|
} from '../MultiValueControl.tsx';
|
||||||
import {
|
import {
|
||||||
AudioTrack,
|
|
||||||
EnumValues,
|
|
||||||
ResizeMode,
|
ResizeMode,
|
||||||
SelectedTrack,
|
|
||||||
SelectedTrackType,
|
|
||||||
SelectedVideoTrack,
|
|
||||||
SelectedVideoTrackType,
|
|
||||||
TextTrack,
|
|
||||||
VideoDecoderProperties,
|
|
||||||
VideoRef,
|
VideoRef,
|
||||||
VideoTrack,
|
SelectedTrackType,
|
||||||
|
SelectedVideoTrackType,
|
||||||
|
VideoDecoderProperties,
|
||||||
|
type EnumValues,
|
||||||
|
type TextTrack,
|
||||||
|
type SelectedVideoTrack,
|
||||||
|
type SelectedTrack,
|
||||||
|
type VideoTrack,
|
||||||
|
type AudioTrack,
|
||||||
} from 'react-native-video';
|
} from 'react-native-video';
|
||||||
import {
|
import {
|
||||||
toast,
|
toast,
|
||||||
@ -35,39 +43,36 @@ import {
|
|||||||
type Props = {
|
type Props = {
|
||||||
channelDown: () => void;
|
channelDown: () => void;
|
||||||
channelUp: () => void;
|
channelUp: () => void;
|
||||||
fullscreen: boolean;
|
setFullscreen: Dispatch<SetStateAction<boolean>>;
|
||||||
setFullscreen: (value: boolean) => void;
|
|
||||||
controls: boolean;
|
controls: boolean;
|
||||||
setControls: (value: boolean) => void;
|
setControls: Dispatch<SetStateAction<boolean>>;
|
||||||
decoration: boolean;
|
|
||||||
setDecoration: (value: boolean) => void;
|
|
||||||
showNotificationControls: boolean;
|
showNotificationControls: boolean;
|
||||||
setShowNotificationControls: (value: boolean) => void;
|
setShowNotificationControls: Dispatch<SetStateAction<boolean>>;
|
||||||
selectedAudioTrack: SelectedTrack | undefined;
|
selectedAudioTrack: SelectedTrack | undefined;
|
||||||
setSelectedAudioTrack: (value: SelectedTrack | undefined) => void;
|
setSelectedAudioTrack: Dispatch<SetStateAction<SelectedTrack | undefined>>;
|
||||||
selectedTextTrack: SelectedTrack | undefined;
|
selectedTextTrack: SelectedTrack | undefined;
|
||||||
setSelectedTextTrack: (value: SelectedTrack | undefined) => void;
|
setSelectedTextTrack: (value: SelectedTrack | undefined) => void;
|
||||||
selectedVideoTrack: SelectedVideoTrack;
|
selectedVideoTrack: SelectedVideoTrack;
|
||||||
setSelectedVideoTrack: (value: SelectedVideoTrack) => void;
|
setSelectedVideoTrack: (value: SelectedVideoTrack) => void;
|
||||||
setIsSeeking: (value: boolean) => void;
|
setIsSeeking: Dispatch<SetStateAction<boolean>>;
|
||||||
rate: number;
|
rate: number;
|
||||||
setRate: (value: number) => void;
|
setRate: Dispatch<SetStateAction<number>>;
|
||||||
volume: number;
|
volume: number;
|
||||||
setVolume: (value: number) => void;
|
setVolume: (value: number) => void;
|
||||||
resizeMode: EnumValues<ResizeMode>;
|
resizeMode: EnumValues<ResizeMode>;
|
||||||
setResizeMode: (value: EnumValues<ResizeMode>) => void;
|
setResizeMode: Dispatch<SetStateAction<EnumValues<ResizeMode>>>;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
srcListId: number;
|
srcListId: number;
|
||||||
useCache: boolean;
|
useCache: boolean;
|
||||||
setUseCache: (value: boolean) => void;
|
setUseCache: Dispatch<SetStateAction<boolean>>;
|
||||||
paused: boolean;
|
paused: boolean;
|
||||||
setPaused: (value: boolean) => void;
|
setPaused: Dispatch<SetStateAction<boolean>>;
|
||||||
repeat: boolean;
|
repeat: boolean;
|
||||||
setRepeat: (value: boolean) => void;
|
setRepeat: Dispatch<SetStateAction<boolean>>;
|
||||||
poster: string | undefined;
|
poster: string | undefined;
|
||||||
setPoster: (value: string | undefined) => void;
|
setPoster: Dispatch<SetStateAction<string | undefined>>;
|
||||||
muted: boolean;
|
muted: boolean;
|
||||||
setMuted: (value: boolean) => void;
|
setMuted: Dispatch<SetStateAction<boolean>>;
|
||||||
currentTime: number;
|
currentTime: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
isSeeking: boolean;
|
isSeeking: boolean;
|
||||||
@ -81,11 +86,8 @@ const _Overlay = forwardRef<VideoRef, Props>((props, ref) => {
|
|||||||
channelUp,
|
channelUp,
|
||||||
channelDown,
|
channelDown,
|
||||||
setFullscreen,
|
setFullscreen,
|
||||||
fullscreen,
|
|
||||||
setControls,
|
setControls,
|
||||||
controls,
|
controls,
|
||||||
setDecoration,
|
|
||||||
decoration,
|
|
||||||
setShowNotificationControls,
|
setShowNotificationControls,
|
||||||
showNotificationControls,
|
showNotificationControls,
|
||||||
setSelectedAudioTrack,
|
setSelectedAudioTrack,
|
||||||
@ -141,21 +143,18 @@ const _Overlay = forwardRef<VideoRef, Props>((props, ref) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const toggleFullscreen = () => {
|
const toggleFullscreen = () => {
|
||||||
setFullscreen(!fullscreen);
|
setFullscreen(prev => !prev);
|
||||||
};
|
};
|
||||||
const toggleControls = () => {
|
const toggleControls = () => {
|
||||||
setControls(!controls);
|
setControls(prev => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleDecoration = () => {
|
const openDecoration = () => {
|
||||||
setDecoration(!decoration);
|
typeof ref !== 'function' && ref?.current?.setFullScreen(true);
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-expect-error
|
|
||||||
ref.current?.setFullScreen(!decoration);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleShowNotificationControls = () => {
|
const toggleShowNotificationControls = () => {
|
||||||
setShowNotificationControls(!showNotificationControls);
|
setShowNotificationControls(prev => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelectedAudioTrackChange = (itemValue: string) => {
|
const onSelectedAudioTrackChange = (itemValue: string) => {
|
||||||
@ -197,9 +196,7 @@ const _Overlay = forwardRef<VideoRef, Props>((props, ref) => {
|
|||||||
|
|
||||||
const videoSeek = (position: number) => {
|
const videoSeek = (position: number) => {
|
||||||
setIsSeeking(true);
|
setIsSeeking(true);
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
typeof ref !== 'function' && ref?.current?.seek(position);
|
||||||
// @ts-expect-error
|
|
||||||
ref.current?.seek(position);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRateSelected = (value: number) => {
|
const onRateSelected = (value: number) => {
|
||||||
@ -214,15 +211,16 @@ const _Overlay = forwardRef<VideoRef, Props>((props, ref) => {
|
|||||||
setResizeMode(value);
|
setResizeMode(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleCache = () => setUseCache(!useCache);
|
const toggleCache = () => setUseCache(prev => !prev);
|
||||||
|
|
||||||
const togglePause = () => setPaused(!paused);
|
const togglePause = () => setPaused(prev => !prev);
|
||||||
|
|
||||||
const toggleRepeat = () => setRepeat(!repeat);
|
const toggleRepeat = () => setRepeat(prev => !prev);
|
||||||
|
|
||||||
const togglePoster = () => setPoster(poster ? undefined : samplePoster);
|
const togglePoster = () =>
|
||||||
|
setPoster(prev => (prev ? undefined : samplePoster));
|
||||||
|
|
||||||
const toggleMuted = () => setMuted(!muted);
|
const toggleMuted = () => setMuted(prev => !prev);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -270,7 +268,7 @@ const _Overlay = forwardRef<VideoRef, Props>((props, ref) => {
|
|||||||
unselectedText="loop disable"
|
unselectedText="loop disable"
|
||||||
/>
|
/>
|
||||||
<ToggleControl onPress={toggleFullscreen} text="fullscreen" />
|
<ToggleControl onPress={toggleFullscreen} text="fullscreen" />
|
||||||
<ToggleControl onPress={toggleDecoration} text="decoration" />
|
<ToggleControl onPress={openDecoration} text="decoration" />
|
||||||
<ToggleControl
|
<ToggleControl
|
||||||
isSelected={!!poster}
|
isSelected={!!poster}
|
||||||
onPress={togglePoster}
|
onPress={togglePoster}
|
||||||
@ -315,16 +313,15 @@ const _Overlay = forwardRef<VideoRef, Props>((props, ref) => {
|
|||||||
<ToggleControl
|
<ToggleControl
|
||||||
isSelected={paused}
|
isSelected={paused}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
typeof ref !== 'function' &&
|
||||||
// @ts-expect-error
|
ref?.current
|
||||||
ref.current
|
?.save({})
|
||||||
?.save({})
|
?.then((response: unknown) => {
|
||||||
?.then((response: unknown) => {
|
console.log('Downloaded URI', response);
|
||||||
console.log('Downloaded URI', response);
|
})
|
||||||
})
|
.catch((error: unknown) => {
|
||||||
.catch((error: unknown) => {
|
console.log('error during save ', error);
|
||||||
console.log('error during save ', error);
|
});
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
text="save"
|
text="save"
|
||||||
/>
|
/>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {Picker} from '@react-native-picker/picker';
|
import {Picker} from '@react-native-picker/picker';
|
||||||
import {Text} from 'react-native';
|
import {Text} from 'react-native';
|
||||||
import {TextTrack, SelectedTrack} from 'react-native-video';
|
import type {TextTrack, SelectedTrack} from 'react-native-video';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import React, {FC, memo} from 'react';
|
|||||||
import {Text, TouchableOpacity, View} from 'react-native';
|
import {Text, TouchableOpacity, View} from 'react-native';
|
||||||
import styles from '../styles.tsx';
|
import styles from '../styles.tsx';
|
||||||
import {srcList} from '../constants';
|
import {srcList} from '../constants';
|
||||||
import {AdditionalSourceInfo} from '../types';
|
import {type AdditionalSourceInfo} from '../types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
srcListId: number;
|
srcListId: number;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import {Picker} from '@react-native-picker/picker';
|
import {Picker} from '@react-native-picker/picker';
|
||||||
import {Text} from 'react-native';
|
import {Text} from 'react-native';
|
||||||
import {
|
import {
|
||||||
SelectedVideoTrack,
|
|
||||||
SelectedVideoTrackType,
|
SelectedVideoTrackType,
|
||||||
VideoTrack,
|
type SelectedVideoTrack,
|
||||||
|
type VideoTrack,
|
||||||
} from 'react-native-video';
|
} from 'react-native-video';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
Loading…
Reference in New Issue
Block a user