@applicaster/quick-brick-player 12.0.0-alpha.3208346089 → 12.0.0-alpha.3235354579

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.3208346089",
3
+ "version": "12.0.0-alpha.3235354579",
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.33",
40
- "@applicaster/quick-brick-tv-transport-controls": "11.0.0-rc.133",
41
- "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3208346089",
42
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3208346089",
43
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.3208346089",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "12.0.0-rc.58",
40
+ "@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.62",
41
+ "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3235354579",
42
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3235354579",
43
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.3235354579",
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";
@@ -26,6 +26,13 @@ import {
26
26
  import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
27
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,
@@ -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 () => {
@@ -292,7 +295,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
292
295
  playerState.isPaused ? player?.play() : player.pause();
293
296
  }, [playerState, player]);
294
297
 
295
- const seekDuration = Number(value("seek_duration"));
298
+ const seekDuration = toNumberWithDefault(10, value("seek_duration"));
296
299
 
297
300
  const onRewindButtonPress = React.useCallback(() => {
298
301
  player?.rewind(seekDuration);
@@ -375,58 +378,64 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
375
378
  player?.seekTo(0);
376
379
  }, [player]);
377
380
 
378
- const edges = React.useMemo<Edge[]>(
379
- () => (docked ? [] : ["right", "left", "top"]),
380
- [docked]
381
- );
381
+ const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
382
382
 
383
- const ContainerView = docked ? View : SafeAreaView;
383
+ const ContainerView = SafeAreaView;
384
384
 
385
385
  const MainContent = React.useMemo(() => {
386
386
  return (
387
- <ContainerView style={Styles.mainContainer(docked, style)} edges={edges}>
388
- <ScrollView
389
- style={Styles.playerContainer(docked, style)}
390
- onLayout={onLayout}
387
+ <ContainerView style={Styles.mainContainer(style)} edges={edges}>
388
+ <AnimationComponent
389
+ animationType={ComponentAnimationType.moveUpComponent}
390
+ additionalData={{ saveArea: true }}
391
391
  >
392
- <Layout
393
- entry={entry}
394
- playerState={playerState}
395
- layoutState={layoutState}
396
- value={value}
397
- onPlaybackButtonPress={onPlaybackButtonPress}
398
- onRewindButtonPress={onRewindButtonPress}
399
- onForwardButtonPress={onForwardButtonPress}
400
- onPlayerSeek={onPlayerSeek}
401
- onSkipStart={onSkipStart}
402
- onSpeedButtonPress={onSpeedButtonPress}
403
- onSleepButtonPress={onSleepButtonPress}
404
- playbackSpeedName={formatSpeed(playbackSpeed.value)}
405
- playbackSleepName={
406
- sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
407
- }
408
- sleepTimerDate={sleepTimerDate}
409
- cancelSleepTimer={cancelSleepTimer}
410
- onSkipLive={onSkipLive}
411
- onCloseVideoModal={onCloseVideoModal}
412
- maximiseVideoModal={maximiseVideoModal}
413
- configuration={configuration}
414
- dimensions={dimensions}
415
- playNextData={playNextData}
416
- title={title}
417
- summary={summary}
418
- />
419
- {children}
420
- {!docked && (
421
- <PlayerDetails
422
- configuration={configuration}
423
- style={Styles.playerDetails}
424
- entry={entry}
425
- isTabletLandscape={isTabletLandscape}
426
- isAudioPlayer={true}
427
- />
428
- )}
429
- </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>
430
439
  </ContainerView>
431
440
  );
432
441
  }, [
@@ -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,107 @@ 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}
336
422
  />
337
- )}
338
423
 
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>
424
+ {showCounter && timeLeft >= 0 && (
425
+ <CountDown
426
+ timeLeft={timeLeft}
427
+ value={value}
428
+ title={sleepTitle}
429
+ />
430
+ )}
431
+
432
+ <Separator />
433
+ </View>
434
+ )}
435
+ <Controls
436
+ value={value}
437
+ visible={true}
438
+ keepAlive={null}
439
+ buttons={controlButtons}
440
+ style={Styles.controls(
441
+ isTablet,
442
+ isLiveContent && showFullControls
443
+ )}
444
+ playerState={playerState}
445
+ />
446
+ </AnimationComponent>
447
+ )}
351
448
  </View>
