@applicaster/zapp-react-native-ui-components 13.0.0-alpha.8532113155 → 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/CellWithFocusable.tsx +59 -43
- package/Components/Cell/TvOSCellComponent.tsx +20 -22
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +6 -13
- 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/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
- 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 -100
- 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/ModalAnimationContext.tsx +3 -2
- 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/Cell/CellWithFocusable.ios.tsx +0 -126
- 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
|
@@ -16,13 +16,13 @@ export class MasterCellAsyncRenderManager {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
public emitAsyncElementRegistrate = () => {
|
|
19
|
-
this.asyncElementRegistrate$.next(
|
|
19
|
+
this.asyncElementRegistrate$.next();
|
|
20
20
|
|
|
21
21
|
return this.decrementAsyncElementRegistrationCount;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
public emitAsyncElementLayout = () => {
|
|
25
|
-
this.asyncElementLayout$.next(
|
|
25
|
+
this.asyncElementLayout$.next();
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
public decrementAsyncElementRegistrationCount = () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { View, StyleSheet, LayoutChangeEvent } from "react-native";
|
|
3
3
|
import { Title, TitleProps } from "./Title";
|
|
4
4
|
import { CloseButton, CloseButtonProps } from "./CloseButton";
|
|
5
5
|
import { getCloseButtonProps, getTitleProps } from "./utils";
|
|
@@ -60,8 +60,8 @@ export function ModalHeader(props: Props) {
|
|
|
60
60
|
width: width - buttonsContainerWidth,
|
|
61
61
|
}}
|
|
62
62
|
>
|
|
63
|
-
{title
|
|
64
|
-
{summary
|
|
63
|
+
{title && <Title {...titleProps} />}
|
|
64
|
+
{summary && <Title {...summaryProps} />}
|
|
65
65
|
</View>
|
|
66
66
|
<View style={{ width: buttonsContainerWidth }}>
|
|
67
67
|
<CloseButton {...closeButtonProps} />
|
|
@@ -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);
|