From 9373493d6a447bfe059479c99cef2c11a849c8af Mon Sep 17 00:00:00 2001 From: Krzysztof Moch Date: Mon, 23 Oct 2023 18:23:57 +0200 Subject: [PATCH] feat(ios): implement onPlaybackStateChanged callback (#3307) * chore: fix typo * feat(ios): implement onPlaybackStateChanged * docs: update onPlaybackStateChanged platforms --- API.md | 3 ++- ios/Video/Features/RCTPlayerObserver.swift | 6 +++--- ios/Video/RCTVideo.swift | 6 ++++++ ios/Video/RCTVideoManager.m | 1 + src/Video.tsx | 1 - src/types/events.ts | 4 ++-- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/API.md b/API.md index 0020859c..b1b25899 100644 --- a/API.md +++ b/API.md @@ -363,6 +363,7 @@ var styles = StyleSheet.create({ | [onLoadStart](#onloadstart) | All | | [onPictureInPictureStatusChanged](#onpictureinpicturestatuschanged) | iOS | | [onPlaybackRateChange](#onplaybackratechange) | All | +| [onPlaybackStateChanged](#onplaybackstatechanged) | Android, iOS | | [onProgress](#onprogress) | All | | [onReadyForDisplay](#onreadyfordisplay) | Android, iOS, Web | | [onReceiveAdEvent](#onreceiveadevent) | Android, iOS | @@ -1325,7 +1326,7 @@ Example: } ``` -Platforms: Android +Platforms: Android, iOS #### onPictureInPictureStatusChanged Callback function that is called when picture in picture becomes active or inactive. diff --git a/ios/Video/Features/RCTPlayerObserver.swift b/ios/Video/Features/RCTPlayerObserver.swift index 9e798dc3..1c512bcf 100644 --- a/ios/Video/Features/RCTPlayerObserver.swift +++ b/ios/Video/Features/RCTPlayerObserver.swift @@ -74,7 +74,7 @@ class RCTPlayerObserver: NSObject { private var _timeObserver:Any? private var _playerRateChangeObserver:NSKeyValueObservation? - private var _playerExpernalPlaybackActiveObserver:NSKeyValueObservation? + private var _playerExternalPlaybackActiveObserver:NSKeyValueObservation? private var _playerItemStatusObserver:NSKeyValueObservation? private var _playerPlaybackBufferEmptyObserver:NSKeyValueObservation? private var _playerPlaybackLikelyToKeepUpObserver:NSKeyValueObservation? @@ -95,12 +95,12 @@ class RCTPlayerObserver: NSObject { } _playerRateChangeObserver = player.observe(\.rate, changeHandler: _handlers.handlePlaybackRateChange) - _playerExpernalPlaybackActiveObserver = player.observe(\.isExternalPlaybackActive, changeHandler: _handlers.handleExternalPlaybackActiveChange) + _playerExternalPlaybackActiveObserver = player.observe(\.isExternalPlaybackActive, changeHandler: _handlers.handleExternalPlaybackActiveChange) } func removePlayerObservers() { _playerRateChangeObserver?.invalidate() - _playerExpernalPlaybackActiveObserver?.invalidate() + _playerExternalPlaybackActiveObserver?.invalidate() } func addPlayerItemObservers() { diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index e1ae52da..6a33bdb9 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -107,6 +107,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH @objc var onPlaybackStalled: RCTDirectEventBlock? @objc var onPlaybackResume: RCTDirectEventBlock? @objc var onPlaybackRateChange: RCTDirectEventBlock? + @objc var onVideoPlaybackStateChanged: RCTDirectEventBlock? @objc var onVideoExternalPlaybackChange: RCTDirectEventBlock? @objc var onPictureInPictureStatusChanged: RCTDirectEventBlock? @objc var onRestoreUserInterfaceForPictureInPictureStop: RCTDirectEventBlock? @@ -1219,8 +1220,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH func handlePlaybackRateChange(player: AVPlayer, change: NSKeyValueObservedChange) { guard let _player = _player else { return } + onPlaybackRateChange?(["playbackRate": NSNumber(value: _player.rate), "target": reactTag as Any]) + + onVideoPlaybackStateChanged?(["isPlaying": _player.rate != 0, + "target": reactTag as Any]) + if _playbackStalled && _player.rate > 0 { onPlaybackResume?(["playbackRate": NSNumber(value: _player.rate), "target": reactTag as Any]) diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index a77ce134..a90a5512 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -57,6 +57,7 @@ RCT_EXPORT_VIEW_PROPERTY(onReadyForDisplay, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackStalled, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackResume, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTDirectEventBlock); +RCT_EXPORT_VIEW_PROPERTY(onVideoPlaybackStateChanged, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoExternalPlaybackChange, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onGetLicense, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPictureInPictureStatusChanged, RCTDirectEventBlock); diff --git a/src/Video.tsx b/src/Video.tsx index 2e64d488..f4582864 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -291,7 +291,6 @@ const Video = forwardRef( [onSeek], ); - // android only const onVideoPlaybackStateChanged = useCallback( (e: NativeSyntheticEvent) => { onPlaybackStateChanged?.(e.nativeEvent); diff --git a/src/types/events.ts b/src/types/events.ts index 36399e7e..983a1686 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -38,11 +38,11 @@ export interface ReactVideoEvents { ) => void; //iOS onPlaybackRateChange?: (e: OnPlaybackData) => void; //All onProgress?: (e: OnProgressData) => void; //All - onReadyForDisplay?: () => void; //Android, iOS, Web + onReadyForDisplay?: () => void; //Android, iOS onReceiveAdEvent?: (e: OnReceiveAdEventData) => void; //Android, iOS onRestoreUserInterfaceForPictureInPictureStop?: () => void; //iOS onSeek?: (e: OnSeekData) => void; //Android, iOS, Windows UWP - onPlaybackStateChanged?: (e: OnPlaybackStateChangedData) => void; // Android + onPlaybackStateChanged?: (e: OnPlaybackStateChangedData) => void; // Android, iOS onTimedMetadata?: (e: OnTimedMetadataData) => void; //Android, iOS onAudioTracks?: (e: OnAudioTracksData) => void; // Android onTextTracks?: (e: OnTextTracksData) => void; //Android