@applicaster/zapp-react-native-ui-components 14.0.0-alpha.8419134002 → 14.0.0-alpha.8583696651

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 (39) hide show
  1. package/Components/AnimatedInOut/index.tsx +5 -3
  2. package/Components/Focusable/Focusable.tsx +5 -3
  3. package/Components/Focusable/FocusableTvOS.tsx +3 -3
  4. package/Components/Focusable/FocusableiOS.tsx +1 -1
  5. package/Components/Focusable/__tests__/index.android.test.tsx +3 -0
  6. package/Components/Focusable/index.android.tsx +12 -8
  7. package/Components/FocusableList/index.tsx +4 -0
  8. package/Components/HandlePlayable/HandlePlayable.tsx +25 -9
  9. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -27
  10. package/Components/MasterCell/elementMapper.tsx +1 -2
  11. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
  12. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
  13. package/Components/PlayerContainer/PlayerContainer.tsx +41 -28
  14. package/Components/River/ComponentsMap/ComponentsMap.tsx +0 -1
  15. package/Components/River/TV/withTVEventHandler.tsx +1 -1
  16. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
  17. package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
  18. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
  19. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
  20. package/Components/ScreenRevealManager/index.ts +1 -0
  21. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
  22. package/Components/Tabs/TV/Tabs.android.tsx +0 -2
  23. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
  24. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
  25. package/Components/VideoLive/animationUtils.ts +3 -3
  26. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +9 -1
  27. package/Components/VideoModal/PlayerDetails.tsx +24 -2
  28. package/Components/VideoModal/PlayerWrapper.tsx +26 -142
  29. package/Components/VideoModal/VideoModal.tsx +3 -17
  30. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -7
  31. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +44 -240
  32. package/Components/VideoModal/hooks/index.ts +0 -2
  33. package/Components/VideoModal/hooks/useModalSize.ts +18 -2
  34. package/Components/VideoModal/utils.ts +6 -0
  35. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
  36. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
  37. package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
  38. package/package.json +5 -9
  39. package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
@@ -4,9 +4,11 @@ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/uti
4
4
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
5
5
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
6
6
 
7
- type AnimatedInterpolatedStyle =
8
- | Animated.AnimatedInterpolation
9
- | [{ [Key: string]: Animated.AnimatedInterpolation }];
7
+ type AnimatedInterpolatedStyle = any;
8
+
9
+ // type AnimatedInterpolatedStyle =
10
+ // | Animated.AnimatedInterpolation
11
+ // | [{ [Key: string]: Animated.AnimatedInterpolation }];
10
12
 
