@applicaster/zapp-react-native-ui-components 14.0.0-alpha.8419134002 → 14.0.0-alpha.9848043301
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/{tv/Artwork.tsx → Artwork.tsx} +2 -3
- package/Components/AudioPlayer/{tv/index.tsx → AudioPlayer.tsx} +58 -17
- package/Components/AudioPlayer/AudioPlayerLayout.tsx +202 -0
- package/Components/AudioPlayer/{tv/Channel.tsx → Channel.tsx} +7 -7
- package/Components/AudioPlayer/{tv/Runtime.tsx → Runtime.tsx} +1 -7
- package/Components/AudioPlayer/{tv/Summary.tsx → Summary.tsx} +2 -6
- package/Components/AudioPlayer/{tv/Title.tsx → Title.tsx} +2 -6
- package/Components/AudioPlayer/{tv/__tests__ → __tests__}/__snapshots__/Runtime.test.js.snap +2 -2
- package/Components/AudioPlayer/{mobile/__tests__/__snapshots__/audioPlayerMobileLayout.test.js.snap → __tests__/__snapshots__/audioPlayer.test.js.snap} +8 -2
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +72 -0
- package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +28 -0
- package/Components/AudioPlayer/{tv/__tests__ → __tests__}/__snapshots__/summary.test.js.snap +2 -1
- package/Components/AudioPlayer/{tv/__tests__ → __tests__}/__snapshots__/title.test.js.snap +2 -1
- package/Components/AudioPlayer/{tv/__tests__ → __tests__}/audioPlayer.test.js +3 -7
- package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +26 -0
- package/Components/AudioPlayer/{tv/helpers.tsx → helpers.tsx} +2 -1
- package/Components/AudioPlayer/index.ts +1 -0
- package/Components/Cell/index.js +2 -6
- package/Components/MasterCell/index.tsx +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +19 -7
- package/Components/PlayerImageBackground/index.tsx +1 -1
- 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/index.ts +0 -2
- package/Components/VideoModal/utils.ts +6 -0
- package/Components/Viewport/VisibilitySensor/VisibilitySensor.tsx +3 -3
- package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/index.ts +3 -3
- package/package.json +5 -5
- package/Components/AudioPlayer/index.tsx +0 -15
- package/Components/AudioPlayer/mobile/Layout.tsx +0 -66
- package/Components/AudioPlayer/mobile/__tests__/audioPlayerMobileLayout.test.js +0 -18
- package/Components/AudioPlayer/mobile/index.tsx +0 -18
- package/Components/AudioPlayer/tv/Layout.tsx +0 -168
- package/Components/AudioPlayer/tv/__tests__/__snapshots__/audioPlayer.test.js.snap +0 -164
- package/Components/AudioPlayer/tv/__tests__/__snapshots__/channel.test.js.snap +0 -19
- package/Components/AudioPlayer/types.ts +0 -40
- package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
- /package/Components/AudioPlayer/{tv/__tests__ → __tests__}/Runtime.test.js +0 -0
- /package/Components/AudioPlayer/{tv/__tests__ → __tests__}/__snapshots__/artWork.test.js.snap +0 -0
- /package/Components/AudioPlayer/{tv/__tests__ → __tests__}/artWork.test.js +0 -0
- /package/Components/AudioPlayer/{tv/__tests__ → __tests__}/channel.test.js +0 -0
- /package/Components/AudioPlayer/{tv/__tests__ → __tests__}/summary.test.js +0 -0
- /package/Components/AudioPlayer/{tv/__tests__ → __tests__}/title.test.js +0 -0
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { render } from "@testing-library/react-native";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
jest.mock("@applicaster/zapp-react-native-utils/audioPlayerUtils", () => ({
|
|
7
|
-
useArtworkImage: jest.fn(() => "artwork_url"),
|
|
8
|
-
}));
|
|
4
|
+
import { AudioPlayer } from "../AudioPlayer";
|
|
9
5
|
|
|
10
6
|
const audioPlayerProps = {
|
|
11
7
|
audio_item: {
|
|
@@ -49,9 +45,9 @@ const audioPlayerProps = {
|
|
|
49
45
|
styles: {},
|
|
50
46
|
};
|
|
51
47
|
|
|
52
|
-
describe("<
|
|
48
|
+
describe("<AudioPlayer />", () => {
|
|
53
49
|
it("renders correctly", () => {
|
|
54
|
-
const { toJSON } = render(<
|
|
50
|
+
const { toJSON } = render(<AudioPlayer {...audioPlayerProps} />);
|
|
55
51
|
expect(toJSON()).toMatchSnapshot();
|
|
56
52
|
});
|
|
57
53
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
|
+
|
|
4
|
+
import { AudioPlayerLayout } from "../AudioPlayerLayout";
|
|
5
|
+
|
|
6
|
+
const audioPlayerLayoutProps = {
|
|
7
|
+
artwork: "string",
|
|
8
|
+
config: {
|
|
9
|
+
titleColor: "white",
|
|
10
|
+
summaryColor: "white",
|
|
11
|
+
backgroundColor: "black",
|
|
12
|
+
backgroundImage: "https://example.com",
|
|
13
|
+
isRTL: true,
|
|
14
|
+
},
|
|
15
|
+
children: [],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe("<AudioPlayerLayout />", () => {
|
|
19
|
+
it("renders correctly", () => {
|
|
20
|
+
const { toJSON } = render(
|
|
21
|
+
<AudioPlayerLayout {...audioPlayerLayoutProps} />
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
expect(toJSON()).toMatchSnapshot();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -2,8 +2,9 @@ const defaults = {
|
|
|
2
2
|
audio_player_title_color: "white",
|
|
3
3
|
audio_player_summary_color: "white",
|
|
4
4
|
audio_player_background_color: "black",
|
|
5
|
-
|
|
5
|
+
audio_player_artwork_aspect_ratio: "1:1",
|
|
6
6
|
audio_player_rtl: false,
|
|
7
|
+
audio_player_background_image_default_color: "",
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
export function getPropertyFromEntryOrConfig({ entry, plugin_configuration }) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AudioPlayer } from "./AudioPlayer";
|
package/Components/Cell/index.js
CHANGED
|
@@ -3,15 +3,11 @@ import * as R from "ramda";
|
|
|
3
3
|
import { connectToStore } from "@applicaster/zapp-react-native-redux";
|
|
4
4
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
HorizontalScrollContext,
|
|
8
|
-
RiverOffsetContext,
|
|
9
|
-
ScreenScrollingContext,
|
|
10
|
-
} from "../../Contexts";
|
|
11
|
-
|
|
6
|
+
import { HorizontalScrollContext, RiverOffsetContext } from "../../Contexts";
|
|
12
7
|
import { CellComponent } from "./Cell";
|
|
13
8
|
import { TvOSCellComponent } from "./TvOSCellComponent";
|
|
14
9
|
import { withConsumer } from "../../Contexts/HeaderOffsetContext";
|
|
10
|
+
import { ScreenScrollingContext } from "../../Contexts/ScreenScrollingContext";
|
|
15
11
|
|
|
16
12
|
import { ScreenLayoutContextConsumer } from "../../Contexts/ScreenLayoutContext";
|
|
17
13
|
import { createContext } from "@applicaster/zapp-react-native-utils/reactUtils/createContext";
|
|
@@ -86,7 +86,7 @@ export function masterCellBuilder({
|
|
|
86
86
|
entry: item,
|
|
87
87
|
state: getEntryState(state, entryIsSelected),
|
|
88
88
|
}),
|
|
89
|
-
[state, item, entryIsSelected] // Assuming that item won't mutate
|
|
89
|
+
[state, item?.id, entryIsSelected] // Assuming that item won't mutate
|
|
90
90
|
);
|
|
91
91
|
|
|
92
92
|
const wrapperRef = React.useRef(null);
|
|
@@ -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;
|
|
@@ -127,7 +127,7 @@ const webStyles = {
|
|
|
127
127
|
playerScreen: {
|
|
128
128
|
flex: 1,
|
|
129
129
|
height: "100vh",
|
|
130
|
-
|
|
130
|
+
backgroundColor: "black",
|
|
131
131
|
},
|
|
132
132
|
playerWrapper: {
|
|
133
133
|
height: "100%",
|
|
@@ -135,6 +135,9 @@ const webStyles = {
|
|
|
135
135
|
},
|
|
136
136
|
inlineRiver: {
|
|
137
137
|
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
138
|
+
|
|
139
|
+
borderWidth: 4,
|
|
140
|
+
borderColor: "yellow",
|
|
138
141
|
},
|
|
139
142
|
};
|
|
140
143
|
|
|
@@ -145,7 +148,6 @@ const nativeStyles = {
|
|
|
145
148
|
},
|
|
146
149
|
playerScreen: {
|
|
147
150
|
flex: 1,
|
|
148
|
-
backgroundColor: "black",
|
|
149
151
|
overflow: "hidden",
|
|
150
152
|
},
|
|
151
153
|
playerWrapper: {
|
|
@@ -565,8 +567,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
565
567
|
const isInlineTV = isInlineTVUtil(screenData);
|
|
566
568
|
|
|
567
569
|
const inline =
|
|
568
|
-
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
569
|
-
|
|
570
|
+
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
571
|
+
mode as any
|
|
572
|
+
) || isInlineTV;
|
|
570
573
|
|
|
571
574
|
const value = React.useMemo(
|
|
572
575
|
() => ({ playerId: state.playerId }),
|
|
@@ -587,7 +590,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
587
590
|
);
|
|
588
591
|
}
|
|
589
592
|
|
|
590
|
-
if (
|
|
593
|
+
if (
|
|
594
|
+
screen_background_color &&
|
|
595
|
+
mode !== VideoModalMode.FULLSCREEN &&
|
|
596
|
+
isTV()
|
|
597
|
+
) {
|
|
591
598
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
592
599
|
}
|
|
593
600
|
|
|
@@ -617,6 +624,8 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
617
624
|
playNextData,
|
|
618
625
|
};
|
|
619
626
|
|
|
627
|
+
const pointerEventsProp = mode === "MINIMIZED" ? "box-none" : "auto";
|
|
628
|
+
|
|
620
629
|
return (
|
|
621
630
|
<PlayerStateContext.Provider value={value}>
|
|
622
631
|
<PlayerContainerContextProvider
|
|
@@ -637,14 +646,17 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
637
646
|
preferredFocus
|
|
638
647
|
shouldUsePreferredFocus
|
|
639
648
|
groupId={groupId}
|
|
649
|
+
pointerEvents={pointerEventsProp}
|
|
640
650
|
>
|
|
641
651
|
{/* Video player and components */}
|
|
642
652
|
<View
|
|
643
653
|
style={styles.playerScreen}
|
|
644
654
|
testID={"player-screen-container"}
|
|
655
|
+
pointerEvents={pointerEventsProp}
|
|
645
656
|
>
|
|
646
657
|
{/* Player container */}
|
|
647
658
|
<View
|
|
659
|
+
pointerEvents={pointerEventsProp}
|
|
648
660
|
style={[
|
|
649
661
|
styles.playerWrapper,
|
|
650
662
|
// eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
|
|
@@ -716,7 +728,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
716
728
|
key={item.id}
|
|
717
729
|
groupId={FocusableGroupMainContainerId}
|
|
718
730
|
cellTapAction={onCellTap}
|
|
719
|
-
extraAnchorPointYOffset={
|
|
731
|
+
extraAnchorPointYOffset={-600}
|
|
720
732
|
isScreenWrappedInContainer={true}
|
|
721
733
|
containerHeight={styles.inlineRiver.height}
|
|
722
734
|
componentsMapExtraProps={{
|
|
@@ -28,7 +28,7 @@ const PlayerImageBackgroundComponent = ({
|
|
|
28
28
|
defaultImageDimensions,
|
|
29
29
|
}: Props) => {
|
|
30
30
|
const source = React.useMemo(
|
|
31
|
-
() => ({ uri: imageSrcFromMediaItem(entry,
|
|
31
|
+
() => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
|
|
32
32
|
[imageKey, entry]
|
|
33
33
|
);
|
|
34
34
|
|
|
@@ -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
|
|
|
@@ -9,16 +9,8 @@ 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";
|
|
13
12
|
import { playerDimensionsHack } from "./utils";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
AnimatedScrollModal,
|
|
18
|
-
AnimatedVideoPlayerComponent,
|
|
19
|
-
AnimationComponent,
|
|
20
|
-
ComponentAnimationType,
|
|
21
|
-
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
13
|
+
import { getTabletWidth } from "@applicaster/zapp-react-native-utils/playerUtils";
|
|
22
14
|
|
|
23
15
|
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("screen");
|
|
24
16
|
|
|
@@ -44,29 +36,15 @@ type Props = {
|
|
|
44
36
|
isModal?: boolean;
|
|
45
37
|
fullscreen?: boolean;
|
|
46
38
|
isTabletPortrait?: boolean;
|
|
47
|
-
children: (playerDimensions: DimensionsT) => React.ReactNode;
|
|
48
39
|
configuration: Configuration;
|
|
40
|
+
|
|
41
|
+
playerContent: (styles: ViewStyle) => React.ReactNode;
|
|
49
42
|
};
|
|
50
43
|
|
|
51
44
|
const defaultStyles = StyleSheet.create({
|
|
52
45
|
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" },
|
|
60
46
|
});
|
|
61
47
|
|
|
62
|
-
const directionStyles = (isTabletLandscape: boolean): ViewStyle => {
|
|
63
|
-
if (isTabletLandscape) {
|
|
64
|
-
return orientationStyles.landscape;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return orientationStyles.portrait;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
48
|
const getScreenAspectRatio = () => {
|
|
71
49
|
const longEdge = Math.max(SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
72
50
|
const shortEdge = Math.min(SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
@@ -86,51 +64,6 @@ const getEdges = (isTablet: boolean, isInlineModal: boolean) => {
|
|
|
86
64
|
return ["top"];
|
|
87
65
|
};
|
|
88
66
|
|
|
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
|
-
|
|
134
67
|
const PlayerWrapperComponent = (props: Props) => {
|
|
135
68
|
const {
|
|
136
69
|
entry,
|
|
@@ -139,35 +72,26 @@ const PlayerWrapperComponent = (props: Props) => {
|
|
|
139
72
|
inline,
|
|
140
73
|
docked,
|
|
141
74
|
isModal,
|
|
142
|
-
children,
|
|
143
75
|
isTabletPortrait,
|
|
144
76
|
configuration,
|
|
145
|
-
fullscreen,
|
|
146
77
|
pip,
|
|
78
|
+
playerContent,
|
|
147
79
|
} = props;
|
|
148
80
|
|
|
149
81
|
const isTablet = useIsTablet();
|
|
150
82
|
|
|
151
83
|
const isInlineModal = inline && isModal;
|
|
152
84
|
|
|
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
|
-
|
|
163
85
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
164
86
|
|
|
165
|
-
const tabletWidth = getTabletWidth(
|
|
87
|
+
const tabletWidth = getTabletWidth(
|
|
88
|
+
configuration.tablet_landscape_sidebar_width,
|
|
89
|
+
style
|
|
90
|
+
);
|
|
166
91
|
|
|
167
92
|
const baseDimensions: DimensionsT = React.useMemo(
|
|
168
93
|
() => ({
|
|
169
|
-
width:
|
|
170
|
-
isInlineModal && !docked && isTabletLandscape ? tabletWidth : "100%",
|
|
94
|
+
width: isInlineModal && isTabletLandscape ? tabletWidth : "100%",
|
|
171
95
|
height: undefined,
|
|
172
96
|
}),
|
|
173
97
|
[isInlineModal, tabletWidth, docked]
|
|
@@ -176,7 +100,7 @@ const PlayerWrapperComponent = (props: Props) => {
|
|
|
176
100
|
const playerDimensions: DimensionsT = React.useMemo(
|
|
177
101
|
() => ({
|
|
178
102
|
...baseDimensions,
|
|
179
|
-
width:
|
|
103
|
+
width: baseDimensions.width,
|
|
180
104
|
aspectRatio: !isInlineModal && !pip ? getScreenAspectRatio() : 16 / 9,
|
|
181
105
|
}),
|
|
182
106
|
[baseDimensions, isInlineModal, pip]
|
|
@@ -185,8 +109,7 @@ const PlayerWrapperComponent = (props: Props) => {
|
|
|
185
109
|
const containerDimensions: DimensionsT = React.useMemo(
|
|
186
110
|
() => ({
|
|
187
111
|
...baseDimensions,
|
|
188
|
-
aspectRatio:
|
|
189
|
-
isInlineModal && docked ? undefined : playerDimensions.aspectRatio,
|
|
112
|
+
aspectRatio: playerDimensions.aspectRatio,
|
|
190
113
|
}),
|
|
191
114
|
[baseDimensions, isInlineModal, docked, playerDimensions.aspectRatio]
|
|
192
115
|
);
|
|
@@ -194,68 +117,29 @@ const PlayerWrapperComponent = (props: Props) => {
|
|
|
194
117
|
const WrapperView = React.useMemo(() => (isTV() ? View : SafeAreaView), []);
|
|
195
118
|
|
|
196
119
|
const childrenStyles = React.useMemo(
|
|
197
|
-
() => ({
|
|
120
|
+
() => ({
|
|
121
|
+
...playerDimensions,
|
|
122
|
+
...playerDimensionsHack,
|
|
123
|
+
}),
|
|
198
124
|
[containerDimensions, playerDimensionsHack]
|
|
199
125
|
);
|
|
200
126
|
|
|
201
|
-
const wrapperViewStyle: ViewStyle = {
|
|
202
|
-
backgroundColor:
|
|
203
|
-
isTablet && !fullscreen
|
|
204
|
-
? configuration?.tablet_landscape_player_container_background_color
|
|
205
|
-
: "transparent",
|
|
206
|
-
};
|
|
207
|
-
|
|
208
127
|
return (
|
|
209
128
|
<WrapperView
|
|
210
129
|
edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
|
|
211
|
-
style={
|
|
130
|
+
style={playerDimensionsHack}
|
|
212
131
|
>
|
|
213
|
-
<
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
132
|
+
<View
|
|
133
|
+
testID={`${entry?.id}-player-container`}
|
|
134
|
+
style={[
|
|
135
|
+
defaultStyles.playerContainer,
|
|
136
|
+
playerDimensionsHack,
|
|
137
|
+
containerDimensions,
|
|
138
|
+
containerStyle,
|
|
139
|
+
]}
|
|
217
140
|
>
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
242
|
-
<AnimatedScrollModal>
|
|
243
|
-
{isShowPlayerDetails ? (
|
|
244
|
-
<AnimationComponent
|
|
245
|
-
animationType={ComponentAnimationType.componentFade}
|
|
246
|
-
style={defaultStyles.flex}
|
|
247
|
-
>
|
|
248
|
-
<PlayerDetails
|
|
249
|
-
configuration={configuration}
|
|
250
|
-
style={defaultStyles.playerDetails}
|
|
251
|
-
entry={entry}
|
|
252
|
-
isTabletLandscape={isTabletLandscape}
|
|
253
|
-
isTablet={isTablet}
|
|
254
|
-
/>
|
|
255
|
-
</AnimationComponent>
|
|
256
|
-
) : null}
|
|
257
|
-
</AnimatedScrollModal>
|
|
258
|
-
</AnimationComponent>
|
|
141
|
+
{playerContent(childrenStyles)}
|
|
142
|
+
</View>
|
|
259
143
|
</WrapperView>
|
|
260
144
|
);
|
|
261
145
|
};
|
|
@@ -17,11 +17,7 @@ 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 {
|
|
21
|
-
useModalSize,
|
|
22
|
-
useBackgroundColor,
|
|
23
|
-
useInitialPlayerState,
|
|
24
|
-
} from "./hooks";
|
|
20
|
+
import { useModalSize, useInitialPlayerState } from "./hooks";
|
|
25
21
|
|
|
26
22
|
import { APP_EVENTS } from "@applicaster/zapp-react-native-utils/appUtils/events";
|
|
27
23
|
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
|
|
@@ -33,8 +29,6 @@ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
|
33
29
|
import { Spinner } from "../Spinner";
|
|
34
30
|
import { OpaqueLayer } from "./OpaqueLayer";
|
|
35
31
|
|
|
36
|
-
import { AnimatedPlayerModalWrapper } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
37
|
-
|
|
38
32
|
const LOADER_BACKGROUND_COLOR = "rgba(64,64,64,0.5)";
|
|
39
33
|
|
|
40
34
|
const styles = StyleSheet.create({
|
|
@@ -65,7 +59,6 @@ const VideoModalComponent = () => {
|
|
|
65
59
|
|
|
66
60
|
const modalSize = useModalSize();
|
|
67
61
|
const isFirstRender = useIsInitialRender();
|
|
68
|
-
const backgroundColor = useBackgroundColor();
|
|
69
62
|
|
|
70
63
|
const {
|
|
71
64
|
closeVideoModal,
|
|
@@ -145,20 +138,13 @@ const VideoModalComponent = () => {
|
|
|
145
138
|
{mode === "FULLSCREEN" && <OpaqueLayer />}
|
|
146
139
|
|
|
147
140
|
{itemIdHooksFinished === item?.id ? (
|
|
148
|
-
<
|
|
149
|
-
style={[
|
|
150
|
-
styles.container,
|
|
151
|
-
{
|
|
152
|
-
backgroundColor,
|
|
153
|
-
},
|
|
154
|
-
]}
|
|
155
|
-
>
|
|
141
|
+
<View pointerEvents="box-none" style={styles.container}>
|
|
156
142
|
<HandlePlayable
|
|
157
143
|
item={item}
|
|
158
144
|
isModal={mode !== "PIP"}
|
|
159
145
|
mode={mode}
|
|
160
146
|
/>
|
|
161
|
-
</
|
|
147
|
+
</View>
|
|
162
148
|
) : (
|
|
163
149
|
<View style={styles.loaderContainer}>
|
|
164
150
|
<Spinner />
|
|
@@ -13,6 +13,7 @@ const props = {
|
|
|
13
13
|
tablet_landscape_sidebar_width: "35%",
|
|
14
14
|
tablet_landscape_player_container_background_color: "red",
|
|
15
15
|
},
|
|
16
|
+
playerContent: jest.fn(() => <></>),
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
const mockUseIsDeviceTablet = jest.fn();
|
|
@@ -122,13 +123,6 @@ describe("PlayerWrapper", () => {
|
|
|
122
123
|
</PlayerWrapper>
|
|
123
124
|
);
|
|
124
125
|
|
|
125
|
-
const expectDimensions = {
|
|
126
|
-
...dimensions,
|
|
127
|
-
width: undefined,
|
|
128
|
-
aspectRatio: 16 / 9,
|
|
129
|
-
};
|
|
130
|
-
|
|
131
126
|
expect(element).toMatchSnapshot();
|
|
132
|
-
expect(children).toHaveBeenCalledWith(expectDimensions);
|
|
133
127
|
});
|
|
134
128
|
});
|