@applicaster/quick-brick-player 13.0.0-rc.4 → 13.0.0-rc.41

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": "13.0.0-rc.4",
3
+ "version": "13.0.0-rc.41",
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.118",
40
- "@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.112",
41
- "@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.4",
42
- "@applicaster/zapp-react-native-ui-components": "13.0.0-rc.4",
43
- "@applicaster/zapp-react-native-utils": "13.0.0-rc.4",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.28",
40
+ "@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.31",
41
+ "@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.41",
42
+ "@applicaster/zapp-react-native-ui-components": "13.0.0-rc.41",
43
+ "@applicaster/zapp-react-native-utils": "13.0.0-rc.41",
44
44
  "keymirror": "^0.1.1",
45
45
  "query-string": "7.1.3",
46
46
  "react-native-web-linear-gradient": "1.1.2",
@@ -51,12 +51,31 @@
51
51
  "videojs-contrib-quality-levels": "3.0.0"
52
52
  },
53
53
  "peerDependencies": {
54
+ "@applicaster/applicaster-types": "*",
55
+ "@applicaster/blur": "*",
54
56
  "@applicaster/quick-brick-xray": "*",
55
57
  "@applicaster/react-native-color-thief": "*",
58
+ "@applicaster/zapp-pipes-v2-client": "*",
59
+ "@applicaster/zapp-react-dom-ui-components": "*",
60
+ "@applicaster/zapp-react-native-redux": "*",
61
+ "@applicaster/zapp-react-native-tvos-ui-components": "*",
62
+ "@babel/runtime": "*",
63
+ "@react-native-community/netinfo": "*",
56
64
  "@types/node": "*",
57
65
  "@types/react-native": "0.69.6",
66
+ "immer": "*",
58
67
  "react": "17.0.2",
68
+ "react-hot-loader": "*",
59
69
  "react-native": "0.68.6",
60
- "react-native-linear-gradient": "*"
70
+ "react-native-fs": "*",
71
+ "react-native-gesture-handler": "*",
72
+ "react-native-linear-gradient": "*",
73
+ "react-native-safe-area-context": "*",
74
+ "react-native-svg": "*",
75
+ "react-native-web": "*",
76
+ "react-native-webview": "*",
77
+ "uglify-js": "*",
78
+ "validate-color": "*",
79
+ "zustand": "*"
61
80
  }
62
81
  }
@@ -17,13 +17,7 @@ import { PlayerDetails } from "@applicaster/zapp-react-native-ui-components/Comp
17
17
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
18
18
  import { useEffect, useState } from "react";
19
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";
20
+ import { formatSpeed } from "./utils";
27
21
  import { addQueryParam, getLiveUrl } from "../Utils";
28
22
  import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
29
23
  import {
@@ -33,6 +27,19 @@ import {
33
27
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
34
28
  import { PADDING_HORIZONTAL } from "./Layout/defaultLayoutsConts";
35
29
  import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
30
+ import {
31
+ speed_0_8,
32
+ speed_1,
33
+ speed_1_2,
34
+ speed_1_5,
35
+ speed_2,
36
+ } from "@applicaster/quick-brick-mobile-transport-controls";
37
+ import {
38
+ SleepTimerController,
39
+ SleepTimerState,
40
+ SLEEP_TIMER_OFF,
41
+ } from "./SleepTimerManager";
42
+ import { SpeedController, PlaybackSpeed, DEFAULT_SPEED } from "./SpeedManager";
36
43
 
37
44
  const { log_debug } = createLogger({
38
45
  subsystem: "UIComponent",
@@ -132,11 +139,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
132
139
  } = props;
133
140
 
134
141
  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 },
142
+ { asset: configuration["speed_0_8"] || speed_0_8, value: 0.8 },
143
+ { asset: configuration["speed_1"] || speed_1, value: 1.0 },
144
+ { asset: configuration["speed_1_2"] || speed_1_2, value: 1.2 },
145
+ { asset: configuration["speed_1_5"] || speed_1_5, value: 1.5 },
146
+ { asset: configuration["speed_2"] || speed_2, value: 2.0 },
140
147
  ];
141
148
 
142
149
  const isTablet = useIsTablet();
@@ -154,17 +161,29 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
154
161
  configuration?.audio_live_player_update_interval
155
162
  );
