@applicaster/zapp-react-native-ui-components 13.0.0-rc.11 → 13.0.0-rc.111

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.
Files changed (212) hide show
  1. package/Components/AppContainer/__tests__/AppContainer.test.js +4 -6
  2. package/Components/AppContainer/__tests__/__snapshots__/AppContainer.test.js.snap +1 -1
  3. package/Components/AudioPlayer/AudioPlayer.tsx +7 -4
  4. package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
  5. package/Components/AudioPlayer/__tests__/__snapshots__/Runtime.test.js.snap +4 -4
  6. package/Components/AudioPlayer/__tests__/__snapshots__/artWork.test.js.snap +3 -3
  7. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +56 -113
  8. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +39 -23
  9. package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +3 -3
  10. package/Components/AudioPlayer/__tests__/__snapshots__/summary.test.js.snap +2 -2
  11. package/Components/AudioPlayer/__tests__/__snapshots__/title.test.js.snap +2 -2
  12. package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
  13. package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
  14. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
  15. package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
  16. package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
  17. package/Components/AudioPlayer/__tests__/title.test.js +3 -5
  18. package/Components/AudioPlayer/helpers.tsx +1 -1
  19. package/Components/BaseFocusable/index.ios.ts +1 -1
  20. package/Components/BaseFocusable/index.tsx +67 -31
  21. package/Components/Cell/Cell.tsx +18 -22
  22. package/Components/Cell/CellWithFocusable.tsx +51 -60
  23. package/Components/Cell/CellWrapper.tsx +18 -0
  24. package/Components/Cell/TvOSCellComponent.tsx +23 -30
  25. package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
  26. package/Components/Cell/index.js +3 -1
  27. package/Components/Cell/styles.ts +17 -0
  28. package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +50 -50
  29. package/Components/CellRendererResolver/index.ts +2 -1
  30. package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
  31. package/Components/ComponentResolver/__tests__/componentResolver.test.js +26 -30
  32. package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
  33. package/Components/DisplayState/__tests__/__snapshots__/displayState.test.js.snap +2 -2
  34. package/Components/ErrorScreen/index.tsx +14 -6
  35. package/Components/Focusable/Focusable.tsx +1 -54
  36. package/Components/Focusable/FocusableTvOS.tsx +6 -2
  37. package/Components/Focusable/Touchable.tsx +19 -20
  38. package/Components/Focusable/index.android.tsx +10 -3
  39. package/Components/FocusableCell/index.tsx +1 -1
  40. package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
  41. package/Components/FocusableGroup/index.tsx +0 -3
  42. package/Components/FocusableList/index.tsx +26 -10
  43. package/Components/FocusableScrollView/index.tsx +43 -13
  44. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +3 -0
  45. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +9 -0
  46. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  47. package/Components/GeneralContentScreen/utils/useEventAlerts.ts +30 -0
  48. package/Components/HandlePlayable/HandlePlayable.tsx +21 -27
  49. package/Components/Layout/TV/LayoutBackground.tsx +28 -0
  50. package/Components/Layout/TV/NavBarContainer.tsx +19 -23
  51. package/Components/Layout/TV/ScreenContainer.tsx +8 -2
  52. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
  53. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +3 -1
  54. package/Components/Layout/TV/__tests__/__snapshots__/LayoutContainer.test.tsx.snap +1 -1
  55. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +6 -5
  56. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +12 -11
  57. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +15 -10
  58. package/Components/Layout/TV/__tests__/index.test.tsx +14 -4
  59. package/Components/Layout/TV/index.tsx +6 -20
  60. package/Components/Layout/TV/index.web.tsx +4 -1
  61. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
  62. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +66 -0
  63. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -1
  64. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +10 -15
  65. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
  66. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +93 -0
  67. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
  68. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +3 -3
  69. package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +1 -1
  70. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  71. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const.ts +3 -0
  72. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -6
  73. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/__snapshots__/index.test.tsx.snap +1 -1
  74. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
  75. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +180 -180
  76. package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +11 -19
  77. package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +6 -235
  78. package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
  79. package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
  80. package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
  81. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +2 -2
  82. package/Components/MasterCell/utils/behaviorProvider.ts +136 -0
  83. package/Components/MasterCell/utils/index.ts +9 -135
  84. package/Components/ModalComponent/BottomSheetModalContent.tsx +59 -43
  85. package/Components/ModalComponent/Button/Item.tsx +6 -5
  86. package/Components/ModalComponent/Button/assets.ts +1 -1
  87. package/Components/ModalComponent/Button/index.tsx +45 -62
  88. package/Components/ModalComponent/Header/index.tsx +12 -11
  89. package/Components/ModalComponent/utils.ts +55 -7
  90. package/Components/NativeFocusables/{index.js → index.ts} +4 -2
  91. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
  92. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
  93. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
  94. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +7 -7
  95. package/Components/OfflineHandler/__tests__/index.test.tsx +28 -25
  96. package/Components/OfflineHandler/utils/index.ts +1 -1
  97. package/Components/PlayerContainer/PlayerContainer.tsx +45 -25
  98. package/Components/PlayerContainer/PlayerContainerContext.tsx +9 -0
  99. package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
  100. package/Components/PlayerImageBackground/index.tsx +1 -1
  101. package/Components/River/ComponentsMap/ComponentsMap.tsx +42 -65
  102. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +78 -51
  103. package/Components/River/RefreshControl.tsx +1 -1
  104. package/Components/River/RiverFooter.tsx +39 -9
  105. package/Components/River/RiverItem.tsx +39 -3
  106. package/Components/River/TV/index.tsx +6 -1
  107. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +114 -45
  108. package/Components/River/__tests__/__snapshots__/river.test.js.snap +21 -83
  109. package/Components/River/__tests__/componentsMap.test.js +64 -17
  110. package/Components/River/__tests__/river.test.js +75 -40
  111. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +12 -5
  112. package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
  113. package/Components/RouteManager/__tests__/testId.test.js +8 -6
  114. package/Components/Screen/TV/__tests__/index.web.test.tsx +26 -0
  115. package/Components/Screen/TV/index.web.tsx +5 -6
  116. package/Components/Screen/__tests__/Screen.test.tsx +53 -31
  117. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +6 -6
  118. package/Components/Screen/hooks.ts +53 -0
  119. package/Components/Screen/index.tsx +16 -42
  120. package/Components/ScreenResolver/__tests__/screenResolver.test.js +95 -70
  121. package/Components/Tabs/Tab.tsx +12 -9
  122. package/Components/TextInputTv/__tests__/TextInputTv.test.js +42 -42
  123. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +7 -0
  124. package/Components/TextInputTv/index.tsx +6 -5
  125. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
  126. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +2 -2
  127. package/Components/TrackedView/index.tsx +1 -0
  128. package/Components/Transitioner/AnimationManager.js +15 -15
  129. package/Components/Transitioner/Scene.tsx +53 -24
  130. package/Components/Transitioner/Transitioner.tsx +3 -3
  131. package/Components/Transitioner/__tests__/Scene.test.js +25 -14
  132. package/Components/Transitioner/__tests__/__snapshots__/AnimationManager.test.js.snap +26 -26
  133. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +10 -50
  134. package/Components/Transitioner/__tests__/__snapshots__/config.test.js.snap +20 -20
  135. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +4 -4
  136. package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
  137. package/Components/Transitioner/index.js +8 -4
  138. package/Components/VideoLive/LiveImageManager.ts +27 -1
  139. package/Components/VideoLive/PlayerLiveImageComponent.tsx +36 -24
  140. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +63 -8
  141. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +6 -10
  142. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
  143. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +51 -31
  144. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +8 -4
  145. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +48 -22
  146. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +15 -15
  147. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
  148. package/Components/VideoModal/ModalAnimation/const.ts +5 -0
  149. package/Components/VideoModal/ModalAnimation/index.ts +4 -1
  150. package/Components/VideoModal/ModalAnimation/useModalAnimationContext.ts +6 -0
  151. package/Components/VideoModal/ModalAnimation/utils.ts +38 -2
  152. package/Components/VideoModal/OpaqueLayer.tsx +33 -0
  153. package/Components/VideoModal/PlayerDetails.tsx +18 -10
  154. package/Components/VideoModal/PlayerWrapper.tsx +43 -39
  155. package/Components/VideoModal/VideoModal.tsx +17 -11
  156. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -2
  157. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +13 -10
  158. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
  159. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +66 -156
  160. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +89 -0
  161. package/Components/VideoModal/hooks/index.ts +7 -0
  162. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +49 -0
  163. package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +91 -0
  164. package/Components/VideoModal/hooks/utils/index.ts +33 -0
  165. package/Components/VideoModal/utils.ts +6 -9
  166. package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
  167. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
  168. package/Components/Viewport/ViewportTracker/__tests__/__snapshots__/viewportTracker.test.js.snap +1 -1
  169. package/Components/Viewport/__tests__/utils.test.js +5 -4
  170. package/Components/ZappUIComponent/Placeholder.tsx +3 -1
  171. package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
  172. package/Components/ZappUIComponent/index.tsx +4 -17
  173. package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
  174. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
  175. package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
  176. package/Contexts/ConfigutaionContext/__tests__/__snapshots__/ConfigurationProvider.test.tsx.snap +1 -1
  177. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
  178. package/Contexts/HeaderOffsetContext/index.tsx +4 -6
  179. package/Contexts/ScreenContext/index.tsx +6 -12
  180. package/Contexts/ScreenLayoutContext/index.tsx +5 -3
  181. package/Decorators/Analytics/{index.js → index.tsx} +11 -11
  182. package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
  183. package/Decorators/Navigator/index.tsx +1 -1
  184. package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +77 -77
  185. package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +34 -39
  186. package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -9
  187. package/Decorators/RiverFeedLoader/index.tsx +1 -1
  188. package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +39 -0
  189. package/Decorators/RiverFeedLoader/utils/index.ts +29 -0
  190. package/Decorators/RiverFeedLoader/utils/usePipesContexts.ts +40 -0
  191. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +27 -27
  192. package/Decorators/RiverResolver/index.tsx +6 -8
  193. package/Decorators/ZappPipesDataConnector/__tests__/Hero.js +1 -1
  194. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
  195. package/Decorators/ZappPipesDataConnector/index.tsx +7 -3
  196. package/package.json +13 -11
  197. package/tsconfig.json +2 -3
  198. package/.babelrc +0 -8
  199. package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
  200. package/Components/Cell/CellStyles/Hero/index.js +0 -111
  201. package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
  202. package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
  203. package/Components/Cell/CellStyles/colors.js +0 -40
  204. package/Components/Cell/CellStyles/index.js +0 -15
  205. package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
  206. package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
  207. package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
  208. package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
  209. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
  210. package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
  211. package/Decorators/RiverFeedLoader/utils.ts +0 -100
  212. package/Decorators/RiverResolver/__tests__/__snapshots__/riverResolver.test.tsx.snap +0 -28
