@applicaster/quick-brick-player 13.0.0-rc.97 → 13.0.0-rc.99

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.97",
3
+ "version": "13.0.0-rc.99",
4
4
  "description": "Quick Brick Player",
5
5
  "main": "./src/index.ts",
6
6
  "types": "index.d.ts",
@@ -35,11 +35,11 @@
35
35
  },
36
36
  "homepage": "https://github.com/applicaster/quickbrick#readme",
37
37
  "dependencies": {
38
- "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.95",
38
+ "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.99",
39
39
  "@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.56",
40
- "@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.97",
41
- "@applicaster/zapp-react-native-ui-components": "13.0.0-rc.97",
42
- "@applicaster/zapp-react-native-utils": "13.0.0-rc.97",
40
+ "@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.99",
41
+ "@applicaster/zapp-react-native-ui-components": "13.0.0-rc.99",
42
+ "@applicaster/zapp-react-native-utils": "13.0.0-rc.99",
43
43
  "query-string": "7.1.3",
44
44
  "react-native-web-linear-gradient": "1.1.2",
45
45
  "shaka-player": "4.3.5",
@@ -82,7 +82,7 @@ export const AudioDescription = (props: AudioDescriptionProps) => {
82
82
 
83
83
  return (
84
84
  <>
85
- <Text style={titleStyles(value, prefix)} numberOfLines={1}>
85
+ <Text style={titleStyles(value, prefix)} numberOfLines={2}>
86
86
  {title}
87
87
  </Text>
88
88
  <Text style={summaryStyles(value, prefix)} numberOfLines={1}>
@@ -48,7 +48,7 @@ import { SpeedController, PlaybackSpeed, DEFAULT_SPEED } from "./SpeedManager";
48
48
  import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
49
49
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
50
50
  import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
51
- import { sleepTimerOptions } from "../Const/sleepTimerOptions";
51
+ import { getSleepTimerOptions } from "../Const/sleepTimerOptions";
52
52
  import { speedOptions } from "../Const/speedOptions";
53
53
 
54
54
  const { log_debug } = createLogger({
@@ -278,12 +278,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
278
278
  const onSleepButtonPress = React.useCallback(() => {
279
279
  openBottomSheetModal({
280
280
  modalBottomSheetContentProps: {
281
- items: [
282
- {
283
- label: configuration["playback_sleep_off_label"],
284
- value: 0,
285
- },
286
- ].concat(sleepTimerOptions),
281
+ items: getSleepTimerOptions(configuration),
287
282
  current_selection: sleepTimerState.timer,
288
283
  onPress: onSleepSelect,
289
284
  title: configuration["playback_sleep_title"],
@@ -5,7 +5,6 @@ import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
5
5
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
6
6
  import {
7
7
  Controls as MobileTransportControls,
8
- CountDown,
9
8
  ProgressBar,
10
9
  } from "@applicaster/quick-brick-mobile-transport-controls";
11
10
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
@@ -39,19 +38,24 @@ const styles = StyleSheet.create({
39
38
  progressBar: {
40
39
  flex: 0,
41
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
+ },
42
55
  });
43
56
 
44
- const controlsStyles = ({
45
- isTablet,
46
- isLiveShowFullControls,
47
- }: {
48
- isTablet: boolean;
49
- isLiveShowFullControls: boolean;
50
- }) => ({
51
- height: isTablet ? undefined : 50,
52
- marginHorizontal: isTablet ? undefined : 10,
53
- justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
54
- });
57
+ const getControlJustifyContent = (countOfButtons: number) =>
58
+ countOfButtons <= 1 ? "center" : "space-between";
55
59
 
56
60
  type Props = {
57
61
  entry: ZappEntry;
@@ -117,14 +121,19 @@ export const Controls = (props: Props) => {
117
121
  showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
118
122
  }
119
123
 
120
- const sleepTitle = value("playback_sleep_countdown_label");
121
-
122
124
  const [timeLeft, setTimeLeft] = React.useState(
123
125
  sleepTimerDate !== 0 ? sleepTimerDate - Date.now() : 0
124
126
  );
125
127
 
126
128
  const showCounter = React.useMemo(() => sleepTimerDate > 0, [sleepTimerDate]);
127
129
 
130
+ const countDownOptions = React.useMemo(() => {
131
+ return {
132
+ showCounter: showCounter && timeLeft >= 0,
133
+ timeLeft,
134
+ };
135
+ }, [showCounter, timeLeft]);
136
+
128
137
  React.useEffect(() => {
129
138
  if (showCounter && sleepTimerDate !== 0) {
130
139
  setTimeLeft(sleepTimerDate - Date.now());
@@ -282,12 +291,12 @@ export const Controls = (props: Props) => {
282
291
  isDateBasedLiveContent={isDateBasedLiveContent}
283
292
  onSkipLive={onSkipLive}
284
293
  progressBarStyles={styles.progressBar}
294
+ countDownOptions={countDownOptions}
295
+ thumbStyles={styles.progressBarThumbStyles}
296
+ thumbStylesPressed={styles.progressBarThumbStyles_pressed}
297
+ trackStyles={styles.progressBarTrackStyles}
285
298
  />
286
299
 
287
- {showCounter && timeLeft >= 0 ? (
288
- <CountDown timeLeft={timeLeft} value={value} title={sleepTitle} />
289
- ) : null}
290
-
291
300
  <VerticalGutter />
292
301
  </>
293
302
  ) : null}
@@ -297,7 +306,9 @@ export const Controls = (props: Props) => {
297
306
  visible={true}
298
307
  keepAlive={null}
299
308
  buttons={controlButtons}
300
- style={controlsStyles({ isTablet, isLiveShowFullControls })}
309
+ style={{
310
+ justifyContent: getControlJustifyContent(controlButtons().length),
311
+ }}
301
312
  playerState={playerState}
302
313
  />
303
314
  </AnimationComponent>
@@ -1,14 +1,7 @@
1
- const rewindButtonSize = (isTablet: boolean): keyof ButtonSizeStyles =>
2
- isTablet ? "big" : "smallMargins";
3
-
4
- const playbackButtonSize = (isTablet: boolean): keyof ButtonSizeStyles =>
5
- isTablet ? "bigExtended" : "mediumExtended";
6
-
7
1
  const playbackButtonMargins = (
8
2
  isTablet: boolean,
9
3
  isLiveShowFullControls: boolean
10
- ): number =>
11
- isLiveShowFullControls ? (isTablet ? 65 : 10) : isTablet ? undefined : 40;
4
+ ): number => (isLiveShowFullControls ? (isTablet ? 65 : 10) : undefined);
12
5
 
13
6
  export const playbackButton = ({
14
7
  playerState,
@@ -30,7 +23,7 @@ export const playbackButton = ({
30
23
  : "pause";
31
24
 
32
25
  return {
33
- size: playbackButtonSize(isTablet),
26
+ size: "bigExtended",
34
27
  icon: playerState.isBuffering ? "buffering" : icon,
35
28
  preferredFocus: true,
36
29
  onPress,
@@ -52,10 +45,9 @@ type ButtonsByNameProps = ButtonsProps & { name?: string };
52
45
  const rewindButtonByName = ({
53
46
  name,
54
47
  onPress,
55
- isTablet,
56
48
  style,
57
49
  }: ButtonsByNameProps): ControlsButton => ({
58
- size: rewindButtonSize(isTablet),
50
+ size: "big",
59
51
  icon: name,
60
52
  onPress,
61
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
+ );
@@ -6,14 +6,19 @@ import {
6
6
  } from "react-native-safe-area-context";
7
7
  import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
8
 
9
- import { MOBILE } from "./const";
9
+ import { MOBILE, NAVBAR_HEIGHT } from "./const";
10
10
  import { TransportInfo } from "./TransportInfo";
11
11
  import { PlayerImage } from "./PlayerImage";
12
12
  import { Controls } from "./Controls";
13
13
 
14
- import { useImageSize, useTransportInfoHeight } from "./hooks";
14
+ import { useMobileLayoutImageSize, useTransportInfoHeight } from "./hooks";
15
15
  import { DockedControls } from "./DockedControls";
16
- import { withDebug } from "./debug";
16
+ import { withDebug, DEBUG } from "./debug";
17
+ import {
18
+ LeftDebugSquare,
19
+ RightDebugSquare,
20
+ BottomDebugSquare,
21
+ } from "./Debug/index";
17
22
 
18
23
  import { Props } from "./types";
19
24
 
@@ -90,11 +95,27 @@ export function MobileLayout({
90
95
  const { height: screenHeight } = useSafeAreaFrame();
91
96
  const { progressBarHeight } = useModalAnimationContext();
92
97
 
93
- const { imageSize, onLayout } = useImageSize({ isPortraitMode: true });
98
+ const { imageSize } = useMobileLayoutImageSize();
94
99
 
95
100
  const { height: transportInfoHeight, onLayout: onTransportInfoLayout } =
96
101
  useTransportInfoHeight();
97
102
 
103
+ const controlsContainerHeight = React.useMemo(() => {
104
+ return (
105
+ screenHeight -
106
+ topInset -
107
+ imageSize -
108
+ NAVBAR_HEIGHT -
109
+ MOBILE.MARGIN_BOTTOM -
110
+ MOBILE.MARGIN_TOP -
111
+ bottomInset
112
+ );
113
+ }, [screenHeight, topInset, imageSize, bottomInset]);
114
+
115
+ const verticalOffsetForImage = React.useMemo(() => {
116
+ return transportInfoHeight + MOBILE.MARGIN_TOP - progressBarHeight;
117
+ }, [transportInfoHeight, progressBarHeight]);
118
+
98
119
  return (
99
120
  <View
100
121
  style={[
@@ -107,6 +128,10 @@ export function MobileLayout({
107
128
  }),
108
129
  ]}
109
130
  >
131
+ {DEBUG ? <LeftDebugSquare /> : null}
132
+ {DEBUG ? <RightDebugSquare /> : null}
133
+ {DEBUG ? <BottomDebugSquare /> : null}
134
+
110
135
  {/* TransportInfo */}
111
136
  <TransportInfo
112
137
  entry={entry}
@@ -139,7 +164,6 @@ export function MobileLayout({
139
164
  }),
140
165
  },
141
166
  ]}
142
- onLayout={onLayout}
143
167
  >
144
168
  <PlayerImage
145
169
  entry={entry}
@@ -155,20 +179,15 @@ export function MobileLayout({
155
179
  summary={summary}
156
180
  docked={docked}
157
181
  imageWidth={imageSize}
158
- verticalOffset={
159
- transportInfoHeight + MOBILE.MARGIN_TOP - progressBarHeight
160
- }
182
+ verticalOffset={verticalOffsetForImage}
161
183
  />
162
184
  </View>
163
185
  {/* PlayerImage */}
164
186
 
165
187
  <View
166
- style={[
167
- styles.flex,
168
- {
169
- marginBottom: MOBILE.MARGIN_BOTTOM,
170
- },
171
- ]}
188
+ style={{
189
+ height: controlsContainerHeight,
190
+ }}
172
191
  >
173
192
  <Controls
174
193
  entry={entry}
@@ -12,7 +12,7 @@ import { TransportInfo } from "./TransportInfo";
12
12
  import { PlayerImage } from "./PlayerImage";
13
13
  import { Controls } from "./Controls";
14
14
 
15
- import { useImageSize, useTransportInfoHeight } from "./hooks";
15
+ import { useTabletLayoutImageSize, useTransportInfoHeight } from "./hooks";
16
16
  import { DockedControls } from "./DockedControls";
17
17
  import { withDebug } from "./debug";
18
18
 
@@ -104,7 +104,9 @@ export function TabletLandscapeLayout({
104
104
  const { height: screenHeight } = useSafeAreaFrame();
105
105
  const { progressBarHeight } = useModalAnimationContext();
106
106
 
107
- const { imageSize, onLayout } = useImageSize({ isPortraitMode: false });
107
+ const { imageSize, onLayout } = useTabletLayoutImageSize({
108
+ isPortraitMode: false,
109
+ });
108
110
 
109
111
  const { height: transportInfoHeight, onLayout: onTransportInfoLayout } =
110
112
  useTransportInfoHeight();
@@ -14,7 +14,7 @@ import { TransportInfo } from "./TransportInfo";
14
14
  import { PlayerImage } from "./PlayerImage";
15
15
  import { Controls } from "./Controls";
16
16
 
17
- import { useImageSize } from "./hooks";
17
+ import { useTabletLayoutImageSize } from "./hooks";
18
18
  import { DockedControls } from "./DockedControls";
19
19
  import { VerticalGutter } from "./VerticalGutter";
20
20
 
@@ -36,7 +36,7 @@ const styles = StyleSheet.create({
36
36
 
37
37
  fillContainer: {
38
38
  ...StyleSheet.absoluteFillObject,
39
-
39
+ alignItems: "center",
40
40
  ...withDebug({
41
41
  borderWidth: 2,
42
42
  borderColor: "red",
@@ -104,7 +104,7 @@ export function TabletPortraitLayout({
104
104
  imageSize,
105
105
  offsetY: topOffset,
106
106
  onLayout,
107
- } = useImageSize({ isPortraitMode: true });
107
+ } = useTabletLayoutImageSize({ isPortraitMode: true });
108
108
 
109
109
  return (
110
110
  <View
@@ -12,14 +12,23 @@ import {
12
12
  import { toPositiveNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
13
13
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
14
14
 
15
- import { TABLET_LANDSCAPE } from "../const";
15
+ import { TABLET_LANDSCAPE, NAVBAR_HEIGHT } from "../const";
16
16
  import { withDebug } from "../debug";
17
17
 
18
18
  const styles = StyleSheet.create({
19
19
  container: {
20
+ height: NAVBAR_HEIGHT,
21
+ justifyContent: "center",
22
+ },
23
+ animatedContainer: {
20
24
  width: "100%",
21
25
  alignItems: "center",
22
26
  justifyContent: "space-between",
27
+
28
+ ...withDebug({
29
+ borderWidth: 2,
30
+ borderColor: "yellow",
31
+ }),
23
32
  },
24
33
  });
25
34
 
@@ -74,19 +83,22 @@ export const TransportInfo = ({
74
83
 
75
84
  return (
76
85
  <View
77
- style={{
78
- marginBottom: applyMarginBottom({ isTablet, marginBottom }),
86
+ style={[
87
+ styles.container,
88
+ {
89
+ marginBottom: applyMarginBottom({ isTablet, marginBottom }),
79
90
 
80
- ...withDebug({
81
- borderWidth: 2,
82
- borderColor: "red",
83
- }),
84
- }}
91
+ ...withDebug({
92
+ borderWidth: 2,
93
+ borderColor: "red",
94
+ }),
95
+ },
96
+ ]}
85
97
  onLayout={handleLayout}
86
98
  >
87
99
  <AnimationComponent
88
100
  animationType={ComponentAnimationType.componentFade}
89
- style={styles.container}
101
+ style={styles.animatedContainer}
90
102
  >
91
103
  <MobileTransportInfo
92
104
  content={entry}
@@ -18,3 +18,5 @@ export const MOBILE = {
18
18
  MARGIN_TOP: 10,
19
19
  MIN_HEIGHT: 458,
20
20
  };
21
+
22
+ export const NAVBAR_HEIGHT = 60;
@@ -1,5 +1,5 @@
1
1
  // use this variable to activate borders on AudioPlayer. It will help you to fix layout if needed.
2
- const DEBUG = false;
2
+ export const DEBUG = false;
3
3
 
4
4
  export const withDebug = (style) => {
5
5
  return DEBUG ? style : {};
@@ -1,3 +1,5 @@
1
- export { useImageSize } from "./useImageSize";
1
+ export { useTabletLayoutImageSize } from "./useTabletLayoutImageSize";
2
+
3
+ export { useMobileLayoutImageSize } from "./useMobileLayoutImageSize";
2
4
 
3
5
  export { useTransportInfoHeight } from "./useTransportInfoHeight";
@@ -0,0 +1,14 @@
1
+ import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
2
+ import { MOBILE } from "../const";
3
+
4
+ type Return = {
5
+ imageSize: Option<number>;
6
+ };
7
+
8
+ export const useMobileLayoutImageSize = (): Return => {
9
+ const { width } = useDimensions("screen");
10
+
11
+ return {
12
+ imageSize: width - 2 * MOBILE.MARGIN_HORIZONTAL,
13
+ };
14
+ };
@@ -3,9 +3,11 @@ import { LayoutChangeEvent } from "react-native";
3
3
 
4
4
  import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
5
5
  import { Subject } from "rxjs";
6
- import { take, last } from "rxjs/operators";
6
+ import { first, debounceTime, filter } from "rxjs/operators";
7
7
  import { useRefWithInitialValue } from "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue";
8
8
 
9
+ const TIMEOUT = 200; // ms
10
+
9
11
  type Layout = {
10
12
  x: number;
11
13
  y: number;
@@ -36,7 +38,7 @@ type Return = {
36
38
  onLayout: (event: LayoutChangeEvent) => void;
37
39
  };
38
40
 
39
- export const useImageSize = ({ isPortraitMode }: Props): Return => {
41
+ export const useTabletLayoutImageSize = ({ isPortraitMode }: Props): Return => {
40
42
  const [imageSize, setImageSize] = React.useState(undefined);
41
43
  const [offsetY, setOffsetY] = React.useState(undefined);
42
44
 
@@ -45,7 +47,7 @@ export const useImageSize = ({ isPortraitMode }: Props): Return => {
45
47
  React.useEffect(() => {
46
48
  const subscription = layoutRef.current.layoutChange$
47
49
  // for landscape layout we need to wait the second layout change in order to get proper size of image
48
- .pipe(take(isPortraitMode ? 1 : 2), last())
50
+ .pipe(debounceTime(TIMEOUT), first())
49
51
  .subscribe({
50
52
  next: (layout: Layout) => {
51
53
  const size = isPortraitMode
@@ -63,8 +65,11 @@ export const useImageSize = ({ isPortraitMode }: Props): Return => {
63
65
 
64
66
  React.useEffect(() => {
65
67
  const subscription = layoutRef.current.layoutChange$
66
- // wait the second layout change in order to get proper offsetY
67
- .pipe(take(2), last())
68
+ .pipe(
69
+ filter((layout: Layout) => layout.y > 0),
70
+ debounceTime(TIMEOUT),
71
+ first()
72
+ )
68
73
  .subscribe({
69
74
  next: (layout: Layout) => {
70
75
  setOffsetY(layout.y);
@@ -1,10 +1,39 @@
1
- export const sleepTimerOptions = [
2
- // { label: "End of episode", value: "episode" },
3
- { label: "5 minutes", value: 5 },
4
- { label: "10 minutes", value: 10 },
5
- { label: "15 minutes", value: 15 },
6
- { label: "30 minutes", value: 30 },
7
- { label: "45 minutes", value: 45 },
8
- { label: "1 hour", value: 60 },
9
- { label: "2 hours", value: 120 },
10
- ];
1
+ import { toDayJSLocaleMap } from "@applicaster/zapp-react-native-utils/appUtils/localizationsHelper";
2
+ import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
3
+ import { getUILanguage } from "@applicaster/zapp-react-native-utils/localizationUtils";
4
+
5
+ const createTimerOptions = (value) => {
6
+ let label = "";
7
+
8
+ const str = dayjs
9
+ .duration(value, "minute")
10
+ .locale(toDayJSLocaleMap(getUILanguage()))
11
+ .humanize();
12
+
13
+ if (value === 60) {
14
+ /** Skipping prefix "an"/"un"/"una" for 1 hour */
15
+
16
+ if (str.includes(" ")) {
17
+ label = `1 ${str.split(" ")[1]}`; // Combine "1" with second part of the string
18
+ } else {
19
+ label = `1 ${str}`; // Use dayjs provided translation
20
+ }
21
+ } else {
22
+ label = str;
23
+ }
24
+
25
+ return {
26
+ label,
27
+ value,
28
+ };
29
+ };
30
+
31
+ export const getSleepTimerOptions = (configuration) => {
32
+ return [
33
+ {
34
+ label: configuration["playback_sleep_off_label"],
35
+ value: 0,
36
+ },
37
+ ...[5, 10, 15, 30, 45, 60, 120].map(createTimerOptions),
38
+ ];
39
+ };