@applicaster/zapp-react-native-ui-components 13.0.0-alpha.6400875052 → 13.0.0-alpha.6444233049

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 (42) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +0 -11
  2. package/Components/AudioPlayer/helpers.tsx +0 -2
  3. package/Components/Cell/CellWithFocusable.tsx +4 -2
  4. package/Components/Cell/CellWrapper.tsx +18 -0
  5. package/Components/CellRendererResolver/index.ts +2 -1
  6. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +3 -0
  7. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +4 -2
  8. package/Components/GeneralContentScreen/utils/useEventAlerts.ts +30 -0
  9. package/Components/Layout/TV/LayoutBackground.tsx +28 -0
  10. package/Components/Layout/TV/ScreenContainer.tsx +0 -1
  11. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +15 -10
  12. package/Components/Layout/TV/__tests__/index.test.tsx +8 -2
  13. package/Components/Layout/TV/index.tsx +6 -20
  14. package/Components/Layout/TV/index.web.tsx +4 -1
  15. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const.ts +3 -0
  16. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -6
  17. package/Components/ModalComponent/BottomSheetModalContent.tsx +34 -45
  18. package/Components/ModalComponent/Button/Item.tsx +5 -5
  19. package/Components/ModalComponent/Button/index.tsx +25 -29
  20. package/Components/ModalComponent/Header/index.tsx +9 -8
  21. package/Components/ModalComponent/utils.ts +3 -3
  22. package/Components/PlayerContainer/PlayerContainer.tsx +18 -5
  23. package/Components/River/ComponentsMap/ComponentsMap.tsx +11 -3
  24. package/Components/River/RiverItem.tsx +8 -3
  25. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +7 -1
  26. package/Components/Screen/TV/__tests__/index.web.test.tsx +26 -0
  27. package/Components/Screen/__tests__/Screen.test.tsx +22 -14
  28. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -2
  29. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
  30. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +4 -2
  31. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +17 -10
  32. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +9 -1
  33. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
  34. package/Components/VideoModal/ModalAnimation/const.ts +5 -0
  35. package/Components/VideoModal/ModalAnimation/index.ts +2 -0
  36. package/Components/VideoModal/ModalAnimation/utils.ts +30 -0
  37. package/Components/VideoModal/PlayerDetails.tsx +5 -0
  38. package/Components/VideoModal/PlayerWrapper.tsx +9 -19
  39. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
  40. package/Components/VideoModal/utils.ts +3 -4
  41. package/package.json +5 -5
  42. package/Components/Cell/CellWrapper.ts +0 -5
@@ -8,13 +8,18 @@ import { PluginConfiguration } from "../index";
8
8
  type Props = {
9
9
  dismiss: () => void;
10
10
  configuration: PluginConfiguration;
11
- width: number;
12
11
  onLayout?: (event: LayoutChangeEvent) => void;
13
12
  summary?: string;
14
13
  title?: string;
15
14
  };
16
15
 
