@applicaster/zapp-react-native-ui-components 14.0.0-alpha.5071825192 → 14.0.0-alpha.5114565431
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/AnimatedInOut/index.tsx +5 -3
- 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 -2
- 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} +11 -5
- package/Components/AudioPlayer/{AudioPlayer.tsx → tv/index.tsx} +17 -58
- package/Components/AudioPlayer/types.ts +40 -0
- package/Components/Cell/index.js +6 -2
- package/Components/Focusable/Focusable.tsx +5 -3
- package/Components/Focusable/FocusableTvOS.tsx +3 -3
- package/Components/Focusable/FocusableiOS.tsx +2 -2
- package/Components/Focusable/__tests__/index.android.test.tsx +3 -0
- package/Components/Focusable/index.android.tsx +12 -8
- package/Components/Focusable/index.tsx +1 -1
- package/Components/FocusableList/index.tsx +4 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +25 -9
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -27
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +2 -2
- package/Components/MasterCell/elementMapper.tsx +1 -2
- package/Components/MasterCell/index.tsx +1 -1
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +42 -32
- package/Components/PlayerImageBackground/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +0 -1
- package/Components/River/TV/River.tsx +2 -17
- package/Components/River/TV/index.tsx +3 -1
- package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
- package/Components/River/TV/withRiverDataLoader.tsx +17 -0
- package/Components/River/TV/withTVEventHandler.tsx +1 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
- package/Components/ScreenRevealManager/index.ts +1 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
- package/Components/Tabs/TV/Tabs.android.tsx +0 -2
- package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
- package/Components/VideoLive/animationUtils.ts +3 -3
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -8
- 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/hooks/useModalSize.ts +18 -2
- package/Components/VideoModal/utils.ts +6 -0
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
- package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
- package/Components/Viewport/VisibilitySensor/VisibilitySensor.tsx +3 -3
- package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/index.ts +3 -3
- package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
- package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
- package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
- package/Decorators/ZappPipesDataConnector/index.tsx +26 -293
- package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +241 -0
- package/Decorators/ZappPipesDataConnector/types.ts +29 -0
- package/package.json +5 -9
- package/Components/AudioPlayer/AudioPlayerLayout.tsx +0 -202
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +0 -66
- 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/VideoModal/hooks/useBackgroundColor.ts +0 -10
- /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
|
@@ -21,6 +21,15 @@ exports[`OfflineHandler renders 1`] = `
|
|
|
21
21
|
}
|
|
22
22
|
>
|
|
23
23
|
<View
|
|
24
|
+
accessibilityState={
|
|
25
|
+
{
|
|
26
|
+
"busy": undefined,
|
|
27
|
+
"checked": undefined,
|
|
28
|
+
"disabled": undefined,
|
|
29
|
+
"expanded": undefined,
|
|
30
|
+
"selected": undefined,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
24
33
|
accessible={true}
|
|
25
34
|
collapsable={false}
|
|
26
35
|
focusable={true}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { useEffect, useReducer } from "react";
|
|
3
|
-
|
|
4
|
-
import { TVMenuControl, View, ViewStyle } from "react-native";
|
|
3
|
+
import { View, ViewStyle } from "react-native";
|
|
5
4
|
import * as R from "ramda";
|
|
6
5
|
import uuid from "uuid/v4";
|
|
7
6
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
@@ -62,6 +61,11 @@ import {
|
|
|
62
61
|
useModalAnimationContext,
|
|
63
62
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
64
63
|
|
|
64
|
+
import {
|
|
65
|
+
PlayerNativeCommandTypes,
|
|
66
|
+
PlayerNativeSendCommand,
|
|
67
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerNativeCommand";
|
|
68
|
+
|
|
65
69
|
type Props = {
|
|
66
70
|
Player: React.ComponentType<any>;
|
|
67
71
|
PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
|
|
@@ -88,7 +92,7 @@ export const VideoModalMode = {
|
|
|
88
92
|
MAXIMIZED: "MAXIMIZED",
|
|
89
93
|
MINIMIZED: "MINIMIZED",
|
|
90
94
|
FULLSCREEN: "FULLSCREEN",
|
|
91
|
-
};
|
|
95
|
+
} as const;
|
|
92
96
|
|
|
93
97
|
export type PlayNextData = {
|
|
94
98
|
state: PlayNextState;
|
|
@@ -127,7 +131,7 @@ const webStyles = {
|
|
|
127
131
|
playerScreen: {
|
|
128
132
|
flex: 1,
|
|
129
133
|
height: "100vh",
|
|
130
|
-
|
|
134
|
+
backgroundColor: "black",
|
|
131
135
|
},
|
|
132
136
|
playerWrapper: {
|
|
133
137
|
height: "100%",
|
|
@@ -135,9 +139,6 @@ const webStyles = {
|
|
|
135
139
|
},
|
|
136
140
|
inlineRiver: {
|
|
137
141
|
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
138
|
-
|
|
139
|
-
borderWidth: 4,
|
|
140
|
-
borderColor: "yellow",
|
|
141
142
|
},
|
|
142
143
|
};
|
|
143
144
|
|
|
@@ -148,7 +149,6 @@ const nativeStyles = {
|
|
|
148
149
|
},
|
|
149
150
|
playerScreen: {
|
|
150
151
|
flex: 1,
|
|
151
|
-
backgroundColor: "black",
|
|
152
152
|
overflow: "hidden",
|
|
153
153
|
},
|
|
154
154
|
playerWrapper: {
|
|
@@ -263,9 +263,15 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
263
263
|
return;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
// send command to clear and stop player
|
|
267
|
+
PlayerNativeSendCommand(
|
|
268
|
+
PlayerNativeCommandTypes.clearPlayerData,
|
|
269
|
+
state.playerId
|
|
270
|
+
);
|
|
271
|
+
|
|
266
272
|
showNavBar(true);
|
|
267
273
|
navigator.goBack();
|
|
268
|
-
}, [isModal, navigator.goBack, showNavBar]);
|
|
274
|
+
}, [isModal, navigator.goBack, state.playerId, showNavBar]);
|
|
269
275
|
|
|
270
276
|
const playEntry = (entry) => navigator.replaceTop(entry, { mode });
|
|
271
277
|
|
|
@@ -393,13 +399,17 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
393
399
|
}
|
|
394
400
|
};
|
|
395
401
|
|
|
396
|
-
const playerRemoteHandler = (
|
|
397
|
-
|
|
402
|
+
const playerRemoteHandler = React.useCallback(
|
|
403
|
+
(isLanguageOverlayVisible = false) =>
|
|
404
|
+
(event) => {
|
|
405
|
+
const { eventType } = event;
|
|
398
406
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
407
|
+
if (!isLanguageOverlayVisible && eventType === "menu") {
|
|
408
|
+
close();
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
[close]
|
|
412
|
+
);
|
|
403
413
|
|
|
404
414
|
// Effects
|
|
405
415
|
useEffect(() => {
|
|
@@ -512,16 +522,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
512
522
|
}
|
|
513
523
|
}, [isAudioContent]);
|
|
514
524
|
|
|
515
|
-
// Needs to handle back button on Apple TV
|
|
516
|
-
// https://github.com/facebook/react-native/issues/18930
|
|
517
|
-
useEffect(() => {
|
|
518
|
-
TVMenuControl?.enableTVMenuKey();
|
|
519
|
-
|
|
520
|
-
return () => {
|
|
521
|
-
TVMenuControl?.disableTVMenuKey();
|
|
522
|
-
};
|
|
523
|
-
}, []);
|
|
524
|
-
|
|
525
525
|
useEffect(() => {
|
|
526
526
|
playerEvent("source_changed", { item });
|
|
527
527
|
|
|
@@ -568,8 +568,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
568
568
|
const isInlineTV = isInlineTVUtil(screenData);
|
|
569
569
|
|
|
570
570
|
const inline =
|
|
571
|
-
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
572
|
-
|
|
571
|
+
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
572
|
+
mode as any
|
|
573
|
+
) || isInlineTV;
|
|
573
574
|
|
|
574
575
|
const value = React.useMemo(
|
|
575
576
|
() => ({ playerId: state.playerId }),
|
|
@@ -590,7 +591,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
590
591
|
);
|
|
591
592
|
}
|
|
592
593
|
|
|
593
|
-
if (
|
|
594
|
+
if (
|
|
595
|
+
screen_background_color &&
|
|
596
|
+
mode !== VideoModalMode.FULLSCREEN &&
|
|
597
|
+
isTV()
|
|
598
|
+
) {
|
|
594
599
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
595
600
|
}
|
|
596
601
|
|
|
@@ -620,6 +625,8 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
620
625
|
playNextData,
|
|
621
626
|
};
|
|
622
627
|
|
|
628
|
+
const pointerEventsProp = mode === "MINIMIZED" ? "box-none" : "auto";
|
|
629
|
+
|
|
623
630
|
return (
|
|
624
631
|
<PlayerStateContext.Provider value={value}>
|
|
625
632
|
<PlayerContainerContextProvider
|
|
@@ -630,9 +637,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
630
637
|
<PlayerContainerContext.Consumer>
|
|
631
638
|
{(context) => (
|
|
632
639
|
<TVEventHandlerComponent
|
|
633
|
-
tvEventHandler={(
|
|
634
|
-
|
|
635
|
-
}
|
|
640
|
+
tvEventHandler={playerRemoteHandler(
|
|
641
|
+
context.isLanguageOverlayVisible
|
|
642
|
+
)}
|
|
636
643
|
>
|
|
637
644
|
<FocusableGroup
|
|
638
645
|
id={FocusableGroupMainContainerId}
|
|
@@ -640,14 +647,17 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
640
647
|
preferredFocus
|
|
641
648
|
shouldUsePreferredFocus
|
|
642
649
|
groupId={groupId}
|
|
650
|
+
pointerEvents={pointerEventsProp}
|
|
643
651
|
>
|
|
644
652
|
{/* Video player and components */}
|
|
645
653
|
<View
|
|
646
654
|
style={styles.playerScreen}
|
|
647
655
|
testID={"player-screen-container"}
|
|
656
|
+
pointerEvents={pointerEventsProp}
|
|
648
657
|
>
|
|
649
658
|
{/* Player container */}
|
|
650
659
|
<View
|
|
660
|
+
pointerEvents={pointerEventsProp}
|
|
651
661
|
style={[
|
|
652
662
|
styles.playerWrapper,
|
|
653
663
|
// eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
|
|
@@ -719,7 +729,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
719
729
|
key={item.id}
|
|
720
730
|
groupId={FocusableGroupMainContainerId}
|
|
721
731
|
cellTapAction={onCellTap}
|
|
722
|
-
extraAnchorPointYOffset={
|
|
732
|
+
extraAnchorPointYOffset={0}
|
|
723
733
|
isScreenWrappedInContainer={true}
|
|
724
734
|
containerHeight={styles.inlineRiver.height}
|
|
725
735
|
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
|
|
|
@@ -4,10 +4,6 @@ import * as React from "react";
|
|
|
4
4
|
import { Text } from "react-native";
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
useFeedLoader,
|
|
9
|
-
useLayoutVersion,
|
|
10
|
-
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
11
7
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
12
8
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
13
9
|
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
@@ -21,6 +17,7 @@ type Props = {
|
|
|
21
17
|
screenId: string;
|
|
22
18
|
screenData: ZappRiver | ZappEntry;
|
|
23
19
|
feedUrl?: string;
|
|
20
|
+
feedData?: PipesDataObject["data"];
|
|
24
21
|
extraProps?: any;
|
|
25
22
|
screenResolverExtraProps?: any;
|
|
26
23
|
componentsMapExtraProps?: any;
|
|
@@ -32,7 +29,7 @@ type Props = {
|
|
|
32
29
|
export const River = (props: Props) => {
|
|
33
30
|
const {
|
|
34
31
|
screenId,
|
|
35
|
-
|
|
32
|
+
feedData,
|
|
36
33
|
extraProps,
|
|
37
34
|
screenResolverExtraProps,
|
|
38
35
|
componentsMapExtraProps,
|
|
@@ -46,7 +43,6 @@ export const River = (props: Props) => {
|
|
|
46
43
|
useSetNavbarState();
|
|
47
44
|
|
|
48
45
|
const rivers = useRivers();
|
|
49
|
-
const isV2 = useLayoutVersion({ isV2: true });
|
|
50
46
|
|
|
51
47
|
const river = React.useMemo(() => rivers?.[screenId], [screenId]);
|
|
52
48
|
|
|
@@ -55,17 +51,6 @@ export const River = (props: Props) => {
|
|
|
55
51
|
[screenId]
|
|
56
52
|
);
|
|
57
53
|
|
|
58
|
-
const connectedScreenUrl = React.useMemo(() => {
|
|
59
|
-
// Avoid using feedUrl or content.src on layouts v2
|
|
60
|
-
if (isV2) return null;
|
|
61
|
-
|
|
62
|
-
return feedUrl || R.path(["content", "src"], screenData);
|
|
63
|
-
}, [feedUrl, screenData]);
|
|
64
|
-
|
|
65
|
-
const { data: feedData } = useFeedLoader({
|
|
66
|
-
feedUrl: connectedScreenUrl,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
54
|
const stringOrEmpty = (value: string | number | undefined): string =>
|
|
70
55
|
R.isNil(value) ? "" : String(value);
|
|
71
56
|
|
|
@@ -2,8 +2,10 @@ import { compose } from "ramda";
|
|
|
2
2
|
import { River as RiverComponent } from "./River";
|
|
3
3
|
import { withTvEventHandler } from "./withTVEventHandler";
|
|
4
4
|
import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
|
|
5
|
+
import { withRiverDataLoader } from "./withRiverDataLoader";
|
|
5
6
|
|
|
6
7
|
export const River = compose(
|
|
7
8
|
withTvEventHandler,
|
|
8
|
-
withComponentsMapOffsetContext
|
|
9
|
+
withComponentsMapOffsetContext,
|
|
10
|
+
withRiverDataLoader
|
|
9
11
|
)(RiverComponent);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { path } from "ramda";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
useFeedLoader,
|
|
6
|
+
useRivers,
|
|
7
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
screenId: string;
|
|
11
|
+
screenData: ZappRiver | ZappEntry;
|
|
12
|
+
feedUrl?: string;
|
|
13
|
+
river?: ZappRiver | ZappEntry;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const withPipesV1DataLoader = (
|
|
17
|
+
WrappedComponent: React.ComponentType<any>
|
|
18
|
+
) => {
|
|
19
|
+
return function WithPipesV1DataLoaderComponent(props: Props) {
|
|
20
|
+
const { screenId, feedUrl } = props;
|
|
21
|
+
|
|
22
|
+
const rivers = useRivers();
|
|
23
|
+
|
|
24
|
+
const river = React.useMemo(() => rivers?.[screenId], [screenId]);
|
|
25
|
+
|
|
26
|
+
const screenData = React.useMemo(
|
|
27
|
+
() => props.screenData || props.river || river,
|
|
28
|
+
[screenId]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const connectedScreenUrl = useMemo(() => {
|
|
32
|
+
// Avoid using feedUrl or content.src on layouts v2
|
|
33
|
+
|
|
34
|
+
return feedUrl || path(["content", "src"], screenData);
|
|
35
|
+
}, [feedUrl, screenData]);
|
|
36
|
+
|
|
37
|
+
const { data: feedData } = useFeedLoader({
|
|
38
|
+
feedUrl: connectedScreenUrl,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return <WrappedComponent {...props} feedData={feedData} />;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useLayoutVersion } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { withPipesV1DataLoader } from "./withPipesV1DataLoader";
|
|
4
|
+
|
|
5
|
+
export const withRiverDataLoader = (
|
|
6
|
+
WrappedComponent: React.ComponentType<any>
|
|
7
|
+
) => {
|
|
8
|
+
return function WithRiverDataLoaderComponent(props) {
|
|
9
|
+
const isV2 = useLayoutVersion({ isV2: true });
|
|
10
|
+
|
|
11
|
+
if (isV2) {
|
|
12
|
+
return <WrappedComponent {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return withPipesV1DataLoader(WrappedComponent)(props);
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -8,7 +8,7 @@ export const withTvEventHandler = (Component) => {
|
|
|
8
8
|
return function WithTVEventHandler(props) {
|
|
9
9
|
const navigator = useNavigation();
|
|
10
10
|
|
|
11
|
-
const remoteHandler = (
|
|
11
|
+
const remoteHandler = (event) => {
|
|
12
12
|
const { eventType } = event;
|
|
13
13
|
|
|
14
14
|
const canGoBack = navigator.canGoBack();
|
|
@@ -159,6 +159,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
159
159
|
>
|
|
160
160
|
<View>
|
|
161
161
|
<View
|
|
162
|
+
onFocusCapture={[Function]}
|
|
162
163
|
onLayout={[Function]}
|
|
163
164
|
style={null}
|
|
164
165
|
>
|
|
@@ -174,6 +175,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
174
175
|
</View>
|
|
175
176
|
</View>
|
|
176
177
|
<View
|
|
178
|
+
onFocusCapture={[Function]}
|
|
177
179
|
onLayout={[Function]}
|
|
178
180
|
style={null}
|
|
179
181
|
>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { makeListOf } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
2
|
+
import { isFirstComponentGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
3
|
+
import { once } from "ramda";
|
|
4
|
+
|
|
5
|
+
const INITIAL_NUMBER_TO_LOAD = 3;
|
|
6
|
+
|
|
7
|
+
// Infer the values of COMPONENT_LOADING_STATE as a type
|
|
8
|
+
type ComponentLoadingState =
|
|
9
|
+
(typeof COMPONENT_LOADING_STATE)[keyof typeof COMPONENT_LOADING_STATE];
|
|
10
|
+
|
|
11
|
+
export const COMPONENT_LOADING_STATE = {
|
|
12
|
+
UNKNOWN: "UNKNOWN",
|
|
13
|
+
LOADED_WITH_SUCCESS: "LOADED_WITH_SUCCESS",
|
|
14
|
+
LOADED_WITH_FAILURE: "LOADED_WITH_FAILURE",
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
// Function to get the number of loaded components
|
|
18
|
+
const getNumberOfLoaded = (states: ComponentLoadingState[]): number => {
|
|
19
|
+
return states.filter((value) => value !== COMPONENT_LOADING_STATE.UNKNOWN)
|
|
20
|
+
.length;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getNumberOfComponentsWaitToLoadBeforePresent = (
|
|
24
|
+
componentsToRender: ZappUIComponent[]
|
|
25
|
+
): number => {
|
|
26
|
+
// when Gallery is the first component, no need to wait the others
|
|
27
|
+
if (isFirstComponentGallery(componentsToRender)) {
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Math.min(INITIAL_NUMBER_TO_LOAD, componentsToRender.length);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export class ScreenRevealManager {
|
|
35
|
+
public numberOfComponentsWaitToLoadBeforePresent: number;
|
|
36
|
+
private renderingState: Array<ComponentLoadingState>;
|
|
37
|
+
private callback: Callback;
|
|
38
|
+
|
|
39
|
+
constructor(componentsToRender: ZappUIComponent[], callback: Callback) {
|
|
40
|
+
this.numberOfComponentsWaitToLoadBeforePresent =
|
|
41
|
+
getNumberOfComponentsWaitToLoadBeforePresent(componentsToRender);
|
|
42
|
+
|
|
43
|
+
this.renderingState = makeListOf<ComponentLoadingState>(
|
|
44
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
45
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
this.callback = once(callback);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
onLoadFinished = (index: number): void => {
|
|
52
|
+
this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS;
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
getNumberOfLoaded(this.renderingState) >=
|
|
56
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
57
|
+
) {
|
|
58
|
+
this.setIsReadyToShow();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
onLoadFailed = (index: number): void => {
|
|
63
|
+
this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE;
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
getNumberOfLoaded(this.renderingState) >=
|
|
67
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
68
|
+
) {
|
|
69
|
+
this.setIsReadyToShow();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
setIsReadyToShow = (): void => {
|
|
74
|
+
this.callback();
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ScreenRevealManager,
|
|
3
|
+
COMPONENT_LOADING_STATE,
|
|
4
|
+
} from "../ScreenRevealManager";
|
|
5
|
+
|
|
6
|
+
describe("ScreenRevealManager", () => {
|
|
7
|
+
const mockCallback = jest.fn();
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
jest.clearAllMocks();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should initialize with the correct number of components to wait for", () => {
|
|
14
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
15
|
+
{ component_type: "component1" },
|
|
16
|
+
{ component_type: "component2" },
|
|
17
|
+
{ component_type: "component3" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
21
|
+
|
|
22
|
+
expect(manager["numberOfComponentsWaitToLoadBeforePresent"]).toBe(3);
|
|
23
|
+
|
|
24
|
+
expect(manager["renderingState"]).toEqual([
|
|
25
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
26
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
27
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should call the callback when the required number of components are loaded successfully", () => {
|
|
32
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
33
|
+
{ component_type: "component1" },
|
|
34
|
+
{ component_type: "component2" },
|
|
35
|
+
{ component_type: "component3" },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
39
|
+
|
|
40
|
+
manager.onLoadFinished(0);
|
|
41
|
+
manager.onLoadFinished(1);
|
|
42
|
+
manager.onLoadFinished(2);
|
|
43
|
+
|
|
44
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should call the callback when the required number of components fail to load", () => {
|
|
48
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
49
|
+
{ component_type: "component1" },
|
|
50
|
+
{ component_type: "component2" },
|
|
51
|
+
{ component_type: "component3" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
55
|
+
|
|
56
|
+
manager.onLoadFailed(0);
|
|
57
|
+
manager.onLoadFailed(1);
|
|
58
|
+
manager.onLoadFailed(2);
|
|
59
|
+
|
|
60
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should call the callback when a mix of successful and failed loads meet the required number", () => {
|
|
64
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
65
|
+
{ component_type: "component1" },
|
|
66
|
+
{ component_type: "component2" },
|
|
67
|
+
{ component_type: "component3" },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
71
|
+
|
|
72
|
+
manager.onLoadFinished(0);
|
|
73
|
+
manager.onLoadFailed(1);
|
|
74
|
+
manager.onLoadFinished(2);
|
|
75
|
+
|
|
76
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should not call the callback if the required number of components are not loaded", () => {
|
|
80
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
81
|
+
{ component_type: "component1" },
|
|
82
|
+
{ component_type: "component2" },
|
|
83
|
+
{ component_type: "component3" },
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
87
|
+
|
|
88
|
+
manager.onLoadFinished(0);
|
|
89
|
+
manager.onLoadFailed(1);
|
|
90
|
+
|
|
91
|
+
expect(mockCallback).not.toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should call the callback when the when first component is gallery and it was loaded successfully", () => {
|
|
95
|
+
const componentsToRender: ZappUIComponent[] = [
|
|
96
|
+
{ component_type: "gallery-qb" },
|
|
97
|
+
{ component_type: "component2" },
|
|
98
|
+
{ component_type: "component3" },
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const manager = new ScreenRevealManager(componentsToRender, mockCallback);
|
|
102
|
+
|
|
103
|
+
manager.onLoadFinished(0);
|
|
104
|
+
|
|
105
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/* eslint-disable react/prop-types */
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { render, screen, act } from "@testing-library/react-native";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import {
|
|
7
|
+
withScreenRevealManager,
|
|
8
|
+
SHOWN,
|
|
9
|
+
TIMEOUT,
|
|
10
|
+
} from "../withScreenRevealManager";
|
|
11
|
+
|
|
12
|
+
// jest.mock("react-native/Libraries/Animated/NativeAnimatedHelper");
|
|
13
|
+
|
|
14
|
+
const MockComponent = ({
|
|
15
|
+
initialNumberToLoad,
|
|
16
|
+
onLoadFinishedFromScreenRevealManager,
|
|
17
|
+
onLoadFailedFromScreenRevealManager,
|
|
18
|
+
}) => {
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
// Simulate loading components
|
|
21
|
+
for (let i = 0; i < initialNumberToLoad; i++) {
|
|
22
|
+
onLoadFinishedFromScreenRevealManager(i);
|
|
23
|
+
}
|
|
24
|
+
}, [initialNumberToLoad, onLoadFinishedFromScreenRevealManager]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<View
|
|
28
|
+
testID="mock-component"
|
|
29
|
+
initialNumberToLoad={initialNumberToLoad}
|
|
30
|
+
onLoadFinishedFromScreenRevealManager={
|
|
31
|
+
onLoadFinishedFromScreenRevealManager
|
|
32
|
+
}
|
|
33
|
+
onLoadFailedFromScreenRevealManager={onLoadFailedFromScreenRevealManager}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const WrappedComponent = withScreenRevealManager(MockComponent);
|
|
39
|
+
|
|
40
|
+
describe.skip("withScreenRevealManager", () => {
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
jest.clearAllMocks();
|
|
43
|
+
jest.useFakeTimers();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
jest.runOnlyPendingTimers();
|
|
48
|
+
jest.useRealTimers();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should render the wrapped component", () => {
|
|
52
|
+
render(
|
|
53
|
+
<WrappedComponent
|
|
54
|
+
componentsToRender={[{ id: "1" }, { id: "2" }, { id: "3" }]}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect(screen.getByTestId("mock-component")).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should animate opacity when ready to show", () => {
|
|
62
|
+
render(
|
|
63
|
+
<WrappedComponent
|
|
64
|
+
componentsToRender={[{ id: "1" }, { id: "2" }, { id: "3" }]}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const animatedView = screen.getByTestId("animated-component");
|
|
69
|
+
|
|
70
|
+
act(() => {
|
|
71
|
+
jest.advanceTimersByTime(TIMEOUT + 100);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(animatedView.props.style.opacity).toBe(SHOWN);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should pass initialNumberToLoad, onLoadFinishedFromScreenRevealManager, and onLoadFailedFromScreenRevealManager to the wrapped component", () => {
|
|
78
|
+
render(
|
|
79
|
+
<WrappedComponent
|
|
80
|
+
componentsToRender={[{ id: "1" }, { id: "2" }, { id: "3" }]}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const mockComponent = screen.getByTestId("mock-component");
|
|
85
|
+
|
|
86
|
+
expect(mockComponent.props.initialNumberToLoad).toBe(3);
|
|
87
|
+
|
|
88
|
+
expect(
|
|
89
|
+
mockComponent.props.onLoadFinishedFromScreenRevealManager
|
|
90
|
+
).toBeInstanceOf(Function);
|
|
91
|
+
|
|
92
|
+
expect(
|
|
93
|
+
mockComponent.props.onLoadFailedFromScreenRevealManager
|
|
94
|
+
).toBeInstanceOf(Function);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { withScreenRevealManager } from "./withScreenRevealManager";
|