@applicaster/quick-brick-player 14.0.0-rc.82 → 14.0.0-rc.84

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-rc.82",
3
+ "version": "14.0.0-rc.84",
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-rc.67",
38
+ "@applicaster/quick-brick-mobile-transport-controls": "14.0.0-rc.83",
39
39
  "@applicaster/quick-brick-tv-transport-controls": "14.0.0-rc.71",
40
- "@applicaster/zapp-react-native-tvos-app": "14.0.0-rc.82",
41
- "@applicaster/zapp-react-native-ui-components": "14.0.0-rc.82",
42
- "@applicaster/zapp-react-native-utils": "14.0.0-rc.82",
40
+ "@applicaster/zapp-react-native-tvos-app": "14.0.0-rc.84",
41
+ "@applicaster/zapp-react-native-ui-components": "14.0.0-rc.84",
42
+ "@applicaster/zapp-react-native-utils": "14.0.0-rc.84",
43
43
  "query-string": "7.1.3",
44
44
  "shaka-player": "4.3.5",
45
45
  "typeface-montserrat": "^0.0.54",
@@ -61,6 +61,7 @@ type Props = {
61
61
  inline: boolean;
62
62
  docked: boolean;
63
63
  isModal: boolean;
64
+ pip: boolean;
64
65
  };
65
66
  playNextData: PlayNextData;
66
67
  isTabletPortrait?: boolean;
@@ -246,13 +247,28 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
246
247
  player?.seekTo(0);
247
248
  }, [player]);
248
249
 
