@applicaster/zapp-react-native-ui-components 12.0.0-rc.3 → 12.0.0-rc.30

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.
Files changed (66) hide show
  1. package/Components/AnimatedInOut/index.tsx +18 -10
  2. package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
  3. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
  4. package/Components/AudioPlayer/helpers.tsx +1 -0
  5. package/Components/FocusableList/FocusableChild.ts +24 -14
  6. package/Components/FocusableList/FocusableItem.tsx +1 -1
  7. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  8. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  9. package/Components/FocusableList/index.tsx +26 -25
  10. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  11. package/Components/HandlePlayable/HandlePlayable.tsx +1 -1
  12. package/Components/HookRenderer/index.tsx +1 -4
  13. package/Components/Image/Image.android.tsx +33 -2
  14. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +1 -41
  15. package/Components/Layout/TV/__tests__/index.test.tsx +0 -21
  16. package/Components/Layout/TV/index.tsx +20 -36
  17. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  18. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  19. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
  20. package/Components/MasterCell/utils/index.ts +2 -2
  21. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  22. package/Components/ModalComponent/Button/Item.tsx +82 -0
  23. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  24. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  25. package/Components/ModalComponent/Button/assets.ts +4 -0
  26. package/Components/ModalComponent/Button/index.tsx +111 -0
  27. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  28. package/Components/ModalComponent/Header/Title.tsx +70 -0
  29. package/Components/ModalComponent/Header/assets.ts +4 -0
  30. package/Components/ModalComponent/Header/index.tsx +71 -0
  31. package/Components/ModalComponent/Header/utils.ts +79 -0
  32. package/Components/ModalComponent/index.tsx +38 -0
  33. package/Components/ModalComponent/utils.ts +126 -0
  34. package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +4 -7
  35. package/Components/River/ComponentsMap/ComponentsMap.tsx +25 -0
  36. package/Components/River/River.tsx +8 -5
  37. package/Components/River/TV/River.tsx +2 -2
  38. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  39. package/Components/River/useScreenConfiguration.ts +5 -6
  40. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  41. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  42. package/Components/RouteManager/index.tsx +4 -2
  43. package/Components/Screen/__tests__/Screen.test.tsx +43 -35
  44. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +10 -6
  45. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  46. package/Components/Screen/index.tsx +84 -45
  47. package/Components/Screen/navigationHandler.ts +0 -82
  48. package/Components/Screen/orientationHandler.ts +1 -1
  49. package/Components/ScreenResolver/index.tsx +1 -1
  50. package/Components/TrackedView/index.tsx +6 -3
  51. package/Components/VideoLive/LiveImageManager.ts +42 -13
  52. package/Components/VideoLive/PlayerLiveImageComponent.tsx +79 -73
  53. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  54. package/Components/VideoModal/PlayerWrapper.tsx +66 -63
  55. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  56. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +4 -4
  57. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +10 -18
  58. package/Components/VideoModal/hooks/useModalSize.ts +13 -4
  59. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  60. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  61. package/Components/ZappUIComponent/index.tsx +22 -12
  62. package/Components/index.js +2 -0
  63. package/Contexts/ScreenContext/index.tsx +1 -4
  64. package/Decorators/RiverResolver/index.tsx +0 -4
  65. package/Decorators/index.tsx +0 -4
  66. package/package.json +5 -6
