@applicaster/quick-brick-player 14.0.0-alpha.5333112458 → 14.0.0-alpha.5365702091

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": "14.0.0-alpha.5333112458",
3
+ "version": "14.0.0-alpha.5365702091",
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": "14.0.0-alpha.5333112458",
39
- "@applicaster/quick-brick-tv-transport-controls": "14.0.0-alpha.5333112458",
40
- "@applicaster/zapp-react-native-tvos-app": "14.0.0-alpha.5333112458",
41
- "@applicaster/zapp-react-native-ui-components": "14.0.0-alpha.5333112458",
42
- "@applicaster/zapp-react-native-utils": "14.0.0-alpha.5333112458",
38
+ "@applicaster/quick-brick-mobile-transport-controls": "14.0.0-rc.56",
39
+ "@applicaster/quick-brick-tv-transport-controls": "14.0.0-rc.60",
40
+ "@applicaster/zapp-react-native-tvos-app": "14.0.0-alpha.5365702091",
41
+ "@applicaster/zapp-react-native-ui-components": "14.0.0-alpha.5365702091",
42
+ "@applicaster/zapp-react-native-utils": "14.0.0-alpha.5365702091",
43
43
  "query-string": "7.1.3",
44
44
  "shaka-player": "4.3.5",
45
45
  "typeface-montserrat": "^0.0.54",
@@ -57,12 +57,10 @@
57
57
  "@applicaster/zapp-react-native-tvos-ui-components": "*",
58
58
  "@babel/runtime": "*",
59
59
  "@react-native-community/netinfo": "*",
60
- "immer": "*",
61
60
  "react": "*",
62
61
  "react-native": "*",
63
62
  "react-native-fs": "*",
64
63
  "react-native-linear-gradient": "*",
65
- "react-native-safe-area-context": "*",
66
64
  "react-native-svg": "*",
67
65
  "react-native-webview": "*",
68
66
  "uglify-js": "*",
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { StyleSheet } from "react-native";
2
+ import { StyleSheet, View } from "react-native";
3
3
 
4
4
  import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
5
5
  import {
@@ -12,11 +12,6 @@ import {
12
12
  } from "@applicaster/quick-brick-mobile-transport-controls";
13
13
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
14
14
 
15
- import {
16
- AnimationComponent,
17
- ComponentAnimationType,
18
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
19
-
20
15
  import { AudioDescription } from "../../AudioDescription";
21
16
  import { isValidDate } from "../../../Utils";
22
17
  import { VerticalGutter } from "./VerticalGutter";
@@ -103,8 +98,6 @@ export const Controls = (props: Props) => {
103
98
  onSkipLive,
104
99
  onSpeedButtonPress,
105
100
  maxWidth = 320,
106
-
107
- docked,
108
101
  } = props;
109
102
 
110
103
  const configuration = useZStore("playerConfiguration");
@@ -229,15 +222,8 @@ export const Controls = (props: Props) => {
229
222
  isLiveShowFullControls,
230
223
  ]);
231
224
 
232
- if (docked) {
233
- return null;
234
- }
235
-
236
225
  return (
237
- <AnimationComponent
238
- animationType={ComponentAnimationType.componentFade}
239
- style={isTablet ? styles.nonFlex : styles.flex}
240
- >
226
+ <View style={isTablet ? styles.nonFlex : styles.flex}>
241
227
  <VerticalGutter />
242
228
 
243
229
  <AudioDescription
@@ -257,7 +243,11 @@ export const Controls = (props: Props) => {
257
243
  content={entry}
258
244
  value={value}
259
245
  visible
260
- layoutState={layoutState}
246
+ layoutState={{
247
+ ...layoutState,
248
+ docked: false, // always use non-docked layout for audio (to show time labels
249
+ inline: true, // always use inline layout for audio (to show time labels)
250
+ }}
261
251
  onPlayerSeek={onPlayerSeek}
262
252
  playerState={playerState}
263
253
  disableFullscreen
@@ -286,6 +276,6 @@ export const Controls = (props: Props) => {
286
276
  }}
287
277
  playerState={playerState}
288
278
  />
289
- </AnimationComponent>
279
+ </View>
290
280
  );
291
281
  };
@@ -18,12 +18,15 @@ import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Compo
18
18
 
19
19
  import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
20
20
  import { useSafeAreaInsets } from "react-native-safe-area-context";
21
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
21
22
  import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight";
22
23
  import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
23
24
  import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
24
25
  import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
25
26
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
26
27
  import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
28
+ import { isMenuVisible } from "@applicaster/zapp-react-native-ui-components/Components/Screen/navigationHandler";
29
+ import { usePlugins } from "@applicaster/zapp-react-native-redux";
27
30
 
28
31
  const bottomTabBarHeight = getTabBarHeight();
29
32
 
@@ -172,13 +175,20 @@ export const DockedControls = (props: Props) => {
172
175
  playerManager.close();
173
176
  }, []);
174
177
 
178
+ const { currentRoute, screenData } = useNavigation();
179
+
180
+ const plugins = usePlugins();
181
+ const menuVisible = isMenuVisible(currentRoute, screenData, plugins);
182
+
175
183
  const { minimised_height: minimisedHeight } = useConfiguration();
