@applicaster/zapp-react-native-ui-components 12.0.0-rc.4 → 12.0.0-rc.41

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 (83) 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/Cell/Cell.tsx +2 -2
  6. package/Components/Cell/CellWithFocusable.tsx +21 -14
  7. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  8. package/Components/ErrorScreen/index.tsx +1 -1
  9. package/Components/FocusableCell/index.tsx +7 -7
  10. package/Components/FocusableList/FocusableChild.ts +24 -14
  11. package/Components/FocusableList/FocusableItem.tsx +1 -1
  12. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  13. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  14. package/Components/FocusableList/index.tsx +26 -25
  15. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  16. package/Components/HandlePlayable/HandlePlayable.tsx +1 -1
  17. package/Components/HookRenderer/index.tsx +1 -6
  18. package/Components/Image/Image.android.tsx +11 -2
  19. package/Components/Image/Image.tsx +18 -2
  20. package/Components/Image/utils/index.ts +39 -0
  21. package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
  22. package/Components/Layout/TV/index.tsx +20 -36
  23. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  24. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  25. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  26. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  27. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +3 -1
  28. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  29. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  30. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
  31. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  32. package/Components/ModalComponent/Button/Item.tsx +82 -0
  33. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  34. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  35. package/Components/ModalComponent/Button/assets.ts +4 -0
  36. package/Components/ModalComponent/Button/index.tsx +111 -0
  37. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  38. package/Components/ModalComponent/Header/Title.tsx +70 -0
  39. package/Components/ModalComponent/Header/assets.ts +4 -0
  40. package/Components/ModalComponent/Header/index.tsx +71 -0
  41. package/Components/ModalComponent/Header/utils.ts +79 -0
  42. package/Components/ModalComponent/index.tsx +38 -0
  43. package/Components/ModalComponent/utils.ts +126 -0
  44. package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +4 -7
  45. package/Components/PlayerContainer/PlayerContainer.tsx +52 -28
  46. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  47. package/Components/River/ComponentsMap/ComponentsMap.tsx +25 -0
  48. package/Components/River/River.tsx +8 -5
  49. package/Components/River/TV/River.tsx +2 -2
  50. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  51. package/Components/River/__tests__/componentsMap.test.js +1 -0
  52. package/Components/River/useScreenConfiguration.ts +5 -6
  53. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  54. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  55. package/Components/RouteManager/index.tsx +5 -3
  56. package/Components/Screen/__tests__/Screen.test.tsx +48 -36
  57. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +20 -6
  58. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  59. package/Components/Screen/index.tsx +91 -43
  60. package/Components/Screen/navigationHandler.ts +0 -82
  61. package/Components/Screen/orientationHandler.ts +1 -1
  62. package/Components/ScreenResolver/index.tsx +1 -1
  63. package/Components/Tabs/TV/styles.ts +1 -1
  64. package/Components/TrackedView/index.tsx +6 -3
  65. package/Components/VideoLive/LiveImageManager.ts +42 -13
  66. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  67. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +30 -3
  68. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +22 -27
  69. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  70. package/Components/VideoModal/PlayerWrapper.tsx +66 -63
  71. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  72. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +4 -4
  73. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +202 -162
  74. package/Components/VideoModal/hooks/useModalSize.ts +13 -4
  75. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  76. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  77. package/Components/ZappUIComponent/index.tsx +22 -12
  78. package/Components/index.js +2 -0
  79. package/Contexts/ScreenContext/index.tsx +1 -4
  80. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  81. package/Decorators/RiverResolver/index.tsx +0 -4
  82. package/Decorators/index.tsx +0 -4
  83. package/package.json +5 -6
@@ -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,14 +8,13 @@ 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,
16
14
  } from "@applicaster/zapp-react-native-utils/reactUtils";
