@applicaster/quick-brick-player 13.0.0-rc.11 → 13.0.0-rc.110

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 (37) hide show
  1. package/package.json +27 -13
  2. package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
  3. package/src/Player/AudioLayer/AudioDescription.tsx +5 -7
  4. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +136 -181
  5. package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +27 -0
  6. package/src/Player/AudioLayer/Layout/Controls/index.tsx +316 -0
  7. package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +7 -25
  8. package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
  9. package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +44 -67
  10. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +231 -0
  11. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +83 -0
  12. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +25 -0
  13. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +101 -0
  14. package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +26 -0
  15. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +216 -0
  16. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +224 -0
  17. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +115 -0
  18. package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
  19. package/src/Player/AudioLayer/Layout/const.ts +22 -0
  20. package/src/Player/AudioLayer/Layout/debug.ts +6 -0
  21. package/src/Player/AudioLayer/Layout/hooks/index.ts +5 -0
  22. package/src/Player/AudioLayer/Layout/hooks/useMobileLayoutImageSize.ts +14 -0
  23. package/src/Player/AudioLayer/Layout/hooks/useTabletLayoutImageSize.ts +105 -0
  24. package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +54 -0
  25. package/src/Player/AudioLayer/Layout/index.tsx +21 -48
  26. package/src/Player/AudioLayer/Layout/types.ts +7 -0
  27. package/src/Player/AudioLayer/MagicBG/index.tsx +1 -1
  28. package/src/Player/AudioLayer/SleepTimerManager.ts +119 -0
  29. package/src/Player/AudioLayer/SpeedManager.ts +52 -0
  30. package/src/Player/AudioLayer/utils.ts +27 -0
  31. package/src/Player/Const/sleepTimerOptions.ts +39 -0
  32. package/src/Player/Const/speedOptions.ts +4 -0
  33. package/src/Player/Utils/Utils.ts +0 -5
  34. package/src/Player/Utils/index.tsx +117 -0
  35. package/src/Player/index.tsx +31 -19
  36. package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
  37. package/src/Player/Helpers/VideoResizeMode.ts +0 -7