352
449
  </View>
353
450
  );
@@ -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
  }
@@ -111,7 +111,7 @@ export const MagicBG: React.FC<MagicBGProps> = ({
111
111
  };
112
112
 
113
113
  fetchColors();
114
- }, [image, fallbackUrl, colors, defaultColor]);
114
+ }, []);
115
115
 
116
116
  return (
117
117
  <View style={[styles.container, { backgroundColor: dominantColor }]}>
@@ -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,7 @@ export const addQueryParam = (
42
21
 
43
22
  return `${urlWithoutQuery}?${updatedQueryString}`;
44
23
  };
24
+
25
+ export const isValidDate = (dateString: string): boolean => {
26
+ return dateString.trim() !== "" && dayjs.utc(dateString).isValid();
27
+ };
@@ -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";
@@ -38,6 +32,12 @@ import { getAllAccessibilityProps } from "@applicaster/zapp-react-native-utils/c
38
32
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
39
33
  import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
40
34
  import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
35
+ import {
36
+ AnimationComponent,
37
+ ComponentAnimationType,
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
41
 
42
42
  const RNPlayerManager = {
43
43
  QuickBrickPlayerPlugin: isApplePlatform()
@@ -57,6 +57,7 @@ const styles = StyleSheet.create({
57
57
  position: "absolute",
58
58
  zIndex: 1,
59
59
  },
60
+ playerSize: { width: "100%", height: "100%" },
60
61
  });
61
62
 
62
63
  const logger = createLogger({
@@ -70,7 +71,6 @@ export default class VideoPlayer extends React.Component<
70
71
  > {
71
72
  public static propTypes = {};
72
73
  _root: any;
73
- analyticsTracker: AnalyticsTracker;
74
74
  playerPluginId: string;
75
75
  takeParentStyle: Record<any, any>;
76
76
  playbackStarted = false;
@@ -101,6 +101,17 @@ export default class VideoPlayer extends React.Component<
101
101
  duration: 0,
102
102
  };
103
103
 
104
+ private _tracker: PlayerAnalyticsTrackerI;
105
+ get analyticsTracker() {
106
+ if (!this._tracker) {
107
+ this._tracker = PlayerAnalyticsManager.getInstance().getTracker(
108
+ this.props.playerId
109
+ );
110
+ }
111
+
112
+ return this._tracker;
113
+ }
114
+
104
115
  constructor(props) {
105
116
  super(props);
106
117
  this.onVideoLoadCalled = false; // android
@@ -109,8 +120,6 @@ export default class VideoPlayer extends React.Component<
109
120
  ? { width: "100%", flex: "1 1 auto", objectFit: "contain" }
110
121
  : { flexBasis: "auto", flexGrow: 1, flexShrink: 1 };
111
122
 
112
- const entry = this.props?.entry;
113
- this.analyticsTracker = new AnalyticsTracker(entry);
114
123
  this.playerPluginId = this.props?.playerPluginIdentifier;
115
124
  }
116
125
 
@@ -118,7 +127,8 @@ export default class VideoPlayer extends React.Component<
118
127
  this.stopBackgroundPlayback();
119
128
 
120
129
  this.playbackStarted = false;
121
- this.handleAnalyticEvent(GENERAL_EVENT.session_end);
130
+
131
+ this.analyticsTracker.handleAnalyticEvent(GENERAL_EVENT.session_end);
122
132
  this.onPlayerClosed();
123
133
 
124
134
  if (isAndroidPlatform()) {
@@ -174,27 +184,6 @@ export default class VideoPlayer extends React.Component<
174
184
  return this.props.pluginConfiguration;
175
185
  };
176
186
 
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
187
  /**
199
188
  * This method is for the events that have no implementation in react but are being invoked by native
200
189
  * When we get the synthetic event we need to pull the data in the nativeEvent object
@@ -398,28 +387,16 @@ export default class VideoPlayer extends React.Component<
398
387
  };
399
388
 
400
389
  onPlayerPresented = () => {
401
- this.handleAnalyticEvent(GENERAL_EVENT.player_presented);
390
+ this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_presented);
402
391
  };
403
392
 
404
393
  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);
394
+ this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_closed);
417
395
  };
418
396
 
419
397
  onVideoEnd = () => {
420
398
  this.setState({ displayOverlay: !this.state.displayOverlay }, () => {
421
399
  if (this.state?.displayOverlay) {
422
- this.handleAnalyticEvent(PLAYBACK_EVENT.complete);
423
400
  this.props?.listener?.onVideoEnd({});
424
401
  }
425
402
  });
@@ -429,15 +406,12 @@ export default class VideoPlayer extends React.Component<
429
406
  onVideoError = ({ nativeEvent }) => {
430
407
  const { message } = nativeEvent;
431
408
 
432
- this.handleAnalyticEvent(PLAYBACK_EVENT.error, nativeEvent);
433
-
434
409
  return this.props?.listener?.onError(new Error(message));
435
410
  };
436
411
 
437
412
  onPlayerPause = ({ nativeEvent = null }) => {
438
413
  this.setState({ paused: true });
439
414
  this.props?.listener?.onPlayerPause(nativeEvent);
440
- this.handleAnalyticEvent(PLAYBACK_EVENT.pause, nativeEvent);
441
415
  };
442
416
 
443
417
  onPlayerResume = ({ nativeEvent = null }) => {
@@ -448,98 +422,61 @@ export default class VideoPlayer extends React.Component<
448
422
 
449
423
  if (isNotAnAd && !resume) {
450
424
  this.setState({ resume: true });
451
- this.handleAnalyticEvent(PLAYBACK_EVENT.play, nativeEvent);
452
425
  }
453
426
  };
454
427
 
455
428
  onPlayerSeekComplete = ({ nativeEvent }) => {
456
429
  this.props?.listener?.onPlayerSeekComplete(nativeEvent);
457
- this.handleAnalyticEvent(PLAYBACK_EVENT.seek_complete, nativeEvent);
458
430
  };
459
431
 
460
432
  onPlayerSeekStart = ({ nativeEvent }) => {
461
433
  this.props?.listener?.onPlayerSeekStart(nativeEvent);
462
- this.handleAnalyticEvent(PLAYBACK_EVENT.seek_start, nativeEvent);
463
434
  };
464
435
 
465
436
  onBufferStart = ({ nativeEvent }) => {
466
437
  this.props?.listener?.onBufferStart(nativeEvent);
467
- this.handleAnalyticEvent(PLAYBACK_EVENT.buffer_start, nativeEvent);
468
438
  };
469
439
 
470
440
  onBufferComplete = ({ nativeEvent }) => {
471
441
  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
442
  };
498
443
 
499
444
  onAdBegin = ({ nativeEvent }) => {
500
445
  this.setState({ isAd: true });
501
- this.handleAnalyticEvent(AD_EVENT.ad_start, nativeEvent);
502
446
  this.props.listener?.onAdBegin?.(nativeEvent);
503
447
  };
504
448
 
505
449
  onAdBreakBegin = ({ nativeEvent }) => {
506
450
  this.setState({ isAd: true });
507
- this.handleAnalyticEvent(AD_EVENT.ad_break_start, nativeEvent);
508
451
  this.props.listener?.onAdBreakBegin?.(nativeEvent);
509
452
  };
510
453
 
511
454
  onAdBreakEnd = ({ nativeEvent }) => {
512
455
  this.setState({ isAd: false });
513
- this.handleAnalyticEvent(AD_EVENT.ad_break_completed, nativeEvent);
514
456
  this.props.listener?.onAdBreakEnd?.(nativeEvent);
515
457
  };
516
458
 
517
459
  onAdEnd = ({ nativeEvent }) => {
518
460
  this.setState({ isAd: false });
519
- this.handleAnalyticEvent(AD_EVENT.ad_complete, nativeEvent);
520
461
  this.props.listener?.onAdEnd?.(nativeEvent);
521
462
  };
522
463
 
523
464
  onAdError = ({ nativeEvent }) => {
524
465
  this.setState({ isAd: false });
525
- this.handleAnalyticEvent(AD_EVENT.ad_error, nativeEvent);
526
466
  this.props.listener?.onAdError?.(nativeEvent);
527
467
  };
528
468
 
529
469
  onAdRequest = ({ nativeEvent }) => {
530
- this.handleAnalyticEvent(AD_EVENT.ad_request, nativeEvent);
531
470
  this.props.listener?.onAdRequest?.(nativeEvent);
532
471
  };
533
472
 
534
473
  onAdClicked = ({ nativeEvent }) => {
535
- this.handleAnalyticEvent(AD_EVENT.ad_clicked, nativeEvent);
536
474
  // Broadcast click event
537
475
  this.props.playerEvent("ad-clicked", nativeEvent);
538
476
  this.props.listener?.onAdClicked?.(nativeEvent);
539
477
  };
540
478
 
541
479
  onAdTapped = ({ nativeEvent }) => {
542
- this.handleAnalyticEvent(AD_EVENT.ad_tapped, nativeEvent);
543
480
  // Broadcast click event
544
481
  this.props.playerEvent("ad-tapped", nativeEvent);
545
482
  this.props.listener?.onAdTapped?.(nativeEvent);
@@ -652,10 +589,6 @@ export default class VideoPlayer extends React.Component<
652
589
  }
653
590
 
654
591
  if (!this.state.isAd && !this.onVideoLoadCalled) {
655
- this.handleAnalyticEvent(PLAYBACK_EVENT.load_video, {
656
- player_type: this.props.playerPluginIdentifier,
657
- });
658
-
659
592
  // TODO: Hack, needs to remove
660
593
  this.onVideoLoadCalled = true;
661
594
  }
@@ -780,7 +713,6 @@ export default class VideoPlayer extends React.Component<
780
713
 
781
714
  render() {
782
715
  const {
783
- castAction,
784
716
  docked,
785
717
  entry,
786
718
  fullscreen,
@@ -790,8 +722,13 @@ export default class VideoPlayer extends React.Component<
790
722
  isTabletPortrait,
791
723
  muted,
792
724
  style,
725
+ castAction,
726
+ controller,
727
+ startComponentsAnimation,
793
728
  } = this.props;
794
729
 
730
+ const supportNativeCast = controller.supportNativeCast();
731
+
795
732
  const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
796
733
  this.state;
797
734
 
@@ -856,7 +793,11 @@ export default class VideoPlayer extends React.Component<
856
793
  ? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
857
794
  : supportsNativeControls && !this.getPlayNextData();
858
795
 
859
- const shouldUseNativeControls = controls && !docked;
796
+ const shouldUseNativeControls =
797
+ controls &&
798
+ !startComponentsAnimation &&
799
+ !docked &&
800
+ !castAction?.state?.connected;
860
801
 
861
802
  platformSpecificProps = {
862
803
  ...platformSpecificProps,
@@ -915,8 +856,6 @@ export default class VideoPlayer extends React.Component<
915
856
  onPlayerResume: this.onPlayerResume, // play
916
857
  onPlayerSeekComplete: this.onPlayerSeekComplete, // seek_complete
917
858
  onPlayerSeekStart: this.onPlayerSeekStart, // seek_start
918
- onPlayerSessionEnd: this.onPlayerSessionEnd, // session_end
919
- onPlayerSessionStart: this.onPlayerSessionStart, // session_start
920
859
  };
921
860
 
922
861
  const lifecycleEvents = {
@@ -949,7 +888,6 @@ export default class VideoPlayer extends React.Component<
949
888
  onTimedMetadata: this.unHandledEvent("onTimedMetadata"),
950
889
  onTracksChanged: this.onTracksChanged,
951
890
  eventSubtitlesChange: this.unHandledEvent("eventSubtitlesChange"),
952
- onVideoBandwidthUpdate: this.onVideoBandwidthUpdate,
953
891
  };
954
892
 
955
893
  const playerSystemEvents = {
@@ -969,9 +907,6 @@ export default class VideoPlayer extends React.Component<
969
907
  const unsupportedEvents = {
970
908
  onBufferComplete: this.onBufferComplete, // buffer_complete
971
909
  onBufferStart: this.onBufferStart, // buffer_start
972
- onPlayerNext: this.onPlayerNext, // next
973
- onPlayerPrevious: this.onPlayerPrevious, // previous
974
- onPlayerStop: this.onPlayerStop, // stop
975
910
  };
976
911
 
977
912
  const nativeEvents = {
@@ -1027,6 +962,7 @@ export default class VideoPlayer extends React.Component<
1027
962
  extraInfoText={castAction?.state?.friendlyStatus}
1028
963
  controlsAlwaysVisible={castAction?.state?.connected}
1029
964
  playNextData={this.getPlayNextData()}
965
+ nativeControls={!!controls}
1030
966
  />
1031
967
  ) : null;
1032
968
  };
@@ -1061,29 +997,14 @@ export default class VideoPlayer extends React.Component<
1061
997
  const renderMobilePlayer = () => {
1062
998
  return isFullScreenAudioPlayer && isAudioItem ? (
1063
999
  <View style={containerStyle}>
1064
- {!castAction?.state?.connected && (
1000
+ {(!castAction?.state?.connected || supportNativeCast) && (
1065
1001
  <this.props.PlayerComponent
1066
1002
  ref={this._assignRoot}
1067
1003
  {...nativeEvents}
1068
1004
  {...nativeProps}
1069
1005
  />
1070
1006
  )}
1071
- <AudioPlayerWrapper {...sharedWrapperViewProps}>
1072
- <View>
1073
- {
1074
- <PlayNextOverlay
1075
- item={entry}
1076
- playerIsDocked={docked}
1077
- pluginConfiguration={this.getPluginConfiguration()}
1078
- playerId={this.props.playerId}
1079
- playNextData={this.getPlayNextData()}
1080
- setNextVideoPreloadThresholdPercentage={
1081
- this.props.setNextVideoPreloadThresholdPercentage
1082
- }
1083
- />
1084
- }
1085
- </View>
1086
- </AudioPlayerWrapper>
1007
+ <AudioPlayerWrapper {...sharedWrapperViewProps} />
1087
1008
  </View>
1088
1009
  ) : (
1089
1010
  <PlayerWrapper {...sharedWrapperViewProps}>
@@ -1098,11 +1019,24 @@ export default class VideoPlayer extends React.Component<
1098
1019
  <View style={styles.container}>
1099
1020
  <View style={[playerContainerStyles, playerDimensions]}>
1100
1021
  {isAudioItem && (
1101
- <AudioPlayer
1102
- style={playerDimensions}
1103
- audio_item={entry}
1104
- plugin_configuration={this.getPluginConfiguration()}
1105
- />
1022
+ <AnimationComponent
1023
+ animationType={ComponentAnimationType.player}
1024
+ additionalData={{
1025
+ ...playerDimensions,
1026
+ inlineAudioPlayer: true,
1027
+ }}
1028
+ style={getStyle(playerDimensions)}
1029
+ >
1030
+ <AudioPlayer
1031
+ style={
1032
+ isTV()
1033
+ ? getStyle(playerDimensions)
1034
+ : styles.playerSize
1035
+ }
1036
+ audio_item={entry}
1037
+ plugin_configuration={this.getPluginConfiguration()}
1038
+ />
1039
+ </AnimationComponent>
1106
1040
  )}
1107
1041
 
1108
1042
  {shouldRenderBackground && (
@@ -1114,18 +1048,28 @@ export default class VideoPlayer extends React.Component<
1114
1048
  />
1115
1049
  )}
1116
1050
 
1117
- {!castAction?.state?.connected && (
1118
- <this.props.PlayerComponent
1119
- ref={this._assignRoot}
1120
- {...nativeEvents}
1121
- {...nativeProps}
1122
- listener={this.props.listener}
1051
+ {(!castAction?.state?.connected || supportNativeCast) && (
1052
+ <AnimationComponent
1053
+ animationType={ComponentAnimationType.player}
1054
+ additionalData={playerDimensions}
1123
1055
  style={getStyle(playerDimensions)}
1124
- pluginConfiguration={this.getPluginConfiguration()}
1125
- controller={this.props.controller}
1126
1056
  >
1127
- {this.childrenWithPlayNext()}
1128
- </this.props.PlayerComponent>
1057
+ <this.props.PlayerComponent
1058
+ ref={this._assignRoot}
1059
+ {...nativeEvents}
1060
+ {...nativeProps}
1061
+ listener={this.props.listener}
1062
+ style={
1063
+ isTV()
1064
+ ? getStyle(playerDimensions)
1065
+ : styles.playerSize
1066
+ }
1067
+ pluginConfiguration={this.getPluginConfiguration()}
1068
+ controller={this.props.controller}
1069
+ >
1070
+ {this.childrenWithPlayNext()}
1071
+ </this.props.PlayerComponent>
1072
+ </AnimationComponent>
1129
1073
  )}
1130
1074
  </View>
1131
1075