17
15
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
18
16
  import { getUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
19
- import { PlayerImageBackground } from "../PlayerImageBackground";
17
+ import Image from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/DefaultComponents/Image";
20
18
  import { LiveImage, LiveImageManager, LiveImageType } from "./LiveImageManager";
21
19
 
22
20
  import { AnimatedInOut } from "@applicaster/zapp-react-native-ui-components/Components/AnimatedInOut";
@@ -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;
@@ -40,12 +39,13 @@ type Props = {
40
39
  imageKey?: string;
41
40
  screenConfig: Record<string, any>;
42
41
  audioMutedByDefault?: boolean;
42
+ uri: string; // cover image url
43
43
  };
44
44
 
45
45
  const PlayerLiveImageComponent = (props: Props) => {
46
46
  const dimensions = useDimensions("screen", { fullDimensions: true });
47
47
 
48
- const { item, style, playerId, imageKey } = props;
48
+ const { item, style, playerId } = props;
49
49
 
50
50
  const timeoutRef = React.useRef<NodeJS.Timeout | null>(null);
51
51
  const [mode, setMode] = React.useState(LiveImageType.Image);
@@ -55,20 +55,17 @@ const PlayerLiveImageComponent = (props: Props) => {
55
55
  isTV() ? false : getUserCellPlayerMutedPreference(props.audioMutedByDefault)
56
56
  );
57
57
 
58
- const [PlayerViewComponent, setPlayerViewComponent] = React.useState(null);
59
- const Player: any = PlayerViewComponent || BufferAnimation;
60
-
61
58
  const ref = React.useRef(null);
62
59
 
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) => {
60
+ /**
61
+ * Debounced setMode function.
62
+ *
63
+ * Sets to video with a 1sec delay. Set to image happens immediately and cancels the timeout.
64
+ *
65
+ * @param type video or image
66
+ */
67
+ const setModeDebounced = React.useCallback(
68
+ (type: LiveImageType) => {
72
69
  if (type === LiveImageType.Video) {
73
70
  if (type === mode) {
74
71
  return;
@@ -80,45 +77,45 @@ const PlayerLiveImageComponent = (props: Props) => {
80
77
  } else {
81
78
  if (timeoutRef.current) {
82
79
  clearTimeout(timeoutRef.current);
80
+ timeoutRef.current = null;
83
81
  }
84
82
 
85
83
  setMode(type);
86
84
  }
87
- };
85
+ },
86
+ [mode]
87
+ );
88
+
89
+ const { screenConfig, playerPluginId } = props;
88
90
 
91
+ const liveImageItem: LiveImage = React.useMemo(() => {
89
92
  const playerFactoryItem = playerFactory({
90
93
  player: ref,
91
- listener: props as Record<string, any>,
92
94
  playerId,
93
95
  autoplay: false,
94
96
  entry: item,
95
- muted,
96
- playerPluginId: props?.playerPluginId,
97
- screenConfig: props?.screenConfig,
97
+ muted, // Initial muted state, not needed in dependencies
98
+ playerPluginId: playerPluginId,
99
+ screenConfig: screenConfig,
98
100
  playerRole: PlayerRole.Cell,
99
101
  });
100
102
 
101
- const Component = playerFactoryItem?.Component;
102
-
103
- if (!R.isNil(Component) && Component !== PlayerViewComponent) {
104
- setPlayerViewComponent(Component);
105
- }
106
-
107
103
  if (playerFactoryItem) {
108
104
  return new LiveImage({
109
105
  playerId,
110
106
  player: playerFactoryItem.controller,
111
- setMode: setModeDebounced,
107
+ component: playerFactoryItem?.Component,
112
108
  });
113
109
  } else {
114
110
  throw new Error("Player factory item is null");
115
111
  }
116
- }, [playerId, item?.id]);
112
+ }, [playerId, item, playerPluginId, screenConfig]);
117
113
 
118
- const { start, end } = React.useMemo(
119
- () => getAutoplaySettings(item),
120
- [item?.id]
121
- );
114
+ React.useEffect(() => {
115
+ liveImageItem.setMode = setModeDebounced;
116
+ }, [setModeDebounced, liveImageItem]);
117
+
118
+ const { start, end } = React.useMemo(() => getAutoplaySettings(item), [item]);
122
119
 
123
120
  const controller = liveImageItem.getPlayer();
124
121
  const player = usePlayer(playerId);
@@ -127,6 +124,10 @@ const PlayerLiveImageComponent = (props: Props) => {
127
124
  ref.current = component;
128
125
  };
129
126
 
127
+ const onLiveImageCompleted = React.useCallback(() => {
128
+ LiveImageManager.instance.onLiveImageCompleted(liveImageItem);
129
+ }, [liveImageItem]);
130
+
130
131
  const onStop = React.useCallback(() => {
131
132
  LiveImageManager.instance.pauseLiveImage(liveImageItem);
132
133
  }, [liveImageItem]);
@@ -140,13 +141,14 @@ const PlayerLiveImageComponent = (props: Props) => {
140
141
  const unregister = LiveImageManager.instance.register(liveImageItem);
141
142
 
142
143
  return () => {
143
- unregister();
144
-
145
144
  if (timeoutRef.current) {
146
145
  clearTimeout(timeoutRef.current);
146
+ timeoutRef.current = null;
147
147
  }
148
+
149
+ unregister();
148
150
  };
149
- }, [liveImageItem, item]);
151
+ }, [item, liveImageItem]);
150
152
 