@@ -0,0 +1,316 @@
1
+ import * as React from "react";
2
+ import { StyleSheet } from "react-native";
3
+
4
+ import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
5
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
6
+ import {
7
+ Controls as MobileTransportControls,
8
+ ProgressBar,
9
+ } from "@applicaster/quick-brick-mobile-transport-controls";
10
+ import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
11
+
12
+ import {
13
+ AnimationComponent,
14
+ ComponentAnimationType,
15
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
16
+
17
+ import { AudioDescription } from "../../AudioDescription";
18
+ import { isValidDate } from "../../../Utils";
19
+ import { VerticalGutter } from "./VerticalGutter";
20
+
21
+ import {
22
+ forwardButton,
23
+ playbackButton,
24
+ rewindButton,
25
+ skipToLiveButton,
26
+ skipToStartButton,
27
+ sleepButton,
28
+ speedButton,
29
+ } from "./utils";
30
+
31
+ const styles = StyleSheet.create({
32
+ flex: {
33
+ flex: 1,
34
+ },
35
+ nonFlex: {
36
+ flex: 0,
37
+ },
38
+ progressBar: {
39
+ flex: 0,
40
+ },
41
+ progressBarTrackStyles: {
42
+ borderRadius: 3,
43
+ height: 6,
44
+ },
45
+ progressBarThumbStyles: {
46
+ width: 14,
47
+ height: 14,
48
+ borderRadius: 7,
49
+ },
50
+ progressBarThumbStyles_pressed: {
51
+ width: 20,
52
+ height: 20,
53
+ borderRadius: 10,
54
+ },
55
+ });
56
+
57
+ const getControlJustifyContent = (countOfButtons: number) =>
58
+ countOfButtons <= 1 ? "center" : "space-between";
59
+
60
+ type Props = {
61
+ entry: ZappEntry;
62
+ layoutState: QuickBrickPlayer.LayoutState;
63
+ playerState: QuickBrickPlayer.PlayerState;
64
+ value: GetValue;
65
+ title: string | number;
66
+ summary: string | number;
67
+ sleepTimerDate: number;
68
+ cancelSleepTimer: Callback;
69
+
70
+ playbackSpeedName: string;
71
+ playbackSleepName: string;
72
+
73
+ onPlaybackButtonPress: Callback;
74
+ onRewindButtonPress: Callback;
75
+ onForwardButtonPress: Callback;
76
+ onPlayerSeek: (targetTime: number) => void;
77
+ onSkipStart: Callback;
78
+ onSkipLive: Callback;
79
+ onSpeedButtonPress: Callback;
80
+ onSleepButtonPress: Callback;
81
+
82
+ docked: boolean;
83
+ };
84
+
85
+ export const Controls = (props: Props) => {
86
+ const {
87
+ entry,
88
+ layoutState,
89
+ playerState,
90
+ value,
91
+ title,
92
+ summary,
93
+ sleepTimerDate,
94
+ cancelSleepTimer,
95
+
96
+ playbackSpeedName,
97
+ playbackSleepName,
98
+
99
+ onPlaybackButtonPress,
100
+ onRewindButtonPress,
101
+ onForwardButtonPress,
102
+ onPlayerSeek,
103
+ onSkipStart,
104
+ onSkipLive,
105
+ onSpeedButtonPress,
106
+ onSleepButtonPress,
107
+
108
+ docked,
109
+ } = props;
110
+
111
+ const isTablet = useIsTablet();
112
+ const controller = playerManager.getActivePlayer();
113
+ let showFullControls = !controller?.isAd();
114
+ const liveButton = Boolean(value("live_badge_enabled"));
115
+
116
+ const isLiveContent = playerState.isLive;
117
+
118
+ if (isLiveContent) {
119
+ const seekEnabled = Boolean(value("liveSeekingEnabled"));
120
+
121
+ showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
122
+ }
123
+
124
+ const [timeLeft, setTimeLeft] = React.useState(
125
+ sleepTimerDate !== 0 ? sleepTimerDate - Date.now() : 0
126
+ );
127
+
128
+ const showCounter = React.useMemo(() => sleepTimerDate > 0, [sleepTimerDate]);
129
+
130
+ const countDownOptions = React.useMemo(() => {
131
+ return {
132
+ showCounter: showCounter && timeLeft >= 0,
133
+ timeLeft,
134
+ };
135
+ }, [showCounter, timeLeft]);
136
+
137
+ React.useEffect(() => {
138
+ if (showCounter && sleepTimerDate !== 0) {
139
+ setTimeLeft(sleepTimerDate - Date.now());
140
+
141
+ const intervalId = setInterval(() => {
142
+ setTimeLeft(() => {
143
+ const newTimeLeft = sleepTimerDate - Date.now();
144
+
145
+ if (newTimeLeft <= 0) {
146
+ clearInterval(intervalId);
147
+
148
+ cancelSleepTimer();
149
+
150
+ return 0;
151
+ } else {
152
+ return newTimeLeft;
153
+ }
154
+ });
155
+ }, 1000);
156
+
157
+ return () => clearInterval(intervalId);
158
+ } else {
159
+ setTimeLeft(0);
160
+ }
161
+ }, [sleepTimerDate, showCounter, cancelSleepTimer]);
162
+
163
+ const startTime = entry.extensions?.live?.start_time;
164
+ const endTime = entry.extensions?.live?.end_time;
165
+
166
+ const hasValidStartTime = isValidDate(startTime);
167
+ const hasValidEndTime = isValidDate(endTime);
168
+
169
+ const isDateBasedLiveContent =
170
+ isLiveContent && hasValidStartTime && hasValidEndTime;
171
+
172
+ const needsToShowProgressBar =
173
+ (isLiveContent &&
174
+ (Boolean(value("liveSeekingEnabled")) || isDateBasedLiveContent)) ||
175
+ !isLiveContent;
176
+
177
+ const startTimestamp = hasValidStartTime
178
+ ? dayjs.utc(startTime!).valueOf()
179
+ : undefined;
180
+
181
+ const endTimestamp = hasValidEndTime
182
+ ? dayjs.utc(endTime!).valueOf()
183
+ : undefined;
184
+
185
+ const isLiveShowFullControls = showFullControls && isLiveContent;
186
+
187
+ const controlButtons = React.useCallback((): Array<ControlsButton> => {
188
+ const play = playbackButton({
189
+ playerState,
190
+ liveButton,
191
+ isTablet,
192
+ isLiveShowFullControls,
193
+ onPress: onPlaybackButtonPress,
194
+ });
195
+
196
+ if (!showFullControls) {
197
+ return [play];
198
+ }
199
+
200
+ const rewind = rewindButton({
201
+ isTablet,
202
+ onPress: controller?.hasSeekableDuration?.() ? onRewindButtonPress : null,
203
+ });
204
+
205
+ const forward = forwardButton({
206
+ isTablet,
207
+ onPress: controller?.hasSeekableDuration?.()
208
+ ? onForwardButtonPress
209
+ : null,
210
+ });
211
+
212
+ const speed = speedButton({
213
+ isTablet,
214
+ onPress: onSpeedButtonPress,
215
+ name: playbackSpeedName,
216
+ });
217
+
218
+ const sleep = sleepButton({
219
+ isTablet,
220
+ onPress: onSleepButtonPress,
221
+ name: playbackSleepName,
222
+ });
223
+
224
+ if (isLiveContent) {
225
+ const skipToStart = skipToStartButton({
226
+ isTablet,
227
+ onPress: onSkipStart,
228
+ });
229
+
230
+ const skipToLive = skipToLiveButton({
231
+ isTablet,
232
+ onPress: onSkipLive,
233
+ });
234
+
235
+ return [skipToStart, rewind, play, forward, skipToLive];
236
+ }
237
+
238
+ return [speed, rewind, play, forward, sleep];
239
+ }, [
240
+ playerState,
241
+ liveButton,
242
+ isTablet,
243
+ onPlaybackButtonPress,
244
+ onRewindButtonPress,
245
+ onForwardButtonPress,
246
+ onSpeedButtonPress,
247
+ showFullControls,
248
+ onSkipStart,
249
+ onSkipLive,
250
+ isLiveContent,
251
+ playbackSpeedName,
252
+ playbackSleepName,
253
+ controller,
254
+ isLiveShowFullControls,
255
+ ]);
256
+
257
+ if (docked) {
258
+ return null;
259
+ }
260
+
261
+ return (
262
+ <AnimationComponent
263
+ animationType={ComponentAnimationType.componentFade}
264
+ style={isTablet ? styles.nonFlex : styles.flex}
265
+ >
266
+ <VerticalGutter />
267
+
268
+ <AudioDescription
269
+ title={title}
270
+ summary={summary}
271
+ value={value}
272
+ layoutState={layoutState}
273
+ />
274
+
275
+ <VerticalGutter />
276
+
277
+ {needsToShowProgressBar ? (
278
+ <>
279
+ <ProgressBar
280
+ name={"audio-default-layout"}
281
+ content={entry}
282
+ value={value}
283
+ visible
284
+ layoutState={layoutState}
285
+ onPlayerSeek={onPlayerSeek}
286
+ playerState={playerState}
287
+ disableFullscreen
288
+ sliderStyle={2}
289
+ startTimestamp={startTimestamp}
290
+ endTimestamp={endTimestamp}
291
+ isDateBasedLiveContent={isDateBasedLiveContent}
292
+ onSkipLive={onSkipLive}
293
+ progressBarStyles={styles.progressBar}
294
+ countDownOptions={countDownOptions}
295
+ thumbStyles={styles.progressBarThumbStyles}
296
+ thumbStylesPressed={styles.progressBarThumbStyles_pressed}
297
+ trackStyles={styles.progressBarTrackStyles}
298
+ />
299
+
300
+ <VerticalGutter />
301
+ </>
302
+ ) : null}
303
+
304
+ <MobileTransportControls
305
+ value={value}
306
+ visible={true}
307
+ keepAlive={null}
308
+ buttons={controlButtons}
309
+ style={{
310
+ justifyContent: getControlJustifyContent(controlButtons().length),
311
+ }}
312
+ playerState={playerState}
313
+ />
314
+ </AnimationComponent>
315
+ );
316
+ };
@@ -1,25 +1,7 @@
1
- type PlayerState = {
2
- currentTime: number;
3
- duration: number;
4
- seekableDuration: number;
5
- isLive: boolean;
6
- isPaused: boolean;
7
- isBuffering: boolean;
8
- };
9
-
10
- const rewindButtonSize = (isTablet: boolean): keyof ButtonSizeStyles =>
11
- isTablet ? "big" : "smallMargins";
12
-
13
- const playbackButtonSize = (isTablet: boolean): keyof ButtonSizeStyles =>
14
- isTablet ? "bigExtended" : "mediumExtended";
15
-
16
1
  const playbackButtonMargins = (
17
2
  isTablet: boolean,
18
3
  isLiveShowFullControls: boolean
19
- ): number =>
20
- isLiveShowFullControls ? (isTablet ? 65 : 10) : isTablet ? 95 : 40;
21
-
22
- export const PADDING_HORIZONTAL = 15;
4
+ ): number => (isLiveShowFullControls ? (isTablet ? 65 : 10) : undefined);
23
5
 
