@applicaster/quick-brick-player 12.0.0-alpha.6602834797 → 12.0.0-alpha.7101461483

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.6602834797",
3
+ "version": "12.0.0-alpha.7101461483",
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-alpha.6602834797",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "12.0.0-alpha.7101461483",
40
40
  "@applicaster/quick-brick-tv-transport-controls": "11.0.0-rc.133",
41
- "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.6602834797",
42
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.6602834797",
43
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.6602834797",
41
+ "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.7101461483",
42
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.7101461483",
43
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.7101461483",
44
44
  "keymirror": "^0.1.1",
45
45
  "react-native-web-linear-gradient": "1.1.2",
46
46
  "shaka-player": "4.3.5",
@@ -15,7 +15,15 @@ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
15
15
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
16
16
  import { PlayerDetails } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/PlayerDetails";
17
17
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
18
+ import { useEffect, useState } from "react";
18
19
  import { MagicBG } from "./MagicBG";
20
+ import {
21
+ formatSpeed,
22
+ hasDatePassed,
23
+ loadItemsFromStorage,
24
+ NAMESPACE,
25
+ } from "./utils";
26
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
19
27
 
20
28
  const { log_debug } = createLogger({
21
29
  subsystem: "UIComponent",
@@ -96,6 +104,17 @@ const Styles = {
96
104
  },
97
105
  };
98
106
 
107
+ const sleeps = [
108
+ // { label: "End of episode", value: "episode" },
109
+ { label: "5 minutes", value: 5 },
110
+ { label: "10 minutes", value: 10 },
111
+ { label: "15 minutes", value: 15 },
112
+ { label: "30 minutes", value: 30 },
113
+ { label: "45 minutes", value: 45 },
114
+ { label: "1 hour", value: 60 },
115
+ { label: "2 hours", value: 120 },
116
+ ];
117
+
99
118
  export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
100
119
  const player = usePlayer();
101
120
  const playerState = usePlayerState("audio-player-wrapper");
@@ -111,15 +130,37 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
111
130
  isTabletPortrait,
112
131
  } = props;
113
132
 
133
+ const speeds = [
134
+ { asset: configuration["speed_0_8"], value: 0.8 },
135
+ { asset: configuration["speed_1"], value: 1.0 },
136
+ { asset: configuration["speed_1_2"], value: 1.2 },
137
+ { asset: configuration["speed_1_5"], value: 1.5 },
138
+ { asset: configuration["speed_2"], value: 2.0 },
139
+ ];
140
+
114
141
  const isTablet = useIsTablet();
115
142
 
116
143
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
117
144
 
145
+ const [playbackSpeed, setPlaybackSpeed] = useState({
146
+ asset: configuration["speed_1"],
147
+ value: 1.0,
148
+ });
149
+
150
+ const [sleepTimer, setSleepTimer] = useState({
151
+ label: "playback_sleep_off_label",
152
+ value: 0,
153
+ });
154
+
155
+ const [sleepTimerDate, setSleepTimerDate] = useState(0);
156
+
118
157
  const [dimensions, setDimensions] = React.useState<Dimensions>({
119
158
  width: 0,
120
159
  height: 0,
121
160
  });
122
161
 
162
+ const navigator = useNavigation();
163
+
123
164
  const { maximiseVideoModal } = useNavigation();
124
165
 
125
166
  const onLayout = (event: any) => {
@@ -131,6 +172,84 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
131
172
  });
132
173
  };
133
174
 