151
153
  React.useEffect(() => {
152
154
  if (!player) {
@@ -178,11 +180,12 @@ const PlayerLiveImageComponent = (props: Props) => {
178
180
  setMuted(false);
179
181
  },
180
182
  onPlayerClose: () => {
183
+ onLiveImageCompleted();
181
184
  setIsReady(false);
182
185
  },
183
186
  },
184
187
  });
185
- }, [player, onStop]);
188
+ }, [player, onStop, onLiveImageCompleted, start, end]);
186
189
 
187
190
  React.useEffect(() => {
188
191
  const subscription = AppState.addEventListener(
@@ -233,40 +236,48 @@ const PlayerLiveImageComponent = (props: Props) => {
233
236
  };
234
237
  }
235
238
  }
236
- }, [liveImageItem]);
237
-
238
- const onPositionUpdated = (data) => {
239
- const normalizedRect = (rect) => {
240
- if (!rect) {
241
- return null;
242
- }
239
+ }, [liveImageItem, playerId, controller]);
240
+
241
+ const onPositionUpdated = React.useCallback(
242
+ (data) => {
243
+ const normalizedRect = (rect: {
244
+ left: number;
245
+ right: number;
246
+ top: number;
247
+ bottom: number;
248
+ }) => {
249
+ if (!rect) {
250
+ return null;
251
+ }
243
252
 
244
- const { left, right, top, bottom } = rect;
253
+ const { left, right, top, bottom } = rect;
245
254
 
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,
255
+ return {
256
+ left: left / dimensions.width,
257
+ right: right / dimensions.width,
258
+ top: top / dimensions.height,
259
+ bottom: bottom / dimensions.height,
260
+ centerX: (left + right) / 2 / dimensions.width,
261
+ centerY: (top + bottom) / 2 / dimensions.height,
262
+ };
253
263
  };
254
- };
255
264
 
256
- liveImageItem.position = normalizedRect(data.rect);
265
+ liveImageItem.position = normalizedRect(data.rect);
257
266
 
258
- const newIsFullyVisible = !!data.rect;
267
+ const newIsFullyVisible = !!data.rect;
259
268
 
260
- if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
261
- liveImageItem.isFullyVisible = newIsFullyVisible;
269
+ if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
270
+ liveImageItem.isFullyVisible = newIsFullyVisible;
262
271
 
263
- liveImageItem.isFullyVisible
264
- ? LiveImageManager.instance.onViewportEnter(liveImageItem)
265
- : LiveImageManager.instance.onViewportLeave(liveImageItem);
266
- } else {
267
- LiveImageManager.instance.checkPlayerPosition(liveImageItem);
268
- }
269
- };
272
+ liveImageItem.isFullyVisible
273
+ ? LiveImageManager.instance.onViewportEnter(liveImageItem)
274
+ : LiveImageManager.instance.onViewportLeave(liveImageItem);
275
+ } else {
276
+ LiveImageManager.instance.checkPlayerPosition(liveImageItem);
277
+ }
278
+ },
279
+ [liveImageItem, dimensions]
280
+ );
270
281
 
271
282
  const platformSpecificProps = isApplePlatform()
272
283
  ? { hideNativeControls: true, controls: false }