@@ -6,6 +6,7 @@ import {
6
6
  import { setUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
7
7
  import { loggerLiveImageManager } from "./loggerHelper";
8
8
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
9
+ import { Component } from "react";
9
10
 
10
11
  const { log_debug, log_info, log_error } = loggerLiveImageManager;
11
12
 
@@ -36,7 +37,8 @@ type Position = {
36
37
  type LiveImageProps = {
37
38
  player: Player;
38
39
  playerId: string;
39
- setMode: (type: LiveImageType) => void;
40
+ setMode?: (type: LiveImageType) => void;
41
+ component: Component;
40
42
  // TODO: ...primary, powerCell, tvGallery, etc.
41
43
  // type: string;
42
44
  };
@@ -164,7 +166,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
164
166
 
165
167
  // Fake close event, because we unmount native view
166
168
  item.player?.onPlayerClose();
167
- item.setMode(LiveImageType.Image);
169
+ item.setMode?.(LiveImageType.Image);
168
170
 
169
171
  if (item === this.currentlyPlaying) {
170
172
  this.currentlyPlaying = null;
@@ -191,8 +193,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
191
193
  }
192
194
 
193
195
  this.currentlyPlaying = item;
194
-
195
- item.setMode(LiveImageType.Video);
196
+ item.setMode?.(LiveImageType.Video);
196
197
 
197
198
  if (item.player.playerState.isReadyToPlay) {
198
199
  item.player.play();
@@ -209,6 +210,11 @@ export class LiveImageManager implements PlayerLifecycleListener {
209
210
  this.pauseItem(item);
210
211
  };
211
212
 
213
+ public onLiveImageCompleted = (_item: LiveImage) => {
214
+ // TODO: Notify listeners that player has died
215
+ // Do not try look for new playable, otherwise you will restart video finish to play
216
+ };
217
+
212
218
  public muteAll = () => {
213
219
  log_debug("muteAll");
214
220
 
@@ -235,6 +241,14 @@ export class LiveImageManager implements PlayerLifecycleListener {
235
241
  const playerItem = this.findNextPlayableItem();
236
242
 
237
243
  if (playerItem) {
244
+ if (!playerItem.isFullyVisible) {
245
+ log_error(
246
+ `checkPlayerPosition: trying to start playback currently invisible item: ${playerInfo(
247
+ playerItem.player
248
+ )}`
249
+ );
250
+ }
251
+
238
252
  // Will also check if it's item that already playing
239
253
  this.playLiveImage(playerItem);
240
254
  }
@@ -242,7 +256,6 @@ export class LiveImageManager implements PlayerLifecycleListener {
242
256
 
243
257
  onPrimaryPlayerClosed = () => {
244
258
  const playerItem = this.findNextPlayableItem();
245
-
246
259
  log_info("onPrimaryPlayerClosed: starting to play visible live-image");
247
260
 
248
261
  this.currentlyPlaying = null;
@@ -356,12 +369,12 @@ export class LiveImageManager implements PlayerLifecycleListener {
356
369
  // TODO: This branch was used when we had play button to toggle replay.
357
370
  // Now we mute button instead but we keep it just in case.
358
371
  if (IS_ALLOWED_REPLAY && !isTV() && isCurrentItemEnded) {
359
- this.currentlyPlaying.player.seekTo(0);
360
- this.currentlyPlaying.player.pause();
372
+ this.currentlyPlaying?.player.seekTo(0);
373
+ this.currentlyPlaying?.player.pause();
361
374
 
362
375
  // TODO: ...Maybe player some other item
363
376
  } else {
364
- item.setMode(LiveImageType.Image);
377
+ item.setMode?.(LiveImageType.Image);
365
378
  }
366
379
 
367
380
  // Prevent receiving onEnd event from both `close` and `end` player events
@@ -377,10 +390,25 @@ export class LiveImageManager implements PlayerLifecycleListener {
377
390
  };
378
391
 
379
392
  onLiveImageError = (item: LiveImage, error: Error) => {
380
- item.setMode(LiveImageType.Image);
393
+ item.setMode?.(LiveImageType.Image);
381
394
 
382
- if (this.currentlyPlaying === item) {
395
+ const currentItem = this.currentlyPlaying;
396
+
397
+ log_debug(
398
+ `onLiveImageError: error: ${error.message}, live-image ${playerInfo(
399
+ item.player
400
+ )}, currentPlayingId: ${
401
+ this.currentlyPlaying?.playerId
402
+ }, primaryPlayerId: ${this.primaryPlayer?.playerId}`
403
+ );
404
+
405
+ if (currentItem === item) {
383
406
  this.currentlyPlaying = null;
407
+
408
+ log_debug(
409
+ `onLiveImageError: currentitem: ${currentItem.playerId} was removed`
410
+ );
411
+
384
412
  // TODO: ...Maybe player some other item
385
413
  }
386
414
 
@@ -389,8 +417,8 @@ export class LiveImageManager implements PlayerLifecycleListener {
389
417
  event: {
390
418
  item,
391
419
  error,
392
- playerId: this.currentlyPlaying?.playerId,
393
- primaryPlayerId: this.primaryPlayer?.playerId,
420
+ playerId: currentItem?.playerId,
421
+ primaryPlayerId: currentItem?.playerId,
394
422
  },
395
423
  });
396
424
  };
@@ -446,12 +474,13 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
446
474
  };
447
475
 
448
476
  readonly playerId: string;
477
+ readonly component: Component;
449
478
 
450
479
  constructor(props: LiveImageProps) {
451
480
  this.player = props.player;
452
481
  this.setMode = props.setMode;
453
482
  this.playerId = this.player.playerId;
454
-
483
+ this.component = props.component;
455
484
  this.player.addListener({ id: "live-image", listener: this });
456
485
  }
457
486
 
@@ -1,7 +1,6 @@
1
1
  // /// <reference types="@applicaster/applicaster-types" />
2
2
  //
3
3
  import * as React from "react";
4
- import * as R from "ramda";
5
4
 
6
5
  import { AppState, AppStateStatus } from "react-native";
7
6
  import { TrackedView } from "../TrackedView";
@@ -9,7 +8,6 @@ import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/l
9
8
 
10
9
  import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
11
10
 
12
- import { BufferAnimation } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/BufferAnimation";
13
11
  import {
14
12
  isApplePlatform,
15
13
  isTV,
@@ -25,12 +23,13 @@ import { loggerLiveImageComponent } from "./loggerHelper";
25
23
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
26
24
  import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/conts";
27
25
  import { getAutoplaySettings } from "./utils";
26
+ import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
27
+ import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
28
28
 
29
29
  const { log_error } = loggerLiveImageComponent;
30
30
 
31
- const isMeasurement = (item) => {
32
- return item.id.startsWith("pre-measurement-");
33
- };
31
+ const isMeasurement = (item: ZappEntry) =>
32
+ isString(item.id) && item.id.startsWith("pre-measurement-");
34
33
 
35
34
  type Props = {
36
35
  item: ZappEntry;
@@ -55,69 +54,66 @@ const PlayerLiveImageComponent = (props: Props) => {
55
54
  isTV() ? false : getUserCellPlayerMutedPreference(props.audioMutedByDefault)
56
55
  );
57
56
 
58
- const [PlayerViewComponent, setPlayerViewComponent] = React.useState(null);
59
- const Player: any = PlayerViewComponent || BufferAnimation;
60
-
61
57
  const ref = React.useRef(null);
62
58
 
63
- const liveImageItem: LiveImage = React.useMemo(() => {
64
- /**
65
- * Debounced setMode function.
66
- *
67
- * Sets to video with a 1sec delay. Set to image happens immediately and cancels the timeout.
68
- *
69
- * @param type video or image
70
- */
71
- const setModeDebounced = (type: LiveImageType) => {
72
- if (type === LiveImageType.Video) {
73
- if (type === mode) {
74
- return;
75
- }
76
-
77
- timeoutRef.current = setTimeout(() => {
78
- setMode(type);
79
- }, 1000) as unknown as NodeJS.Timeout;
80
- } else {
81
- if (timeoutRef.current) {
82
- clearTimeout(timeoutRef.current);
83
- }
59
+ /**
60
+ * Debounced setMode function.
61
+ *
62
+ * Sets to video with a 1sec delay. Set to image happens immediately and cancels the timeout.
63
+ *
64
+ * @param type video or image
65
+ */
66
+ const setModeDebounced = React.useCallback((type: LiveImageType) => {
67
+ if (type === LiveImageType.Video) {
68
+ if (type === mode) {
69
+ return;
70
+ }
84
71
 
72
+ timeoutRef.current = setTimeout(() => {
85
73
  setMode(type);
74
+ }, 1000) as unknown as NodeJS.Timeout;
75
+ } else {
76
+ if (timeoutRef.current) {
77
+ clearTimeout(timeoutRef.current);
78
+ timeoutRef.current = null;
86
79
  }
87
- };
88
80
 
81
+ setMode(type);
82
+ }
83
+ }, [mode]);
84
+
85
+ const { screenConfig, playerPluginId } = props;
86
+
87
+ const liveImageItem: LiveImage = React.useMemo(() => {
89
88
  const playerFactoryItem = playerFactory({
90
89
  player: ref,
91
- listener: props as Record<string, any>,
92
90
  playerId,
93
91
  autoplay: false,
94
92
  entry: item,
95
- muted,
96
- playerPluginId: props?.playerPluginId,
97
- screenConfig: props?.screenConfig,
93
+ muted, // Initial muted state, not needed in dependencies
94
+ playerPluginId: playerPluginId,
95
+ screenConfig: screenConfig,
98
96
  playerRole: PlayerRole.Cell,
99
97
  });
100
98
 
101
- const Component = playerFactoryItem?.Component;
102
-
103
- if (!R.isNil(Component) && Component !== PlayerViewComponent) {
104
- setPlayerViewComponent(Component);
105
- }
106
-
107
99
  if (playerFactoryItem) {
108
100
  return new LiveImage({
109
101
  playerId,
110
102
  player: playerFactoryItem.controller,
111
- setMode: setModeDebounced,
103
+ component: playerFactoryItem?.Component
112
104
  });
113
105
  } else {
114
106
  throw new Error("Player factory item is null");
115
107
  }
116
- }, [playerId, item?.id]);
108
+ }, [playerId, item, playerPluginId, screenConfig]);
109
+
110
+ React.useEffect(() => {
111
+ liveImageItem.setMode = setModeDebounced;
112
+ }, [setModeDebounced, liveImageItem]);
117
113
 
118
114
  const { start, end } = React.useMemo(
119
115
  () => getAutoplaySettings(item),
120
- [item?.id]
116
+ [item]
121
117
  );
122
118
 
123
119
  const controller = liveImageItem.getPlayer();
@@ -127,6 +123,10 @@ const PlayerLiveImageComponent = (props: Props) => {
127
123
  ref.current = component;
128
124
  };
129
125
 
126
+ const onLiveImageCompleted = React.useCallback(() => {
127
+ LiveImageManager.instance.onLiveImageCompleted(liveImageItem);
128
+ }, [liveImageItem]);
129
+
130
130
  const onStop = React.useCallback(() => {
131
131
  LiveImageManager.instance.pauseLiveImage(liveImageItem);
132
132
  }, [liveImageItem]);
@@ -140,13 +140,14 @@ const PlayerLiveImageComponent = (props: Props) => {
140
140
  const unregister = LiveImageManager.instance.register(liveImageItem);
141
141
 
142
142
  return () => {
143
- unregister();
144
-
145
143
  if (timeoutRef.current) {
146
144
  clearTimeout(timeoutRef.current);
145
+ timeoutRef.current = null;
147
146
  }
147
+
148
+ unregister();
148
149
  };
149
- }, [liveImageItem, item]);
150
+ }, [item, liveImageItem]);
150
151
 
151
152
  React.useEffect(() => {
152
153
  if (!player) {
@@ -178,11 +179,12 @@ const PlayerLiveImageComponent = (props: Props) => {
178
179
  setMuted(false);
179
180
  },
180
181
  onPlayerClose: () => {
182
+ onLiveImageCompleted();
181
183
  setIsReady(false);
182
184
  },
183
185
  },
184
186
  });
185
- }, [player, onStop]);
187
+ }, [player, onStop, onLiveImageCompleted, start, end]);
186
188
 
187
189
  React.useEffect(() => {
188
190
  const subscription = AppState.addEventListener(
@@ -233,40 +235,43 @@ const PlayerLiveImageComponent = (props: Props) => {
233
235
  };
234
236
  }
235
237
  }
236
- }, [liveImageItem]);
238
+ }, [liveImageItem, playerId, controller]);
237
239
 
238
- const onPositionUpdated = (data) => {
239
- const normalizedRect = (rect) => {
240
- if (!rect) {
241
- return null;
242
- }
240
+ const onPositionUpdated = React.useCallback(
241
+ (data) => {
242
+ const normalizedRect = (rect: {left: number, right: number, top: number, bottom: number }) => {
243
+ if (!rect) {
244
+ return null;
245
+ }
243
246
 
244
- const { left, right, top, bottom } = rect;
247
+ const { left, right, top, bottom } = rect;
245
248
 
246
- return {
247
- left: left / dimensions.width,
248
- right: right / dimensions.width,
249
- top: top / dimensions.height,
250
- bottom: bottom / dimensions.height,
251
- centerX: (left + right) / 2 / dimensions.width,
252
- centerY: (top + bottom) / 2 / dimensions.height,
249
+ return {
250
+ left: left / dimensions.width,
251
+ right: right / dimensions.width,
252
+ top: top / dimensions.height,
253
+ bottom: bottom / dimensions.height,
254
+ centerX: (left + right) / 2 / dimensions.width,
255
+ centerY: (top + bottom) / 2 / dimensions.height,
256
+ };
253
257
  };
254
- };
255
258
 
256
- liveImageItem.position = normalizedRect(data.rect);
259
+ liveImageItem.position = normalizedRect(data.rect);
257
260
 
258
- const newIsFullyVisible = !!data.rect;
261
+ const newIsFullyVisible = !!data.rect;
259
262
 
260
- if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
261
- liveImageItem.isFullyVisible = newIsFullyVisible;
263
+ if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
264
+ liveImageItem.isFullyVisible = newIsFullyVisible;
262
265
 
263
- liveImageItem.isFullyVisible
264
- ? LiveImageManager.instance.onViewportEnter(liveImageItem)
265
- : LiveImageManager.instance.onViewportLeave(liveImageItem);
266
- } else {
267
- LiveImageManager.instance.checkPlayerPosition(liveImageItem);
268
- }
269
- };
266
+ liveImageItem.isFullyVisible
267
+ ? LiveImageManager.instance.onViewportEnter(liveImageItem)
268
+ : LiveImageManager.instance.onViewportLeave(liveImageItem);
269
+ } else {
270
+ LiveImageManager.instance.checkPlayerPosition(liveImageItem);
271
+ }
272
+ },
273
+ [liveImageItem, dimensions]
274
+ );
270
275
 
