diff --git a/Video.tsx b/Video.tsx index 6d8cf532d2..a6c39d5665 100644 --- a/Video.tsx +++ b/Video.tsx @@ -75,6 +75,10 @@ export default class Video extends React.PureComponent { this.props.onSeek?.(event.nativeEvent); }; + onSeekEndedEvent = (event) => { + this.props.onSeekEndedEvent?.(event.nativeEvent); + }; + onEnd = (event) => { this.props.onEnd?.(event.nativeEvent); }; @@ -130,6 +134,10 @@ export default class Video extends React.PureComponent { this.props.onSkipMarkerButton?.(event.nativeEvent); }; + onPlayPauseAction = (event) => { + this.props.onPlayPauseAction?.(event.nativeEvent); + } + replaceAdTagParameters = (payload: IVideoReplaceAdTagParametersPayload) => { let command = 'replaceAdTagParameters'; @@ -189,6 +197,7 @@ export default class Video extends React.PureComponent { onVideoError: this.onError, onVideoProgress: this.onProgress, onVideoSeek: this.onSeek, + onSeekEndedEvent: this.onSeekEndedEvent, onVideoEnd: this.onEnd, onVideoBuffer: this.onBuffer, onTimedMetadata: this.onTimedMetadata, @@ -204,6 +213,7 @@ export default class Video extends React.PureComponent { onReloadCurrentSource: this.onReloadCurrentSource, onBehindLiveWindowError: this.onBehindLiveWindowError, onSkipMarkerButton: this.onSkipMarkerButton, + onPlayPauseAction: this.onPlayPauseAction, }; }; diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactTVExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactTVExoplayerView.java index 3905b783b4..c492b85ec2 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactTVExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactTVExoplayerView.java @@ -1919,7 +1919,7 @@ public void onWatchlistButtonClicked() { } @Override - public void onSkipMarkerClicked(SkipMarker skipMarker) { + public void onSkipMarkerClicked(long currentPosition, SkipMarker skipMarker) { eventEmitter.skipMarkerClick(skipMarker); } @@ -1933,6 +1933,31 @@ public void onStatsButtonClicked() { eventEmitter.statsIconClick(); } + @Override + public void onVideoPlayPauseButtonClick(boolean playing) { + eventEmitter.playPauseButtonClick(playing); + } + + @Override + public void onAdPlayPauseButtonClick(boolean playing) { + eventEmitter.playPauseButtonClick(playing); + } + + @Override + public void onGoToLiveButtonClick(long seekStartAt, long seekEndAt) { + eventEmitter.goToLiveSeek(seekStartAt, seekEndAt); + } + + @Override + public void onForwardRewindButtonClick(long seekStartAt, long seekEndAt) { + eventEmitter.forwardRewindSeek(seekStartAt, seekEndAt); + } + + @Override + public void onContinuousSeekClick(long seekStartAt, long seekEndAt) { + eventEmitter.continuousSeek(seekStartAt, seekEndAt); + } + @Override public void onSubtitleSelected(String language) { TrackPreferenceStorage storage = TrackPreferenceStorage.getInstance(getContext()); diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java index ff711b3ca6..f141d45aad 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java @@ -65,6 +65,8 @@ class VideoEventEmitter { private static final String EVENT_SUBTITLE_TRACK_CHANGED = "onSubtitleTrackChanged"; private static final String EVENT_AUDIO_TRACK_CHANGED = "onAudioTrackChanged"; private static final String EVENT_SKIP_MARKER = "onSkipMarkerButton"; + private static final String EVENT_SEEK_ENDED = "onSeekEndedEvent"; + private static final String EVENT_PLAY_PAUSE_ACTION = "onPlayPauseAction"; static final String[] Events = { EVENT_LOAD_START, @@ -103,7 +105,9 @@ class VideoEventEmitter { EVENT_REQUIRE_AD_PARAMETERS, EVENT_RELOAD_CURRENT_SOURCE, EVENT_BEHIND_LIVE_WINDOW_ERROR, - EVENT_SKIP_MARKER + EVENT_SKIP_MARKER, + EVENT_SEEK_ENDED, + EVENT_PLAY_PAUSE_ACTION }; @Retention(RetentionPolicy.SOURCE) @@ -144,7 +148,9 @@ class VideoEventEmitter { EVENT_REQUIRE_AD_PARAMETERS, EVENT_RELOAD_CURRENT_SOURCE, EVENT_BEHIND_LIVE_WINDOW_ERROR, - EVENT_SKIP_MARKER + EVENT_SKIP_MARKER, + EVENT_SEEK_ENDED, + EVENT_PLAY_PAUSE_ACTION }) @interface VideoEvents { } @@ -165,6 +171,10 @@ class VideoEventEmitter { private static final String EVENT_PROP_CURRENT_DATE = "currentDate"; private static final String EVENT_PROP_CURRENT_TIME = "currentTime"; + private static final String EVENT_PROP_IS_PAUSE = "isPaused"; + private static final String EVENT_PROP_SEEK_TYPE = "seekType"; + private static final String EVENT_PROP_SEEK_START_TIME = "seekStartAt"; + private static final String EVENT_PROP_SEEK_END_TIME = "seekEndAt"; private static final String EVENT_PROP_SEEK_TIME = "seekTime"; private static final String EVENT_PROP_NATURAL_SIZE = "naturalSize"; private static final String EVENT_PROP_WIDTH = "width"; @@ -189,6 +199,9 @@ class VideoEventEmitter { private static final String EVENT_PROP_ERROR_EXCEPTION = "errorException"; private static final String EVENT_PROP_TIMED_METADATA = "metadata"; + private static final String EVENT_PROP_SEEK_GO_TO_LIVE = "liveBadge"; + private static final String EVENT_PROP_SEEK_SKIP = "skip"; + private static final String EVENT_PROP_SEEK = "seek"; void setViewId(int viewId) { this.viewId = viewId; @@ -250,6 +263,32 @@ void seek(long currentPosition, long seekTime) { receiveEvent(EVENT_SEEK, event); } + void goToLiveSeek(long seekStartAt, long seekEndAt) { + onSeek(EVENT_PROP_SEEK_GO_TO_LIVE, seekStartAt, seekEndAt); + } + + void forwardRewindSeek(long seekStartAt, long seekEndAt) { + onSeek(EVENT_PROP_SEEK_SKIP, seekStartAt, seekEndAt); + } + + void continuousSeek(long seekStartAt, long seekEndAt) { + onSeek(EVENT_PROP_SEEK, seekStartAt, seekEndAt); + } + + private void onSeek(String seekType, long seekStartAt, long seekEndAt) { + WritableMap event = Arguments.createMap(); + event.putString(EVENT_PROP_SEEK_TYPE, seekType); + event.putDouble(EVENT_PROP_SEEK_START_TIME, seekStartAt / 1000D); + event.putDouble(EVENT_PROP_SEEK_END_TIME, seekEndAt / 1000D); + receiveEvent(EVENT_SEEK_ENDED, event); + } + + void playPauseButtonClick(boolean isPlaying) { + WritableMap event = Arguments.createMap(); + event.putBoolean(EVENT_PROP_IS_PAUSE, !isPlaying); + receiveEvent(EVENT_PLAY_PAUSE_ACTION, event); + } + void ready() { receiveEvent(EVENT_READY, null); } diff --git a/ios/Video/NewPlayerView.swift b/ios/Video/NewPlayerView.swift index 37ff24ed55..136a6e6e48 100644 --- a/ios/Video/NewPlayerView.swift +++ b/ios/Video/NewPlayerView.swift @@ -34,7 +34,9 @@ class NewPlayerView: UIView, JSInputProtocol { @objc var onWatchlistButtonClick: RCTBubblingEventBlock? @objc var onSkipMarkerButton: RCTBubblingEventBlock? @objc var onVideoSeek: RCTBubblingEventBlock? - + @objc var onSeekEndedEvent: RCTBubblingEventBlock? + @objc var onPlayPauseAction: RCTBubblingEventBlock? + //not used @objc var onVideoLoadStart: RCTBubblingEventBlock? @objc var onTimedMetadata: RCTBubblingEventBlock? @@ -223,6 +225,8 @@ class NewPlayerView: UIView, JSInputProtocol { jsPlayerView.onWatchlistButtonClick = self.onWatchlistButtonClick jsPlayerView.onSkipMarkerButton = self.onSkipMarkerButton jsPlayerView.onSeekEvent = self.onVideoSeek + jsPlayerView.onSeekEndedEvent = self.onSeekEndedEvent + jsPlayerView.onPlayPauseAction = self.onPlayPauseAction jsPlayerView.onVideoBuffer = self.onVideoBuffer jsPlayerView.onVideoAboutToEnd = self.onVideoAboutToEnd diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index 58e3bc0ffe..e1822ab800 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -42,6 +42,7 @@ @interface RCT_EXTERN_MODULE(RCTVideoManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(onVideoError, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoProgress, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoSeek, RCTBubblingEventBlock); +RCT_EXPORT_VIEW_PROPERTY(onSeekEndedEvent, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoEnd, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onTimedMetadata, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoAudioBecomingNoisy, RCTBubblingEventBlock); @@ -65,6 +66,8 @@ @interface RCT_EXTERN_MODULE(RCTVideoManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(onSubtitleTrackChanged, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onAudioTrackChanged, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onSkipMarkerButton, RCTBubblingEventBlock); +RCT_EXPORT_VIEW_PROPERTY(onPlayPauseAction, RCTBubblingEventBlock); + RCT_EXTERN_METHOD(seekToPosition:(nonnull NSNumber *)node position:(double)position) RCT_EXTERN_METHOD(replaceAdTagParameters:(nonnull NSNumber *)node payload:(NSDictionary)payload) diff --git a/package.json b/package.json index d3298c455a..7e54c71b1e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-native-video", - "version": "7.12.18", - "dorisAndroidVersion": "5.2.20", + "version": "7.12.19", + "dorisAndroidVersion": "5.2.23", "messagingAndroidVersion": "1.1.0", "description": "A