@@ -276,7 +287,9 @@ const PlayerLiveImageComponent = (props: Props) => {
276
287
  const isVideoMode = mode === LiveImageType.Video;
277
288
  const isBackgroundImageVisible = isImageMode || !isReadyToPlay;
278
289
  const videoStyles = { ...style, position: "absolute", zIndex: -100 };
290
+ const Player: any = liveImageItem.component || BufferAnimation;
279
291
 
292
+ // TODO: nice to have - resolve imageKey when imageUrl is not provided
280
293
  return (
281
294
  <TrackedView
282
295
  testId={`tracked-view-${playerId}-${item.title}`}
@@ -301,11 +314,7 @@ const PlayerLiveImageComponent = (props: Props) => {
301
314
  animationConfig={overlayFadeIn}
302
315
  staticStyles={style}
303
316
  >
304
- <PlayerImageBackground
305
- entry={item}
306
- style={style}
307
- imageKey={imageKey}
308
- />
317
+ <Image {...props} resizeMode="cover" style={style} applyMaxSize />
309
318
  </AnimatedInOut>
310
319
  }
311
320
  </TrackedView>
@@ -3,6 +3,9 @@ import * as React from "react";
3
3
  import { render } from "@testing-library/react-native";
4
4
  import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
5
5
  import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
6
+ import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
7
+ import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
+
6
9
  import { PlayerLiveImage } from "../PlayerLiveImageComponent";
7
10
 
8
11
  const seekTo = jest.fn();
@@ -16,6 +19,16 @@ jest.mock(
16
19
  })
17
20
  );
18
21
 
22
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
23
+
24
+ const Wrapper = ({ children }: { children: React.ReactChildren }) => (
25
+ <ThemeContext.Provider
26
+ value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
27
+ >
28
+ {children}
29
+ </ThemeContext.Provider>
30
+ );
31
+
19
32
  describe("PlayerLiveImageComponent", () => {
20
33
  const defaultProps = {
21
34
  item: { id: "1", title: "Test", type: { value: "" } },
@@ -36,10 +49,16 @@ describe("PlayerLiveImageComponent", () => {
36
49
  controller: new Player({}),
37
50
  Component: () => null,
38
51
  }));
52
+
53
+ jest.spyOn(navigationHooks, "useIsScreenActive").mockReturnValue(true);
39
54
  });
40
55
 
41
56
  it("should render correctly with default props", () => {
42
- const component = render(<PlayerLiveImage {...defaultProps} />);
57
+ const component = render(
58
+ <Wrapper>
59
+ <PlayerLiveImage {...defaultProps} />
60
+ </Wrapper>
61
+ );
43
62
 
44
63
  expect(component.toJSON()).toMatchSnapshot();
45
64
  });
@@ -53,7 +72,11 @@ describe("PlayerLiveImageComponent", () => {
53
72
  },
54
73
  };
55
74
 
56
- render(<PlayerLiveImage {...props} />);
75
+ render(
76
+ <Wrapper>
77
+ <PlayerLiveImage {...props} />
78
+ </Wrapper>
79
+ );
57
80
 
58
81
  // TODO: implement this test
59
82
  });
@@ -67,7 +90,11 @@ describe("PlayerLiveImageComponent", () => {
67
90
  },
68
91
  };
69
92
 
70
- render(<PlayerLiveImage {...props} />);
93
+ render(
94
+ <Wrapper>
95
+ <PlayerLiveImage {...props} />
96
+ </Wrapper>
97
+ );
71
98
 
72
99
  // TODO: implement this test
73
100
  });
@@ -13,35 +13,30 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
13
13
  }
14
14
  }
15
15
  >
16
- <View
17
- accessibilityIgnoresInvertColors={true}
18
- style={Object {}}
19
- >
20
- <Image
21
- resizeMode="cover"
22
- source={
23
- Object {
24
- "uri": undefined,
25
- }
16
+ <Image
17
+ applyMaxSize={true}
18
+ audioMutedByDefault={false}
19
+ imageKey="image1"
20
+ item={
21
+ Object {
22
+ "id": "1",
23
+ "title": "Test",
24
+ "type": Object {
25
+ "value": "",
26
+ },
26
27
  }
27
- style={
28
- Array [
29
- Object {
30
- "bottom": 0,
31
- "left": 0,
32
- "position": "absolute",
33
- "right": 0,
34
- "top": 0,
35
- },
36
- Object {
37
- "height": undefined,
38
- "width": undefined,
39
- },
40
- undefined,
41
- ]
28
+ }
29
+ onError={[Function]}
30
+ playerId="player1"
31
+ resizeMode="cover"
32
+ screenConfig={Object {}}
33
+ source={
34
+ Object {
35
+ "uri": "",
42
36
  }
43
- />
44
- </View>
37
+ }
38
+ style={Object {}}
39
+ />
45
40
  </View>
46
41
  </TrackedView>
47
42
  `;
@@ -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();