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:
Kamil Moskała 2024-07-15 23:29:23 +02:00 committed by GitHub
parent 8ef2df1bac
commit 7611da155f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 111 additions and 112 deletions

View File

@ -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}

View File

@ -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';

View File

@ -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,9 +313,8 @@ 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);

View File

@ -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';

View File

@ -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;

View File

@ -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';