@applicaster/quick-brick-player 13.0.0-rc.13 → 13.0.0-rc.130

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.
Files changed (49) hide show
  1. package/package.json +27 -14
  2. package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
  3. package/src/Player/AudioLayer/AudioDescription.tsx +107 -68
  4. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +142 -295
  5. package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +45 -0
  6. package/src/Player/AudioLayer/Layout/Controls/index.tsx +291 -0
  7. package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +9 -27
  8. package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
  9. package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +77 -81
  10. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +222 -0
  11. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +87 -0
  12. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +20 -0
  13. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +1 -0
  14. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +99 -0
  15. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +112 -0
  16. package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +36 -0
  17. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +212 -0
  18. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +215 -0
  19. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +128 -0
  20. package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
  21. package/src/Player/AudioLayer/Layout/const.ts +26 -0
  22. package/src/Player/AudioLayer/Layout/debug.ts +6 -0
  23. package/src/Player/AudioLayer/Layout/hooks/index.ts +5 -0
  24. package/src/Player/AudioLayer/Layout/hooks/useMobileLayoutImageSize.ts +14 -0
  25. package/src/Player/AudioLayer/Layout/hooks/useTabletLayoutImageSize.ts +105 -0
  26. package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +54 -0
  27. package/src/Player/AudioLayer/Layout/index.tsx +21 -48
  28. package/src/Player/AudioLayer/Layout/types.ts +7 -0
  29. package/src/Player/AudioLayer/Layout/utils.ts +7 -0
  30. package/src/Player/AudioLayer/SleepTimerManager.ts +130 -0
  31. package/src/Player/AudioLayer/SpeedManager.ts +52 -0
  32. package/src/Player/AudioLayer/components/SleepTimerModalHeader/SleepTimerModalHeader.tsx +66 -0
  33. package/src/Player/AudioLayer/components/SleepTimerModalHeader/index.ts +1 -0
  34. package/src/Player/AudioLayer/useSleepTimerModal.ts +109 -0
  35. package/src/Player/AudioLayer/utils.ts +27 -0
  36. package/src/Player/Const/sleepTimerOptions.ts +41 -0
  37. package/src/Player/Const/speedOptions.ts +4 -0
  38. package/src/Player/Utils/Utils.ts +0 -5
  39. package/src/Player/Utils/index.tsx +123 -0
  40. package/src/Player/hooks/useIsCasting.tsx +57 -0
  41. package/src/Player/index.tsx +106 -49
  42. package/src/QuickBrickPlayer.tsx +3 -0
  43. package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
  44. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
  45. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
  46. package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
  47. package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
  48. package/src/Player/Helpers/VideoResizeMode.ts +0 -7
  49. package/src/utils/utils.ts +0 -25
@@ -1,7 +1,13 @@
1
1
  import * as React from "react";
2
- import { ViewStyle, View } from "react-native";
2
+ import { useEffect, useState } from "react";
3
+ import {
4
+ Dimensions as ScreenDimensions,
5
+ StyleSheet,
6
+ View,
7
+ ViewStyle,
8
+ } from "react-native";
3
9
 
4
- import { SafeAreaView, Edge } from "react-native-safe-area-context";
10
+ import { Edge, SafeAreaView } from "react-native-safe-area-context";
5
11
  import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
6
12
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
7
13
  import * as R from "ramda";
@@ -15,25 +21,31 @@ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
15
21
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
16
22
  import { PlayerDetails } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/PlayerDetails";
17
23
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
18
- import { useEffect, useState } from "react";
19
- import { MagicBG } from "./MagicBG";
24
+ import { formatSpeed } from "./utils";
20
25
  import {
21
- formatSpeed,
22
- hasDatePassed,
23
- loadItemsFromStorage,
24
- NAMESPACE,
25
- } from "./utils";
26
- import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
27
- import { addQueryParam, getLiveUrl } from "../Utils";
26
+ getBottomSheetModalDefaultItemIcon,
27
+ getBottomSheetModalIconProps,
28
+ getBottomSheetModalItemProps,
29
+ getBottomSheetModalLabelProps,
30
+ getBottomSheetModalSelectedItemIcon,
31
+ } from "../Utils";
28
32
  import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