250
+ const layoutStateMemo = React.useMemo(
251
+ () => ({
252
+ inline: layoutState.inline,
253
+ docked: layoutState.docked,
254
+ isModal: layoutState.isModal,
255
+ pip: layoutState.pip,
256
+ }),
257
+ [
258
+ layoutState.inline,
259
+ layoutState.docked,
260
+ layoutState.isModal,
261
+ layoutState.pip,
262
+ ]
263
+ );
264
+
249
265
  return (
250
266
  <SafeAreaView style={[style, Styles.playerContainer]} edges={edges}>
251
267
  <View style={Styles.playerContainer} onLayout={onLayout}>
252
268
  <Layout
253
269
  entry={entry}
254
270
  playerState={playerState}
255
- layoutState={layoutState}
271
+ layoutState={layoutStateMemo}
256
272
  value={value}
257
273
  onPlaybackButtonPress={onPlaybackButtonPress}
258
274
  onRewindButtonPress={onRewindButtonPress}
@@ -1,6 +1,5 @@
1
1
  import * as React from "react";
2
- import { StyleSheet, View, ViewStyle } from "react-native";
3
- import * as R from "ramda";
2
+ import { StyleSheet, View } from "react-native";
4
3
  import {
5
4
  useIsTablet,
6
5
  useZStore,
@@ -16,7 +15,6 @@ import {
16
15
 
17
16
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
18
17
 
19
- import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
20
18
  import { useSafeAreaInsets } from "react-native-safe-area-context";
21
19
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
22
20
  import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight";
@@ -27,6 +25,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
27
25
  import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
28
26
  import { isMenuVisible } from "@applicaster/zapp-react-native-ui-components/Components/Screen/navigationHandler";
29
27
  import { usePlugins } from "@applicaster/zapp-react-native-redux";
28
+ import { partial } from "@applicaster/zapp-react-native-utils/utils";
30
29
 
31
30
  const bottomTabBarHeight = getTabBarHeight();
32
31
 
@@ -45,7 +44,6 @@ const styles = StyleSheet.create({
45
44
  flex: 1,
46
45
  flexDirection: "column",
47
46
  alignItems: "stretch",
48
- marginTop: PROGRESS_BAR_HEIGHT,
49
47
  },
50
48
  content: {
51
49
  flex: 1,
@@ -88,14 +86,12 @@ const styles = StyleSheet.create({
88
86
  buttons: {
89
87
  marginVertical: 10,
90
88
  },
89
+ liveMarginTop: { marginTop: 0 },
90
+ marginTop: { marginTop: PROGRESS_BAR_HEIGHT },
91
91
  });
92
92
 
93
- const playerDimensionsStyle = (
94
- minimisedHeight: number,
95
- addPadding: boolean
96
- ): ViewStyle => ({
97
- width: addPadding ? toNumberWithDefault(100, minimisedHeight) : 0,
98
- });
93
+ const getValue = (key: string, stylesObj: Record<string, any>) =>
94
+ stylesObj?.[key] ?? null;
99
95
 
100
96
  const controlButtons = (
101
97
  live: boolean,
@@ -161,7 +157,6 @@ export const DockedControls = (props: Props) => {
161
157
  onPlayerSeek = noop,
162
158
  playNextData,
163
159
  ImageComponent,
164
- isActiveGesture = true,
165
160
  aspectRatio,
166
161
  } = props;
167
162
 
@@ -179,11 +174,6 @@ export const DockedControls = (props: Props) => {
179
174
  const configuration = useZStore("playerConfiguration")();
180
175
  const playerState = usePlayerState("shared-player-wrapper-docked");
181
176
 
182
- const getValue = React.useCallback(
183
- (key: string, stylesObj: {}) => R.propOr(null, key, stylesObj),
184
- []
185
- );
186
-
187
177
  const value = React.useCallback(
188
178
  (key: string) => {
189
179
  const retVal = getValue(key, configuration);
@@ -202,7 +192,7 @@ export const DockedControls = (props: Props) => {
202
192
 
203
193
  return retVal;
204
194
  },
205
- [...Object.values(configuration), playerState.seekableDuration, getValue]
195
+ [...Object.values(configuration), playerState.seekableDuration]
206
196
  );
207
197
 
208
198
  const { title, summary } = useTitleSummaryOverlay(
@@ -219,15 +209,65 @@ export const DockedControls = (props: Props) => {
219
209
 
220
210
  const insets = useSafeAreaInsets();
221
211
 
212
+ const progressBarLayoutState = React.useMemo(
213
+ () => ({
214
+ inline: layoutState.inline,
215
+ docked: true,
216
+ isModal: layoutState.isModal,
217
+ pip: layoutState.pip,
218
+ }),
219
+ [layoutState.inline, layoutState.isModal, layoutState.pip]
220
+ );
221
+
222
+ const _controlButtons = React.useMemo(
223
+ () => partial(controlButtons, playerState.isLive && liveButton),
224
+ [playerState.isLive, liveButton]
225
+ );
226
+
227
+ const containerStyles = React.useMemo(
228
+ () => ({
229
+ height: minimisedHeight,
230
+ maxHeight: minimisedHeight,
231
+ }),
232
+ [minimisedHeight]
233
+ );
234
+
235
+ const imageComponentWrapperStyles = React.useMemo(
236
+ () => ({
237
+ aspectRatio: aspectRatio,
238
+ height: minimisedHeight,
239
+ }),
240
+ [aspectRatio, minimisedHeight]
241
+ );
242
+
243
+ const backgroundColorStyle = React.useMemo(
244
+ () => ({
245
+ backgroundColor: dockedBackgroundColor,
246
+ }),
247
+ [dockedBackgroundColor]
248
+ );
249
+
250
+ const bottomSpacerStyle = React.useMemo(() => {
251
+ const tabBarHeight = menuVisible ? bottomTabBarHeight : 0;
252
+ const safeAreaBottomInset = insets.bottom || 0;
253
+
254
+ return {
255
+ height: safeAreaBottomInset + tabBarHeight,
256
+ };
257
+ }, [menuVisible, insets.bottom]);
258
+
259
+ const contentInfoContent = React.useMemo(
260
+ () => ({ ...entry, title, summary }),
261
+ [title, summary, entry]
262
+ );
263
+
222
264
  return (
223
265
  <>
224
266
  <View
225
267
  style={[
226
268
  styles.container,
227
- {
228
- height: minimisedHeight,
229
- maxHeight: minimisedHeight,
230
- },
269
+ containerStyles,
270
+ playerState.isLive ? styles.liveMarginTop : styles.marginTop,
231
271
  ]}
232
272
  >
233
273
  {!playerState.isLive ? (
@@ -236,42 +276,23 @@ export const DockedControls = (props: Props) => {
236
276
  content={entry}
237
277
  value={value}
238
278
  visible
239
- layoutState={layoutState}
279
+ layoutState={progressBarLayoutState}
240
280
  onPlayerSeek={onPlayerSeek}
241
281
  playerState={playerState}
242
- startComponentsAnimation={noop}
243
282
  docked
244
283
  />
245
284
  ) : null}
246
285
 
247
286
  <View style={styles.content}>
248
287
  <View style={styles.touchableArea}>
249
- {isActiveGesture || layoutState.docked ? (
250
- <View
251
- style={{ aspectRatio: aspectRatio, height: minimisedHeight }}
252
- >
253
- {ImageComponent || null}
254
- </View>
255
- ) : (
256
- <View
257
- style={playerDimensionsStyle(
258
- minimisedHeight,
259
- isActiveGesture || layoutState.docked
260
- )}
261
- />
262
- )}
288
+ <View style={imageComponentWrapperStyles}>
289
+ {ImageComponent || null}
290
+ </View>
263
291
  <View
264
292
  testID="content-info"
265
- style={[
266
- styles.contentInfo,
267
- { backgroundColor: dockedBackgroundColor },
268
- ]}
293
+ style={[styles.contentInfo, backgroundColorStyle]}
269
294
  >
270
- <ContentInfo
271
- content={{ ...entry, title, summary }}
272
- value={value}
273
- docked
274
- />
295
+ <ContentInfo content={contentInfoContent} value={value} docked />
275
296
  </View>
276
297
  </View>
277
298
  <View
@@ -279,15 +300,13 @@ export const DockedControls = (props: Props) => {
279
300
  isTablet
280
301
  ? styles.controlsContainerForTablet
281
302
  : styles.controlsContainerForMobile,
282
- { backgroundColor: dockedBackgroundColor },
303
+ backgroundColorStyle,
283
304
  ]}
284
305
  >
285
306
  <Controls
286
307
  value={value}
287
308
  visible
288
- buttons={R.partial(controlButtons, [
289
- playerState.isLive && liveButton,
290
- ])}
309
+ buttons={_controlButtons}
291
310
  style={styles.playPauseButton}
292
311
  playNextData={playNextData}
293
312
  playerState={playerState}
@@ -302,12 +321,7 @@ export const DockedControls = (props: Props) => {
302
321
  </View>
303
322
  </View>
304
323
  </View>
305
- <View
306
- style={{
307
- height: insets.bottom + (menuVisible ? bottomTabBarHeight : 0),
308
- backgroundColor: dockedBackgroundColor,
309
- }}
310
- />
324
+ <View style={[bottomSpacerStyle, backgroundColorStyle]} />
311
325
  </>
312
326
  );
313
327
  };
@@ -151,12 +151,7 @@ export function MobileLayout({
151
151
  },
152
152
  ]}
153
153
  >
154
- <PlayerImage
155
- entry={entry}
156
- docked={false}
157
- imageWidth={imageSize}
158
- configuration={configuration}
159
- />
154
+ <PlayerImage entry={entry} configuration={configuration} />
160
155
  </View>
161
156
  {/* PlayerImage */}
162
157
 
@@ -4,7 +4,6 @@ import { LayoutChangeEvent, View } from "react-native";
4
4
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
5
5
  import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
6
6
 
7
- import { AnimatedImage } from "./AnimatedImage";
8
7
  import { FlexImage } from "./FlexImage";
9
8
 
10
9
  import { styles } from "./styles";
@@ -13,19 +12,12 @@ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/nu
13
12
  type Props = {
14
13
  entry: ZappEntry;
15
14
  configuration: QuickBrickPlayer.AudioPlayerProps["configuration"];
16
- docked: boolean;
17
- imageWidth?: Option<number>;
15
+ docked?: boolean;
18
16
  onLayoutImage?: (event: LayoutChangeEvent) => void;
19
17
  };
20
18
 
21
19
  export const PlayerImage = (props: Props) => {
22
- const {
23
- entry,
24
- docked,
25
- imageWidth,
26
- configuration,
27
- onLayoutImage = noop,
28
- } = props;
20
+ const { entry, docked = false, configuration, onLayoutImage = noop } = props;
29
21
 
30
22
  const isShadowEnabled = toBooleanWithDefaultTrue(
31
23
  configuration?.audio_player_artwork_shadow_enabled
@@ -43,19 +35,9 @@ export const PlayerImage = (props: Props) => {
43
35
  onLayout={onLayoutImage}
44
36
  style={[shouldShowShadow ? styles.shadow : undefined, { borderRadius }]}
45
37
  >
46
- {!imageWidth ? (
47
- <View style={[styles.defaultImageWrapperView, { borderRadius }]}>
48
- <FlexImage entry={entry} style={styles.backgroundImageContainer} />
49
- </View>
50
- ) : (
51
- // we have imageSize here and now we could animate resizing of this image
52
- <AnimatedImage
53
- entry={entry}
54
- style={[styles.backgroundImageContainer, { borderRadius }]}
55
- imageWidth={imageWidth}
56
- docked={docked}
57
- />
58
- )}
38
+ <View style={[styles.defaultImageWrapperView, { borderRadius }]}>
39
+ <FlexImage entry={entry} style={styles.backgroundImageContainer} />
40
+ </View>
59
41
  </View>
60
42
  </View>
61
43
  );
@@ -117,14 +117,11 @@ export function TabletLandscapeLayout({
117
117
  <View style={[styles.flex, styles.audioPlayerContainerHeightLimit]}>
118
118
  {/* PlayerImage non-docked */}
119
119
  <View style={[styles.flex, withDebug(styles.debugYellow)]}>
120
- {!docked ? (
121
- <PlayerImage
122
- docked={false}
123
- entry={entry}
124
- configuration={configuration}
125
- onLayoutImage={onLayoutImage}
126
- />
127
- ) : null}
120
+ <PlayerImage
121
+ entry={entry}
122
+ configuration={configuration}
123
+ onLayoutImage={onLayoutImage}
124
+ />
128
125
  </View>
129
126
  {/* PlayerImage */}
130
127
 
@@ -144,12 +144,7 @@ export function TabletPortraitLayout({
144
144
  ]}
145
145
  onLayout={onLayout}
146
146
  >
147
- <PlayerImage
148
- entry={entry}
149
- configuration={configuration}
150
- docked={docked}
151
- imageWidth={imageSize}
152
- />
147
+ <PlayerImage entry={entry} configuration={configuration} />
153
148
  </View>
154
149
 
155
150
  <View
@@ -1,10 +1,6 @@
1
1
  import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
2
- import {
3
- PlayerAnimationStateEnum,
4
- PlayerAnimationStateT,
5
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/ModalAnimationContext";
2
+
6
3
  import { parseJsonIfNeeded } from "@applicaster/zapp-react-native-utils/functionUtils";
7
- import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
8
4
 
9
5
  export const NAMESPACE = "audio-player";
10
6
 
@@ -36,25 +32,3 @@ export const formatSpeed = (value: number) => {
36
32
  // Return the formatted string with "speed_" prefix
37
33
  return `speed_${formattedValue}`;
38
34
  };
39
-
40
- export const calculateBorderRadius = (
41
- docked: boolean,
42
- startComponentsAnimation: boolean,
43
- isActiveGesture: boolean,
44
- playerAnimationState: PlayerAnimationStateT,
45
- configuration: Record<string, any>
46
- ): number => {
47
- const shouldRemoveBorderRadius =
48
- (startComponentsAnimation &&
49
- isActiveGesture &&
50
- playerAnimationState !== PlayerAnimationStateEnum.maximize) ||
51
- docked;
52
-
53
- if (shouldRemoveBorderRadius) {
54
- return 0;
55
- }
56
-
57
- return toNumberWithDefaultZero(
58
- configuration.audio_player_artwork_border_radius
59
- );
60
- };
@@ -29,10 +29,10 @@ export function AnimatedModal({
29
29
 
30
30
  const styles = useStyles({ height: collapsedHeight, type: "audio" });
31
31
 
32
- const WINDOW_HEIGHT = getWindowHeight();
33
- const heightAboveMinimised = WINDOW_HEIGHT - collapsedHeight;
32
+ const height = getWindowHeight();
33
+ const heightAboveMinimised = height - collapsedHeight;
34
34
 
35
- const MODAL_COLLAPSE_START = WINDOW_HEIGHT * MODAL_COLLAPSE_RATIO;
35
+ const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
36
36
 
37
37
  // Interpolated opacities for smooth cross-fade
38
38
  const collapsedOpacity = translateY.interpolate({
@@ -63,7 +63,7 @@ export function AnimatedModal({
63
63
  borderTopLeftRadius: borderTopRadiusAnimated,
64
64
  borderTopRightRadius: borderTopRadiusAnimated,
65
65
  transform: [{ translateY }],
66
- height: WINDOW_HEIGHT,
66
+ height: height,
67
67
  },
68
68
  ]}
69
69
  >
@@ -73,7 +73,6 @@ export function AnimatedModal({
73
73
  {
74
74
  borderTopLeftRadius: borderTopRadiusAnimated,
75
75
  borderTopRightRadius: borderTopRadiusAnimated,
76
- height: WINDOW_HEIGHT,
77
76
  },
78
77
  ]}
79
78
  >
@@ -1,6 +1,6 @@
1
1
  import React, { ReactElement, useMemo, useRef } from "react";
2
2
 
3
- import { Animated, Pressable, StyleSheet, ViewStyle } from "react-native";
3
+ import { Animated, Pressable } from "react-native";
4
4
  import { PanGestureHandler } from "react-native-gesture-handler";
5
5
  import { useStyles } from "./styles";
6
6
  import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
@@ -12,22 +12,23 @@ import {
12
12
  VIDEO_TRANSITION_THRESHOLD,
13
13
  } from "./consts";
14
14
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
15
- import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
16
15
  import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/useModalAnimationContext";
17
16
  import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
18
- import { useSafeAreaInsets } from "react-native-safe-area-context";
17
+ import {
18
+ SafeAreaView,
19
+ useSafeAreaFrame,
20
+ useSafeAreaInsets,
21
+ } from "react-native-safe-area-context";
19
22
  import { GestureAnimatedScrollView } from "./GestureAnimatedScrollView";
20
23
  import { PlayerDetailsWrapperHeightContext } from "./context";
21
- import { getWindowHeight, getWindowWidth } from "./utils";
22
-
23
- const orientationStyles = StyleSheet.create({
24
- landscape: { flexDirection: "row" },
25
- portrait: { flexDirection: "column" },
26
- });
27
-
28
- const directionStyles = (isLandscape: boolean): ViewStyle => {
29
- return isLandscape ? orientationStyles.landscape : orientationStyles.portrait;
30
- };
24
+ import {
25
+ getInsetsOffset,
26
+ getWindowHeight,
27
+ getWindowWidth,
28
+ directionStyles,
29
+ getScaledPos,
30
+ getExtraContentPadding,
31
+ } from "./utils";
31
32
 
32
33
  type AnimatedModalProps = {
33
34
  pip?: boolean;
@@ -59,16 +60,19 @@ export function VideoPlayerModal({
59
60
  const enabled = !!modal && !fullscreen;
60
61
  const isTablet = useIsTablet();
61
62
 
62
- const WINDOW_WIDTH = useMemo(() => getWindowWidth(), []); // remember initial width, ignore rotation changes
63
+ // remember initial width, ignore rotation changes
64
+ const width = useMemo(
65
+ () =>
66
+ isTablet && !isTabletPortrait
67
+ ? style.tabletLandscapeWidth
68
+ : getWindowWidth(),
69
+ // eslint-disable-next-line react-hooks/exhaustive-deps
70
+ []
71
+ );
72
+
63
73
  const height = useMemo(() => getWindowHeight(), []); // remember initial height, ignore rotation changes
64
74
  const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
65
75
 
66
- let width = WINDOW_WIDTH;
67
-
68
- if (isTablet && !isTabletPortrait) {
69
- width = style?.tabletLandscapeWidth || width;
70
- }
71
-
72
76
  const { minimised_height: minimisedHeight } = useConfiguration();
73
77
  const scrollViewRef = useRef<typeof Animated.ScrollView | null>(null);
74
78
 
@@ -84,9 +88,9 @@ export function VideoPlayerModal({
84
88
  expand,
85
89
  } = useVideoModalState(modal ? translateYRef : dummyRef);
86
90
 
87
- const heightAboveMinimised = height - collapsedHeight;
91
+ const frame = useSafeAreaFrame();
88
92
 
89
- const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
93
+ const heightAboveMinimised = height - collapsedHeight;
90
94
 
91
95
  const styles = useStyles({ height: collapsedHeight });
92
96
 
@@ -113,9 +117,10 @@ export function VideoPlayerModal({
113
117
  })
114
118
  : new Animated.Value(1);
115
119
 
120
+ // animated position for video content during modal transition
116
121
  const xPosition = !isFullScreenOrPIP
117
122
  ? translateY.interpolate({
118
- inputRange: [height * VIDEO_TRANSITION_THRESHOLD, heightAboveMinimised],
123
+ inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
119
124
  outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
120
125
  extrapolate: "clamp",
121
126
  })
@@ -123,34 +128,26 @@ export function VideoPlayerModal({
123
128
 
124
129
  const vidHeight = width / aspectRatio;
125
130
 
131
+ // animated position for video content during modal transition
126
132
  const yPosition = !isFullScreenOrPIP
127
133
  ? translateY.interpolate({
128
- inputRange: [
129
- height * VIDEO_TRANSITION_THRESHOLD,
130
- height - collapsedHeight,
131
- ],
134
+ inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
132
135
  outputRange: [
133
136
  0,
134
- isTablet && isTabletLandscape
135
- ? -((-PROGRESS_BAR_HEIGHT + height - vidHeight * SCALE_FACTOR) / 2)
136
- : -(
137
- PROGRESS_BAR_HEIGHT +
138
- insets.top / 2 +
139
- (WINDOW_WIDTH / aspectRatio -
140
- (WINDOW_WIDTH / aspectRatio) * SCALE_FACTOR) /
141
- 2
142
- ),
137
+ -(
138
+ PROGRESS_BAR_HEIGHT +
139
+ getInsetsOffset(insets, isTabletPortrait) +
140
+ getScaledPos(height, vidHeight, minimisedHeight, isTabletPortrait)
141
+ ),
143
142
  ],
144
143
  extrapolate: "clamp",
145
144
  })
146
145
  : new Animated.Value(0);
147
146
 
147
+ // animated position for video content during modal transition
148
148
  const scalePosition = !isFullScreenOrPIP
149
149
  ? translateY.interpolate({
150
- inputRange: [
151
- height * VIDEO_TRANSITION_THRESHOLD,
152
- height - collapsedHeight,
153
- ],
150
+ inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
154
151
  outputRange: [1, SCALE_FACTOR],
155
152
  extrapolate: "clamp",
156
153
  })
@@ -158,7 +155,7 @@ export function VideoPlayerModal({
158
155
 
159
156
  const borderTopRadiusAnimated = !isFullScreenOrPIP
160
157
  ? translateY.interpolate({
161
- inputRange: [0, height - collapsedHeight],
158
+ inputRange: [0, heightAboveMinimised],
162
159
  outputRange: [MODAL_RADIUS, 0],
163
160
  extrapolate: "clamp",
164
161
  })
@@ -184,88 +181,92 @@ export function VideoPlayerModal({
184
181
  waitFor={scrollViewRef}
185
182
  {...gestureHandlerProps}
186
183
  >
187
- <Animated.View
188
- pointerEvents={"auto"}
189
- style={[
190
- styles.modalWrapper,
191
- {
192
- borderTopLeftRadius: borderTopRadiusAnimated,
193
- borderTopRightRadius: borderTopRadiusAnimated,
194
- transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
195
- height: height,
196
- },
197
- ]}
198
- >
184
+ <SafeAreaView pointerEvents="box-none" edges={["bottom"]}>
199
185
  <Animated.View
200
186
  pointerEvents={"auto"}
201
187
  style={[
202
- styles.modal,
203
- collapsed ? styles.collapsedModalBg : null,
188
+ styles.modalWrapper,
204
189
  {
205
190
  borderTopLeftRadius: borderTopRadiusAnimated,
206
191
  borderTopRightRadius: borderTopRadiusAnimated,
207
- height: height,
192
+ transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
193
+ height: frame.height,
208
194
  },
209
195
  ]}
210
196
  >
211
197
  <Animated.View
212
- pointerEvents={!collapsed ? "auto" : "none"}
213
- style={[styles.modalContent, directionStyles(isTabletLandscape)]}
198
+ pointerEvents={"auto"}
199
+ style={[
200
+ styles.modal,
201
+ collapsed ? styles.collapsedModalBg : null,
202
+ {
203
+ borderTopLeftRadius: borderTopRadiusAnimated,
204
+ borderTopRightRadius: borderTopRadiusAnimated,
205
+ },
206
+ ]}
214
207
  >
215
208
  <Animated.View
209
+ pointerEvents={!collapsed ? "auto" : "none"}
216
210
  style={[
217
- styles.expandedContentContainer,
218
- {
219
- transform: [
220
- { translateX: xPosition },
221
- { translateY: yPosition },
222
- { scale: scalePosition },
223
- ],
224
- },
211
+ pip ? styles.modalContentPiP : styles.modalContent,
212
+ directionStyles(isTabletPortrait),
225
213
  ]}
226
214
  >
227
- {content}
215
+ <Animated.View
216
+ style={[
217
+ styles.expandedContentContainer,
218
+ {
219
+ transform: [
220
+ { translateX: xPosition },
221
+ { translateY: yPosition },
222
+ { scale: scalePosition },
223
+ ],
224
+ },
225
+ ]}
226
+ >
227
+ {content}
228
+ </Animated.View>
229
+ {extraContent ? (
230
+ <GestureAnimatedScrollView
231
+ ref={scrollViewRef}
232
+ contentContainerStyle={getExtraContentPadding(insets)}
233
+ bounces={false}
234
+ overScrollMode="never"
235
+ onLayout={onScrollViewLayout}
236
+ style={[
237
+ styles.extraContentScrollView,
238
+ { opacity: expandedOpacity },
239
+ ]}
240
+ >
241
+ <PlayerDetailsWrapperHeightContext.Provider
242
+ value={playerDetailsWrapperHeight}
243
+ >
244
+ {extraContent}
245
+ </PlayerDetailsWrapperHeightContext.Provider>
246
+ </GestureAnimatedScrollView>
247
+ ) : null}
228
248
  </Animated.View>
229
- {extraContent ? (
230
- <GestureAnimatedScrollView
231
- ref={scrollViewRef}
232
- contentContainerStyle={{
233
- paddingBottom: insets.bottom,
234
- }}
235
- onLayout={onScrollViewLayout}
249
+
250
+ {!isFullScreenOrPIP ? (
251
+ <Animated.View
252
+ pointerEvents={collapsed ? "box-none" : "none"}
236
253
  style={[
237
- styles.extraContentScrollView,
238
- { opacity: expandedOpacity },
254
+ styles.collapsedBarContainer,
255
+ { opacity: collapsedOpacity },
239
256
  ]}
240
257
  >
241
- <PlayerDetailsWrapperHeightContext.Provider
242
- value={playerDetailsWrapperHeight}
258
+ <Pressable
259
+ testID="collapsedBarWrapper"
260
+ onPress={expand}
261
+ style={styles.collapsedBarWrapper}
243
262
  >
244
- {extraContent}
245
- </PlayerDetailsWrapperHeightContext.Provider>
246
- </GestureAnimatedScrollView>
263
+ {collapsedContent}
264
+ </Pressable>
265
+ </Animated.View>
247
266
  ) : null}
248
267
  </Animated.View>
249
-
250
- {!isFullScreenOrPIP ? (
251
- <Animated.View
252
- pointerEvents={collapsed ? "box-none" : "none"}
253
- style={[
254
- styles.collapsedBarContainer,
255
- { opacity: collapsedOpacity },
256
- ]}
257
- >
258
- <Pressable
259
- testID="collapsedBarWrapper"
260
- onPress={expand}
261
- style={styles.collapsedBarWrapper}
262
- >
263
- {collapsedContent}
264
- </Pressable>
265
- </Animated.View>
266
- ) : null}
267
268
  </Animated.View>
268
- </Animated.View>
269
+ </SafeAreaView>
269
270
  </PanGestureHandler>
270
271
  );
271
272
  }
@@ -1,5 +1,8 @@
1
1
  import { useCallback, useEffect, useMemo, useRef } from "react";
2
- import { useSafeAreaInsets } from "react-native-safe-area-context";
2
+ import {
3
+ useSafeAreaFrame,
4
+ useSafeAreaInsets,
5
+ } from "react-native-safe-area-context";
3
6
  import { State } from "react-native-gesture-handler";
4
7
  import { Animated } from "react-native";
5
8
 
@@ -15,7 +18,7 @@ import {
15
18
  } from "../consts";
16
19
  import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
17
20
  import { usePlugins } from "@applicaster/zapp-react-native-redux";
18
- import { getWindowHeight } from "../utils";
21
+ import { isOldAndroidDevice } from "../utils";
19
22
 
20
23
  const bottomTabBarHeight = getTabBarHeight();
21
24
 
@@ -24,8 +27,6 @@ export const useVideoModalState = (
24
27
  ) => {
25
28
  const { minimised_height: minimisedHeight } = useConfiguration();
26
29
 
27
- const WINDOW_HEIGHT = getWindowHeight();
28
-
29
30
  const {
30
31
  maximiseVideoModal,
31
32
  minimiseVideoModal,
@@ -42,17 +43,16 @@ export const useVideoModalState = (
42
43
  videoModalState.visible &&
43
44
  videoModalState.mode === VideoModalMode.MINIMIZED;
44
45
 
45
- const { bottom } = useSafeAreaInsets();
46
-
47
- const initialBottomOffset = useRef(bottom).current;
46
+ const frame = useSafeAreaFrame();
47
+ const insets = useSafeAreaInsets();
48
48
 
49
49
  const collapsedHeight =
50
50
  minimisedHeight +
51
- initialBottomOffset +
52
51
  (menuVisible ? bottomTabBarHeight : 0) +
52
+ (isOldAndroidDevice ? 0 : insets.bottom) + // insets.bottom is added to properly display docked modal
53
53
  PROGRESS_BAR_HEIGHT;
54
54
 
55
- const heightAboveMinimised = WINDOW_HEIGHT - collapsedHeight;
55
+ const heightAboveMinimised = frame.height - collapsedHeight;
56
56
 
57
57
  const translateY = translateYRef.current;
58
58
 
@@ -179,7 +179,12 @@ export const useVideoModalState = (
179
179
  });
180
180
  }
181
181
  }
182
- }, [videoModalState.visible, videoModalState.mode, collapsedHeight]);
182
+ }, [
183
+ videoModalState.visible,
184
+ videoModalState.mode,
185
+ collapsedHeight,
186
+ heightAboveMinimised,
187
+ ]);
183
188
 
184
189
  return useMemo(
185
190
  () => ({
@@ -63,6 +63,7 @@ export const useStyles = ({ height }: { height: number }) => {
63
63
  backgroundColor,
64
64
  elevation: 10,
65
65
  zIndex: 100,
66
+ height: "100%",
66
67
  overflow: "hidden",
67
68
  },
68
69
  modalWrapper: {
@@ -75,6 +76,10 @@ export const useStyles = ({ height }: { height: number }) => {
75
76
  flex: 1,
76
77
  alignItems: "center",
77
78
  },
79
+ modalContentPiP: {
80
+ flex: 1,
81
+ alignItems: "flex-start",
82
+ },
78
83
  expandedContentContainer: {
79
84
  justifyContent: "flex-start",
80
85
  backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
@@ -1,25 +1,31 @@
1
- import { StatusBar, Dimensions } from "react-native";
1
+ import { StyleSheet, Dimensions, ViewStyle } from "react-native";
2
2
 
3
3
  import {
4
4
  isAndroidPlatform,
5
5
  isAndroidVersionAtLeast,
6
+ isTV,
6
7
  } from "@applicaster/zapp-react-native-utils/reactUtils";
7
- import { isAndroidTablet } from "@applicaster/zapp-react-native-utils/reactHooks/layout/isTablet";
8
+ import {
9
+ isTablet,
10
+ useIsTablet as getIsTablet,
11
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
8
12
 
9
- const MIN_SUPPORTED_ANDROID_API = 34;
13
+ const SAFE_AREA_BREAKING_API_VERSION = 35;
10
14
 
11
- const isOldAndroidDevice =
15
+ export const isOldAndroidDevice =
12
16
  isAndroidPlatform() &&
13
- !isAndroidVersionAtLeast(MIN_SUPPORTED_ANDROID_API) &&
14
- !isAndroidTablet();
17
+ !isAndroidVersionAtLeast(SAFE_AREA_BREAKING_API_VERSION);
15
18
 
16
19
  export const getWindowHeight = (): number => {
17
20
  const windowDimensions = Dimensions.get("window");
18
21
 
19
- return (
20
- windowDimensions.height +
21
- (isOldAndroidDevice ? (StatusBar.currentHeight ?? 0) : 0)
22
- );
22
+ return windowDimensions.height;
23
+ };
24
+
25
+ export const getScreenHeight = (): number => {
26
+ const screenDimensions = Dimensions.get("screen");
27
+
28
+ return screenDimensions.height;
23
29
  };
24
30
 
25
31
  export const getWindowWidth = (): number => {
@@ -27,3 +33,60 @@ export const getWindowWidth = (): number => {
27
33
 
28
34
  return windowDimensions.width;
29
35
  };
36
+
37
+ const getIsTabletLandscape = (isTabletPortrait: boolean): boolean => {
38
+ return !isTV() && isTablet() && !isTabletPortrait;
39
+ };
40
+
41
+ export const getInsetsOffset = (
42
+ insets: { top: number; bottom: number },
43
+ isTabletPortrait: boolean
44
+ ): number => {
45
+ const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
46
+
47
+ return isTablet() && isTabletLandscape
48
+ ? isOldAndroidDevice
49
+ ? insets.top / 2
50
+ : 0
51
+ : insets.top / 2;
52
+ };
53
+
54
+ const orientationStyles = StyleSheet.create({
55
+ landscape: { flexDirection: "row" },
56
+ portrait: { flexDirection: "column" },
57
+ });
58
+
59
+ export const directionStyles = (isTabletPortrait: boolean): ViewStyle => {
60
+ const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
61
+
62
+ return isTabletLandscape
63
+ ? orientationStyles.landscape
64
+ : orientationStyles.portrait;
65
+ };
66
+
67
+ export const getScaledPos = (
68
+ height,
69
+ vidHeight,
70
+ minimisedHeight,
71
+ isTabletPortrait
72
+ ) => {
73
+ const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
74
+
75
+ const SCALE_FACTOR = minimisedHeight / vidHeight; // Scale factor for expanded content
76
+
77
+ return (
78
+ ((isTabletLandscape ? height : vidHeight) - vidHeight * SCALE_FACTOR) / 2
79
+ );
80
+ };
81
+
82
+ export const getExtraContentPadding = (insets: {
83
+ top: number;
84
+ bottom: number;
85
+ }): ViewStyle => {
86
+ const isTablet = getIsTablet(); // not a hook, just a utility function
87
+
88
+ return {
89
+ paddingTop: isTablet ? insets.top : 0,
90
+ paddingBottom: insets.bottom,
91
+ };
92
+ };
@@ -83,7 +83,6 @@ type VideoPlayerProps = QuickBrickPlayer.PlayerProps & {
83
83
  updatePlayerState?: (state: string) => void;
84
84
  setNextVideoPreloadThresholdPercentage?: (percentage: number) => void;
85
85
  hideTransportControls?: boolean;
86
- startComponentsAnimation?: boolean;
87
86
  playableItem?: any;
88
87
  playerPluginIdentifier?: string;
89
88
  controller?: {
@@ -836,25 +835,25 @@ export default class VideoPlayer extends React.Component<
836
835
  : styles.playerContainerBlack;
837
836
 
838
837
  private getBackgroundImageStyle = (
839
- dimensions: any,
838
+ dimensions: ViewStyle,
840
839
  isAudioItem: boolean
841
- ): ViewStyle => ({
842
- ...(isAudioItem ? styles.audio : { position: "absolute" }),
843
- ...dimensions,
844
- });
840
+ ): ViewStyle[] => [
841
+ isAudioItem ? styles.audio : { position: "absolute" },
842
+ dimensions,
843
+ ];
845
844
 
846
845
  /* Returns player view style based on platform and content type (audio/video) */
847
846
  private getPlayerViewStyle = (
848
847
  dimensions: ViewStyle,
849
848
  isAudioItem: boolean
850
- ): ViewStyle => {
851
- const generalStyles = isAudioItem ? styles.audio : {};
849
+ ): ViewStyle | ViewStyle[] => {
850
+ const generalStyles = isAudioItem ? styles.audio : undefined;
852
851
 
853
852
  if (isAndroidPlatform() && isAudioItem) {
854
853
  return generalStyles;
855
854
  }
856
855
 
857
- return { ...generalStyles, ...dimensions };
856
+ return [generalStyles, dimensions];
858
857
  };
859
858
 
860
859
  private renderAudioPlayer = (
@@ -877,7 +876,7 @@ export default class VideoPlayer extends React.Component<
877
876
  shouldRender: boolean,
878
877
  imageKey: string,
879
878
  entry: ZappEntry,
880
- style: ViewStyle
879
+ style: ViewStyle | ViewStyle[]
881
880
  ) => {
882
881
  if (!shouldRender) return null;
883
882
 
@@ -888,7 +887,7 @@ export default class VideoPlayer extends React.Component<
888
887
 
889
888
  private renderNativePlayer = (
890
889
  shouldRender: boolean,
891
- style: ViewStyle,
890
+ style: ViewStyle | ViewStyle[],
892
891
  nativeEvents: ReturnType<typeof this.getNativeEvents>,
893
892
  nativeProps: ReturnType<typeof this.getNativeProps>,
894
893
  pluginConfiguration: Record<string, any>
@@ -1047,10 +1046,7 @@ export default class VideoPlayer extends React.Component<
1047
1046
  : supportsNativeControls && !this.getPlayNextData();
1048
1047
 
1049
1048
  const shouldUseNativeControls =
1050
- controls &&
1051
- !this.props.startComponentsAnimation &&
1052
- !docked &&
1053
- !castAction?.state?.connected;
1049
+ controls && !docked && !castAction?.state?.connected;
1054
1050
 
1055
1051
  platformSpecificProps = {
1056
1052
  ...platformSpecificProps,
@@ -1134,7 +1130,8 @@ export default class VideoPlayer extends React.Component<
1134
1130
  const needsToRender =
1135
1131
  !hideTransportControls &&
1136
1132
  !needToShowPlayNextOverlay &&
1137
- this.props.mode !== "PIP";
1133
+ this.props.mode !== "PIP" &&
1134
+ !docked;
1138
1135
 
1139
1136
  const supportsNativeControls =
1140
1137
  !!this.props.controller?.supportsNativeControls?.();
@@ -1145,10 +1142,7 @@ export default class VideoPlayer extends React.Component<
1145
1142
  : supportsNativeControls && !this.getPlayNextData();
1146
1143
 
1147
1144
  const shouldUseNativeControls =
1148
- controls &&
1149
- !this.props.startComponentsAnimation &&
1150
- !docked &&
1151
- !castAction?.state?.connected;
1145
+ controls && !docked && !castAction?.state?.connected;
1152
1146
 
1153
1147
  if (shouldUseNativeControls) {
1154
1148
  return null;
@@ -1271,13 +1265,13 @@ export default class VideoPlayer extends React.Component<
1271
1265
  </View>
1272
1266
  }
1273
1267
  />
1274
- ) : (
1268
+ ) : isModal ? (
1275
1269
  <VideoPlayerModal
1276
1270
  isTabletPortrait={isTabletPortrait}
1277
1271
  aspectRatio={aspectRatio}
1278
1272
  pip={piped}
1279
1273
  fullscreen={fullscreen}
1280
- modal={isModal}
1274
+ modal
1281
1275
  style={{
1282
1276
  tabletLandscapeWidth: getTabletWidth(
1283
1277
  this.getPluginConfiguration().tablet_landscape_sidebar_width,
@@ -1315,6 +1309,13 @@ export default class VideoPlayer extends React.Component<
1315
1309
  </View>
1316
1310
  }
1317
1311
  />
1312
+ ) : (
1313
+ <View style={style} testID={"player-view"}>
1314
+ <PlayerWrapper
1315
+ {...sharedWrapperViewProps}
1316
+ playerContent={this.renderPlayerContent}
1317
+ />
1318
+ </View>
1318
1319
  );
1319
1320
  };
1320
1321
 
@@ -1,82 +0,0 @@
1
- import React, { PropsWithChildren } from "react";
2
- import { Image, Animated, StyleSheet, ImageStyle } from "react-native";
3
-
4
- import {
5
- useModalAnimationContext,
6
- PlayerAnimationStateEnum,
7
- DURATION_TO_MINIMIZE,
8
- DURATION_TO_MAXIMIZE,
9
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
10
- import { PlayerAnimationStateT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/ModalAnimationContext";
11
- import { useBackgroundImage } from "@applicaster/zapp-react-native-utils/audioPlayerUtils";
12
-
13
- import { useChangePlayerState } from "./hooks";
14
-
15
- const styles = StyleSheet.create({
16
- container: {
17
- // we have to specify flex:0 and dimensions to make animation work
18
- flex: 0,
19
- aspectRatio: 1,
20
- },
21
- });
22
-
23
- type Props = PropsWithChildren<{
24
- entry: ZappEntry;
25
- style?: ImageStyle | ImageStyle[];
26
- imageWidth: number;
27
- docked: boolean;
28
- }>;
29
-
30
- export const AnimatedImage = ({ entry, style, imageWidth, docked }: Props) => {
31
- const heightAnim = React.useRef(new Animated.Value(imageWidth)).current;
32
-
33
- const backgroundImageSource = useBackgroundImage(entry);
34
-
35
- const { minimisedHeight } = useModalAnimationContext();
36
-
37
- const changePlayerState$ = useChangePlayerState({ docked });
38
-
39
- React.useEffect(() => {
40
- const subscription = changePlayerState$.subscribe({
41
- next: (nextPlayerState: PlayerAnimationStateT) => {
42
- if (nextPlayerState === PlayerAnimationStateEnum.minimize) {
43
- Animated.timing(heightAnim, {
44
- toValue: minimisedHeight,
45
- duration: DURATION_TO_MINIMIZE,
46
- useNativeDriver: false, // width/height can't use native driver
47
- }).start();
48
- }
49
-
50
- if (nextPlayerState === PlayerAnimationStateEnum.maximize) {
51
- Animated.timing(heightAnim, {
52
- toValue: imageWidth,
53
- duration: DURATION_TO_MAXIMIZE,
54
- useNativeDriver: false, // width/height can't use native driver
55
- }).start();
56
- }
57
-
58
- if (nextPlayerState === PlayerAnimationStateEnum.appear_as_docked) {
59
- // minimize image immediatly
60
- heightAnim.setValue(minimisedHeight);
61
- }
62
- },
63
- });
64
-
65
- return () => {
66
- subscription.unsubscribe();
67
- };
68
- }, [changePlayerState$, minimisedHeight, imageWidth]);
69
-
70
- return (
71
- <Animated.View
72
- style={[
73
- styles.container,
74
- {
75
- width: heightAnim,
76
- },
77
- ]}
78
- >
79
- <Image resizeMode="cover" style={style} source={backgroundImageSource} />
80
- </Animated.View>
81
- );
82
- };
@@ -1 +0,0 @@
1
- export { useChangePlayerState } from "./useChangePlayerState";
@@ -1,99 +0,0 @@
1
- import * as React from "react";
2
- import { Subject, Observable } from "rxjs";
3
-
4
- import { distinctUntilChanged } from "rxjs/operators";
5
- import { isNil } from "@applicaster/zapp-react-native-utils/utils";
6
- import { useRefWithInitialValue } from "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue";
7
- import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
8
- import {
9
- useModalAnimationContext,
10
- PlayerAnimationStateEnum,
11
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
12
- import { PlayerAnimationStateT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/ModalAnimationContext";
13
-
14
- const builder = () => {
15
- const changePlayerState$ = new Subject<PlayerAnimationStateT>();
16
-
17
- const emitMaximized = (): void => {
18
- changePlayerState$.next(PlayerAnimationStateEnum.maximize);
19
- };
20
-
21
- const emitMinimized = (): void => {
22
- changePlayerState$.next(PlayerAnimationStateEnum.minimize);
23
- };
24
-
25
- const emitAppearInDocked = (): void => {
26
- // if audio_player was presented in docked mode
27
- changePlayerState$.next(PlayerAnimationStateEnum.appear_as_docked);
28
- };
29
-
30
- return {
31
- emitMaximized,
32
- emitMinimized,
33
- emitAppearInDocked,
34
- changePlayerState$: changePlayerState$.pipe(distinctUntilChanged()),
35
- };
36
- };
37
-
38
- export const useChangePlayerState = ({
39
- docked,
40
- }): Observable<PlayerAnimationStateT> => {
41
- const changePlayerStateRef =
42
- useRefWithInitialValue<ReturnType<typeof builder>>(builder);
43
-
44
- const { playerAnimationState } = useModalAnimationContext();
45
-
46
- const previousPlayerAnimationState = usePrevious(playerAnimationState);
47
-
48
- React.useEffect(() => {
49
- if (
50
- !docked &&
51
- isNil(previousPlayerAnimationState) &&
52
- playerAnimationState === PlayerAnimationStateEnum.minimize
53
- ) {
54
- changePlayerStateRef.current.emitMinimized();
55
-
56
- return;
57
- }
58
-
59
- if (
60
- !docked &&
61
- isNil(previousPlayerAnimationState) &&
62
- playerAnimationState === PlayerAnimationStateEnum.maximize
63
- ) {
64
- changePlayerStateRef.current.emitMaximized();
65
-
66
- return;
67
- }
68
-
69
- if (
70
- !docked &&
71
- previousPlayerAnimationState === PlayerAnimationStateEnum.drag_scroll &&
72
- playerAnimationState === PlayerAnimationStateEnum.maximize
73
- ) {
74
- changePlayerStateRef.current.emitMaximized();
75
-
76
- return;
77
- }
78
-
79
- if (
80
- !docked &&
81
- previousPlayerAnimationState === PlayerAnimationStateEnum.drag_scroll &&
82
- playerAnimationState === PlayerAnimationStateEnum.minimize
83
- ) {
84
- changePlayerStateRef.current.emitMinimized();
85
-
86
- return;
87
- }
88
-
89
- if (
90
- docked &&
91
- isNil(previousPlayerAnimationState) &&
92
- isNil(playerAnimationState)
93
- ) {
94
- changePlayerStateRef.current.emitAppearInDocked();
95
- }
96
- }, [previousPlayerAnimationState, playerAnimationState, docked]);
97
-
98
- return changePlayerStateRef.current.changePlayerState$;
99
- };