11
13
  type AnimationConfig = {
12
14
  duration: number;
@@ -5,6 +5,7 @@ import { BaseFocusable } from "../BaseFocusable";
5
5
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
6
6
  import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
7
7
  import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
8
+ import { StyleSheet, ViewStyle } from "react-native";
8
9
 
9
10
  type Props = {
10
11
  initialFocus?: boolean;
@@ -21,7 +22,7 @@ type Props = {
21
22
  handleFocus?: ({ mouse }: { mouse: boolean }) => void;
22
23
  children: (boolean, string) => React.ComponentType<any>;
23
24
  selected?: boolean;
24
- style?: React.CSSProperties;
25
+ style?: ViewStyle[] | ViewStyle;
25
26
  };
26
27
 
27
28
  class Focusable extends BaseFocusable<Props> {
@@ -122,7 +123,7 @@ class Focusable extends BaseFocusable<Props> {
122
123
  }
123
124
 
124
125
  render() {
125
- const { children, style } = this.props;
126
+ const { children, style, ...otherProps } = this.props;
126
127
  const { focused } = this.state;
127
128
 
128
129
  const id = this.getId();
@@ -139,7 +140,8 @@ class Focusable extends BaseFocusable<Props> {
139
140
  onMouseUp={this.pressOut}
140
141
  data-testid={focusableId}
141
142
  focused-teststate={focused ? "focused" : "default"}
142
- style={style}
143
+ style={StyleSheet.flatten(style) as any as React.CSSProperties}
144
+ {...otherProps}
143
145
  >
144
146
  {children(focused, { mouse: this.mouse })}
145
147
  </div>
@@ -16,9 +16,9 @@ function noop() {}
16
16
  type Props = {
17
17
  id: string;
18
18
  groupId: string;
19
- onPress?: (nativeEvent: React.SyntheticEvent) => void;
20
- onFocus?: (nativeEvent: React.SyntheticEvent) => void;
21
- onBlur?: (nativeEvent: React.SyntheticEvent) => void;
19
+ onPress?: (nativeEvent: any) => void;
20
+ onFocus?: (nativeEvent: any) => void;
21
+ onBlur?: (nativeEvent: any) => void;
22
22
  children: (focused?: boolean) => React.ReactNode;
23
23
  isParallaxDisabled: boolean;
24
24
  preferredFocus?: boolean;
@@ -12,4 +12,4 @@ function FocusableiOSComponent({ children }: Props) {
12
12
  return children;
13
13
  }
14
14
 
15
- export const FocusableiOS = React.forwardRef(FocusableiOSComponent);
15
+ export const FocusableiOS = FocusableiOSComponent;
@@ -38,6 +38,9 @@ describe("Focusable", () => {
38
38
  });
39
39
 
40
40
  it("updates disableFocus state when disableFocus prop changes", () => {
41
+ const unregister = jest.fn();
42
+ mockFocusManager.registerFocusable.mockReturnValue(unregister);
43
+
41
44
  const { rerender } = render(
42
45
  <Focusable id="test-id" disableFocus={false}>
43
46
  <Touchable testID="touchable" />
@@ -43,11 +43,13 @@ export const FocusableContext = React.createContext<
43
43
  // eslint-disable-next-line
44
44
  setIsFocusable: (enableFocus: boolean) => void;
45
45
  ref: FocusManager.FocusableRef;
46
+ parentFocusableId: Option<string>;
46
47
  } & ParentFocus
47
48
  >({
48
49
  focused: false,
49
50
  setIsFocusable: () => {},
50
51
  ref: { current: null },
52
+ parentFocusableId: undefined,
51
53
  });
52
54
 
53
55
  export const useFocusable = () => React.useContext(FocusableContext);
@@ -74,7 +76,7 @@ function FocusableComponent(props: Props, forwardedRef) {
74
76
 
75
77
  const isRTL = useIsRTL();
76
78
  const focusManager = useFocusManager();
77
- const { ref: parentFocusable } = useFocusable();
79
+ const { ref: parentFocusableRef, parentFocusableId } = useFocusable();
78
80
  const touchableRef = React.useRef(null);
79
81
 
80
82
  const [focused, setFocused] = React.useState(() =>
@@ -98,13 +100,14 @@ function FocusableComponent(props: Props, forwardedRef) {
98
100
  }
99
101
  }, [disableFocus]);
100
102
 
101
- React.useEffect(() => {
103
+ React.useLayoutEffect(() => {
102
104
  if (id) {
103
- const unregister = focusManager.registerFocusable(
105
+ const unregister = focusManager.registerFocusable({
104
106
  touchableRef,
105
- parentFocusable,
106
- isFocusableCell
107
- );
107
+ parentFocusableRef,
108
+ isFocusableCell,
109
+ parentFocusableId,
110
+ });
108
111
 
109
112
  onRegister();
110
113
 
@@ -112,7 +115,7 @@ function FocusableComponent(props: Props, forwardedRef) {
112
115
  unregister();
113
116
  };
114
117
  }
115
- }, [id, onRegister, isFocusableCell]);
118
+ }, [id, onRegister, isFocusableCell, parentFocusableId]);
116
119
 
117
120
  if (R.isNil(id)) {
118
121
  // eslint-disable-next-line no-console
@@ -164,8 +167,9 @@ function FocusableComponent(props: Props, forwardedRef) {
164
167
  ...parentFocus,
165
168
  ref: touchableRef,
166
169
  setIsFocusable,
170
+ parentFocusableId: id,
167
171
  };
168
- }, [parentFocus, focused]);
172
+ }, [parentFocus, focused, id]);
169
173
 
170
174
  return (
171
175
  <Touchable
@@ -91,6 +91,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
91
91
  // eslint-disable-next-line unused-imports/no-unused-vars
92
92
  omitPropsPropagation = [],
93
93
  useScrollView = false,
94
+ onScrollToIndexFailed = noop,
94
95
  } = props;
95
96
 
96
97
  useCheckItemIdsForUnique({ componentId: props.id, items: data });
@@ -277,6 +278,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
277
278
  "withStateMemory",
278
279
  "useSequentialLoading",
279
280
  "useScrollView",
281
+ "onScrollToIndexFailed",
280
282
  ...omitPropsPropagation,
281
283
  ],
282
284
  R.__
@@ -305,6 +307,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
305
307
  {...getFlatListProps(props)}
306
308
  onEndReached={onEndReached}
307
309
  initialNumToRender={initialNumToRender}
310
+ onScrollToIndexFailed={onScrollToIndexFailed}
308
311
  renderItem={renderItem}
309
312
  focused={focused}
310
313
  data={data}
@@ -319,6 +322,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
319
322
  renderItem={renderItem}
320
323
  onEndReached={onEndReached}
321
324
  initialNumToRender={initialNumToRender}
325
+ onScrollToIndexFailed={onScrollToIndexFailed}
322
326
  />
323
327
  )}
324
328
  </ChildrenFocusDeactivatorView>
@@ -7,12 +7,15 @@ import {
7
7
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
8
8
  import {
9
9
  useDimensions,
10
+ useIsTablet as isTablet,
10
11
  useNavigation,
11
12
  } from "@applicaster/zapp-react-native-utils/reactHooks";
12
13
 
13
14
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
14
15
  import { PlayerContainer } from "../PlayerContainer";
15
16
  import { useModalSize } from "../VideoModal/hooks";
17
+ import { ViewStyle } from "react-native";
18
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
16
19
 
17
20
  type Props = {
18
21
  item: ZappEntry;
@@ -83,6 +86,13 @@ type PlayableComponent = {
83
86
  Component: React.ComponentType<any>;
84
87
  };
85
88
 
89
+ const dimensionsContext: "window" | "screen" = platformSelect({
90
+ android_tv: "window",
91
+ amazon: "window",
92
+ // eslint-disable-next-line react-hooks/rules-of-hooks
93
+ default: isTablet() ? "window" : "screen", // on tablet, window represents correct values, on phone it's not as the screen could be rotated
94
+ });
95
+
86
96
  export function HandlePlayable({
87
97
  item,
88
98
  isModal,
@@ -135,19 +145,25 @@ export function HandlePlayable({
135
145
  });
136
146
  }, [casting]);
137
147
 
138
- const { width: screenWidth, height: screenHeight } = useDimensions("window");
148
+ const { width: screenWidth, height: screenHeight } =
149
+ useDimensions(dimensionsContext);
139
150
 
140
151
  const modalSize = useModalSize();
141
152
 
142
153
  const style = React.useMemo(
143
- () => ({
144
- width: isModal ? modalSize.width : mode === "PIP" ? "100%" : screenWidth,
145
- height: isModal
146
- ? modalSize.height
147
- : mode === "PIP"
148
- ? "100%"
149
- : screenHeight,
150
- }),
154
+ () =>
155
+ ({
156
+ width: isModal
157
+ ? modalSize.width
158
+ : mode === "PIP"
159
+ ? "100%"
160
+ : screenWidth,
161
+ height: isModal
162
+ ? modalSize.height
163
+ : mode === "PIP"
164
+ ? "100%"
165
+ : screenHeight,
166
+ }) as ViewStyle,
151
167
  [screenWidth, screenHeight, modalSize, isModal, mode]
152
168
  );
153
169
 
@@ -2,7 +2,6 @@ import React, { useMemo } from "react";
2
2
  import { ImageStyle } from "react-native";
3
3
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
4
4
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
- import * as R from "ramda";
6
5
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
7
6
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
8
7
  import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
@@ -67,32 +66,10 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
67
66
  const handleFocus = (focusable) => {
68
67
  const focusedButtonId = getFocusedButtonId(focusable);
69
68
 
70
- wrapperRef?.current?.measure((x, y, width, height, pageX, pageY) => {
71
- const top = pageY;
72
- const bottom = top + height;
73
- const left = pageX;
74
- const right = left + width;
75
-
76
- const boundingRect = {
77
- x,
78
- y,
79
- pageX,
80
- pageY,
81
- width,
82
- height,
83
- top,
84
- bottom,
85
- left,
86
- right,
87
- };
88
-
89
- otherProps?.onToggleFocus?.({
90
- focusable: {
91
- getRect: R.always(boundingRect),
92
- },
93
- focusedButtonId,
94
- mouse: focusable.mouse,
95
- });
69
+ otherProps?.onToggleFocus?.({
70
+ focusable: wrapperRef.current,
71
+ focusedButtonId,
72
+ mouse: focusable.mouse,
96
73
  });
97
74
 
98
75
  if (ttsLabel) {
@@ -73,7 +73,6 @@ export function elementMapper(
73
73
  : {};
74
74
 
75
75
  const componentProps = {
76
- key,
77
76
  style,
78
77
  skipButtons: otherProps?.skipButtons,
79
78
  emitAsyncElementRegistrate: otherProps?.emitAsyncElementRegistrate,
@@ -91,7 +90,7 @@ export function elementMapper(
91
90
  const fn = mapElementWithKey(elementMapper(components, otherProps));
92
91
 
93
92
  return (
94
- <Component {...componentProps}>
93
+ <Component key={key} {...componentProps}>
95
94
  {focusableTypes.has(type) && elements.length > 0
96
95
  ? elements.map(fn)
97
96
  : null}
@@ -1,9 +1,12 @@
1
1
  import React from "react";
2
2
  import { Text, Animated } from "react-native";
3
+ import { render } from "@testing-library/react-native";
3
4
 
4
- import renderer from "react-test-renderer";
5
-
6
- jest.useFakeTimers();
5
+ import {
6
+ NotificationView,
7
+ onlinePhrase,
8
+ offlinePhrase,
9
+ } from "../NotificationView";
7
10
 
8
11
  jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
9
12
  usePickFromState: () => ({
@@ -32,39 +35,31 @@ jest.mock("react-native-safe-area-context", () => ({
32
35
 
33
36
  const dismiss = jest.fn();
34
37
 
35
- const {
36
- NotificationView,
37
- onlinePhrase,
38
- offlinePhrase,
39
- } = require("../NotificationView");
40
-
41
38
  describe("NotificationView", () => {
42
39
  it("Show online message when Online", () => {
43
- const component = renderer.create(
44
- <NotificationView online dismiss={dismiss} />
45
- );
40
+ const component = render(<NotificationView online dismiss={dismiss} />);
46
41
 
47
- expect(component.root.findByType(Text).props.children).toBe(onlinePhrase);
42
+ expect(component.UNSAFE_getByType(Text).props.children).toBe(onlinePhrase);
48
43
  });
49
44
 
50
45
  it("Show offline message when Online", () => {
51
- const component = renderer.create(
46
+ const component = render(
52
47
  <NotificationView online={false} dismiss={dismiss} />
53
48
  );
54
49
 
55
- expect(component.root.findByType(Text).props.children).toBe(offlinePhrase);
50
+ expect(component.UNSAFE_getByType(Text).props.children).toBe(offlinePhrase);
56
51
  });
57
52
 
58
53
  it("When hidden is false to true notification is visible", () => {
59
- const component = renderer.create(
54
+ const component = render(
60
55
  <NotificationView online={false} hidden={false} dismiss={dismiss} />
61
56
  );
62
57
 
63
- component.update(
58
+ component.rerender(
64
59
  <NotificationView online={false} hidden={true} dismiss={dismiss} />
65
60
  );
66
61
 
67
- const animatedView = component.root.findByType(Animated.View);
62
+ const animatedView = component.UNSAFE_getByType(Animated.View);
68
63
  const animatedViewStyles = animatedView.props.style;
69
64
 
70
65
  expect(animatedViewStyles.opacity).toBe(1);
@@ -21,6 +21,15 @@ exports[`OfflineHandler renders 1`] = `
21
21
  }
22
22
  >
23
23
  <View
24
+ accessibilityState={
25
+ {
26
+ "busy": undefined,
27
+ "checked": undefined,
28
+ "disabled": undefined,
29
+ "expanded": undefined,
30
+ "selected": undefined,
31
+ }
32
+ }
24
33
  accessible={true}
25
34
  collapsable={false}
26
35
  focusable={true}
@@ -1,7 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { useEffect, useReducer } from "react";
3
- // @ts-ignore
4
- import { TVMenuControl, View, ViewStyle } from "react-native";
3
+ import { View, ViewStyle } from "react-native";
5
4
  import * as R from "ramda";
6
5
  import uuid from "uuid/v4";
7
6
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
@@ -62,6 +61,11 @@ import {
62
61
  useModalAnimationContext,
63
62
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
64
63
 
64
+ import {
65
+ PlayerNativeCommandTypes,
66
+ PlayerNativeSendCommand,
67
+ } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerNativeCommand";
68
+
65
69
  type Props = {
66
70
  Player: React.ComponentType<any>;
67
71
  PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
@@ -88,7 +92,7 @@ export const VideoModalMode = {
88
92
  MAXIMIZED: "MAXIMIZED",
89
93
  MINIMIZED: "MINIMIZED",
90
94
  FULLSCREEN: "FULLSCREEN",
91
- };
95
+ } as const;
92
96
 
93
97
  export type PlayNextData = {
94
98
  state: PlayNextState;
@@ -127,7 +131,7 @@ const webStyles = {
127
131
  playerScreen: {
128
132
  flex: 1,
129
133
  height: "100vh",
130
- background: "black",
134
+ backgroundColor: "black",
131
135
  },
132
136
  playerWrapper: {
133
137
  height: "100%",
@@ -145,7 +149,6 @@ const nativeStyles = {
145
149
  },
146
150
  playerScreen: {
147
151
  flex: 1,
148
- backgroundColor: "black",
149
152
  overflow: "hidden",
150
153
  },
151
154
  playerWrapper: {
@@ -260,9 +263,15 @@ const PlayerContainerComponent = (props: Props) => {
260
263
  return;
261
264
  }
262
265
 
266
+ // send command to clear and stop player
267
+ PlayerNativeSendCommand(
268
+ PlayerNativeCommandTypes.clearPlayerData,
269
+ state.playerId
270
+ );
271
+
263
272
  showNavBar(true);
264
273
  navigator.goBack();
265
- }, [isModal, navigator.goBack, showNavBar]);
274
+ }, [isModal, navigator.goBack, state.playerId, showNavBar]);
266
275
 
267
276
  const playEntry = (entry) => navigator.replaceTop(entry, { mode });
268
277
 
@@ -390,13 +399,17 @@ const PlayerContainerComponent = (props: Props) => {
390
399
  }
391
400
  };
392
401
 
393
- const playerRemoteHandler = (event, isLanguageOverlayVisible) => {
394
- const { eventType } = event;
402
+ const playerRemoteHandler = React.useCallback(
403
+ (isLanguageOverlayVisible = false) =>
404
+ (event) => {
405
+ const { eventType } = event;
395
406
 
396
- if (!isLanguageOverlayVisible && eventType === "menu") {
397
- close();
398
- }
399
- };
407
+ if (!isLanguageOverlayVisible && eventType === "menu") {
408
+ close();
409
+ }
410
+ },
411
+ [close]
412
+ );
400
413
 
401
414
  // Effects
402
415
  useEffect(() => {
@@ -509,16 +522,6 @@ const PlayerContainerComponent = (props: Props) => {
509
522
  }
510
523
  }, [isAudioContent]);
511
524
 
512
- // Needs to handle back button on Apple TV
513
- // https://github.com/facebook/react-native/issues/18930
514
- useEffect(() => {
515
- TVMenuControl?.enableTVMenuKey();
516
-
517
- return () => {
518
- TVMenuControl?.disableTVMenuKey();
519
- };
520
- }, []);
521
-
522
525
  useEffect(() => {
523
526
  playerEvent("source_changed", { item });
524
527
 
@@ -565,8 +568,9 @@ const PlayerContainerComponent = (props: Props) => {
565
568
  const isInlineTV = isInlineTVUtil(screenData);
566
569
 
567
570
  const inline =
568
- [VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(mode) ||
569
- isInlineTV;
571
+ [VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
572
+ mode as any
573
+ ) || isInlineTV;
570
574
 
571
575
  const value = React.useMemo(
572
576
  () => ({ playerId: state.playerId }),
@@ -587,7 +591,11 @@ const PlayerContainerComponent = (props: Props) => {
587
591
  );
588
592
  }
589
593
 
590
- if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
594
+ if (
595
+ screen_background_color &&
596
+ mode !== VideoModalMode.FULLSCREEN &&
597
+ isTV()
598
+ ) {
591
599
  updatedStyles.playerScreen.backgroundColor = screen_background_color;
592
600
  }
593
601
 
@@ -617,6 +625,8 @@ const PlayerContainerComponent = (props: Props) => {
617
625
  playNextData,
618
626
  };
619
627
 
628
+ const pointerEventsProp = mode === "MINIMIZED" ? "box-none" : "auto";
629
+
620
630
  return (
621
631
  <PlayerStateContext.Provider value={value}>
622
632
  <PlayerContainerContextProvider
@@ -627,9 +637,9 @@ const PlayerContainerComponent = (props: Props) => {
627
637
  <PlayerContainerContext.Consumer>
628
638
  {(context) => (
629
639
  <TVEventHandlerComponent
630
- tvEventHandler={(_component, event) =>
631
- playerRemoteHandler(event, context.isLanguageOverlayVisible)
632
- }
640
+ tvEventHandler={playerRemoteHandler(
641
+ context.isLanguageOverlayVisible
642
+ )}
633
643
  >
634
644
  <FocusableGroup
635
645
  id={FocusableGroupMainContainerId}
@@ -637,14 +647,17 @@ const PlayerContainerComponent = (props: Props) => {
637
647
  preferredFocus
638
648
  shouldUsePreferredFocus
639
649
  groupId={groupId}
650
+ pointerEvents={pointerEventsProp}
640
651
  >
641
652
  {/* Video player and components */}
642
653
  <View
643
654
  style={styles.playerScreen}
644
655
  testID={"player-screen-container"}
656
+ pointerEvents={pointerEventsProp}
645
657
  >
646
658
  {/* Player container */}
647
659
  <View
660
+ pointerEvents={pointerEventsProp}
648
661
  style={[
649
662
  styles.playerWrapper,
650
663
  // eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
@@ -286,7 +286,6 @@ function ComponentsMapComponent(props: Props) {
286
286
  initialNumToRender={3}
287
287
  maxToRenderPerBatch={10}
288
288
  windowSize={12}
289
- listKey={riverId}
290
289
  keyExtractor={keyExtractor}
291
290
  renderItem={renderRiverItem}
292
291
  data={riverComponents}
@@ -8,7 +8,7 @@ export const withTvEventHandler = (Component) => {
8
8
  return function WithTVEventHandler(props) {
9
9
  const navigator = useNavigation();
10
10
 
11
- const remoteHandler = (_, event) => {
11
+ const remoteHandler = (event) => {
12
12
  const { eventType } = event;
13
13
 
14
14
  const canGoBack = navigator.canGoBack();
@@ -159,6 +159,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
159
159
  >
160
160
  <View>
161
161
  <View
162
+ onFocusCapture={[Function]}
162
163
  onLayout={[Function]}
163
164
  style={null}
164
165
  >
@@ -174,6 +175,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
174
175
  </View>
175
176
  </View>
176
177
  <View
178
+ onFocusCapture={[Function]}
177
179
  onLayout={[Function]}
178
180
  style={null}
179
181
  >
@@ -0,0 +1,76 @@
1
+ import { makeListOf } from "@applicaster/zapp-react-native-utils/arrayUtils";
2
+ import { isFirstComponentGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
3
+ import { once } from "ramda";
4
+
5
+ const INITIAL_NUMBER_TO_LOAD = 3;
6
+
7
+ // Infer the values of COMPONENT_LOADING_STATE as a type
8
+ type ComponentLoadingState =
9
+ (typeof COMPONENT_LOADING_STATE)[keyof typeof COMPONENT_LOADING_STATE];
10
+
11
+ export const COMPONENT_LOADING_STATE = {
12
+ UNKNOWN: "UNKNOWN",
13
+ LOADED_WITH_SUCCESS: "LOADED_WITH_SUCCESS",
14
+ LOADED_WITH_FAILURE: "LOADED_WITH_FAILURE",
15
+ } as const;
16
+
17
+ // Function to get the number of loaded components
18
+ const getNumberOfLoaded = (states: ComponentLoadingState[]): number => {
19
+ return states.filter((value) => value !== COMPONENT_LOADING_STATE.UNKNOWN)
20
+ .length;
21
+ };
22
+
23
+ const getNumberOfComponentsWaitToLoadBeforePresent = (
24
+ componentsToRender: ZappUIComponent[]
25
+ ): number => {
26
+ // when Gallery is the first component, no need to wait the others
27
+ if (isFirstComponentGallery(componentsToRender)) {
28
+ return 1;
29
+ }
30
+
31
+ return Math.min(INITIAL_NUMBER_TO_LOAD, componentsToRender.length);
32
+ };
33
+
34
+ export class ScreenRevealManager {
35
+ public numberOfComponentsWaitToLoadBeforePresent: number;
36
+ private renderingState: Array<ComponentLoadingState>;
37
+ private callback: Callback;
38
+
39
+ constructor(componentsToRender: ZappUIComponent[], callback: Callback) {
40
+ this.numberOfComponentsWaitToLoadBeforePresent =
41
+ getNumberOfComponentsWaitToLoadBeforePresent(componentsToRender);
42
+
43
+ this.renderingState = makeListOf<ComponentLoadingState>(
44
+ COMPONENT_LOADING_STATE.UNKNOWN,
45
+ this.numberOfComponentsWaitToLoadBeforePresent
46
+ );
47
+
48
+ this.callback = once(callback);
49
+ }
50
+
51
+ onLoadFinished = (index: number): void => {
52
+ this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS;
53
+
54
+ if (
55
+ getNumberOfLoaded(this.renderingState) >=
56
+ this.numberOfComponentsWaitToLoadBeforePresent
57
+ ) {
58
+ this.setIsReadyToShow();
59
+ }
60
+ };
61
+
62
+ onLoadFailed = (index: number): void => {
63
+ this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE;
64
+
65
+ if (
66
+ getNumberOfLoaded(this.renderingState) >=
67
+ this.numberOfComponentsWaitToLoadBeforePresent
68
+ ) {
69
+ this.setIsReadyToShow();
70
+ }
71
+ };
72
+
73
+ setIsReadyToShow = (): void => {
74
+ this.callback();
75
+ };
76
+ }