@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5114122134 → 12.0.0-alpha.5208030571

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 (104) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
  2. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
  3. package/Components/AudioPlayer/helpers.tsx +1 -0
  4. package/Components/BaseFocusable/index.tsx +1 -1
  5. package/Components/Cell/Cell.tsx +7 -3
  6. package/Components/Cell/CellWithFocusable.tsx +38 -19
  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/FocusableGroup/index.tsx +1 -0
  11. package/Components/FocusableList/FocusableChild.ts +24 -14
  12. package/Components/FocusableList/FocusableItem.tsx +1 -1
  13. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  14. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  15. package/Components/FocusableList/index.tsx +26 -25
  16. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  17. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  18. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  19. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  20. package/Components/HookRenderer/index.tsx +1 -6
  21. package/Components/Image/Image.android.tsx +3 -25
  22. package/Components/Image/Image.tsx +18 -2
  23. package/Components/Image/utils/index.ts +39 -0
  24. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  25. package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
  26. package/Components/Layout/TV/index.tsx +141 -58
  27. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  28. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  29. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  30. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  31. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  32. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
  33. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  34. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  35. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  36. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
  37. package/Components/MasterCell/utils/index.ts +16 -5
  38. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  39. package/Components/ModalComponent/Button/Item.tsx +82 -0
  40. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  41. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  42. package/Components/ModalComponent/Button/assets.ts +4 -0
  43. package/Components/ModalComponent/Button/index.tsx +111 -0
  44. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  45. package/Components/ModalComponent/Header/Title.tsx +70 -0
  46. package/Components/ModalComponent/Header/assets.ts +4 -0
  47. package/Components/ModalComponent/Header/index.tsx +71 -0
  48. package/Components/ModalComponent/Header/utils.ts +79 -0
  49. package/Components/ModalComponent/index.tsx +38 -0
  50. package/Components/ModalComponent/utils.ts +126 -0
  51. package/Components/PlayerContainer/PlayerContainer.tsx +63 -31
  52. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  53. package/Components/PlayerImageBackground/index.tsx +34 -8
  54. package/Components/River/ComponentsMap/ComponentsMap.tsx +90 -2
  55. package/Components/River/TV/River.tsx +2 -3
  56. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  57. package/Components/River/__tests__/componentsMap.test.js +7 -0
  58. package/Components/River/useScreenConfiguration.ts +2 -2
  59. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  60. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  61. package/Components/RouteManager/index.tsx +5 -3
  62. package/Components/Screen/TV/index.web.tsx +151 -0
  63. package/Components/Screen/__tests__/Screen.test.tsx +88 -74
  64. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  65. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  66. package/Components/Screen/index.tsx +103 -43
  67. package/Components/Screen/navigationHandler.ts +0 -82
  68. package/Components/ScreenResolver/index.tsx +4 -2
  69. package/Components/Tabs/TV/styles.ts +1 -1
  70. package/Components/TrackedView/index.tsx +6 -3
  71. package/Components/VideoLive/LiveImageManager.ts +37 -10
  72. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  73. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  74. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  75. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  76. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  77. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  78. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  79. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
  80. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  81. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  82. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  83. package/Components/VideoModal/PlayerWrapper.tsx +65 -42
  84. package/Components/VideoModal/VideoModal.tsx +8 -25
  85. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  86. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +5 -1
  87. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  88. package/Components/VideoModal/utils.ts +3 -3
  89. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  90. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +1 -1
  91. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  92. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  93. package/Components/Viewport/utils.js +1 -1
  94. package/Components/ZappUIComponent/index.tsx +22 -12
  95. package/Components/index.js +2 -0
  96. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  97. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  98. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  99. package/Contexts/ScreenContext/index.tsx +95 -29
  100. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  101. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  102. package/package.json +5 -5
  103. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  104. /package/Contexts/{index.js → index.ts} +0 -0
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+ import { View, Text } from "react-native";
3
+ import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
4
+
5
+ import { textTransform } from "@applicaster/zapp-react-native-utils/cellUtils/";
6
+
7
+ export type TitleProps = {
8
+ text: string;
9
+ letterSpacing: number;
10
+ lineHeight: number;
11
+ fontFamily: string;
12
+ fontSize: number;
13
+ color: string;
14
+ marginTop: number;
15
+ marginLeft: number;
16
+ marginRight: number;
17
+ marginBottom: number;
18
+ transform: string;
19
+ numberOfLines: number;
20
+ };
21
+
22
+ export function Title(props: TitleProps) {
23
+ const {
24
+ text,
25
+ letterSpacing,
26
+ lineHeight,
27
+ fontFamily,
28
+ fontSize,
29
+ color,
30
+ marginTop,
31
+ marginBottom,
32
+ marginLeft,
33
+ marginRight,
34
+ numberOfLines,
35
+ transform,
36
+ } = props;
37
+
38
+ const isRTL = useIsRTL();
39
+ const writingDirection = isRTL ? "rtl" : "ltr";
40
+
41
+ if (!text) return null;
42
+
43
+ return (
44
+ <View
45
+ style={{
46
+ marginTop,
47
+ marginBottom,
48
+ marginLeft,
49
+ marginRight,
50
+ }}
51
+ >
52
+ {!!text?.length && (
53
+ <Text
54
+ style={{
55
+ letterSpacing,
56
+ fontFamily,
57
+ fontSize,
58
+ lineHeight,
59
+ color,
60
+ writingDirection,
61
+ }}
62
+ numberOfLines={numberOfLines}
63
+ ellipsizeMode="tail"
64
+ >
65
+ {textTransform(transform, text)}
66
+ </Text>
67
+ )}
68
+ </View>
69
+ );
70
+ }
@@ -0,0 +1,4 @@
1
+ /* eslint-disable max-len */
2
+
3
+ export const defaultCloseAsset: string =
4
+ "data:image/png;base64,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";
@@ -0,0 +1,71 @@
1
+ import React, { useMemo } from "react";
2
+ import { View, StyleSheet, LayoutChangeEvent } from "react-native";
3
+ import { Title, TitleProps } from "./Title";
4
+ import { CloseButton, CloseButtonProps } from "./CloseButton";
5
+ import { getCloseButtonProps, getTitleProps } from "./utils";
6
+ import { PluginConfiguration } from "../index";
7
+
8
+ type Props = {
9
+ dismiss: () => void;
10
+ configuration: PluginConfiguration;
11
+ width: number;
12
+ onLayout?: (event: LayoutChangeEvent) => void;
13
+ summary?: string;
14
+ title?: string;
15
+ };
16
+
17
+ const styles = StyleSheet.create({
18
+ container: {
19
+ flexDirection: "row",
20
+ alignItems: "center",
21
+ },
22
+ });
23
+
24
+ export function ModalHeader(props: Props) {
25
+ const { configuration, dismiss, width, onLayout, summary, title } = props;
26
+
27
+ const closeButtonProps = useMemo<CloseButtonProps>(
28
+ () => ({
29
+ ...getCloseButtonProps(configuration),
30
+ close: dismiss,
31
+ }),
32
+ [configuration, dismiss]
33
+ );
34
+
35
+ const titleProps = useMemo<TitleProps>(
36
+ () => ({
37
+ ...getTitleProps(configuration, "title"),
38
+ text: title,
39
+ }),
40
+ [configuration, title]
41
+ );
42
+
43
+ const summaryProps = useMemo<TitleProps>(
44
+ () => ({
45
+ ...getTitleProps(configuration, "summary"),
46
+ text: summary,
47
+ }),
48
+ [configuration, summary]
49
+ );
50
+
51
+ const buttonsContainerWidth =
52
+ configuration.modal_bottom_sheet_close_width +
53
+ configuration.modal_bottom_sheet_close_margin_left +
54
+ configuration.modal_bottom_sheet_close_margin_right;
55
+
56
+ return (
57
+ <View onLayout={onLayout} style={styles.container}>
58
+ <View
59
+ style={{
60
+ width: width - buttonsContainerWidth,
61
+ }}
62
+ >
63
+ {title && <Title {...titleProps} />}
64
+ {summary && <Title {...summaryProps} />}
65
+ </View>
66
+ <View style={{ width: buttonsContainerWidth }}>
67
+ <CloseButton {...closeButtonProps} />
68
+ </View>
69
+ </View>
70
+ );
71
+ }
@@ -0,0 +1,79 @@
1
+ import * as R from "ramda";
2
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
3
+ import { PluginConfiguration } from "../index";
4
+
5
+ export function getCloseButtonProps(config: PluginConfiguration) {
6
+ const {
7
+ modal_bottom_sheet_close_asset,
8
+ modal_bottom_sheet_close_focus_asset,
9
+ modal_bottom_sheet_close_height,
10
+ modal_bottom_sheet_close_width,
11
+ modal_bottom_sheet_close_switch,
12
+ modal_bottom_sheet_close_margin_bottom,
13
+ modal_bottom_sheet_close_margin_left,
14
+ modal_bottom_sheet_close_margin_right,
15
+ modal_bottom_sheet_close_margin_top,
16
+ } = config;
17
+
18
+ return {
19
+ asset: modal_bottom_sheet_close_asset,
20
+ assetFocused: modal_bottom_sheet_close_focus_asset,
21
+ enabled: modal_bottom_sheet_close_switch,
22
+ width: modal_bottom_sheet_close_width,
23
+ height: modal_bottom_sheet_close_height,
24
+ marginTop: modal_bottom_sheet_close_margin_top,
25
+ marginBottom: modal_bottom_sheet_close_margin_bottom,
26
+ marginLeft: modal_bottom_sheet_close_margin_left,
27
+ marginRight: modal_bottom_sheet_close_margin_right,
28
+ };
29
+ }
30
+
31
+ export function getTextValue(
32
+ config: PluginConfiguration,
33
+ entry: ZappEntry,
34
+ key: string
35
+ ): string {
36
+ const keyValue = config[key];
37
+
38
+ if (entry) {
39
+ const keyPath = R.split(".", keyValue);
40
+
41
+ return R.path(keyPath, entry);
42
+ } else {
43
+ return keyValue;
44
+ }
45
+ }
46
+
47
+ function getConfigKey(
48
+ config: PluginConfiguration,
49
+ suffix: string,
50
+ key: "title" | "summary"
51
+ ) {
52
+ return config?.[`modal_bottom_sheet_${key}_${suffix}`];
53
+ }
54
+
55
+ export function getTitleProps(
56
+ config: PluginConfiguration,
57
+ key: "title" | "summary"
58
+ ) {
59
+ return {
60
+ enabled: getConfigKey(config, "switch", key),
61
+ letterSpacing: platformSelect({
62
+ ios: getConfigKey(config, "ios_letter_spacing", key),
63
+ android: getConfigKey(config, "android_letter_spacing", key),
64
+ }),
65
+ fontFamily: platformSelect({
66
+ ios: getConfigKey(config, "family_ios_font_selector", key),
67
+ android: getConfigKey(config, "family_android_font_selector", key),
68
+ }),
69
+ lineHeight: getConfigKey(config, "line_height", key),
70
+ fontSize: getConfigKey(config, "font_size", key),
71
+ color: getConfigKey(config, "font_color", key),
72
+ marginTop: getConfigKey(config, "margin_top", key),
73
+ marginBottom: getConfigKey(config, "margin_bottom", key),
74
+ marginLeft: getConfigKey(config, "margin_left", key),
75
+ marginRight: getConfigKey(config, "margin_right", key),
76
+ numberOfLines: getConfigKey(config, "number_of_lines", key),
77
+ transform: getConfigKey(config, "transform", key),
78
+ };
79
+ }
@@ -0,0 +1,38 @@
1
+ import React, { useCallback, useState } from "react";
2
+
3
+ import { BasicMeasurementsPortal as MeasurementsPortal } from "@applicaster/zapp-react-native-ui-components/Components/MeasurmentsPortal";
4
+ import { BottomSheetModalContent } from "./BottomSheetModalContent";
5
+
6
+ export type PluginConfiguration = {
7
+ [key: string]: any;
8
+ };
9
+
10
+ type Props = {
11
+ actionPlugins?: [QuickBrickPlugin];
12
+ configuration?: PluginConfiguration;
13
+ };
14
+
15
+ export function ModalComponent(props: ModalBottomSheetContentProps & Props) {
16
+ const [height, setHeight] = useState(0);
17
+
18
+ const onLayout = useCallback(
19
+ ({ nativeEvent }) => {
20
+ if (height === 0) {
21
+ setHeight(nativeEvent.layout.height);
22
+ }
23
+ },
24
+ [height]
25
+ );
26
+
27
+ if (height === 0) {
28
+ return (
29
+ <MeasurementsPortal
30
+ Component={BottomSheetModalContent}
31
+ componentProps={props}
32
+ onLayout={onLayout}
33
+ />
34
+ );
35
+ }
36
+
37
+ return <BottomSheetModalContent {...props} />;
38
+ }
@@ -0,0 +1,126 @@
1
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
2
+ import { PluginConfiguration } from "./index";
3
+
4
+ export function defaultItemProps(
5
+ config: PluginConfiguration,
6
+ maxWidth: number
7
+ ) {
8
+ const {
9
+ modal_bottom_sheet_item_background_color,
10
+ modal_bottom_sheet_item_focus_background_color,
11
+ modal_bottom_sheet_item_selected_background_color,
12
+ modal_bottom_sheet_item_focusected_background_color,
13
+ modal_bottom_sheet_item_corner_radius,
14
+ modal_bottom_sheet_item_margin_bottom,
15
+ modal_bottom_sheet_item_margin_left,
16
+ modal_bottom_sheet_item_margin_right,
17
+ modal_bottom_sheet_item_margin_top,
18
+ modal_bottom_sheet_item_padding_bottom,
19
+ modal_bottom_sheet_item_padding_left,
20
+ modal_bottom_sheet_item_padding_right,
21
+ modal_bottom_sheet_item_padding_top,
22
+ } = config;
23
+
24
+ return {
25
+ backgroundColor: modal_bottom_sheet_item_background_color,
26
+ focusedBackgroundColor: modal_bottom_sheet_item_focus_background_color,
27
+ selectedBackgroundColor: modal_bottom_sheet_item_selected_background_color,
28
+ focusectedBackgroundColor:
29
+ modal_bottom_sheet_item_focusected_background_color,
30
+ borderRadius: modal_bottom_sheet_item_corner_radius,
31
+ marginBottom: modal_bottom_sheet_item_margin_bottom,
32
+ marginTop: modal_bottom_sheet_item_margin_top,
33
+ marginLeft: modal_bottom_sheet_item_margin_left,
34
+ marginRight: modal_bottom_sheet_item_margin_right,
35
+ paddingTop: modal_bottom_sheet_item_padding_top,
36
+ paddingBottom: modal_bottom_sheet_item_padding_bottom,
37
+ paddingRight: modal_bottom_sheet_item_padding_right,
38
+ paddingLeft: modal_bottom_sheet_item_padding_left,
39
+ maxWidth,
40
+ };
41
+ }
42
+
43
+ export function defaultItemLabelProps(
44
+ config: PluginConfiguration,
45
+ sheetWidth: number
46
+ ) {
47
+ const {
48
+ modal_bottom_sheet_item_label_android_letter_spacing,
49
+ modal_bottom_sheet_item_label_ios_letter_spacing,
50
+ modal_bottom_sheet_item_label_family_ios_font_selector,
51
+ modal_bottom_sheet_item_label_family_android_font_selector,
52
+ modal_bottom_sheet_item_label_focus_font_color,
53
+ modal_bottom_sheet_item_label_font_color,
54
+ modal_bottom_sheet_item_label_selected_font_color,
55
+ modal_bottom_sheet_item_label_hover_selected_font_color,
56
+ modal_bottom_sheet_item_label_font_size,
57
+ modal_bottom_sheet_item_label_line_height,
58
+ modal_bottom_sheet_item_label_margin_bottom,
59
+ modal_bottom_sheet_item_label_margin_top,
60
+ modal_bottom_sheet_item_label_margin_left,
61
+ modal_bottom_sheet_item_label_margin_right,
62
+ modal_bottom_sheet_item_label_transform,
63
+ modal_bottom_sheet_item_icon_width,
64
+ modal_bottom_sheet_item_icon_margin_left,
65
+ modal_bottom_sheet_item_icon_margin_right,
66
+ modal_bottom_sheet_item_margin_left,
67
+ modal_bottom_sheet_item_margin_right,
68
+ modal_bottom_sheet_item_padding_left,
69
+ modal_bottom_sheet_item_padding_right,
70
+ } = config;
71
+
72
+ const maxWidth =
73
+ sheetWidth -
74
+ (modal_bottom_sheet_item_icon_width +
75
+ modal_bottom_sheet_item_icon_margin_left +
76
+ modal_bottom_sheet_item_icon_margin_right +
77
+ modal_bottom_sheet_item_margin_left +
78
+ modal_bottom_sheet_item_margin_right +
79
+ modal_bottom_sheet_item_padding_left +
80
+ modal_bottom_sheet_item_padding_right);
81
+
82
+ return {
83
+ fontFamily: platformSelect({
84
+ ios: modal_bottom_sheet_item_label_family_ios_font_selector,
85
+ android: modal_bottom_sheet_item_label_family_android_font_selector,
86
+ }),
87
+ letterSpacing: platformSelect({
88
+ ios: modal_bottom_sheet_item_label_ios_letter_spacing,
89
+ android: modal_bottom_sheet_item_label_android_letter_spacing,
90
+ }),
91
+ fontSize: modal_bottom_sheet_item_label_font_size,
92
+ color: modal_bottom_sheet_item_label_font_color,
93
+ focusColor: modal_bottom_sheet_item_label_focus_font_color,
94
+ hoverSelectedColor: modal_bottom_sheet_item_label_hover_selected_font_color,
95
+ selectedColor: modal_bottom_sheet_item_label_selected_font_color,
96
+ lineHeight: modal_bottom_sheet_item_label_line_height,
97
+ marginBottom: modal_bottom_sheet_item_label_margin_bottom,
98
+ marginTop: modal_bottom_sheet_item_label_margin_top,
99
+ marginLeft: modal_bottom_sheet_item_label_margin_left,
100
+ marginRight: modal_bottom_sheet_item_label_margin_right,
101
+ transform: modal_bottom_sheet_item_label_transform,
102
+ maxWidth,
103
+ };
104
+ }
105
+
106
+ export function defaultItemIconProps(config: PluginConfiguration) {
107
+ const {
108
+ modal_bottom_sheet_item_icon_height,
109
+ modal_bottom_sheet_item_icon_width,
110
+ modal_bottom_sheet_item_icon_margin_bottom,
111
+ modal_bottom_sheet_item_icon_margin_left,
112
+ modal_bottom_sheet_item_icon_margin_right,
113
+ modal_bottom_sheet_item_icon_margin_top,
114
+ modal_bottom_sheet_item_icon_flavour,
115
+ } = config;
116
+
117
+ return {
118
+ width: modal_bottom_sheet_item_icon_width,
119
+ height: modal_bottom_sheet_item_icon_height,
120
+ flavour: modal_bottom_sheet_item_icon_flavour,
121
+ marginTop: modal_bottom_sheet_item_icon_margin_top,
122
+ marginBottom: modal_bottom_sheet_item_icon_margin_bottom,
123
+ marginLeft: modal_bottom_sheet_item_icon_margin_left,
124
+ marginRight: modal_bottom_sheet_item_icon_margin_right,
125
+ };
126
+ }
@@ -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"] & {
@@ -145,34 +151,30 @@ const renderApplePlayer = ({
145
151
  }) => {
146
152
  const { title, summary } = item || {};
147
153
 
148
- if (!isApplePlatform()) {
154
+ if (!isAppleTV() || !player) {
155
+ return null;
156
+ }
157
+
158
+ if (isAudioContent) {
159
+ return (
160
+ <AudioPlayer
161
+ audio_item={item}
162
+ plugin_configuration={pluginConfiguration}
163
+ />
164
+ );
165
+ }
166
+
167
+ if (!playNextData && player.isPaused() && player.isAd() === false) {
149
168
  return null;
150
169
  }
151
170
 
152
171
  return (
153
- <>
154
- {!playNextData && (
155
- <>
156
- {!isAudioContent &&
157
- !!player?.isPaused() &&
158
- !!player?.isAd() === false && (
159
- <ProgramInfo
160
- title={title}
161
- subtitle={summary}
162
- plugin_configuration={pluginConfiguration}
163
- videoStyle={videoStyle}
164
- />
165
- )}
166
- </>
167
- )}
168
-
169
- {isAudioContent && (
170
- <AudioPlayer
171
- audio_item={item}
172
- plugin_configuration={pluginConfiguration}
173
- />
174
- )}
175
- </>
172
+ <ProgramInfo
173
+ title={title}
174
+ subtitle={summary}
175
+ plugin_configuration={pluginConfiguration}
176
+ videoStyle={videoStyle}
177
+ />
176
178
  );
177
179
  };
178
180
 
@@ -199,6 +201,7 @@ const PlayerContainerComponent = (props: Props) => {
199
201
  style: videoStyle,
200
202
  mode = VideoModalMode.MAXIMIZED,
201
203
  disableCastAction = false,
204
+ groupId,
202
205
  } = props;
203
206
 
204
207
  // Hooks
@@ -233,6 +236,9 @@ const PlayerContainerComponent = (props: Props) => {
233
236
  const screenData = useTargetScreenData(item);
234
237
  const { setVisible: showNavBar } = useSetNavbarState();
235
238
 
239
+ const { isActiveGesture, startComponentsAnimation, setPlayerAnimationState } =
240
+ useModalAnimationContext();
241
+
236
242
  const playerEvent = (event, ...args) => {
237
243
  playerManager.invokeHandler(event, ...args);
238
244
  };
@@ -245,7 +251,6 @@ const PlayerContainerComponent = (props: Props) => {
245
251
  return;
246
252
  }
247
253
 
248
- navigator.goBack();
249
254
  showNavBar(true);
250
255
  }, [isModal, navigator.goBack, showNavBar]);