@@ -34,6 +34,7 @@ type Props = {
34
34
  getStaticComponentFeed: any;
35
35
  pullToRefreshPipesV1RefreshingStateUpdater: () => boolean;
36
36
  refreshingPipesV1?: boolean;
37
+ stickyHeaderIndices?: number[];
37
38
  };
38
39
 
39
40
  const styles = StyleSheet.create({
@@ -61,6 +62,7 @@ function ComponentsMapComponent(props: Props) {
61
62
  // TODO: Remove when pipes v1 is deprecated.
62
63
  pullToRefreshPipesV1RefreshingStateUpdater,
63
64
  refreshingPipesV1,
65
+ stickyHeaderIndices,
64
66
  } = props;
65
67
 
66
68
  const flatListRef = React.useRef<FlatList | null>(null);
@@ -70,21 +72,6 @@ function ComponentsMapComponent(props: Props) {
70
72
 
71
73
  const [flatListHeight, setFlatListHeight] = React.useState(null);
72
74
 
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
-
88
75
  const riverComponents = React.useMemo(() => {
89
76
  if (feed?.entry?.length < components.length) {
90
77
  return R.slice(0, feed?.entry?.length, components);
@@ -93,55 +80,42 @@ function ComponentsMapComponent(props: Props) {
93
80
  return components;
94
81
  }, [components, feed]);
95
82
 
83
+ const logTimestamp = useProfilerLogging();
84
+
85
+ const onLoadDone = React.useCallback(() => {
86
+ logTimestamp(riverId?.toString());
87
+ }, [logTimestamp]);
88
+
89
+ const { loadingState, onLoadFinished, onLoadFailed, shouldShowLoadingError } =
90
+ useLoadingState(riverComponents.length, onLoadDone);
91
+
92
+ const theme = useTheme();
93
+
96
94
  const renderRiverItem = React.useCallback(
97
95
  ({ item, index }) => {
98
- const readyToBeDisplayed = arePreviousComponentsLoaded(index);
99
-
100
- const styles = {
101
- display: !readyToBeDisplayed ? "none" : ("flex" as "none" | "flex"),
96
+ const riverItemProps = {
97
+ riverId,
98
+ item,
99
+ index,
100
+ isScreenWrappedInContainer,
101
+ feed,
102
+ groupId,
103
+ onLoadFailed,
104
+ onLoadFinished,
105
+ getStaticComponentFeed,
106
+ isLast: isLast(index, riverComponents.length),
107
+ loadingState,
102
108
  };
103
109
 
104
110
  return (
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>
111
+ <ScreenLoadingMeasurementsListItemWrapper index={index}>
112
+ <RiverItem {...riverItemProps} />
113
+ </ScreenLoadingMeasurementsListItemWrapper>
124
114
  );
125
115
  },
126
- [
127
- feed,
128
- getStaticComponentFeed,
129
- arePreviousComponentsLoaded,
130
- onLoadFailed,
131
- onLoadFinished,
132
- ]
116
+ [feed, getStaticComponentFeed, onLoadFailed, onLoadFinished]
133
117
  );
134
118
 
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
-
145
119
  const screenStyle = React.useMemo(
146
120
  () => ({
147
121
  paddingTop: ifEmptyUseFallback(
@@ -179,12 +153,6 @@ function ComponentsMapComponent(props: Props) {
179
153
 
180
154
  usePipesCacheReset(riverId, riverComponents);
181
155
 
182
- React.useEffect(() => {
183
- if (isAllLoaded) {
184
- logTimestamp(riverId?.toString());
185
- }
186
- }, [isAllLoaded]);
187
-
188
156
  const refreshControl = React.useMemo(
189
157
  () =>
190
158
  pullToRefreshEnabled ? (
@@ -280,6 +248,11 @@ function ComponentsMapComponent(props: Props) {
280
248
  }
281
249
  }, []);
282
250
 
251
+ const contentContainerStyle = React.useMemo(
252
+ () => (isScreenWrappedInContainer ? {} : screenStyle),
253
+ [isScreenWrappedInContainer, screenStyle]
254
+ );
255
+
283
256
  if (shouldShowLoadingError) {
284
257
  return <RiverError />;
285
258
  }
@@ -291,7 +264,7 @@ function ComponentsMapComponent(props: Props) {
291
264
  <View style={styles.container}>
292
265
  <ScreenLoadingMeasurements
293
266
  riverId={riverId}
294
- numberOfComponents={feed?.entry?.length || components.length}
267
+ numberOfComponents={riverComponents.length}
295
268
  >
296
269
  <ViewportTracker>
297
270
  <FlatList
@@ -303,6 +276,7 @@ function ComponentsMapComponent(props: Props) {
303
276
  overScrollMode={Platform.OS === "android" ? "never" : "auto"}
304
277
  scrollIndicatorInsets={scrollIndicatorInsets}
305
278
  extraData={feed}
279
+ stickyHeaderIndices={stickyHeaderIndices}
306
280
  onLayout={handleOnLayout}
307
281
  removeClippedSubviews
308
282
  initialNumToRender={3}
@@ -312,10 +286,13 @@ function ComponentsMapComponent(props: Props) {
312
286
  keyExtractor={keyExtractor}
313
287
  renderItem={renderRiverItem}
314
288
  data={riverComponents}
315
- contentContainerStyle={
316
- isScreenWrappedInContainer ? {} : screenStyle
289
+ contentContainerStyle={contentContainerStyle}
290
+ ListFooterComponent={
291
+ <RiverFooter
292
+ flatListHeight={flatListHeight}
293
+ loadingState={loadingState}
294
+ />
317
295
  }
318
- ListFooterComponent={renderFooter}
319
296
  refreshControl={refreshControl}
320
297
  onScrollBeginDrag={onScrollBeginDrag}
321
298
  onScroll={onScroll}
@@ -1,50 +1,86 @@
1
1
  import * as React from "react";
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));
2
+ import { isNil, set, lensIndex, T, slice } from "ramda";
3
+ import { BehaviorSubject } from "rxjs";
4
+ import { useRefWithInitialValue } from "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue";
7
5
 
8
6
  const reducer = (state, { payload }) => {
9
- if (!R.isNil(payload) && !state[payload]) {
10
- return R.set(R.lensIndex(payload), true)(state);
7
+ if (!isNil(payload) && !state[payload]) {
8
+ return set(lensIndex(payload), true)(state);
11
9
  }
12
10
 
13
11
  return state;
14
12
  };
15
13
 
16
- type Return = {
17
- isAnyLoading: boolean;
18
- isAllLoaded: boolean;
14
+ type LoadingState = {
15
+ index: number;
16
+ done: boolean;
19
17
  waitForAllComponents: boolean;
18
+ };
19
+
20
+ type Return = {
21
+ loadingState: BehaviorSubject<LoadingState>;
20
22
  onLoadFinished: (index: number) => void;
21
23
  onLoadFailed: ({ error, index }: { error: Error; index: number }) => void;
22
24
  shouldShowLoadingError: boolean;
23
- isAnyLoaded: boolean;
24
25
  arePreviousComponentsLoaded: (index: number) => boolean;
25
26
  };
26
27
 
27
- type Action = { payload: { index: number } };
28
-
29
- type Loaded = true;
30
- type Loading = false;
31
-
32
- type LoadingState = Array<Loaded | Loading>;
33
-
34
28
  // TODO: Take this value from Zapp configuration, when feature is added to GeneralScreen
35
29
  const SHOULD_FAIL_ON_COMPONENT_LOADING = false;
36
30
 
37
- export const useLoadingState = (count: number): Return => {
31
+ const createLoadingStateObservable = (count: number) =>
32
+ new BehaviorSubject<LoadingState>({
33
+ index: -1,
34
+ done: count === 0,
35
+ waitForAllComponents: SHOULD_FAIL_ON_COMPONENT_LOADING,
36
+ });
37
+
38
+ export const useLoadingState = (
39
+ count: number,
40
+ onLoadDone: () => void
41
+ ): Return => {
42
+ const componentStateRef = React.useRef(new Array(count).fill(false));
38
43
  const [loadingError, setLoadingError] = React.useState(null);
39
44
 
40
- const [componentsState, dispatch] = React.useReducer<
41
- React.Reducer<LoadingState, Action>
42
- >(reducer, new Array(count).fill(false));
45
+ const loadingState = useRefWithInitialValue<BehaviorSubject<LoadingState>>(
46
+ () => createLoadingStateObservable(count)
47
+ );
48
+
49
+ const arePreviousComponentsLoaded = React.useCallback((index) => {
50
+ if (index === 0) {
51
+ return true;
52
+ }
43
53
 
44
- const handleComponentLoaded = React.useCallback((index) => {
45
- dispatch({ payload: index });
54
+ const componentsBefore = slice(0, index, componentStateRef.current);
55
+
56
+ return componentsBefore.every(T);
46
57
  }, []);
47
58
 
59
+ const dispatch = React.useCallback(({ payload }) => {
60
+ const newState = reducer(componentStateRef.current, { payload });
61
+ componentStateRef.current = newState;
62
+ const isDone = arePreviousComponentsLoaded(count - 1);
63
+
64
+ const state = loadingState.current.getValue();
65
+
66
+ const newLoadingState = {
67
+ ...state,
68
+ index: state.index < payload ? payload : state.index,
69
+ done: isDone,
70
+ };
71
+
72
+ loadingState.current.next(newLoadingState);
73
+
74
+ if (isDone) {
75
+ onLoadDone();
76
+ }
77
+ }, []);
78
+
79
+ const handleComponentLoaded = React.useCallback(
80
+ (index) => dispatch({ payload: index }),
81
+ []
82
+ );
83
+
48
84
  const handleComponentLoadErrorWhenNeedToFail = React.useCallback(
49
85
  ({ error }) => {
50
86
  if (error !== loadingError) {
@@ -55,35 +91,26 @@ export const useLoadingState = (count: number): Return => {
55
91
  );
56
92
 
57
93
  const handleComponentLoadErrorWhenNoNeedToFail = React.useCallback(
58
- ({ index }) => {
59
- handleComponentLoaded(index);
60
- },
94
+ ({ index }) => handleComponentLoaded(index),
61
95
  []
62
96
  );
63
97
 
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]
98
+ return React.useMemo(
99
+ () => ({
100
+ loadingState: loadingState.current,
101
+ onLoadFinished: handleComponentLoaded,
102
+ onLoadFailed: SHOULD_FAIL_ON_COMPONENT_LOADING
103
+ ? handleComponentLoadErrorWhenNeedToFail
104
+ : handleComponentLoadErrorWhenNoNeedToFail,
105
+ shouldShowLoadingError: SHOULD_FAIL_ON_COMPONENT_LOADING && loadingError,
106
+ arePreviousComponentsLoaded,
107
+ }),
108
+ [
109
+ loadingError,
110
+ handleComponentLoaded,
111
+ handleComponentLoadErrorWhenNeedToFail,
112
+ handleComponentLoadErrorWhenNoNeedToFail,
113
+ arePreviousComponentsLoaded,
114
+ ]
75
115
  );
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
- };
89
116
  };
@@ -9,7 +9,7 @@ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
9
9
  import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/localizationUtils";
10
10
  import { useAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils";
11
11
  import { useSendAnalyticsEventWithFunction } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
12
- import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
12
+ import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useCurrentScreenData";
13
13
  import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
14
14
  import { useDispatch } from "react-redux";
15
15
  import { useShallow } from "zustand/react/shallow";
@@ -1,11 +1,23 @@
1
- import React from "react";
1
+ import React, { useCallback } 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
+ };
4
17
 
5
18
  type Props = {
6
- visible?: boolean;
7
19
  flatListHeight?: number;
8
- isAnyLoaded: boolean;
20
+ loadingState: Subject<LoadingState>;
9
21
  };
10
22
 
11
23
  const FOOTER_COMPONENT_HEIGHT = 200;
@@ -19,17 +31,35 @@ const footerStyles = StyleSheet.create({
19
31
  });
20
32
 
21
33
  function RiverFooterComponent(props: Props) {
22
- const { visible = true, flatListHeight, isAnyLoaded } = props;
34
+ const { flatListHeight, loadingState } = props;
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
+ );
23
51
 
24
52
  if (!visible) return null;
25
53
 
26
54
  return (
27
55
  <View
28
- renderToHardwareTextureAndroid={true}
29
- style={{
30
- ...footerStyles.container,
31
- height: isAnyLoaded ? FOOTER_COMPONENT_HEIGHT : flatListHeight,
32
- }}
56
+ renderToHardwareTextureAndroid
57
+ style={[
58
+ footerStyles.container,
59
+ {
60
+ height: isAnyLoaded ? FOOTER_COMPONENT_HEIGHT : flatListHeight,
61
+ },
62
+ ]}
33
63
  >
34
64
  <Spinner size={isAnyLoaded ? "small" : "large"} />
35
65
  </View>
@@ -1,5 +1,6 @@
1
- import React from "react";
1
+ import React, { useEffect } from "react";
2
2
  import * as R from "ramda";
3
+ import { isGroup } from "@applicaster/zapp-react-native-utils/componentsUtils";
3
4
 
4
5
  import { applyDecorators } from "../../Decorators";
5
6
 
@@ -11,6 +12,7 @@ import {
11
12
  import { riverLogger } from "./logger";
12
13
  import { tvPluginsWithCellRenderer } from "../../const";
13
14
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
15
+ import type { BehaviorSubject } from "rxjs";
14
16
 
15
17
  export type RiverItemType = {
16
18
  item: ZappUIComponent;
@@ -24,6 +26,7 @@ export type RiverItemType = {
24
26
  getStaticComponentFeed: GeneralContentScreenProps["getStaticComponentFeed"];
25
27
  readyToBeDisplayed?: boolean;
26
28
  isLast: boolean;
29
+ loadingState: BehaviorSubject<{ index: number }>;
27
30
  };
28
31
 
29
32
  function getFeedUrl(feed: ZappFeed, index: number) {
@@ -36,6 +39,33 @@ function getFeedUrl(feed: ZappFeed, index: number) {
36
39
  }
37
40
  }
38
41
 
42
+ /**
43
+ * useLoadingState for RiverItemComponent
44
+ * takes currentIndex and loadingState as arguments
45
+ **/
46
+ const useLoadingState = (
47
+ currentIndex: number,
48
+ loadingState: RiverItemType["loadingState"]
49
+ ) => {
50
+ const [readyToBeDisplayed, setReadyToBeDisplayed] = React.useState(
51
+ loadingState.getValue().index + 1 === currentIndex
52
+ );
53
+
54
+ useEffect(() => {
55
+ const subscription = loadingState.subscribe(({ index }) => {
56
+ if (index + 1 === currentIndex) {
57
+ setReadyToBeDisplayed(true);
58
+ }
59
+ });
60
+
61
+ return () => {
62
+ subscription.unsubscribe();
63
+ };
64
+ }, [loadingState, currentIndex]);
65
+
66
+ return readyToBeDisplayed;
67
+ };
68
+
39
69
  function RiverItemComponent(props: RiverItemType) {
40
70
  const {
41
71
  item,
@@ -47,10 +77,12 @@ function RiverItemComponent(props: RiverItemType) {
47
77
  onLoadFinished,
48
78
  onLoadFailed,
49
79
  getStaticComponentFeed,
50
- readyToBeDisplayed,
51
80
  isLast,
81
+ loadingState,
52
82
  } = props;
53
83
 
84
+ const readyToBeDisplayed = useLoadingState(index, loadingState);
85
+
54
86
  const feedUrl = getFeedUrl(feed, index);
55
87
 
56
88
  const Component = useComponentResolver(
@@ -81,7 +113,7 @@ function RiverItemComponent(props: RiverItemType) {
81
113
  jsOnly: true,
82
114
  });
83
115
 
84
- if (!CellRenderer && item.component_type !== "group-qb") {
116
+ if (!CellRenderer && !isGroup(item)) {
85
117
  riverLogger.warning({
86
118
  message: "Cell Renderer is null - will fallback to default cell",
87
119
  data: { item, CellRenderer },
@@ -90,6 +122,10 @@ function RiverItemComponent(props: RiverItemType) {
90
122
  }
91
123
  }, []);
92
124
 
125
+ if (!readyToBeDisplayed) {
126
+ return null;
127
+ }
128
+
93
129
  if (Component === null || typeof Component === "undefined") {
94
130
  riverLogger.warning({
95
131
  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 = withTvEventHandler(RiverComponent);
6
+ export const River = compose(
7
+ withTvEventHandler,
8
+ withComponentsMapOffsetContext
9
+ )(RiverComponent);