@applicaster/quick-brick-player 12.0.0-alpha.9531194637 → 12.0.0-alpha.9709055278

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.9531194637",
3
+ "version": "12.0.0-alpha.9709055278",
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",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "12.0.0-alpha.9709055278",
40
40
  "@applicaster/quick-brick-tv-transport-controls": "11.0.0-rc.133",
41
- "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.9531194637",
42
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.9531194637",
43
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.9531194637",
41
+ "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.9709055278",
42
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.9709055278",
43
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.9709055278",
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,12 @@ 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";
29
35
 
30
36
  const { log_debug } = createLogger({
31
37
  subsystem: "UIComponent",
@@ -68,29 +74,20 @@ export const defaultAspectRatioWidth = (height: number): number =>
68
74
  (height / 9) * 16;
69
75
 
70
76
  const Styles = {
71
- mainContainer: (docked: boolean, style: ViewStyle) => {
77
+ mainContainer: (style: ViewStyle) => {
72
78
  const combinedStyle: ViewStyle = {
73
79
  flex: 1,
74
80
  };
75
81
 
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,
82
+ return {
83
+ ...combinedStyle,
84
+ ...style,
86
85
  };
87
-
88
- if (docked) {
89
- combinedStyle.height = style.height;
90
- }
91
-
92
- return combinedStyle;
93
86
  },
87
+ playerContainer: {
88
+ flex: 1,
89
+ },
90
+ paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
94
91
 
95
92
  controlsMobile: {
96
93
  height: 50,
@@ -168,6 +165,9 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
168
165
 
169
166
  const [sleepTimerDate, setSleepTimerDate] = useState(0);
170
167
 
168
+ const [defaultDimensions, setDefaultDimensions] =
169
+ React.useState<Dimensions>(undefined);
170
+
171
171
  const [dimensions, setDimensions] = React.useState<Dimensions>({
172
172
  width: 0,
173
173
  height: 0,
@@ -181,9 +181,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
181
181
  const { width, height } = event.nativeEvent.layout;
182
182
 
183
183
  setDimensions({
184
- width: docked ? defaultAspectRatioWidth(height) : width,
184
+ width,
185
185
  height,
186
186
  });
187
+
188
+ if (!defaultDimensions) setDefaultDimensions({ width, height });
187
189
  };
188
190
 
189
191
  const cancelSleepTimer = async () => {
@@ -292,7 +294,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
292
294
  playerState.isPaused ? player?.play() : player.pause();
293
295
  }, [playerState, player]);
294
296
 
295
- const seekDuration = Number(value("seek_duration"));
297
+ const seekDuration = Number(value("seek_duration")) ?? 10;
296
298
 
297
299
  const onRewindButtonPress = React.useCallback(() => {
298
300
  player?.rewind(seekDuration);
@@ -375,58 +377,64 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
375
377
  player?.seekTo(0);
376
378
  }, [player]);
377
379
 
378
- const edges = React.useMemo<Edge[]>(
379
- () => (docked ? [] : ["right", "left", "top"]),
380
- [docked]
381
- );
380
+ const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
382
381
 
383
- const ContainerView = docked ? View : SafeAreaView;
382
+ const ContainerView = SafeAreaView;
384
383
 
385
384
  const MainContent = React.useMemo(() => {
386
385
  return (
387
- <ContainerView style={Styles.mainContainer(docked, style)} edges={edges}>
388
- <ScrollView
389
- style={Styles.playerContainer(docked, style)}
390
- onLayout={onLayout}
386
+ <ContainerView style={Styles.mainContainer(style)} edges={edges}>
387
+ <AnimationComponent
388
+ animationType={ComponentAnimationType.moveUpComponent}
389
+ additionalData={{ saveArea: true }}
391
390
  >
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>
391
+ <AnimatedScrollModal>
392
+ <View style={Styles.playerContainer} onLayout={onLayout}>
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
+ defaultDimensions={defaultDimensions}
420
+ />
421
+ <View style={Styles.paddingHorizontal}>
422
+ {children}
423
+ <AnimationComponent
424
+ animationType={ComponentAnimationType.componentFade}
425
+ >
426
+ <PlayerDetails
427
+ configuration={configuration}
428
+ style={Styles.playerDetails}
429
+ entry={entry}
430
+ isTabletLandscape={isTabletLandscape}
431
+ isAudioPlayer={true}
432
+ />
433
+ </AnimationComponent>
434
+ </View>
435
+ </View>
436
+ </AnimatedScrollModal>
437
+ </AnimationComponent>
430
438
  </ContainerView>
431
439
  );
432
440
  }, [
@@ -1,6 +1,10 @@
1
+ // DefaultLayout.tsx
2
+
1
3
  import * as React from "react";
2
4
  import * as R from "ramda";
3
5
  import { View } from "react-native";
6
+ import dayjs from "dayjs";
7
+ import utc from "dayjs/plugin/utc";
4
8
 
5
9
  import {
6
10
  ProgressBar,
@@ -18,13 +22,24 @@ import {
18
22
  rewindButton,
19
23
  skipToStartButton,
20
24
  skipToLiveButton,
25
+ PADDING_HORIZONTAL,
21
26
  speedButton,
22
27
  sleepButton,
23
28
  } from "./defaultLayoutsConts";
24
29
  import { AudioDescription } from "../AudioDescription";
25
30
  import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
26
31
  import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
32
+ import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
27
33
  import { useEffect, useMemo, useState } from "react";
34
+ import {
35
+ useModalAnimationContext,
36
+ AnimationComponent,
37
+ ComponentAnimationType,
38
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
39
+ import DockedLayout from "./DockedLayout";
40
+ import { isValidDate } from "../../Utils";
41
+
42
+ dayjs.extend(utc);
28
43
 
29
44
  type Dimensions = {
30
45
  width: number;
@@ -60,22 +75,29 @@ type LayoutProps = {
60
75
  onPlayerSeek: (targetTime: number) => void;
61
76
  onSkipLive: () => void;
62
77
  onSkipStart: () => void;
78
+ onCloseVideoModal: () => void;
79
+ maximiseVideoModal: () => void;
63
80
  dimensions: Dimensions;
81
+ playNextData: PlayNextData;
64
82
  title: string | number;
65
83
  summary: string | number;
84
+ defaultDimensions: Dimensions;
66
85
  };
67
86
 
68
87
  const Styles = {
69
88
  container: { flex: 1 },
70
- tabletContainer: (isPortraitMode) => ({
89
+ tabletContainer: (isPortraitMode: boolean) => ({
71
90
  flex: 1,
72
91
  alignItems: "center",
73
92
  justifyContent: isPortraitMode ? "center" : "flex-start",
74
93
  }),
75
- tabletLayout: {
76
- width: 463,
94
+ playerImageWrapper: {
95
+ width: "100%",
77
96
  maxHeight: 750,
78
97
  marginTop: 80,
98
+ },
99
+ tabletLayout: {
100
+ width: 463,
79
101
  marginBottom: 80,
80
102
  },
81
103
  controls: (isTablet: boolean, isLiveShowFullControls: boolean) => ({
@@ -84,24 +106,31 @@ const Styles = {
84
106
  justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
85
107
  }),
86
108
  backgroundImageContainer: (dimensions: Dimensions, isTablet: boolean) => {
109
+ const mobileValue = dimensions.width
110
+ ? dimensions.width - PADDING_HORIZONTAL * 2
111
+ : 330;
112
+
87
113
  return {
88
- width: isTablet ? 463 : dimensions.width || 330,
89
- height: isTablet ? 463 : dimensions.width || 330,
114
+ width: isTablet ? 463 : mobileValue,
115
+ height: isTablet ? 463 : mobileValue,
90
116
  };
91
117
  },
92
- backgroundImageContainerImageStyle: (isTablet) => ({
93
- borderRadius: isTablet ? 24 : 10,
118
+ backgroundImageContainerImageStyle: (
119
+ isTablet: boolean,
120
+ docked: boolean,
121
+ startComponentsAnimation: boolean,
122
+ isActiveGesture: boolean
123
+ ) => ({
124
+ borderRadius:
125
+ (startComponentsAnimation && isActiveGesture) || docked
126
+ ? 0
127
+ : isTablet
128
+ ? 24
129
+ : 10,
94
130
  }),
95
- playerContainer: (docked: boolean, style) => {
96
- const combinedStyle = {
97
- flex: 1,
98
- };
99
-
100
- if (docked) {
101
- combinedStyle["height"] = style.height;
102
- }
103
131
 
104
- return combinedStyle;
132
+ paddingHorizontal: {
133
+ paddingHorizontal: PADDING_HORIZONTAL,
105
134
  },
106
135
 
107
136
  controlsMobile: {
@@ -115,6 +144,12 @@ const Styles = {
115
144
  separator: {
116
145
  height: 20,
117
146
  },
147
+ flexDirectionRow: {
148
+ flexDirection: "row",
149
+ },
150
+ alignItemsCenter: {
151
+ alignItems: "center",
152
+ },
118
153
  };
119
154
 
120
155
  export default function DefaultLayout(props: LayoutProps) {
@@ -139,12 +174,14 @@ export default function DefaultLayout(props: LayoutProps) {
139
174
  sleepTimerDate,
140
175
  title,
141
176
  summary,
177
+ defaultDimensions,
142
178
  } = props;
143
179
 
144
180
  const isTablet = useIsTablet();
145
181
  const { width, height } = dimensions;
146
182
  const isPortraitMode = width < height;
147
183
  const isLiveContent = playerState.isLive;
184
+ const docked = layoutState.docked;
148
185
 
149
186
  const languageData = useLanguageData("audio-player");
150
187
 
@@ -160,8 +197,35 @@ export default function DefaultLayout(props: LayoutProps) {
160
197
 
161
198
  let showFullControls = !controller?.isAd();
162
199
 
200
+ // Safely access and validate start_time and end_time
201
+ const startTime = entry.extensions?.start_time;
202
+ const endTime = entry.extensions?.end_time;
203
+
204
+ const hasValidStartTime = isValidDate(startTime);
205
+ const hasValidEndTime = isValidDate(endTime);
206
+
207
+ // Abstracted condition
208
+ const isDateBasedLiveContent =
209
+ isLiveContent && hasValidStartTime && hasValidEndTime;
210
+
211
+ // Determine if progress bar should be shown
212
+ const needsToShowProgressBar =
213
+ (isLiveContent &&
214
+ (Boolean(value("liveSeekingEnabled")) || isDateBasedLiveContent)) ||
215
+ !isLiveContent;
216
+
217
+ // Convert valid date strings to timestamps
218
+ const startTimestamp = hasValidStartTime
219
+ ? dayjs.utc(startTime!).valueOf()
220
+ : undefined;
221
+
222
+ const endTimestamp = hasValidEndTime
223
+ ? dayjs.utc(endTime!).valueOf()
224
+ : undefined;
225
+
163
226
  if (isLiveContent) {
164
227
  const seekEnabled = Boolean(value("liveSeekingEnabled"));
228
+
165
229
  showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
166
230
  }
167
231
 
@@ -191,12 +255,14 @@ export default function DefaultLayout(props: LayoutProps) {
191
255
 
192
256
  const rewind = rewindButton({
193
257
  isTablet,
194
- onPress: controller?.hasContentDuration?.() ? onRewindButtonPress : null,
258
+ onPress: controller?.hasSeekableDuration?.() ? onRewindButtonPress : null,
195
259
  });
196
260
 
197
261
  const forward = forwardButton({
198
262
  isTablet,
199
- onPress: controller?.hasContentDuration?.() ? onForwardButtonPress : null,
263
+ onPress: controller?.hasSeekableDuration?.()
264
+ ? onForwardButtonPress
265
+ : null,
200
266
  });
201
267
 
202
268
  const speed = speedButton({
@@ -278,10 +344,15 @@ export default function DefaultLayout(props: LayoutProps) {
278
344
 
279
345
  const Separator = () => <View style={Styles.separator} />;
280
346
 
281
- const liveSeekingEnabled = value("liveSeekingEnabled");
347
+ const defaultImageDimensions = React.useMemo(
348
+ () =>
349
+ defaultDimensions &&
350
+ Styles.backgroundImageContainer(defaultDimensions, isTablet),
351
+ [defaultDimensions, isTablet]
352
+ );
282
353
 
283
- const needsToShowProgressBar =
284
- (isLiveContent && liveSeekingEnabled) || !isLiveContent;
354
+ const { isActiveGesture, startComponentsAnimation } =
355
+ useModalAnimationContext();
285
356
 
286
357
  return (
287
358
  <View
@@ -289,65 +360,107 @@ export default function DefaultLayout(props: LayoutProps) {
289
360
  isTablet ? Styles.tabletContainer(isPortraitMode) : Styles.container
290
361
  }
291
362
  >
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
- }
363
+ <AnimationComponent animationType={ComponentAnimationType.componentFade}>
364
+ <TransportInfo
365
+ content={entry}
366
+ value={value}
367
+ visible={true}
368
+ languageData={languageData}
369
+ layoutState={layoutState}
370
+ actionButtons={actionButtons}
371
+ />
372
+ </AnimationComponent>
373
+ <AnimationComponent
374
+ animationType={ComponentAnimationType.moveUpComponent}
375
+ style={isTablet ? Styles.playerImageWrapper : undefined}
304
376
  >
305
- <View style={isTablet ? Styles.tabletLayout : null}>
377
+ <AnimationComponent
378
+ animationType={ComponentAnimationType.moveComponentHorizontal}
379
+ additionalData={{
380
+ disableAnimatedComponent: !isTablet,
381
+ moveValue: (dimensions.width - 463) / 2,
382
+ extraAnimation: !isTablet
383
+ ? {
384
+ [ComponentAnimationType.audioPlayerPaddingHorizontal]: {
385
+ style: Styles.paddingHorizontal,
386
+ },
387
+ }
388
+ : null,
389
+ }}
390
+ style={isTablet ? Styles.alignItemsCenter : undefined}
391
+ >
306
392
  <PlayerImageBackground
307
393
  entry={entry}
308
394
  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}
395
+ imageStyle={Styles.backgroundImageContainerImageStyle(
396
+ isTablet,
397
+ docked,
398
+ startComponentsAnimation,
399
+ isActiveGesture
400
+ )}
401
+ defaultImageDimensions={defaultImageDimensions}
316
402
  />
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}
403
+ </AnimationComponent>
404
+
405
+ <DockedLayout {...props} />
406
+ </AnimationComponent>
407
+ <View
408
+ style={[
409
+ Styles.paddingHorizontal,
410
+ isTablet ? Styles.tabletLayout : undefined,
411
+ ]}
412
+ >
413
+ {!docked && (
414
+ <AnimationComponent
415
+ animationType={ComponentAnimationType.componentFade}
416
+ >
417
+ <AudioDescription
418
+ title={title}
419
+ summary={summary}
420
+ value={value}
421
+ layoutState={layoutState}
422
+ />
423
+ <Separator />
424
+ {needsToShowProgressBar && (
425
+ <View>
426
+ <ProgressBar
427
+ content={entry}
334
428
  value={value}
335
- title={sleepTitle}
429
+ visible={true}
430
+ layoutState={layoutState}
431
+ onPlayerSeek={onPlayerSeek}
432
+ playerState={playerState}
433
+ disableFullscreen={true}
434
+ sliderStyle={2}
435
+ startTimestamp={startTimestamp}
436
+ endTimestamp={endTimestamp}
437
+ isDateBasedLiveContent={isDateBasedLiveContent}
336
438
  />
337
- )}
338
439
 
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>
440
+ {showCounter && timeLeft >= 0 && (
441
+ <CountDown
442
+ timeLeft={timeLeft}
443
+ value={value}
444
+ title={sleepTitle}
445
+ />
446
+ )}
447
+
448
+ <Separator />
449
+ </View>
450
+ )}
451
+ <Controls
452
+ value={value}
453
+ visible={true}
454
+ keepAlive={null}
455
+ buttons={controlButtons}
456
+ style={Styles.controls(
457
+ isTablet,
458
+ isLiveContent && showFullControls
459
+ )}
460
+ playerState={playerState}
461
+ />
462
+ </AnimationComponent>
463
+ )}
351
464
  </View>
352
465
  </View>
353
466
  );
@@ -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,26 +1,8 @@
1
1
  import queryString from "query-string";
2
+ import dayjs from "dayjs";
3
+ import utc from "dayjs/plugin/utc";
2
4
 
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
- };
5
+ dayjs.extend(utc);
24
6
 
25
7
  export const getLiveUrl = (url: string) => {
26
8
  // Use the replace method with a regular expression to replace all instances of subClass with livePage
@@ -42,3 +24,7 @@ export const addQueryParam = (
42
24
 
43
25
  return `${urlWithoutQuery}?${updatedQueryString}`;
44
26
  };
27
+
28
+ export const isValidDate = (dateString: string) => {
29
+ return dateString && dayjs.utc(dateString).isValid();
30
+ };
@@ -38,6 +38,10 @@ 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
+ import {
42
+ AnimationComponent,
43
+ ComponentAnimationType,
44
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
41
45
 
42
46
  const RNPlayerManager = {
43
47
  QuickBrickPlayerPlugin: isApplePlatform()
@@ -57,6 +61,7 @@ const styles = StyleSheet.create({
57
61
  position: "absolute",
58
62
  zIndex: 1,
59
63
  },
64
+ playerSize: { width: "100%", height: "100%" },
60
65
  });
61
66
 
62
67
  const logger = createLogger({
@@ -780,7 +785,6 @@ export default class VideoPlayer extends React.Component<
780
785
 
781
786
  render() {
782
787
  const {
783
- castAction,
784
788
  docked,
785
789
  entry,
786
790
  fullscreen,
@@ -790,8 +794,12 @@ export default class VideoPlayer extends React.Component<
790
794
  isTabletPortrait,
791
795
  muted,
792
796
  style,
797
+ castAction,
798
+ controller,
793
799
  } = this.props;
794
800
 
801
+ const supportNativeCast = controller.supportNativeCast();
802
+
795
803
  const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
796
804
  this.state;
797
805
 
@@ -856,7 +864,8 @@ export default class VideoPlayer extends React.Component<
856
864
  ? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
857
865
  : supportsNativeControls && !this.getPlayNextData();
858
866
 
859
- const shouldUseNativeControls = controls && !docked;
867
+ const shouldUseNativeControls =
868
+ controls && !docked && !castAction?.state?.connected;
860
869
 
861
870
  platformSpecificProps = {
862
871
  ...platformSpecificProps,
@@ -1061,29 +1070,14 @@ export default class VideoPlayer extends React.Component<
1061
1070
  const renderMobilePlayer = () => {
1062
1071
  return isFullScreenAudioPlayer && isAudioItem ? (
1063
1072
  <View style={containerStyle}>
1064
- {!castAction?.state?.connected && (
1073
+ {(!castAction?.state?.connected || supportNativeCast) && (
1065
1074
  <this.props.PlayerComponent
1066
1075
  ref={this._assignRoot}
1067
1076
  {...nativeEvents}
1068
1077
  {...nativeProps}
1069
1078
  />
1070
1079
  )}
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>
1080
+ <AudioPlayerWrapper {...sharedWrapperViewProps} />
1087
1081
  </View>
1088
1082
  ) : (
1089
1083
  <PlayerWrapper {...sharedWrapperViewProps}>
@@ -1098,11 +1092,24 @@ export default class VideoPlayer extends React.Component<
1098
1092
  <View style={styles.container}>
1099
1093
  <View style={[playerContainerStyles, playerDimensions]}>
1100
1094
  {isAudioItem && (
1101
- <AudioPlayer
1102
- style={playerDimensions}
1103
- audio_item={entry}
1104
- plugin_configuration={this.getPluginConfiguration()}
1105
- />
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>
1106
1113
  )}
1107
1114
 
1108
1115
  {shouldRenderBackground && (
@@ -1114,18 +1121,28 @@ export default class VideoPlayer extends React.Component<
1114
1121
  />
1115
1122
  )}
1116
1123
 
1117
- {!castAction?.state?.connected && (
1118
- <this.props.PlayerComponent
1119
- ref={this._assignRoot}
1120
- {...nativeEvents}
1121
- {...nativeProps}
1122
- listener={this.props.listener}
1124
+ {(!castAction?.state?.connected || supportNativeCast) && (
1125
+ <AnimationComponent
1126
+ animationType={ComponentAnimationType.player}
1127
+ additionalData={playerDimensions}
1123
1128
  style={getStyle(playerDimensions)}
1124
- pluginConfiguration={this.getPluginConfiguration()}
1125
- controller={this.props.controller}
1126
1129
  >
1127
- {this.childrenWithPlayNext()}
1128
- </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>
1129
1146
  )}
1130
1147
  </View>
1131
1148