176
184
 
177
185
  const configuration = useZStore("playerConfiguration")();
178
186
  const playerState = usePlayerState("shared-player-wrapper-docked");
179
187
 
180
- const getValue = (key: string, stylesObj: {}) =>
181
- R.propOr(null, key, stylesObj);
188
+ const getValue = React.useCallback(
189
+ (key: string, stylesObj: {}) => R.propOr(null, key, stylesObj),
190
+ []
191
+ );
182
192
 
183
193
  const value = React.useCallback(
184
194
  (key: string) => {
@@ -198,7 +208,7 @@ export const DockedControls = (props: Props) => {
198
208
 
199
209
  return retVal;
200
210
  },
201
- [...Object.values(configuration), playerState]
211
+ [...Object.values(configuration), playerState.seekableDuration, getValue]
202
212
  );
203
213
 
204
214
  const { title, summary } = useTitleSummaryOverlay(
@@ -216,89 +226,94 @@ export const DockedControls = (props: Props) => {
216
226
  const insets = useSafeAreaInsets();
217
227
 
218
228
  return (
219
- <View
220
- style={[
221
- styles.container,
222
- {
223
- height: minimisedHeight + bottomTabBarHeight + insets.bottom,
224
- },
225
- ]}
226
- >
227
- {!playerState.isLive ? (
228
- <ProgressBar
229
- name={"shared-docked-layout"}
230
- content={entry}
231
- value={value}
232
- visible
233
- layoutState={layoutState}
234
- onPlayerSeek={onPlayerSeek}
235
- playerState={playerState}
236
- startComponentsAnimation={noop}
237
- docked
238
- />
239
- ) : null}
229
+ <>
230
+ <View
231
+ style={[
232
+ styles.container,
233
+ {
234
+ height: minimisedHeight,
235
+ maxHeight: minimisedHeight,
236
+ },
237
+ ]}
238
+ >
239
+ {!playerState.isLive ? (
240
+ <ProgressBar
241
+ name={"shared-docked-layout"}
242
+ content={entry}
243
+ value={value}
244
+ visible
245
+ layoutState={layoutState}
246
+ onPlayerSeek={onPlayerSeek}
247
+ playerState={playerState}
248
+ startComponentsAnimation={noop}
249
+ docked
250
+ />
251
+ ) : null}
240
252
 
241
- <View style={styles.content}>
242
- <View style={styles.touchableArea}>
243
- {isActiveGesture || layoutState.docked ? (
244
- <View style={{ aspectRatio: aspectRatio, height: minimisedHeight }}>
245
- {ImageComponent || null}
246
- </View>
247
- ) : (
253
+ <View style={styles.content}>
254
+ <View style={styles.touchableArea}>
255
+ {isActiveGesture || layoutState.docked ? (
256
+ <View
257
+ style={{ aspectRatio: aspectRatio, height: minimisedHeight }}
258
+ >
259
+ {ImageComponent || null}
260
+ </View>
261
+ ) : (
262
+ <View
263
+ style={playerDimensionsStyle(
264
+ minimisedHeight,
265
+ isActiveGesture || layoutState.docked
266
+ )}
267
+ />
268
+ )}
248
269
  <View
249
- style={playerDimensionsStyle(
250
- minimisedHeight,
251
- isActiveGesture || layoutState.docked
252
- )}
253
- />
254
- )}
270
+ testID="content-info"
271
+ style={[
272
+ styles.contentInfo,
273
+ { backgroundColor: dockedBackgroundColor },
274
+ ]}
275
+ >
276
+ <ContentInfo
277
+ content={{ ...entry, title, summary }}
278
+ value={value}
279
+ docked
280
+ />
281
+ </View>
282
+ </View>
255
283
  <View
256
- testID="content-info"
257
284
  style={[
258
- styles.contentInfo,
285
+ isTablet
286
+ ? styles.controlsContainerForTablet
287
+ : styles.controlsContainerForMobile,
259
288
  { backgroundColor: dockedBackgroundColor },
260
289
  ]}
261
290
  >
262
- <ContentInfo
263
- content={{ ...entry, title, summary }}
291
+ <Controls
292
+ value={value}
293
+ visible
294
+ buttons={R.partial(controlButtons, [
295
+ playerState.isLive && liveButton,
296
+ ])}
297
+ style={styles.playPauseButton}
298
+ playNextData={playNextData}
299
+ playerState={playerState}
300
+ />
301
+ <Button
302
+ icon={"close_mini"}
303
+ size={"medium"}
264
304
  value={value}
265
- docked
305
+ onPress={onCloseVideoModal}
306
+ style={styles.buttons}
266
307
  />
267
308
  </View>
268
309
  </View>
269
- <View
270
- style={[
271
- isTablet
272
- ? styles.controlsContainerForTablet
273
- : styles.controlsContainerForMobile,
274
- { backgroundColor: dockedBackgroundColor },
275
- ]}
276
- >
277
- <Controls
278
- value={value}
279
- visible
280
- buttons={R.partial(controlButtons, [
281
- playerState.isLive && liveButton,
282
- ])}
283
- style={styles.playPauseButton}
284
- playNextData={playNextData}
285
- playerState={playerState}
286
- />
287
- <Button
288
- icon={"close_mini"}
289
- size={"medium"}
290
- value={value}
291
- onPress={onCloseVideoModal}
292
- style={styles.buttons}
293
- />
294
- </View>
295
310
  </View>
296
311
  <View
297
312
  style={{
298
- height: insets.bottom + bottomTabBarHeight,
313
+ height: insets.bottom + (menuVisible ? bottomTabBarHeight : 0),
299
314
  backgroundColor: dockedBackgroundColor,
300
315
  }}
301
316
  />
302
- </View>
317
+ </>
303
318
  );
304
319
  };
@@ -30,17 +30,12 @@ const directionStyles = (isLandscape: boolean): ViewStyle => {
30
30
  };
31
31
 
32
32
  type AnimatedModalProps = {
33
- enabled?: boolean;
34
33
  pip?: boolean;
35
- content?: (
36
- opacity: Animated.Value | Animated.AnimatedInterpolation
37
- ) => ReactElement;
38
- collapsedContent?: (
39
- opacity: Animated.Value | Animated.AnimatedInterpolation
40
- ) => ReactElement;
41
- extraContent?: (
42
- opacity: Animated.Value | Animated.AnimatedInterpolation
43
- ) => ReactElement;
34
+ fullscreen?: boolean;
35
+ modal?: boolean;
36
+ content?: ReactElement;
37
+ collapsedContent?: ReactElement;
38
+ extraContent?: ReactElement;
44
39
  aspectRatio?: number;
45
40
  isTabletPortrait?: boolean;
46
41
  style?: {
@@ -53,7 +48,6 @@ type AnimatedModalProps = {
53
48
  const height = SCREEN_HEIGHT;
54
49
 
55
50
  export function VideoPlayerModal({
56
- enabled = true,
57
51
  aspectRatio = DEFAULT_IMAGE_RATIO_VIDEO,
58
52
  content,
59
53
  extraContent,
@@ -61,7 +55,10 @@ export function VideoPlayerModal({
61
55
  isTabletPortrait,
62
56
  style,
63
57
  pip = false,
58
+ fullscreen = false,
59
+ modal = true,
64
60
  }: AnimatedModalProps) {
61
+ const enabled = !!modal && !fullscreen;
65
62
  const isTablet = useIsTablet();
66
63
 
67
64
  let width = SCREEN_WIDTH;
@@ -74,6 +71,8 @@ export function VideoPlayerModal({
74
71
  const scrollViewRef = useRef<typeof Animated.ScrollView | null>(null);
75
72
 
76
73
  const translateYRef = useModalAnimationContext().yTranslate;
74
+ // used when modal is false, should not be used in animation
75
+ const dummyRef = useRef(new Animated.Value(0));
77
76
 
78
77
  const {
79
78
  translateY,
@@ -81,7 +80,7 @@ export function VideoPlayerModal({
81
80
  collapsedHeight,
82
81
  gestureHandlerProps,
83
82
  expand,
84
- } = useVideoModalState(translateYRef);
83
+ } = useVideoModalState(modal ? translateYRef : dummyRef);
85
84
 
86
85
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
87
86
 
@@ -91,65 +90,78 @@ export function VideoPlayerModal({
91
90
 
92
91
  const insets = useSafeAreaInsets();
93
92
 
93
+ const isFullScreenOrPIP = fullscreen || pip;
94
+
94
95
  // Interpolated opacities for smooth cross-fade
95
- const collapsedOpacity = translateY.interpolate({
96
- inputRange: [MODAL_COLLAPSE_START, height - collapsedHeight],
97
- outputRange: [0, 1],
98
- extrapolate: "clamp",
99
- });
100
-
101
- const expandedOpacity = translateY.interpolate({
102
- inputRange: [0, height - collapsedHeight],
103
- outputRange: [1, 0],
104
- extrapolate: "clamp",
105
- });
106
-
107
- const xPosition = translateY.interpolate({
108
- inputRange: [height * VIDEO_TRANSITION_THRESHOLD, height - collapsedHeight],
109
- outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
110
- extrapolate: "clamp",
111
- });
96
+ const collapsedOpacity = !isFullScreenOrPIP
97
+ ? translateY.interpolate({
98
+ inputRange: [MODAL_COLLAPSE_START, height - collapsedHeight],
99
+ outputRange: [0, 1],
100
+ extrapolate: "clamp",
101
+ })
102
+ : new Animated.Value(0);
103
+
104
+ const expandedOpacity = !isFullScreenOrPIP
105
+ ? translateY.interpolate({
106
+ inputRange: [0, height - collapsedHeight],
107
+ outputRange: [1, 0],
108
+ extrapolate: "clamp",
109
+ })
110
+ : new Animated.Value(1);
111
+
112
+ const xPosition = !isFullScreenOrPIP
113
+ ? translateY.interpolate({
114
+ inputRange: [
115
+ height * VIDEO_TRANSITION_THRESHOLD,
116
+ height - collapsedHeight,
117
+ ],
118
+ outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
119
+ extrapolate: "clamp",
120
+ })
121
+ : new Animated.Value(0);
112
122
 
113
123
  const vidHeight = width / aspectRatio;
114
124
 
115
- const yPosition = translateY.interpolate({
116
- inputRange: [height * VIDEO_TRANSITION_THRESHOLD, height - collapsedHeight],
117
- outputRange: [
118
- 0,
119
- isTablet && isTabletLandscape
120
- ? -(
121
- (-PROGRESS_BAR_HEIGHT + SCREEN_HEIGHT - vidHeight * SCALE_FACTOR) /
122
- 2
123
- )
124
- : -(
125
- PROGRESS_BAR_HEIGHT +
126
- insets.top / 2 +
127
- (SCREEN_WIDTH / aspectRatio -
128
- (SCREEN_WIDTH / aspectRatio) * SCALE_FACTOR) /
129
- 2
130
- ),
131
- ],
132
- extrapolate: "clamp",
133
- });
134
-
135
- const scalePosition = translateY.interpolate({
136
- inputRange: [
137
- SCREEN_HEIGHT * VIDEO_TRANSITION_THRESHOLD,
138
- SCREEN_HEIGHT - collapsedHeight,
139
- ],
140
- outputRange: [1, SCALE_FACTOR],
141
- extrapolate: "clamp",
142
- });
143
-
144
- const borderTopRadiusAnimated = translateY.interpolate({
145
- inputRange: [0, SCREEN_HEIGHT - collapsedHeight],
146
- outputRange: [MODAL_RADIUS, 0],
147
- extrapolate: "clamp",
148
- });
149
-
150
- if (pip) {
151
- return content(new Animated.Value(1));
152
- }
125
+ const yPosition = !isFullScreenOrPIP
126
+ ? translateY.interpolate({
127
+ inputRange: [
128
+ height * VIDEO_TRANSITION_THRESHOLD,
129
+ height - collapsedHeight,
130
+ ],
131
+ outputRange: [
132
+ 0,
133
+ isTablet && isTabletLandscape
134
+ ? -((-PROGRESS_BAR_HEIGHT + height - vidHeight * SCALE_FACTOR) / 2)
135
+ : -(
136
+ PROGRESS_BAR_HEIGHT +
137
+ insets.top / 2 +
138
+ (SCREEN_WIDTH / aspectRatio -
139
+ (SCREEN_WIDTH / aspectRatio) * SCALE_FACTOR) /
140
+ 2
141
+ ),
142
+ ],
143
+ extrapolate: "clamp",
144
+ })
145
+ : new Animated.Value(0);
146
+
147
+ const scalePosition = !isFullScreenOrPIP
148
+ ? translateY.interpolate({
149
+ inputRange: [
150
+ height * VIDEO_TRANSITION_THRESHOLD,
151
+ height - collapsedHeight,
152
+ ],
153
+ outputRange: [1, SCALE_FACTOR],
154
+ extrapolate: "clamp",
155
+ })
156
+ : new Animated.Value(1);
157
+
158
+ const borderTopRadiusAnimated = !isFullScreenOrPIP
159
+ ? translateY.interpolate({
160
+ inputRange: [0, height - collapsedHeight],
161
+ outputRange: [MODAL_RADIUS, 0],
162
+ extrapolate: "clamp",
163
+ })
164
+ : new Animated.Value(0);
153
165
 
154
166
  return (
155
167
  <PanGestureHandler
@@ -164,8 +176,8 @@ export function VideoPlayerModal({
164
176
  {
165
177
  borderTopLeftRadius: borderTopRadiusAnimated,
166
178
  borderTopRightRadius: borderTopRadiusAnimated,
167
- transform: [{ translateY }],
168
- height: SCREEN_HEIGHT,
179
+ transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
180
+ height: height,
169
181
  },
170
182
  ]}
171
183
  >
@@ -177,7 +189,7 @@ export function VideoPlayerModal({
177
189
  {
178
190
  borderTopLeftRadius: borderTopRadiusAnimated,
179
191
  borderTopRightRadius: borderTopRadiusAnimated,
180
- height: SCREEN_HEIGHT,
192
+ height: height,
181
193
  },
182
194
  ]}
183
195
  >
@@ -197,7 +209,7 @@ export function VideoPlayerModal({
197
209
  },
198
210
  ]}
199
211
  >
200
- {content(expandedOpacity)}
212
+ {content}
201
213
  </Animated.View>
202
214
  {extraContent ? (
203
215
  <GestureAnimatedScrollView
@@ -210,26 +222,28 @@ export function VideoPlayerModal({
210
222
  { opacity: expandedOpacity },
211
223
  ]}
212
224
  >
213
- {extraContent ? extraContent(expandedOpacity) : null}
225
+ {extraContent || null}
214
226
  </GestureAnimatedScrollView>
215
227
  ) : null}
216
228
  </Animated.View>
217
229
 
218
- <Animated.View
219
- pointerEvents={collapsed ? "box-none" : "none"}
220
- style={[
221
- styles.collapsedBarContainer,
222
- { opacity: collapsedOpacity },
223
- ]}
224
- >
225
- <Pressable
226
- testID="collapsedBarWrapper"
227
- onPress={expand}
228
- style={styles.collapsedBarWrapper}
230
+ {!isFullScreenOrPIP ? (
231
+ <Animated.View
232
+ pointerEvents={collapsed ? "box-none" : "none"}
233
+ style={[
234
+ styles.collapsedBarContainer,
235
+ { opacity: collapsedOpacity },
236
+ ]}
229
237
  >
230
- {collapsedContent}
231
- </Pressable>
232
- </Animated.View>
238
+ <Pressable
239
+ testID="collapsedBarWrapper"
240
+ onPress={expand}
241
+ style={styles.collapsedBarWrapper}
242
+ >
243
+ {collapsedContent}
244
+ </Pressable>
245
+ </Animated.View>
246
+ ) : null}
233
247
  </Animated.View>
234
248
  </Animated.View>
235
249
  </PanGestureHandler>
@@ -1,18 +1,21 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
3
+ import { State } from "react-native-gesture-handler";
4
+ import { Animated } from "react-native";
5
+
1
6
  import { VideoModalMode } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
2
7
  import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
3
8
  import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight";
4
9
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
5
- import { useCallback, useEffect, useMemo, useRef } from "react";
6
- import { useSafeAreaInsets } from "react-native-safe-area-context";
10
+ import { isMenuVisible } from "@applicaster/zapp-react-native-ui-components/Components/Screen/navigationHandler";
7
11
  import {
8
12
  ANIMATION_DURATION,
9
13
  DRAG_TO_COLLAPSE,
10
14
  DRAG_TO_EXPAND,
11
15
  SCREEN_HEIGHT,
12
16
  } from "../consts";
13
- import { State } from "react-native-gesture-handler";
14
- import { Animated } from "react-native";
15
17
  import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
18
+ import { usePlugins } from "@applicaster/zapp-react-native-redux";
16
19
 
17
20
  const bottomTabBarHeight = getTabBarHeight();
18
21
 
@@ -21,15 +24,29 @@ export const useVideoModalState = (
21
24
  ) => {
22
25
  const { minimised_height: minimisedHeight } = useConfiguration();
23
26
 
24
- const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
25
- useNavigation();
27
+ const {
28
+ maximiseVideoModal,
29
+ minimiseVideoModal,
30
+ videoModalState,
31
+ currentRoute,
32
+ screenData,
33
+ } = useNavigation();
34
+
35
+ const plugins = usePlugins();
36
+
37
+ const menuVisible = isMenuVisible(currentRoute, screenData, plugins);
26
38
 
27
39
  const collapsed = videoModalState.mode === VideoModalMode.MINIMIZED;
28
40
 
29
41
  const { bottom } = useSafeAreaInsets();
30
42
 
43
+ const initialBottomOffset = useRef(bottom).current;
44
+
31
45
  const collapsedHeight =
32
- minimisedHeight + bottom + bottomTabBarHeight + PROGRESS_BAR_HEIGHT;
46
+ minimisedHeight +
47
+ initialBottomOffset +
48
+ (menuVisible ? bottomTabBarHeight : 0) +
49
+ PROGRESS_BAR_HEIGHT;
33
50
 
34
51
  const translateY = translateYRef.current;
35
52
 
@@ -58,74 +75,80 @@ export const useVideoModalState = (
58
75
  const offset = useRef(SCREEN_HEIGHT - collapsedHeight);
59
76
 
60
77
  // Gesture handler for modal
61
- const onGestureEvent = (event: any) => {
62
- if (event.nativeEvent.state === State.ACTIVE) {
63
- const y = event.nativeEvent.translationY;
64
- let newY = offset.current + y;
65
- if (newY < 0) newY = 0;
66
-
67
- if (newY > SCREEN_HEIGHT - collapsedHeight) {
68
- newY = SCREEN_HEIGHT - collapsedHeight;
69
- }
70
-
71
- translateY.setValue(newY);
72
- }
73
- };
74
-
75
- const onHandlerStateChange = (event: any) => {
76
- if (event.nativeEvent.oldState === State.ACTIVE) {
77
- const { translationY } = event.nativeEvent;
78
- let newY = offset.current + translationY;
79
- if (newY < 0) newY = 0;
80
-
81
- if (newY > SCREEN_HEIGHT - collapsedHeight) {
82
- newY = SCREEN_HEIGHT - collapsedHeight;
78
+ const onGestureEvent = useCallback(
79
+ (event: any) => {
80
+ if (event.nativeEvent.state === State.ACTIVE) {
81
+ const y = event.nativeEvent.translationY;
82
+ let newY = offset.current + y;
83
+ if (newY < 0) newY = 0;
84
+
85
+ if (newY > SCREEN_HEIGHT - collapsedHeight) {
86
+ newY = SCREEN_HEIGHT - collapsedHeight;
87
+ }
88
+
89
+ translateY.setValue(newY);
83
90
  }
91
+ },
92
+ [collapsedHeight, translateY]
93
+ );
84
94
 
85
- const shouldCollapse =
86
- translationY > (SCREEN_HEIGHT - collapsedHeight) * DRAG_TO_COLLAPSE;
87
-
88
- const shouldExpand =
89
- translationY < -(SCREEN_HEIGHT - collapsedHeight) * DRAG_TO_EXPAND;
90
-
91
- if (!collapsed && shouldCollapse) {
92
- // Collapse
93
- Animated.timing(translateY, {
94
- toValue: SCREEN_HEIGHT - collapsedHeight,
95
- duration: ANIMATION_DURATION,
96
- useNativeDriver: true,
97
- }).start(() => {
98
- minimiseVideoModal();
99
- offset.current = SCREEN_HEIGHT - collapsedHeight;
100
- });
101
- } else if (collapsed && shouldExpand) {
102
- // Expand
103
- Animated.timing(translateY, {
104
- toValue: 0,
105
- duration: ANIMATION_DURATION,
106
- useNativeDriver: true,
107
- }).start(() => {
108
- maximiseVideoModal();
109
- offset.current = 0;
110
- translateY.setValue(0);
111
- });
112
- } else {
113
- // Snap back to current state
114
- Animated.spring(translateY, {
115
- toValue: collapsed ? SCREEN_HEIGHT - collapsedHeight : 0,
116
- useNativeDriver: true,
117
- }).start(() => {
118
- offset.current = collapsed ? SCREEN_HEIGHT - collapsedHeight : 0;
119
- translateY.setValue(offset.current);
95
+ const onHandlerStateChange = useCallback(
96
+ (event: any) => {
97
+ if (event.nativeEvent.oldState === State.ACTIVE) {
98
+ const { translationY } = event.nativeEvent;
99
+ let newY = offset.current + translationY;
100
+ if (newY < 0) newY = 0;
101
+
102
+ if (newY > SCREEN_HEIGHT - collapsedHeight) {
103
+ newY = SCREEN_HEIGHT - collapsedHeight;
104
+ }
105
+
106
+ const shouldCollapse =
107
+ translationY > (SCREEN_HEIGHT - collapsedHeight) * DRAG_TO_COLLAPSE;
108
+
109
+ const shouldExpand =
110
+ translationY < -(SCREEN_HEIGHT - collapsedHeight) * DRAG_TO_EXPAND;
111
+
112
+ if (!collapsed && shouldCollapse) {
113
+ // Collapse
114
+ Animated.timing(translateY, {
115
+ toValue: SCREEN_HEIGHT - collapsedHeight,
116
+ duration: ANIMATION_DURATION,
117
+ useNativeDriver: true,
118
+ }).start(() => {
119
+ minimiseVideoModal();
120
+ offset.current = SCREEN_HEIGHT - collapsedHeight;
121
+ });
122
+ } else if (collapsed && shouldExpand) {
123
+ // Expand
124
+ Animated.timing(translateY, {
125
+ toValue: 0,
126
+ duration: ANIMATION_DURATION,
127
+ useNativeDriver: true,
128
+ }).start(() => {
129
+ maximiseVideoModal();
130
+ offset.current = 0;
131
+ translateY.setValue(0);
132
+ });
133
+ } else {
134
+ // Snap back to current state
135
+ Animated.spring(translateY, {
136
+ toValue: collapsed ? SCREEN_HEIGHT - collapsedHeight : 0,
137
+ useNativeDriver: true,
138
+ }).start(() => {
139
+ offset.current = collapsed ? SCREEN_HEIGHT - collapsedHeight : 0;
140
+ translateY.setValue(offset.current);
141
+ });
142
+ }
143
+ } else if (event.nativeEvent.state === State.BEGAN) {
144
+ // Gesture started, set offset
145
+ translateY.stopAnimation((value: number) => {
146
+ offset.current = value;
120
147
  });
121
148
  }
122
- } else if (event.nativeEvent.state === State.BEGAN) {
123
- // Gesture started, set offset
124
- translateY.stopAnimation((value: number) => {
125
- offset.current = value;
126
- });
127
- }
128
- };
149
+ },
150
+ [collapsedHeight, translateY, collapsed, videoModalState]
151
+ );
129
152
 
130
153
  const gestureHandlerProps = useMemo(() => {
131
154
  return {
@@ -148,14 +171,23 @@ export const useVideoModalState = (
148
171
  translateY.setValue(SCREEN_HEIGHT - collapsedHeight);
149
172
  });
150
173
  }
151
- }, [videoModalState.visible, videoModalState.mode]);
152
-
153
- return {
154
- collapsed,
155
- collapsedHeight,
156
- offset,
157
- gestureHandlerProps,
158
- translateY,
159
- expand: maximiseVideoModal,
160
- };
174
+ }, [videoModalState.visible, videoModalState.mode, collapsedHeight]);
175
+
176
+ return useMemo(
177
+ () => ({
178
+ collapsed,
179
+ collapsedHeight,
180
+ offset,
181
+ gestureHandlerProps,
182
+ translateY,
183
+ expand: maximiseVideoModal,
184
+ }),
185
+ [
186
+ collapsed,
187
+ collapsedHeight,
188
+ gestureHandlerProps,
189
+ translateY,
190
+ maximiseVideoModal,
191
+ ]
192
+ );
161
193
  };
@@ -0,0 +1,5 @@
1
+ const View = require("react-native").View;
2
+
3
+ export const VideoPlayerModal = View;
4
+
5
+ export default View;
@@ -52,50 +52,53 @@ export const useStyles = ({ height }: { height: number }) => {
52
52
  const BG_COLOR_DEFAULT_BLACK = "black";
53
53
  const BG_COLOR_DEFAULT_TRANSPARENT = "transparent";
54
54
 
55
- const styles = StyleSheet.create({
56
- modal: {
57
- position: "absolute",
58
- left: 0,
59
- right: 0,
60
- top: 0,
61
- backgroundColor,
62
- elevation: 10,
63
- zIndex: 100,
64
- overflow: "hidden",
65
- },
66
- modalWrapper: {
67
- backgroundColor: BG_COLOR_DEFAULT_BLACK,
68
- },
69
- collapsedModalBg: {
70
- backgroundColor: BG_COLOR_DEFAULT_BLACK,
71
- },
72
- modalContent: {
73
- flex: 1,
74
- alignItems: "center",
75
- },
76
- expandedContentContainer: {
77
- justifyContent: "flex-start",
78
- backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
79
- zIndex: 1,
80
- flex: 0,
81
- },
82
- extraContentScrollView: {
83
- width: "100%",
84
- backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
85
- },
86
- collapsedBarContainer: {
87
- ...StyleSheet.absoluteFillObject,
88
- height: COLLAPSED_HEIGHT,
89
- justifyContent: "flex-end",
90
- },
91
- collapsedBarWrapper: {
92
- flex: 1,
93
- },
94
- flexNone: {
95
- ...StyleSheet.absoluteFillObject,
96
- flex: -1,
97
- },
98
- });
99
-
100
- return useMemo(() => styles, [styles]);
55
+ return useMemo(
56
+ () =>
57
+ StyleSheet.create({
58
+ modal: {
59
+ position: "absolute",
60
+ left: 0,
61
+ right: 0,
62
+ top: 0,
63
+ backgroundColor,
64
+ elevation: 10,
65
+ zIndex: 100,
66
+ overflow: "hidden",
67
+ },
68
+ modalWrapper: {
69
+ backgroundColor: BG_COLOR_DEFAULT_BLACK,
70
+ },
71
+ collapsedModalBg: {
72
+ backgroundColor: BG_COLOR_DEFAULT_BLACK,
73
+ },
74
+ modalContent: {
75
+ flex: 1,
76
+ alignItems: "center",
77
+ },
78
+ expandedContentContainer: {
79
+ justifyContent: "flex-start",
80
+ backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
81
+ zIndex: 1,
82
+ flex: 0,
83
+ },
84
+ extraContentScrollView: {
85
+ width: "100%",
86
+ backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
87
+ },
88
+ collapsedBarContainer: {
89
+ ...StyleSheet.absoluteFillObject,
90
+ height: COLLAPSED_HEIGHT,
91
+ zIndex: 90,
92
+ justifyContent: "flex-end",
93
+ },
94
+ collapsedBarWrapper: {
95
+ flex: 1,
96
+ },
97
+ flexNone: {
98
+ ...StyleSheet.absoluteFillObject,
99
+ flex: -1,
100
+ },
101
+ }),
102
+ [backgroundColor, COLLAPSED_HEIGHT]
103
+ );
101
104
  };
@@ -793,7 +793,7 @@ export default class VideoPlayer extends React.Component<
793
793
  };
794
794
 
795
795
  const isFullScreenAudioPlayer =
796
- this.getPluginConfiguration()?.["full_screen_audio_player"] || false;
796
+ this.getPluginConfiguration()?.full_screen_audio_player || false;
797
797
 
798
798
  const isAudioPlayer = isFullScreenAudioPlayer && isAudioItem;
799
799
 
@@ -835,7 +835,7 @@ export default class VideoPlayer extends React.Component<
835
835
  this.isReactNativeMethodsSupported() &&
836
836
  RNPlayerManager?.[this.playerPluginId]?.play
837
837
  ) {
838
- delete nativeProps["paused"];
838
+ delete nativeProps.paused;
839
839
  }
840
840
 
841
841
  const adEvents = {
@@ -1032,10 +1032,11 @@ export default class VideoPlayer extends React.Component<
1032
1032
  />
1033
1033
  ) : (
1034
1034
  <VideoPlayerModal
1035
- enabled={!!isModal && !fullscreen}
1036
1035
  isTabletPortrait={isTabletPortrait}
1037
1036
  aspectRatio={aspectRatio}
1038
1037
  pip={this.state.piped}
1038
+ fullscreen={fullscreen}
1039
+ modal={isModal}
1039
1040
  style={{
1040
1041
  tabletLandscapeWidth: getTabletWidth(
1041
1042
  this.getPluginConfiguration().tablet_landscape_sidebar_width,
@@ -1044,9 +1045,10 @@ export default class VideoPlayer extends React.Component<
1044
1045
  width: style.width,
1045
1046
  height: style.height,
1046
1047
  }}
1047
- content={(_opacityAnim) => (
1048
+ content={
1048
1049
  <PlayerWrapper
1049
1050
  {...sharedWrapperViewProps}
1051
+ // eslint-disable-next-line react/no-unstable-nested-components
1050
1052
  playerContent={(playerDimensions) => {
1051
1053
  const shouldRenderBackground =
1052
1054
  !R.isNil(backgroundImageKey) &&
@@ -1059,11 +1061,7 @@ export default class VideoPlayer extends React.Component<
1059
1061
  <View style={[playerContainerStyles, playerDimensions]}>
1060
1062
  {isAudioItem ? (
1061
1063
  <AudioPlayer
1062
- style={
1063
- isTV()
1064
- ? getStyle(playerDimensions)
1065
- : styles.playerSize
1066
- }
1064
+ style={styles.playerSize}
1067
1065
  audio_item={entry}
1068
1066
  plugin_configuration={this.getPluginConfiguration()}
1069
1067
  />
@@ -1085,11 +1083,7 @@ export default class VideoPlayer extends React.Component<
1085
1083
  {...nativeEvents}
1086
1084
  {...nativeProps}
1087
1085
  listener={this.props.listener}
1088
- style={
1089
- isTV()
1090
- ? getStyle(playerDimensions)
1091
- : styles.playerSize
1092
- }
1086
+ style={styles.playerSize}
1093
1087
  pluginConfiguration={this.getPluginConfiguration()}
1094
1088
  controller={this.props.controller}
1095
1089
  >
@@ -1116,8 +1110,8 @@ export default class VideoPlayer extends React.Component<
1116
1110
  );
1117
1111
  }}
1118
1112
  />
1119
- )}
1120
- extraContent={(_opacityAnim) => (
1113
+ }
1114
+ extraContent={
1121
1115
  <PlayerDetails
1122
1116
  configuration={this.getPluginConfiguration()}
1123
1117
  style={{ flex: 1 }}
@@ -1128,18 +1122,16 @@ export default class VideoPlayer extends React.Component<
1128
1122
  isModal={isModal}
1129
1123
  pip={this.state.piped}
1130
1124
  />
1131
- )}
1132
- collapsedContent={(_opacityAnim) =>
1133
- this.state.piped ? null : (
1134
- <View style={styles.container}>
1135
- <DockedControls
1136
- entry={entry}
1137
- aspectRatio={aspectRatio}
1138
- layoutState={sharedWrapperViewProps.layoutState}
1139
- playNextData={sharedWrapperViewProps.playNextData}
1140
- />
1141
- </View>
1142
- )
1125
+ }
1126
+ collapsedContent={
1127
+ <View style={styles.container}>
1128
+ <DockedControls
1129
+ entry={entry}
1130
+ aspectRatio={aspectRatio}
1131
+ layoutState={sharedWrapperViewProps.layoutState}
1132
+ playNextData={sharedWrapperViewProps.playNextData}
1133
+ />
1134
+ </View>
1143
1135
  }
1144
1136
  />
1145
1137
  );
@@ -1,10 +1,12 @@
1
1
  import * as React from "react";
2
+ import { ZStoreProvider } from "@applicaster/zapp-react-native-utils/reactHooks/state";
2
3
 
3
4
  import { useOrientationEffect } from "@applicaster/zapp-react-native-utils/reactHooks/videoModal";
4
5
  import Player from "./Player";
5
6
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
6
7
  import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
7
8
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
9
+ import { usePlayerTTS } from "@applicaster/zapp-react-native-utils/playerUtils/usePlayerTTS";
8
10
  import { useIsCasting } from "./Player/hooks/useIsCasting";
9
11
 
10
12
  const CHROMECAST_IDENTIFIER = "quick-brick-chromecast-action";
@@ -45,17 +47,21 @@ const QuickBrickPlayerComponent = (
45
47
  isRunningPlayNext: !!props?.playNextData,
46
48
  });
47
49
 
50
+ usePlayerTTS();
51
+
48
52
  return (
49
- <Player
50
- {...props}
51
- ref={ref}
52
- castAction={!props?.disableCastAction && castAction}
53
- isCasting={isCasting}
54
- PlayerComponent={props.PlayerComponent}
55
- openPiP={openPiP}
56
- closePiP={closePiP}
57
- mode={mode}
58
- />
53
+ <ZStoreProvider name="playerConfiguration" value={controller?.config}>
54
+ <Player
55
+ {...props}
56
+ ref={ref}
57
+ castAction={!props?.disableCastAction && castAction}
58
+ isCasting={isCasting}
59
+ PlayerComponent={props.PlayerComponent}
60
+ openPiP={openPiP}
61
+ closePiP={closePiP}
62
+ mode={mode}
63
+ />
64
+ </ZStoreProvider>
59
65
  );
60
66
  };
61
67