@applicaster/zapp-react-native-ui-components 12.0.0-alpha.8433353116 → 12.0.0-alpha.8454200631

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 (57) hide show
  1. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  2. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  3. package/Components/Layout/TV/index.tsx +12 -9
  4. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
  5. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +80 -109
  6. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  7. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  8. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  9. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +14 -1
  10. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  11. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  12. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  13. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -3
  14. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  15. package/Components/MasterCell/utils/index.ts +16 -5
  16. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  17. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  18. package/Components/PlayerContainer/PlayerContainer.tsx +16 -9
  19. package/Components/PlayerImageBackground/index.tsx +34 -8
  20. package/Components/River/ComponentsMap/ComponentsMap.tsx +92 -22
  21. package/Components/River/RefreshControl.tsx +55 -1
  22. package/Components/River/__tests__/componentsMap.test.js +6 -0
  23. package/Components/RouteManager/index.tsx +2 -2
  24. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
  25. package/Components/Screen/index.tsx +36 -25
  26. package/Components/Transitioner/Scene.tsx +24 -19
  27. package/Components/Transitioner/Transitioner.tsx +9 -2
  28. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
  29. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  30. package/Components/VideoLive/LiveImageManager.ts +3 -0
  31. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +20 -5
  32. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +0 -5
  33. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  34. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  35. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  36. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  37. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
  38. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  39. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  40. package/Components/VideoModal/PlayerDetails.tsx +3 -3
  41. package/Components/VideoModal/PlayerWrapper.tsx +78 -48
  42. package/Components/VideoModal/VideoModal.tsx +25 -42
  43. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +13 -1
  44. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +151 -119
  45. package/Components/VideoModal/utils.ts +3 -3
  46. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  47. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  48. package/Components/Viewport/utils.js +1 -1
  49. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  50. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  51. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  52. package/Contexts/ScreenContext/index.tsx +94 -25
  53. package/Contexts/ScreenDataContext/index.ts +3 -0
  54. package/events/index.ts +1 -0
  55. package/package.json +5 -5
  56. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  57. /package/Contexts/{index.js → index.ts} +0 -0
@@ -35,7 +35,16 @@ const MeasurementsPortal = ({ Component, onLayout, componentProps }: Props) => {
35
35
  );
36
36
  };
37
37
 
38
- const MeasurementPortalContext = React.createContext(null);
38
+ type MeasurementPortalContextType = {
39
+ measureComponent?: (
40
+ comp: React.ElementType,
41
+ props: Record<any, any>
42
+ ) => Promise<any>;
43
+ measuringInProgress?: boolean;
44
+ };
45
+
46
+ const MeasurementPortalContext =
47
+ React.createContext<null | MeasurementPortalContextType>(null);
39
48
 
