@applicaster/zapp-react-native-ui-components 13.0.8-alpha.4915596275 → 13.0.8-alpha.8384339831

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.
@@ -88,7 +88,7 @@ export const VideoModalMode = {
88
88
  MAXIMIZED: "MAXIMIZED",
89
89
  MINIMIZED: "MINIMIZED",
90
90
  FULLSCREEN: "FULLSCREEN",
91
- } as const;
91
+ };
92
92
 
93
93
  export type PlayNextData = {
94
94
  state: PlayNextState;
@@ -132,7 +132,7 @@ const webStyles = {
132
132
  playerScreen: {
133
133
  flex: 1,
134
134
  height: "100vh",
135
- backgroundColor: "black",
135
+ background: "black",
136
136
  },
137
137
  playerWrapper: {
138
138
  height: "100%",
@@ -150,6 +150,7 @@ const nativeStyles = {
150
150
  },
151
151
  playerScreen: {
152
152
  flex: 1,
153
+ backgroundColor: "black",
153
154
  overflow: "hidden",
154
155
  },
155
156
  playerWrapper: {
@@ -569,9 +570,8 @@ const PlayerContainerComponent = (props: Props) => {
569
570
  const isInlineTV = isInlineTVUtil(screenData);
570
571
 
571
572
  const inline =
572
- [VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
573
- mode as any
574
- ) || isInlineTV;
573
+ [VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(mode) ||
574
+ isInlineTV;
575
575
 
576
576
  const value = React.useMemo(
577
577
  () => ({ playerId: state.playerId }),
@@ -592,11 +592,7 @@ const PlayerContainerComponent = (props: Props) => {
592
592
  );
593
593
  }
594
594
 
595
- if (
596
- screen_background_color &&
597
- mode !== VideoModalMode.FULLSCREEN &&
598
- isTV()
599
- ) {
595
+ if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
600
596
  updatedStyles.playerScreen.backgroundColor = screen_background_color;
601
597
  }
602
598
 
@@ -626,8 +622,6 @@ const PlayerContainerComponent = (props: Props) => {
626
622
  playNextData,
627
623
  };
628
624
 
629
- const pointerEventsProp = mode === "MINIMIZED" ? "box-none" : "auto";
630
-
631
625
  return (
632
626
  <PlayerStateContext.Provider value={value}>
633
627
  <PlayerContainerContextProvider
@@ -648,17 +642,14 @@ const PlayerContainerComponent = (props: Props) => {
648
642
  preferredFocus
649
643
  shouldUsePreferredFocus
650
644
  groupId={groupId}
651
- pointerEvents={pointerEventsProp}
652
645
  >
653
646
  {/* Video player and components */}
654
647
  <View
655
648
  style={styles.playerScreen}
656
649
  testID={"player-screen-container"}
657
- pointerEvents={pointerEventsProp}
658
650
  >
659
651
  {/* Player container */}
660
652
  <View
661
- pointerEvents={pointerEventsProp}
662
653
  style={[
663
654
  styles.playerWrapper,
664
655
  // eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { View, StyleSheet, FlatList } from "react-native";
3
+ import { FlatList, StyleSheet, View } 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";
@@ -9,8 +9,8 @@ import { useScreenConfiguration } from "../useScreenConfiguration";
9
9
  import { RefreshControl } from "../RefreshControl";
10
10
  import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
11
11
  import {
12
- useProfilerLogging,
13
12
  usePipesCacheReset,
13
+ useProfilerLogging,
14
14
  } from "@applicaster/zapp-react-native-utils/reactHooks";
15
15
  import { useLoadingState } from "./hooks/useLoadingState";
16
16
  import { ViewportTracker } from "../../Viewport";
@@ -25,6 +25,8 @@ import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHo
25
25
  import { useShallow } from "zustand/react/shallow";
26
26
 
27
27
  import { isAndroidPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
28
+ import { ComponentsMapHeightContext } from "./ContextProviders/ComponentsMapHeightContext";
29
+ import { ComponentsMapRefContext } from "./ContextProviders/ComponentsMapRefContext";
28
30
 
29
31
  const isAndroid = isAndroidPlatform();
30
32
 
@@ -70,6 +72,7 @@ function ComponentsMapComponent(props: Props) {
70
72
  } = props;
71
73
 
72
74
  const flatListRef = React.useRef<FlatList | null>(null);
75
+ const flatListWrapperRef = React.useRef<View | null>(null);
73
76
  const screenConfig = useScreenConfiguration(riverId);
74
77
  const screenData = useScreenData(riverId);
75
78
  const pullToRefreshEnabled = screenData?.rules?.pull_to_refresh_enabled;
@@ -265,48 +268,57 @@ function ComponentsMapComponent(props: Props) {
265
268
  // The Screen Picker in Mobile is completly different than the TV
266
269
  // so the various offsets / margins in TV do not apply here.
267
270
  return (
268
- <View style={styles.container}>
269
- <ScreenLoadingMeasurements
270
- riverId={riverId}
271
- numberOfComponents={riverComponents.length}
272
- >
273
- <ViewportTracker>
274
- <FlatList
275
- ref={(ref) => {
276
- flatListRef.current = ref;
277
- }}
278
- // Fix for WebView rerender crashes on Android API 28+
279
- // https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
280
- overScrollMode={isAndroid ? "never" : "auto"}
281
- scrollIndicatorInsets={scrollIndicatorInsets}
282
- extraData={feed}
283
- stickyHeaderIndices={stickyHeaderIndices}
284
- removeClippedSubviews={isAndroid}
285
- onLayout={handleOnLayout}
286
- initialNumToRender={3}
287
- maxToRenderPerBatch={10}
288
- windowSize={12}
289
- listKey={riverId}
290
- keyExtractor={keyExtractor}
291
- renderItem={renderRiverItem}
292
- data={riverComponents}
293
- contentContainerStyle={contentContainerStyle}
294
- ListFooterComponent={
295
- <RiverFooter
296
- flatListHeight={flatListHeight}
297
- loadingState={loadingState}
271
+ <View
272
+ style={styles.container}
273
+ ref={(ref) => {
274
+ flatListWrapperRef.current = ref;
275
+ }}
276
+ >
277
+ <ComponentsMapHeightContext.Provider value={flatListHeight}>
278
+ <ComponentsMapRefContext.Provider value={flatListWrapperRef}>
279
+ <ScreenLoadingMeasurements
280
+ riverId={riverId}
281
+ numberOfComponents={riverComponents.length}
282
+ >
283
+ <ViewportTracker>
284
+ <FlatList
285
+ ref={(ref) => {
286
+ flatListRef.current = ref;
287
+ }}
288
+ // Fix for WebView rerender crashes on Android API 28+
289
+ // https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
290
+ overScrollMode={isAndroid ? "never" : "auto"}
291
+ scrollIndicatorInsets={scrollIndicatorInsets}
292
+ extraData={feed}
293
+ stickyHeaderIndices={stickyHeaderIndices}
294
+ removeClippedSubviews={isAndroid}
295
+ onLayout={handleOnLayout}
296
+ initialNumToRender={3}
297
+ maxToRenderPerBatch={10}
298
+ windowSize={12}
299
+ listKey={riverId}
300
+ keyExtractor={keyExtractor}
301
+ renderItem={renderRiverItem}
302
+ data={riverComponents}
303
+ contentContainerStyle={contentContainerStyle}
304
+ ListFooterComponent={
305
+ <RiverFooter
306
+ flatListHeight={flatListHeight}
307
+ loadingState={loadingState}
308
+ />
309
+ }
310
+ refreshControl={refreshControl}
311
+ onScrollBeginDrag={onScrollBeginDrag}
312
+ onScroll={onScroll}
313
+ onMomentumScrollEnd={_onMomentumScrollEnd}
314
+ onScrollEndDrag={_onScrollEndDrag}
315
+ scrollEventThrottle={16}
316
+ {...scrollViewExtraProps}
298
317
  />
299
- }
300
- refreshControl={refreshControl}
301
- onScrollBeginDrag={onScrollBeginDrag}
302
- onScroll={onScroll}
303
- onMomentumScrollEnd={_onMomentumScrollEnd}
304
- onScrollEndDrag={_onScrollEndDrag}
305
- scrollEventThrottle={16}
306
- {...scrollViewExtraProps}
307
- />
308
- </ViewportTracker>
309
- </ScreenLoadingMeasurements>
318
+ </ViewportTracker>
319
+ </ScreenLoadingMeasurements>
320
+ </ComponentsMapRefContext.Provider>
321
+ </ComponentsMapHeightContext.Provider>
310
322
  </View>
311
323
  );
312
324
  }
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+
3
+ export const ComponentsMapHeightContext = React.createContext<number | null>(
4
+ null
5
+ );
6
+
7
+ export const useComponentsMapHeight = () =>
8
+ React.useContext(ComponentsMapHeightContext);
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+ import { View } from "react-native";
3
+
4
+ export const ComponentsMapRefContext =
5
+ React.createContext<React.RefObject<View | null> | null>(null);
6
+
7
+ export const useComponentsMapRef = () =>
8
+ React.useContext(ComponentsMapRefContext);
@@ -372,7 +372,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
372
372
  maxDeltaY={lastSnap - modalSnapPoints[0]}
373
373
  numberOfTaps={1}
374
374
  >
375
- <View pointerEvents="box-none">
375
+ <View pointerEvents="box-none" style={generalStyles.container}>
376
376
  <PanGestureHandler
377
377
  enabled={isEnablePanGesture}
378
378
  ref={panHandlerRef}
@@ -382,7 +382,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
382
382
  onHandlerStateChange={onHandlerStateChange}
383
383
  activeOffsetY={[-5, 5]}
384
384
  >
385
- <Animated.View>
385
+ <Animated.View style={generalStyles.container}>
386
386
  <NativeViewGestureHandler
387
387
  ref={scrollRef}
388
388
  waitFor={tapHandlerRef}
@@ -397,6 +397,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
397
397
  onMomentumScrollEnd={onMomentumScrollEnd}
398
398
  scrollEventThrottle={1}
399
399
  showsVerticalScrollIndicator={false}
400
+ contentContainerStyle={generalStyles.container}
400
401
  >
401
402
  {children}
402
403
  </Animated.ScrollView>
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect } from "react";
2
- import { Animated, Dimensions } from "react-native";
2
+ import { Animated } from "react-native";
3
3
 
4
4
  import {
5
5
  useSafeAreaInsets,
@@ -11,7 +11,6 @@ import { isLive } from "@applicaster/zapp-react-native-utils/playerUtils";
11
11
 
12
12
  import { PROGRESS_BAR_HEIGHT } from "./utils";
13
13
  import { useConfiguration } from "../utils";
14
- import { useIsTabletLandscape } from "@applicaster/zapp-react-native-utils/reactHooks/device/useMemoizedIsTablet";
15
14
 
16
15
  export enum PlayerAnimationStateEnum {
17
16
  minimize = "minimize",
@@ -24,7 +23,6 @@ export enum PlayerAnimationStateEnum {
24
23
  export type PlayerAnimationStateT = number | PlayerAnimationStateEnum | null;
25
24
 
26
25
  export type ModalAnimationContextT = {
27
- yTranslate: React.MutableRefObject<Animated.Value | null>;
28
26
  isActiveGesture: boolean;
29
27
  playerAnimationState: PlayerAnimationStateT;
30
28
  setPlayerAnimationState: (value: PlayerAnimationStateT) => void;
@@ -50,7 +48,6 @@ export type ModalAnimationContextT = {
50
48
  };
51
49
 
52
50
  export const ReactContext = React.createContext<ModalAnimationContextT>({
53
- yTranslate: React.createRef<Animated.Value | null>(),
54
51
  isActiveGesture: false,
55
52
  playerAnimationState: null,
56
53
  setPlayerAnimationState: () => null,
@@ -76,10 +73,6 @@ export const ReactContext = React.createContext<ModalAnimationContextT>({
76
73
  });
77
74
 
78
75
  const Provider = ({ children }: { children: React.ReactNode }) => {
79
- const yTranslate = React.useRef(
80
- new Animated.Value(Dimensions.get("window").height)
81
- );
82
-
83
76
  const [playerAnimationState, setPlayerAnimationState] =
84
77
  React.useState<PlayerAnimationStateT>(null);
85
78
 
@@ -103,6 +96,13 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
103
96
  setStartComponentsAnimation(false);
104
97
  }, []);
105
98
 
99
+ useEffect(() => {
100
+ // Reset player animation state when video modal is closed
101
+ if (!visible) {
102
+ resetPlayerAnimationState();
103
+ }
104
+ }, [visible, resetPlayerAnimationState]);
105
+
106
106
  // Animated values
107
107
  const lastScrollY = React.useRef(new Animated.Value(0)).current;
108
108
  const dragScrollY = React.useRef(new Animated.Value(0)).current;
@@ -115,29 +115,6 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
115
115
  const { bottom: bottomSafeArea } = useSafeAreaInsets();
116
116
  const bottomTabBarHeight = useGetBottomTabBarHeight();
117
117
  const startComponentsAnimationDistance = Math.round((height * 60) / 100);
118
- const isTabletLandscape = useIsTabletLandscape();
119
- const windowDimensions = Dimensions.get("window");
120
-
121
- useEffect(() => {
122
- // Reset player animation state when video modal is closed
123
- if (!visible) {
124
- resetPlayerAnimationState();
125
-
126
- if (!isTabletLandscape) {
127
- // restore to portrait ( in portrait mode height is bigger)
128
- if (windowDimensions.height > windowDimensions.width) {
129
- yTranslate.current?.setValue(windowDimensions.height);
130
- }
131
- } else {
132
- yTranslate.current?.setValue(windowDimensions.height);
133
- }
134
- }
135
- }, [
136
- visible,
137
- resetPlayerAnimationState,
138
- windowDimensions.height,
139
- isTabletLandscape,
140
- ]);
141
118
 
142
119
  React.useEffect(() => {
143
120
  if (visible && mode === "MAXIMIZED" && height !== safeAreaFrameHeight) {
@@ -164,7 +141,6 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
164
141
  return (
165
142
  <ReactContext.Provider
166
143
  value={{
167
- yTranslate,
168
144
  startComponentsAnimation,
169
145
  setStartComponentsAnimation,
170
146
  isActiveGesture: playerAnimationState !== null,
@@ -4,17 +4,16 @@ import {
4
4
  Dimensions,
5
5
  Easing,
6
6
  StyleProp,
7
- ViewStyle,
8
7
  StyleSheet,
8
+ ViewStyle,
9
9
  } from "react-native";
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
13
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
14
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
15
- import { useDelayedPlayerDetails } from "./hooks";
16
14
 
17
15
  const { width: SCREEN_WIDTH } = Dimensions.get("screen");
16
+ const flex1 = { flex: 1 };
18
17
 
19
18
  type Configuration = {
20
19
  [key: string]: any;
@@ -28,10 +27,6 @@ type Props = {
28
27
  isTabletLandscape?: boolean;
29
28
  isAudioPlayer?: boolean;
30
29
  isTablet?: boolean;
31
- inline?: any;
32
- docked?: boolean;
33
- isModal?: boolean;
34
- pip?: boolean;
35
30
  };
36
31
 
37
32
  const containerStyle = ({
@@ -48,31 +43,15 @@ export const PlayerDetails = ({
48
43
  configuration,
49
44
  isTabletLandscape = false,
50
45
  isAudioPlayer,
51
- inline,
52
- docked,
53
- isModal,
54
- pip,
46
+ isTablet = false,
55
47
  }: Props) => {
56
- const isInlineModal = inline && isModal;
57
-
58
- // Mounting the PlayerDetails component is a resource-intensive process.
59
- // Therefore, for performance reasons, we mount it with a delay to make the rotation process as smooth as possible.
60
- // The flow is as follows: the rotation occurs first, and then, after a short delay, we mount the PlayerDetails component.
61
- // This helps to avoid blocking the rotation and any animations related to the rotation.
62
- const isShowPlayerDetails = useDelayedPlayerDetails({
63
- isInline: isInlineModal,
64
- isDocked: docked,
65
- isPip: pip,
66
- });
67
-
68
- const isTablet = useIsTablet();
69
48
  const screenData = useTargetScreenData(entry);
70
49
  const insets = useSafeAreaInsets();
71
50
 
72
51
  const extraTabletStyles = !isAudioPlayer
73
52
  ? isTabletLandscape
74
53
  ? { marginTop: -insets.top, paddingTop: insets.top + 20 }
75
- : { marginTop: -8, paddingTop: -8 }
54
+ : {}
76
55
  : {};
77
56
 
78
57
  // Animation setup
@@ -101,7 +80,7 @@ export const PlayerDetails = ({
101
80
  }
102
81
  }, [isAudioPlayer]);
103
82
 
104
- if (isNilOrEmpty(screenData?.ui_components) || !isShowPlayerDetails) {
83
+ if (isNilOrEmpty(screenData?.ui_components)) {
105
84
  return null;
106
85
  }
107
86
 
@@ -115,6 +94,7 @@ export const PlayerDetails = ({
115
94
  transform: [{ translateY }],
116
95
  opacity,
117
96
  },
97
+ flex1,
118
98
  {
119
99
  // workaround for avoid wrong text-height after going back to portrait rotation
120
100
  // we don't see this view in landscape mode, so we are able to use fixed width from portrait mode
@@ -129,6 +109,7 @@ export const PlayerDetails = ({
129
109
  riverId={screenData.id}
130
110
  feed={screenData?.data?.source}
131
111
  riverComponents={screenData.ui_components}
112
+ isScreenWrappedInContainer
132
113
  />
133
114
  ) : null}
134
115
  </Animated.View>
@@ -9,8 +9,16 @@ import {
9
9
  import { Edge, SafeAreaView } from "react-native-safe-area-context";
10
10
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
11
11
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
12
+ import { PlayerDetails } from "./PlayerDetails";
12
13
  import { playerDimensionsHack } from "./utils";
13
- import { getTabletWidth } from "@applicaster/zapp-react-native-utils/playerUtils";
14
+ import { useDelayedPlayerDetails } from "./hooks";
15
+
16
+ import {
17
+ AnimatedScrollModal,
18
+ AnimatedVideoPlayerComponent,
19
+ AnimationComponent,
20
+ ComponentAnimationType,
21
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
14
22
 
15
23
  const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("screen");
16
24
 
@@ -36,15 +44,29 @@ type Props = {
36
44
  isModal?: boolean;
37
45
  fullscreen?: boolean;
38
46
  isTabletPortrait?: boolean;
47
+ children: (playerDimensions: DimensionsT) => React.ReactNode;
39
48
  configuration: Configuration;
40
-
41
- playerContent: (styles: ViewStyle) => React.ReactNode;
42
49
  };
43
50
 
44
51
  const defaultStyles = StyleSheet.create({
45
52
  playerContainer: { position: "relative", alignSelf: "center", zIndex: 200 },
53
+ playerDetails: { flex: 1, paddingTop: 20 },
54
+ flex: { flex: 1 },
55
+ });
56
+
57
+ const orientationStyles = StyleSheet.create({
58
+ landscape: { flexDirection: "row" },
59
+ portrait: { flexDirection: "column" },
46
60
  });
47
61
 
62
+ const directionStyles = (isTabletLandscape: boolean): ViewStyle => {
63
+ if (isTabletLandscape) {
64
+ return orientationStyles.landscape;
65
+ }
66
+
67
+ return orientationStyles.portrait;
68
+ };
69
+
48
70
  const getScreenAspectRatio = () => {
49
71
  const longEdge = Math.max(SCREEN_WIDTH, SCREEN_HEIGHT);
50
72
  const shortEdge = Math.min(SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -64,6 +86,51 @@ const getEdges = (isTablet: boolean, isInlineModal: boolean) => {
64
86
  return ["top"];
65
87
  };
66
88
 
89
+ const isPercentage = (value: string | number): boolean => {
90
+ if (typeof value === "string") {
91
+ return value.includes("%");
92
+ }
93
+
94
+ return false;
95
+ };
96
+
97
+ const getPercentageOf = (percent: string, value: number) => {
98
+ const percentageValue = parseFloat(percent.replace("%", ""));
99
+
100
+ if (isNaN(percentageValue)) {
101
+ return value;
102
+ }
103
+
104
+ return (value * percentageValue) / 100;
105
+ };
106
+
107
+ const getTabletWidth = (
108
+ configuration: Configuration,
109
+ dimensions: DimensionsT
110
+ ) => {
111
+ const tablet_landscape_sidebar_width =
112
+ configuration?.tablet_landscape_sidebar_width;
113
+
114
+ const { width } = dimensions;
115
+ let widthValue = Number(width);
116
+
117
+ if (isPercentage(width)) {
118
+ widthValue = getPercentageOf(width.toString(), SCREEN_WIDTH);
119
+ }
120
+
121
+ const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
122
+
123
+ if (tablet_landscape_sidebar_width?.includes("%")) {
124
+ return widthValue * (1 - sidebarWidth / 100);
125
+ }
126
+
127
+ if (Number.isNaN(sidebarWidth)) {
128
+ return widthValue * 0.65;
129
+ }
130
+
131
+ return widthValue - sidebarWidth;
132
+ };
133
+
67
134
  const PlayerWrapperComponent = (props: Props) => {
68
135
  const {
69
136
  entry,
@@ -72,26 +139,35 @@ const PlayerWrapperComponent = (props: Props) => {
72
139
  inline,
73
140
  docked,
74
141
  isModal,
142
+ children,
75
143
  isTabletPortrait,
76
144
  configuration,
145
+ fullscreen,
77
146
  pip,
78
- playerContent,
79
147
  } = props;
80
148
 
81
149
  const isTablet = useIsTablet();
82
150
 
83
151
  const isInlineModal = inline && isModal;
84
152
 
153
+ // Mounting the PlayerDetails component is a resource-intensive process.
154
+ // Therefore, for performance reasons, we mount it with a delay to make the rotation process as smooth as possible.
155
+ // The flow is as follows: the rotation occurs first, and then, after a short delay, we mount the PlayerDetails component.
156
+ // This helps to avoid blocking the rotation and any animations related to the rotation.
157
+ const isShowPlayerDetails = useDelayedPlayerDetails({
158
+ isInline: isInlineModal,
159
+ isDocked: docked,
160
+ isPip: pip,
161
+ });
162
+
85
163
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
86
164
 
87
- const tabletWidth = getTabletWidth(
88
- configuration.tablet_landscape_sidebar_width,
89
- style
90
- );
165
+ const tabletWidth = getTabletWidth(configuration, style);
91
166
 
92
167
  const baseDimensions: DimensionsT = React.useMemo(
93
168
  () => ({
94
- width: isInlineModal && isTabletLandscape ? tabletWidth : "100%",
169
+ width:
170
+ isInlineModal && !docked && isTabletLandscape ? tabletWidth : "100%",
95
171
  height: undefined,
96
172
  }),
97
173
  [isInlineModal, tabletWidth, docked]
@@ -100,7 +176,7 @@ const PlayerWrapperComponent = (props: Props) => {
100
176
  const playerDimensions: DimensionsT = React.useMemo(
101
177
  () => ({
102
178
  ...baseDimensions,
103
- width: baseDimensions.width,
179
+ width: isInlineModal && docked ? undefined : baseDimensions.width,
104
180
  aspectRatio: !isInlineModal && !pip ? getScreenAspectRatio() : 16 / 9,
105
181
  }),
106
182
  [baseDimensions, isInlineModal, pip]
@@ -109,7 +185,8 @@ const PlayerWrapperComponent = (props: Props) => {
109
185
  const containerDimensions: DimensionsT = React.useMemo(
110
186
  () => ({
111
187
  ...baseDimensions,
112
- aspectRatio: playerDimensions.aspectRatio,
188
+ aspectRatio:
189
+ isInlineModal && docked ? undefined : playerDimensions.aspectRatio,
113
190
  }),
114
191
  [baseDimensions, isInlineModal, docked, playerDimensions.aspectRatio]
115
192
  );
@@ -117,29 +194,67 @@ const PlayerWrapperComponent = (props: Props) => {
117
194
  const WrapperView = React.useMemo(() => (isTV() ? View : SafeAreaView), []);
118
195
 
119
196
  const childrenStyles = React.useMemo(
120
- () => ({
121
- ...playerDimensions,
122
- ...playerDimensionsHack,
123
- }),
197
+ () => ({ ...playerDimensions, ...playerDimensionsHack }),
124
198
  [containerDimensions, playerDimensionsHack]
125
199
  );
126
200
 
201
+ const wrapperViewStyle: ViewStyle = {
202
+ backgroundColor:
203
+ isTablet && !fullscreen
204
+ ? configuration?.tablet_landscape_player_container_background_color
205
+ : "transparent",
206
+ };
207
+
127
208
  return (
128
209
  <WrapperView
129
210
  edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
130
- style={playerDimensionsHack}
211
+ style={[wrapperViewStyle, style, playerDimensionsHack]}
131
212
  >
132
- <View
133
- testID={`${entry?.id}-player-container`}
134
- style={[
135
- defaultStyles.playerContainer,
136
- playerDimensionsHack,
137
- containerDimensions,
138
- containerStyle,
139
- ]}
213
+ <AnimationComponent
214
+ animationType={ComponentAnimationType.moveUpComponent}
215
+ additionalData={{ saveArea: true }}
216
+ style={[directionStyles(isTabletLandscape), defaultStyles.flex]}
140
217
  >
141
- {playerContent(childrenStyles)}
142
- </View>
218
+ <View
219
+ testID={`${entry?.id}-player-container`}
220
+ style={[
221
+ defaultStyles.playerContainer,
222
+ containerDimensions,
223
+ containerStyle,
224
+ playerDimensionsHack,
225
+ ]}
226
+ >
227
+ <AnimationComponent
228
+ animationType={ComponentAnimationType.moveUpComponent}
229
+ style={isTabletLandscape ? defaultStyles.flex : undefined}
230
+ additionalData={{
231
+ useLayoutMeasure: isTabletLandscape,
232
+ disableAnimatedComponent: !isTabletLandscape,
233
+ resetAnimationValue: isTabletLandscape && docked,
234
+ }}
235
+ >
236
+ <AnimatedVideoPlayerComponent>
237
+ {children(childrenStyles)}
238
+ </AnimatedVideoPlayerComponent>
239
+ </AnimationComponent>
240
+ </View>
241
+ <AnimatedScrollModal>
242
+ {isShowPlayerDetails ? (
243
+ <AnimationComponent
244
+ animationType={ComponentAnimationType.componentFade}
245
+ style={defaultStyles.flex}
246
+ >
247
+ <PlayerDetails
248
+ configuration={configuration}
249
+ style={defaultStyles.playerDetails}
250
+ entry={entry}
251
+ isTabletLandscape={isTabletLandscape}
252
+ isTablet={isTablet}
253
+ />
254
+ </AnimationComponent>
255
+ ) : null}
256
+ </AnimatedScrollModal>
257
+ </AnimationComponent>
143
258
  </WrapperView>
144
259
  );
145
260
  };
@@ -17,7 +17,11 @@ import {
17
17
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
18
18
 
19
19
  import { withModalNavigationContextProvider } from "../../Contexts/ModalNavigationContext";
20
- import { useModalSize, useInitialPlayerState } from "./hooks";
20
+ import {
21
+ useModalSize,
22
+ useBackgroundColor,
23
+ useInitialPlayerState,
24
+ } from "./hooks";
21
25
 
22
26
  import { APP_EVENTS } from "@applicaster/zapp-react-native-utils/appUtils/events";
23
27
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
@@ -29,6 +33,8 @@ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
29
33
  import { Spinner } from "../Spinner";
30
34
  import { OpaqueLayer } from "./OpaqueLayer";
31
35
 
36
+ import { AnimatedPlayerModalWrapper } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
37
+
32
38
  const LOADER_BACKGROUND_COLOR = "rgba(64,64,64,0.5)";
33
39
 
34
40
  const styles = StyleSheet.create({
@@ -59,6 +65,7 @@ const VideoModalComponent = () => {
59
65
 
60
66
  const modalSize = useModalSize();
61
67
  const isFirstRender = useIsInitialRender();
68
+ const backgroundColor = useBackgroundColor();
62
69
 
63
70
  const {
64
71
  closeVideoModal,
@@ -138,13 +145,20 @@ const VideoModalComponent = () => {
138
145
  {mode === "FULLSCREEN" && <OpaqueLayer />}
139
146
 
140
147
  {itemIdHooksFinished === item?.id ? (
141
- <View pointerEvents="box-none" style={styles.container}>
148
+ <AnimatedPlayerModalWrapper
149
+ style={[
150
+ styles.container,
151
+ {
152
+ backgroundColor,
153
+ },
154
+ ]}
155
+ >
142
156
  <HandlePlayable
143
157
  item={item}
144
158
  isModal={mode !== "PIP"}
145
159
  mode={mode}
146
160
  />
147
- </View>
161
+ </AnimatedPlayerModalWrapper>
148
162
  ) : (
149
163
  <View style={styles.loaderContainer}>
150
164
  <Spinner />
@@ -13,7 +13,6 @@ const props = {
13
13
  tablet_landscape_sidebar_width: "35%",
14
14
  tablet_landscape_player_container_background_color: "red",
15
15
  },
16
- playerContent: jest.fn(() => <></>),
17
16
  };
18
17
 
19
18
  const mockUseIsDeviceTablet = jest.fn();
@@ -123,6 +122,13 @@ describe("PlayerWrapper", () => {
123
122
  </PlayerWrapper>
124
123
  );
125
124
 
125
+ const expectDimensions = {
126
+ ...dimensions,
127
+ width: undefined,
128
+ aspectRatio: 16 / 9,
129
+ };
130
+
126
131
  expect(element).toMatchSnapshot();
132
+ expect(children).toHaveBeenCalledWith(expectDimensions);
127
133
  });
128
134
  });
@@ -21,27 +21,87 @@ exports[`PlayerWrapper renders inline 1`] = `
21
21
  "top": "additive",
22
22
  }
23
23
  }
24
- style={{}}
24
+ style={
25
+ [
26
+ {
27
+ "backgroundColor": "transparent",
28
+ },
29
+ {
30
+ "height": 800,
31
+ "width": 300,
32
+ },
33
+ {},
34
+ ]
35
+ }
25
36
  >
26
37
  <View
38
+ additionalData={
39
+ {
40
+ "saveArea": true,
41
+ }
42
+ }
43
+ animationType="moveUpComponent"
27
44
  style={
28
45
  [
29
46
  {
30
- "alignSelf": "center",
31
- "position": "relative",
32
- "zIndex": 200,
47
+ "flexDirection": "column",
33
48
  },
34
- {},
35
49
  {
36
- "aspectRatio": 1.7777777777777777,
37
- "height": undefined,
38
- "width": "100%",
50
+ "flex": 1,
39
51
  },
40
- {},
41
52
  ]
42
53
  }
43
- testID="test-player-container"
44
- />
54
+ >
55
+ <View
56
+ style={
57
+ [
58
+ {
59
+ "alignSelf": "center",
60
+ "position": "relative",
61
+ "zIndex": 200,
62
+ },
63
+ {
64
+ "aspectRatio": 1.7777777777777777,
65
+ "height": undefined,
66
+ "width": "100%",
67
+ },
68
+ {},
69
+ {},
70
+ ]
71
+ }
72
+ testID="test-player-container"
73
+ />
74
+ <View
75
+ animationType="componentFade"
76
+ style={
77
+ {
78
+ "flex": 1,
79
+ }
80
+ }
81
+ >
82
+ <View
83
+ configuration={
84
+ {
85
+ "tablet_landscape_player_container_background_color": "red",
86
+ "tablet_landscape_sidebar_width": "35%",
87
+ }
88
+ }
89
+ entry={
90
+ {
91
+ "id": "test",
92
+ }
93
+ }
94
+ isTablet={false}
95
+ isTabletLandscape={false}
96
+ style={
97
+ {
98
+ "flex": 1,
99
+ "paddingTop": 20,
100
+ }
101
+ }
102
+ />
103
+ </View>
104
+ </View>
45
105
  </RNCSafeAreaView>
46
106
  </RNCSafeAreaProvider>
47
107
  `;
@@ -67,27 +127,57 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
67
127
  "top": "additive",
68
128
  }
69
129
  }
70
- style={{}}
130
+ style={
131
+ [
132
+ {
133
+ "backgroundColor": "transparent",
134
+ },
135
+ {
136
+ "height": undefined,
137
+ "width": 300,
138
+ },
139
+ {},
140
+ ]
141
+ }
71
142
  >
72
143
  <View
144
+ additionalData={
145
+ {
146
+ "saveArea": true,
147
+ }
148
+ }
149
+ animationType="moveUpComponent"
73
150
  style={
74
151
  [
75
152
  {
76
- "alignSelf": "center",
77
- "position": "relative",
78
- "zIndex": 200,
153
+ "flexDirection": "column",
79
154
  },
80
- {},
81
155
  {
82
- "aspectRatio": 1.7777777777777777,
83
- "height": undefined,
84
- "width": "100%",
156
+ "flex": 1,
85
157
  },
86
- {},
87
158
  ]
88
159
  }
89
- testID="test-player-container"
90
- />
160
+ >
161
+ <View
162
+ style={
163
+ [
164
+ {
165
+ "alignSelf": "center",
166
+ "position": "relative",
167
+ "zIndex": 200,
168
+ },
169
+ {
170
+ "aspectRatio": undefined,
171
+ "height": undefined,
172
+ "width": "100%",
173
+ },
174
+ {},
175
+ {},
176
+ ]
177
+ }
178
+ testID="test-player-container"
179
+ />
180
+ </View>
91
181
  </RNCSafeAreaView>
92
182
  </RNCSafeAreaProvider>
93
183
  `;
@@ -113,27 +203,103 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
113
203
  "top": "additive",
114
204
  }
115
205
  }
116
- style={{}}
206
+ style={
207
+ [
208
+ {
209
+ "backgroundColor": "red",
210
+ },
211
+ {
212
+ "height": 800,
213
+ "width": 300,
214
+ },
215
+ {},
216
+ ]
217
+ }
117
218
  >
118
219
  <View
220
+ additionalData={
221
+ {
222
+ "saveArea": true,
223
+ }
224
+ }
225
+ animationType="moveUpComponent"
119
226
  style={
120
227
  [
121
228
  {
122
- "alignSelf": "center",
123
- "position": "relative",
124
- "zIndex": 200,
229
+ "flexDirection": "row",
125
230
  },
126
- {},
127
231
  {
128
- "aspectRatio": 1.7777777777777777,
129
- "height": undefined,
130
- "width": 195,
232
+ "flex": 1,
131
233
  },
132
- {},
133
234
  ]
134
235
  }
135
- testID="test-player-container"
136
- />
236
+ >
237
+ <View
238
+ style={
239
+ [
240
+ {
241
+ "alignSelf": "center",
242
+ "position": "relative",
243
+ "zIndex": 200,
244
+ },
245
+ {
246
+ "aspectRatio": 1.7777777777777777,
247
+ "height": undefined,
248
+ "width": 195,
249
+ },
250
+ {},
251
+ {},
252
+ ]
253
+ }
254
+ testID="test-player-container"
255
+ >
256
+ <View
257
+ additionalData={
258
+ {
259
+ "disableAnimatedComponent": false,
260
+ "resetAnimationValue": undefined,
261
+ "useLayoutMeasure": true,
262
+ }
263
+ }
264
+ animationType="moveUpComponent"
265
+ style={
266
+ {
267
+ "flex": 1,
268
+ }
269
+ }
270
+ />
271
+ </View>
272
+ <View
273
+ animationType="componentFade"
274
+ style={
275
+ {
276
+ "flex": 1,
277
+ }
278
+ }
279
+ >
280
+ <View
281
+ configuration={
282
+ {
283
+ "tablet_landscape_player_container_background_color": "red",
284
+ "tablet_landscape_sidebar_width": "35%",
285
+ }
286
+ }
287
+ entry={
288
+ {
289
+ "id": "test",
290
+ }
291
+ }
292
+ isTablet={true}
293
+ isTabletLandscape={true}
294
+ style={
295
+ {
296
+ "flex": 1,
297
+ "paddingTop": 20,
298
+ }
299
+ }
300
+ />
301
+ </View>
302
+ </View>
137
303
  </RNCSafeAreaView>
138
304
  </RNCSafeAreaProvider>
139
305
  `;
@@ -159,27 +325,57 @@ exports[`PlayerWrapper renders properly 1`] = `
159
325
  "top": "additive",
160
326
  }
161
327
  }
162
- style={{}}
328
+ style={
329
+ [
330
+ {
331
+ "backgroundColor": "transparent",
332
+ },
333
+ {
334
+ "height": 800,
335
+ "width": 300,
336
+ },
337
+ {},
338
+ ]
339
+ }
163
340
  >
164
341
  <View
342
+ additionalData={
343
+ {
344
+ "saveArea": true,
345
+ }
346
+ }
347
+ animationType="moveUpComponent"
165
348
  style={
166
349
  [
167
350
  {
168
- "alignSelf": "center",
169
- "position": "relative",
170
- "zIndex": 200,
351
+ "flexDirection": "column",
171
352
  },
172
- {},
173
353
  {
174
- "aspectRatio": 1.7786666666666666,
175
- "height": undefined,
176
- "width": "100%",
354
+ "flex": 1,
177
355
  },
178
- {},
179
356
  ]
180
357
  }
181
- testID="test-player-container"
182
- />
358
+ >
359
+ <View
360
+ style={
361
+ [
362
+ {
363
+ "alignSelf": "center",
364
+ "position": "relative",
365
+ "zIndex": 200,
366
+ },
367
+ {
368
+ "aspectRatio": 1.7786666666666666,
369
+ "height": undefined,
370
+ "width": "100%",
371
+ },
372
+ {},
373
+ {},
374
+ ]
375
+ }
376
+ testID="test-player-container"
377
+ />
378
+ </View>
183
379
  </RNCSafeAreaView>
184
380
  </RNCSafeAreaProvider>
185
381
  `;
@@ -1,3 +1,5 @@
1
+ export { useBackgroundColor } from "./useBackgroundColor";
2
+
1
3
  export { useDelayedPlayerDetails } from "./useDelayedPlayerDetails";
2
4
 
3
5
  export { useInitialPlayerState } from "./useInitialPlayerState";
@@ -0,0 +1,10 @@
1
+ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
2
+ import { useConfiguration } from "../utils";
3
+
4
+ export const useBackgroundColor = (): string => {
5
+ const { modal_background_color: modalBackgroundColor } = useConfiguration();
6
+
7
+ const theme = useTheme<BaseThemePropertiesMobile>();
8
+
9
+ return modalBackgroundColor || theme?.status_background_color;
10
+ };
@@ -9,12 +9,6 @@ import {
9
9
 
10
10
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
11
11
  import { useSafeAreaFrame } from "react-native-safe-area-context";
12
- import {
13
- isAndroidPlatform,
14
- isAndroidVersionAtLeast,
15
- } from "@applicaster/zapp-react-native-utils/reactUtils";
16
- import { StatusBar } from "react-native";
17
- import { isAndroidTablet } from "@applicaster/zapp-react-native-utils/reactHooks/layout/isTablet";
18
12
 
19
13
  const { Logger } = getXray();
20
14
 
@@ -33,17 +27,12 @@ const MODAL_SIZE_FOR_LANDSCAPE: Size = {
33
27
  height: "100%",
34
28
  };
35
29
 
36
- const isOldAndroidDevice =
37
- isAndroidPlatform() && !isAndroidVersionAtLeast(35) && !isAndroidTablet();
38
-
39
30
  export const useModalSize = (): Size => {
40
31
  const frame = useSafeAreaFrame();
41
32
 
42
33
  const [modalSize, setModalSize] = React.useState<Size>({
43
34
  width: frame.width,
44
- height: isOldAndroidDevice
45
- ? frame.height + StatusBar.currentHeight
46
- : frame.height,
35
+ height: frame.height,
47
36
  });
48
37
 
49
38
  const setNewModalSize = React.useCallback((newSize, log) => {
@@ -55,12 +44,7 @@ export const useModalSize = (): Size => {
55
44
  return oldSize;
56
45
  }
57
46
 
58
- return {
59
- width: newSize.width,
60
- height: isOldAndroidDevice
61
- ? newSize.height + StatusBar.currentHeight
62
- : newSize.height,
63
- };
47
+ return newSize;
64
48
  });
65
49
 
66
50
  logger.debug({
@@ -34,9 +34,6 @@ export const useConfiguration = () => {
34
34
  minimised_height = 0,
35
35
  minimised_height_tablet = 0,
36
36
  modal_background_color,
37
- tablet_landscape_player_container_background_color,
38
- screen_background_color,
39
- audio_player_background_color,
40
37
  } = config;
41
38
 
42
39
  const minimisedHeight = useIsTablet()
@@ -46,9 +43,6 @@ export const useConfiguration = () => {
46
43
  return {
47
44
  minimised_height: Number(minimisedHeight),
48
45
  modal_background_color,
49
- tablet_landscape_player_container_background_color,
50
- audio_player_background_color,
51
- screen_background_color,
52
46
  };
53
47
  };
54
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "13.0.8-alpha.4915596275",
3
+ "version": "13.0.8-alpha.8384339831",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -31,10 +31,10 @@
31
31
  "redux-mock-store": "^1.5.3"
32
32
  },
33
33
  "dependencies": {
34
- "@applicaster/applicaster-types": "13.0.8-alpha.4915596275",
35
- "@applicaster/zapp-react-native-bridge": "13.0.8-alpha.4915596275",
36
- "@applicaster/zapp-react-native-redux": "13.0.8-alpha.4915596275",
37
- "@applicaster/zapp-react-native-utils": "13.0.8-alpha.4915596275",
34
+ "@applicaster/applicaster-types": "13.0.8-alpha.8384339831",
35
+ "@applicaster/zapp-react-native-bridge": "13.0.8-alpha.8384339831",
36
+ "@applicaster/zapp-react-native-redux": "13.0.8-alpha.8384339831",
37
+ "@applicaster/zapp-react-native-utils": "13.0.8-alpha.8384339831",
38
38
  "promise": "^8.3.0",
39
39
  "react-router-native": "^5.1.2",
40
40
  "url": "^0.11.0",