fix: ensure poster works as expected and add it to the sample (#3643)
* fix: ensure poster works as expected and add it to the sample * chore: drop audioOnly property as not implemented on any platform * fix(ios): do not save pause state before seeking * fix(ts): onPlaybackRateChangeData was not correctly typed
This commit is contained in:
parent
051e884c8f
commit
d6941392e0
@ -7,6 +7,9 @@
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"no-trailing-spaces": 1
|
||||
},
|
||||
"parserOptions": {
|
||||
"requireConfigFile": false
|
||||
}
|
||||
|
@ -29,17 +29,6 @@ Indicates whether the player allows switching to external playback mode such as
|
||||
- **true (default)** - allow switching to external playback mode
|
||||
- **false** - Don't allow switching to external playback mode
|
||||
|
||||
### `audioOnly`
|
||||
|
||||
<PlatformsList types={['All']} />
|
||||
|
||||
Indicates whether the player should only play the audio track and instead of displaying the video track, show the poster instead.
|
||||
|
||||
- **false (default)** - Display the video as normal
|
||||
- **true** - Show the poster and play the audio
|
||||
|
||||
For this to work, the poster prop must be set.
|
||||
|
||||
### `audioOutput`
|
||||
|
||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||
|
@ -36,6 +36,7 @@ import Video, {
|
||||
OnTextTrackDataChangedData,
|
||||
TextTrackType,
|
||||
ISO639_1,
|
||||
OnSeekData,
|
||||
OnPlaybackStateChangedData,
|
||||
OnPlaybackRateChangeData,
|
||||
} from 'react-native-video';
|
||||
@ -68,6 +69,7 @@ interface StateType {
|
||||
srcListId: number;
|
||||
loop: boolean;
|
||||
showRNVControls: boolean;
|
||||
poster?: string;
|
||||
}
|
||||
|
||||
class VideoPlayer extends Component {
|
||||
@ -95,6 +97,7 @@ class VideoPlayer extends Component {
|
||||
srcListId: 0,
|
||||
loop: false,
|
||||
showRNVControls: false,
|
||||
poster: undefined,
|
||||
};
|
||||
|
||||
seekerWidth = 0;
|
||||
@ -140,7 +143,7 @@ class VideoPlayer extends Component {
|
||||
type: TextTrackType.VTT,
|
||||
uri: 'https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_en.vtt',
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@ -190,6 +193,10 @@ class VideoPlayer extends Component {
|
||||
},
|
||||
];
|
||||
|
||||
// poster which can be displayed
|
||||
samplePoster =
|
||||
'https://upload.wikimedia.org/wikipedia/commons/1/18/React_Native_Logo.png';
|
||||
|
||||
srcList = this.srcAllPlatformList.concat(
|
||||
Platform.OS === 'android' ? this.srcAndroidList : this.srcIosList,
|
||||
);
|
||||
@ -223,14 +230,26 @@ class VideoPlayer extends Component {
|
||||
this.onTextTracks(data);
|
||||
};
|
||||
|
||||
onProgress = (data: OnProgressData) => {
|
||||
if (!this.state.seeking) {
|
||||
updateSeeker = () => {
|
||||
// put this code in timeout as because it may be put just after a setState
|
||||
setTimeout(()=> {
|
||||
const position = this.calculateSeekerPosition();
|
||||
this.setSeekerPosition(position);
|
||||
}, 1)
|
||||
}
|
||||
|
||||
onProgress = (data: OnProgressData) => {
|
||||
this.setState({currentTime: data.currentTime});
|
||||
if (!this.state.seeking) {
|
||||
this.updateSeeker()
|
||||
}
|
||||
};
|
||||
|
||||
onSeek = (data: OnSeekData) => {
|
||||
this.setState({currentTime: data.currentTime});
|
||||
this.updateSeeker()
|
||||
}
|
||||
|
||||
onVideoLoadStart = () => {
|
||||
console.log('onVideoLoadStart');
|
||||
this.setState({isLoading: true});
|
||||
@ -662,6 +681,16 @@ class VideoPlayer extends Component {
|
||||
}}
|
||||
text="decoration"
|
||||
/>
|
||||
<ToggleControl
|
||||
isSelected={!!this.state.poster}
|
||||
onPress={() => {
|
||||
this.setState({
|
||||
poster: this.state.poster ? undefined : this.samplePoster,
|
||||
});
|
||||
}}
|
||||
selectedText="poster"
|
||||
unselectedText="no poster"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.generalControls}>
|
||||
{/* shall be replaced by slider */}
|
||||
@ -810,11 +839,13 @@ class VideoPlayer extends Component {
|
||||
onAspectRatio={this.onAspectRatio}
|
||||
onReadyForDisplay={this.onReadyForDisplay}
|
||||
onBuffer={this.onVideoBuffer}
|
||||
onSeek={this.onSeek}
|
||||
repeat={this.state.loop}
|
||||
selectedTextTrack={this.state.selectedTextTrack}
|
||||
selectedAudioTrack={this.state.selectedAudioTrack}
|
||||
playInBackground={false}
|
||||
preventsDisplaySleepDuringVideoPlayback={true}
|
||||
poster={this.state.poster}
|
||||
onPlaybackRateChange={this.onPlaybackRateChange}
|
||||
onPlaybackStateChanged={this.onPlaybackStateChanged}
|
||||
/>
|
||||
|
@ -681,21 +681,18 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
_pendingSeekTime = seekTime.floatValue
|
||||
return
|
||||
}
|
||||
let wasPaused = _paused
|
||||
|
||||
RCTPlayerOperations.seek(
|
||||
player: player,
|
||||
playerItem: item,
|
||||
paused: wasPaused,
|
||||
paused: _paused,
|
||||
seekTime: seekTime.floatValue,
|
||||
seekTolerance: seekTolerance.floatValue
|
||||
) { [weak self] (_: Bool) in
|
||||
guard let self else { return }
|
||||
|
||||
self._playerObserver.addTimeObserverIfNotSet()
|
||||
if !wasPaused {
|
||||
self.setPaused(false)
|
||||
}
|
||||
self.setPaused(_paused)
|
||||
self.onVideoSeek?(["currentTime": NSNumber(value: Float(CMTimeGetSeconds(item.currentTime()))),
|
||||
"seekTime": seekTime,
|
||||
"target": self.reactTag])
|
||||
|
@ -48,6 +48,7 @@
|
||||
"test": "echo no test available",
|
||||
"check-ios": "scripts/swift-format.sh && scripts/swift-lint.sh && scripts/clang-format.sh",
|
||||
"check-android": "scripts/kotlin-lint.sh",
|
||||
"check-all": "yarn check-android; yarn check-ios; yarn lint",
|
||||
"codegen": "node ./node_modules/react-native/scripts/generate-codegen-artifacts.js --path ./ ./output"
|
||||
},
|
||||
"files": [
|
||||
|
@ -121,6 +121,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
setRestoreUserInterfaceForPIPStopCompletionHandler,
|
||||
] = useState<boolean | undefined>();
|
||||
|
||||
const hasPoster = !!poster;
|
||||
|
||||
const posterStyle = useMemo<StyleProp<ImageStyle>>(
|
||||
() => ({
|
||||
...StyleSheet.absoluteFillObject,
|
||||
@ -286,19 +288,20 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
|
||||
const onVideoLoadStart = useCallback(
|
||||
(e: NativeSyntheticEvent<OnLoadStartData>) => {
|
||||
hasPoster && setShowPoster(true);
|
||||
onLoadStart?.(e.nativeEvent);
|
||||
},
|
||||
[onLoadStart],
|
||||
[hasPoster, onLoadStart],
|
||||
);
|
||||
|
||||
const onVideoLoad = useCallback(
|
||||
(e: NativeSyntheticEvent<OnLoadData>) => {
|
||||
if (Platform.OS === 'windows') {
|
||||
setShowPoster(false);
|
||||
hasPoster && setShowPoster(false);
|
||||
}
|
||||
onLoad?.(e.nativeEvent);
|
||||
},
|
||||
[onLoad, setShowPoster],
|
||||
[onLoad, hasPoster, setShowPoster],
|
||||
);
|
||||
|
||||
const onVideoError = useCallback(
|
||||
@ -388,9 +391,9 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
);
|
||||
|
||||
const _onReadyForDisplay = useCallback(() => {
|
||||
setShowPoster(false);
|
||||
hasPoster && setShowPoster(false);
|
||||
onReadyForDisplay?.();
|
||||
}, [setShowPoster, onReadyForDisplay]);
|
||||
}, [setShowPoster, hasPoster, onReadyForDisplay]);
|
||||
|
||||
const _onPictureInPictureStatusChanged = useCallback(
|
||||
(e: NativeSyntheticEvent<OnPictureInPictureStatusChangedData>) => {
|
||||
@ -567,7 +570,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
_onReceiveAdEvent as (e: NativeSyntheticEvent<object>) => void
|
||||
}
|
||||
/>
|
||||
{showPoster ? (
|
||||
{hasPoster && showPoster ? (
|
||||
<Image style={posterStyle} source={{uri: poster}} />
|
||||
) : null}
|
||||
</View>
|
||||
|
@ -186,7 +186,6 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
|
||||
drm?: Drm;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
adTagUrl?: string;
|
||||
audioOnly?: boolean;
|
||||
audioOutput?: AudioOutput; // Mobile
|
||||
automaticallyWaitsToMinimizeStalling?: boolean; // iOS
|
||||
bufferConfig?: BufferConfig; // Android
|
||||
|
Loading…
Reference in New Issue
Block a user