@applicaster/quick-brick-player 13.0.0-alpha.8490438700 → 13.0.0-alpha.8541129242

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-alpha.8490438700",
3
+ "version": "13.0.0-alpha.8541129242",
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": "13.0.0-rc.28",
40
- "@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.26",
41
- "@applicaster/zapp-react-native-tvos-app": "13.0.0-alpha.8490438700",
42
- "@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.8490438700",
43
- "@applicaster/zapp-react-native-utils": "13.0.0-alpha.8490438700",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-alpha.8541129242",
40
+ "@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.46",
41
+ "@applicaster/zapp-react-native-tvos-app": "13.0.0-alpha.8541129242",
42
+ "@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.8541129242",
43
+ "@applicaster/zapp-react-native-utils": "13.0.0-alpha.8541129242",
44
44
  "keymirror": "^0.1.1",
45
45
  "query-string": "7.1.3",
46
46
  "react-native-web-linear-gradient": "1.1.2",
@@ -64,9 +64,9 @@
64
64
  "@types/node": "*",
65
65
  "@types/react-native": "0.69.6",
66
66
  "immer": "*",
67
- "react": "17.0.2",
67
+ "react": "*",
68
68
  "react-hot-loader": "*",
69
- "react-native": "0.68.6",
69
+ "react-native": "*",
70
70
  "react-native-fs": "*",
71
71
  "react-native-gesture-handler": "*",
72
72
  "react-native-linear-gradient": "*",
@@ -55,6 +55,11 @@ const useMuteUnmuteListeners = (playerId, player, asset, setImageUri) =>
55
55
  return;
56
56
  }
57
57
 
58
+ // initial state setup - show correct mute/unmute icon based on current state
59
+ if (player?.playerState?.isReadyToPlay) {
60
+ setImageUri(player.getIsMuted() ? asset.active : asset.inactive);
61
+ }
62
+
58
63
  // active action = muted, inactive = unmuted
59
64
  return player.addListener({
60
65
  id: liveImageButtonsListenerKey,
@@ -73,10 +78,17 @@ const useMuteUnmuteListeners = (playerId, player, asset, setImageUri) =>
73
78
  setImageUri(player?.getIsMuted() ? asset.active : asset.inactive);
74
79
  },
75
80
  onPlayerClose: () => {
76
- setImageUri(null);
81
+ if (isCurrentPlayer(playerId)) {
82
+ setImageUri(null);
83
+ }
77
84
  },
78
85
  onVideoEnd: () => {
79
- setImageUri(null);
86
+ if (isCurrentPlayer(playerId)) {
87
+ setImageUri(null);
88
+ }
89
+ },
90
+ onPlayerResume: () => {
91
+ setImageUri(player?.getIsMuted() ? asset.active : asset.inactive);
80
92
  },
81
93
  },
82
94
  });
@@ -93,7 +105,7 @@ const styles = StyleSheet.create({
93
105
  },
94
106
  });
95
107
 