156
163
 
157
- const [playbackSpeed, setPlaybackSpeed] = useState({
158
- asset: configuration["speed_1"],
159
- value: 1.0,
160
- });
164
+ const [sleepTimerManager, setSleepTimerManager] =
165
+ useState<SleepTimerController | null>(null);
161
166
 
162
- const [sleepTimer, setSleepTimer] = useState({
163
- label: "playback_sleep_off_label",
164
- value: 0,
165
- });
167
+ const [speedManager, setSpeedManager] = useState<SpeedController | null>(
168
+ null
169
+ );
166
170
 
167
- const [sleepTimerDate, setSleepTimerDate] = useState(0);
171
+ useEffect(() => {
172
+ if (player) {
173
+ setSleepTimerManager(new SleepTimerController(player));
174
+ setSpeedManager(new SpeedController(player));
175
+ } else {
176
+ setSleepTimerManager(null);
177
+ setSpeedManager(null);
178
+ }
179
+ }, [player]);
180
+
181
+ const [playbackSpeed, setPlaybackSpeed] =
182
+ useState<PlaybackSpeed>(DEFAULT_SPEED);
183
+
184
+ const [sleepTimerState, setSleepTimerState] = useState<SleepTimerState>(
185
+ new SleepTimerState(SLEEP_TIMER_OFF, 0)
186
+ );
168
187
 
169
188
  const [defaultDimensions, setDefaultDimensions] =
170
189
  React.useState<Dimensions>(undefined);
@@ -189,82 +208,27 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
189
208
  if (!defaultDimensions) setDefaultDimensions({ width, height });
190
209
  };
191
210
 
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
211
  useEffect(() => {
245
- const loadSpeed = async () => {
246
- const speed = await loadItemsFromStorage("speed");
212
+ const sleepSubscription =
213
+ sleepTimerManager?.sleepTimerState$.subscribe(setSleepTimerState);
247
214
 
248
- if (playerState.isReadyToPlay && speed) {
249
- setPlaybackSpeed(speed);
250
- player?.setPlaybackRate(speed.value);
251
- }
252
- };
215
+ const speedSubscription =
216
+ speedManager?.playbackSpeed$.subscribe(setPlaybackSpeed);
253
217
 
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
- }
218
+ return () => {
219
+ sleepSubscription?.unsubscribe();
220
+ speedSubscription?.unsubscribe();
263
221
  };
222
+ }, [sleepTimerManager, speedManager]);
223
+
224
+ useEffect(() => {
225
+ if (!playerState.isReadyToPlay) {
226
+ return;
227
+ }
264
228
 
265
- loadSpeed().then();
266
- loadSleep().then();
267
- }, [playerState.isReadyToPlay]);
229
+ void speedManager?.loadSpeed();
230
+ void sleepTimerManager?.loadSleep();
231
+ }, [playerState.isReadyToPlay, speedManager, sleepTimerManager]);
268
232
 
269
233
  const getValue = (key: string, stylesObj: {}) =>
270
234
  R.propOr(null, key, stylesObj);
@@ -292,7 +256,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
292
256
 
293
257
  const onPlaybackButtonPress = React.useCallback(() => {
294
258
  if (playerState.isBuffering) return;
295
- playerState.isPaused ? player?.play() : player.pause();
259
+ playerState.isPaused ? player?.play() : player?.pause();
296
260
  }, [playerState, player]);
297
261
 
298
262
  const seekDuration = toNumberWithDefault(10, value("seek_duration"));
@@ -307,26 +271,16 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
307
271
 
