@applicaster/zapp-react-native-ui-components 14.0.0-alpha.3552323332 → 14.0.0-alpha.4009339136
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/index.tsx +15 -0
- package/Components/AudioPlayer/mobile/Layout.tsx +66 -0
- package/Components/AudioPlayer/{__tests__/__snapshots__/audioPlayer.test.js.snap → mobile/__tests__/__snapshots__/audioPlayerMobileLayout.test.js.snap} +2 -8
- package/Components/AudioPlayer/mobile/__tests__/audioPlayerMobileLayout.test.js +18 -0
- package/Components/AudioPlayer/mobile/index.tsx +18 -0
- package/Components/AudioPlayer/{Artwork.tsx → tv/Artwork.tsx} +3 -2
- package/Components/AudioPlayer/{Channel.tsx → tv/Channel.tsx} +7 -7
- package/Components/AudioPlayer/tv/Layout.tsx +168 -0
- package/Components/AudioPlayer/{Runtime.tsx → tv/Runtime.tsx} +7 -1
- package/Components/AudioPlayer/{Summary.tsx → tv/Summary.tsx} +6 -2
- package/Components/AudioPlayer/{Title.tsx → tv/Title.tsx} +6 -2
- package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/Runtime.test.js.snap +2 -2
- package/Components/AudioPlayer/tv/__tests__/__snapshots__/audioPlayer.test.js.snap +164 -0
- package/Components/AudioPlayer/tv/__tests__/__snapshots__/channel.test.js.snap +19 -0
- package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/summary.test.js.snap +1 -2
- package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/title.test.js.snap +1 -2
- package/Components/AudioPlayer/{__tests__ → tv/__tests__}/audioPlayer.test.js +7 -3
- package/Components/AudioPlayer/{helpers.tsx → tv/helpers.tsx} +1 -2
- package/Components/AudioPlayer/{AudioPlayer.tsx → tv/index.tsx} +17 -58
- package/Components/AudioPlayer/types.ts +40 -0
- package/Components/MasterCell/index.tsx +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +7 -17
- package/Components/PlayerImageBackground/index.tsx +1 -1
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +1 -9
- package/Components/VideoModal/PlayerDetails.tsx +2 -24
- package/Components/VideoModal/PlayerWrapper.tsx +142 -26
- package/Components/VideoModal/VideoModal.tsx +17 -3
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +240 -44
- package/Components/VideoModal/hooks/index.ts +2 -0
- package/Components/VideoModal/hooks/useBackgroundColor.ts +10 -0
- package/Components/VideoModal/utils.ts +0 -6
- package/package.json +5 -5
- package/Components/AudioPlayer/AudioPlayerLayout.tsx +0 -202
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +0 -72
- package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +0 -28
- package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +0 -26
- package/Components/AudioPlayer/index.ts +0 -1
- /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/Runtime.test.js +0 -0
- /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/artWork.test.js.snap +0 -0
- /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/artWork.test.js +0 -0
- /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/channel.test.js +0 -0
- /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/summary.test.js +0 -0
- /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/title.test.js +0 -0
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { render } from "@testing-library/react-native";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { AudioPlayerTV } from "..";
|
|
5
|
+
|
|
6
|
+
jest.mock("@applicaster/zapp-react-native-utils/audioPlayerUtils", () => ({
|
|
7
|
+
useArtworkImage: jest.fn(() => "artwork_url"),
|
|
8
|
+
}));
|
|
5
9
|
|
|
6
10
|
const audioPlayerProps = {
|
|
7
11
|
audio_item: {
|
|
@@ -45,9 +49,9 @@ const audioPlayerProps = {
|
|
|
45
49
|
styles: {},
|
|
46
50
|
};
|
|
47
51
|
|
|
48
|
-
describe("<
|
|
52
|
+
describe("<AudioPlayerTV />", () => {
|
|
49
53
|
it("renders correctly", () => {
|
|
50
|
-
const { toJSON } = render(<
|
|
54
|
+
const { toJSON } = render(<AudioPlayerTV {...audioPlayerProps} />);
|
|
51
55
|
expect(toJSON()).toMatchSnapshot();
|
|
52
56
|
});
|
|
53
57
|
});
|
|
@@ -2,9 +2,8 @@ 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_background_image: undefined,
|
|
6
6
|
audio_player_rtl: false,
|
|
7
|
-
audio_player_background_image_default_color: "",
|
|
8
7
|
};
|
|
9
8
|
|
|
10
9
|
export function getPropertyFromEntryOrConfig({ entry, plugin_configuration }) {
|
|
@@ -1,60 +1,24 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from "react";
|
|
2
2
|
|
|
3
3
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
|
+
import { useArtworkImage } from "@applicaster/zapp-react-native-utils/audioPlayerUtils";
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
+
import { AudioPlayerTVLayout } from "./Layout";
|
|
6
7
|
|
|
7
|
-
import { AudioPlayerLayout } from "./AudioPlayerLayout";
|
|
8
8
|
import { Channel } from "./Channel";
|
|
9
9
|
import { Title } from "./Title";
|
|
10
10
|
import { Summary } from "./Summary";
|
|
11
11
|
import { Runtime } from "./Runtime";
|
|
12
12
|
import { getPropertyFromEntryOrConfig } from "./helpers";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
audio_player_artwork_aspect_ratio?: string;
|
|
19
|
-
audio_player_background_image?: string;
|
|
20
|
-
audio_player_background_color?: string;
|
|
21
|
-
audio_player_channel_icon?: string;
|
|
22
|
-
audio_player_title_color?: string;
|
|
23
|
-
audio_player_summary_color?: string;
|
|
24
|
-
audio_player_rtl?: boolean;
|
|
25
|
-
audio_player_background_image_default_color?: string;
|
|
26
|
-
start_time?: string;
|
|
27
|
-
end_time?: string;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
plugin_configuration: {
|
|
31
|
-
audio_player_background_color?: string;
|
|
32
|
-
audio_player_title_color?: string;
|
|
33
|
-
audio_player_summary_color?: string;
|
|
34
|
-
audio_player_rtl?: string;
|
|
35
|
-
audio_player_background_image_default_color?: string;
|
|
36
|
-
audio_player_background_image?: string;
|
|
37
|
-
audio_player_artwork_aspect_ratio?: string;
|
|
38
|
-
lg_tv_audio_player_title_font_family?: string;
|
|
39
|
-
lg_tv_audio_player_title_font_size?: number;
|
|
40
|
-
lg_tv_audio_player_summary_font_family?: string;
|
|
41
|
-
lg_tv_audio_player_summary_font_size?: number;
|
|
42
|
-
samsung_tv_audio_player_title_font_family?: string;
|
|
43
|
-
samsung_tv_audio_player_title_font_size?: number;
|
|
44
|
-
samsung_tv_audio_player_summary_font_family?: string;
|
|
45
|
-
samsung_tv_audio_player_summary_font_size?: number;
|
|
46
|
-
tv_os_audio_player_title_font_family?: string;
|
|
47
|
-
tv_os_audio_player_title_font_size?: number;
|
|
48
|
-
tv_os_audio_player_summary_font_family?: string;
|
|
49
|
-
tv_os_audio_player_summary_font_size?: number;
|
|
50
|
-
};
|
|
51
|
-
style?: ViewStyle;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export function AudioPlayer(props: Props) {
|
|
55
|
-
const { audio_item, plugin_configuration } = props;
|
|
13
|
+
|
|
14
|
+
import { Props } from "../types";
|
|
15
|
+
|
|
16
|
+
export function AudioPlayerTV(props: Props) {
|
|
17
|
+
const { audio_item, plugin_configuration, style = {} } = props;
|
|
56
18
|
const { extensions, title, summary } = audio_item;
|
|
57
19
|
|
|
20
|
+
const artwork = useArtworkImage(audio_item);
|
|
21
|
+
|
|
58
22
|
const getProp = useCallback(
|
|
59
23
|
getPropertyFromEntryOrConfig({
|
|
60
24
|
entry: audio_item,
|
|
@@ -64,20 +28,20 @@ export function AudioPlayer(props: Props) {
|
|
|
64
28
|
);
|
|
65
29
|
|
|
66
30
|
const config = useMemo(() => {
|
|
67
|
-
// Checking if we are
|
|
31
|
+
// Checking if we are receiving items from the DSP
|
|
68
32
|
const titleColor = getProp("audio_player_title_color");
|
|
69
33
|
const summaryColor = getProp("audio_player_summary_color");
|
|
70
34
|
const backgroundColor = getProp("audio_player_background_color");
|
|
71
35
|
const backgroundImage = getProp("audio_player_background_image");
|
|
72
|
-
const artworkAspectRatio = getProp("audio_player_artwork_aspect_ratio");
|
|
73
36
|
const channelIcon = getProp("audio_player_channel_icon");
|
|
74
37
|
const rtlFlag = getProp("audio_player_rtl");
|
|
75
|
-
const artworkBorderRadius = getProp("audio_player_artwork_border_radius");
|
|
76
38
|
|
|
77
|
-
const
|
|
78
|
-
"
|
|
39
|
+
const backgroundImageOverlay = getProp(
|
|
40
|
+
"audio_player_background_image_overlay"
|
|
79
41
|
);
|
|
80
42
|
|
|
43
|
+
const artworkBorderRadius = getProp("audio_player_artwork_border_radius");
|
|
44
|
+
|
|
81
45
|
const isRTL = rtlFlag === "1" || rtlFlag === "true" || rtlFlag === true;
|
|
82
46
|
|
|
83
47
|
const titleFontFamily = getProp(
|
|
@@ -152,23 +116,18 @@ export function AudioPlayer(props: Props) {
|
|
|
152
116
|
summaryFontSize,
|
|
153
117
|
runTimeFontFamily,
|
|
154
118
|
runTimeFontSize,
|
|
155
|
-
artworkAspectRatio,
|
|
156
119
|
channelIcon,
|
|
157
|
-
audioPlayerBackgroundImageDefaultColor,
|
|
158
120
|
artworkBorderRadius,
|
|
121
|
+
backgroundImageOverlay,
|
|
159
122
|
};
|
|
160
123
|
}, [getProp]);
|
|
161
124
|
|
|
162
|
-
const artwork = imageSrcFromMediaItem(audio_item, [
|
|
163
|
-
config?.artworkAspectRatio,
|
|
164
|
-
]);
|
|
165
|
-
|
|
166
125
|
return (
|
|
167
|
-
<
|
|
126
|
+
<AudioPlayerTVLayout artwork={artwork} config={config} style={style}>
|
|
168
127
|
<Channel srcImage={config?.channelIcon} config={config} />
|
|
169
128
|
<Title title={title} config={config} />
|
|
170
129
|
<Summary summary={summary} config={config} />
|
|
171
130
|
<Runtime {...extensions} config={config} />
|
|
172
|
-
</
|
|
131
|
+
</AudioPlayerTVLayout>
|
|
173
132
|
);
|
|
174
133
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ViewStyle } from "react-native";
|
|
2
|
+
|
|
3
|
+
export type Props = {
|
|
4
|
+
audio_item: ZappEntry & {
|
|
5
|
+
extensions?: {
|
|
6
|
+
audio_player_artwork_aspect_ratio?: string;
|
|
7
|
+
audio_player_background_image?: string;
|
|
8
|
+
audio_player_background_color?: string;
|
|
9
|
+
audio_player_channel_icon?: string;
|
|
10
|
+
audio_player_title_color?: string;
|
|
11
|
+
audio_player_summary_color?: string;
|
|
12
|
+
audio_player_rtl?: boolean;
|
|
13
|
+
audio_player_background_image_default_color?: string;
|
|
14
|
+
start_time?: string;
|
|
15
|
+
end_time?: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
plugin_configuration: {
|
|
19
|
+
audio_player_background_color?: string;
|
|
20
|
+
audio_player_title_color?: string;
|
|
21
|
+
audio_player_summary_color?: string;
|
|
22
|
+
audio_player_rtl?: string;
|
|
23
|
+
audio_player_background_image_default_color?: string;
|
|
24
|
+
audio_player_background_image?: string;
|
|
25
|
+
audio_player_artwork_aspect_ratio?: string;
|
|
26
|
+
lg_tv_audio_player_title_font_family?: string;
|
|
27
|
+
lg_tv_audio_player_title_font_size?: number;
|
|
28
|
+
lg_tv_audio_player_summary_font_family?: string;
|
|
29
|
+
lg_tv_audio_player_summary_font_size?: number;
|
|
30
|
+
samsung_tv_audio_player_title_font_family?: string;
|
|
31
|
+
samsung_tv_audio_player_title_font_size?: number;
|
|
32
|
+
samsung_tv_audio_player_summary_font_family?: string;
|
|
33
|
+
samsung_tv_audio_player_summary_font_size?: number;
|
|
34
|
+
tv_os_audio_player_title_font_family?: string;
|
|
35
|
+
tv_os_audio_player_title_font_size?: number;
|
|
36
|
+
tv_os_audio_player_summary_font_family?: string;
|
|
37
|
+
tv_os_audio_player_summary_font_size?: number;
|
|
38
|
+
};
|
|
39
|
+
style?: ViewStyle;
|
|
40
|
+
};
|
|
@@ -86,7 +86,7 @@ export function masterCellBuilder({
|
|
|
86
86
|
entry: item,
|
|
87
87
|
state: getEntryState(state, entryIsSelected),
|
|
88
88
|
}),
|
|
89
|
-
[state, item
|
|
89
|
+
[state, item, 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
|
+
};
|
|
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
|
+
background: "black",
|
|
131
131
|
},
|
|
132
132
|
playerWrapper: {
|
|
133
133
|
height: "100%",
|
|
@@ -135,9 +135,6 @@ const webStyles = {
|
|
|
135
135
|
},
|
|
136
136
|
inlineRiver: {
|
|
137
137
|
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
138
|
-
|
|
139
|
-
borderWidth: 4,
|
|
140
|
-
borderColor: "yellow",
|
|
141
138
|
},
|
|
142
139
|
};
|
|
143
140
|
|
|
@@ -148,6 +145,7 @@ const nativeStyles = {
|
|
|
148
145
|
},
|
|
149
146
|
playerScreen: {
|
|
150
147
|
flex: 1,
|
|
148
|
+
backgroundColor: "black",
|
|
151
149
|
overflow: "hidden",
|
|
152
150
|
},
|
|
153
151
|
playerWrapper: {
|
|
@@ -567,9 +565,8 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
567
565
|
const isInlineTV = isInlineTVUtil(screenData);
|
|
568
566
|
|
|
569
567
|
const inline =
|
|
570
|
-
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
571
|
-
|
|
572
|
-
) || isInlineTV;
|
|
568
|
+
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(mode) ||
|
|
569
|
+
isInlineTV;
|
|
573
570
|
|
|
574
571
|
const value = React.useMemo(
|
|
575
572
|
() => ({ playerId: state.playerId }),
|
|
@@ -590,11 +587,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
590
587
|
);
|
|
591
588
|
}
|
|
592
589
|
|
|
593
|
-
if (
|
|
594
|
-
screen_background_color &&
|
|
595
|
-
mode !== VideoModalMode.FULLSCREEN &&
|
|
596
|
-
isTV()
|
|
597
|
-
) {
|
|
590
|
+
if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
|
|
598
591
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
599
592
|
}
|
|
600
593
|
|
|
@@ -644,17 +637,14 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
644
637
|
preferredFocus
|
|
645
638
|
shouldUsePreferredFocus
|
|
646
639
|
groupId={groupId}
|
|
647
|
-
pointerEvents={mode === "MINIMIZED" ? "box-none" : "auto"}
|
|
648
640
|
>
|
|
649
641
|
{/* Video player and components */}
|
|
650
642
|
<View
|
|
651
643
|
style={styles.playerScreen}
|
|
652
644
|
testID={"player-screen-container"}
|
|
653
|
-
pointerEvents={mode === "MINIMIZED" ? "box-none" : "auto"}
|
|
654
645
|
>
|
|
655
646
|
{/* Player container */}
|
|
656
647
|
<View
|
|
657
|
-
pointerEvents={mode === "MINIMIZED" ? "box-none" : "auto"}
|
|
658
648
|
style={[
|
|
659
649
|
styles.playerWrapper,
|
|
660
650
|
// eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
|
|
@@ -726,7 +716,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
726
716
|
key={item.id}
|
|
727
717
|
groupId={FocusableGroupMainContainerId}
|
|
728
718
|
cellTapAction={onCellTap}
|
|
729
|
-
extraAnchorPointYOffset={
|
|
719
|
+
extraAnchorPointYOffset={0}
|
|
730
720
|
isScreenWrappedInContainer={true}
|
|
731
721
|
containerHeight={styles.inlineRiver.height}
|
|
732
722
|
componentsMapExtraProps={{
|
|
@@ -28,7 +28,7 @@ const PlayerImageBackgroundComponent = ({
|
|
|
28
28
|
defaultImageDimensions,
|
|
29
29
|
}: Props) => {
|
|
30
30
|
const source = React.useMemo(
|
|
31
|
-
() => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
|
|
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
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
useSafeAreaInsets,
|
|
@@ -23,7 +23,6 @@ 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>;
|
|
27
26
|
isActiveGesture: boolean;
|
|
28
27
|
playerAnimationState: PlayerAnimationStateT;
|
|
29
28
|
setPlayerAnimationState: (value: PlayerAnimationStateT) => void;
|
|
@@ -49,7 +48,6 @@ export type ModalAnimationContextT = {
|
|
|
49
48
|
};
|
|
50
49
|
|
|
51
50
|
export const ReactContext = React.createContext<ModalAnimationContextT>({
|
|
52
|
-
yTranslate: React.createRef<Animated.Value | null>(),
|
|
53
51
|
isActiveGesture: false,
|
|
54
52
|
playerAnimationState: null,
|
|
55
53
|
setPlayerAnimationState: () => null,
|
|
@@ -75,10 +73,6 @@ export const ReactContext = React.createContext<ModalAnimationContextT>({
|
|
|
75
73
|
});
|
|
76
74
|
|
|
77
75
|
const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
78
|
-
const yTranslate = React.useRef(
|
|
79
|
-
new Animated.Value(Dimensions.get("window").height)
|
|
80
|
-
);
|
|
81
|
-
|
|
82
76
|
const [playerAnimationState, setPlayerAnimationState] =
|
|
83
77
|
React.useState<PlayerAnimationStateT>(null);
|
|
84
78
|
|
|
@@ -106,7 +100,6 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
106
100
|
// Reset player animation state when video modal is closed
|
|
107
101
|
if (!visible) {
|
|
108
102
|
resetPlayerAnimationState();
|
|
109
|
-
yTranslate.current?.setValue(Dimensions.get("window").height);
|
|
110
103
|
}
|
|
111
104
|
}, [visible, resetPlayerAnimationState]);
|
|
112
105
|
|
|
@@ -148,7 +141,6 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
148
141
|
return (
|
|
149
142
|
<ReactContext.Provider
|
|
150
143
|
value={{
|
|
151
|
-
yTranslate,
|
|
152
144
|
startComponentsAnimation,
|
|
153
145
|
setStartComponentsAnimation,
|
|
154
146
|
isActiveGesture: playerAnimationState !== null,
|
|
@@ -11,8 +11,6 @@ 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";
|
|
16
14
|
|
|
17
15
|
const { width: SCREEN_WIDTH } = Dimensions.get("screen");
|
|
18
16
|
|
|
@@ -28,10 +26,6 @@ type Props = {
|
|
|
28
26
|
isTabletLandscape?: boolean;
|
|
29
27
|
isAudioPlayer?: boolean;
|
|
30
28
|
isTablet?: boolean;
|
|
31
|
-
inline?: any;
|
|
32
|
-
docked?: boolean;
|
|
33
|
-
isModal?: boolean;
|
|
34
|
-
pip?: boolean;
|
|
35
29
|
};
|
|
36
30
|
|
|
37
31
|
const containerStyle = ({
|
|
@@ -48,24 +42,8 @@ export const PlayerDetails = ({
|
|
|
48
42
|
configuration,
|
|
49
43
|
isTabletLandscape = false,
|
|
50
44
|
isAudioPlayer,
|
|
51
|
-
|
|
52
|
-
docked,
|
|
53
|
-
isModal,
|
|
54
|
-
pip,
|
|
45
|
+
isTablet = false,
|
|
55
46
|
}: 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
47
|
const screenData = useTargetScreenData(entry);
|
|
70
48
|
const insets = useSafeAreaInsets();
|
|
71
49
|
|
|
@@ -101,7 +79,7 @@ export const PlayerDetails = ({
|
|
|
101
79
|
}
|
|
102
80
|
}, [isAudioPlayer]);
|
|
103
81
|
|
|
104
|
-
if (isNilOrEmpty(screenData?.ui_components)
|
|
82
|
+
if (isNilOrEmpty(screenData?.ui_components)) {
|
|
105
83
|
return null;
|
|
106
84
|
}
|
|
107
85
|
|
|
@@ -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 {
|
|
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:
|
|
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:
|
|
188
|
+
aspectRatio:
|
|
189
|
+
isInlineModal && docked ? undefined : playerDimensions.aspectRatio,
|
|
113
190
|
}),
|
|
114
191
|
[baseDimensions, isInlineModal, docked, playerDimensions.aspectRatio]
|
|
115
192
|
);
|
|
@@ -117,29 +194,68 @@ 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
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
142
|
-
|
|
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
|
+
|
|
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>
|
|
143
259
|
</WrapperView>
|
|
144
260
|
);
|
|
145
261
|
};
|