@applicaster/quick-brick-player 12.0.0-alpha.3425722002 → 12.0.0-alpha.3455514658

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.3425722002",
3
+ "version": "12.0.0-alpha.3455514658",
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-rc.28",
40
- "@applicaster/quick-brick-tv-transport-controls": "11.0.0-rc.133",
41
- "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3425722002",
42
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3425722002",
43
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.3425722002",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "12.0.0-alpha.3455514658",
40
+ "@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.70",
41
+ "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3455514658",
42
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3455514658",
43
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.3455514658",
44
44
  "keymirror": "^0.1.1",
45
45
  "query-string": "7.1.3",
46
46
  "react-native-web-linear-gradient": "1.1.2",
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { ViewStyle, View, ScrollView } from "react-native";
2
+ import { ViewStyle, View } from "react-native";
3
3
 
4
4
  import { SafeAreaView, Edge } from "react-native-safe-area-context";
5
5
  import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
@@ -24,8 +24,15 @@ import {
24
24
  NAMESPACE,
25
25
  } from "./utils";
26
26
  import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
27
- import { getLiveUrl } from "../Utils";
27
+ import { addQueryParam, getLiveUrl } from "../Utils";
28
28
  import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
29
+ import {
30
+ AnimationComponent,
31
+ ComponentAnimationType,
32
+ AnimatedScrollModal,
33
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
34
+ import { PADDING_HORIZONTAL } from "./Layout/defaultLayoutsConts";
35
+ import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
29
36
 
30
37
  const { log_debug } = createLogger({
31
38
  subsystem: "UIComponent",
@@ -68,29 +75,20 @@ export const defaultAspectRatioWidth = (height: number): number =>
68
75
  (height / 9) * 16;
69
76
 
70
77
  const Styles = {
71
- mainContainer: (docked: boolean, style: ViewStyle) => {
78
+ mainContainer: (style: ViewStyle) => {
72
79
  const combinedStyle: ViewStyle = {
73
80
  flex: 1,
74
81
  };
75
82
 
76
- if (!docked) {
77
- style.paddingTop = 0;
78
- style.paddingHorizontal = 15;
79
- }
80
-
81
- return { ...combinedStyle, ...style };
82
- },
83
- playerContainer: (docked: boolean, style: ViewStyle) => {
84
- const combinedStyle: ViewStyle = {
85
- flex: 1,
83
+ return {
84
+ ...combinedStyle,
85
+ ...style,
86
86
  };
87
-
88
- if (docked) {
89
- combinedStyle.height = style.height;
90
- }
91
-
92
- return combinedStyle;
93
87
  },
88
+ playerContainer: {
89
+ flex: 1,
90
+ },
91
+ paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
94
92
 
95
93
  controlsMobile: {
96
94
  height: 50,
@@ -144,9 +142,9 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
144
142
  const isTablet = useIsTablet();
145
143
 
146
144
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
147
-
145
+
148
146
  // TODO: Have generic place for live url from configuration. Currently its hardcoded for client.
149
-
147
+
150
148
  const feedUrl = getLiveUrl(entry?.extensions?.live?.channel_src ?? "");
151
149
 
152
150
  const { title, summary } = useTitleSummaryOverlay(
@@ -168,6 +166,9 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
168
166
 
169
167
  const [sleepTimerDate, setSleepTimerDate] = useState(0);
170
168
 
169
+ const [defaultDimensions, setDefaultDimensions] =
170
+ React.useState<Dimensions>(undefined);
171
+
171
172
  const [dimensions, setDimensions] = React.useState<Dimensions>({
172
173
  width: 0,
173
174
  height: 0,
@@ -181,9 +182,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
181
182
  const { width, height } = event.nativeEvent.layout;
182
183
 
183
184
  setDimensions({
184
- width: docked ? defaultAspectRatioWidth(height) : width,
185
+ width,
185
186
  height,
186
187
  });
188
+
189
+ if (!defaultDimensions) setDefaultDimensions({ width, height });
187
190
  };
188
191
 
189
192
  const cancelSleepTimer = async () => {
@@ -195,7 +198,6 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
195
198
  });
196
199
 
197
200
  setSleepTimerDate(0);
198
- player?.pause();
199
201
 
200
202
  await localStorage.removeItem("sleep", NAMESPACE);
201
203
  };
@@ -293,7 +295,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
293
295
  playerState.isPaused ? player?.play() : player.pause();
294
296
  }, [playerState, player]);
295
297
 
296
- const seekDuration = Number(value("seek_duration"));
298
+ const seekDuration = toNumberWithDefault(10, value("seek_duration"));
297
299
 
298
300
  const onRewindButtonPress = React.useCallback(() => {
299
301
  player?.rewind(seekDuration);
@@ -376,58 +378,64 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
376
378
  player?.seekTo(0);
377
379
  }, [player]);
378
380
 
379
- const edges = React.useMemo<Edge[]>(
380
- () => (docked ? [] : ["right", "left", "top"]),
381
- [docked]
382
- );
381
+ const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
383
382
 
384
- const ContainerView = docked ? View : SafeAreaView;
383
+ const ContainerView = SafeAreaView;
385
384
 
386
385
  const MainContent = React.useMemo(() => {
387
386
  return (
388
- <ContainerView style={Styles.mainContainer(docked, style)} edges={edges}>
389
- <ScrollView
390
- style={Styles.playerContainer(docked, style)}
391
- onLayout={onLayout}
387
+ <ContainerView style={Styles.mainContainer(style)} edges={edges}>
388
+ <AnimationComponent
389
+ animationType={ComponentAnimationType.moveUpComponent}
390
+ additionalData={{ saveArea: true }}
392
391
  >
393
- <Layout
394
- entry={entry}
395
- playerState={playerState}
396
- layoutState={layoutState}
397
- value={value}
398
- onPlaybackButtonPress={onPlaybackButtonPress}
399
- onRewindButtonPress={onRewindButtonPress}
400
- onForwardButtonPress={onForwardButtonPress}
401
- onPlayerSeek={onPlayerSeek}
402
- onSkipStart={onSkipStart}
403
- onSpeedButtonPress={onSpeedButtonPress}
404
- onSleepButtonPress={onSleepButtonPress}
405
- playbackSpeedName={formatSpeed(playbackSpeed.value)}
406
- playbackSleepName={
407
- sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
408
- }
409
- sleepTimerDate={sleepTimerDate}
410
- cancelSleepTimer={cancelSleepTimer}
411
- onSkipLive={onSkipLive}
412
- onCloseVideoModal={onCloseVideoModal}
413
- maximiseVideoModal={maximiseVideoModal}
414
- configuration={configuration}
415
- dimensions={dimensions}
416
- playNextData={playNextData}
417
- title={title}
418
- summary={summary}
419
- />
420
- {children}
421
- {!docked && (
422
- <PlayerDetails
423
- configuration={configuration}
424
- style={Styles.playerDetails}
425
- entry={entry}
426
- isTabletLandscape={isTabletLandscape}
427
- isAudioPlayer={true}
428
- />
429
- )}
430
- </ScrollView>
392
+ <AnimatedScrollModal>
393
+ <View style={Styles.playerContainer} onLayout={onLayout}>
394
+ <Layout
395
+ entry={entry}
396
+ playerState={playerState}
397
+ layoutState={layoutState}
398
+ value={value}
399
+ onPlaybackButtonPress={onPlaybackButtonPress}
400
+ onRewindButtonPress={onRewindButtonPress}
401
+ onForwardButtonPress={onForwardButtonPress}
402
+ onPlayerSeek={onPlayerSeek}
403
+ onSkipStart={onSkipStart}
404
+ onSpeedButtonPress={onSpeedButtonPress}
405
+ onSleepButtonPress={onSleepButtonPress}
406
+ playbackSpeedName={formatSpeed(playbackSpeed.value)}
407
+ playbackSleepName={
408
+ sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
409
+ }
410
+ sleepTimerDate={sleepTimerDate}
411
+ cancelSleepTimer={cancelSleepTimer}
412
+ onSkipLive={onSkipLive}
413
+ onCloseVideoModal={onCloseVideoModal}
414
+ maximiseVideoModal={maximiseVideoModal}
415
+ configuration={configuration}
416
+ dimensions={dimensions}
417
+ playNextData={playNextData}
418
+ title={title}
419
+ summary={summary}
420
+ defaultDimensions={defaultDimensions}
421
+ />
422
+ <View style={Styles.paddingHorizontal}>
423
+ {children}
424
+ <AnimationComponent
425
+ animationType={ComponentAnimationType.componentFade}
426
+ >
427
+ <PlayerDetails
428
+ configuration={configuration}
429
+ style={Styles.playerDetails}
430
+ entry={entry}
431
+ isTabletLandscape={isTabletLandscape}
432
+ isAudioPlayer={true}
433
+ />
434
+ </AnimationComponent>
435
+ </View>
436
+ </View>
437
+ </AnimatedScrollModal>
438
+ </AnimationComponent>
431
439
  </ContainerView>
432
440
  );
433
441
  }, [
@@ -456,17 +464,20 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
456
464
  if (configuration.magic_background) {
457
465
  const baseUrl = entry?.extensions?.audio_player_background_image ?? "";
458
466
 
459
- // TODO: To be added when background is ready
467
+ const queryParamName =
468
+ configuration.audio_player_background_image_query || "width";
469
+
470
+ const queryParamValue = 15;
460
471
 
461
- // const queryParamName =
462
- // configuration.audio_player_background_image_query || "width";
463
- //
464
- // const queryParamValue = 15;
465
- //
466
- // const url = addQueryParam(baseUrl, queryParamName, queryParamValue);
472
+ const url = addQueryParam(baseUrl, queryParamName, queryParamValue);
467
473
 
468
474
  return (
469
- <MagicBG image={baseUrl} fallbackUrl={baseUrl} defaultColor="#000000">
475
+ <MagicBG
476
+ image={url}
477
+ fallbackUrl={baseUrl}
478
+ colors={entry?.extensions?.backgroundColors}
479
+ defaultColor="#000000"
480
+ >
470
481
  {MainContent}
471
482
  </MagicBG>
472
483
  );
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
3
  import { View } from "react-native";
4
+ import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
4
5
 
5
6
  import {
6
7
  ProgressBar,
@@ -18,13 +19,22 @@ import {
18
19
  rewindButton,
19
20
  skipToStartButton,
20
21
  skipToLiveButton,
22
+ PADDING_HORIZONTAL,
21
23
  speedButton,
22
24
  sleepButton,
23
25
  } from "./defaultLayoutsConts";
24
26
  import { AudioDescription } from "../AudioDescription";
25
27
  import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
26
28
  import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
29
+ import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
27
30
  import { useEffect, useMemo, useState } from "react";
31
+ import {
32
+ useModalAnimationContext,
33
+ AnimationComponent,
34
+ ComponentAnimationType,
35
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
36
+ import DockedLayout from "./DockedLayout";
37
+ import { isValidDate } from "../../Utils";
28
38
 
29
39
  type Dimensions = {
30
40
  width: number;
@@ -60,22 +70,29 @@ type LayoutProps = {
60
70
  onPlayerSeek: (targetTime: number) => void;
61
71
  onSkipLive: () => void;
62
72
  onSkipStart: () => void;
73
+ onCloseVideoModal: () => void;
74
+ maximiseVideoModal: () => void;
63
75
  dimensions: Dimensions;
76
+ playNextData: PlayNextData;
64
77
  title: string | number;
65
78
  summary: string | number;
79
+ defaultDimensions: Dimensions;
66
80
  };
67
81
 
68
82
  const Styles = {
69
83
  container: { flex: 1 },
70
- tabletContainer: (isPortraitMode) => ({
84
+ tabletContainer: (isPortraitMode: boolean) => ({
71
85
  flex: 1,
72
86
  alignItems: "center",
73
87
  justifyContent: isPortraitMode ? "center" : "flex-start",
74
88
  }),
75
- tabletLayout: {
76
- width: 463,
89
+ playerImageWrapper: {
90
+ width: "100%",
77
91
  maxHeight: 750,
78
92
  marginTop: 80,
93
+ },
94
+ tabletLayout: {
95
+ width: 463,
79
96
  marginBottom: 80,
80
97
  },
81
98
  controls: (isTablet: boolean, isLiveShowFullControls: boolean) => ({
@@ -84,24 +101,31 @@ const Styles = {
84
101
  justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
85
102
  }),
86
103
  backgroundImageContainer: (dimensions: Dimensions, isTablet: boolean) => {
104
+ const mobileValue = dimensions.width
105
+ ? dimensions.width - PADDING_HORIZONTAL * 2
106
+ : 330;
107
+
87
108
  return {
88
- width: isTablet ? 463 : dimensions.width || 330,
89
- height: isTablet ? 463 : dimensions.width || 330,
109
+ width: isTablet ? 463 : mobileValue,
110
+ height: isTablet ? 463 : mobileValue,
90
111
  };
91
112
  },
92
- backgroundImageContainerImageStyle: (isTablet) => ({
93
- borderRadius: isTablet ? 24 : 10,
113
+ backgroundImageContainerImageStyle: (
114
+ isTablet: boolean,
115
+ docked: boolean,
116
+ startComponentsAnimation: boolean,
117
+ isActiveGesture: boolean
118
+ ) => ({
119
+ borderRadius:
120
+ (startComponentsAnimation && isActiveGesture) || docked
121
+ ? 0
122
+ : isTablet
123
+ ? 24
124
+ : 10,
94
125
  }),
95
- playerContainer: (docked: boolean, style) => {
96
- const combinedStyle = {
97
- flex: 1,
98
- };
99
126
 
100
- if (docked) {
101
- combinedStyle["height"] = style.height;
102
- }
103
-
104
- return combinedStyle;
127
+ paddingHorizontal: {
128
+ paddingHorizontal: PADDING_HORIZONTAL,
105
129
  },
106
130
 
107
131
  controlsMobile: {
@@ -115,6 +139,12 @@ const Styles = {
115
139
  separator: {
116
140
  height: 20,
117
141
  },
142
+ flexDirectionRow: {
143
+ flexDirection: "row",
144
+ },
145
+ alignItemsCenter: {
146
+ alignItems: "center",
147
+ },
118
148
  };
119
149
 
120
150
  export default function DefaultLayout(props: LayoutProps) {
@@ -139,12 +169,14 @@ export default function DefaultLayout(props: LayoutProps) {
139
169
  sleepTimerDate,
140
170
  title,
141
171
  summary,
172
+ defaultDimensions,
142
173
  } = props;
143
174
 
144
175
  const isTablet = useIsTablet();
145
176
  const { width, height } = dimensions;
146
177
  const isPortraitMode = width < height;
147
178
  const isLiveContent = playerState.isLive;
179
+ const docked = layoutState.docked;
148
180
 
149
181
  const languageData = useLanguageData("audio-player");
150
182
 
@@ -160,8 +192,31 @@ export default function DefaultLayout(props: LayoutProps) {
160
192
 
161
193
  let showFullControls = !controller?.isAd();
162
194
 
195
+ const startTime = entry.extensions?.live?.start_time;
196
+ const endTime = entry.extensions?.live?.end_time;
197
+
198
+ const hasValidStartTime = isValidDate(startTime);
199
+ const hasValidEndTime = isValidDate(endTime);
200
+
201
+ const isDateBasedLiveContent =
202
+ isLiveContent && hasValidStartTime && hasValidEndTime;
203
+
204
+ const needsToShowProgressBar =
205
+ (isLiveContent &&
206
+ (Boolean(value("liveSeekingEnabled")) || isDateBasedLiveContent)) ||
207
+ !isLiveContent;
208
+
209
+ const startTimestamp = hasValidStartTime
210
+ ? dayjs.utc(startTime!).valueOf()
211
+ : undefined;
212
+
213
+ const endTimestamp = hasValidEndTime
214
+ ? dayjs.utc(endTime!).valueOf()
215
+ : undefined;
216
+
163
217
  if (isLiveContent) {
164
218
  const seekEnabled = Boolean(value("liveSeekingEnabled"));
219
+
165
220
  showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
166
221
  }
167
222
 
@@ -191,12 +246,14 @@ export default function DefaultLayout(props: LayoutProps) {
191
246
 
192
247
  const rewind = rewindButton({
193
248
  isTablet,
194
- onPress: controller?.hasContentDuration?.() ? onRewindButtonPress : null,
249
+ onPress: controller?.hasSeekableDuration?.() ? onRewindButtonPress : null,
195
250
  });
196
251
 
197
252
  const forward = forwardButton({
198
253
  isTablet,
199
- onPress: controller?.hasContentDuration?.() ? onForwardButtonPress : null,
254
+ onPress: controller?.hasSeekableDuration?.()
255
+ ? onForwardButtonPress
256
+ : null,
200
257
  });
201
258
 
202
259
  const speed = speedButton({
@@ -225,7 +282,6 @@ export default function DefaultLayout(props: LayoutProps) {
225
282
  return [skipToStart, rewind, play, forward, skipToLive];
226
283
  }
227
284
 
228
- // Temporary empty button until we add sleep button. It will ensure the buttons will not break in their position
229
285
  return [speed, rewind, play, forward, sleep];
230
286
  }, [
231
287
  playerState,
@@ -246,15 +302,12 @@ export default function DefaultLayout(props: LayoutProps) {
246
302
 
247
303
  useEffect(() => {
248
304
  if (showCounter && sleepTimerDate !== 0) {
249
- // Setting the initial timeLeft based on sleepTimerDate
250
305
  setTimeLeft(sleepTimerDate - Date.now());
251
306
 
252
- // Setting up an interval to update the remaining time every second
253
307
  const intervalId = setInterval(() => {
254
308
  setTimeLeft(() => {
255
309
  const newTimeLeft = sleepTimerDate - Date.now();
256
310
 
257
- // If the new remaining time is less than or equal to 0, clear the interval and trigger the cancelSleepTimer function
258
311
  if (newTimeLeft <= 0) {
259
312
  clearInterval(intervalId);
260
313
 
@@ -262,26 +315,28 @@ export default function DefaultLayout(props: LayoutProps) {
262
315
 
263
316
  return 0;
264
317
  } else {
265
- // Otherwise, update the state with the new remaining time
266
318
  return newTimeLeft;
267
319
  }
268
320
  });
269
321
  }, 1000);
270
322
 
271
- // Clearing the interval when the component unmounts or dependencies change
272
323
  return () => clearInterval(intervalId);
273
324
  } else {
274
- // Ensure the timeLeft state is set correctly if showCounter is false
275
325
  setTimeLeft(0);
276
326
  }
277
327
  }, [sleepTimerDate, showCounter, cancelSleepTimer]);
278
328
 
279
329
  const Separator = () => <View style={Styles.separator} />;
280
330
 
281
- const liveSeekingEnabled = value("liveSeekingEnabled");
331
+ const defaultImageDimensions = React.useMemo(
332
+ () =>
333
+ defaultDimensions &&
334
+ Styles.backgroundImageContainer(defaultDimensions, isTablet),
335
+ [defaultDimensions, isTablet]
336
+ );
282
337
 
283
- const needsToShowProgressBar =
284
- (isLiveContent && liveSeekingEnabled) || !isLiveContent;
338
+ const { isActiveGesture, startComponentsAnimation } =
339
+ useModalAnimationContext();
285
340
 
286
341
  return (
287
342
  <View
@@ -289,65 +344,108 @@ export default function DefaultLayout(props: LayoutProps) {
289
344
  isTablet ? Styles.tabletContainer(isPortraitMode) : Styles.container
290
345
  }
291
346
  >
292
- <TransportInfo
293
- content={entry}
294
- value={value}
295
- visible={true}
296
- languageData={languageData}
297
- layoutState={layoutState}
298
- actionButtons={actionButtons}
299
- />
300
- <View
301
- style={
302
- isTablet ? Styles.tabletContainer(isPortraitMode) : Styles.container
303
- }
347
+ <AnimationComponent animationType={ComponentAnimationType.componentFade}>
348
+ <TransportInfo
349
+ content={entry}
350
+ value={value}
351
+ visible={true}
352
+ languageData={languageData}
353
+ layoutState={layoutState}
354
+ actionButtons={actionButtons}
355
+ />
356
+ </AnimationComponent>
357
+ <AnimationComponent
358
+ animationType={ComponentAnimationType.moveUpComponent}
359
+ style={isTablet ? Styles.playerImageWrapper : undefined}
304
360
  >
305
- <View style={isTablet ? Styles.tabletLayout : null}>
361
+ <AnimationComponent
362
+ animationType={ComponentAnimationType.moveComponentHorizontal}
363
+ additionalData={{
364
+ disableAnimatedComponent: !isTablet,
365
+ moveValue: (dimensions.width - 463) / 2,
366
+ extraAnimation: !isTablet
367
+ ? {
368
+ [ComponentAnimationType.audioPlayerPaddingHorizontal]: {
369
+ style: Styles.paddingHorizontal,
370
+ },
371
+ }
372
+ : null,
373
+ }}
374
+ style={isTablet ? Styles.alignItemsCenter : undefined}
375
+ >
306
376
  <PlayerImageBackground
307
377
  entry={entry}
308
378
  style={Styles.backgroundImageContainer(dimensions, isTablet)}
309
- imageStyle={Styles.backgroundImageContainerImageStyle(isTablet)}
310
- />
311
- <AudioDescription
312
- title={title}
313
- summary={summary}
314
- value={value}
315
- layoutState={layoutState}
379
+ imageStyle={Styles.backgroundImageContainerImageStyle(
380
+ isTablet,
381
+ docked,
382
+ startComponentsAnimation,
383
+ isActiveGesture
384
+ )}
385
+ defaultImageDimensions={defaultImageDimensions}
316
386
  />
317
- <Separator />
318
- {needsToShowProgressBar && (
319
- <View>
320
- <ProgressBar
321
- content={entry}
322
- value={value}
323
- visible={true}
324
- layoutState={layoutState}
325
- onPlayerSeek={onPlayerSeek}
326
- playerState={playerState}
327
- disableFullscreen={true}
328
- sliderStyle={2}
329
- />
330
-
331
- {showCounter && timeLeft >= 0 && (
332
- <CountDown
333
- timeLeft={timeLeft}
387
+ </AnimationComponent>
388
+
389
+ <DockedLayout {...props} />
390
+ </AnimationComponent>
391
+ <View
392
+ style={[
393
+ Styles.paddingHorizontal,
394
+ isTablet ? Styles.tabletLayout : undefined,
395
+ ]}
396
+ >
397
+ {!docked && (
398
+ <AnimationComponent
399
+ animationType={ComponentAnimationType.componentFade}
400
+ >
401
+ <AudioDescription
402
+ title={title}
403
+ summary={summary}
404
+ value={value}
405
+ layoutState={layoutState}
406
+ />
407
+ <Separator />
408
+ {needsToShowProgressBar && (
409
+ <View>
410
+ <ProgressBar
411
+ content={entry}
334
412
  value={value}
335
- title={sleepTitle}
413
+ visible={true}
414
+ layoutState={layoutState}
415
+ onPlayerSeek={onPlayerSeek}
416
+ playerState={playerState}
417
+ disableFullscreen={true}
418
+ sliderStyle={2}
419
+ startTimestamp={startTimestamp}
420
+ endTimestamp={endTimestamp}
421
+ isDateBasedLiveContent={isDateBasedLiveContent}
422
+ onSkipLive={onSkipLive}
336
423
  />
337
- )}
338
424
 
339
- <Separator />
340
- </View>
341
- )}
342
- <Controls
343
- value={value}
344
- visible={true}
345
- keepAlive={null}
346
- buttons={controlButtons}
347
- style={Styles.controls(isTablet, isLiveContent && showFullControls)}
348
- playerState={playerState}
349
- />
350
- </View>
425
+ {showCounter && timeLeft >= 0 && (
426
+ <CountDown
427
+ timeLeft={timeLeft}
428
+ value={value}
429
+ title={sleepTitle}
430
+ />
431
+ )}
432
+
433
+ <Separator />
434
+ </View>
435
+ )}
436
+ <Controls
437
+ value={value}
438
+ visible={true}
439
+ keepAlive={null}
440
+ buttons={controlButtons}
441
+ style={Styles.controls(
442
+ isTablet,
443
+ isLiveContent && showFullControls
444
+ )}
445
+ playerState={playerState}
446
+ />
447
+ </AnimationComponent>
448
+ )}
351
449
  </View>
352
450
  </View>
353
451
  );
@@ -15,8 +15,13 @@ import {
15
15
  Button,
16
16
  } from "@applicaster/quick-brick-mobile-transport-controls";
17
17
 
18
- import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
19
18
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
19
+ import {
20
+ useModalAnimationContext,
21
+ AnimationComponent,
22
+ ComponentAnimationType,
23
+ PlayerAnimationStateEnum,
24
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
20
25
 
21
26
  type Dimensions = {
22
27
  width: number;
@@ -104,14 +109,26 @@ const backgroundColorStyle = (value: GetValue): ViewStyle => ({
104
109
  backgroundColor: value("docked_player_background_color"),
105
110
  });
106
111
 
107
- const playerDimensionsStyle = ({
108
- height,
109
- }: PlayerDimensionsProp): ViewStyle => ({
110
- paddingLeft: height || 100,
112
+ const playerDimensionsStyle = (
113
+ minimisedHeight: number,
114
+ addPadding: boolean
115
+ ): ViewStyle => ({
116
+ paddingLeft: addPadding ? minimisedHeight || 100 : 0,
111
117
  });
112
118
 
113
- const backgroundImageStyle = (dimensions: Dimensions): ViewStyle => ({
114
- height: dimensions.height,
119
+ const animatedContainerStyle = (docked: boolean): ViewStyle => ({
120
+ top: docked ? 2 : null,
121
+ position: "absolute",
122
+ width: "100%",
123
+ zIndex: docked ? 1 : -1,
124
+ });
125
+
126
+ const backgroundImageStyle = (
127
+ dimensions: Dimensions,
128
+ minimisedHeight: number,
129
+ isActiveGesture: boolean
130
+ ): ViewStyle => ({
131
+ height: isActiveGesture ? minimisedHeight : dimensions.height,
115
132
  aspectRatio: 1,
116
133
  position: "absolute",
117
134
  });
@@ -193,7 +210,6 @@ export default function DockedLayout(props: LayoutProps) {
193
210
  dimensions,
194
211
  entry,
195
212
  onCloseVideoModal,
196
- maximiseVideoModal,
197
213
  onPlayerSeek,
198
214
  playerState,
199
215
  configuration,
@@ -207,9 +223,29 @@ export default function DockedLayout(props: LayoutProps) {
207
223
  const visible = true;
208
224
  const liveButton = Boolean(value("live_badge_enabled"));
209
225
 
226
+ const {
227
+ isActiveGesture,
228
+ setPlayerAnimationState,
229
+ startComponentsAnimation,
230
+ minimisedHeight,
231
+ } = useModalAnimationContext();
232
+
233
+ const maximazeVideoModal = React.useCallback(
234
+ () => setPlayerAnimationState(PlayerAnimationStateEnum.maximaze),
235
+ []
236
+ );
237
+
238
+ if (!layoutState.docked && !startComponentsAnimation) return null;
239
+
210
240
  return (
211
- <View style={styles.container}>
212
- {!playerState.isLive && (
241
+ <AnimationComponent
242
+ animationType={ComponentAnimationType.componentAppears}
243
+ style={[
244
+ styles.container,
245
+ animatedContainerStyle(isActiveGesture || layoutState.docked),
246
+ ]}
247
+ >
248
+ {!playerState.isLive && layoutState.docked && (
213
249
  <ProgressBar
214
250
  content={entry}
215
251
  value={value}
@@ -217,18 +253,27 @@ export default function DockedLayout(props: LayoutProps) {
217
253
  layoutState={layoutState}
218
254
  onPlayerSeek={onPlayerSeek}
219
255
  playerState={playerState}
256
+ docked
220
257
  />
221
258
  )}
222
259
 
223
260
  <View style={styles.content}>
224
- <PlayerImageBackground
225
- configuration={configuration}
226
- entry={entry}
227
- style={backgroundImageStyle(dimensions)}
261
+ <View
262
+ style={backgroundImageStyle(
263
+ dimensions,
264
+ minimisedHeight,
265
+ isActiveGesture
266
+ )}
228
267
  />
229
- <TouchableWithoutFeedback onPress={maximiseVideoModal}>
268
+ <TouchableWithoutFeedback onPress={maximazeVideoModal}>
230
269
  <View
231
- style={[styles.touchableArea, playerDimensionsStyle(dimensions)]}
270
+ style={[
271
+ styles.touchableArea,
272
+ playerDimensionsStyle(
273
+ minimisedHeight,
274
+ isActiveGesture || layoutState.docked
275
+ ),
276
+ ]}
232
277
  >
233
278
  <View
234
279
  style={[
@@ -272,6 +317,6 @@ export default function DockedLayout(props: LayoutProps) {
272
317
  />
273
318
  </View>
274
319
  </View>
275
- </View>
320
+ </AnimationComponent>
276
321
  );
277
322
  }
@@ -19,6 +19,8 @@ const playbackButtonMargins = (
19
19
  ): number =>
20
20
  isLiveShowFullControls ? (isTablet ? 65 : 10) : isTablet ? 95 : 40;
21
21
 
22
+ export const PADDING_HORIZONTAL = 15;
23
+
22
24
  export const playbackButton = ({
23
25
  playerState,
24
26
  liveButton,
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import DefaultLayout from "./DefaultLayout";
3
- import DockedLayout from "./DockedLayout";
4
3
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
5
4
 
6
5
  type Dimensions = {
@@ -40,6 +39,7 @@ type LayoutProps = {
40
39
  onSkipLive: () => void;
41
40
  maximiseVideoModal: () => void;
42
41
  dimensions: Dimensions;
42
+ defaultDimensions: Dimensions;
43
43
  playNextData: PlayNextData;
44
44
  title: string | number;
45
45
  summary: string | number;
@@ -48,11 +48,5 @@ type LayoutProps = {
48
48
  export default function Layout(
49
49
  props: LayoutProps
50
50
  ): React.ReactElement<LayoutProps> {
51
- const { layoutState } = props;
52
-
53
- if (layoutState.docked) {
54
- return <DockedLayout {...props} />;
55
- }
56
-
57
51
  return <DefaultLayout {...props} />;
58
52
  }
@@ -1,7 +1,6 @@
1
- // Disabling for now as lint can't recognise typescript definition here
2
1
  /* eslint-disable react/prop-types */
3
2
  import * as React from "react";
4
- import { StyleSheet, View } from "react-native";
3
+ import { Animated, StyleSheet, View } from "react-native";
5
4
  import LinearGradient from "../LinearGradient";
6
5
  import { getDominantColor, getPalettes } from "../../../utils/utils";
7
6
  import { useEffect } from "react";
@@ -11,9 +10,10 @@ type MagicBGProps = {
11
10
  image: string;
12
11
  fallbackUrl?: string;
13
12
  defaultColor: string;
13
+ colors: string[];
14
14
  };
15
15
 
16
- const colors = {
16
+ const defaultColors = {
17
17
  overlay: "rgba(0, 0, 0, 0.35)",
18
18
  defaultGradientStart: "rgba(0, 0, 0, 0.25)",
19
19
  defaultGradientEnd: "rgba(0, 0, 0, 0)",
@@ -25,7 +25,7 @@ const styles = StyleSheet.create({
25
25
  },
26
26
  fullScreenOverlay: {
27
27
  ...StyleSheet.absoluteFillObject,
28
- backgroundColor: colors.overlay,
28
+ backgroundColor: defaultColors.overlay,
29
29
  },
30
30
  gradientOverlay: {
31
31
  position: "absolute",
@@ -54,52 +54,102 @@ export const MagicBG: React.FC<MagicBGProps> = ({
54
54
  children,
55
55
  image,
56
56
  fallbackUrl = "",
57
+ colors = [],
57
58
  defaultColor,
58
59
  }) => {
59
60
  const [dominantColor, setDominantColor] =
60
61
  React.useState<string>(defaultColor);
61
62
 
62
63
  const [gradientColors, setGradientColors] = React.useState<string[]>([
63
- colors.defaultGradientStart,
64
- colors.defaultGradientEnd,
64
+ defaultColors.defaultGradientStart,
65
+ defaultColors.defaultGradientEnd,
65
66
  ]);
66
67
 
67
- useEffect(() => {
68
- const fetchColors = async () => {
69
- if (!image) return;
68
+ const [backgroundColorAnim] = React.useState(new Animated.Value(0)); // from 0 to 1
69
+ const [gradientOpacityAnim] = React.useState(new Animated.Value(0)); // from 0 to 1
70
70
 
71
- try {
72
- const { gradientColors, dominantColor } =
73
- await fetchPaletteAndDominantColor(image);
71
+ useEffect(() => {
72
+ const animateColors = () => {
73
+ Animated.timing(backgroundColorAnim, {
74
+ toValue: 1,
75
+ duration: 500,
76
+ useNativeDriver: false,
77
+ }).start();
78
+
79
+ Animated.timing(gradientOpacityAnim, {
80
+ toValue: 1,
81
+ duration: 500,
82
+ useNativeDriver: false,
83
+ }).start();
84
+ };
74
85
 
75
- setGradientColors(gradientColors);
76
- setDominantColor(dominantColor);
77
- } catch (error) {
86
+ const fetchColors = async () => {
87
+ if (colors && colors.length > 0) {
88
+ setGradientColors(colors.slice(0, 2));
89
+ setDominantColor(colors[0]);
90
+ animateColors();
91
+ } else if (image) {
78
92
  try {
79
93
  const { gradientColors, dominantColor } =
80
- await fetchPaletteAndDominantColor(fallbackUrl);
94
+ await fetchPaletteAndDominantColor(image);
81
95
 
82
96
  setGradientColors(gradientColors);
83
97
  setDominantColor(dominantColor);
84
- } catch {
85
- setGradientColors([
86
- colors.defaultGradientStart,
87
- colors.defaultGradientEnd,
88
- ]);
89
-
90
- setDominantColor(defaultColor);
98
+ animateColors();
99
+ } catch (error) {
100
+ try {
101
+ const { gradientColors, dominantColor } =
102
+ await fetchPaletteAndDominantColor(fallbackUrl);
103
+
104
+ setGradientColors(gradientColors);
105
+ setDominantColor(dominantColor);
106
+ animateColors();
107
+ } catch {
108
+ setGradientColors([
109
+ defaultColors.defaultGradientStart,
110
+ defaultColors.defaultGradientEnd,
111
+ ]);
112
+
113
+ setDominantColor(defaultColor);
114
+ }
91
115
  }
116
+ } else {
117
+ setGradientColors([
118
+ defaultColors.defaultGradientStart,
119
+ defaultColors.defaultGradientEnd,
120
+ ]);
121
+
122
+ setDominantColor(defaultColor);
92
123
  }
93
124
  };
94
125
 
95
126
  fetchColors();
96
- }, [image, fallbackUrl, colors, defaultColor]);
127
+ }, []);
128
+
129
+ const interpolatedBackgroundColor = backgroundColorAnim.interpolate({
130
+ inputRange: [0, 1],
131
+ outputRange: ["black", dominantColor],
132
+ });
97
133
 
98
134
  return (
99
- <View style={[styles.container, { backgroundColor: dominantColor }]}>
135
+ <Animated.View
136
+ style={[
137
+ styles.container,
138
+ { backgroundColor: interpolatedBackgroundColor },
139
+ ]}
140
+ >
100
141
  <View style={styles.fullScreenOverlay} />
101
- <LinearGradient colors={gradientColors} style={styles.gradientOverlay} />
142
+
143
+ <Animated.View
144
+ style={[styles.gradientOverlay, { opacity: gradientOpacityAnim }]}
145
+ >
146
+ <LinearGradient
147
+ colors={gradientColors}
148
+ style={StyleSheet.absoluteFill}
149
+ />
150
+ </Animated.View>
151
+
102
152
  {children}
103
- </View>
153
+ </Animated.View>
104
154
  );
105
155
  };
@@ -1,26 +1,5 @@
1
1
  import queryString from "query-string";
2
-
3
- export const toTypeString = (obj) => {
4
- switch (typeof obj) {
5
- case "object":
6
- return obj instanceof Date ? obj.toISOString() : JSON.stringify(obj); // object, null
7
- case "undefined":
8
- return "";
9
- default:
10
- // boolean, number, string
11
- return obj.toString();
12
- }
13
- };
14
-
15
- export const stringsOnlyObject = (obj) => {
16
- const strObj = {};
17
-
18
- Object.keys(obj).forEach((x) => {
19
- strObj[x] = toTypeString(obj[x]);
20
- });
21
-
22
- return strObj;
23
- };
2
+ import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
24
3
 
25
4
  export const getLiveUrl = (url: string) => {
26
5
  // Use the replace method with a regular expression to replace all instances of subClass with livePage
@@ -42,3 +21,11 @@ export const addQueryParam = (
42
21
 
43
22
  return `${urlWithoutQuery}?${updatedQueryString}`;
44
23
  };
24
+
25
+ export const isValidDate = (dateString: string | undefined): boolean => {
26
+ return (
27
+ typeof dateString === "string" &&
28
+ dateString.trim() !== "" &&
29
+ dayjs.utc(dateString).isValid()
30
+ );
31
+ };
@@ -4,7 +4,7 @@
4
4
  import React from "react";
5
5
  import * as R from "ramda";
6
6
 
7
- import { findNodeHandle, NativeModules, StyleSheet, View } from "react-native";
7
+ import { findNodeHandle, StyleSheet, View } from "react-native";
8
8
  import TransportControlsMobile from "@applicaster/quick-brick-mobile-transport-controls";
9
9
  import TransportControlsTV from "@applicaster/quick-brick-tv-transport-controls";
10
10
 
@@ -38,15 +38,11 @@ import { getAllAccessibilityProps } from "@applicaster/zapp-react-native-utils/c
38
38
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
39
39
  import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
40
40
  import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
41
-
42
- const RNPlayerManager = {
43
- QuickBrickPlayerPlugin: isApplePlatform()
44
- ? NativeModules.PlayerModule
45
- : NativeModules.QuickBrickDefaultPlayerModule,
46
- KalturaPlayerPlugin: isApplePlatform()
47
- ? NativeModules.KalturaPlayerModule
48
- : NativeModules.QBKalturaPlayerModule,
49
- };
41
+ import {
42
+ AnimationComponent,
43
+ ComponentAnimationType,
44
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
45
+ import { RNPlayerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/nativePlayerManager";
50
46
 
51
47
  const styles = StyleSheet.create({
52
48
  container: { flex: 1 },
@@ -57,6 +53,7 @@ const styles = StyleSheet.create({
57
53
  position: "absolute",
58
54
  zIndex: 1,
59
55
  },
56
+ playerSize: { width: "100%", height: "100%" },
60
57
  });
61
58
 
62
59
  const logger = createLogger({
@@ -115,8 +112,6 @@ export default class VideoPlayer extends React.Component<
115
112
  }
116
113
 
117
114
  componentWillUnmount() {
118
- this.stopBackgroundPlayback();
119
-
120
115
  this.playbackStarted = false;
121
116
  this.handleAnalyticEvent(GENERAL_EVENT.session_end);
122
117
  this.onPlayerClosed();
@@ -161,6 +156,11 @@ export default class VideoPlayer extends React.Component<
161
156
  }
162
157
  }
163
158
 
159
+ // For close button
160
+ public closeNativePlayer = () => {
161
+ this.stopBackgroundPlayback();
162
+ };
163
+
164
164
  getPlayNextData = () => this.props.playNextData as PlayNextData;
165
165
 
166
166
  /**
@@ -339,7 +339,7 @@ export default class VideoPlayer extends React.Component<
339
339
  * Sets either subtitle language, or audio language if we have a selected a new locale.
340
340
  * If no locale is set it defaults to system language for audio, and leaves subtitles unaltered.
341
341
  */
342
- setLanguage = (selected = null) => {
342
+ selectTrack = (selected = null) => {
343
343
  const { trackType, id, language } = selected || {};
344
344
 
345
345
  const isOff = language === "Off";
@@ -780,7 +780,6 @@ export default class VideoPlayer extends React.Component<
780
780
 
781
781
  render() {
782
782
  const {
783
- castAction,
784
783
  docked,
785
784
  entry,
786
785
  fullscreen,
@@ -790,8 +789,13 @@ export default class VideoPlayer extends React.Component<
790
789
  isTabletPortrait,
791
790
  muted,
792
791
  style,
792
+ castAction,
793
+ controller,
794
+ startComponentsAnimation,
793
795
  } = this.props;
794
796
 
797
+ const supportNativeCast = controller.supportNativeCast();
798
+
795
799
  const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
796
800
  this.state;
797
801
 
@@ -853,11 +857,14 @@ export default class VideoPlayer extends React.Component<
853
857
  !!this.props.controller?.supportsNativeControls?.();
854
858
 
855
859
  const controls = isAppleTV()
856
- ? supportsNativeControls && isInlineTV && !this.getPlayNextData()
860
+ ? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
857
861
  : supportsNativeControls && !this.getPlayNextData();
858
862
 
859
863
  const shouldUseNativeControls =
860
- controls && supportsNativeControls && !docked;
864
+ controls &&
865
+ !startComponentsAnimation &&
866
+ !docked &&
867
+ !castAction?.state?.connected;
861
868
 
862
869
  platformSpecificProps = {
863
870
  ...platformSpecificProps,
@@ -1028,6 +1035,7 @@ export default class VideoPlayer extends React.Component<
1028
1035
  extraInfoText={castAction?.state?.friendlyStatus}
1029
1036
  controlsAlwaysVisible={castAction?.state?.connected}
1030
1037
  playNextData={this.getPlayNextData()}
1038
+ nativeControls={!!controls}
1031
1039
  />
1032
1040
  ) : null;
1033
1041
  };
@@ -1062,29 +1070,14 @@ export default class VideoPlayer extends React.Component<
1062
1070
  const renderMobilePlayer = () => {
1063
1071
  return isFullScreenAudioPlayer && isAudioItem ? (
1064
1072
  <View style={containerStyle}>
1065
- {!castAction?.state?.connected && (
1073
+ {(!castAction?.state?.connected || supportNativeCast) && (
1066
1074
  <this.props.PlayerComponent
1067
1075
  ref={this._assignRoot}
1068
1076
  {...nativeEvents}
1069
1077
  {...nativeProps}
1070
1078
  />
1071
1079
  )}
1072
- <AudioPlayerWrapper {...sharedWrapperViewProps}>
1073
- <View>
1074
- {
1075
- <PlayNextOverlay
1076
- item={entry}
1077
- playerIsDocked={docked}
1078
- pluginConfiguration={this.getPluginConfiguration()}
1079
- playerId={this.props.playerId}
1080
- playNextData={this.getPlayNextData()}
1081
- setNextVideoPreloadThresholdPercentage={
1082
- this.props.setNextVideoPreloadThresholdPercentage
1083
- }
1084
- />
1085
- }
1086
- </View>
1087
- </AudioPlayerWrapper>
1080
+ <AudioPlayerWrapper {...sharedWrapperViewProps} />
1088
1081
  </View>
1089
1082
  ) : (
1090
1083
  <PlayerWrapper {...sharedWrapperViewProps}>
@@ -1099,11 +1092,24 @@ export default class VideoPlayer extends React.Component<
1099
1092
  <View style={styles.container}>
1100
1093
  <View style={[playerContainerStyles, playerDimensions]}>
1101
1094
  {isAudioItem && (
1102
- <AudioPlayer
1103
- style={playerDimensions}
1104
- audio_item={entry}
1105
- plugin_configuration={this.getPluginConfiguration()}
1106
- />
1095
+ <AnimationComponent
1096
+ animationType={ComponentAnimationType.player}
1097
+ additionalData={{
1098
+ ...playerDimensions,
1099
+ inlineAudioPlayer: true,
1100
+ }}
1101
+ style={getStyle(playerDimensions)}
1102
+ >
1103
+ <AudioPlayer
1104
+ style={
1105
+ isTV()
1106
+ ? getStyle(playerDimensions)
1107
+ : styles.playerSize
1108
+ }
1109
+ audio_item={entry}
1110
+ plugin_configuration={this.getPluginConfiguration()}
1111
+ />
1112
+ </AnimationComponent>
1107
1113
  )}
1108
1114
 
1109
1115
  {shouldRenderBackground && (
@@ -1115,18 +1121,28 @@ export default class VideoPlayer extends React.Component<
1115
1121
  />
1116
1122
  )}
1117
1123
 
1118
- {!castAction?.state?.connected && (
1119
- <this.props.PlayerComponent
1120
- ref={this._assignRoot}
1121
- {...nativeEvents}
1122
- {...nativeProps}
1123
- listener={this.props.listener}
1124
+ {(!castAction?.state?.connected || supportNativeCast) && (
1125
+ <AnimationComponent
1126
+ animationType={ComponentAnimationType.player}
1127
+ additionalData={playerDimensions}
1124
1128
  style={getStyle(playerDimensions)}
1125
- pluginConfiguration={this.getPluginConfiguration()}
1126
- controller={this.props.controller}
1127
1129
  >
1128
- {this.childrenWithPlayNext()}
1129
- </this.props.PlayerComponent>
1130
+ <this.props.PlayerComponent
1131
+ ref={this._assignRoot}
1132
+ {...nativeEvents}
1133
+ {...nativeProps}
1134
+ listener={this.props.listener}
1135
+ style={
1136
+ isTV()
1137
+ ? getStyle(playerDimensions)
1138
+ : styles.playerSize
1139
+ }
1140
+ pluginConfiguration={this.getPluginConfiguration()}
1141
+ controller={this.props.controller}
1142
+ >
1143
+ {this.childrenWithPlayNext()}
1144
+ </this.props.PlayerComponent>
1145
+ </AnimationComponent>
1130
1146
  )}
1131
1147
  </View>
1132
1148