175
+ const cancelSleepTimer = async () => {
176
+ player?.cancelSleepTimer();
177
+
178
+ setSleepTimer({
179
+ label: "playback_sleep_off_label",
180
+ value: 0,
181
+ });
182
+
183
+ setSleepTimerDate(0);
184
+ player?.pause();
185
+
186
+ await localStorage.removeItem("sleep", NAMESPACE);
187
+ };
188
+
189
+ const startSleepTimer = (timerValue: number) => {
190
+ try {
191
+ const currentDate = new Date();
192
+ const futureDate = new Date(currentDate.getTime() + timerValue * 60000);
193
+ const futureSleepDate = futureDate.getTime();
194
+
195
+ player?.cancelSleepTimer();
196
+
197
+ player?.startSleepTimer(futureSleepDate);
198
+
199
+ return futureSleepDate;
200
+ } catch (e) {
201
+ return 0;
202
+ }
203
+ };
204
+
205
+ const handleSleep = async (
206
+ timerValue: number,
207
+ currentFutureSleepDate = null
208
+ ) => {
209
+ if (currentFutureSleepDate) {
210
+ if (hasDatePassed(currentFutureSleepDate)) {
211
+ await cancelSleepTimer();
212
+
213
+ return 0;
214
+ }
215
+
216
+ return currentFutureSleepDate;
217
+ }
218
+
219
+ if (timerValue === 0) {
220
+ await cancelSleepTimer();
221
+
222
+ return timerValue;
223
+ }
224
+
225
+ return startSleepTimer(timerValue);
226
+ };
227
+
228
+ useEffect(() => {
229
+ const loadSpeed = async () => {
230
+ const speed = await loadItemsFromStorage("speed");
231
+
232
+ if (playerState.isReadyToPlay && speed) {
233
+ setPlaybackSpeed(speed);
234
+ player?.setPlaybackRate(speed.value);
235
+ }
236
+ };
237
+
238
+ const loadSleep = async () => {
239
+ const sleep = await loadItemsFromStorage("sleep");
240
+
241
+ if (playerState.isReadyToPlay && sleep) {
242
+ const { futureSleepDate, ...rest } = sleep;
243
+ setSleepTimer(rest);
244
+ const sleepTimerDate = await handleSleep(sleep.value, futureSleepDate);
245
+ setSleepTimerDate(sleepTimerDate);
246
+ }
247
+ };
248
+
249
+ loadSpeed().then();
250
+ loadSleep().then();
251
+ }, [playerState.isReadyToPlay]);
252
+
134
253
  const getValue = (key: string, stylesObj: {}) =>
135
254
  R.propOr(null, key, stylesObj);
136
255
 
@@ -170,6 +289,60 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
170
289
  player?.forward(seekDuration);
171
290
  }, [seekDuration, player]);
172
291
 
292
+ const onSpeedSelect = React.useCallback(
293
+ async (item) => {
294
+ setPlaybackSpeed(item);
295
+ player.setPlaybackRate(item.value);
296
+ await localStorage.setItem("speed", item, NAMESPACE);
297
+ },
298
+ [player, setPlaybackSpeed]
299
+ );
300
+
301
+ const onSleepSelect = React.useCallback(
302
+ async (item) => {
303
+ setSleepTimer(item);
304
+ const futureSleepDate = await handleSleep(item.value);
305
+ setSleepTimerDate(futureSleepDate);
306
+
307
+ await localStorage.setItem(
308
+ "sleep",
309
+ { ...item, futureSleepDate },
310
+ NAMESPACE
311
+ );
312
+ },
313
+ [player, setSleepTimer]
314
+ );
315
+
316
+ const onSpeedButtonPress = React.useCallback(() => {
317
+ navigator.openModalBottomSheet({
318
+ modalBottomSheetContentProps: {
319
+ items: speeds,
320
+ current_selection: playbackSpeed,
321
+ onPress: onSpeedSelect,
322
+ title: configuration["playback_speed_title"],
323
+ },
324
+ options: {
325
+ supportedOrientations: ["portrait"],
326
+ },
327
+ });
328
+ }, [playbackSpeed, setPlaybackSpeed]);
329
+
330
+ const onSleepButtonPress = React.useCallback(() => {
331
+ navigator.openModalBottomSheet({
332
+ modalBottomSheetContentProps: {
333
+ items: [
334
+ { label: configuration["playback_sleep_off_label"], value: 0 },
335
+ ].concat(sleeps),
336
+ current_selection: sleepTimer,
337
+ onPress: onSleepSelect,
338
+ title: configuration["playback_sleep_title"],
339
+ },
340
+ options: {
341
+ supportedOrientations: ["portrait"],
342
+ },
343
+ });
344
+ }, [sleepTimer, setSleepTimer, configuration]);
345
+
173
346
  const onCloseVideoModal = React.useCallback(() => {
174
347
  playerManager.close();
175
348
  }, [playerManager]);