24
6
  export const playbackButton = ({
25
7
  playerState,
@@ -28,7 +10,7 @@ export const playbackButton = ({
28
10
  isLiveShowFullControls,
29
11
  onPress,
30
12
  }: {
31
- playerState: PlayerState;
13
+ playerState: QuickBrickPlayer.PlayerState;
32
14
  liveButton: boolean;
33
15
  isTablet: boolean;
34
16
  isLiveShowFullControls: boolean;
@@ -37,11 +19,11 @@ export const playbackButton = ({
37
19
  const icon = playerState.isPaused
38
20
  ? "play"
39
21
  : playerState.isLive && liveButton
40
- ? "stop"
41
- : "pause";
22
+ ? "stop"
23
+ : "pause";
42
24
 
43
25
  return {
44
- size: playbackButtonSize(isTablet),
26
+ size: "bigExtended",
45
27
  icon: playerState.isBuffering ? "buffering" : icon,
46
28
  preferredFocus: true,
47
29
  onPress,
@@ -57,15 +39,15 @@ type ButtonsProps = {
57
39
  style?: any;
58
40
  name?: string;
59
41
  };
42
+
60
43
  type ButtonsByNameProps = ButtonsProps & { name?: string };
61
44
 
62
45
  const rewindButtonByName = ({
63
46
  name,
64
47
  onPress,
65
- isTablet,
66
48
  style,
67
49
  }: ButtonsByNameProps): ControlsButton => ({
68
- size: rewindButtonSize(isTablet),
50
+ size: "big",
69
51
  icon: name,
70
52
  onPress,
71
53
  style,
@@ -0,0 +1,55 @@
1
+ /* eslint react-native/no-color-literals: off */
2
+ /* eslint react-native/no-inline-styles: off */
3
+
4
+ import * as React from "react";
5
+ import { View } from "react-native";
6
+
7
+ import { MOBILE } from "../const";
8
+
9
+ export const LeftDebugSquare = () => (
10
+ <View
11
+ style={{
12
+ position: "absolute",
13
+ top: 200,
14
+ left: 0,
15
+ width: MOBILE.MARGIN_HORIZONTAL,
16
+ height: MOBILE.MARGIN_HORIZONTAL,
17
+ backgroundColor: "blue",
18
+
19
+ borderWidth: 1,
20
+ borderColor: "yellow",
21
+ }}
22
+ />
23
+ );
24
+
25
+ export const RightDebugSquare = () => (
26
+ <View
27
+ style={{
28
+ position: "absolute",
29
+ top: 200,
30
+ right: 0,
31
+ width: MOBILE.MARGIN_HORIZONTAL,
32
+ height: MOBILE.MARGIN_HORIZONTAL,
33
+ backgroundColor: "blue",
34
+
35
+ borderWidth: 1,
36
+ borderColor: "yellow",
37
+ }}
38
+ />
39
+ );
40
+
41
+ export const BottomDebugSquare = () => (
42
+ <View
43
+ style={{
44
+ position: "absolute",
45
+ left: 170,
46
+ bottom: 0,
47
+ width: MOBILE.MARGIN_BOTTOM,
48
+ height: MOBILE.MARGIN_BOTTOM,
49
+ backgroundColor: "blue",
50
+
51
+ borderWidth: 1,
52
+ borderColor: "yellow",
53
+ }}
54
+ />
55
+ );
@@ -9,49 +9,31 @@ import * as R from "ramda";
9
9
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
10
10
 
11
11
  import {
12
+ Button,
12
13
  ContentInfo,
13
- ProgressBar,
14
14
  Controls,
15
- Button,
15
+ ProgressBar,
16
16
  } from "@applicaster/quick-brick-mobile-transport-controls";
17
17
 
18
18
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
19
+
19
20
  import {
20
- useModalAnimationContext,
21
21
  AnimationComponent,
22
22
  ComponentAnimationType,
23
23
  PlayerAnimationStateEnum,
24
+ useModalAnimationContext,
24
25
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
26
+ import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
25
27
 
26
- type Dimensions = {
27
- width: number;
28
- height: number;
29
- };
30
-
31
- type LayoutProps = {
28
+ type Props = {
32
29
  entry: ZappEntry;
33
- layoutState: {
34
- inline: boolean;
35
- docked: boolean;
36
- isModal: boolean;
37
- };
38
- playerState: {
39
- currentTime: number;
40
- duration: number;
41
- seekableDuration: number;
42
- isLive: boolean;
43
- isPaused: boolean;
44
- isBuffering: boolean;
45
- };
30
+ layoutState: QuickBrickPlayer.LayoutState;
31
+ playerState: QuickBrickPlayer.PlayerState;
46
32
  value: GetValue;
47
- configuration: { [key: string]: any };
48
- onPlaybackButtonPress: () => void;
49
- onRewindButtonPress: () => void;
50
- onForwardButtonPress: () => void;
51
- onPlayerSeek: (targetTime: number) => void;
33
+ configuration: QuickBrickPlayer.AudioPlayerProps["configuration"];
34
+ dimensions: QuickBrickPlayer.AudioPlayerProps["dimensions"];
52
35
  onCloseVideoModal: () => void;
53
- maximiseVideoModal: () => void;
54
- dimensions: Dimensions;
36
+ onPlayerSeek: (targetTime: number) => void;
55
37
  playNextData: PlayNextData;
56
38
  title: string | number;
57
39
  summary: string | number;
@@ -113,17 +95,21 @@ const playerDimensionsStyle = (
113
95
  minimisedHeight: number,
114
96
  addPadding: boolean
115
97
  ): ViewStyle => ({
116
- paddingLeft: addPadding ? minimisedHeight || 100 : 0,
98
+ paddingLeft: addPadding ? toNumberWithDefault(100, minimisedHeight) : 0,
117
99
  });
118
100
 
119
- const animatedContainerStyle = (docked: boolean): ViewStyle => ({
101
+ const animatedContainerStyle = (
102
+ docked: boolean,
103
+ progressBarHeight: number
104
+ ): ViewStyle => ({
105
+ top: progressBarHeight,
120
106
  position: "absolute",
121
107
  width: "100%",
122
108
  zIndex: docked ? 1 : -1,
123
109
  });
124
110
 
125
111
  const backgroundImageStyle = (
126
- dimensions: Dimensions,
112
+ dimensions: QuickBrickPlayer.AudioPlayerProps["dimensions"],
127
113
  minimisedHeight: number,
128
114
  isActiveGesture: boolean
129
115
  ): ViewStyle => ({
@@ -133,24 +119,11 @@ const backgroundImageStyle = (
133
119
  });
134
120
 
135
121
  const controlButtons = (
136
- isPlayNextEnabled: boolean,
137
122
  live: boolean,
138
123
  paused: boolean,
139
124
  buffering: boolean,
140
125
  playerId: string
141
126
  ): Array<ControlsButton> => {
142
- if (isPlayNextEnabled) {
143
- return [
144
- {
145
- size: "medium",
146
- name: "play_next",
147
- icon: "play_next",
148
- preferredFocus: true,
149
- style: styles.buttons,
150
- },
151
- ];
152
- }
153
-
154
127
  if (buffering) {
155
128
  return [
156
129
  {
@@ -202,16 +175,16 @@ const controlButtons = (
202
175
  ];
203
176
  };
204
177
 
205
- export default function DockedLayout(props: LayoutProps) {
178
+ export const DockedControls = (props: Props) => {
206
179
  const {
180
+ entry,
207
181
  layoutState,
182
+ playerState,
208
183
  value,
184
+ configuration,
209
185
  dimensions,
210
- entry,
211
186
  onCloseVideoModal,
212
187
  onPlayerSeek,
213
- playerState,
214
- configuration,
215
188
  playNextData,
216
189
  title,
217
190
  summary,
@@ -219,7 +192,6 @@ export default function DockedLayout(props: LayoutProps) {
219
192
 
220
193
  const isTablet = useIsTablet();
221
194
 
222
- const visible = true;
223
195
  const liveButton = Boolean(value("live_badge_enabled"));
224
196
 
225
197
  const {
@@ -227,10 +199,11 @@ export default function DockedLayout(props: LayoutProps) {
227
199
  setPlayerAnimationState,
228
200
  startComponentsAnimation,
229
201
  minimisedHeight,
202
+ progressBarHeight,
230
203
  } = useModalAnimationContext();
231
204
 
232
205
  const maximazeVideoModal = React.useCallback(
233
- () => setPlayerAnimationState(PlayerAnimationStateEnum.maximaze),
206
+ () => setPlayerAnimationState(PlayerAnimationStateEnum.maximize),
234
207
  []
235
208
  );
236
209
 
@@ -241,22 +214,27 @@ export default function DockedLayout(props: LayoutProps) {
241
214
  animationType={ComponentAnimationType.componentAppears}
242
215
  style={[
243
216
  styles.container,
244
- animatedContainerStyle(isActiveGesture || layoutState.docked),
217
+ animatedContainerStyle(
218
+ isActiveGesture || layoutState.docked,
219
+ progressBarHeight
220
+ ),
221
+ { height: minimisedHeight },
245
222
  ]}
246
223
  >
247
224
  {!playerState.isLive &&
248
- (layoutState.docked || startComponentsAnimation) && (
249
- <ProgressBar
250
- content={entry}
251
- value={value}
252
- visible={visible}
253
- layoutState={layoutState}
254
- onPlayerSeek={onPlayerSeek}
255
- playerState={playerState}
256
- startComponentsAnimation={startComponentsAnimation}
257
- docked
258
- />
259
- )}
225
+ (layoutState.docked || startComponentsAnimation) ? (
226
+ <ProgressBar
227
+ name={"audio-docked-layout"}
228
+ content={entry}
229
+ value={value}
230
+ visible
231
+ layoutState={layoutState}
232
+ onPlayerSeek={onPlayerSeek}
233
+ playerState={playerState}
234
+ startComponentsAnimation={startComponentsAnimation}
235
+ docked
236
+ />
237
+ ) : null}
260
238
 
261
239
  <View style={styles.content}>
262
240
  <View
@@ -300,9 +278,8 @@ export default function DockedLayout(props: LayoutProps) {
300
278
  >
301
279
  <Controls
302
280
  value={value}
303
- visible={visible}
281
+ visible
304
282
  buttons={R.partial(controlButtons, [
305
- playNextData,
306
283
  playerState.isLive && liveButton,
307
284
  ])}
308
285
  style={styles.playPauseButton}
@@ -320,4 +297,4 @@ export default function DockedLayout(props: LayoutProps) {
320
297
  </View>
321
298
  </AnimationComponent>
322
299
  );
323
- }
300
+ };