96
- export function AssetComponent(props: CellActionAssetComponentProps) {
108
+ function AssetImage(props: CellActionAssetComponentProps) {
97
109
  const { cellUUID: playerId, asset } = props;
98
110
  const [imageUri, setImageUri] = useState<Asset>(null);
99
111
 
@@ -108,3 +120,5 @@ export function AssetComponent(props: CellActionAssetComponentProps) {
108
120
 
109
121
  return <View />;
110
122
  }
123
+
124
+ export const AssetComponent = React.memo(AssetImage);
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { ViewStyle, View } from "react-native";
2
+ import { ViewStyle, View, Dimensions as ScreenDimensions } 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";
@@ -40,6 +40,7 @@ import {
40
40
  SLEEP_TIMER_OFF,
41
41
  } from "./SleepTimerManager";
42
42
  import { SpeedController, PlaybackSpeed, DEFAULT_SPEED } from "./SpeedManager";
43
+ import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
43
44
 
44
45
  const { log_debug } = createLogger({
45
46
  subsystem: "UIComponent",
@@ -78,8 +79,7 @@ type Props = {
78
79
  isTabletPortrait?: boolean;
79
80
  };
80
81
 
81
- export const defaultAspectRatioWidth = (height: number): number =>
82
- (height / 9) * 16;
82
+ const { width: SCREEN_WIDTH } = ScreenDimensions.get("screen");
83
83
 
84
84
  const Styles = {
85
85
  mainContainer: (style: ViewStyle) => {
@@ -105,7 +105,11 @@ const Styles = {
105
105
  height: 96,
106
106
  marginHorizontal: 24,
107
107
  },
108
- playerDetails: { marginTop: 60 },
108
+ playerDetails: {
109
+ marginTop: 60,
110
+ alignSelf: "center",
111
+ width: SCREEN_WIDTH - PADDING_HORIZONTAL * 2,
112
+ },
109
113
 
110
114
  linearGradient: {
111
115
  flex: 1,
@@ -328,8 +332,12 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
328
332
  onSleepSelect,
329
333
  ]);
330
334
 
335
+ // This method does not actually cancel the sleep timer
336
+ // (and should not to avoid race condition),
337
+ // it just performs the cleanup when timer expires
338
+ // TODO: rename it in code above
331
339
  const cancelSleepTimer = React.useCallback(() => {
332
- sleepTimerManager?.cancelSleepTimer();
340
+ sleepTimerManager?.onTimerExpired();
333
341
  }, [sleepTimerManager]);
334
342
 
335
343
  const onCloseVideoModal = React.useCallback(() => {
@@ -438,7 +446,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
438
446
  ]);
439
447
 
440
448
  if (configuration.magic_background) {
441
- const baseUrl = entry?.extensions?.audio_player_background_image ?? "";
449
+ const baseUrl = imageSrcFromMediaItem(entry, null);
442
450
 
443
451
  const queryParamName =
444
452
  configuration.audio_player_background_image_query || "width";
@@ -1,13 +1,14 @@
1
1
  import * as React from "react";
2
+ import { useEffect, useMemo, useState } from "react";
2
3
  import * as R from "ramda";
3
4
  import { View } from "react-native";
4
5
  import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
5
6
 
6
7
  import {
7
- ProgressBar,
8
8
  Controls,
9
- TransportInfo,
10
9
  CountDown,
10
+ ProgressBar,
11
+ TransportInfo,
11
12
  } from "@applicaster/quick-brick-mobile-transport-controls";
12
13
 
13
14
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
@@ -15,23 +16,22 @@ import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
15
16
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
16
17
  import {
17
18
  forwardButton,
19
+ PADDING_HORIZONTAL,
18
20
  playbackButton,
19
21
  rewindButton,
20
- skipToStartButton,
21
22
  skipToLiveButton,
22
- PADDING_HORIZONTAL,
23
- speedButton,
23
+ skipToStartButton,
24
24
  sleepButton,
25
+ speedButton,
25
26
  } from "./defaultLayoutsConts";
26
27
  import { AudioDescription } from "../AudioDescription";
27
28
  import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
28
29
  import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
29
30
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
30
- import { useEffect, useMemo, useState } from "react";
31
31
  import {
32
- useModalAnimationContext,
33
32
  AnimationComponent,
34
33
  ComponentAnimationType,
34
+ useModalAnimationContext,
35
35
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
36
36
  import DockedLayout from "./DockedLayout";
37
37
  import { isValidDate } from "../../Utils";
@@ -375,6 +375,7 @@ export default function DefaultLayout(props: LayoutProps) {
375
375
  >
376
376
  <PlayerImageBackground
377
377
  entry={entry}
378
+ docked={docked}
378
379
  style={Styles.backgroundImageContainer(dimensions, isTablet)}
379
380
  imageStyle={Styles.backgroundImageContainerImageStyle(
380
381
  isTablet,
@@ -405,7 +406,7 @@ export default function DefaultLayout(props: LayoutProps) {
405
406
  layoutState={layoutState}
406
407
  />
407
408
  <Separator />
408
- {needsToShowProgressBar && (
409
+ {needsToShowProgressBar ? (
409
410
  <View>
410
411
  <ProgressBar
411
412
  content={entry}
@@ -422,17 +423,17 @@ export default function DefaultLayout(props: LayoutProps) {
422
423
  onSkipLive={onSkipLive}
423
424
  />
424
425
 
425
- {showCounter && timeLeft >= 0 && (
426
+ {showCounter && timeLeft >= 0 ? (
426
427
  <CountDown
427
428
  timeLeft={timeLeft}
428
429
  value={value}
429
430
  title={sleepTitle}
430
431
  />
431
- )}
432
+ ) : null}
432
433
 
433
434
  <Separator />
434
435
  </View>
435
- )}
436
+ ) : null}
436
437
  <Controls
437
438
  value={value}
438
439
  visible={true}
@@ -9,18 +9,18 @@ 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
  import {
20
- useModalAnimationContext,
21
20
  AnimationComponent,
22
21
  ComponentAnimationType,
23
22
  PlayerAnimationStateEnum,
23
+ useModalAnimationContext,
24
24
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
25
25
 
26
26
  type Dimensions = {
@@ -245,18 +245,18 @@ export default function DockedLayout(props: LayoutProps) {
245
245
  ]}
246
246
  >
247
247
  {!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
- )}
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
+ ) : null}
260
260
 
261
261
  <View style={styles.content}>
262
262
  <View
@@ -40,94 +40,77 @@ export class SleepTimerController {
40
40
  return this.sleepTimerStateSubject.asObservable();
41
41
  }
42
42
 
43
- async cancelSleepTimer() {
44
- this.player.cancelSleepTimer?.();
43
+ private async scheduleSleep(sleepDate): Promise<boolean> {
44
+ log_debug(`Setting sleep interval to ${sleepDate}`);
45
45
 
46
- await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
47
-
48
- this.sleepTimerStateSubject.next(new SleepTimerState(SLEEP_TIMER_OFF, 0));
49
- }
50
-
51
- private async startSleepTimer(futureSleepDate: number) {
52
46
  try {
53
- log_debug(`Starting sleep timer at ${futureSleepDate}`);
54
47
  this.player.cancelSleepTimer?.();
55
- this.player.startSleepTimer?.(futureSleepDate);
48
+ this.player.startSleepTimer?.(sleepDate);
56
49
 
57
- return futureSleepDate;
50
+ return true;
58
51
  } catch (e) {
59
52
  log_error("Failed to start sleep timer", { error: e.message });
60
53
 
61
- return 0;
54
+ return false;
62
55
  }
63
56
  }
64
57
 
65
- private async handleSleep(timerValue: number, currentFutureSleepDate = null) {
66
- log_debug("Handling sleep interval", {
67
- timerValue,
68
- currentFutureSleepDate,
69
- });
70
-
71
- if (timerValue === 0) {
72
- await this.cancelSleepTimer();
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?.();
73
63
 
74
- return timerValue;
64
+ return this.onTimerExpired();
75
65
  }
76
66
 
77
- // starting a new timer
78
- if (currentFutureSleepDate == null) {
79
- log_debug(`Starting sleep timer in ${timerValue} minutes`);
80
- const futureSleepDate = Date.now() + timerValue * 60000;
67
+ log_debug(`Starting sleep timer in ${item.value} minutes`);
81
68
 
82
- return this.startSleepTimer(futureSleepDate);
83
- }
69
+ const futureSleepDate = Date.now() + item.value * 60000;
84
70
 
85
- // restoring previous timer (leftover time interval)
86
- if (hasDatePassed(currentFutureSleepDate)) {
87
- log_debug("Sleep date has already passed");
88
- await this.cancelSleepTimer();
71
+ if (await this.scheduleSleep(futureSleepDate)) {
72
+ await localStorage.setItem(
73
+ SLEEP_PREFERENCE_KEY,
74
+ { ...item, futureSleepDate },
75
+ NAMESPACE
76
+ );
89
77
 
90
- return 0;
78
+ this.sleepTimerStateSubject.next(
79
+ new SleepTimerState(item, futureSleepDate)
80
+ );
91
81
  }
82
+ }
92
83
 
93
- log_debug(`Starting sleep timer at ${timerValue}`);
84
+ async onTimerExpired() {
85
+ await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
94
86
 
95
- return this.startSleepTimer(currentFutureSleepDate);
87
+ this.sleepTimerStateSubject.next(new SleepTimerState(SLEEP_TIMER_OFF, 0));
96
88
  }
97
89
 
98
90
  async loadSleep() {
99
91
  const sleep = await localStorage.getItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
100
92
 
101
- if (sleep) {
102
- const { futureSleepDate, ...rest } = sleep;
93
+ if (!sleep) return;
103
94
 
104
- const sleepTimerDate = await this.handleSleep(
105
- sleep.value,
106
- futureSleepDate
107
- );
95
+ const { futureSleepDate, ...rest } = sleep;
108
96
 
109
- this.sleepTimerStateSubject.next(
110
- new SleepTimerState(rest as SleepTimer, sleepTimerDate)
111
- );
97
+ if (!futureSleepDate || hasDatePassed(futureSleepDate)) {
98
+ log_debug("Sleep date has already passed");
99
+ await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
112
100
 
113
- log_debug(`Sleep state restored, will go to sleep at ${futureSleepDate}`);
101
+ return;
114
102
  }
115
- }
116
-
117
- async setSleepTimer(item: SleepTimer) {
118
- const futureSleepDate = await this.handleSleep(item.value);
119
103
 
120
- await localStorage.setItem(
121
- SLEEP_PREFERENCE_KEY,
122
- { ...item, futureSleepDate },
123
- NAMESPACE
124
- );
104
+ if (await this.scheduleSleep(futureSleepDate)) {
105
+ log_debug(`Sleep state restored, will go to sleep at ${futureSleepDate}`);
125
106
 
126
- this.sleepTimerStateSubject.next(
127
- new SleepTimerState(item, futureSleepDate)
128
- );
107
+ this.sleepTimerStateSubject.next(
108
+ new SleepTimerState(rest as SleepTimer, futureSleepDate)
109
+ );
110
+ }
129
111
  }
130
112
 
113
+ // Will be called if user closed the player explicitly.
131
114
  // TODO: check if it will be called on Android when we need.
132
115
  // Probably we will have to handle it on native instead.
133
116
  public static async onPlayerDestroy() {
@@ -21,6 +21,7 @@ export const DEFAULT_SPEED: PlaybackSpeed = {
21
21
  value: 1.0,
22
22
  };
23
23
 
24
+ // todo: should not be applied to live streams
24
25
  export class SpeedController {
25
26
  private playbackSpeedSubject = new BehaviorSubject<PlaybackSpeed>(
26
27
  DEFAULT_SPEED
@@ -806,7 +806,6 @@ export default class VideoPlayer extends React.Component<
806
806
  nowPlayingEnabled,
807
807
  paused,
808
808
  seek,
809
- rate,
810
809
  textTrackId,
811
810
  liveSeekingEnabled,
812
811
  liveCatchUpEnabled,
@@ -817,7 +816,14 @@ export default class VideoPlayer extends React.Component<
817
816
  accessibilityProps: getAllAccessibilityProps(
818
817
  this.getPluginConfiguration()
819
818
  ),
820
- }; // rate temporary removed, because of bug with subtitles
819
+ };
820
+
821
+ if (!isAppleTV()) {
822
+ // TODO: Move to RN method and remove from props.
823
+ // Causes tvOS bug: native player passes rate on fast seek,
824
+ // RN returns it and it breaks playback.
825
+ nativeProps.rate = rate;
826
+ }
821
827
 
822
828
  if (
823
829
  this.isReactNativeMethodsSupported() &&
@@ -990,14 +996,14 @@ export default class VideoPlayer extends React.Component<
990
996
  const renderMobilePlayer = () => {
991
997
  return isFullScreenAudioPlayer && isAudioItem ? (
992
998
  <View style={containerStyle}>
993
- {(!castAction?.state?.connected || supportNativeCast) && (
999
+ {!castAction?.state?.connected || supportNativeCast ? (
994
1000
  <this.props.PlayerComponent
995
1001
  ref={this._assignRoot}
996
1002
  {...nativeEvents}
997
1003
  {...nativeProps}
998
1004
  listener={this.props.listener}
999
1005
  />
1000
- )}
1006
+ ) : null}
1001
1007
  <AudioPlayerWrapper {...sharedWrapperViewProps} />
1002
1008
  </View>
1003
1009
  ) : (
@@ -1012,7 +1018,7 @@ export default class VideoPlayer extends React.Component<
1012
1018
  return (
1013
1019
  <View style={styles.container}>
1014
1020
  <View style={[playerContainerStyles, playerDimensions]}>
1015
- {isAudioItem && (
1021
+ {isAudioItem ? (
1016
1022
  <AnimationComponent
1017
1023
  animationType={ComponentAnimationType.player}
1018
1024
  additionalData={{
@@ -1031,18 +1037,18 @@ export default class VideoPlayer extends React.Component<
1031
1037
  plugin_configuration={this.getPluginConfiguration()}
1032
1038
  />
1033
1039
  </AnimationComponent>
1034
- )}
1040
+ ) : null}
1035
1041
 
1036
- {shouldRenderBackground && (
1042
+ {shouldRenderBackground ? (
1037
1043
  <PlayerImageBackground
1038
1044
  imageKey={backgroundImageKey}
1039
1045
  configuration={this.getPluginConfiguration()}
1040
1046
  entry={entry}
1041
1047
  style={getBackgroundImageStyle(playerDimensions)}
1042
1048
  />
1043
- )}
1049
+ ) : null}
1044
1050
 
1045
- {(!castAction?.state?.connected || supportNativeCast) && (
1051
+ {!castAction?.state?.connected || supportNativeCast ? (
1046
1052
  <AnimationComponent
1047
1053
  animationType={ComponentAnimationType.player}
1048
1054
  additionalData={playerDimensions}
@@ -1064,7 +1070,7 @@ export default class VideoPlayer extends React.Component<
1064
1070
  {this.childrenWithPlayNext()}
1065
1071
  </this.props.PlayerComponent>
1066
1072
  </AnimationComponent>
1067
- )}
1073
+ ) : null}
1068
1074
  </View>
1069
1075
 
1070
1076
  {renderTransportControls(playerDimensions)}