251
256
 
@@ -339,6 +344,18 @@ const PlayerContainerComponent = (props: Props) => {
339
344
  }
340
345
  }, [item?.id, item?.extensions?.resumeTime, player]);
341
346
 
347
+ const onVideoFullscreenPlayerWillPresent = React.useCallback(() => {
348
+ playerManager.invokeHandler("toggleFullscreen", {
349
+ fullscreen: true,
350
+ });
351
+ }, []);
352
+
353
+ const onVideoFullscreenPlayerWillDismiss = React.useCallback(() => {
354
+ playerManager.invokeHandler("toggleFullscreen", {
355
+ fullscreen: false,
356
+ });
357
+ }, []);
358
+
342
359
  // Util methods
343
360
  const toggleFullscreen = (event) => {
344
361
  const { fullscreen = false } = event || {};
@@ -381,17 +398,27 @@ const PlayerContainerComponent = (props: Props) => {
381
398
  id: playerContainerId,
382
399
  listener: {
383
400
  onVideoEnd,
384
- onError: onError,
385
- onLoad: onLoad,
401
+ onError,
402
+ onLoad,
386
403
  onPlayerClose: close,
387
404
  onPlayerDetached: close,
405
+ onVideoFullscreenPlayerWillDismiss,
406
+ onVideoFullscreenPlayerWillPresent,
388
407
  },
389
408
  });