308
272
  const onSpeedSelect = React.useCallback(
309
273
  async (item) => {
310
- setPlaybackSpeed(item);
311
- player.setPlaybackRate(item.value);
312
- await localStorage.setItem("speed", item, NAMESPACE);
274
+ await speedManager?.setPlaybackSpeed(item);
313
275
  },
314
- [player, setPlaybackSpeed]
276
+ [speedManager]
315
277
  );
316
278
 
317
279
  const onSleepSelect = React.useCallback(
318
280
  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
- );
281
+ await sleepTimerManager?.setSleepTimer(item);
328
282
  },
329
- [player, setSleepTimer]
283
+ [sleepTimerManager]
330
284
  );
331
285
 
332
286
  const onSpeedButtonPress = React.useCallback(() => {
@@ -341,15 +295,24 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
341
295
  supportedOrientations: ["portrait"],
342
296
  },
343
297
  });
344
- }, [playbackSpeed, setPlaybackSpeed]);
298
+ }, [
299
+ playbackSpeed,
300
+ setPlaybackSpeed,
301
+ navigator,
302
+ onSpeedSelect,
303
+ configuration["playback_speed_title"],
304
+ ]);
345
305
 
346
306
  const onSleepButtonPress = React.useCallback(() => {
347
307
  navigator.openModalBottomSheet({
348
308
  modalBottomSheetContentProps: {
349
309
  items: [
350
- { label: configuration["playback_sleep_off_label"], value: 0 },
310
+ {
311
+ label: configuration["playback_sleep_off_label"],
312
+ value: 0,
313
+ },
351
314
  ].concat(sleeps),
352
- current_selection: sleepTimer,
315
+ current_selection: sleepTimerState.timer,
353
316
  onPress: onSleepSelect,
354
317
  title: configuration["playback_sleep_title"],
355
318
  },
@@ -357,7 +320,21 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
357
320
  supportedOrientations: ["portrait"],
358
321
  },
359
322
  });
360
- }, [sleepTimer, setSleepTimer, configuration]);
323
+ }, [
324
+ navigator,
325
+ sleepTimerState.timer,
326
+ configuration["playback_sleep_title"],
327
+ configuration["playback_sleep_off_label"],
328
+ onSleepSelect,
329
+ ]);
330
+
331
+ // This method does not actually cancel the sleep timer
332
+ // (and should not to avoid race condition),
333
+ // it just performs the cleanup when timer expires
334
+ // TODO: rename it in code above
335
+ const cancelSleepTimer = React.useCallback(() => {
336
+ sleepTimerManager?.onTimerExpired();
337
+ }, [sleepTimerManager]);
361
338
 
362
339
  const onCloseVideoModal = React.useCallback(() => {
363
340
  playerManager.close();
@@ -406,9 +383,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
406
383
  onSleepButtonPress={onSleepButtonPress}
407
384
  playbackSpeedName={formatSpeed(playbackSpeed.value)}
408
385
  playbackSleepName={
409
- sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
386
+ sleepTimerState.timer.value === 0
387
+ ? "sleep_timer"
388
+ : "sleep_timer_active"
410
389
  }
411
- sleepTimerDate={sleepTimerDate}
390
+ sleepTimerDate={sleepTimerState.timerDate}
412
391
  cancelSleepTimer={cancelSleepTimer}
413
392
  onSkipLive={onSkipLive}
414
393
  onCloseVideoModal={onCloseVideoModal}
@@ -458,8 +437,8 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
458
437
  playNextData,
459
438
  onSkipStart,
460
439
  onSkipLive,
461
- sleepTimer.value,
462
- sleepTimerDate,
440
+ sleepTimerState.timer.value,
441
+ sleepTimerState.timerDate,
463
442
  ]);
464
443
 
465
444
  if (configuration.magic_background) {
@@ -120,8 +120,8 @@ const Styles = {
120
120
  (startComponentsAnimation && isActiveGesture) || docked
121
121
  ? 0
122
122
  : isTablet
123
- ? 24
124
- : 10,
123
+ ? 24
124
+ : 10,
125
125
  }),
126
126
 