29
33
  import {
34
+ AnimatedScrollModal,
30
35
  AnimationComponent,
31
36
  ComponentAnimationType,
32
- AnimatedScrollModal,
33
37
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
34
- import { PADDING_HORIZONTAL } from "./Layout/defaultLayoutsConts";
38
+ import { PADDING_HORIZONTAL } from "./Layout/const";
35
39
  import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
36
40
 
41
+ import { DEFAULT_SPEED, PlaybackSpeed, SpeedController } from "./SpeedManager";
42
+ import {
43
+ dismissModal as dismissBottomSheetModal,
44
+ openBottomSheetModal,
45
+ useModalStoreState,
46
+ } from "@applicaster/zapp-react-native-utils/modalState";
47
+ import { speedOptions } from "../Const/speedOptions";
48
+
37
49
  const { log_debug } = createLogger({
38
50
  subsystem: "UIComponent",
39
51
  category: "AudioPlayerWrapper",
@@ -48,8 +60,7 @@ type Dimensions = {
48
60
 
49
61
  type Configuration = {
50
62
  [key: string]: any;
51
- magic_background?: boolean;
52
- audio_player_background_image_query?: string;
63
+ audio_player_background_image_default_color?: string;
53
64
  tablet_landscape_sidebar_width?: string;
54
65
  tablet_landscape_player_container_background_color?: string;
55
66
  };
@@ -57,7 +68,6 @@ type Configuration = {
57
68
  type Props = {
58
69
  children: React.ReactNode;
59
70
  inline?: boolean;
60
- docked?: boolean;
61
71
  configuration: Configuration;
62
72
  style: ViewStyle & Dimensions;
63
73
  entry: ZappEntry;
@@ -71,57 +81,29 @@ type Props = {
71
81
  isTabletPortrait?: boolean;
72
82
  };
73
83
 
74
- export const defaultAspectRatioWidth = (height: number): number =>
75
- (height / 9) * 16;
76
-
77
- const Styles = {
78
- mainContainer: (style: ViewStyle) => {
79
- const combinedStyle: ViewStyle = {
80
- flex: 1,
81
- };
84
+ const { width: SCREEN_WIDTH } = ScreenDimensions.get("screen");
82
85
 
83
- return {
84
- ...combinedStyle,
85
- ...style,
86
- };
87
- },
86
+ const Styles = StyleSheet.create({
88
87
  playerContainer: {
89
88
  flex: 1,
90
89
  },
91
90
  paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
92
-
93
- controlsMobile: {
94
- height: 50,
95
- marginHorizontal: 24,
96
- },
97
- controlsTablet: {
98
- height: 96,
99
- marginHorizontal: 24,
100
- },
101
- playerDetails: { marginTop: 60 },
102
-
103
- linearGradient: {
104
- flex: 1,
91
+ playerDetails: {
92
+ marginTop: 60,
93
+ alignSelf: "center",
94
+ width: SCREEN_WIDTH - PADDING_HORIZONTAL * 2,
105
95
  },
106
- };
96
+ });
107
97
 
108
- const sleeps = [
109
- // { label: "End of episode", value: "episode" },
110
- { label: "5 minutes", value: 5 },
111
- { label: "10 minutes", value: 10 },
112
- { label: "15 minutes", value: 15 },
113
- { label: "30 minutes", value: 30 },
114
- { label: "45 minutes", value: 45 },
115
- { label: "1 hour", value: 60 },
116
- { label: "2 hours", value: 120 },
117
- ];
98
+ const edges: Edge[] = ["right", "left", "top"];
118
99
 
119
100
  export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
120
101
  const player = usePlayer();
121
102
  const playerState = usePlayerState("audio-player-wrapper");
122
103
 
104
+ const modalBottomSheetState = useModalStoreState();
105
+
123
106
  const {
124
- docked,
125
107
  configuration,
126
108
  style,
127
109
  entry,
@@ -131,40 +113,48 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
131
113
  isTabletPortrait,
132
114
  } = props;
133
115
 
134
- const speeds = [
135
- { asset: configuration["speed_0_8"], value: 0.8 },
136
- { asset: configuration["speed_1"], value: 1.0 },
137
- { asset: configuration["speed_1_2"], value: 1.2 },
138
- { asset: configuration["speed_1_5"], value: 1.5 },
139
- { asset: configuration["speed_2"], value: 2.0 },
140
- ];
141
-
142
116
  const isTablet = useIsTablet();
143
117
 
144
118
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
145
119
 
146
- // TODO: Have generic place for live url from configuration. Currently its hardcoded for client.
147
-
148
- const feedUrl = getLiveUrl(entry?.extensions?.live?.channel_src ?? "");
149
-
150
120
  const { title, summary } = useTitleSummaryOverlay(
151
- feedUrl,
152
121
  entry,
153
122
  playerState?.isLive,
154
123
  configuration?.audio_live_player_update_interval
155
124
  );
156
125
 
157
- const [playbackSpeed, setPlaybackSpeed] = useState({
158
- asset: configuration["speed_1"],
159
- value: 1.0,
160
- });
126
+ const [speedManager, setSpeedManager] = useState<SpeedController | null>(
127
+ null
128
+ );
161
129
 
162
- const [sleepTimer, setSleepTimer] = useState({
163
- label: "playback_sleep_off_label",
164
- value: 0,
165
- });
130
+ useEffect(() => {
131
+ if (player) {
132
+ setSpeedManager(new SpeedController(player));
133
+ } else {
134
+ setSpeedManager(null);
135
+ }
136
+ }, [player]);
137
+
138
+ useEffect(() => {
139
+ if (!player) return;
140
+
141
+ const unsubscribe = player.addListener({
142
+ id: "audio-player-wrapper-bottom-sheet-modal",
143
+ listener: {
144
+ onVideoEnd: () => {
145
+ // Dismiss the bottom sheet modal when the video ends to avoid audio breaks and app freeze
146
+ if (modalBottomSheetState.visible) {
147
+ dismissBottomSheetModal();
148
+ }
149
+ },
150
+ },
151
+ });
152
+
153
+ return () => unsubscribe?.();
154
+ }, [player, modalBottomSheetState.visible]);
166
155
 
167
- const [sleepTimerDate, setSleepTimerDate] = useState(0);
156
+ const [playbackSpeed, setPlaybackSpeed] =
157
+ useState<PlaybackSpeed>(DEFAULT_SPEED);
168
158
 
169
159
  const [defaultDimensions, setDefaultDimensions] =
170
160
  React.useState<Dimensions>(undefined);
@@ -174,8 +164,6 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
174
164
  height: 0,
175
165
  });
176
166
 
177
- const navigator = useNavigation();
178
-
179
167
  const { maximiseVideoModal } = useNavigation();
180
168
 
181
169
  const onLayout = (event: any) => {
@@ -189,82 +177,22 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
189
177
  if (!defaultDimensions) setDefaultDimensions({ width, height });
190
178
  };
191
179
 
192
- const cancelSleepTimer = async () => {
193
- player?.cancelSleepTimer();
194
-
195
- setSleepTimer({
196
- label: "playback_sleep_off_label",
197
- value: 0,
198
- });
199
-
200
- setSleepTimerDate(0);
201
-
202
- await localStorage.removeItem("sleep", NAMESPACE);
203
- };
204
-
205
- const startSleepTimer = (timerValue: number) => {
206
- try {
207
- const currentDate = new Date();
208
- const futureDate = new Date(currentDate.getTime() + timerValue * 60000);
209
- const futureSleepDate = futureDate.getTime();
210
-
211
- player?.cancelSleepTimer();
212
-
213
- player?.startSleepTimer(futureSleepDate);
214
-
215
- return futureSleepDate;
216
- } catch (e) {
217
- return 0;
218
- }
219
- };
220
-
221
- const handleSleep = async (
222
- timerValue: number,
223
- currentFutureSleepDate = null
224
- ) => {
225
- if (currentFutureSleepDate) {
226
- if (hasDatePassed(currentFutureSleepDate)) {
227
- await cancelSleepTimer();
228
-
229
- return 0;
230
- }
231
-
232
- return currentFutureSleepDate;
233
- }
234
-
235
- if (timerValue === 0) {
236
- await cancelSleepTimer();
237
-
238
- return timerValue;
239
- }
240
-
241
- return startSleepTimer(timerValue);
242
- };
243
-
244
180
  useEffect(() => {
245
- const loadSpeed = async () => {
246
- const speed = await loadItemsFromStorage("speed");
181
+ const speedSubscription =
182
+ speedManager?.playbackSpeed$.subscribe(setPlaybackSpeed);
247
183
 
248
- if (playerState.isReadyToPlay && speed) {
249
- setPlaybackSpeed(speed);
250
- player?.setPlaybackRate(speed.value);
251
- }
184
+ return () => {
185
+ speedSubscription?.unsubscribe();
252
186
  };
187
+ }, [speedManager]);
253
188
 
254
- const loadSleep = async () => {
255
- const sleep = await loadItemsFromStorage("sleep");
256
-
257
- if (playerState.isReadyToPlay && sleep) {
258
- const { futureSleepDate, ...rest } = sleep;
259
- setSleepTimer(rest);
260
- const sleepTimerDate = await handleSleep(sleep.value, futureSleepDate);
261
- setSleepTimerDate(sleepTimerDate);
262
- }
263
- };
189
+ useEffect(() => {
190
+ if (!playerState.isReadyToPlay) {
191
+ return;
192
+ }
264
193
 
265
- loadSpeed().then();
266
- loadSleep().then();
267
- }, [playerState.isReadyToPlay]);
194
+ void speedManager?.loadSpeed();
195
+ }, [playerState.isReadyToPlay, speedManager]);
268
196
 
269
197
  const getValue = (key: string, stylesObj: {}) =>
270
198
  R.propOr(null, key, stylesObj);
@@ -292,7 +220,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
292
220
 
293
221
  const onPlaybackButtonPress = React.useCallback(() => {
294
222
  if (playerState.isBuffering) return;
295
- playerState.isPaused ? player?.play() : player.pause();
223
+ playerState.isPaused ? player?.play() : player?.pause();
296
224
  }, [playerState, player]);
297
225
 
298
226
  const seekDuration = toNumberWithDefault(10, value("seek_duration"));
@@ -307,57 +235,34 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
307
235
 
308
236
  const onSpeedSelect = React.useCallback(
309
237
  async (item) => {
310
- setPlaybackSpeed(item);
311
- player.setPlaybackRate(item.value);
312
- await localStorage.setItem("speed", item, NAMESPACE);
238
+ await speedManager?.setPlaybackSpeed(item);
313
239
  },
314
- [player, setPlaybackSpeed]
315
- );
316
-
317
- const onSleepSelect = React.useCallback(
318
- async (item) => {
319
- setSleepTimer(item);
320
- const futureSleepDate = await handleSleep(item.value);
321
- setSleepTimerDate(futureSleepDate);
322
-
323
- await localStorage.setItem(
324
- "sleep",
325
- { ...item, futureSleepDate },
326
- NAMESPACE
327
- );
328
- },
329
- [player, setSleepTimer]
240
+ [speedManager]
330
241
  );
331
242
 
332
243
  const onSpeedButtonPress = React.useCallback(() => {
333
- navigator.openModalBottomSheet({
244
+ openBottomSheetModal({
334
245
  modalBottomSheetContentProps: {
335
- items: speeds,
246
+ items: speedOptions,
336
247
  current_selection: playbackSpeed,
337
248
  onPress: onSpeedSelect,
338
249
  title: configuration["playback_speed_title"],
250
+ itemProps: getBottomSheetModalItemProps,
251
+ iconProps: getBottomSheetModalIconProps,
252
+ labelProps: getBottomSheetModalLabelProps,
253
+ getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
254
+ getDefaultItemIcon: getBottomSheetModalDefaultItemIcon,
255
+ iconPlacement: "right",
339
256
  },
340
257
  options: {
341
- supportedOrientations: ["portrait"],
258
+ supportedOrientations: [
259
+ "portrait",
260
+ "landscape",
261
+ "portrait-upside-down",
262
+ ],
342
263
  },
343
264
  });
344
- }, [playbackSpeed, setPlaybackSpeed]);
345
-
346
- const onSleepButtonPress = React.useCallback(() => {
347
- navigator.openModalBottomSheet({
348
- modalBottomSheetContentProps: {
349
- items: [
350
- { label: configuration["playback_sleep_off_label"], value: 0 },
351
- ].concat(sleeps),
352
- current_selection: sleepTimer,
353
- onPress: onSleepSelect,
354
- title: configuration["playback_sleep_title"],
355
- },
356
- options: {
357
- supportedOrientations: ["portrait"],
358
- },
359
- });
360
- }, [sleepTimer, setSleepTimer, configuration]);
265
+ }, [playbackSpeed, onSpeedSelect, configuration["playback_speed_title"]]);
361
266
 
362
267
  const onCloseVideoModal = React.useCallback(() => {
363
268
  playerManager.close();
@@ -378,111 +283,53 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
378
283
  player?.seekTo(0);
379
284
  }, [player]);
380
285
 
381
- const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
382
-
383
- const ContainerView = SafeAreaView;
384
-
385
- const MainContent = React.useMemo(() => {
386
- return (
387
- <ContainerView style={Styles.mainContainer(style)} edges={edges}>
388
- <AnimationComponent
389
- animationType={ComponentAnimationType.moveUpComponent}
390
- additionalData={{ saveArea: true }}
391
- style={Styles.playerContainer}
392
- >
393
- <AnimatedScrollModal>
394
- <View style={Styles.playerContainer} onLayout={onLayout}>
395
- <Layout
396
- entry={entry}
397
- playerState={playerState}
398
- layoutState={layoutState}
399
- value={value}
400
- onPlaybackButtonPress={onPlaybackButtonPress}
401
- onRewindButtonPress={onRewindButtonPress}
402
- onForwardButtonPress={onForwardButtonPress}
403
- onPlayerSeek={onPlayerSeek}
404
- onSkipStart={onSkipStart}
405
- onSpeedButtonPress={onSpeedButtonPress}
406
- onSleepButtonPress={onSleepButtonPress}
407
- playbackSpeedName={formatSpeed(playbackSpeed.value)}
408
- playbackSleepName={
409
- sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
410
- }
411
- sleepTimerDate={sleepTimerDate}
412
- cancelSleepTimer={cancelSleepTimer}
413
- onSkipLive={onSkipLive}
414
- onCloseVideoModal={onCloseVideoModal}
415
- maximiseVideoModal={maximiseVideoModal}
416
- configuration={configuration}
417
- dimensions={dimensions}
418
- playNextData={playNextData}
419
- title={title}
420
- summary={summary}
421
- defaultDimensions={defaultDimensions}
422
- />
423
- <View style={Styles.paddingHorizontal}>
424
- {children}
425
- <AnimationComponent
426
- animationType={ComponentAnimationType.componentFade}
427
- >
428
- <PlayerDetails
429
- configuration={configuration}
430
- style={Styles.playerDetails}
431
- entry={entry}
432
- isTabletLandscape={isTabletLandscape}
433
- isAudioPlayer={true}
434
- />
435
- </AnimationComponent>
436
- </View>
437
- </View>
438
- </AnimatedScrollModal>
439
- </AnimationComponent>
440
- </ContainerView>
441
- );
442
- }, [
443
- docked,
444
- style,
445
- entry,
446
- playerState,
447
- layoutState,
448
- value,
449
- onPlaybackButtonPress,
450
- onRewindButtonPress,
451
- onForwardButtonPress,
452
- onPlayerSeek,
453
- onCloseVideoModal,
454
- maximiseVideoModal,
455
- configuration,
456
- dimensions,
457
- children,
458
- playNextData,
459
- onSkipStart,
460
- onSkipLive,
461
- sleepTimer.value,
462
- sleepTimerDate,
463
- ]);
464
-
465
- if (configuration.magic_background) {
466
- const baseUrl = entry?.extensions?.audio_player_background_image ?? "";
467
-
468
- const queryParamName =
469
- configuration.audio_player_background_image_query || "width";
470
-
471
- const queryParamValue = 15;
472
-
473
- const url = addQueryParam(baseUrl, queryParamName, queryParamValue);
474
-
475
- return (
476
- <MagicBG
477
- image={url}
478
- fallbackUrl={baseUrl}
479
- colors={entry?.extensions?.backgroundColors}
480
- defaultColor="#000000"
286
+ return (
287
+ <SafeAreaView style={[style, Styles.playerContainer]} edges={edges}>
288
+ <AnimationComponent
289
+ animationType={ComponentAnimationType.moveUpComponent}
290
+ additionalData={{ saveArea: true }}
291
+ style={Styles.playerContainer}
481
292
  >
482
- {MainContent}
483
- </MagicBG>
484
- );
485
- }
486
-
487
- return MainContent;
293
+ <AnimatedScrollModal>
294
+ <View style={Styles.playerContainer} onLayout={onLayout}>
295
+ <Layout
296
+ entry={entry}
297
+ playerState={playerState}
298
+ layoutState={layoutState}
299
+ value={value}
300
+ onPlaybackButtonPress={onPlaybackButtonPress}
301
+ onRewindButtonPress={onRewindButtonPress}
302
+ onForwardButtonPress={onForwardButtonPress}
303
+ onPlayerSeek={onPlayerSeek}
304
+ onSkipStart={onSkipStart}
305
+ onSpeedButtonPress={onSpeedButtonPress}
306
+ playbackSpeedName={formatSpeed(playbackSpeed.value)}
307
+ onSkipLive={onSkipLive}
308
+ onCloseVideoModal={onCloseVideoModal}
309
+ maximiseVideoModal={maximiseVideoModal}
310
+ configuration={configuration}
311
+ dimensions={dimensions}
312
+ playNextData={playNextData}
313
+ title={title}
314
+ summary={summary}
315
+ />
316
+ <View style={Styles.paddingHorizontal}>
317
+ {children}
318
+ <AnimationComponent
319
+ animationType={ComponentAnimationType.componentFade}
320
+ >
321
+ <PlayerDetails
322
+ isAudioPlayer
323
+ configuration={configuration}
324
+ style={Styles.playerDetails}
325
+ entry={entry}
326
+ isTabletLandscape={isTabletLandscape}
327
+ />
328
+ </AnimationComponent>
329
+ </View>
330
+ </View>
331
+ </AnimatedScrollModal>
332
+ </AnimationComponent>
333
+ </SafeAreaView>
334
+ );
488
335
  };
@@ -0,0 +1,45 @@
1
+ import * as React from "react";
2
+ import { View, StyleSheet } from "react-native";
3
+
4
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+
6
+ import {
7
+ TABLET_VERTICAL_SEPARATOR_HEIGHT,
8
+ TABLET_VERTICAL_SEPARATOR_HEIGHT_S,
9
+ } from "../const";
10
+
11
+ import { withDebug } from "../debug";
12
+ import { useSafeAreaFrame } from "react-native-safe-area-context";
13
+ import { isSmallTabletHeight } from "../utils";
14
+
15
+ const styles = StyleSheet.create({
16
+ flexingHeight: {
17
+ flex: 1,
18
+ ...withDebug({ backgroundColor: "red" }),
19
+ },
20
+ fixedHeight: {
21
+ height: TABLET_VERTICAL_SEPARATOR_HEIGHT,
22
+ ...withDebug({ backgroundColor: "red" }),
23
+ },
24
+ fixedHeightSmall: {
25
+ height: TABLET_VERTICAL_SEPARATOR_HEIGHT_S,
26
+ ...withDebug({ backgroundColor: "red" }),
27
+ },
28
+ });
29
+
30
+ export const VerticalGutter = () => {
31
+ const isTablet = useIsTablet();
32
+ const { height } = useSafeAreaFrame();
33
+
34
+ return (
35
+ <View
36
+ style={
37
+ isTablet
38
+ ? isSmallTabletHeight(height)
39
+ ? styles.fixedHeightSmall
40
+ : styles.fixedHeight
41
+ : styles.flexingHeight
42
+ }
43
+ />
44
+ );
45
+ };