390
409
 
391
410
  return () => {
392
411
  player.removeListener(playerContainerId);
393
412
  };
394
- }, [player, onVideoEnd]);
413
+ }, [
414
+ player,
415
+ onVideoEnd,
416
+ onError,
417
+ onLoad,
418
+ close,
419
+ onVideoFullscreenPlayerWillDismiss,
420
+ onVideoFullscreenPlayerWillPresent,
421
+ ]);
395
422
 
396
423
  useEffect(() => {
397
424
  // TODO: We should not use playerManager here to connect buttons to player container
@@ -428,7 +455,7 @@ const PlayerContainerComponent = (props: Props) => {
428
455
  if (disableMiniPlayer) {
429
456
  navigator.closeVideoModal();
430
457
  } else {
431
- navigator.minimiseVideoModal();
458
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
432
459
  }
433
460
  }
434
461
 
@@ -603,6 +630,7 @@ const PlayerContainerComponent = (props: Props) => {
603
630
  style={styles.focusableGroup}
604
631
  preferredFocus
605
632
  shouldUsePreferredFocus
633
+ groupId={groupId}
606
634
  >
607
635
  {/* Video player and components */}
608
636
  <View
@@ -621,9 +649,13 @@ const PlayerContainerComponent = (props: Props) => {
621
649
  }}
622
650
  focused={isInlineTV ? true : undefined}
623
651
  autoplay={true}
624
- controls={isAppleTV() && !isInlineTV}
652
+ controls={false}
625
653
  disableCastAction={disableCastAction}
626
- docked={navigator.isVideoModalDocked()}
654
+ docked={
655
+ navigator.isVideoModalDocked() &&
656
+ !startComponentsAnimation &&
657
+ !isActiveGesture
658
+ }
627
659
  entry={item}
628
660
  fullscreen={mode === VideoModalMode.FULLSCREEN}
629
661
  inline={inline}
@@ -4,7 +4,9 @@ import { styleKeys } from "@applicaster/zapp-react-native-utils/styleKeysUtils";
4
4
  import { transformColorCode as fixColorHexCode } from "@applicaster/zapp-react-native-utils/transform";
5
5
  import * as R from "ramda";
6
6
  import * as React from "react";
7
- import { Image, Text, TextStyle, View, ViewStyle } from "react-native";
7
+ import { Text, TextStyle, View, ViewStyle } from "react-native";
8
+ import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
9
+
8
10
  import * as programStyles from "./styles";
9
11
 
10
12
  type Props = {
@@ -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