127
127
  paddingHorizontal: {
@@ -37,8 +37,8 @@ export const playbackButton = ({
37
37
  const icon = playerState.isPaused
38
38
  ? "play"
39
39
  : playerState.isLive && liveButton
40
- ? "stop"
41
- : "pause";
40
+ ? "stop"
41
+ : "pause";
42
42
 
43
43
  return {
44
44
  size: playbackButtonSize(isTablet),
@@ -0,0 +1,119 @@
1
+ import { BehaviorSubject } from "rxjs";
2
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
3
+ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
4
+ import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
5
+ import { hasDatePassed, NAMESPACE } from "./utils";
6
+
7
+ const { log_debug, log_error } = createLogger({
8
+ subsystem: "Player",
9
+ category: "SleepTimerManager",
10
+ });
11
+
12
+ export type SleepTimer = {
13
+ label: string;
14
+ // interval in minutes for UI at the moment when timer was first started
15
+ value: number;
16
+ };
17
+
18
+ export const SLEEP_TIMER_OFF: SleepTimer = {
19
+ label: "playback_sleep_off_label",
20
+ value: 0,
21
+ };
22
+
23
+ export class SleepTimerState {
24
+ constructor(
25
+ public timer: SleepTimer,
26
+ public timerDate: number
27
+ ) {}
28
+ }
29
+
30
+ const SLEEP_PREFERENCE_KEY = "sleep";
31
+
32
+ export class SleepTimerController {
33
+ private sleepTimerStateSubject = new BehaviorSubject<SleepTimerState>(
34
+ new SleepTimerState(SLEEP_TIMER_OFF, 0)
35
+ );
36
+
37
+ constructor(private player: Player) {}
38
+
39
+ get sleepTimerState$() {
40
+ return this.sleepTimerStateSubject.asObservable();
41
+ }
42
+
43
+ private async scheduleSleep(sleepDate): Promise<boolean> {
44
+ log_debug(`Setting sleep interval to ${sleepDate}`);
45
+
46
+ try {
47
+ this.player.cancelSleepTimer?.();
48
+ this.player.startSleepTimer?.(sleepDate);
49
+
50
+ return true;
51
+ } catch (e) {
52
+ log_error("Failed to start sleep timer", { error: e.message });
53
+
54
+ return false;
55
+ }
56
+ }
57
+
58
+ async setSleepTimer(item: SleepTimer) {
59
+ // User has selected Off state
60
+ if (item.value === 0) {
61
+ log_debug("Cancelling sleep timer");
62
+ this.player.cancelSleepTimer?.();
63
+
64
+ return this.onTimerExpired();
65
+ }
66
+
67
+ log_debug(`Starting sleep timer in ${item.value} minutes`);
68
+
69
+ const futureSleepDate = Date.now() + item.value * 60000;
70
+
71
+ if (await this.scheduleSleep(futureSleepDate)) {
72
+ await localStorage.setItem(
73
+ SLEEP_PREFERENCE_KEY,
74
+ { ...item, futureSleepDate },
75
+ NAMESPACE
76
+ );
77
+
78
+ this.sleepTimerStateSubject.next(
79
+ new SleepTimerState(item, futureSleepDate)
80
+ );
81
+ }
82
+ }
83
+
84
+ async onTimerExpired() {
85
+ await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
86
+
87
+ this.sleepTimerStateSubject.next(new SleepTimerState(SLEEP_TIMER_OFF, 0));
88
+ }
89
+
90
+ async loadSleep() {
91
+ const sleep = await localStorage.getItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
92
+
93
+ if (!sleep) return;
94
+
95
+ const { futureSleepDate, ...rest } = sleep;
96
+
97
+ if (!futureSleepDate || hasDatePassed(futureSleepDate)) {
98
+ log_debug("Sleep date has already passed");
99
+ await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
100
+
101
+ return;
102
+ }
103
+
104
+ if (await this.scheduleSleep(futureSleepDate)) {
105
+ log_debug(`Sleep state restored, will go to sleep at ${futureSleepDate}`);
106
+
107
+ this.sleepTimerStateSubject.next(
108
+ new SleepTimerState(rest as SleepTimer, futureSleepDate)
109
+ );
110
+ }
111
+ }
112
+
113
+ // Will be called if user closed the player explicitly.
114
+ // TODO: check if it will be called on Android when we need.
115
+ // Probably we will have to handle it on native instead.
116
+ public static async onPlayerDestroy() {
117
+ await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
118
+ }
119
+ }
@@ -0,0 +1,52 @@
1
+ import { BehaviorSubject } from "rxjs";
2
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
3
+ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
4
+ import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
5
+ import { NAMESPACE } from "./utils";
6
+
7
+ const { log_debug } = createLogger({
8
+ subsystem: "Player",
9
+ category: "PlaybackSpeedManager",
10
+ });
11
+
12
+ export type PlaybackSpeed = {
13
+ asset: string;
14
+ value: number;
15
+ };
16
+
17
+ const SPEED_PREFERENCE_KEY = "speed";
18
+
19
+ export const DEFAULT_SPEED: PlaybackSpeed = {
20
+ asset: "speed_1",
21
+ value: 1.0,
22
+ };
23
+
24
+ // todo: should not be applied to live streams
25
+ export class SpeedController {
26
+ private playbackSpeedSubject = new BehaviorSubject<PlaybackSpeed>(
27
+ DEFAULT_SPEED
28
+ );
29
+
30
+ constructor(private player: Player) {}
31
+
32
+ get playbackSpeed$() {
33
+ return this.playbackSpeedSubject.asObservable();
34
+ }
35
+
36
+ async loadSpeed() {
37
+ const speed = await localStorage.getItem(SPEED_PREFERENCE_KEY, NAMESPACE);
38
+
39
+ // checking for value in case we will pull empty or broken object
40
+ if (speed && speed.value) {
41
+ this.playbackSpeedSubject.next(speed);
42
+ this.player.setPlaybackRate?.(speed.value);
43
+ log_debug(`Speed loaded: ${speed}`);
44
+ }
45
+ }
46
+
47
+ async setPlaybackSpeed(speed: PlaybackSpeed) {
48
+ await localStorage.setItem(SPEED_PREFERENCE_KEY, speed, NAMESPACE);
49
+ this.playbackSpeedSubject.next(speed);
50
+ this.player.setPlaybackRate?.(speed.value);
51
+ }
52
+ }
@@ -253,12 +253,7 @@ export default class VideoPlayer extends React.Component<
253
253
  };
254
254
 
255
255
  stopBackgroundPlayback = () => {
256
- if (
257
- this.isReactNativeMethodsSupported() &&
258
- RNPlayerManager?.[this.playerPluginId]?.stopBackgroundPlayback
259
- ) {
260
- RNPlayerManager?.[this.playerPluginId]?.stopBackgroundPlayback();
261
- }
256
+ RNPlayerManager?.[this.playerPluginId]?.stopBackgroundPlayback?.();
262
257
  };
263
258
 
264
259
  forward = (seekTime = SEEK_TIME) => {
@@ -923,8 +918,8 @@ export default class VideoPlayer extends React.Component<
923
918
  const playerContainerStyles = isApplePlatform()
924
919
  ? styles.playerContainerBlack
925
920
  : isTV() && isAudioItem
926
- ? styles.playerContainerTransparent
927
- : styles.playerContainerBlack;
921
+ ? styles.playerContainerTransparent
922
+ : styles.playerContainerBlack;
928
923
 
929
924
  const isInline = () => {
930
925
  if (isTV()) {
@@ -1000,6 +995,7 @@ export default class VideoPlayer extends React.Component<
1000
995
  ref={this._assignRoot}
1001
996
  {...nativeEvents}
1002
997
  {...nativeProps}
998
+ listener={this.props.listener}
1003
999
  />
1004
1000
  )}
1005
1001
  <AudioPlayerWrapper {...sharedWrapperViewProps} />