@applicaster/zapp-react-native-ui-components 13.0.0-alpha.8490438700 → 13.0.0-alpha.9103242840
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/BaseFocusable/index.ios.ts +1 -1
- package/Components/BaseFocusable/index.tsx +1 -1
- package/Components/Cell/Cell.tsx +4 -7
- package/Components/Cell/TvOSCellComponent.tsx +20 -22
- package/Components/Cell/index.js +3 -1
- package/Components/Focusable/FocusableTvOS.tsx +5 -1
- package/Components/Focusable/Touchable.tsx +20 -19
- package/Components/FocusableList/index.tsx +26 -9
- package/Components/FocusableScrollView/index.tsx +39 -12
- package/Components/Layout/TV/NavBarContainer.tsx +8 -7
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +1 -1
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +1 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -4
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -5
- package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/utils/index.ts +1 -1
- package/Components/ModalComponent/Header/index.tsx +3 -3
- package/Components/River/ComponentsMap/ComponentsMap.tsx +65 -39
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +51 -78
- package/Components/River/RiverFooter.tsx +9 -39
- package/Components/River/RiverItem.tsx +2 -37
- package/Components/River/TV/index.tsx +6 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +31 -148
- package/Components/River/__tests__/componentsMap.test.js +5 -17
- package/Components/Screen/index.tsx +39 -13
- package/Components/Tabs/Tab.tsx +6 -6
- package/Components/TextInputTv/index.tsx +2 -2
- package/Components/Transitioner/AnimationManager.js +8 -8
- package/Components/Transitioner/Scene.tsx +23 -52
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +43 -59
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -2
- package/Components/Transitioner/index.js +4 -8
- package/Components/VideoLive/LiveImageManager.ts +1 -27
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +21 -29
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +1 -51
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +5 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +6 -7
- package/Components/VideoModal/ModalAnimation/utils.ts +2 -2
- package/Components/VideoModal/PlayerWrapper.tsx +35 -16
- package/Components/VideoModal/VideoModal.tsx +23 -14
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +90 -0
- package/Components/VideoModal/hooks/utils/index.ts +0 -33
- package/Components/VideoModal/utils.ts +1 -1
- package/Contexts/ComponentsMapOffsetContext/index.tsx +46 -0
- package/Contexts/ScreenContext/index.tsx +2 -3
- package/Decorators/ZappPipesDataConnector/__tests__/Hero.js +1 -1
- package/Decorators/ZappPipesDataConnector/index.tsx +1 -31
- package/package.json +5 -5
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +0 -66
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +0 -93
- package/Components/Screen/hooks.ts +0 -56
- package/Components/VideoModal/OpaqueLayer.tsx +0 -33
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +0 -89
- package/Components/VideoModal/hooks/index.ts +0 -7
- package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +0 -49
- package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +0 -91
|
@@ -70,6 +70,21 @@ function ComponentsMapComponent(props: Props) {
|
|
|
70
70
|
|
|
71
71
|
const [flatListHeight, setFlatListHeight] = React.useState(null);
|
|
72
72
|
|
|
73
|
+
const {
|
|
74
|
+
isAnyLoading,
|
|
75
|
+
isAllLoaded,
|
|
76
|
+
waitForAllComponents,
|
|
77
|
+
onLoadFinished,
|
|
78
|
+
onLoadFailed,
|
|
79
|
+
shouldShowLoadingError,
|
|
80
|
+
isAnyLoaded,
|
|
81
|
+
arePreviousComponentsLoaded,
|
|
82
|
+
} = useLoadingState(feed?.entry?.length || components.length);
|
|
83
|
+
|
|
84
|
+
const theme = useTheme();
|
|
85
|
+
|
|
86
|
+
const logTimestamp = useProfilerLogging();
|
|
87
|
+
|
|
73
88
|
const riverComponents = React.useMemo(() => {
|
|
74
89
|
if (feed?.entry?.length < components.length) {
|
|
75
90
|
return R.slice(0, feed?.entry?.length, components);
|
|
@@ -78,42 +93,55 @@ function ComponentsMapComponent(props: Props) {
|
|
|
78
93
|
return components;
|
|
79
94
|
}, [components, feed]);
|
|
80
95
|
|
|
81
|
-
const logTimestamp = useProfilerLogging();
|
|
82
|
-
|
|
83
|
-
const onLoadDone = React.useCallback(() => {
|
|
84
|
-
logTimestamp(riverId?.toString());
|
|
85
|
-
}, [logTimestamp]);
|
|
86
|
-
|
|
87
|
-
const { loadingState, onLoadFinished, onLoadFailed, shouldShowLoadingError } =
|
|
88
|
-
useLoadingState(riverComponents.length, onLoadDone);
|
|
89
|
-
|
|
90
|
-
const theme = useTheme();
|
|
91
|
-
|
|
92
96
|
const renderRiverItem = React.useCallback(
|
|
93
97
|
({ item, index }) => {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
isScreenWrappedInContainer,
|
|
99
|
-
feed,
|
|
100
|
-
groupId,
|
|
101
|
-
onLoadFailed,
|
|
102
|
-
onLoadFinished,
|
|
103
|
-
getStaticComponentFeed,
|
|
104
|
-
isLast: isLast(index, riverComponents.length),
|
|
105
|
-
loadingState,
|
|
98
|
+
const readyToBeDisplayed = arePreviousComponentsLoaded(index);
|
|
99
|
+
|
|
100
|
+
const styles = {
|
|
101
|
+
display: !readyToBeDisplayed ? "none" : ("flex" as "none" | "flex"),
|
|
106
102
|
};
|
|
107
103
|
|
|
108
104
|
return (
|
|
109
|
-
<
|
|
110
|
-
<
|
|
111
|
-
|
|
105
|
+
<View style={styles}>
|
|
106
|
+
<ScreenLoadingMeasurementsListItemWrapper index={index}>
|
|
107
|
+
<RiverItem
|
|
108
|
+
{...{
|
|
109
|
+
readyToBeDisplayed,
|
|
110
|
+
riverId,
|
|
111
|
+
item,
|
|
112
|
+
index,
|
|
113
|
+
isScreenWrappedInContainer,
|
|
114
|
+
feed,
|
|
115
|
+
groupId,
|
|
116
|
+
onLoadFailed,
|
|
117
|
+
onLoadFinished,
|
|
118
|
+
getStaticComponentFeed,
|
|
119
|
+
isLast: isLast(index, riverComponents.length),
|
|
120
|
+
}}
|
|
121
|
+
/>
|
|
122
|
+
</ScreenLoadingMeasurementsListItemWrapper>
|
|
123
|
+
</View>
|
|
112
124
|
);
|
|
113
125
|
},
|
|
114
|
-
[
|
|
126
|
+
[
|
|
127
|
+
feed,
|
|
128
|
+
getStaticComponentFeed,
|
|
129
|
+
arePreviousComponentsLoaded,
|
|
130
|
+
onLoadFailed,
|
|
131
|
+
onLoadFinished,
|
|
132
|
+
]
|
|
115
133
|
);
|
|
116
134
|
|
|
135
|
+
const renderFooter = React.useCallback(() => {
|
|
136
|
+
return (
|
|
137
|
+
<RiverFooter
|
|
138
|
+
visible={isAnyLoading}
|
|
139
|
+
flatListHeight={flatListHeight}
|
|
140
|
+
isAnyLoaded={isAnyLoaded || waitForAllComponents}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
}, [flatListHeight, isAnyLoading, isAnyLoaded]);
|
|
144
|
+
|
|
117
145
|
const screenStyle = React.useMemo(
|
|
118
146
|
() => ({
|
|
119
147
|
paddingTop: ifEmptyUseFallback(
|
|
@@ -151,6 +179,12 @@ function ComponentsMapComponent(props: Props) {
|
|
|
151
179
|
|
|
152
180
|
usePipesCacheReset(riverId, riverComponents);
|
|
153
181
|
|
|
182
|
+
React.useEffect(() => {
|
|
183
|
+
if (isAllLoaded) {
|
|
184
|
+
logTimestamp(riverId?.toString());
|
|
185
|
+
}
|
|
186
|
+
}, [isAllLoaded]);
|
|
187
|
+
|
|
154
188
|
const refreshControl = React.useMemo(
|
|
155
189
|
() =>
|
|
156
190
|
pullToRefreshEnabled ? (
|
|
@@ -246,11 +280,6 @@ function ComponentsMapComponent(props: Props) {
|
|
|
246
280
|
}
|
|
247
281
|
}, []);
|
|
248
282
|
|
|
249
|
-
const contentContainerStyle = React.useMemo(
|
|
250
|
-
() => (isScreenWrappedInContainer ? {} : screenStyle),
|
|
251
|
-
[isScreenWrappedInContainer, screenStyle]
|
|
252
|
-
);
|
|
253
|
-
|
|
254
283
|
if (shouldShowLoadingError) {
|
|
255
284
|
return <RiverError />;
|
|
256
285
|
}
|
|
@@ -262,7 +291,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
262
291
|
<View style={styles.container}>
|
|
263
292
|
<ScreenLoadingMeasurements
|
|
264
293
|
riverId={riverId}
|
|
265
|
-
numberOfComponents={
|
|
294
|
+
numberOfComponents={feed?.entry?.length || components.length}
|
|
266
295
|
>
|
|
267
296
|
<ViewportTracker>
|
|
268
297
|
<FlatList
|
|
@@ -283,13 +312,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
283
312
|
keyExtractor={keyExtractor}
|
|
284
313
|
renderItem={renderRiverItem}
|
|
285
314
|
data={riverComponents}
|
|
286
|
-
contentContainerStyle={
|
|
287
|
-
|
|
288
|
-
<RiverFooter
|
|
289
|
-
flatListHeight={flatListHeight}
|
|
290
|
-
loadingState={loadingState}
|
|
291
|
-
/>
|
|
315
|
+
contentContainerStyle={
|
|
316
|
+
isScreenWrappedInContainer ? {} : screenStyle
|
|
292
317
|
}
|
|
318
|
+
ListFooterComponent={renderFooter}
|
|
293
319
|
refreshControl={refreshControl}
|
|
294
320
|
onScrollBeginDrag={onScrollBeginDrag}
|
|
295
321
|
onScroll={onScroll}
|
|
@@ -1,86 +1,50 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import * as R from "ramda";
|
|
3
|
+
|
|
4
|
+
const allTrue = R.all(R.equals(true));
|
|
5
|
+
const anyFalse = R.any(R.equals(false));
|
|
6
|
+
const anyTrue = R.any(R.equals(true));
|
|
5
7
|
|
|
6
8
|
const reducer = (state, { payload }) => {
|
|
7
|
-
if (!isNil(payload) && !state[payload]) {
|
|
8
|
-
return set(lensIndex(payload), true)(state);
|
|
9
|
+
if (!R.isNil(payload) && !state[payload]) {
|
|
10
|
+
return R.set(R.lensIndex(payload), true)(state);
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
return state;
|
|
12
14
|
};
|
|
13
15
|
|
|
14
|
-
type LoadingState = {
|
|
15
|
-
index: number;
|
|
16
|
-
done: boolean;
|
|
17
|
-
waitForAllComponents: boolean;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
16
|
type Return = {
|
|
21
|
-
|
|
17
|
+
isAnyLoading: boolean;
|
|
18
|
+
isAllLoaded: boolean;
|
|
19
|
+
waitForAllComponents: boolean;
|
|
22
20
|
onLoadFinished: (index: number) => void;
|
|
23
21
|
onLoadFailed: ({ error, index }: { error: Error; index: number }) => void;
|
|
24
22
|
shouldShowLoadingError: boolean;
|
|
23
|
+
isAnyLoaded: boolean;
|
|
25
24
|
arePreviousComponentsLoaded: (index: number) => boolean;
|
|
26
25
|
};
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
const SHOULD_FAIL_ON_COMPONENT_LOADING = false;
|
|
27
|
+
type Action = { payload: { index: number } };
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
index: -1,
|
|
34
|
-
done: false,
|
|
35
|
-
waitForAllComponents: SHOULD_FAIL_ON_COMPONENT_LOADING,
|
|
36
|
-
});
|
|
29
|
+
type Loaded = true;
|
|
30
|
+
type Loading = false;
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
count: number,
|
|
40
|
-
onLoadDone: () => void
|
|
41
|
-
): Return => {
|
|
42
|
-
const componentStateRef = React.useRef(new Array(count).fill(false));
|
|
43
|
-
const [loadingError, setLoadingError] = React.useState(null);
|
|
44
|
-
|
|
45
|
-
const loadingState = useRefWithInitialValue<BehaviorSubject<LoadingState>>(
|
|
46
|
-
createLoadingStateObservable
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const arePreviousComponentsLoaded = React.useCallback((index) => {
|
|
50
|
-
if (index === 0) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const componentsBefore = slice(0, index, componentStateRef.current);
|
|
55
|
-
|
|
56
|
-
return componentsBefore.every(T);
|
|
57
|
-
}, []);
|
|
32
|
+
type LoadingState = Array<Loaded | Loading>;
|
|
58
33
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
componentStateRef.current = newState;
|
|
62
|
-
const isDone = arePreviousComponentsLoaded(count - 1);
|
|
63
|
-
|
|
64
|
-
const state = loadingState.current.getValue();
|
|
34
|
+
// TODO: Take this value from Zapp configuration, when feature is added to GeneralScreen
|
|
35
|
+
const SHOULD_FAIL_ON_COMPONENT_LOADING = false;
|
|
65
36
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
index: state.index < payload ? payload : state.index,
|
|
69
|
-
done: isDone,
|
|
70
|
-
};
|
|
37
|
+
export const useLoadingState = (count: number): Return => {
|
|
38
|
+
const [loadingError, setLoadingError] = React.useState(null);
|
|
71
39
|
|
|
72
|
-
|
|
40
|
+
const [componentsState, dispatch] = React.useReducer<
|
|
41
|
+
React.Reducer<LoadingState, Action>
|
|
42
|
+
>(reducer, new Array(count).fill(false));
|
|
73
43
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
44
|
+
const handleComponentLoaded = React.useCallback((index) => {
|
|
45
|
+
dispatch({ payload: index });
|
|
77
46
|
}, []);
|
|
78
47
|
|
|
79
|
-
const handleComponentLoaded = React.useCallback(
|
|
80
|
-
(index) => dispatch({ payload: index }),
|
|
81
|
-
[]
|
|
82
|
-
);
|
|
83
|
-
|
|
84
48
|
const handleComponentLoadErrorWhenNeedToFail = React.useCallback(
|
|
85
49
|
({ error }) => {
|
|
86
50
|
if (error !== loadingError) {
|
|
@@ -91,26 +55,35 @@ export const useLoadingState = (
|
|
|
91
55
|
);
|
|
92
56
|
|
|
93
57
|
const handleComponentLoadErrorWhenNoNeedToFail = React.useCallback(
|
|
94
|
-
({ index }) =>
|
|
58
|
+
({ index }) => {
|
|
59
|
+
handleComponentLoaded(index);
|
|
60
|
+
},
|
|
95
61
|
[]
|
|
96
62
|
);
|
|
97
63
|
|
|
98
|
-
|
|
99
|
-
() =>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
[
|
|
109
|
-
loadingError,
|
|
110
|
-
handleComponentLoaded,
|
|
111
|
-
handleComponentLoadErrorWhenNeedToFail,
|
|
112
|
-
handleComponentLoadErrorWhenNoNeedToFail,
|
|
113
|
-
arePreviousComponentsLoaded,
|
|
114
|
-
]
|
|
64
|
+
const arePreviousComponentsLoaded = React.useCallback(
|
|
65
|
+
(index) => {
|
|
66
|
+
if (index === 0) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const componentsBefore = R.slice(0, index, componentsState);
|
|
71
|
+
|
|
72
|
+
return allTrue(componentsBefore);
|
|
73
|
+
},
|
|
74
|
+
[componentsState]
|
|
115
75
|
);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
isAnyLoading: anyFalse(componentsState),
|
|
79
|
+
isAllLoaded: allTrue(componentsState),
|
|
80
|
+
onLoadFinished: handleComponentLoaded,
|
|
81
|
+
onLoadFailed: SHOULD_FAIL_ON_COMPONENT_LOADING
|
|
82
|
+
? handleComponentLoadErrorWhenNeedToFail
|
|
83
|
+
: handleComponentLoadErrorWhenNoNeedToFail,
|
|
84
|
+
shouldShowLoadingError: SHOULD_FAIL_ON_COMPONENT_LOADING && loadingError,
|
|
85
|
+
isAnyLoaded: anyTrue(componentsState),
|
|
86
|
+
waitForAllComponents: SHOULD_FAIL_ON_COMPONENT_LOADING,
|
|
87
|
+
arePreviousComponentsLoaded,
|
|
88
|
+
};
|
|
116
89
|
};
|
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { StyleSheet, View } from "react-native";
|
|
3
3
|
import { Spinner } from "@applicaster/zapp-react-native-ui-components/Components/Spinner";
|
|
4
|
-
import type { Subject } from "rxjs";
|
|
5
|
-
import { useStateFromSubscribe } from "@applicaster/zapp-react-native-utils/reactHooks/state/useStateFromSubscribe";
|
|
6
|
-
|
|
7
|
-
type LoadingState = {
|
|
8
|
-
waitForAllComponents: boolean;
|
|
9
|
-
index: number;
|
|
10
|
-
done: boolean;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
type State = {
|
|
14
|
-
visible: boolean;
|
|
15
|
-
isAnyLoaded: boolean;
|
|
16
|
-
};
|
|
17
4
|
|
|
18
5
|
type Props = {
|
|
6
|
+
visible?: boolean;
|
|
19
7
|
flatListHeight?: number;
|
|
20
|
-
|
|
8
|
+
isAnyLoaded: boolean;
|
|
21
9
|
};
|
|
22
10
|
|
|
23
11
|
const FOOTER_COMPONENT_HEIGHT = 200;
|
|
@@ -31,35 +19,17 @@ const footerStyles = StyleSheet.create({
|
|
|
31
19
|
});
|
|
32
20
|
|
|
33
21
|
function RiverFooterComponent(props: Props) {
|
|
34
|
-
const { flatListHeight,
|
|
35
|
-
|
|
36
|
-
const { visible, isAnyLoaded } = useStateFromSubscribe<LoadingState, State>(
|
|
37
|
-
loadingState,
|
|
38
|
-
useCallback(
|
|
39
|
-
({ index, done, waitForAllComponents }, setState) =>
|
|
40
|
-
setState(() => ({
|
|
41
|
-
visible: !done,
|
|
42
|
-
isAnyLoaded: index >= 0 || waitForAllComponents,
|
|
43
|
-
})),
|
|
44
|
-
[]
|
|
45
|
-
),
|
|
46
|
-
{
|
|
47
|
-
visible: true,
|
|
48
|
-
isAnyLoaded: false,
|
|
49
|
-
}
|
|
50
|
-
);
|
|
22
|
+
const { visible = true, flatListHeight, isAnyLoaded } = props;
|
|
51
23
|
|
|
52
24
|
if (!visible) return null;
|
|
53
25
|
|
|
54
26
|
return (
|
|
55
27
|
<View
|
|
56
|
-
renderToHardwareTextureAndroid
|
|
57
|
-
style={
|
|
58
|
-
footerStyles.container,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
]}
|
|
28
|
+
renderToHardwareTextureAndroid={true}
|
|
29
|
+
style={{
|
|
30
|
+
...footerStyles.container,
|
|
31
|
+
height: isAnyLoaded ? FOOTER_COMPONENT_HEIGHT : flatListHeight,
|
|
32
|
+
}}
|
|
63
33
|
>
|
|
64
34
|
<Spinner size={isAnyLoaded ? "small" : "large"} />
|
|
65
35
|
</View>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
|
|
4
4
|
import { applyDecorators } from "../../Decorators";
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
import { riverLogger } from "./logger";
|
|
12
12
|
import { tvPluginsWithCellRenderer } from "../../const";
|
|
13
13
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
14
|
-
import type { BehaviorSubject } from "rxjs";
|
|
15
14
|
|
|
16
15
|
export type RiverItemType = {
|
|
17
16
|
item: ZappUIComponent;
|
|
@@ -25,7 +24,6 @@ export type RiverItemType = {
|
|
|
25
24
|
getStaticComponentFeed: GeneralContentScreenProps["getStaticComponentFeed"];
|
|
26
25
|
readyToBeDisplayed?: boolean;
|
|
27
26
|
isLast: boolean;
|
|
28
|
-
loadingState: BehaviorSubject<{ index: number }>;
|
|
29
27
|
};
|
|
30
28
|
|
|
31
29
|
function getFeedUrl(feed: ZappFeed, index: number) {
|
|
@@ -38,33 +36,6 @@ function getFeedUrl(feed: ZappFeed, index: number) {
|
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
/**
|
|
42
|
-
* useLoadingState for RiverItemComponent
|
|
43
|
-
* takes currentIndex and loadingState as arguments
|
|
44
|
-
**/
|
|
45
|
-
const useLoadingState = (
|
|
46
|
-
currentIndex: number,
|
|
47
|
-
loadingState: RiverItemType["loadingState"]
|
|
48
|
-
) => {
|
|
49
|
-
const [readyToBeDisplayed, setReadyToBeDisplayed] = React.useState(
|
|
50
|
-
loadingState.getValue().index + 1 === currentIndex
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const subscription = loadingState.subscribe(({ index }) => {
|
|
55
|
-
if (index + 1 === currentIndex) {
|
|
56
|
-
setReadyToBeDisplayed(true);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
return () => {
|
|
61
|
-
subscription.unsubscribe();
|
|
62
|
-
};
|
|
63
|
-
}, [loadingState, currentIndex]);
|
|
64
|
-
|
|
65
|
-
return readyToBeDisplayed;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
39
|
function RiverItemComponent(props: RiverItemType) {
|
|
69
40
|
const {
|
|
70
41
|
item,
|
|
@@ -76,12 +47,10 @@ function RiverItemComponent(props: RiverItemType) {
|
|
|
76
47
|
onLoadFinished,
|
|
77
48
|
onLoadFailed,
|
|
78
49
|
getStaticComponentFeed,
|
|
50
|
+
readyToBeDisplayed,
|
|
79
51
|
isLast,
|
|
80
|
-
loadingState,
|
|
81
52
|
} = props;
|
|
82
53
|
|
|
83
|
-
const readyToBeDisplayed = useLoadingState(index, loadingState);
|
|
84
|
-
|
|
85
54
|
const feedUrl = getFeedUrl(feed, index);
|
|
86
55
|
|
|
87
56
|
const Component = useComponentResolver(
|
|
@@ -121,10 +90,6 @@ function RiverItemComponent(props: RiverItemType) {
|
|
|
121
90
|
}
|
|
122
91
|
}, []);
|
|
123
92
|
|
|
124
|
-
if (!readyToBeDisplayed) {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
93
|
if (Component === null || typeof Component === "undefined") {
|
|
129
94
|
riverLogger.warning({
|
|
130
95
|
message: `Component ${item.component_type} is null - skipping rendering`,
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import { compose } from "ramda";
|
|
1
2
|
import { River as RiverComponent } from "./River";
|
|
2
3
|
import { withTvEventHandler } from "./withTVEventHandler";
|
|
4
|
+
import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
|
|
3
5
|
|
|
4
|
-
export const River =
|
|
6
|
+
export const River = compose(
|
|
7
|
+
withTvEventHandler,
|
|
8
|
+
withComponentsMapOffsetContext
|
|
9
|
+
)(RiverComponent);
|
|
@@ -17,138 +17,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
17
17
|
}
|
|
18
18
|
>
|
|
19
19
|
<RCTScrollView
|
|
20
|
-
ListFooterComponent={
|
|
21
|
-
<Memo(RiverFooterComponent)
|
|
22
|
-
flatListHeight={null}
|
|
23
|
-
loadingState={
|
|
24
|
-
BehaviorSubject {
|
|
25
|
-
"_isScalar": false,
|
|
26
|
-
"_value": {
|
|
27
|
-
"done": false,
|
|
28
|
-
"index": -1,
|
|
29
|
-
"waitForAllComponents": false,
|
|
30
|
-
},
|
|
31
|
-
"closed": false,
|
|
32
|
-
"hasError": false,
|
|
33
|
-
"isStopped": false,
|
|
34
|
-
"observers": [
|
|
35
|
-
Subscriber {
|
|
36
|
-
"_parentOrParents": null,
|
|
37
|
-
"_subscriptions": [
|
|
38
|
-
SubjectSubscription {
|
|
39
|
-
"_parentOrParents": [Circular],
|
|
40
|
-
"_subscriptions": null,
|
|
41
|
-
"closed": false,
|
|
42
|
-
"subject": [Circular],
|
|
43
|
-
"subscriber": [Circular],
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
"closed": false,
|
|
47
|
-
"destination": SafeSubscriber {
|
|
48
|
-
"_complete": undefined,
|
|
49
|
-
"_context": [Circular],
|
|
50
|
-
"_error": undefined,
|
|
51
|
-
"_next": [Function],
|
|
52
|
-
"_parentOrParents": null,
|
|
53
|
-
"_parentSubscriber": [Circular],
|
|
54
|
-
"_subscriptions": null,
|
|
55
|
-
"closed": false,
|
|
56
|
-
"destination": {
|
|
57
|
-
"closed": true,
|
|
58
|
-
"complete": [Function],
|
|
59
|
-
"error": [Function],
|
|
60
|
-
"next": [Function],
|
|
61
|
-
},
|
|
62
|
-
"isStopped": false,
|
|
63
|
-
"syncErrorThrowable": false,
|
|
64
|
-
"syncErrorThrown": false,
|
|
65
|
-
"syncErrorValue": null,
|
|
66
|
-
},
|
|
67
|
-
"isStopped": false,
|
|
68
|
-
"syncErrorThrowable": true,
|
|
69
|
-
"syncErrorThrown": false,
|
|
70
|
-
"syncErrorValue": null,
|
|
71
|
-
},
|
|
72
|
-
Subscriber {
|
|
73
|
-
"_parentOrParents": null,
|
|
74
|
-
"_subscriptions": [
|
|
75
|
-
SubjectSubscription {
|
|
76
|
-
"_parentOrParents": [Circular],
|
|
77
|
-
"_subscriptions": null,
|
|
78
|
-
"closed": false,
|
|
79
|
-
"subject": [Circular],
|
|
80
|
-
"subscriber": [Circular],
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
"closed": false,
|
|
84
|
-
"destination": SafeSubscriber {
|
|
85
|
-
"_complete": undefined,
|
|
86
|
-
"_context": [Circular],
|
|
87
|
-
"_error": undefined,
|
|
88
|
-
"_next": [Function],
|
|
89
|
-
"_parentOrParents": null,
|
|
90
|
-
"_parentSubscriber": [Circular],
|
|
91
|
-
"_subscriptions": null,
|
|
92
|
-
"closed": false,
|
|
93
|
-
"destination": {
|
|
94
|
-
"closed": true,
|
|
95
|
-
"complete": [Function],
|
|
96
|
-
"error": [Function],
|
|
97
|
-
"next": [Function],
|
|
98
|
-
},
|
|
99
|
-
"isStopped": false,
|
|
100
|
-
"syncErrorThrowable": false,
|
|
101
|
-
"syncErrorThrown": false,
|
|
102
|
-
"syncErrorValue": null,
|
|
103
|
-
},
|
|
104
|
-
"isStopped": false,
|
|
105
|
-
"syncErrorThrowable": true,
|
|
106
|
-
"syncErrorThrown": false,
|
|
107
|
-
"syncErrorValue": null,
|
|
108
|
-
},
|
|
109
|
-
Subscriber {
|
|
110
|
-
"_parentOrParents": null,
|
|
111
|
-
"_subscriptions": [
|
|
112
|
-
SubjectSubscription {
|
|
113
|
-
"_parentOrParents": [Circular],
|
|
114
|
-
"_subscriptions": null,
|
|
115
|
-
"closed": false,
|
|
116
|
-
"subject": [Circular],
|
|
117
|
-
"subscriber": [Circular],
|
|
118
|
-
},
|
|
119
|
-
],
|
|
120
|
-
"closed": false,
|
|
121
|
-
"destination": SafeSubscriber {
|
|
122
|
-
"_complete": undefined,
|
|
123
|
-
"_context": [Circular],
|
|
124
|
-
"_error": undefined,
|
|
125
|
-
"_next": [Function],
|
|
126
|
-
"_parentOrParents": null,
|
|
127
|
-
"_parentSubscriber": [Circular],
|
|
128
|
-
"_subscriptions": null,
|
|
129
|
-
"closed": false,
|
|
130
|
-
"destination": {
|
|
131
|
-
"closed": true,
|
|
132
|
-
"complete": [Function],
|
|
133
|
-
"error": [Function],
|
|
134
|
-
"next": [Function],
|
|
135
|
-
},
|
|
136
|
-
"isStopped": false,
|
|
137
|
-
"syncErrorThrowable": false,
|
|
138
|
-
"syncErrorThrown": false,
|
|
139
|
-
"syncErrorValue": null,
|
|
140
|
-
},
|
|
141
|
-
"isStopped": false,
|
|
142
|
-
"syncErrorThrowable": true,
|
|
143
|
-
"syncErrorThrown": false,
|
|
144
|
-
"syncErrorValue": null,
|
|
145
|
-
},
|
|
146
|
-
],
|
|
147
|
-
"thrownError": null,
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
/>
|
|
151
|
-
}
|
|
20
|
+
ListFooterComponent={[Function]}
|
|
152
21
|
contentContainerStyle={
|
|
153
22
|
{
|
|
154
23
|
"paddingBottom": undefined,
|
|
@@ -211,14 +80,22 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
211
80
|
style={null}
|
|
212
81
|
>
|
|
213
82
|
<View
|
|
214
|
-
onLayout={[Function]}
|
|
215
83
|
style={
|
|
216
84
|
{
|
|
217
|
-
"
|
|
85
|
+
"display": "flex",
|
|
218
86
|
}
|
|
219
87
|
}
|
|
220
88
|
>
|
|
221
|
-
<View
|
|
89
|
+
<View
|
|
90
|
+
onLayout={[Function]}
|
|
91
|
+
style={
|
|
92
|
+
{
|
|
93
|
+
"flex": 1,
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
>
|
|
97
|
+
<View />
|
|
98
|
+
</View>
|
|
222
99
|
</View>
|
|
223
100
|
</View>
|
|
224
101
|
<View
|
|
@@ -226,13 +103,23 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
226
103
|
style={null}
|
|
227
104
|
>
|
|
228
105
|
<View
|
|
229
|
-
onLayout={[Function]}
|
|
230
106
|
style={
|
|
231
107
|
{
|
|
232
|
-
"
|
|
108
|
+
"display": "none",
|
|
233
109
|
}
|
|
234
110
|
}
|
|
235
|
-
|
|
111
|
+
>
|
|
112
|
+
<View
|
|
113
|
+
onLayout={[Function]}
|
|
114
|
+
style={
|
|
115
|
+
{
|
|
116
|
+
"flex": 1,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
>
|
|
120
|
+
<View />
|
|
121
|
+
</View>
|
|
122
|
+
</View>
|
|
236
123
|
</View>
|
|
237
124
|
<View
|
|
238
125
|
onLayout={[Function]}
|
|
@@ -240,16 +127,12 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
240
127
|
<View
|
|
241
128
|
renderToHardwareTextureAndroid={true}
|
|
242
129
|
style={
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
{
|
|
250
|
-
"height": null,
|
|
251
|
-
},
|
|
252
|
-
]
|
|
130
|
+
{
|
|
131
|
+
"alignItems": "center",
|
|
132
|
+
"height": null,
|
|
133
|
+
"justifyContent": "center",
|
|
134
|
+
"width": "100%",
|
|
135
|
+
}
|
|
253
136
|
}
|
|
254
137
|
>
|
|
255
138
|
<ActivityIndicator
|