@@ -213,6 +386,14 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
213
386
  onForwardButtonPress={onForwardButtonPress}
214
387
  onPlayerSeek={onPlayerSeek}
215
388
  onSkipStart={onSkipStart}
389
+ onSpeedButtonPress={onSpeedButtonPress}
390
+ onSleepButtonPress={onSleepButtonPress}
391
+ playbackSpeedName={formatSpeed(playbackSpeed.value)}
392
+ playbackSleepName={
393
+ sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
394
+ }
395
+ sleepTimerDate={sleepTimerDate}
396
+ cancelSleepTimer={cancelSleepTimer}
216
397
  onSkipLive={onSkipLive}
217
398
  onCloseVideoModal={onCloseVideoModal}
218
399
  maximiseVideoModal={maximiseVideoModal}
@@ -252,6 +433,8 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
252
433
  playNextData,
253
434
  onSkipStart,
254
435
  onSkipLive,
436
+ sleepTimer.value,
437
+ sleepTimerDate,
255
438
  ]);
256
439
 
257
440
  if (configuration.magic_background) {
@@ -6,21 +6,25 @@ import {
6
6
  ProgressBar,
7
7
  Controls,
8
8
  TransportInfo,
9
+ CountDown,
9
10
  } from "@applicaster/quick-brick-mobile-transport-controls";
10
11
 
11
12
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
12
13
 
13
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
14
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
14
15
  import {
15
16
  forwardButton,
16
17
  playbackButton,
17
18
  rewindButton,
18
19
  skipToStartButton,
19
20
  skipToLiveButton,
21
+ speedButton,
22
+ sleepButton,
20
23
  } from "./defaultLayoutsConts";
21
24
  import { AudioDescription } from "../AudioDescription";
22
25
  import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
23
26
  import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
27
+ import { useEffect, useMemo, useState } from "react";
24
28
 
25
29
  type Dimensions = {
26
30
  width: number;
@@ -42,11 +46,17 @@ type LayoutProps = {
42
46
  isPaused: boolean;
43
47
  isBuffering: boolean;
44
48
  };
49
+ sleepTimerDate: number;
45
50
  value: GetValue;
51
+ playbackSpeedName: string;
52
+ playbackSleepName: string;
46
53
  configuration: { [key: string]: any };
47
54
  onPlaybackButtonPress: () => void;
48
55
  onRewindButtonPress: () => void;
49
56
  onForwardButtonPress: () => void;
57
+ onSpeedButtonPress: () => void;
58
+ onSleepButtonPress: () => void;
59
+ cancelSleepTimer: () => void;
50
60
  onPlayerSeek: (targetTime: number) => void;
51
61
  onSkipLive: () => void;
52
62
  onSkipStart: () => void;
@@ -68,8 +78,8 @@ const Styles = {
68
78
  },
69
79
  controls: (isTablet: boolean, isLiveShowFullControls: boolean) => ({
70
80
  height: isTablet ? 64 : 50,
71
- marginHorizontal: isLiveShowFullControls ? 10 : 24,
72
- justifyContent: isLiveShowFullControls ? "space-between" : "center",
81
+ marginHorizontal: 10,
82
+ justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
73
83
  }),
74
84
  backgroundImageContainer: (dimensions: Dimensions, isTablet: boolean) => {
75
85
  return {
@@ -117,8 +127,14 @@ export default function DefaultLayout(props: LayoutProps) {
117
127
  onPlayerSeek,
118
128
  onSkipStart,
119
129
  onSkipLive,
130
+ onSpeedButtonPress,
131
+ onSleepButtonPress,
132
+ playbackSpeedName,
133
+ playbackSleepName,
120
134
  configuration,
121
135
  dimensions,
136
+ cancelSleepTimer,
137
+ sleepTimerDate,
122
138
  } = props;
123
139
 
124
140
  const isTablet = useIsTablet();
@@ -128,8 +144,15 @@ export default function DefaultLayout(props: LayoutProps) {
128
144
 
129
145
  const languageData = useLanguageData("audio-player");
130
146
 
147
+ const showCounter = useMemo(() => sleepTimerDate > 0, [sleepTimerDate]);
148
+
131
149
  const controller = playerManager.getActivePlayer();
132
150
  const liveButton = Boolean(value("live_badge_enabled"));
151
+ const sleepTitle = value("playback_sleep_countdown_label");
152
+
153
+ const [timeLeft, setTimeLeft] = useState(
154
+ sleepTimerDate !== 0 ? sleepTimerDate - Date.now() : 0
155
+ );
133
156
 
134
157
  let showFullControls =
135
158
  controller?.hasContentDuration?.() && !controller?.isAd();
@@ -166,6 +189,18 @@ export default function DefaultLayout(props: LayoutProps) {
166
189
  const rewind = rewindButton({ isTablet, onPress: onRewindButtonPress });
167
190
  const forward = forwardButton({ isTablet, onPress: onForwardButtonPress });
168
191
 
192
+ const speed = speedButton({
193
+ isTablet,
194
+ onPress: onSpeedButtonPress,
195
+ name: playbackSpeedName,
196
+ });
197
+
198
+ const sleep = sleepButton({
199
+ isTablet,
200
+ onPress: onSleepButtonPress,
201
+ name: playbackSleepName,
202
+ });
203
+
169
204
  if (isLiveContent) {
170
205
  const skipToStart = skipToStartButton({
171
206
  isTablet,
@@ -180,7 +215,8 @@ export default function DefaultLayout(props: LayoutProps) {
180
215
  return [skipToStart, rewind, play, forward, skipToLive];
181
216
  }
182
217
 
183
- return [rewind, play, forward];
218
+ // Temporary empty button until we add sleep button. It will ensure the buttons will not break in their position
219
+ return [speed, rewind, play, forward, sleep];
184
220
  }, [
185
221
  playerState,
186
222
  liveButton,
@@ -188,12 +224,47 @@ export default function DefaultLayout(props: LayoutProps) {
188
224
  onPlaybackButtonPress,
189
225
  onRewindButtonPress,
190
226
  onForwardButtonPress,
227
+ onSpeedButtonPress,
191
228
  showFullControls,
192
229
  onSkipStart,
193
230
  onSkipLive,
194
231
  isLiveContent,
232
+ playbackSpeedName,
233
+ playbackSleepName,
195
234
  ]);
196
235
 
236
+ useEffect(() => {
237
+ if (showCounter && sleepTimerDate !== 0) {
238
+ // Setting the initial timeLeft based on sleepTimerDate
239
+ setTimeLeft(sleepTimerDate - Date.now());
240
+
241
+ // Setting up an interval to update the remaining time every second
242
+ const intervalId = setInterval(() => {
243
+ setTimeLeft(() => {
244
+ const newTimeLeft = sleepTimerDate - Date.now();
245
+
246
+ // If the new remaining time is less than or equal to 0, clear the interval and trigger the cancelSleepTimer function
247
+ if (newTimeLeft <= 0) {
248
+ clearInterval(intervalId);
249
+
250
+ cancelSleepTimer();
251
+
252
+ return 0;
253
+ } else {
254
+ // Otherwise, update the state with the new remaining time
255
+ return newTimeLeft;
256
+ }
257
+ });
258
+ }, 1000);
259
+
260
+ // Clearing the interval when the component unmounts or dependencies change
261
+ return () => clearInterval(intervalId);
262
+ } else {
263
+ // Ensure the timeLeft state is set correctly if showCounter is false
264
+ setTimeLeft(0);
265
+ }
266
+ }, [sleepTimerDate, showCounter, cancelSleepTimer]);
267
+
197
268
  const Separator = () => <View style={Styles.separator} />;
198
269
 
199
270
  const liveSeekingEnabled = value("liveSeekingEnabled");
@@ -222,7 +293,6 @@ export default function DefaultLayout(props: LayoutProps) {
222
293
  >
223
294
  <View style={isTablet ? Styles.tabletLayout : null}>
224
295
  <PlayerImageBackground
225
- configuration={configuration}
226
296
  entry={entry}
227
297
  style={Styles.backgroundImageContainer(dimensions, isTablet)}
228
298
  imageStyle={Styles.backgroundImageContainerImageStyle(isTablet)}
@@ -245,6 +315,15 @@ export default function DefaultLayout(props: LayoutProps) {
245
315
  disableFullscreen={true}
246
316
  sliderStyle={2}
247
317
  />
318
+
319
+ {showCounter && timeLeft >= 0 && (
320
+ <CountDown
321
+ timeLeft={timeLeft}
322
+ value={value}
323
+ title={sleepTitle}
324
+ />
325
+ )}
326
+
248
327
  <Separator />
249
328
  </View>
250
329
  )}
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import * as React from "react";
2
2
  import {
3
3
  StyleSheet,
4
4
  TouchableWithoutFeedback,
@@ -6,7 +6,7 @@ import {
6
6
  ViewStyle,
7
7
  } from "react-native";
8
8
  import * as R from "ramda";
9
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
9
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
10
10
 
11
11
  import {
12
12
  ContentInfo,
@@ -198,9 +198,7 @@ export default function DockedLayout(props: LayoutProps) {
198
198
  playNextData,
199
199
  } = props;
200
200
 
201
- const {
202
- deviceInfo: { isTablet },
203
- } = useDimensions("screen", { deviceInfo: true });
201
+ const isTablet = useIsTablet();
204
202
 
205
203
  const visible = true;
206
204
  const liveButton = Boolean(value("live_badge_enabled"));
@@ -53,8 +53,9 @@ type ButtonsProps = {
53
53
  onPress: () => void;
54
54
  isTablet: boolean;
55
55
  style?: any;
56
+ name?: string;
56
57
  };
57
- type ButtonsByNameProps = ButtonsProps & { name: string };
58
+ type ButtonsByNameProps = ButtonsProps & { name?: string };
58
59
 
59
60
  const rewindButtonByName = ({
60
61
  name,
@@ -79,6 +80,28 @@ const skipButtonByName = ({
79
80
  style,
80
81
  });
81
82
 
83
+ const speedButtonByName = ({
84
+ name = "speed_1",
85
+ onPress,
86
+ style,
87
+ }: ButtonsByNameProps): ControlsButton => ({
88
+ size: "small",
89
+ icon: name,
90
+ onPress,
91
+ style,
92
+ });
93
+
94
+ const sleepButtonByName = ({
95
+ name = "sleep_timer",
96
+ onPress,
97
+ style,
98
+ }: ButtonsByNameProps): ControlsButton => ({
99
+ size: "small",
100
+ icon: name,
101
+ onPress,
102
+ style,
103
+ });
104
+
82
105
  export const rewindButton = (props: ButtonsProps): ControlsButton =>
83
106
  rewindButtonByName({ ...props, name: "rewind" });
84
107
 
@@ -90,3 +113,9 @@ export const skipToStartButton = (props: ButtonsProps): ControlsButton =>
90
113
 
91
114
  export const skipToLiveButton = (props: ButtonsProps): ControlsButton =>
92
115
  skipButtonByName({ ...props, name: "skip_live" });
116
+
117
+ export const speedButton = (props: ButtonsProps): ControlsButton =>
118
+ speedButtonByName({ ...props });
119
+
120
+ export const sleepButton = (props: ButtonsProps): ControlsButton =>
121
+ sleepButtonByName({ ...props });
@@ -24,11 +24,17 @@ type LayoutProps = {
24
24
  isBuffering: boolean;
25
25
  };
26
26
  value: GetValue;
27
+ sleepTimerDate: number;
28
+ playbackSpeedName: string;
29
+ playbackSleepName: string;
27
30
  configuration: { [key: string]: any };
28
31
  onPlaybackButtonPress: () => void;
29
32
  onRewindButtonPress: () => void;
30
33
  onForwardButtonPress: () => void;
34
+ onSpeedButtonPress: () => void;
35
+ onSleepButtonPress: () => void;
31
36
  onCloseVideoModal: () => void;
37
+ cancelSleepTimer: () => void;
32
38
  onPlayerSeek: (targetTime: number) => void;
33
39
  onSkipStart: () => void;
34
40
  onSkipLive: () => void;
@@ -0,0 +1,33 @@
1
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
2
+ import { parseJsonIfNeeded } from "@applicaster/zapp-react-native-utils/functionUtils";
3
+
4
+ export const NAMESPACE = "audio-player";
5
+
6
+ export async function loadItemsFromStorage(key: string) {
7
+ const storedItems = await localStorage.getItem(key, NAMESPACE);
8
+
9
+ return parseJsonIfNeeded(storedItems) || null;
10
+ }
11
+
12
+ export const hasDatePassed = (timestamp: number) => {
13
+ // Get the current date and time
14
+ const currentDate = new Date();
15
+
16
+ // Compare the current date's timestamp with the given timestamp
17
+ return currentDate.getTime() > timestamp;
18
+ };
19
+
20
+ export const formatSpeed = (value: number) => {
21
+ let formattedValue = value.toString();
22
+
23
+ // If the value ends with ".0", remove it
24
+ if (formattedValue.endsWith(".0")) {
25
+ formattedValue = formattedValue.slice(0, -2);
26
+ }
27
+
28
+ // Replace "." with "_"
29
+ formattedValue = formattedValue.replace(".", "_");
30
+
31
+ // Return the formatted string with "speed_" prefix
32
+ return `speed_${formattedValue}`;
33
+ };
@@ -87,7 +87,7 @@ export default class VideoPlayer extends React.Component<
87
87
  // TODO: Can be deleted, on controller logic
88
88
  paused: false,
89
89
  piped: false,
90
- rate: 1,
90
+ rate: 1.0,
91
91
  // TODO: Hack for analytics, must br removed
92
92
  resume: null,
93
93
 
@@ -368,6 +368,10 @@ export default class VideoPlayer extends React.Component<
368
368
  }
369
369
  };
370
370
 
371
+ setPlaybackRate = (rate = 1.0) => {
372
+ this.setState({ rate });
373
+ };
374
+
371
375
  getCurrentTime = () => {
372
376
  return this.state.currentTime;
373
377
  };
@@ -767,7 +771,8 @@ export default class VideoPlayer extends React.Component<
767
771
  style,
768
772
  } = this.props;
769
773
 
770
- const { audioTrackId, keyEvent, paused, seek, textTrackId } = this.state;
774
+ const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
775
+ this.state;
771
776
 
772
777
  const isAudioItem =
773
778
  entry?.content?.type?.includes?.("audio") ||
@@ -839,6 +844,7 @@ export default class VideoPlayer extends React.Component<
839
844
  nowPlayingEnabled,
840
845
  paused,
841
846
  seek,
847
+ rate,
842
848
  textTrackId,
843
849
  liveSeekingEnabled,
844
850
  liveCatchUpEnabled,
@@ -1005,10 +1011,12 @@ export default class VideoPlayer extends React.Component<
1005
1011
  inline,
1006
1012
  docked,
1007
1013
  isModal,
1014
+ pip: this.state.piped,
1008
1015
  layoutState: {
1009
1016
  inline,
1010
1017
  docked,
1011
1018
  isModal,
1019
+ pip: this.state.piped,
1012
1020
  },
1013
1021
  configuration: this.getPluginConfiguration(),
1014
1022
  fullscreen: fullscreen,
@@ -1085,6 +1093,7 @@ export default class VideoPlayer extends React.Component<
1085
1093
  listener={this.props.listener}
1086
1094
  style={getStyle(playerDimensions)}
1087
1095
  pluginConfiguration={this.getPluginConfiguration()}
1096
+ controller={this.props.controller}
1088
1097
  >
1089
1098
  {this.childrenWithPlayNext()}
1090
1099
  </this.props.PlayerComponent>
@@ -1121,6 +1130,7 @@ export default class VideoPlayer extends React.Component<
1121
1130
  listener={this.props.listener}
1122
1131
  style={this.takeParentStyle}
1123
1132
  pluginConfiguration={this.getPluginConfiguration()}
1133
+ controller={this.props.controller}
1124
1134
  >
1125
1135
  {this.childrenWithPlayNext()}
1126
1136
  </this.props.PlayerComponent>