17
16
  const styles = StyleSheet.create({
17
+ noFlex: {
18
+ flex: 0,
19
+ },
20
+ flex: {
21
+ flex: 1,
22
+ },
18
23
  container: {
19
24
  flexDirection: "row",
20
25
  alignItems: "center",
@@ -22,7 +27,7 @@ const styles = StyleSheet.create({
22
27
  });
23
28
 
24
29
  export function ModalHeader(props: Props) {
25
- const { configuration, dismiss, width, onLayout, summary, title } = props;
30
+ const { configuration, dismiss, onLayout, summary, title } = props;
26
31
 
27
32
  const closeButtonProps = useMemo<CloseButtonProps>(
28
33
  () => ({
@@ -55,15 +60,11 @@ export function ModalHeader(props: Props) {
55
60
 
56
61
  return (
57
62
  <View onLayout={onLayout} style={styles.container}>
58
- <View
59
- style={{
60
- width: width - buttonsContainerWidth,
61
- }}
62
- >
63
+ <View style={styles.flex}>
63
64
  {title ? <Title {...titleProps} /> : null}
64
65
  {summary ? <Title {...summaryProps} /> : null}
65
66
  </View>
66
- <View style={{ width: buttonsContainerWidth }}>
67
+ <View style={[styles.noFlex, { width: buttonsContainerWidth }]}>
67
68
  <CloseButton {...closeButtonProps} />
68
69
  </View>
69
70
  </View>
@@ -12,7 +12,7 @@ export function defaultItemProps(
12
12
  modal_bottom_sheet_item_background_color,
13
13
  modal_bottom_sheet_item_focus_background_color,
14
14
  modal_bottom_sheet_item_selected_background_color,
15
- modal_bottom_sheet_item_focusected_background_color,
15
+ modal_bottom_sheet_item_focused_selected_background_color,
16
16
  modal_bottom_sheet_item_corner_radius,
17
17
  modal_bottom_sheet_item_margin_bottom,
18
18
  modal_bottom_sheet_item_margin_left,
@@ -28,8 +28,8 @@ export function defaultItemProps(
28
28
  backgroundColor: modal_bottom_sheet_item_background_color,
29
29
  focusedBackgroundColor: modal_bottom_sheet_item_focus_background_color,
30
30
  selectedBackgroundColor: modal_bottom_sheet_item_selected_background_color,
31
- focusectedBackgroundColor:
32
- modal_bottom_sheet_item_focusected_background_color,
31
+ focusedSelectedBackgroundColor:
32
+ modal_bottom_sheet_item_focused_selected_background_color,
33
33
  borderRadius: modal_bottom_sheet_item_corner_radius,
34
34
  marginBottom: modal_bottom_sheet_item_margin_bottom,
35
35
  marginTop: modal_bottom_sheet_item_margin_top,
@@ -9,6 +9,7 @@ import {
9
9
  isApplePlatform,
10
10
  isTV,
11
11
  platformSelect,
12
+ isAndroidTVPlatform,
12
13
  } from "@applicaster/zapp-react-native-utils/reactUtils";
13
14
 
14
15
  import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
@@ -93,6 +94,20 @@ export type PlayNextData = {
93
94
 
94
95
  const focusableBottomContainerId = "player-container-bottom";
95
96
 
97
+ const isAndroidTV = isAndroidTVPlatform();
98
+
99
+ const withBorderHack = () => {
100
+ if (isAndroidTV) {
101
+ /* @HACK: see GH#7269 */
102
+ return {
103
+ borderWidth: 1,
104
+ borderColor: "transparent",
105
+ };
106
+ }
107
+
108
+ return {};
109
+ };
110
+
96
111
  // Styles
97
112
  const webStyles = {
98
113
  focusableGroup: {
@@ -582,7 +597,7 @@ const PlayerContainerComponent = (props: Props) => {
582
597
  );
583
598
  }
584
599
 
585
- if (screen_background_color) {
600
+ if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
586
601
  updatedStyles.playerScreen.backgroundColor = screen_background_color;
587
602
  }
588
603
 
@@ -600,6 +615,7 @@ const PlayerContainerComponent = (props: Props) => {
600
615
  tv_component_container_height,
601
616
  screen_background_color,
602
617
  isInlineTV,
618
+ mode,
603
619
  ]);
604
620
 
605
621
  const applePlayerProps = {
@@ -648,10 +664,7 @@ const PlayerContainerComponent = (props: Props) => {
648
664
  style={[
649
665
  styles.playerWrapper,
650
666
  // eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
651
- {
652
- borderWidth: 1,
653
- borderColor: "transparent",
654
- } /* @HACK: see GH#7269 */,
667
+ withBorderHack(),
655
668
  ]}
656
669
  testID={"player-wrapper"}
657
670
  >
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { View, StyleSheet, Platform, FlatList } from "react-native";
3
+ import { View, StyleSheet, FlatList } from "react-native";
4
4
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
5
5
  import { RiverItem } from "../RiverItem";
6
6
  import { RiverFooter } from "../RiverFooter";
@@ -24,6 +24,10 @@ import { withComponentsMapProvider } from "@applicaster/zapp-react-native-ui-com
24
24
  import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
25
25
  import { useShallow } from "zustand/react/shallow";
26
26
 
27
+ import { isAndroidPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
28
+
29
+ const isAndroid = isAndroidPlatform();
30
+
27
31
  type Props = {
28
32
  feed: ZappFeed;
29
33
  groupId?: string;
@@ -273,12 +277,12 @@ function ComponentsMapComponent(props: Props) {
273
277
  }}
274
278
  // Fix for WebView rerender crashes on Android API 28+
275
279
  // https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
276
- overScrollMode={Platform.OS === "android" ? "never" : "auto"}
280
+ overScrollMode={isAndroid ? "never" : "auto"}
277
281
  scrollIndicatorInsets={scrollIndicatorInsets}
278
282
  extraData={feed}
279
283
  stickyHeaderIndices={stickyHeaderIndices}
280
284
  onLayout={handleOnLayout}
281
- removeClippedSubviews
285
+ removeClippedSubviews={isAndroid}
282
286
  initialNumToRender={3}
283
287
  maxToRenderPerBatch={10}
284
288
  windowSize={12}
@@ -299,6 +303,10 @@ function ComponentsMapComponent(props: Props) {
299
303
  onMomentumScrollEnd={_onMomentumScrollEnd}
300
304
  onScrollEndDrag={_onScrollEndDrag}
301
305
  scrollEventThrottle={16}
306
+ maintainVisibleContentPosition={{
307
+ minIndexForVisible: 0,
308
+ autoscrollToTopThreshold: 10,
309
+ }}
302
310
  {...scrollViewExtraProps}
303
311
  />
304
312
  </ViewportTracker>
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect } from "react";
2
2
  import * as R from "ramda";
3
+ import { isGroup } from "@applicaster/zapp-react-native-utils/componentsUtils";
3
4
 
4
5
  import { applyDecorators } from "../../Decorators";
5
6
 
@@ -47,16 +48,20 @@ const useLoadingState = (
47
48
  loadingState: RiverItemType["loadingState"]
48
49
  ) => {
49
50
  const [readyToBeDisplayed, setReadyToBeDisplayed] = React.useState(
50
- loadingState.getValue().index + 1 === currentIndex
51
+ loadingState.getValue().index + 1 >= currentIndex
51
52
  );
52
53
 
53
54
  useEffect(() => {
54
55
  const subscription = loadingState.subscribe(({ index }) => {
55
- if (index + 1 === currentIndex) {
56
+ if (index + 1 >= currentIndex) {
56
57
  setReadyToBeDisplayed(true);
57
58
  }
58
59
  });
59
60
 
61
+ if (loadingState.getValue().index + 1 >= currentIndex) {
62
+ setReadyToBeDisplayed(true);
63
+ }
64
+
60
65
  return () => {
61
66
  subscription.unsubscribe();
62
67
  };
@@ -112,7 +117,7 @@ function RiverItemComponent(props: RiverItemType) {
112
117
  jsOnly: true,
113
118
  });
114
119
 
115
- if (!CellRenderer && item.component_type !== "group-qb") {
120
+ if (!CellRenderer && !isGroup(item)) {
116
121
  riverLogger.warning({
117
122
  message: "Cell Renderer is null - will fallback to default cell",
118
123
  data: { item, CellRenderer },
@@ -135,6 +135,12 @@ exports[`componentsMap renders renders components map correctly 1`] = `
135
135
  getItemCount={[Function]}
136
136
  initialNumToRender={3}
137
137
  keyExtractor={[Function]}
138
+ maintainVisibleContentPosition={
139
+ {
140
+ "autoscrollToTopThreshold": 10,
141
+ "minIndexForVisible": 0,
142
+ }
143
+ }
138
144
  maxToRenderPerBatch={10}
139
145
  onContentSizeChange={[Function]}
140
146
  onLayout={[Function]}
@@ -145,7 +151,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
145
151
  onScrollEndDrag={[Function]}
146
152
  overScrollMode="auto"
147
153
  refreshControl={null}
148
- removeClippedSubviews={true}
154
+ removeClippedSubviews={false}
149
155
  renderItem={[Function]}
150
156
  scrollEventThrottle={16}
151
157
  scrollIndicatorInsets={
@@ -0,0 +1,26 @@
1
+ const {
2
+ useScreenBackgroundColor,
3
+ } = require("@applicaster/zapp-react-native-utils/reactHooks/screen");
4
+
5
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
6
+ useScreenBackgroundColor: jest.fn(),
7
+ useNavbarState: jest.fn().mockReturnValue({ visible: true }),
8
+ }));
9
+
10
+ describe("TV Screen Component", () => {
11
+ it("uses the useScreenBackgroundColor hook with the correct screen ID", () => {
12
+ useScreenBackgroundColor.mockReturnValue("#FF0000");
13
+
14
+ expect(useScreenBackgroundColor("test-screen-id")).toBe("#FF0000");
15
+
16
+ // Verify the hook was called with the correct screen ID
17
+ expect(useScreenBackgroundColor).toHaveBeenCalledWith("test-screen-id");
18
+ });
19
+
20
+ it("returns 'transparent' when the screen background color is not defined", () => {
21
+ useScreenBackgroundColor.mockReturnValue("transparent");
22
+
23
+ // Verify the hook returns 'transparent'
24
+ expect(useScreenBackgroundColor("test-screen-id")).toBe("transparent");
25
+ });
26
+ });
@@ -68,21 +68,21 @@ jest.mock(
68
68
  })
69
69
  );
70
70
 
71
- jest.mock(
72
- "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData",
73
- () => ({
74
- useScreenData: jest.fn(() => ({
75
- id: "testId",
76
- navigations: [{ id: "testId", category: "nav_bar" }],
77
- })),
78
- })
79
- );
80
-
81
71
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
82
72
  isNavBarVisible: mockIsNavBarVisible,
83
- useRoute: jest.fn(() => ({
84
- pathname: "/river/testId",
85
- screenData: { id: "testId" },
73
+ useIsScreenActive: jest.fn().mockReturnValue(true),
74
+ }));
75
+
76
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
77
+ useCurrentScreenData: jest.fn(() => ({
78
+ id: "testId",
79
+ })),
80
+ useNavbarState: jest.fn(() => ({
81
+ title: "Test Title",
82
+ })),
83
+ useScreenData: jest.fn(() => ({
84
+ id: "testId",
85
+ navigations: [{ id: "testId", category: "nav_bar" }],
86
86
  })),
87
87
  useNavigation: jest.fn(() => ({
88
88
  canGoBack: () => false,
@@ -91,7 +91,15 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
91
91
  screenData: { id: "testId" },
92
92
  data: { screen: { id: "testId" } },
93
93
  })),
94
- useIsScreenActive: jest.fn().mockReturnValue(true),
94
+ useRoute: jest.fn(() => ({
95
+ pathname: "/river/testId",
96
+ screenData: { id: "testId" },
97
+ })),
98
+ useDimensions: jest.fn(() => ({
99
+ width: 1920,
100
+ height: 1080,
101
+ })),
102
+ useIsTablet: jest.fn(() => false),
95
103
  }));
96
104
 
97
105
  jest.mock("@applicaster/zapp-react-native-redux/hooks/usePickFromState", () => {
@@ -16,7 +16,7 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
16
16
  pathname="/river/testId"
17
17
  selected="testId"
18
18
  testID="navBar"
19
- title=""
19
+ title="Test Title"
20
20
  />
21
21
  <View>
22
22
  <View
@@ -48,7 +48,7 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
48
48
  pathname="/river/testId"
49
49
  selected="testId"
50
50
  testID="navBar"
51
- title=""
51
+ title="Test Title"
52
52
  />
53
53
  <View>
54
54
  <View
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import { View, ViewProps, ViewStyle } from "react-native";
3
3
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
4
4
  import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+ import { isFirstComponentScreenPicker } from "@applicaster/zapp-react-native-utils/componentsUtils";
5
6
 
6
7
  interface IProps {
7
8
  targetScreenId?: string;
@@ -31,11 +32,9 @@ export const useMarginTop = (targetScreenId: string): number => {
31
32
  * ScreenPicker is a component but should really be a screen.
32
33
  * We need to skip margin top for it as it's already applied to the target screen
33
34
  **/
34
- const isScreenPicker =
35
- screenData?.ui_components?.[0]?.component_type === "screen-picker-qb-tv";
36
35
 
37
36
  // ignore margin on screenPicker
38
- if (isScreenPicker) {
37
+ if (isFirstComponentScreenPicker(screenData?.ui_components)) {
39
38
  return 0;
40
39
  }
41
40
 
@@ -23,10 +23,12 @@ import {
23
23
  setScrollModalAnimatedValue,
24
24
  } from "./utils";
25
25
 
26
+ import { DURATION_TO_MINIMIZE } from "./const";
27
+
26
28
  const getAnimatedConfig = (toValue) => {
27
29
  return {
28
30
  toValue,
29
- duration: 200,
31
+ duration: DURATION_TO_MINIMIZE,
30
32
  useNativeDriver: true,
31
33
  };
32
34
  };
@@ -142,7 +144,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
142
144
 
143
145
  setLastSnap(destSnapPoint);
144
146
 
145
- if (destSnapPoint === modalSnapPoints[0] && isMinimizedModal) {
147
+ if (destSnapPoint === modalSnapPoints[0]) {
146
148
  translateYOffset.extractOffset();
147
149
  translateYOffset.setValue(preparedTranslationY);
148
150
  translateYOffset.flattenOffset();
@@ -24,8 +24,11 @@ import {
24
24
  gestureListenerHelper,
25
25
  getAnimationDefaultValue,
26
26
  getAnimationStyle,
27
+ getMoveUpValue,
27
28
  } from "./utils";
28
29
 
30
+ import { DURATION_TO_MINIMIZE, DEFAULT_DURATION_FOR_ANIMATION } from "./const";
31
+
29
32
  type Props = {
30
33
  animationType: string;
31
34
  children: React.ReactNode;
@@ -91,20 +94,21 @@ export const AnimationView = ({
91
94
  const isAudioItem = React.useMemo(
92
95
  () =>
93
96
  videoModalItem?.content?.type?.includes?.("audio") ||
94
- videoModalItem?.type?.value === "audio",
97
+ videoModalItem?.type?.value?.includes?.("audio"),
95
98
  [videoModalItem]
96
99
  );
97
100
 
98
101
  const inlineAudioPlayer = additionalData.inlineAudioPlayer;
99
102
 
100
- const moveUpValue = additionalData.saveArea
101
- ? -insets.top + (isAudioItem ? 0 : progressBarHeight)
102
- : isTablet
103
- ? isTabletLandscape &&
104
- (!isAudioItem || (isAudioItem && inlineAudioPlayer))
105
- ? -tabletLandscapePlayerTopPosition + progressBarHeight
106
- : -130
107
- : -50 + progressBarHeight;
103
+ const moveUpValue = getMoveUpValue({
104
+ additionalData,
105
+ insets,
106
+ isAudioItem,
107
+ progressBarHeight,
108
+ isTablet,
109
+ isTabletLandscape,
110
+ tabletLandscapePlayerTopPosition,
111
+ });
108
112
 
109
113
  const moveComponentHorizontalValue = additionalData.moveValue
110
114
  ? isRTL
@@ -119,7 +123,10 @@ export const AnimationView = ({
119
123
  (animationType, state) => {
120
124
  const defaultConfig = {
121
125
  toValue: 0,
122
- duration: state === PlayerAnimationStateEnum.minimize ? 150 : 100,
126
+ duration:
127
+ state === PlayerAnimationStateEnum.minimize
128
+ ? DURATION_TO_MINIMIZE
129
+ : DEFAULT_DURATION_FOR_ANIMATION,
123
130
  useNativeDriver: true,
124
131
  };
125
132
 
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useEffect } from "react";
2
2
  import { Animated } from "react-native";
3
3
 
4
4
  import {
@@ -17,6 +17,7 @@ export enum PlayerAnimationStateEnum {
17
17
  maximize = "maximize",
18
18
  drag_player = "drag_player",
19
19
  drag_scroll = "drag_scroll",
20
+ appear_as_docked = "appear_as_docked",
20
21
  }
21
22
 
22
23
  export type PlayerAnimationStateT = number | PlayerAnimationStateEnum | null;
@@ -95,6 +96,13 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
95
96
  setStartComponentsAnimation(false);
96
97
  }, []);
97
98
 
99
+ useEffect(() => {
100
+ // Reset player animation state when video modal is closed
101
+ if (!visible) {
102
+ resetPlayerAnimationState();
103
+ }
104
+ }, [visible, resetPlayerAnimationState]);
105
+
98
106
  // Animated values
99
107
  const lastScrollY = React.useRef(new Animated.Value(0)).current;
100
108
  const dragScrollY = React.useRef(new Animated.Value(0)).current;
@@ -0,0 +1,108 @@
1
+ import { getMoveUpValue } from "../utils";
2
+
3
+ describe("getMoveUpValue", () => {
4
+ it("returns correct value when additionalData.saveArea is true and isAudioItem is false", () => {
5
+ const result = getMoveUpValue({
6
+ additionalData: { saveArea: true },
7
+ insets: { top: 20 },
8
+ isAudioItem: false,
9
+ progressBarHeight: 10,
10
+ isTablet: false,
11
+ isTabletLandscape: false,
12
+ inlineAudioPlayer: false,
13
+ tabletLandscapePlayerTopPosition: 100,
14
+ });
15
+
16
+ expect(result).toBe(-20 + 10);
17
+ });
18
+
19
+ it("returns correct value when additionalData.saveArea is true and isAudioItem is true", () => {
20
+ const result = getMoveUpValue({
21
+ additionalData: { saveArea: true },
22
+ insets: { top: 15 },
23
+ isAudioItem: true,
24
+ progressBarHeight: 5,
25
+ isTablet: false,
26
+ isTabletLandscape: false,
27
+ inlineAudioPlayer: false,
28
+ tabletLandscapePlayerTopPosition: 100,
29
+ });
30
+
31
+ expect(result).toBe(-15 + 0);
32
+ });
33
+
34
+ it("returns correct value for audio item (tablet or not)", () => {
35
+ const result = getMoveUpValue({
36
+ additionalData: { marginTop: 30 },
37
+ insets: { top: 0 },
38
+ isAudioItem: true,
39
+ progressBarHeight: 0,
40
+ isTablet: false,
41
+ isTabletLandscape: false,
42
+ inlineAudioPlayer: false,
43
+ tabletLandscapePlayerTopPosition: 0,
44
+ });
45
+
46
+ expect(result).toBe(-30);
47
+ });
48
+
49
+ it("returns correct value for tablet landscape with inline audio player", () => {
50
+ const result = getMoveUpValue({
51
+ additionalData: {},
52
+ insets: { top: 0 },
53
+ isAudioItem: true,
54
+ progressBarHeight: 8,
55
+ isTablet: true,
56
+ isTabletLandscape: true,
57
+ inlineAudioPlayer: true,
58
+ tabletLandscapePlayerTopPosition: 50,
59
+ });
60
+
61
+ expect(result).toBe(-0);
62
+ });
63
+
64
+ it("returns correct value for tablet landscape without audio item", () => {
65
+ const result = getMoveUpValue({
66
+ additionalData: {},
67
+ insets: { top: 0 },
68
+ isAudioItem: false,
69
+ progressBarHeight: 12,
70
+ isTablet: true,
71
+ isTabletLandscape: true,
72
+ inlineAudioPlayer: false,
73
+ tabletLandscapePlayerTopPosition: 60,
74
+ });
75
+
76
+ expect(result).toBe(-60 + 12);
77
+ });
78
+
79
+ it("returns -130 for tablet portrait (not landscape)", () => {
80
+ const result = getMoveUpValue({
81
+ additionalData: {},
82
+ insets: { top: 0 },
83
+ isAudioItem: false,
84
+ progressBarHeight: 0,
85
+ isTablet: true,
86
+ isTabletLandscape: false,
87
+ inlineAudioPlayer: false,
88
+ tabletLandscapePlayerTopPosition: 0,
89
+ });
90
+
91
+ expect(result).toBe(-130);
92
+ });
93
+
94
+ it("returns -50 + progressBarHeight for mobile audio player in docked mode", () => {
95
+ const result = getMoveUpValue({
96
+ additionalData: {},
97
+ insets: { top: 0 },
98
+ isAudioItem: false,
99
+ progressBarHeight: 7,
100
+ isTablet: false,
101
+ isTabletLandscape: false,
102
+ inlineAudioPlayer: false,
103
+ tabletLandscapePlayerTopPosition: 0,
104
+ });
105
+
106
+ expect(result).toBe(-50 + 7);
107
+ });
108
+ });
@@ -0,0 +1,5 @@
1
+ export const DURATION_TO_MINIMIZE = 200; // old value 200
2
+
3
+ export const DURATION_TO_MAXIMIZE = 0;
4
+
5
+ export const DEFAULT_DURATION_FOR_ANIMATION = 200; // old value 100
@@ -14,3 +14,5 @@ export { useModalAnimationContext } from "./useModalAnimationContext";
14
14
  export { AnimationComponent } from "./AnimationComponent";
15
15
 
16
16
  export { ComponentAnimationType, defaultAspectRatioWidth } from "./utils";
17
+
18
+ export { DURATION_TO_MINIMIZE, DURATION_TO_MAXIMIZE } from "./const";
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable padding-line-between-statements */
2
2
 
3
3
  import { PlayerAnimationStateEnum } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
4
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
4
5
 
5
6
  export enum ComponentAnimationType {
6
7
  bottomBar = "bottomBar",
@@ -300,3 +301,32 @@ export const resetScrollAnimatedValues = (
300
301
  dragScrollY.setValue(0);
301
302
  dragVideoPlayerY.setValue(0);
302
303
  };
304
+
305
+ export const getMoveUpValue = ({
306
+ additionalData,
307
+ insets,
308
+ isAudioItem,
309
+ progressBarHeight,
310
+ isTablet,
311
+ isTabletLandscape,
312
+ tabletLandscapePlayerTopPosition,
313
+ }) => {
314
+ if (additionalData.saveArea) {
315
+ return -insets.top + (isAudioItem ? 0 : progressBarHeight);
316
+ }
317
+
318
+ if (isAudioItem) {
319
+ // for any layouts in audioPlayer
320
+ return -1 * toNumberWithDefaultZero(additionalData?.marginTop);
321
+ }
322
+
323
+ if (isTablet) {
324
+ if (isTabletLandscape) {
325
+ return -tabletLandscapePlayerTopPosition + progressBarHeight;
326
+ } else {
327
+ return -130;
328
+ }
329
+ }
330
+
331
+ return -50 + progressBarHeight;
332
+ };
@@ -10,6 +10,7 @@ import {
10
10
  import { useTargetScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
11
11
  import { ComponentsMap } from "@applicaster/zapp-react-native-ui-components/Components/River/ComponentsMap";
12
12
  import { useSafeAreaInsets } from "react-native-safe-area-context";
13
+ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
13
14
 
14
15
  const { width: SCREEN_WIDTH } = Dimensions.get("screen");
15
16
 
@@ -78,6 +79,10 @@ export const PlayerDetails = ({
78
79
  }
79
80
  }, [isAudioPlayer]);
80
81
 
82
+ if (isNilOrEmpty(screenData?.ui_components)) {
83
+ return null;
84
+ }
85
+
81
86
  return (
82
87
  <Animated.View
83
88
  style={[