271
276
  const platformSpecificProps = isApplePlatform()
272
277
  ? { hideNativeControls: true, controls: false }
@@ -276,6 +281,7 @@ const PlayerLiveImageComponent = (props: Props) => {
276
281
  const isVideoMode = mode === LiveImageType.Video;
277
282
  const isBackgroundImageVisible = isImageMode || !isReadyToPlay;
278
283
  const videoStyles = { ...style, position: "absolute", zIndex: -100 };
284
+ const Player: any = liveImageItem.component || BufferAnimation;
279
285
 
280
286
  return (
281
287
  <TrackedView
@@ -23,6 +23,8 @@ const containerStyle = ({
23
23
  backgroundColor: modal_background_color,
24
24
  });
25
25
 
26
+ // const audioMarginStyle = { marginTop: 0, marginBottom: 0 };
27
+
26
28
  export const PlayerDetails = ({
27
29
  entry,
28
30
  style,
@@ -75,6 +77,7 @@ export const PlayerDetails = ({
75
77
  transform: [{ translateY }],
76
78
  opacity,
77
79
  },
80
+ // isAudioPlayer && audioMarginStyle,
78
81
  ]}
79
82
  >
80
83
  {screenData && (
@@ -1,18 +1,24 @@
1
1
  import * as React from "react";
2
- import { Platform, StyleSheet, View, ViewStyle } from "react-native";
2
+ import {
3
+ Dimensions,
4
+ Platform,
5
+ StyleSheet,
6
+ View,
7
+ ViewStyle,
8
+ } from "react-native";
3
9
  import { Edge, SafeAreaView } from "react-native-safe-area-context";
4
10
 
5
11
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
6
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device";
12
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
7
13
  import { PlayerDetails } from "./PlayerDetails";
8
14
  import { playerDimesionsHack } from "./utils";
9
15
  import { PathnameContext } from "../../Contexts/PathnameContext";
10
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
11
16
  import { ScreenContextProvider } from "../../Contexts/ScreenContext";
12
17
 
13
- type Dimensions = {
14
- width: number;
15
- height: number;
18
+ type DimensionsT = {
19
+ width: number | string;
20
+ height: number | string;
21
+ aspectRatio?: number;
16
22
  };
17
23
 
18
24
  type Configuration = {
@@ -23,14 +29,15 @@ type Configuration = {
23
29
 
24
30
  type Props = {
25
31
  entry: ZappEntry;
26
- style: ViewStyle & Dimensions;
32
+ style: ViewStyle & DimensionsT;
27
33
  containerStyle?: ViewStyle;
28
34
  inline?: boolean;
29
35
  docked?: boolean;
36
+ pip?: boolean;
30
37
  isModal?: boolean;
31
38
  fullscreen?: boolean;
32
39
  isTabletPortrait?: boolean;
33
- children: (playerDimensions: Dimensions) => React.ReactNode;
40
+ children: (playerDimensions: DimensionsT) => React.ReactNode;
34
41
  configuration: Configuration;
35
42
  };
36
43
 
@@ -52,6 +59,15 @@ const directionStyles = (isTabletLandscape: boolean): ViewStyle => {
52
59
  return orientationStyles.portrait;
53
60
  };
54
61
 
62
+ const getScreenAspectRatio = () => {
63
+ const { width, height } = Dimensions.get("screen");
64
+
65
+ const longEdge = Math.max(width, height);
66
+ const shortEdge = Math.min(width, height);
67
+
68
+ return longEdge / shortEdge;
69
+ };
70
+
55
71
  const safeAreaStyles = (
56
72
  configuration: Configuration,
57
73
  isTablet: boolean
@@ -66,34 +82,6 @@ const safeAreaStyles = (
66
82
  };
67
83
  };
68
84
 
69
- const getTabletWidth = (
70
- configuration: Configuration,
71
- dimensions: Dimensions
72
- ) => {
73
- const tablet_landscape_sidebar_width =
74
- configuration?.tablet_landscape_sidebar_width;
75
-
76
- const { width } = dimensions;
77
-
78
- const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
79
-
80
- if (tablet_landscape_sidebar_width?.includes("%")) {
81
- return width * (1 - sidebarWidth / 100);
82
- }
83
-
84
- if (Number.isNaN(sidebarWidth)) {
85
- return width * 0.65;
86
- }
87
-
88
- return width - sidebarWidth;
89
- };
90
-
91
- export const defaultAspectRatioHeight = (width: number): number =>
92
- (width / 16) * 9;
93
-
94
- export const defaultAspectRatioWidth = (height: number): number =>
95
- (height / 9) * 16;
96
-
97
85
  const getEdges = (
98
86
  isTablet: boolean,
99
87
  docked: boolean,
@@ -115,6 +103,28 @@ const getEdges = (
115
103
  return ["top"];
116
104
  };
117
105
 
106
+ const getTabletWidth = (
107
+ configuration: Configuration,
108
+ dimensions: DimensionsT
109
+ ) => {
110
+ const tablet_landscape_sidebar_width =
111
+ configuration?.tablet_landscape_sidebar_width;
112
+
113
+ const { width } = dimensions;
114
+
115
+ const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
116
+
117
+ if (tablet_landscape_sidebar_width?.includes("%")) {
118
+ return Number(width) * (1 - sidebarWidth / 100);
119
+ }
120
+
121
+ if (Number.isNaN(sidebarWidth)) {
122
+ return Number(width) * 0.65;
123
+ }
124
+
125
+ return Number(width) - sidebarWidth;
126
+ };
127
+
118
128
  export const PlayerWrapper = (props: Props) => {
119
129
  const {
120
130
  entry,
@@ -126,6 +136,7 @@ export const PlayerWrapper = (props: Props) => {
126
136
  children,
127
137
  isTabletPortrait,
128
138
  configuration,
139
+ pip,
129
140
  } = props;
130
141
 
131
142
  const isTablet = useIsTablet();
@@ -136,40 +147,38 @@ export const PlayerWrapper = (props: Props) => {
136
147
 
137
148
  const tabletWidth = getTabletWidth(configuration, style);
138
149
 
139
- const { width: screenWidth } = useDimensions("screen");
140
-
141
- const containerDimensions: Dimensions = React.useMemo(
150
+ const baseDimensions: DimensionsT = React.useMemo(
142
151
  () => ({
143
152
  width:
144
- isInlineModal && !docked && isTabletLandscape
145
- ? tabletWidth
146
- : style.width,
147
- height:
148
- isInlineModal && !docked
149
- ? defaultAspectRatioHeight(
150
- isTabletLandscape ? tabletWidth : screenWidth
151
- )
152
- : style.height,
153
+ isInlineModal && !docked && isTabletLandscape ? tabletWidth : "100%",
154
+ height: isInlineModal && docked ? style.height : undefined,
153
155
  }),
154
- [isInlineModal, docked, isTabletLandscape, tabletWidth, style, screenWidth]
156
+ [isInlineModal, tabletWidth, style.height, docked]
155
157
  );
156
158
 
157
- const playerDimensions: Dimensions = React.useMemo(
159
+ const playerDimensions: DimensionsT = React.useMemo(
158
160
  () => ({
159
- width:
160
- isInlineModal && docked
161
- ? defaultAspectRatioWidth(containerDimensions.height)
162
- : containerDimensions.width,
163
- height: containerDimensions.height,
161
+ ...baseDimensions,
162
+ width: isInlineModal && docked ? undefined : baseDimensions.width,
163
+ aspectRatio: !isInlineModal && !pip ? getScreenAspectRatio() : 16 / 9,
164
+ }),
165
+ [baseDimensions, isInlineModal, pip]
166
+ );
167
+
168
+ const containerDimensions: DimensionsT = React.useMemo(
169
+ () => ({
170
+ ...baseDimensions,
171
+ aspectRatio:
172
+ isInlineModal && docked ? undefined : playerDimensions.aspectRatio,
164
173
  }),
165
- [isInlineModal, docked, containerDimensions]
174
+ [baseDimensions, isInlineModal, docked, playerDimensions.aspectRatio]
166
175
  );
167
176
 
168
177
  const WrapperView = React.useMemo(() => (isTV() ? View : SafeAreaView), []);
169
178
 
170
179
  const childrenStyles = React.useMemo(
171
180
  () => ({ ...playerDimensions, ...playerDimesionsHack }),
172
- [playerDimensions, playerDimesionsHack]
181
+ [containerDimensions, playerDimesionsHack]
173
182
  );
174
183
 
175
184
  return (
@@ -190,12 +199,6 @@ export const PlayerWrapper = (props: Props) => {
190
199
  defaultStyles.playerContainer,
191
200
  containerDimensions,
192
201
  containerStyle,
193
- {
194
- height:
195
- isInlineModal && !docked
196
- ? containerDimensions.height + 10
197
- : containerDimensions.height,
198
- },
199
202
  playerDimesionsHack,
200
203
  ]}
201
204
  >
@@ -8,8 +8,6 @@ const props = {
8
8
  configuration: { modal_background_color: "transparent" },
9
9
  };
10
10
 
11
- jest.mock("react-native");
12
-
13
11
  jest.mock("react-native-safe-area-context", () => ({
14
12
  useSafeAreaInsets: jest.fn(() => ({
15
13
  top: 20,
@@ -19,8 +19,6 @@ const props = {
19
19
 
20
20
  const useIsTablet = jest.fn();
21
21
 
22
- jest.mock("react-native");
23
-
24
22
  jest.mock("../PlayerDetails", () => ({ PlayerDetails: View }));
25
23
 
26
24
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/device", () => ({
@@ -38,6 +36,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactUtils", () => ({
38
36
  }));
39
37
 
40
38
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
39
+ isNavBarVisible: jest.fn(() => true),
41
40
  useRoute: jest.fn(() => ({
42
41
  pathname: "/river/testId",
43
42
  })),
@@ -50,7 +49,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
50
49
 
51
50
  jest.mock("../utils", () => ({ playerDimesionsHack: {} }));
52
51
 
53
- const { PlayerWrapper, defaultAspectRatioWidth } = require("../PlayerWrapper");
52
+ const { PlayerWrapper } = require("../PlayerWrapper");
54
53
 
55
54
  jest.useFakeTimers();
56
55
  const children = jest.fn(() => {});
@@ -110,7 +109,8 @@ describe("PlayerWrapper", () => {
110
109
 
111
110
  const expectDimensions = {
112
111
  ...dimensions,
113
- width: defaultAspectRatioWidth(dimensions.height),
112
+ width: undefined,
113
+ aspectRatio: 16 / 9,
114
114
  };
115
115
 
116
116
  expect(element).toMatchSnapshot();