@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4757075613 → 12.0.0-alpha.4796013211

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 (114) hide show
  1. package/Components/BaseFocusable/index.tsx +3 -3
  2. package/Components/Cell/Cell.tsx +30 -9
  3. package/Components/Cell/CellWithFocusable.tsx +23 -9
  4. package/Components/Cell/TvOSCellComponent.tsx +3 -7
  5. package/Components/Focusable/Focusable.tsx +6 -1
  6. package/Components/FocusableGroup/index.tsx +11 -2
  7. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  8. package/Components/FreezeWithCallback/LICENSE +21 -0
  9. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  10. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  11. package/Components/FreezeWithCallback/index.tsx +3 -0
  12. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  13. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  14. package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
  15. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  16. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  17. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  18. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  19. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  20. package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
  21. package/Components/Layout/TV/index.tsx +14 -67
  22. package/Components/Layout/TV/index.web.tsx +33 -0
  23. package/Components/Layout/index.tsx +15 -11
  24. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
  25. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -116
  26. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  27. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +16 -1
  28. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  29. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  30. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  31. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +34 -1
  32. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  33. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  34. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  35. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  36. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  37. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  38. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -3
  39. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  40. package/Components/MasterCell/dataAdapter.ts +21 -7
  41. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  42. package/Components/MasterCell/index.tsx +5 -3
  43. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  44. package/Components/MasterCell/utils/index.ts +33 -35
  45. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  46. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  47. package/Components/Navigator/StackNavigator.tsx +57 -0
  48. package/Components/Navigator/index.ts +1 -0
  49. package/Components/PlayerContainer/PlayerContainer.tsx +20 -3
  50. package/Components/PlayerImageBackground/index.tsx +34 -8
  51. package/Components/River/ComponentsMap/ComponentsMap.tsx +92 -22
  52. package/Components/River/RefreshControl.tsx +55 -1
  53. package/Components/River/TV/River.tsx +0 -23
  54. package/Components/River/__tests__/componentsMap.test.js +6 -0
  55. package/Components/RouteManager/index.tsx +2 -2
  56. package/Components/Screen/TV/hooks/index.ts +1 -0
  57. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  58. package/Components/Screen/TV/index.web.tsx +178 -0
  59. package/Components/Screen/__tests__/Screen.test.tsx +3 -49
  60. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
  61. package/Components/Screen/index.tsx +62 -72
  62. package/Components/Screen/navigationHandler.ts +6 -3
  63. package/Components/Screen/orientationHandler.ts +18 -7
  64. package/Components/Screen/utils.ts +16 -0
  65. package/Components/ScreenResolver/index.tsx +9 -12
  66. package/Components/Transitioner/Scene.tsx +39 -26
  67. package/Components/Transitioner/Transitioner.tsx +46 -48
  68. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  69. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
  70. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -0
  71. package/Components/VideoLive/LiveImageManager.ts +28 -1
  72. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  73. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +20 -5
  74. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +25 -28
  75. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +66 -0
  76. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +376 -0
  77. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +165 -0
  78. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +473 -0
  79. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +182 -0
  80. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  81. package/Components/VideoModal/ModalAnimation/utils.ts +302 -0
  82. package/Components/VideoModal/PlayerDetails.tsx +3 -3
  83. package/Components/VideoModal/PlayerWrapper.tsx +77 -47
  84. package/Components/VideoModal/VideoModal.tsx +23 -40
  85. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +13 -1
  86. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +203 -105
  87. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  88. package/Components/VideoModal/utils.ts +8 -5
  89. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  90. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  91. package/Components/Viewport/utils.js +1 -1
  92. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  93. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  94. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  95. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  96. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  97. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  98. package/Contexts/FocusableGroupContext/index.ts +7 -0
  99. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  100. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  101. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  102. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  103. package/Contexts/ScreenContext/index.tsx +94 -25
  104. package/Contexts/ScreenDataContext/index.tsx +20 -0
  105. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  106. package/const.ts +6 -0
  107. package/events/index.ts +1 -0
  108. package/index.js +3 -0
  109. package/package.json +5 -5
  110. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  111. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  112. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  113. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
  114. /package/Contexts/{index.js → index.ts} +0 -0
