@applicaster/zapp-react-native-ui-components 14.0.0-alpha.5071825192 → 14.0.0-alpha.5621117258
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.
- package/Components/AudioPlayer/AudioPlayer.tsx +2 -2
- package/Components/AudioPlayer/AudioPlayerLayout.tsx +6 -6
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +6 -0
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +6 -0
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +2 -0
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +0 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +22 -10
- package/Components/River/ComponentsMap/ComponentsMap.tsx +5 -1
- package/Components/River/RiverItem.tsx +8 -8
- package/Components/River/TV/River.tsx +3 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +6 -0
- package/Components/TopMarginApplicator/TopMarginApplicator.tsx +15 -16
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +9 -1
- package/Components/VideoModal/PlayerDetails.tsx +24 -2
- package/Components/VideoModal/PlayerWrapper.tsx +26 -142
- package/Components/VideoModal/VideoModal.tsx +3 -17
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -7
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +44 -240
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +55 -17
- package/Components/VideoModal/hooks/index.ts +0 -2
- package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +26 -15
- package/Components/VideoModal/utils.ts +6 -0
- package/index.d.ts +1 -0
- package/package.json +5 -5
- package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
|
@@ -52,7 +52,7 @@ type Props = {
|
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
export function AudioPlayer(props: Props) {
|
|
55
|
-
const { audio_item, plugin_configuration
|
|
55
|
+
const { audio_item, plugin_configuration } = props;
|
|
56
56
|
const { extensions, title, summary } = audio_item;
|
|
57
57
|
|
|
58
58
|
const getProp = useCallback(
|
|
@@ -164,7 +164,7 @@ export function AudioPlayer(props: Props) {
|
|
|
164
164
|
]);
|
|
165
165
|
|
|
166
166
|
return (
|
|
167
|
-
<AudioPlayerLayout artwork={artwork} config={config}
|
|
167
|
+
<AudioPlayerLayout artwork={artwork} config={config}>
|
|
168
168
|
<Channel srcImage={config?.channelIcon} config={config} />
|
|
169
169
|
<Title title={title} config={config} />
|
|
170
170
|
<Summary summary={summary} config={config} />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useRef } from "react";
|
|
2
|
-
import { View, ImageBackground, Animated
|
|
2
|
+
import { View, ImageBackground, Animated } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
5
5
|
|
|
@@ -17,10 +17,9 @@ type Props = {
|
|
|
17
17
|
artworkBorderRadius: Option<number>;
|
|
18
18
|
};
|
|
19
19
|
children: React.ReactNode;
|
|
20
|
-
style: ViewStyle;
|
|
21
20
|
};
|
|
22
21
|
|
|
23
|
-
export function AudioPlayerLayout({ artwork, config, children
|
|
22
|
+
export function AudioPlayerLayout({ artwork, config, children }: Props) {
|
|
24
23
|
const fadeAnimation = useRef(new Animated.Value(0)).current;
|
|
25
24
|
|
|
26
25
|
const fadeAudioPlayerIn = () => {
|
|
@@ -33,9 +32,9 @@ export function AudioPlayerLayout({ artwork, config, children, style }: Props) {
|
|
|
33
32
|
|
|
34
33
|
const { isRTL, backgroundColor, backgroundImage } = config;
|
|
35
34
|
|
|
36
|
-
const backgroundImageSource = { uri: backgroundImage };
|
|
35
|
+
const backgroundImageSource = { uri: backgroundImage || artwork };
|
|
37
36
|
|
|
38
|
-
const backgroundColorStyle =
|
|
37
|
+
const backgroundColorStyle = backgroundImageSource.uri
|
|
39
38
|
? "transparent"
|
|
40
39
|
: backgroundColor;
|
|
41
40
|
|
|
@@ -67,7 +66,8 @@ export function AudioPlayerLayout({ artwork, config, children, style }: Props) {
|
|
|
67
66
|
native: {
|
|
68
67
|
backgroundColor: backgroundColorStyle,
|
|
69
68
|
overflow: "hidden",
|
|
70
|
-
|
|
69
|
+
width: "100%",
|
|
70
|
+
height: "100%",
|
|
71
71
|
},
|
|
72
72
|
samsung_tv: {
|
|
73
73
|
position: "absolute",
|
|
@@ -6,7 +6,9 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
6
6
|
style={
|
|
7
7
|
{
|
|
8
8
|
"backgroundColor": "transparent",
|
|
9
|
+
"height": "100%",
|
|
9
10
|
"overflow": "hidden",
|
|
11
|
+
"width": "100%",
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
>
|
|
@@ -15,8 +17,10 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
15
17
|
style={
|
|
16
18
|
{
|
|
17
19
|
"backgroundColor": "transparent",
|
|
20
|
+
"height": "100%",
|
|
18
21
|
"opacity": 0,
|
|
19
22
|
"overflow": "hidden",
|
|
23
|
+
"width": "100%",
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
>
|
|
@@ -56,7 +60,9 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
56
60
|
style={
|
|
57
61
|
{
|
|
58
62
|
"backgroundColor": "transparent",
|
|
63
|
+
"height": "100%",
|
|
59
64
|
"overflow": "hidden",
|
|
65
|
+
"width": "100%",
|
|
60
66
|
}
|
|
61
67
|
}
|
|
62
68
|
/>
|
|
@@ -6,7 +6,9 @@ exports[`<AudioPlayerLayout /> renders correctly 1`] = `
|
|
|
6
6
|
style={
|
|
7
7
|
{
|
|
8
8
|
"backgroundColor": "transparent",
|
|
9
|
+
"height": "100%",
|
|
9
10
|
"overflow": "hidden",
|
|
11
|
+
"width": "100%",
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
>
|
|
@@ -15,8 +17,10 @@ exports[`<AudioPlayerLayout /> renders correctly 1`] = `
|
|
|
15
17
|
style={
|
|
16
18
|
{
|
|
17
19
|
"backgroundColor": "transparent",
|
|
20
|
+
"height": "100%",
|
|
18
21
|
"opacity": 0,
|
|
19
22
|
"overflow": "hidden",
|
|
23
|
+
"width": "100%",
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
>
|
|
@@ -56,7 +60,9 @@ exports[`<AudioPlayerLayout /> renders correctly 1`] = `
|
|
|
56
60
|
style={
|
|
57
61
|
{
|
|
58
62
|
"backgroundColor": "transparent",
|
|
63
|
+
"height": "100%",
|
|
59
64
|
"overflow": "hidden",
|
|
65
|
+
"width": "100%",
|
|
60
66
|
}
|
|
61
67
|
}
|
|
62
68
|
/>
|
|
@@ -30,6 +30,7 @@ export const GeneralContentScreen = ({
|
|
|
30
30
|
isScreenWrappedInContainer,
|
|
31
31
|
componentsMapExtraProps = {},
|
|
32
32
|
focused,
|
|
33
|
+
extraOffset,
|
|
33
34
|
parentFocus,
|
|
34
35
|
containerHeight,
|
|
35
36
|
preferredFocus = false,
|
|
@@ -121,6 +122,7 @@ export const GeneralContentScreen = ({
|
|
|
121
122
|
isScreenWrappedInContainer={isScreenWrappedInContainer}
|
|
122
123
|
parentFocus={parentFocus}
|
|
123
124
|
focused={focused}
|
|
125
|
+
extraOffset={extraOffset}
|
|
124
126
|
containerHeight={containerHeight}
|
|
125
127
|
preferredFocus={preferredFocus}
|
|
126
128
|
{...componentsMapExtraProps}
|
|
@@ -88,7 +88,7 @@ export const VideoModalMode = {
|
|
|
88
88
|
MAXIMIZED: "MAXIMIZED",
|
|
89
89
|
MINIMIZED: "MINIMIZED",
|
|
90
90
|
FULLSCREEN: "FULLSCREEN",
|
|
91
|
-
};
|
|
91
|
+
} as const;
|
|
92
92
|
|
|
93
93
|
export type PlayNextData = {
|
|
94
94
|
state: PlayNextState;
|
|
@@ -105,6 +105,11 @@ const isTvOS = isTvOSPlatform();
|
|
|
105
105
|
// height for container with additional content below player
|
|
106
106
|
const INLINE_CONTAINER_CONTENT_HEIGHT = 400;
|
|
107
107
|
|
|
108
|
+
// Default Y offset for anchor points on non-Android TV platforms
|
|
109
|
+
const DEFAULT_OFFSET_Y = -600;
|
|
110
|
+
|
|
111
|
+
const EXTRA_ANCHOR_POINT_Y_OFFSET = isAndroidTV ? 0 : DEFAULT_OFFSET_Y;
|
|
112
|
+
|
|
108
113
|
const withBorderHack = () => {
|
|
109
114
|
if (isAndroidTV) {
|
|
110
115
|
/* @HACK: see GH#7269 */
|
|
@@ -127,7 +132,7 @@ const webStyles = {
|
|
|
127
132
|
playerScreen: {
|
|
128
133
|
flex: 1,
|
|
129
134
|
height: "100vh",
|
|
130
|
-
|
|
135
|
+
backgroundColor: "black",
|
|
131
136
|
},
|
|
132
137
|
playerWrapper: {
|
|
133
138
|
height: "100%",
|
|
@@ -135,9 +140,6 @@ const webStyles = {
|
|
|
135
140
|
},
|
|
136
141
|
inlineRiver: {
|
|
137
142
|
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
138
|
-
|
|
139
|
-
borderWidth: 4,
|
|
140
|
-
borderColor: "yellow",
|
|
141
143
|
},
|
|
142
144
|
};
|
|
143
145
|
|
|
@@ -568,8 +570,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
568
570
|
const isInlineTV = isInlineTVUtil(screenData);
|
|
569
571
|
|
|
570
572
|
const inline =
|
|
571
|
-
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
572
|
-
|
|
573
|
+
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
574
|
+
mode as any
|
|
575
|
+
) || isInlineTV;
|
|
573
576
|
|
|
574
577
|
const value = React.useMemo(
|
|
575
578
|
() => ({ playerId: state.playerId }),
|
|
@@ -590,7 +593,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
590
593
|
);
|
|
591
594
|
}
|
|
592
595
|
|
|
593
|
-
if (
|
|
596
|
+
if (
|
|
597
|
+
screen_background_color &&
|
|
598
|
+
mode !== VideoModalMode.FULLSCREEN &&
|
|
599
|
+
isTV()
|
|
600
|
+
) {
|
|
594
601
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
595
602
|
}
|
|
596
603
|
|
|
@@ -640,14 +647,17 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
640
647
|
preferredFocus
|
|
641
648
|
shouldUsePreferredFocus
|
|
642
649
|
groupId={groupId}
|
|
650
|
+
pointerEvents={mode === "MINIMIZED" ? "box-none" : "auto"}
|
|
643
651
|
>
|
|
644
652
|
{/* Video player and components */}
|
|
645
653
|
<View
|
|
646
654
|
style={styles.playerScreen}
|
|
647
655
|
testID={"player-screen-container"}
|
|
656
|
+
pointerEvents={mode === "MINIMIZED" ? "box-none" : "auto"}
|
|
648
657
|
>
|
|
649
658
|
{/* Player container */}
|
|
650
659
|
<View
|
|
660
|
+
pointerEvents={mode === "MINIMIZED" ? "box-none" : "auto"}
|
|
651
661
|
style={[
|
|
652
662
|
styles.playerWrapper,
|
|
653
663
|
// eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
|
|
@@ -719,11 +729,13 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
719
729
|
key={item.id}
|
|
720
730
|
groupId={FocusableGroupMainContainerId}
|
|
721
731
|
cellTapAction={onCellTap}
|
|
722
|
-
extraAnchorPointYOffset={
|
|
732
|
+
extraAnchorPointYOffset={
|
|
733
|
+
EXTRA_ANCHOR_POINT_Y_OFFSET
|
|
734
|
+
}
|
|
723
735
|
isScreenWrappedInContainer={true}
|
|
724
736
|
containerHeight={styles.inlineRiver.height}
|
|
725
737
|
componentsMapExtraProps={{
|
|
726
|
-
isNestedComponentsMap:
|
|
738
|
+
isNestedComponentsMap: R.T,
|
|
727
739
|
}}
|
|
728
740
|
/>
|
|
729
741
|
)}
|
|
@@ -281,8 +281,8 @@ function ComponentsMapComponent(props: Props) {
|
|
|
281
281
|
scrollIndicatorInsets={scrollIndicatorInsets}
|
|
282
282
|
extraData={feed}
|
|
283
283
|
stickyHeaderIndices={stickyHeaderIndices}
|
|
284
|
-
removeClippedSubviews={isAndroid}
|
|
285
284
|
onLayout={handleOnLayout}
|
|
285
|
+
removeClippedSubviews={isAndroid}
|
|
286
286
|
initialNumToRender={3}
|
|
287
287
|
maxToRenderPerBatch={10}
|
|
288
288
|
windowSize={12}
|
|
@@ -303,6 +303,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
303
303
|
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
304
304
|
onScrollEndDrag={_onScrollEndDrag}
|
|
305
305
|
scrollEventThrottle={16}
|
|
306
|
+
maintainVisibleContentPosition={{
|
|
307
|
+
minIndexForVisible: 0,
|
|
308
|
+
autoscrollToTopThreshold: 10,
|
|
309
|
+
}}
|
|
306
310
|
{...scrollViewExtraProps}
|
|
307
311
|
/>
|
|
308
312
|
</ViewportTracker>
|
|
@@ -39,10 +39,6 @@ function getFeedUrl(feed: ZappFeed, index: number) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const isNextIndex = (index, readyIndex) => {
|
|
43
|
-
return readyIndex + 1 >= index;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
42
|
/**
|
|
47
43
|
* useLoadingState for RiverItemComponent
|
|
48
44
|
* takes currentIndex and loadingState as arguments
|
|
@@ -52,20 +48,24 @@ const useLoadingState = (
|
|
|
52
48
|
loadingState: RiverItemType["loadingState"]
|
|
53
49
|
) => {
|
|
54
50
|
const [readyToBeDisplayed, setReadyToBeDisplayed] = React.useState(
|
|
55
|
-
|
|
51
|
+
loadingState.getValue().index + 1 >= currentIndex
|
|
56
52
|
);
|
|
57
53
|
|
|
58
54
|
useEffect(() => {
|
|
59
55
|
const subscription = loadingState.subscribe(({ index }) => {
|
|
60
|
-
if (
|
|
56
|
+
if (index + 1 >= currentIndex) {
|
|
61
57
|
setReadyToBeDisplayed(true);
|
|
62
58
|
}
|
|
63
59
|
});
|
|
64
60
|
|
|
61
|
+
if (loadingState.getValue().index + 1 >= currentIndex) {
|
|
62
|
+
setReadyToBeDisplayed(true);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
65
|
return () => {
|
|
66
66
|
subscription.unsubscribe();
|
|
67
67
|
};
|
|
68
|
-
}, [currentIndex]);
|
|
68
|
+
}, [loadingState, currentIndex]);
|
|
69
69
|
|
|
70
70
|
return readyToBeDisplayed;
|
|
71
71
|
};
|
|
@@ -151,7 +151,7 @@ function RiverItemComponent(props: RiverItemType) {
|
|
|
151
151
|
component={item}
|
|
152
152
|
componentIndex={index}
|
|
153
153
|
onLoadFailed={onLoadFailed}
|
|
154
|
-
onLoadFinished={() => onLoadFinished(index)}
|
|
154
|
+
onLoadFinished={() => onLoadFinished(index)} // Keeping it here to don't break the plugins.
|
|
155
155
|
groupId={groupId}
|
|
156
156
|
feedUrl={feedUrl}
|
|
157
157
|
isLast={isLast}
|
|
@@ -26,6 +26,7 @@ type Props = {
|
|
|
26
26
|
componentsMapExtraProps?: any;
|
|
27
27
|
isInsideContainer?: boolean;
|
|
28
28
|
extraAnchorPointYOffset: number;
|
|
29
|
+
extraOffset: number;
|
|
29
30
|
river?: ZappRiver | ZappEntry;
|
|
30
31
|
};
|
|
31
32
|
|
|
@@ -38,6 +39,7 @@ export const River = (props: Props) => {
|
|
|
38
39
|
componentsMapExtraProps,
|
|
39
40
|
isInsideContainer,
|
|
40
41
|
extraAnchorPointYOffset,
|
|
42
|
+
extraOffset,
|
|
41
43
|
} = props;
|
|
42
44
|
|
|
43
45
|
const { title: screenTitle, summary: screenSummary } = useNavbarState();
|
|
@@ -118,6 +120,7 @@ export const River = (props: Props) => {
|
|
|
118
120
|
<GeneralContentScreen
|
|
119
121
|
feed={feedData}
|
|
120
122
|
screenId={screenId}
|
|
123
|
+
extraOffset={extraOffset}
|
|
121
124
|
isScreenWrappedInContainer={isInsideContainer}
|
|
122
125
|
extraAnchorPointYOffset={extraAnchorPointYOffset}
|
|
123
126
|
componentsMapExtraProps={componentsMapExtraProps}
|
|
@@ -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]}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { View, ViewStyle } from "react-native";
|
|
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
5
|
import { isFirstComponentScreenPicker } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
6
|
-
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
7
6
|
|
|
8
7
|
interface IProps {
|
|
9
8
|
targetScreenId?: string;
|
|
10
9
|
children?: React.ReactNode;
|
|
11
10
|
style?: ViewStyle;
|
|
12
|
-
|
|
11
|
+
extraOffset?: number;
|
|
13
12
|
}
|
|
14
13
|
|
|
14
|
+
type CombinedProps = IProps & ViewProps;
|
|
15
15
|
/**
|
|
16
16
|
* The MarginTop is essentially a feature used for managing the visibility of components on your screen.
|
|
17
17
|
* A more accurate term for this might be something like a 'component visibility threshold' or 'cut-off point'.
|
|
@@ -47,7 +47,7 @@ export const useMarginTop = (targetScreenId: string): number => {
|
|
|
47
47
|
|
|
48
48
|
// Empty string means that value is blank in the CMS. Fallback to theme
|
|
49
49
|
if (String(screenData?.styles?.screen_margin_top) === "") {
|
|
50
|
-
return
|
|
50
|
+
return Number(theme.screen_margin_top);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -58,29 +58,28 @@ export const useMarginTop = (targetScreenId: string): number => {
|
|
|
58
58
|
*/
|
|
59
59
|
if (screenData?.styles?.screen_margin_top === undefined) {
|
|
60
60
|
if (isGeneralContentScreen || supportsUiComponents) {
|
|
61
|
-
return
|
|
61
|
+
return Number(theme.screen_margin_top);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
return 0;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
return
|
|
67
|
+
return Number(screenData?.styles?.screen_margin_top);
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
export const TopMarginApplicator: React.FC<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
extraVerticalOffset,
|
|
75
|
-
}: IProps) => {
|
|
76
|
-
const extraOffset = toNumberWithDefault(0, extraVerticalOffset);
|
|
70
|
+
export const TopMarginApplicator: React.FC<CombinedProps> = (
|
|
71
|
+
props: CombinedProps
|
|
72
|
+
) => {
|
|
73
|
+
const extraOffset = props?.extraOffset ?? 0;
|
|
77
74
|
|
|
78
75
|
// HACK: Remove extraOffset when focusIssue with absolute elements is fixed on tvos
|
|
79
|
-
const marginTop = useMarginTop(targetScreenId);
|
|
76
|
+
const marginTop = useMarginTop(props.targetScreenId) + extraOffset;
|
|
77
|
+
const style = { ...((props.style as {}) || {}), marginTop };
|
|
80
78
|
|
|
79
|
+
// Then, spread the rest of the props on your returned JSX.
|
|
81
80
|
return (
|
|
82
|
-
<View style={
|
|
83
|
-
{children}
|
|
81
|
+
<View {...props} style={style}>
|
|
82
|
+
{props.children}
|
|
84
83
|
</View>
|
|
85
84
|
);
|
|
86
85
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
|
-
import { Animated } from "react-native";
|
|
2
|
+
import { Animated, Dimensions } from "react-native";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
useSafeAreaInsets,
|
|
@@ -23,6 +23,7 @@ export enum PlayerAnimationStateEnum {
|
|
|
23
23
|
export type PlayerAnimationStateT = number | PlayerAnimationStateEnum | null;
|
|
24
24
|
|
|
25
25
|
export type ModalAnimationContextT = {
|
|
26
|
+
yTranslate: React.MutableRefObject<Animated.Value | null>;
|
|
26
27
|
isActiveGesture: boolean;
|
|
27
28
|
playerAnimationState: PlayerAnimationStateT;
|
|
28
29
|
setPlayerAnimationState: (value: PlayerAnimationStateT) => void;
|
|
@@ -48,6 +49,7 @@ export type ModalAnimationContextT = {
|
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
export const ReactContext = React.createContext<ModalAnimationContextT>({
|
|
52
|
+
yTranslate: React.createRef<Animated.Value | null>(),
|
|
51
53
|
isActiveGesture: false,
|
|
52
54
|
playerAnimationState: null,
|
|
53
55
|
setPlayerAnimationState: () => null,
|
|
@@ -73,6 +75,10 @@ export const ReactContext = React.createContext<ModalAnimationContextT>({
|
|
|
73
75
|
});
|
|
74
76
|
|
|
75
77
|
const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
78
|
+
const yTranslate = React.useRef(
|
|
79
|
+
new Animated.Value(Dimensions.get("window").height)
|
|
80
|
+
);
|
|
81
|
+
|
|
76
82
|
const [playerAnimationState, setPlayerAnimationState] =
|
|
77
83
|
React.useState<PlayerAnimationStateT>(null);
|
|
78
84
|
|
|
@@ -100,6 +106,7 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
100
106
|
// Reset player animation state when video modal is closed
|
|
101
107
|
if (!visible) {
|
|
102
108
|
resetPlayerAnimationState();
|
|
109
|
+
yTranslate.current?.setValue(Dimensions.get("window").height);
|
|
103
110
|
}
|
|
104
111
|
}, [visible, resetPlayerAnimationState]);
|
|
105
112
|
|
|
@@ -141,6 +148,7 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
141
148
|
return (
|
|
142
149
|
<ReactContext.Provider
|
|
143
150
|
value={{
|
|
151
|
+
yTranslate,
|
|
144
152
|
startComponentsAnimation,
|
|
145
153
|
setStartComponentsAnimation,
|
|
146
154
|
isActiveGesture: playerAnimationState !== null,
|
|
@@ -11,6 +11,8 @@ import { useTargetScreenData } from "@applicaster/zapp-react-native-utils/reactH
|
|
|
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";
|
|
14
16
|
|
|
15
17
|
const { width: SCREEN_WIDTH } = Dimensions.get("screen");
|
|
16
18
|
|
|
@@ -26,6 +28,10 @@ type Props = {
|
|
|
26
28
|
isTabletLandscape?: boolean;
|
|
27
29
|
isAudioPlayer?: boolean;
|
|
28
30
|
isTablet?: boolean;
|
|
31
|
+
inline?: any;
|
|
32
|
+
docked?: boolean;
|
|
33
|
+
isModal?: boolean;
|
|
34
|
+
pip?: boolean;
|
|
29
35
|
};
|
|
30
36
|
|
|
31
37
|
const containerStyle = ({
|
|
@@ -42,8 +48,24 @@ export const PlayerDetails = ({
|
|
|
42
48
|
configuration,
|
|
43
49
|
isTabletLandscape = false,
|
|
44
50
|
isAudioPlayer,
|
|
45
|
-
|
|
51
|
+
inline,
|
|
52
|
+
docked,
|
|
53
|
+
isModal,
|
|
54
|
+
pip,
|
|
46
55
|
}: 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();
|
|
47
69
|
const screenData = useTargetScreenData(entry);
|
|
48
70
|
const insets = useSafeAreaInsets();
|
|
49
71
|
|
|
@@ -79,7 +101,7 @@ export const PlayerDetails = ({
|
|
|
79
101
|
}
|
|
80
102
|
}, [isAudioPlayer]);
|
|
81
103
|
|
|
82
|
-
if (isNilOrEmpty(screenData?.ui_components)) {
|
|
104
|
+
if (isNilOrEmpty(screenData?.ui_components) || !isShowPlayerDetails) {
|
|
83
105
|
return null;
|
|
84
106
|
}
|
|
85
107
|
|