40
49
  const MeasurementsPortalContextProvider = ({ children }) => {
41
50
  const Component = React.useRef(View);
@@ -54,6 +54,11 @@ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
54
54
  import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayNextOverlay";
55
55
  import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
56
56
 
57
+ import {
58
+ useModalAnimationContext,
59
+ PlayerAnimationStateEnum,
60
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
61
+
57
62
  type Props = {
58
63
  Player: React.ComponentType<any>;
59
64
  PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
@@ -145,13 +150,7 @@ const renderApplePlayer = ({
145
150
  }) => {
146
151
  const { title, summary } = item || {};
147
152
 
148
- if (!isApplePlatform() || !player) {
149
- return null;
150
- }
151
-
152
- // TODO: Check if it is not breaking default player logic on tvos
153
- // Also if needs to add on tvos brightcove player for QB player
154
- if (player.supportsNativeControls()) {
153
+ if (!isAppleTV() || !player) {
155
154
  return null;
156
155
  }
157
156
 
@@ -235,6 +234,9 @@ const PlayerContainerComponent = (props: Props) => {
235
234
  const screenData = useTargetScreenData(item);
236
235
  const { setVisible: showNavBar } = useSetNavbarState();
237
236
 
237
+ const { isActiveGesture, startComponentsAnimation, setPlayerAnimationState } =
238
+ useModalAnimationContext();
239
+
238
240
  const playerEvent = (event, ...args) => {
239
241
  playerManager.invokeHandler(event, ...args);
240
242
  };
@@ -452,7 +454,7 @@ const PlayerContainerComponent = (props: Props) => {
452
454
  if (disableMiniPlayer) {
453
455
  navigator.closeVideoModal();
454
456
  } else {
455
- navigator.minimiseVideoModal();
457
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
456
458
  }
457
459
  }
458
460
 
@@ -647,7 +649,11 @@ const PlayerContainerComponent = (props: Props) => {
647
649
  autoplay={true}
648
650
  controls={false}
649
651
  disableCastAction={disableCastAction}
650
- docked={navigator.isVideoModalDocked()}
652
+ docked={
653
+ navigator.isVideoModalDocked() &&
654
+ !startComponentsAnimation &&
655
+ !isActiveGesture
656
+ }
651
657
  entry={item}
652
658
  fullscreen={mode === VideoModalMode.FULLSCREEN}
653
659
  inline={inline}
@@ -665,6 +671,7 @@ const PlayerContainerComponent = (props: Props) => {
665
671
  setNextVideoPreloadThresholdPercentage={
666
672
  setNextVideoPreloadThresholdPercentage
667
673
  }
674
+ startComponentsAnimation={startComponentsAnimation}
668
675
  >
669
676
  {renderApplePlayer(applePlayerProps)}
670
677
  </Player>
@@ -1,38 +1,64 @@
1
1
  import React, { PropsWithChildren } from "react";
2
- import { ImageBackground } from "react-native";
2
+ import { ImageBackground, View } from "react-native";
3
3
 
4
4
  import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
5
+ import {
6
+ AnimationComponent,
7
+ ComponentAnimationType,
8
+ useModalAnimationContext,
9
+ PlayerAnimationStateEnum,
10
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
5
11
 
6
12
  type Props = PropsWithChildren<{
7
13
  entry: ZappEntry;
8
14
  style?: { [K: string]: any };
9
15
  imageStyle?: { [K: string]: any };
10
16
  imageKey?: string;
17
+ defaultImageDimensions?: { [K: string]: any };
11
18
  }>;
12
19
 
20
+ const imageSize = { width: "100%", height: "100%" };
21
+
13
22
  const PlayerImageBackgroundComponent = ({
14
23
  entry,
15
24
  children,
16
25
  style,
17
26
  imageStyle,
18
27
  imageKey,
28
+ defaultImageDimensions,
19
29
  }: Props) => {
20
30
  const source = React.useMemo(
21
31
  () => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
22
32
  [imageKey, entry]
23
33
  );
24
34
 
35
+ const { playerAnimationState } = useModalAnimationContext();
36
+
25
37
  if (!source) return <>{children}</>;
26
38
 
27
39
  return (
28
- <ImageBackground
29
- resizeMode="cover"
30
- style={style}
31
- imageStyle={imageStyle}
32
- source={source}
40
+ <View
41
+ style={
42
+ playerAnimationState === PlayerAnimationStateEnum.maximaze
43
+ ? defaultImageDimensions
44
+ : style
45
+ }
33
46
  >
34
- {children}
35
- </ImageBackground>
47
+ <AnimationComponent
48
+ style={style}
49
+ animationType={ComponentAnimationType.player}
50
+ additionalData={defaultImageDimensions}
51
+ >
52
+ <ImageBackground
53
+ resizeMode="cover"
54
+ style={imageSize}
55
+ imageStyle={imageStyle}
56
+ source={source}
57
+ >
58
+ {children}
59
+ </ImageBackground>
60
+ </AnimationComponent>
61
+ </View>
36
62
  );
37
63
  };
38
64
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { View, FlatList, StyleSheet, Platform } from "react-native";
3
+ import { View, StyleSheet, Platform, FlatList } from "react-native";
4
4
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
5
5
  import { RiverItem } from "../RiverItem";
6
6
  import { RiverFooter } from "../RiverFooter";
@@ -21,7 +21,8 @@ import {
21
21
  import { useScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData";
22
22
  import { isLast } from "@applicaster/zapp-react-native-utils/arrayUtils";
23
23
  import { withComponentsMapProvider } from "@applicaster/zapp-react-native-ui-components/Decorators/ComponentsMapWrapper";
24
- import { useScreenScrollStore } from "@applicaster/zapp-react-native-utils/screenState";
24
+ import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
25
+ import { useShallow } from "zustand/react/shallow";
25
26
 
26
27
  type Props = {
27
28
  feed: ZappFeed;
@@ -41,8 +42,10 @@ const styles = StyleSheet.create({
41
42
  },
42
43
  });
43
44
 
44
- const scrollIndicatorInsets = { right: 1 };
45
+ const getNearestValue = (value, optionA, optionB) =>
46
+ Math.abs(value - optionA) < Math.abs(value - optionB) ? optionA : optionB;
45
47
 
48
+ const scrollIndicatorInsets = { right: 1 };
46
49
  const keyExtractor = R.compose(String, R.prop("id"));
47
50
 
48
51
  function ComponentsMapComponent(props: Props) {
@@ -60,6 +63,7 @@ function ComponentsMapComponent(props: Props) {
60
63
  refreshingPipesV1,
61
64
  } = props;
62
65
 
66
+ const flatListRef = React.useRef<FlatList | null>(null);
63
67
  const screenConfig = useScreenConfiguration(riverId);
64
68
  const screenData = useScreenData(riverId);
65
69
  const pullToRefreshEnabled = screenData?.rules?.pull_to_refresh_enabled;
@@ -194,26 +198,87 @@ function ComponentsMapComponent(props: Props) {
194
198
  []
195
199
  );
196
200
 
197
- const onScrollFlatList = React.useCallback(
198
- ({ nativeEvent }, isScrollingDone = false) => {
199
- const {
200
- contentOffset: { y },
201
- } = nativeEvent;
201
+ const navBarStore = useScreenContextV2()._navBarStore;
202
202
 
203
- useScreenScrollStore.setState({
204
- scrollingVelocity: isScrollingDone ? 0 : 1,
205
- scrollPosition: y,
206
- });
207
- },
208
- []
203
+ const scrollY = navBarStore(
204
+ useShallow(({ scrollYAnimated }) => scrollYAnimated)
209
205
  );
210
206
 
211
- const onMomentumScrollEnd = React.useCallback(
212
- ({ nativeEvent }) => {
213
- onScrollFlatList({ nativeEvent }, true);
214
- },
215
- [onScrollFlatList]
216
- );
207
+ const canMomentum = React.useRef(false);
208
+
209
+ const onScrollBeginDrag = React.useCallback(() => {
210
+ canMomentum.current = true;
211
+ }, []);
212
+
213
+ /* onMomentumScrollEnd: Handling snap to expanded/collapsed state ( for navbar ) */
214
+ const _onMomentumScrollEnd = React.useCallback(({ nativeEvent }) => {
215
+ if (!canMomentum.current) return;
216
+ canMomentum.current = false;
217
+
218
+ const { height: headerHeight, scrollState } = navBarStore.getState();
219
+
220
+ const offsetY = Math.max(0, nativeEvent.contentOffset.y);
221
+
222
+ if (
223
+ !(scrollState === 0 || scrollState === -headerHeight) &&
224
+ flatListRef.current
225
+ ) {
226
+ const offset =
227
+ getNearestValue(Math.round(scrollState), -headerHeight, 0) ===
228
+ -headerHeight
229
+ ? Math.round(offsetY + scrollState + headerHeight)
230
+ : Math.round(offsetY + scrollState);
231
+
232
+ flatListRef.current.scrollToOffset({
233
+ animated: true,
234
+ offset,
235
+ });
236
+ }
237
+ }, []);
238
+
239
+ /* onScrollEnd: Handling snap to expanded/collapsed state ( for navbar ) */
240
+ const _onScrollEndDrag = React.useCallback(({ nativeEvent }) => {
241
+ const { height: headerHeight, scrollState } = navBarStore.getState();
242
+
243
+ const offsetY = Math.max(0, nativeEvent.contentOffset.y);
244
+
245
+ if (
246
+ !(scrollState === 0 || scrollState === -headerHeight) &&
247
+ flatListRef.current &&
248
+ nativeEvent.velocity.y === 0
249
+ ) {
250
+ const offset =
251
+ getNearestValue(Math.round(scrollState), -headerHeight, 0) ===
252
+ -headerHeight
253
+ ? Math.round(offsetY + scrollState + headerHeight)
254
+ : Math.round(offsetY + scrollState);
255
+
256
+ flatListRef.current.scrollToOffset({
257
+ animated: true,
258
+ offset,
259
+ });
260
+ }
261
+ }, []);
262
+
263
+ const onScroll = React.useCallback((event) => {
264
+ const {
265
+ nativeEvent: {
266
+ contentOffset: { y },
267
+ layoutMeasurement: { height },
268
+ contentSize: { height: contentHeight },
269
+ },
270
+ } = event;
271
+
272
+ if (y >= 0 && y + height <= contentHeight) {
273
+ scrollY.setValue(y);
274
+ } else {
275
+ if (y <= 0) {
276
+ scrollY.setValue(0);
277
+ } else if (y + height > contentHeight) {
278
+ scrollY.setValue(contentHeight - height);
279
+ }
280
+ }
281
+ }, []);
217
282
 
218
283
  if (shouldShowLoadingError) {
219
284
  return <RiverError />;
@@ -230,6 +295,9 @@ function ComponentsMapComponent(props: Props) {
230
295
  >
231
296
  <ViewportTracker>
232
297
  <FlatList
298
+ ref={(ref) => {
299
+ flatListRef.current = ref;
300
+ }}
233
301
  // Fix for WebView rerender crashes on Android API 28+
234
302
  // https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
235
303
  overScrollMode={Platform.OS === "android" ? "never" : "auto"}
@@ -249,8 +317,10 @@ function ComponentsMapComponent(props: Props) {
249
317
  }
250
318
  ListFooterComponent={renderFooter}
251
319
  refreshControl={refreshControl}
252
- onScroll={onScrollFlatList}
253
- onMomentumScrollEnd={onMomentumScrollEnd}
320
+ onScrollBeginDrag={onScrollBeginDrag}
321
+ onScroll={onScroll}
322
+ onMomentumScrollEnd={_onMomentumScrollEnd}
323
+ onScrollEndDrag={_onScrollEndDrag}
254
324
  scrollEventThrottle={16}
255
325
  {...scrollViewExtraProps}
256
326
  />
@@ -1,5 +1,9 @@
1
1
  import * as React from "react";
2
- import { RefreshControl as RNRefreshControl } from "react-native";
2
+ import {
3
+ Platform,
4
+ RefreshControl as RNRefreshControl,
5
+ StyleSheet,
6
+ } from "react-native";
3
7
  import * as R from "ramda";
4
8
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
5
9
  import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/localizationUtils";
@@ -8,10 +12,30 @@ import { useSendAnalyticsEventWithFunction } from "@applicaster/zapp-react-nativ
8
12
  import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
9
13
  import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
10
14
  import { useDispatch } from "react-redux";
15
+ import { useShallow } from "zustand/react/shallow";
16
+ import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
17
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
11
18
 
12
19
  const BRIGHTNESS_THRESHOLD = 160;
13
20
  const ABOVE_DEFAULT_COLOR = "gray";
14
21
  const BELOW_DEFAULT_COLOR = "white";
22
+ const BASE_INDICATOR_HEIGHT = 40;
23
+ const BASE_INDICATOR_OFFSET = 16;
24
+
25
+ /** Return spacing required to position indicator below the navbar bottom line (Android only) */
26
+ const getRefreshControlOffset = () => {
27
+ return Platform.OS === "ios"
28
+ ? 0
29
+ : BASE_INDICATOR_HEIGHT + BASE_INDICATOR_OFFSET;
30
+ };
31
+
32
+ const styles = StyleSheet.create({
33
+ // eslint-disable-next-line react-native/no-color-literals
34
+ control: {
35
+ zIndex: 1,
36
+ backgroundColor: "transparent",
37
+ },
38
+ });
15
39
 
16
40
  const getBrightness = (RGBcolor) => {
17
41
  const RGBvalues = RGBcolor.substring(
@@ -91,6 +115,34 @@ export const usePullToRefresh = (
91
115
  };
92
116
  };
93
117
 
118
+ /** Returns the offset for the progress view of the RefreshControl component
119
+ * based on navbar content position */
120
+ export const useGetProgressViewOffset = () => {
121
+ const { _navBarStore } = useScreenContextV2();
122
+ const { top } = useSafeAreaInsets();
123
+
124
+ const offset = getRefreshControlOffset();
125
+
126
+ const { height, contentPosition } = _navBarStore(
127
+ useShallow(({ contentPosition, height }) => ({ contentPosition, height }))
128
+ );
129
+
130
+ if (height === 0) {
131
+ return offset;
132
+ }
133
+
134
+ switch (contentPosition) {
135
+ case "on_bottom_status_bar":
136
+ // navbar height
137
+ return offset + height;
138
+ case "on_top_screen":
139
+ // navbar height + status bar height
140
+ return offset + height + top;
141
+ default:
142
+ return offset;
143
+ }
144
+ };
145
+
94
146
  export function RefreshControl(props: {
95
147
  pullToRefreshPipesV1RefreshingStateUpdater?: (refreshing: boolean) => void;
96
148
  refreshingPipesV1?: boolean;
@@ -211,6 +263,7 @@ export function RefreshControl(props: {
211
263
  refreshing={refreshing}
212
264
  onRefresh={onRefreshHandler}
213
265
  colors={[preparedIndicatorColor]}
266
+ progressViewOffset={useGetProgressViewOffset()}
214
267
  progressBackgroundColor={preparedIndicatorBackgroundColor}
215
268
  // @ts-ignore in RN68 this `size` became string
216
269
  size={indicatorSize}
@@ -222,6 +275,7 @@ export function RefreshControl(props: {
222
275
  : null
223
276
  }
224
277
  titleColor={preparedTitleUnderIndicatorColor}
278
+ style={styles.control}
225
279
  />
226
280
  );
227
281
  }
@@ -6,6 +6,12 @@ import configureStore from "redux-mock-store";
6
6
 
7
7
  import * as themeUtils from "@applicaster/zapp-react-native-utils/theme";
8
8
 
9
+ // silences the errors related to React-native-gesture-handler in tests
10
+ jest.mock(
11
+ "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation",
12
+ () => () => null
13
+ );
14
+
9
15
  jest.mock("react-native-safe-area-context", () => ({
10
16
  useSafeAreaInsets: () => ({ top: 50 }),
11
17
  }));
@@ -14,7 +14,7 @@ type Props = { pathname: string; screenData: Record<string, any> };
14
14
  * @param {Props}: see props above
15
15
  */
16
16
  export function RouteManager(props: Props) {
17
- const { pathname, screenData: _screenData } = useRoute();
17
+ const { pathname, screenData } = useRoute();
18
18
  const pathAttributes = getPathAttributes({ pathname });
19
19
 
20
20
  const { screenType, screenId } = R.last(pathAttributes);
@@ -25,7 +25,7 @@ export function RouteManager(props: Props) {
25
25
  screenType={screenType}
26
26
  screenId={screenId}
27
27
  {...props}
28
- screenData={props.screenData}
28
+ screenData={screenData}
29
29
  />
30
30
  </TestId>
31
31
  );
@@ -11,7 +11,9 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
11
11
  }
12
12
  >
13
13
  <View
14
+ hasMenu={false}
14
15
  id="/river/testId"
16
+ pathname="/river/testId"
15
17
  selected="testId"
16
18
  testID="navBar"
17
19
  title=""
@@ -41,7 +43,9 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
41
43
  }
42
44
  >
43
45
  <View
46
+ hasMenu={false}
44
47
  id="/river/testId"
48
+ pathname="/river/testId"
45
49
  selected="testId"
46
50
  testID="navBar"
47
51
  title=""
@@ -6,7 +6,10 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
6
 
7
7
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
8
8
  import { getComponentModule } from "@applicaster/zapp-react-native-utils/pluginUtils";
9
- import { getNavigationPropsV2 } from "@applicaster/zapp-react-native-utils/navigationUtils";
9
+ import {
10
+ getNavigationPropsV2,
11
+ resolveNavigationPlugin,
12
+ } from "@applicaster/zapp-react-native-utils/navigationUtils";
10
13
  import { useSafeAreaInsets } from "react-native-safe-area-context";
11
14
  import {
12
15
  useDimensions,
@@ -52,11 +55,11 @@ function isValidColor(string) {
52
55
  }
53
56
 
54
57
  type Props = {
55
- setToggleMenu: () => void;
56
- setCloseMenu: () => void;
58
+ pathname: unknown;
59
+ screenData: unknown;
57
60
  };
58
61
 
59
- export function Screen({ setToggleMenu, setCloseMenu }: Props) {
62
+ export function Screen(_props: Props) {
60
63
  const theme = useTheme<BaseThemePropertiesMobile>();
61
64
  const navigation = useNavigation();
62
65
  const { plugins } = usePickFromState(["plugins"]);
@@ -70,26 +73,38 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
70
73
  fullDimensions: true,
71
74
  });
72
75
 
73
- const routeData = useRoute();
76
+ const { screenData, pathname } = useRoute();
74
77
 
75
78
  const currentRiver = useScreenData(
76
- getScreenId(routeData.screenData, navigation.activeRiver)
79
+ getScreenId(screenData, navigation.activeRiver)
77
80
  );
78
81
 
79
82
  const { title } = useNavbarState();
80
83
 
81
- const navBarProps = React.useMemo(
82
- () => ({
83
- ...getNavigationPropsV2({
84
- currentRiver,
85
- title,
86
- category: "nav_bar",
87
- }),
88
- setToggleMenu,
89
- setCloseMenu,
90
- }),
91
- [currentRiver, setCloseMenu, setToggleMenu]
92
- );
84
+ const hasMenu =
85
+ resolveNavigationPlugin({
86
+ category: "menu",
87
+ navigations: currentRiver.navigations,
88
+ plugins,
89
+ })?.identifier === "quick_brick_side_menu";
90
+
91
+ const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(() => {
92
+ const props = getNavigationPropsV2({
93
+ currentRiver,
94
+ title,
95
+ category: "nav_bar",
96
+ });
97
+
98
+ if (props) {
99
+ return {
100
+ ...props,
101
+ id: pathname,
102
+ pathname: pathname,
103
+ };
104
+ }
105
+
106
+ return null;
107
+ }, [currentRiver, pathname]);
93
108
 
94
109
  const NavBar = React.useMemo(
95
110
  () =>
@@ -97,12 +112,10 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
97
112
  "nav_bar",
98
113
  currentRiver,
99
114
  plugins
100
- ) as React.ComponentType<MobileNavBarPluginProps>,
115
+ ) as React.ComponentType<MobileNavBarPluginProps & { hasMenu: boolean }>,
101
116
  []
102
117
  );
103
118
 
104
- const { screenData, pathname } = routeData;
105
-
106
119
  const offlinePlugin = getComponentModule({
107
120
  plugins,
108
121
  components: {},
@@ -133,11 +146,9 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
133
146
  return (
134
147
  <ScreenContextProvider pathname={pathname}>
135
148
  <View style={style}>
136
- <NavBar
137
- {...{ ...(navBarProps as MobileNavBarPluginProps), id: pathname }}
138
- />
149
+ {navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
139
150
 
140
- <OfflineFallbackScreen screenData={screenData}>
151
+ <OfflineFallbackScreen screenData={targetScreenData}>
141
152
  {/* @TODO RouteManager doesn't use props, can they be removed ? */}
142
153
  <RouteManager pathname={pathname} screenData={screenData} />
143
154
  </OfflineFallbackScreen>
@@ -7,6 +7,7 @@ import {
7
7
  } from "react-native";
8
8
  import { useSafeAreaFrame } from "react-native-safe-area-context";
9
9
  import { PathnameContext } from "../../Contexts/PathnameContext";
10
+ import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
10
11
 
11
12
  type Props = {
12
13
  children: any;
@@ -16,6 +17,8 @@ type Props = {
16
17
  animating: boolean;
17
18
  contentStyle: ViewStyle;
18
19
  pathname: string;
20
+ isActive: boolean;
21
+ screenData: NavigationScreenData;
19
22
  };
20
23
 
21
24
  /**
@@ -38,34 +41,36 @@ export function Scene({
38
41
  animating,
39
42
  contentStyle,
40
43
  pathname,
44
+ isActive = false,
45
+ screenData,
41
46
  }: Props) {
47
+ const [initialScreenData, setInitialScreenData] = React.useState(screenData);
48
+
49
+ React.useLayoutEffect(() => {
50
+ if (isActive) {
51
+ setInitialScreenData(screenData);
52
+ }
53
+ }, [screenData, isActive]);
54
+
42
55
  const frame = useSafeAreaFrame();
43
56
  const { height, width } = useWindowDimensions();
44
57
 
45
- if (overlayStyle && animating) {
46
- // Safe frame takes too long to update,
47
- // so we can not rely on it there, and use height and width instead.
48
- return (
49
- <Animated.View
50
- pointerEvents={pointerEvents}
51
- style={[style, contentStyle, { height, width }]}
52
- >
53
- <PathnameContext.Provider value={pathname}>
54
- {children}
55
- </PathnameContext.Provider>
56
- <Animated.View style={overlayStyle} />
57
- </Animated.View>
58
- );
59
- }
58
+ // Safe frame takes too long to update,
59
+ // so we can not rely on it there, and use height and width instead.
60
+ const isAnimating = animating && overlayStyle;
61
+ const dimensions = isAnimating ? { height, width } : frame;
60
62
 
61
63
  return (
62
64
  <Animated.View
63
65
  pointerEvents={pointerEvents}
64
- style={[style, contentStyle, frame]}
66
+ style={[style, contentStyle, dimensions]}
65
67
  >
66
- <PathnameContext.Provider value={pathname}>
67
- {children}
68
- </PathnameContext.Provider>
68
+ <ScreenDataContext.Provider value={initialScreenData}>
69
+ <PathnameContext.Provider value={pathname}>
70
+ {children}
71
+ </PathnameContext.Provider>
72
+ </ScreenDataContext.Provider>
73
+ {isAnimating && <Animated.View style={overlayStyle} />}
69
74
  </Animated.View>
70
75
  );
71
76
  }