@@ -7,6 +7,10 @@ import type {
7
7
  ContainerProps,
8
8
  ContainerChildren,
9
9
  } from "./types";
10
+ import {
11
+ useIsRTL,
12
+ applyRTLStylesIfNeeded,
13
+ } from "@applicaster/zapp-react-native-utils/localizationUtils";
10
14
 
11
15
  const HorizontalSeparator = ({ width }: HorizontalSeparatorProps) => (
12
16
  <View style={{ width }} />
@@ -17,6 +21,7 @@ export function ButtonContainerView({
17
21
  children,
18
22
  ...otherProps
19
23
  }: ContainerProps) {
24
+ const isRTL = useIsRTL();
20
25
  const horizontalGutter = R.pathOr(0, ["horizontalGutter"], otherProps);
21
26
 
22
27
  const filteredChildren = useFilterChildren<ContainerChildren>(children);
@@ -26,10 +31,13 @@ export function ButtonContainerView({
26
31
  }
27
32
 
28
33
  return (
29
- <View style={style}>
34
+ <View style={applyRTLStylesIfNeeded(style, isRTL)}>
30
35
  {insertBetween(
31
36
  (index) => (
32
- <HorizontalSeparator key={index} width={horizontalGutter} />
37
+ <HorizontalSeparator
38
+ key={`separator_${index}`}
39
+ width={horizontalGutter}
40
+ />
33
41
  ),
34
42
  filteredChildren
35
43
  )}
@@ -51,9 +51,7 @@ export const CollapsibleTextContainer = ({
51
51
  func: (data) => {
52
52
  return getColorFromData({
53
53
  data,
54
- getValue,
55
- key: "background_color",
56
- defaultColor: additionalStyles.backgroundColor,
54
+ valueFromLayout: additionalStyles.backgroundColor,
57
55
  });
58
56
  },
59
57
  propName: "backgroundColor",
@@ -5,6 +5,7 @@ import * as R from "ramda";
5
5
 
6
6
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
7
7
  import { normalizeProgressValue } from "./utils";
8
+ import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
8
9
 
9
10
  const ACTION_NAME = "continue-watching";
10
11
  const DEFAULT_FILL = 0;
@@ -27,6 +28,7 @@ const getProgressValue = (
27
28
 
28
29
  export const useFillInPercent = (entry: ZappEntry): number => {
29
30
  const action = useActions(ACTION_NAME);
31
+ const isActive = useIsScreenActive();
30
32
 
31
33
  const [fillInPercent, setFillInPercent] =
32
34
  React.useState<number>(DEFAULT_FILL);
@@ -39,6 +41,10 @@ export const useFillInPercent = (entry: ZappEntry): number => {
39
41
  }, []);
40
42
 
41
43
  React.useEffect(() => {
44
+ if (!isActive) {
45
+ return;
46
+ }
47
+
42
48
  // refresh progress in UI when it was changed in CW
43
49
  const unsubscribe = action?.addDataSourceListener?.(() => {
44
50
  getProgressValue(action, entry, (progress) => {
@@ -49,7 +55,7 @@ export const useFillInPercent = (entry: ZappEntry): number => {
49
55
  return () => {
50
56
  unsubscribe?.();
51
57
  };
52
- }, []);
58
+ }, [isActive]);
53
59
 
54
60
  return fillInPercent;
55
61
  };
@@ -37,14 +37,28 @@ function retrieveData(entry, func, args) {
37
37
  */
38
38
 
39
39
  export function configInflater(
40
- entry,
41
- { type, style, additionalProps = {}, data = [], elements }
40
+ entry: any,
41
+ {
42
+ type,
43
+ style,
44
+ additionalProps = {},
45
+ data = [],
46
+ elements,
47
+ }: {
48
+ type: any;
49
+ style: any;
50
+ additionalProps?: Record<string, any>;
51
+ data?: Array<{ propName: string; func: Function; args: any[] }>;
52
+ elements?: any[];
53
+ }
42
54
  ) {
43
- const props = R.reduce(
44
- (acc, curr) =>
45
- R.assoc(curr.propName, retrieveData(entry, curr.func, curr.args), acc),
46
- additionalProps,
47
- data
55
+ const props = data.reduce(
56
+ (acc, curr) => {
57
+ acc[curr.propName] = retrieveData(entry, curr.func, curr.args);
58
+
59
+ return acc;
60
+ },
61
+ { ...additionalProps }
48
62
  );
49
63
 
50
64
  let adjustedElements;
@@ -53,7 +53,7 @@ export const useAsyncRendering = (viewRef: React.RefObject<View>): Return => {
53
53
  measure(viewRef?.current, ({ width, height }) => {
54
54
  setDimensions({
55
55
  width,
56
- height,
56
+ height: Math.ceil(height),
57
57
  });
58
58
  });
59
59
  })
@@ -52,6 +52,8 @@ export function masterCellBuilder({
52
52
  const { View } = componentsMap;
53
53
  const elementsBuilder = dataAdapter(cellConfiguration);
54
54
 
55
+ // This is very expensive operation
56
+ // Keep calls to minimum
55
57
  const hasFocusableInside = hasFocusableInsideBuilder(elementsBuilder);
56
58
 
57
59
  /**
@@ -74,8 +76,8 @@ export function masterCellBuilder({
74
76
  const selectedState = screen?.selectedEntry;
75
77
 
76
78
  const entryIsSelected = React.useMemo(
77
- () => selectedState?.id === item?.id,
78
- [selectedState?.id]
79
+ () => !!(selectedState?.id && selectedState?.id === item?.id),
80
+ [selectedState?.id, item?.id]
79
81
  );
80
82
 
81
83
  const elements = React.useMemo(
@@ -84,7 +86,7 @@ export function masterCellBuilder({
84
86
  entry: item,
85
87
  state: getEntryState(state, entryIsSelected),
86
88
  }),
87
- [state, item, entryIsSelected]
89
+ [state, item?.id, entryIsSelected] // Assuming that item won't mutate
88
90
  );
89
91
 
90
92
  const wrapperRef = React.useRef(null);
@@ -9,4 +9,13 @@ describe("insertBetween", () => {
9
9
 
10
10
  expect(result).toEqual([1, "|", 2, "|", 3]);
11
11
  });
12
+
13
+ it("insertBetween", () => {
14
+ const separator = (index) => `separator:${index}`;
15
+ const items = [1, 2, 3];
16
+
17
+ const result = insertBetween(separator, items);
18
+
19
+ expect(result).toEqual([1, "separator:0", 2, "separator:1", 3]);
20
+ });
12
21
  });
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect, useMemo } from "react";
2
2
  import * as R from "ramda";
3
+ import validateColor from "validate-color";
3
4
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
4
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
6
 
@@ -9,6 +10,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
9
10
  import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
10
11
  import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
11
12
  import { getCellState } from "../../Cell/utils";
13
+ import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
12
14
 
13
15
  const hasElementSpecificViewType = (viewType) => (element) => {
14
16
  if (R.isNil(element)) {
@@ -47,44 +49,29 @@ export const hasElementsSpecificViewType = (viewType) => (elements) => {
47
49
  return R.any(hasElementSpecificViewType(viewType))(elements);
48
50
  };
49
51
 
50
- const isColorOrEmpty = (value) =>
51
- value === null ||
52
- value === undefined ||
53
- value === "" ||
54
- value.startsWith("#") ||
55
- value.startsWith("rgba") ||
56
- value === "transparent";
57
-
58
52
  function resolveColorForProp(entry, style, colorProp) {
59
- const colorValue = style[colorProp];
60
-
61
- if (isColorOrEmpty(colorValue)) {
62
- return style;
53
+ const colorFromProp = style[colorProp];
54
+ const nestedEntryValue = R.path(colorFromProp.split("."), entry);
55
+
56
+ if (
57
+ nestedEntryValue === undefined &&
58
+ !validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
59
+ ) {
60
+ logWarning(colorFromProp, style, entry, nestedEntryValue);
63
61
  }
64
62
 
65
- const pathParts = colorValue.split(".");
66
- let nestedEntryValue = entry;
67
-
68
- for (const part of pathParts) {
69
- if (nestedEntryValue === null || typeof nestedEntryValue !== "object") {
70
- logWarning(colorValue, style, entry, nestedEntryValue);
71
-
72
- return style;
73
- }
74
-
75
- nestedEntryValue = nestedEntryValue[part];
76
- }
63
+ const colorValue = getColorFromData({
64
+ data: entry,
65
+ valueFromLayout: colorFromProp,
66
+ });
77
67
 
78
- if (nestedEntryValue === undefined) {
79
- logWarning(colorValue, style, entry, nestedEntryValue);
68
+ if (!colorValue) {
69
+ logWarning(colorProp, style, entry, colorValue);
80
70
 
81
71
  return style;
82
72
  }
83
73
 
84
- // After successful traversal, set the value.
85
- style[colorProp] = nestedEntryValue;
86
-
87
- return style;
74
+ return { ...style, [colorProp]: colorValue };
88
75
  }
89
76
 
90
77
  export function resolveColor(entry, style) {
@@ -125,13 +112,24 @@ export const useFilterChildren = <
125
112
 
126
113
  const filteredChildren = children.filter((child) => {
127
114
  const item = child.props.item;
128
- const action = actions.actions[child.props.pluginIdentifier];
115
+ const actionIdentifier = child.props.pluginIdentifier;
116
+ const action = actions.actions[actionIdentifier];
117
+
129
118
  // context value of specific plugin
130
- const currentValue = action?.module?.context?._currentValue;
119
+ if (action?.module && action.module.context) {
120
+ const currentValue = action.module.context._currentValue;
131
121
 
132
- return currentValue?.isActionAvailable
133
- ? currentValue.isActionAvailable(item)
134
- : true;
122
+ return currentValue?.isActionAvailable
123
+ ? currentValue.isActionAvailable(item)
124
+ : true;
125
+ }
126
+
127
+ masterCellLogger.error({
128
+ message: `Action plugin for ${actionIdentifier} could not be found, check the configuration of your action button`,
129
+ data: { item, action: child.props.pluginIdentifier },
130
+ });
131
+
132
+ return false;
135
133
  });
136
134
 
137
135
  return filteredChildren;
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { View, StyleSheet } from "react-native";
3
+ import { MeasurementPortalContext } from "./MeasurementsPortal";
3
4
 
4
5
  type Props = {
5
6
  Component: React.ElementType;
@@ -19,13 +20,16 @@ const _MeasurementsPortal = (
19
20
  { Component, onLayout, componentProps, containerStyle }: Props,
20
21
  ref
21
22
  ) => (
22
- <View
23
- onLayout={onLayout}
24
- style={[styles.container, containerStyle]}
25
- ref={ref}
26
- >
27
- <Component {...componentProps} />
28
- </View>
23
+ // hack for cell to determine if cell is in measurement mode
24
+ <MeasurementPortalContext.Provider value={{}}>
25
+ <View
26
+ onLayout={onLayout}
27
+ style={[styles.container, containerStyle]}
28
+ ref={ref}
29
+ >
30
+ <Component {...componentProps} />
31
+ </View>
32
+ </MeasurementPortalContext.Provider>
29
33
  );
30
34
 
31
35
  export const MeasurementsPortal = React.forwardRef(_MeasurementsPortal);
@@ -35,7 +35,16 @@ const MeasurementsPortal = ({ Component, onLayout, componentProps }: Props) => {
35
35
  );
36
36
  };
37
37
 
38
- const MeasurementPortalContext = React.createContext(null);
38
+ type MeasurementPortalContextType = {
39
+ measureComponent?: (
40
+ comp: React.ElementType,
41
+ props: Record<any, any>
42
+ ) => Promise<any>;
43
+ measuringInProgress?: boolean;
44
+ };
45
+
46
+ const MeasurementPortalContext =
47
+ React.createContext<null | MeasurementPortalContextType>(null);
39
48
 
40
49
  const MeasurementsPortalContextProvider = ({ children }) => {
41
50
  const Component = React.useRef(View);
@@ -0,0 +1,57 @@
1
+ import * as React from "react";
2
+ import { isEmpty } from "ramda";
3
+
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
5
+ import { getPathAttributes } from "@applicaster/zapp-react-native-utils/navigationUtils";
6
+ import { FocusableGroup } from "@applicaster/zapp-react-native-ui-components/Components/FocusableGroup";
7
+ import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
8
+ import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
9
+
10
+ import { Screen } from "../Screen/TV/index.web";
11
+ import { isLast } from "@applicaster/zapp-react-native-utils/arrayUtils";
12
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
13
+
14
+ type Components = {
15
+ NavBar: React.ComponentType<any>;
16
+ Background: React.ComponentType<any>;
17
+ };
18
+
19
+ type Props = {
20
+ Components: Components;
21
+ };
22
+
23
+ export const StackNavigator = ({ Components }: Props) => {
24
+ const { mainStack } = useNavigation();
25
+
26
+ const renderScreen = ({ route, state }, index) => {
27
+ const pathAttributes = getPathAttributes({ pathname: route });
28
+
29
+ if (isEmpty(pathAttributes)) {
30
+ return null;
31
+ }
32
+
33
+ // HACK: Adding index to route to avoid conflicts in the navigator.
34
+ // Startup hooks are all using PUSH navigation action to navigate, but their routes are always like root routes.
35
+ // This means some hooks can have the same routes, e.g., ["hooks/context-setter", "/hooks/login-plug", "hooks/context-setter"].
36
+ const routeId = `${route}--${index}`;
37
+
38
+ return (
39
+ <FocusableGroup
40
+ id={route}
41
+ preferredFocus={isLast(index, mainStack.length)}
42
+ excludeFromFocusSearching
43
+ key={routeId}
44
+ >
45
+ <ScreenDataContext.Provider value={state}>
46
+ <PathnameContext.Provider value={route}>
47
+ <ScreenContextProvider pathname={route}>
48
+ <Screen route={route} Components={Components} />
49
+ </ScreenContextProvider>
50
+ </PathnameContext.Provider>
51
+ </ScreenDataContext.Provider>
52
+ </FocusableGroup>
53
+ );
54
+ };
55
+
56
+ return <>{mainStack.map(renderScreen)}</>;
57
+ };
@@ -0,0 +1 @@
1
+ export { StackNavigator } from "./StackNavigator";
@@ -54,6 +54,11 @@ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
54
54
  import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayNextOverlay";
55
55
  import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
56
56
 
57
+ import {
58
+ useModalAnimationContext,
59
+ PlayerAnimationStateEnum,
60
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
61
+
57
62
  type Props = {
58
63
  Player: React.ComponentType<any>;
59
64
  PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
@@ -63,6 +68,7 @@ type Props = {
63
68
  mode?: VideoModalMode;
64
69
  loadPipesData: (url: string, options: {}) => void;
65
70
  disableCastAction?: boolean;
71
+ groupId?: string;
66
72
  };
67
73
 
68
74
  type ScreenStyles = ZappRiver["styles"] & {
@@ -118,6 +124,7 @@ const nativeStyles = {
118
124
  playerScreen: {
119
125
  flex: 1,
120
126
  backgroundColor: "black",
127
+ overflow: "hidden",
121
128
  },
122
129
  playerWrapper: {
123
130
  flex: 1,
@@ -195,6 +202,7 @@ const PlayerContainerComponent = (props: Props) => {
195
202
  style: videoStyle,
196
203
  mode = VideoModalMode.MAXIMIZED,
197
204
  disableCastAction = false,
205
+ groupId,
198
206
  } = props;
199
207
 
200
208
  // Hooks
@@ -229,6 +237,9 @@ const PlayerContainerComponent = (props: Props) => {
229
237
  const screenData = useTargetScreenData(item);
230
238
  const { setVisible: showNavBar } = useSetNavbarState();
231
239
 
240
+ const { isActiveGesture, startComponentsAnimation, setPlayerAnimationState } =
241
+ useModalAnimationContext();
242
+
232
243
  const playerEvent = (event, ...args) => {
233
244
  playerManager.invokeHandler(event, ...args);
234
245
  };
@@ -241,8 +252,8 @@ const PlayerContainerComponent = (props: Props) => {
241
252
  return;
242
253
  }
243
254
 
244
- navigator.goBack();
245
255
  showNavBar(true);
256
+ navigator.goBack();
246
257
  }, [isModal, navigator.goBack, showNavBar]);
247
258
 
248
259
  const playEntry = (entry) => navigator.replaceTop(entry, { mode });
@@ -446,7 +457,7 @@ const PlayerContainerComponent = (props: Props) => {
446
457
  if (disableMiniPlayer) {
447
458
  navigator.closeVideoModal();
448
459
  } else {
449
- navigator.minimiseVideoModal();
460
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
450
461
  }
451
462
  }
452
463
 
@@ -621,6 +632,7 @@ const PlayerContainerComponent = (props: Props) => {
621
632
  style={styles.focusableGroup}
622
633
  preferredFocus
623
634
  shouldUsePreferredFocus
635
+ groupId={groupId}
624
636
  >
625
637
  {/* Video player and components */}
626
638
  <View
@@ -641,7 +653,11 @@ const PlayerContainerComponent = (props: Props) => {
641
653
  autoplay={true}
642
654
  controls={false}
643
655
  disableCastAction={disableCastAction}
644
- docked={navigator.isVideoModalDocked()}
656
+ docked={
657
+ navigator.isVideoModalDocked() &&
658
+ !startComponentsAnimation &&
659
+ !isActiveGesture
660
+ }
645
661
  entry={item}
646
662
  fullscreen={mode === VideoModalMode.FULLSCREEN}
647
663
  inline={inline}
@@ -659,6 +675,7 @@ const PlayerContainerComponent = (props: Props) => {
659
675
  setNextVideoPreloadThresholdPercentage={
660
676
  setNextVideoPreloadThresholdPercentage
661
677
  }
678
+ startComponentsAnimation={startComponentsAnimation}
662
679
  >
663
680
  {renderApplePlayer(applePlayerProps)}
664
681
  </Player>
@@ -1,38 +1,64 @@
1
1
  import React, { PropsWithChildren } from "react";
2
- import { ImageBackground } from "react-native";
2
+ import { ImageBackground, View } from "react-native";
3
3
 
4
4
  import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
5
+ import {
6
+ AnimationComponent,
7
+ ComponentAnimationType,
8
+ useModalAnimationContext,
9
+ PlayerAnimationStateEnum,
10
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
5
11
 
6
12
  type Props = PropsWithChildren<{
7
13
  entry: ZappEntry;
8
14
  style?: { [K: string]: any };
9
15
  imageStyle?: { [K: string]: any };
10
16
  imageKey?: string;
17
+ defaultImageDimensions?: { [K: string]: any };
11
18
  }>;
12
19
 
20
+ const imageSize = { width: "100%", height: "100%" };
21
+
13
22
  const PlayerImageBackgroundComponent = ({
14
23
  entry,
15
24
  children,
16
25
  style,
17
26
  imageStyle,
18
27
  imageKey,
28
+ defaultImageDimensions,
19
29
  }: Props) => {
20
30
  const source = React.useMemo(
21
31
  () => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
22
32
  [imageKey, entry]
23
33
  );
24
34
 
35
+ const { playerAnimationState } = useModalAnimationContext();
36
+
25
37
  if (!source) return <>{children}</>;
26
38
 
27
39
  return (
28
- <ImageBackground
29
- resizeMode="cover"
30
- style={style}
31
- imageStyle={imageStyle}
32
- source={source}
40
+ <View
41
+ style={
42
+ playerAnimationState === PlayerAnimationStateEnum.maximaze
43
+ ? defaultImageDimensions
44
+ : style
45
+ }
33
46
  >
34
- {children}
35
- </ImageBackground>
47
+ <AnimationComponent
48
+ style={style}
49
+ animationType={ComponentAnimationType.player}
50
+ additionalData={defaultImageDimensions}
51
+ >
52
+ <ImageBackground
53
+ resizeMode="cover"
54
+ style={imageSize}
55
+ imageStyle={imageStyle}
56
+ source={source}
57
+ >
58
+ {children}
59
+ </ImageBackground>
60
+ </AnimationComponent>
61
+ </View>
36
62
  );
37
63
  };
38
64