@applicaster/quick-brick-player 12.0.0-alpha.4462655310 → 12.0.0-alpha.4484269996

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/quick-brick-player",
3
- "version": "12.0.0-alpha.4462655310",
3
+ "version": "12.0.0-alpha.4484269996",
4
4
  "description": "Quick Brick Player",
5
5
  "main": "./src/index.ts",
6
6
  "types": "index.d.ts",
@@ -36,11 +36,11 @@
36
36
  },
37
37
  "homepage": "https://github.com/applicaster/quickbrick#readme",
38
38
  "dependencies": {
39
- "@applicaster/quick-brick-mobile-transport-controls": "12.0.0-alpha.4462655310",
40
- "@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.70",
41
- "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.4462655310",
42
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.4462655310",
43
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.4462655310",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "12.0.0-rc.106",
40
+ "@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.112",
41
+ "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.4484269996",
42
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.4484269996",
43
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.4484269996",
44
44
  "keymirror": "^0.1.1",
45
45
  "query-string": "7.1.3",
46
46
  "react-native-web-linear-gradient": "1.1.2",
@@ -10,66 +10,76 @@ type Asset = string | undefined;
10
10
  const isCurrentPlayer = (playerId) =>
11
11
  LiveImageManager.instance.getCurrentlyPlaying()?.playerId === playerId;
12
12
 
13
+ const liveImageButtonsListenerKey = "live-image-buttons";
14
+
13
15
  const usePlayPauseListeners = (playerId, player, asset, setImageUri) =>
14
16
  useEffect(() => {
15
17
  if (playerId && player) {
16
- if (player.playerState.isReadyToPlay) {
17
- if (player.playerState.isPaused) {
18
- setImageUri(asset.active);
19
- } else {
20
- setImageUri(asset.inactive);
21
- }
18
+ setImageUri(null);
19
+
20
+ return;
21
+ }
22
+
23
+ if (player.playerState.isReadyToPlay) {
24
+ if (player.playerState.isPaused) {
25
+ setImageUri(asset.active);
26
+ } else {
27
+ setImageUri(asset.inactive);
22
28
  }
29
+ }
23
30
 
24
- return player.addListener({
25
- id: "live-image-buttons",
26
- listener: {
27
- onPlayerResume: () => {
28
- setImageUri(asset.inactive);
29
- },
30
- onPlayerPause: () => {
31
- setImageUri(asset.active);
32
- },
33
- onPlayerClose: () => {
34
- setImageUri(null);
35
- },
36
- onLoad() {
37
- setImageUri(asset.inactive);
38
- },
31
+ return player.addListener({
32
+ id: liveImageButtonsListenerKey,
33
+ listener: {
34
+ onPlayerResume: () => {
35
+ setImageUri(asset.inactive);
39
36
  },
40
- });
41
- }
37
+ onPlayerPause: () => {
38
+ setImageUri(asset.active);
39
+ },
40
+ onPlayerClose: () => {
41
+ setImageUri(null);
42
+ },
43
+ onLoad() {
44
+ setImageUri(asset.inactive);
45
+ },
46
+ },
47
+ });
42
48
  }, [player, playerId, asset]);
43
49
 
44
50
  const useMuteUnmuteListeners = (playerId, player, asset, setImageUri) =>
45
51
  useEffect(() => {
46
- if (playerId && player) {
47
- // active action = muted, inactive = unmuted
48
- return player.addListener({
49
- id: "live-image-buttons",
50
- listener: {
51
- onPlayerMute: () => {
52
- if (isCurrentPlayer(playerId)) {
53
- setImageUri(asset.active);
54
- }
55
- },
56
- onPlayerUnmute: () => {
57
- if (isCurrentPlayer(playerId)) {
58
- setImageUri(asset.inactive);
59
- }
60
- },
61
- onLoad() {
62
- setImageUri(player?.getIsMuted() ? asset.active : asset.inactive);
63
- },
64
- onPlayerClose: () => {
65
- setImageUri(null);
66
- },
67
- onVideoEnd: () => {
68
- setImageUri(null);
69
- },
70
- },
71
- });
52
+ if (!player || !playerId) {
53
+ setImageUri(null);
54
+
55
+ return;
72
56
  }
57
+
58
+ // active action = muted, inactive = unmuted
59
+ return player.addListener({
60
+ id: liveImageButtonsListenerKey,
61
+ listener: {
62
+ onPlayerMute: () => {
63
+ if (isCurrentPlayer(playerId)) {
64
+ setImageUri(asset.active);
65
+ }
66
+ },
67
+ onPlayerUnmute: () => {
68
+ if (isCurrentPlayer(playerId)) {
69
+ setImageUri(asset.inactive);
70
+ }
71
+ },
72
+ onLoad() {
73
+ setImageUri(player?.getIsMuted() ? asset.active : asset.inactive);
74
+ },
75
+ onPlayerClose: () => {
76
+ setImageUri(null);
77
+ },
78
+ onVideoEnd: () => {
79
+ setImageUri(null);
80
+ },
81
+ },
82
+ });
73
83
  }, [player, playerId, asset]);
74
84
 
75
85
  const useListeners = MUTED_USAGE
@@ -21,7 +21,7 @@ const playActionCallback = (player) => {
21
21
  }
22
22
  };
23
23
 
24
- const invokeAction = () => {
24
+ const invokeAction = (_item: ZappEntry, _object) => {
25
25
  const actionCallback = MUTED_USAGE ? muteActionCallback : playActionCallback;
26
26
  // We only allow one player to be present at a time
27
27
  const player = LiveImageManager.instance.getCurrentlyPlaying()?.player;
@@ -29,6 +29,54 @@ const invokeAction = () => {
29
29
  actionCallback(player);
30
30
  };
31
31
 
32
+ // Not exported because currently the is no way
33
+ // to subscribe to the action availability change.
34
+ // We currently return a null state to disable the action.
35
+ // eslint-disable-next-line unused-imports/no-unused-vars
36
+ const isActionAvailable = (item: ZappEntry) => {
37
+ return (
38
+ LiveImageManager.instance.getCurrentlyPlaying()?.getPlayer().entry.id ===
39
+ item.id
40
+ );
41
+ };
42
+
43
+ const addListener = (
44
+ entryId: string,
45
+ listener: CellActionStateListenerFunction
46
+ ) => {
47
+ const callback = (event: Record<string, any>) => {
48
+ if (event.entry?.id !== entryId) {
49
+ return;
50
+ }
51
+
52
+ const player = LiveImageManager.instance.getCurrentlyPlaying()?.getPlayer();
53
+
54
+ if (!player || player.entry?.id !== entryId) {
55
+ listener(null);
56
+
57
+ return;
58
+ }
59
+
60
+ const actionState = MUTED_USAGE ? player.getIsMuted() : player.isPaused();
61
+
62
+ listener({
63
+ state: actionState ? 1 : 0,
64
+ label: "",
65
+ asset: AssetComponent,
66
+ });
67
+ };
68
+
69
+ return LiveImageManager.instance.addListener({
70
+ id: `cell-player-${entryId}`,
71
+ listener: {
72
+ onEnd: callback,
73
+ onStart: callback,
74
+ onError: callback,
75
+ onDestroy: callback,
76
+ },
77
+ });
78
+ };
79
+
32
80
  const emptyState = [];
33
81
 
34
82
  const initialEntryState = () => ({
@@ -46,6 +94,7 @@ export function ContextProvider(Component: ReactComponent<any>) {
46
94
  state: emptyState,
47
95
  invokeAction,
48
96
  initialEntryState,
97
+ addListener,
49
98
  }),
50
99
  [invokeAction, initialEntryState]
51
100
  );
@@ -388,6 +388,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
388
388
  <AnimationComponent
389
389
  animationType={ComponentAnimationType.moveUpComponent}
390
390
  additionalData={{ saveArea: true }}
391
+ style={Styles.playerContainer}
391
392
  >
392
393
  <AnimatedScrollModal>
393
394
  <View style={Styles.playerContainer} onLayout={onLayout}>
@@ -117,7 +117,6 @@ const playerDimensionsStyle = (
117
117
  });
118
118
 
119
119
  const animatedContainerStyle = (docked: boolean): ViewStyle => ({
120
- top: docked ? 2 : null,
121
120
  position: "absolute",
122
121
  width: "100%",
123
122
  zIndex: docked ? 1 : -1,
@@ -245,17 +244,19 @@ export default function DockedLayout(props: LayoutProps) {
245
244
  animatedContainerStyle(isActiveGesture || layoutState.docked),
246
245
  ]}
247
246
  >
248
- {!playerState.isLive && layoutState.docked && (
249
- <ProgressBar
250
- content={entry}
251
- value={value}
252
- visible={visible}
253
- layoutState={layoutState}
254
- onPlayerSeek={onPlayerSeek}
255
- playerState={playerState}
256
- docked
257
- />
258
- )}
247
+ {!playerState.isLive &&
248
+ (layoutState.docked || startComponentsAnimation) && (
249
+ <ProgressBar
250
+ content={entry}
251
+ value={value}
252
+ visible={visible}
253
+ layoutState={layoutState}
254
+ onPlayerSeek={onPlayerSeek}
255
+ playerState={playerState}
256
+ startComponentsAnimation={startComponentsAnimation}
257
+ docked
258
+ />
259
+ )}
259
260
 
260
261
  <View style={styles.content}>
261
262
  <View
@@ -21,14 +21,8 @@ import { PlayerWrapper } from "@applicaster/zapp-react-native-ui-components/Comp
21
21
 
22
22
  import { PlayNextOverlay } from "./PlayNextOverlay";
23
23
  import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
24
- import { AnalyticsTracker } from "@applicaster/zapp-react-native-utils/analyticsUtils/analyticsTracker";
25
24
 
26
- import {
27
- AD_EVENT,
28
- GENERAL_EVENT,
29
- PLAYBACK_EVENT,
30
- QOS_EVENT,
31
- } from "@applicaster/zapp-react-native-utils/analyticsUtils/events";
25
+ import { GENERAL_EVENT } from "@applicaster/zapp-react-native-utils/analyticsUtils/events";
32
26
  import { Categories, createLogger, Subsystem } from "../logger";
33
27
  import { parseLanguageTracks } from "@applicaster/zapp-react-native-utils/playerUtils/configurationUtils";
34
28
  import { DEFAULT_COLORS, SEEK_TIME } from "../utils/const";
@@ -42,6 +36,9 @@ import {
42
36
  AnimationComponent,
43
37
  ComponentAnimationType,
44
38
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
39
+ import { PlayerAnalyticsManager } from "@applicaster/zapp-react-native-utils/analyticsUtils/PlayerAnalyticsManager";
40
+ import { PlayerAnalyticsTrackerI } from "@applicaster/zapp-react-native-utils/analyticsUtils/playerAnalyticsTracker";
41
+
45
42
  import { RNPlayerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/nativePlayerManager";
46
43
 
47
44
  const styles = StyleSheet.create({
@@ -67,7 +64,6 @@ export default class VideoPlayer extends React.Component<
67
64
  > {
68
65
  public static propTypes = {};
69
66
  _root: any;
70
- analyticsTracker: AnalyticsTracker;
71
67
  playerPluginId: string;
72
68
  takeParentStyle: Record<any, any>;
73
69
  playbackStarted = false;
@@ -98,6 +94,17 @@ export default class VideoPlayer extends React.Component<
98
94
  duration: 0,
99
95
  };
100
96
 
97
+ private _tracker: PlayerAnalyticsTrackerI;
98
+ get analyticsTracker() {
99
+ if (!this._tracker) {
100
+ this._tracker = PlayerAnalyticsManager.getInstance().getTracker(
101
+ this.props.playerId
102
+ );
103
+ }
104
+
105
+ return this._tracker;
106
+ }
107
+
101
108
  constructor(props) {
102
109
  super(props);
103
110
  this.onVideoLoadCalled = false; // android
@@ -106,14 +113,13 @@ export default class VideoPlayer extends React.Component<
106
113
  ? { width: "100%", flex: "1 1 auto", objectFit: "contain" }
107
114
  : { flexBasis: "auto", flexGrow: 1, flexShrink: 1 };
108
115
 
109
- const entry = this.props?.entry;
110
- this.analyticsTracker = new AnalyticsTracker(entry);
111
116
  this.playerPluginId = this.props?.playerPluginIdentifier;
112
117
  }
113
118
 
114
119
  componentWillUnmount() {
115
120
  this.playbackStarted = false;
116
- this.handleAnalyticEvent(GENERAL_EVENT.session_end);
121
+
122
+ this.analyticsTracker.handleAnalyticEvent(GENERAL_EVENT.session_end);
117
123
  this.onPlayerClosed();
118
124
 
119
125
  if (isAndroidPlatform()) {
@@ -174,27 +180,6 @@ export default class VideoPlayer extends React.Component<
174
180
  return this.props.pluginConfiguration;
175
181
  };
176
182
 
177
- /**
178
- * Handles analytic events, generates a new analytics tracker and transmits events
179
- * Passes entry data, and playerState to the tracker for additional context
180
- * The end result is an event formatted and passed to AnalyticsBridge.postEvent
181
- * When we get the synthetic event we need to pull the data in the nativeEvent object
182
- * nativeEvent contains the return value from native
183
- */
184
- handleAnalyticEvent = (event, data = {}) => {
185
- const entry = this.props?.entry;
186
- const playerState = this.getState();
187
-
188
- if (this.analyticsTracker?.handleAnalyticEvent) {
189
- this.analyticsTracker?.handleAnalyticEvent?.(
190
- event,
191
- { ...data, player_type: this.props.playerPluginIdentifier },
192
- entry,
193
- playerState
194
- );
195
- }
196
- };
197
-
198
183
  /**
199
184
  * This method is for the events that have no implementation in react but are being invoked by native
200
185
  * When we get the synthetic event we need to pull the data in the nativeEvent object
@@ -335,11 +320,7 @@ export default class VideoPlayer extends React.Component<
335
320
  }
336
321
  };
337
322
 
338
- /**
339
- * Sets either subtitle language, or audio language if we have a selected a new locale.
340
- * If no locale is set it defaults to system language for audio, and leaves subtitles unaltered.
341
- */
342
- selectTrack = (selected = null) => {
323
+ selectTrack = (selected) => {
343
324
  const { trackType, id, language } = selected || {};
344
325
 
345
326
  const isOff = language === "Off";
@@ -398,28 +379,16 @@ export default class VideoPlayer extends React.Component<
398
379
  };
399
380
 
400
381
  onPlayerPresented = () => {
401
- this.handleAnalyticEvent(GENERAL_EVENT.player_presented);
382
+ this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_presented);
402
383
  };
403
384
 
404
385
  onPlayerClosed = () => {
405
- this.handleAnalyticEvent(GENERAL_EVENT.player_closed);
406
- };
407
-
408
- onPlayerSessionEnd = () => {
409
- // TODO: Implement method on native android, ios exists
410
- this.handleAnalyticEvent(GENERAL_EVENT.session_end);
411
- };
412
-
413
- onPlayerSessionStart = () => {
414
- // TODO: Implement method on native android, ios exists
415
-
416
- this.handleAnalyticEvent(GENERAL_EVENT.session_start);
386
+ this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_closed);
417
387
  };
418
388
 
419
389
  onVideoEnd = () => {
420
390
  this.setState({ displayOverlay: !this.state.displayOverlay }, () => {
421
391
  if (this.state?.displayOverlay) {
422
- this.handleAnalyticEvent(PLAYBACK_EVENT.complete);
423
392
  this.props?.listener?.onVideoEnd({});
424
393
  }
425
394
  });
@@ -429,15 +398,12 @@ export default class VideoPlayer extends React.Component<
429
398
  onVideoError = ({ nativeEvent }) => {
430
399
  const { message } = nativeEvent;
431
400
 
432
- this.handleAnalyticEvent(PLAYBACK_EVENT.error, nativeEvent);
433
-
434
401
  return this.props?.listener?.onError(new Error(message));
435
402
  };
436
403
 
437
404
  onPlayerPause = ({ nativeEvent = null }) => {
438
405
  this.setState({ paused: true });
439
406
  this.props?.listener?.onPlayerPause(nativeEvent);
440
- this.handleAnalyticEvent(PLAYBACK_EVENT.pause, nativeEvent);
441
407
  };
442
408
 
443
409
  onPlayerResume = ({ nativeEvent = null }) => {
@@ -448,98 +414,61 @@ export default class VideoPlayer extends React.Component<
448
414
 
449
415
  if (isNotAnAd && !resume) {
450
416
  this.setState({ resume: true });
451
- this.handleAnalyticEvent(PLAYBACK_EVENT.play, nativeEvent);
452
417
  }
453
418
  };
454
419
 
455
420
  onPlayerSeekComplete = ({ nativeEvent }) => {
456
421
  this.props?.listener?.onPlayerSeekComplete(nativeEvent);
457
- this.handleAnalyticEvent(PLAYBACK_EVENT.seek_complete, nativeEvent);
458
422
  };
459
423
 
460
424
  onPlayerSeekStart = ({ nativeEvent }) => {
461
425
  this.props?.listener?.onPlayerSeekStart(nativeEvent);
462
- this.handleAnalyticEvent(PLAYBACK_EVENT.seek_start, nativeEvent);
463
426
  };
464
427
 
465
428
  onBufferStart = ({ nativeEvent }) => {
466
429
  this.props?.listener?.onBufferStart(nativeEvent);
467
- this.handleAnalyticEvent(PLAYBACK_EVENT.buffer_start, nativeEvent);
468
430
  };
469
431
 
470
432
  onBufferComplete = ({ nativeEvent }) => {
471
433
  this.props?.listener?.onBufferComplete(nativeEvent);
472
- this.handleAnalyticEvent(PLAYBACK_EVENT.buffer_complete, nativeEvent);
473
- };
474
-
475
- onPlayerNext = ({ nativeEvent }) => {
476
- // TODO: Implement method on native
477
-
478
- this.handleAnalyticEvent(PLAYBACK_EVENT.next, nativeEvent);
479
- };
480
-
481
- onPlayerPrevious = ({ nativeEvent }) => {
482
- // TODO: Implement method on native
483
-
484
- this.handleAnalyticEvent(PLAYBACK_EVENT.previous, nativeEvent);
485
- };
486
-
487
- onPlayerStop = ({ nativeEvent }) => {
488
- // TODO: Implement method on native
489
-
490
- this.handleAnalyticEvent(PLAYBACK_EVENT.stop, nativeEvent);
491
- };
492
-
493
- onVideoBandwidthUpdate = ({ nativeEvent }) => {
494
- // TODO: Implement method on native
495
-
496
- this.handleAnalyticEvent(QOS_EVENT.bitrate_changed, nativeEvent);
497
434
  };
498
435
 
499
436
  onAdBegin = ({ nativeEvent }) => {
500
437
  this.setState({ isAd: true });
501
- this.handleAnalyticEvent(AD_EVENT.ad_start, nativeEvent);
502
438
  this.props.listener?.onAdBegin?.(nativeEvent);
503
439
  };
504
440
 
505
441
  onAdBreakBegin = ({ nativeEvent }) => {
506
442
  this.setState({ isAd: true });
507
- this.handleAnalyticEvent(AD_EVENT.ad_break_start, nativeEvent);
508
443
  this.props.listener?.onAdBreakBegin?.(nativeEvent);
509
444
  };
510
445
 
511
446
  onAdBreakEnd = ({ nativeEvent }) => {
512
447
  this.setState({ isAd: false });
513
- this.handleAnalyticEvent(AD_EVENT.ad_break_completed, nativeEvent);
514
448
  this.props.listener?.onAdBreakEnd?.(nativeEvent);
515
449
  };
516
450
 
517
451
  onAdEnd = ({ nativeEvent }) => {
518
452
  this.setState({ isAd: false });
519
- this.handleAnalyticEvent(AD_EVENT.ad_complete, nativeEvent);
520
453
  this.props.listener?.onAdEnd?.(nativeEvent);
521
454
  };
522
455
 
523
456
  onAdError = ({ nativeEvent }) => {
524
457
  this.setState({ isAd: false });
525
- this.handleAnalyticEvent(AD_EVENT.ad_error, nativeEvent);
526
458
  this.props.listener?.onAdError?.(nativeEvent);
527
459
  };
528
460
 
529
461
  onAdRequest = ({ nativeEvent }) => {
530
- this.handleAnalyticEvent(AD_EVENT.ad_request, nativeEvent);
531
462
  this.props.listener?.onAdRequest?.(nativeEvent);
532
463
  };
533
464
 
534
465
  onAdClicked = ({ nativeEvent }) => {
535
- this.handleAnalyticEvent(AD_EVENT.ad_clicked, nativeEvent);
536
466
  // Broadcast click event
537
467
  this.props.playerEvent("ad-clicked", nativeEvent);
538
468
  this.props.listener?.onAdClicked?.(nativeEvent);
539
469
  };
540
470
 
541
471
  onAdTapped = ({ nativeEvent }) => {
542
- this.handleAnalyticEvent(AD_EVENT.ad_tapped, nativeEvent);
543
472
  // Broadcast click event
544
473
  this.props.playerEvent("ad-tapped", nativeEvent);
545
474
  this.props.listener?.onAdTapped?.(nativeEvent);
@@ -652,10 +581,6 @@ export default class VideoPlayer extends React.Component<
652
581
  }
653
582
 
654
583
  if (!this.state.isAd && !this.onVideoLoadCalled) {
655
- this.handleAnalyticEvent(PLAYBACK_EVENT.load_video, {
656
- player_type: this.props.playerPluginIdentifier,
657
- });
658
-
659
584
  // TODO: Hack, needs to remove
660
585
  this.onVideoLoadCalled = true;
661
586
  }
@@ -857,7 +782,7 @@ export default class VideoPlayer extends React.Component<
857
782
  !!this.props.controller?.supportsNativeControls?.();
858
783
 
859
784
  const controls = isAppleTV()
860
- ? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
785
+ ? (supportsNativeControls && !isInlineTV) || !!this.getPlayNextData()
861
786
  : supportsNativeControls && !this.getPlayNextData();
862
787
 
863
788
  const shouldUseNativeControls =
@@ -923,8 +848,6 @@ export default class VideoPlayer extends React.Component<
923
848
  onPlayerResume: this.onPlayerResume, // play
924
849
  onPlayerSeekComplete: this.onPlayerSeekComplete, // seek_complete
925
850
  onPlayerSeekStart: this.onPlayerSeekStart, // seek_start
926
- onPlayerSessionEnd: this.onPlayerSessionEnd, // session_end
927
- onPlayerSessionStart: this.onPlayerSessionStart, // session_start
928
851
  };
929
852
 
930
853
  const lifecycleEvents = {
@@ -957,7 +880,6 @@ export default class VideoPlayer extends React.Component<
957
880
  onTimedMetadata: this.unHandledEvent("onTimedMetadata"),
958
881
  onTracksChanged: this.onTracksChanged,
959
882
  eventSubtitlesChange: this.unHandledEvent("eventSubtitlesChange"),
960
- onVideoBandwidthUpdate: this.onVideoBandwidthUpdate,
961
883
  };
962
884
 
963
885
  const playerSystemEvents = {
@@ -977,9 +899,6 @@ export default class VideoPlayer extends React.Component<
977
899
  const unsupportedEvents = {
978
900
  onBufferComplete: this.onBufferComplete, // buffer_complete
979
901
  onBufferStart: this.onBufferStart, // buffer_start
980
- onPlayerNext: this.onPlayerNext, // next
981
- onPlayerPrevious: this.onPlayerPrevious, // previous
982
- onPlayerStop: this.onPlayerStop, // stop
983
902
  };
984
903
 
985
904
  const nativeEvents = {
@@ -993,7 +912,13 @@ export default class VideoPlayer extends React.Component<
993
912
  ...androidLifecyclePiPEvents,
994
913
  };
995
914
 
996
- const needToShowPlayNextOverlay = this.getPlayNextData() && !docked;
915
+ const needToShowPlayNextOverlay =
916
+ isTV() && this.getPlayNextData() && !docked;
917
+
918
+ const needToShowDefaultControls = !(
919
+ (controls && !castAction?.state?.connected) ||
920
+ this.getPlayNextData()
921
+ );
997
922
 
998
923
  const playerContainerStyles = isApplePlatform()
999
924
  ? styles.playerContainerBlack
@@ -1035,7 +960,7 @@ export default class VideoPlayer extends React.Component<
1035
960
  extraInfoText={castAction?.state?.friendlyStatus}
1036
961
  controlsAlwaysVisible={castAction?.state?.connected}
1037
962
  playNextData={this.getPlayNextData()}
1038
- nativeControls={!!controls}
963
+ needToShowDefaultControls={needToShowDefaultControls}
1039
964
  />
1040
965
  ) : null;
1041
966
  };