Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(JS): improve loader api #4171

Merged
merged 8 commits into from
Sep 17, 2024
21 changes: 18 additions & 3 deletions docs/pages/component/props.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -515,14 +515,29 @@ Speed at which the media should play.

<PlatformsList types={['All']} />

Allows you to create custom components to display while the video is loading. If `renderLoader` is provided, `poster` and `posterResizeMode` will be ignored.
Allows you to create custom components to display while the video is loading.
If `renderLoader` is provided, `poster` and `posterResizeMode` will be ignored.
renderLoader is either a component or a function returning a component.
It is recommended to use the function for optimization matter.

`renderLoader` function be called with parameters of type `ReactVideoRenderLoaderProps` to be able to adapt loader

```typescript
interface ReactVideoRenderLoaderProps {
source?: ReactVideoSource; /// source of the video
style?: StyleProp<ImageStyle>; /// style to apply
resizeMode?: EnumValues<VideoResizeMode>; /// resizeMode provided to the video component
}
````

Sample:

```javascript
<Video>
renderLoader={
renderLoader={() => (
<View>
<Text>Custom Loader</Text>
</View>
</View>)
}
</Video>
````
Expand Down
26 changes: 16 additions & 10 deletions examples/basic/src/VideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,18 @@ const VideoPlayer: FC<Props> = ({}) => {
Platform.OS === 'ios' && setPaused(true);
};

const _renderLoader = showPoster ? () => <VideoLoader /> : undefined;

const _subtitleStyle = {subtitlesFollowVideo: true};
const _controlsStyles = {
hideNavigationBarOnFullScreenMode: true,
hideNotificationBarOnFullScreenMode: true,
};
const _bufferConfig = {
...bufferConfig,
cacheSizeMB: useCache ? 200 : 0,
}

return (
<View style={styles.container}>
<StatusBar animated={true} backgroundColor="black" hidden={false} />
Expand Down Expand Up @@ -278,21 +290,15 @@ const VideoPlayer: FC<Props> = ({}) => {
selectedAudioTrack={selectedAudioTrack}
selectedVideoTrack={selectedVideoTrack}
playInBackground={false}
bufferConfig={{
...bufferConfig,
cacheSizeMB: useCache ? 200 : 0,
}}
bufferConfig={_bufferConfig}
preventsDisplaySleepDuringVideoPlayback={true}
renderLoader={showPoster ? <VideoLoader /> : undefined}
renderLoader={_renderLoader}
onPlaybackRateChange={onPlaybackRateChange}
onPlaybackStateChanged={onPlaybackStateChanged}
bufferingStrategy={BufferingStrategyType.DEFAULT}
debug={{enable: true, thread: true}}
subtitleStyle={{subtitlesFollowVideo: true}}
controlsStyles={{
hideNavigationBarOnFullScreenMode: true,
hideNotificationBarOnFullScreenMode: true,
}}
subtitleStyle={_subtitleStyle}
controlsStyles={_controlsStyles}
/>
</TouchableOpacity>
)}
Expand Down
32 changes: 26 additions & 6 deletions src/Video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,18 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(

const isPosterDeprecated = typeof poster === 'string';

const _renderLoader = useMemo(
() =>
!renderLoader
? undefined
: renderLoader instanceof Function
? renderLoader
: () => renderLoader,
[renderLoader],
);

const hasPoster = useMemo(() => {
if (renderLoader) {
if (_renderLoader) {
return true;
}

Expand All @@ -137,7 +147,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
}

return !!poster?.source;
}, [isPosterDeprecated, poster, renderLoader]);
}, [isPosterDeprecated, poster, _renderLoader]);

const [showPoster, setShowPoster] = useState(hasPoster);

Expand Down Expand Up @@ -688,15 +698,23 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
}

// render poster
if (renderLoader && (poster || posterResizeMode)) {
if (_renderLoader && (poster || posterResizeMode)) {
console.warn(
'You provided both `renderLoader` and `poster` or `posterResizeMode` props. `renderLoader` will be used.',
);
}

// render loader
if (renderLoader) {
return <View style={StyleSheet.absoluteFill}>{renderLoader}</View>;
if (_renderLoader) {
return (
<View style={StyleSheet.absoluteFill}>
{_renderLoader({
source: source,
style: posterStyle,
resizeMode: resizeMode,
})}
</View>
);
}

return (
Expand All @@ -711,8 +729,10 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
isPosterDeprecated,
poster,
posterResizeMode,
renderLoader,
_renderLoader,
showPoster,
source,
resizeMode,
]);

const _style: StyleProp<ViewStyle> = useMemo(
Expand Down
9 changes: 8 additions & 1 deletion src/types/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
ViewStyle,
ImageRequireSource,
ImageURISource,
ImageStyle,
} from 'react-native';
import type {ReactNode} from 'react';
import type VideoResizeMode from './ResizeMode';
Expand Down Expand Up @@ -254,6 +255,12 @@ export type ControlsStyles = {
hideNotificationBarOnFullScreenMode?: boolean;
};

export interface ReactVideoRenderLoaderProps {
source?: ReactVideoSource;
style?: StyleProp<ImageStyle>;
resizeMode?: EnumValues<VideoResizeMode>;
}

export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
source?: ReactVideoSource;
/** @deprecated Use source.drm */
Expand Down Expand Up @@ -295,7 +302,7 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
preventsDisplaySleepDuringVideoPlayback?: boolean;
progressUpdateInterval?: number;
rate?: number;
renderLoader?: ReactNode;
renderLoader?: ReactNode | ((arg0: ReactVideoRenderLoaderProps) => ReactNode);
repeat?: boolean;
reportBandwidth?: boolean; //Android
resizeMode?: EnumValues<VideoResizeMode>;
Expand Down
Loading