@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5114122134 → 12.0.0-alpha.5208030571

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 (104) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
  2. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
  3. package/Components/AudioPlayer/helpers.tsx +1 -0
  4. package/Components/BaseFocusable/index.tsx +1 -1
  5. package/Components/Cell/Cell.tsx +7 -3
  6. package/Components/Cell/CellWithFocusable.tsx +38 -19
  7. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  8. package/Components/ErrorScreen/index.tsx +1 -1
  9. package/Components/FocusableCell/index.tsx +7 -7
  10. package/Components/FocusableGroup/index.tsx +1 -0
  11. package/Components/FocusableList/FocusableChild.ts +24 -14
  12. package/Components/FocusableList/FocusableItem.tsx +1 -1
  13. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  14. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  15. package/Components/FocusableList/index.tsx +26 -25
  16. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  17. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  18. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  19. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  20. package/Components/HookRenderer/index.tsx +1 -6
  21. package/Components/Image/Image.android.tsx +3 -25
  22. package/Components/Image/Image.tsx +18 -2
  23. package/Components/Image/utils/index.ts +39 -0
  24. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  25. package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
  26. package/Components/Layout/TV/index.tsx +141 -58
  27. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  28. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  29. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  30. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  31. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  32. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
  33. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  34. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  35. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  36. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
  37. package/Components/MasterCell/utils/index.ts +16 -5
  38. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  39. package/Components/ModalComponent/Button/Item.tsx +82 -0
  40. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  41. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  42. package/Components/ModalComponent/Button/assets.ts +4 -0
  43. package/Components/ModalComponent/Button/index.tsx +111 -0
  44. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  45. package/Components/ModalComponent/Header/Title.tsx +70 -0
  46. package/Components/ModalComponent/Header/assets.ts +4 -0
  47. package/Components/ModalComponent/Header/index.tsx +71 -0
  48. package/Components/ModalComponent/Header/utils.ts +79 -0
  49. package/Components/ModalComponent/index.tsx +38 -0
  50. package/Components/ModalComponent/utils.ts +126 -0
  51. package/Components/PlayerContainer/PlayerContainer.tsx +63 -31
  52. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  53. package/Components/PlayerImageBackground/index.tsx +34 -8
  54. package/Components/River/ComponentsMap/ComponentsMap.tsx +90 -2
  55. package/Components/River/TV/River.tsx +2 -3
  56. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  57. package/Components/River/__tests__/componentsMap.test.js +7 -0
  58. package/Components/River/useScreenConfiguration.ts +2 -2
  59. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  60. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  61. package/Components/RouteManager/index.tsx +5 -3
  62. package/Components/Screen/TV/index.web.tsx +151 -0
  63. package/Components/Screen/__tests__/Screen.test.tsx +88 -74
  64. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  65. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  66. package/Components/Screen/index.tsx +103 -43
  67. package/Components/Screen/navigationHandler.ts +0 -82
  68. package/Components/ScreenResolver/index.tsx +4 -2
  69. package/Components/Tabs/TV/styles.ts +1 -1
  70. package/Components/TrackedView/index.tsx +6 -3
  71. package/Components/VideoLive/LiveImageManager.ts +37 -10
  72. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  73. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  74. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  75. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  76. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  77. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  78. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  79. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
  80. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  81. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  82. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  83. package/Components/VideoModal/PlayerWrapper.tsx +65 -42
  84. package/Components/VideoModal/VideoModal.tsx +8 -25
  85. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  86. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +5 -1
  87. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  88. package/Components/VideoModal/utils.ts +3 -3
  89. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  90. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +1 -1
  91. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  92. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  93. package/Components/Viewport/utils.js +1 -1
  94. package/Components/ZappUIComponent/index.tsx +22 -12
  95. package/Components/index.js +2 -0
  96. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  97. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  98. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  99. package/Contexts/ScreenContext/index.tsx +95 -29
  100. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  101. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  102. package/package.json +5 -5
  103. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  104. /package/Contexts/{index.js → index.ts} +0 -0
@@ -19,6 +19,7 @@ type Props = {
19
19
  modalHeight?: number;
20
20
  modalWidth?: number;
21
21
  mode: VideoModalMode;
22
+ groupId?: string;
22
23
  };
23
24
 
24
25
  const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
@@ -93,6 +94,7 @@ export function HandlePlayable({
93
94
  modalHeight,
94
95
  modalWidth,
95
96
  mode,
97
+ groupId,
96
98
  }: Props): React.ReactElement | null {
97
99
  const state = usePickFromState();
98
100
 
@@ -104,7 +106,7 @@ export function HandlePlayable({
104
106
  const [Player, playerModuleProperties] = getPlayer(item, state);
105
107
 
106
108
  const { module: CastPlugin } =
107
- findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins) || {};
109
+ findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
108
110
 
109
111
  const [playable, setPlayable] =
110
112
  React.useState<Nullable<PlayableComponent>>(null);
@@ -167,6 +169,7 @@ export function HandlePlayable({
167
169
  isModal={isModal}
168
170
  mode={mode}
169
171
  disableCastAction={playerModuleProperties?.disableCastAction}
172
+ groupId={groupId}
170
173
  />
171
174
  );
172
175
  }
@@ -1,6 +1 @@
1
- import * as R from "ramda";
2
-
3
- import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator/";
4
- import { HookRenderer as HookRendererComponent } from "./HookRenderer";
5
-
6
- export const HookRenderer = R.compose(withNavigator)(HookRendererComponent);
1
+ export { HookRenderer } from "./HookRenderer";
@@ -3,32 +3,10 @@ import FastImage, {
3
3
  FastImageProps,
4
4
  } from "@applicaster/react-native-fast-image";
5
5
 
6
- export const QBImage = (props: FastImageProps) => {
7
- const source = React.useMemo(() => {
8
- if (typeof props.source === "number") {
9
- return props.source;
10
- }
6
+ import { useImageSource } from "./utils";
11
7
 
12
- return {
13
- uri: props.source.uri,
14
- headers: props.source.headers,
15
- priority: props.source.priority,
16
- cache: props.source.cache,
17
- maxWidth: props.source.maxWidth,
18
- maxHeight: props.source.maxHeight,
19
- };
20
- }, [
21
- ...(typeof props.source === "object"
22
- ? [
23
- props.source?.uri,
24
- props.source?.priority,
25
- props.source?.cache,
26
- props.source?.headers,
27
- props.source?.maxWidth,
28
- props.source?.maxHeight,
29
- ]
30
- : []),
31
- ]);
8
+ export const QBImage = (props: FastImageProps) => {
9
+ const source = useImageSource(props.source);
32
10
 
33
11
  return <FastImage {...props} source={source} />;
34
12
  };
@@ -1,8 +1,24 @@
1
- import { Image, ImageProps, ImageStyle, StyleProp } from "react-native";
1
+ import React from "react";
2
+ import {
3
+ Image,
4
+ ImageBackground,
5
+ ImageProps,
6
+ ImageStyle,
7
+ StyleProp,
8
+ } from "react-native";
2
9
 
3
10
  export interface Props extends ImageProps {
4
11
  style?: StyleProp<ImageStyle> | undefined;
5
12
  }
6
13
 
7
14
  // TODO - React.FC<Props> QBImage should process incoming url and apply any transformations if needed
8
- export const QBImage = Image;
15
+ export const QBImage = ({
16
+ children,
17
+ ...props
18
+ }: Props & { children?: React.ReactNode }) => {
19
+ if (children) {
20
+ return <ImageBackground {...props}>{children}</ImageBackground>;
21
+ }
22
+
23
+ return <Image {...props} />;
24
+ };
@@ -0,0 +1,39 @@
1
+ import FastImage, { Source } from "@applicaster/react-native-fast-image";
2
+ import { useMemo } from "react";
3
+ import { ImageRequireSource } from "react-native";
4
+
5
+ function getSourceCache(cache: Source["cache"]) {
6
+ return cache || FastImage.cacheControl.web;
7
+ }
8
+
9
+ export const useImageSource = (source?: Source | ImageRequireSource) => {
10
+ return useMemo(() => {
11
+ if (source) {
12
+ if (typeof source === "number") {
13
+ return source;
14
+ }
15
+
16
+ return {
17
+ uri: source.uri,
18
+ headers: source.headers,
19
+ priority: source.priority,
20
+ cache: getSourceCache(source?.cache),
21
+ maxWidth: source.maxWidth,
22
+ maxHeight: source.maxHeight,
23
+ };
24
+ }
25
+
26
+ return undefined;
27
+ }, [
28
+ ...(typeof source === "object"
29
+ ? [
30
+ source?.uri,
31
+ source?.priority,
32
+ source?.cache,
33
+ source?.headers,
34
+ source?.maxWidth,
35
+ source?.maxHeight,
36
+ ]
37
+ : []),
38
+ ]);
39
+ };
@@ -60,7 +60,7 @@ export function ScreenLayoutContextProvider(props: {
60
60
  initialState
61
61
  );
62
62
 
63
- const screeenLayoutValue = React.useMemo(
63
+ const screenLayoutValue = React.useMemo(
64
64
  () => ({
65
65
  ...screenLayout,
66
66
  setScreenLayout,
@@ -69,7 +69,7 @@ export function ScreenLayoutContextProvider(props: {
69
69
  );
70
70
 
71
71
  return (
72
- <ScreenLayoutContext.Provider value={screeenLayoutValue}>
72
+ <ScreenLayoutContext.Provider value={screenLayoutValue}>
73
73
  {props.children}
74
74
  </ScreenLayoutContext.Provider>
75
75
  );
@@ -12,19 +12,7 @@ jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
12
12
  useRiverInitialState: () => ({}),
13
13
  }));
14
14
 
15
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
16
- useCurrentScreenData: jest.fn(() => ({
17
- navigations: [
18
- {
19
- category: "menu",
20
- navigation_type: "menu",
21
- styles: {
22
- hide_secondary_level_menu: false,
23
- },
24
- },
25
- ],
26
- })),
27
- }));
15
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen");
28
16
 
29
17
  const Layout = require("..").default;
30
18
 
@@ -125,25 +113,4 @@ describe("Layout TV", () => {
125
113
  expect(bgComponent.props.testProp).toBe(true);
126
114
  });
127
115
  });
128
-
129
- describe("props passed to navbar component", () => {
130
- it("passes correct props", () => {
131
- const { getByTestId } = render(
132
- <Layout
133
- Components={Components}
134
- ComponentsExtraProps={{
135
- NavBar: { testProp: true },
136
- }}
137
- >
138
- <Screen />
139
- </Layout>,
140
- { wrapper }
141
- );
142
-
143
- const navbarComponent = getByTestId("nav-bar-component");
144
- expect(navbarComponent.props.isVisible).toBe(isNavBarVisible);
145
- expect(navbarComponent.props.menuPlugin).toBe(plugins[0]);
146
- expect(navbarComponent.props.testProp).toBe(true);
147
- });
148
- });
149
116
  });
@@ -1,14 +1,15 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
+ import { View, StyleSheet } from "react-native";
3
4
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
- import {
5
- useIsNavBarVisible,
6
- useNavigation,
7
- } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
5
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
6
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
7
+ import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
8
+ import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
9
9
 
10
10
  import {
11
11
  getNavigationProps,
12
+ getPathAttributes,
12
13
  resolveNavigationPlugin,
13
14
  routeIsPlayerScreen,
14
15
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
@@ -20,9 +21,25 @@ import { ScreenContainer } from "./ScreenContainer";
20
21
  import { TransitionOverlay } from "./TransitionOverlay";
21
22
 
22
23
  import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
23
- import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
24
24
  import { PathnameContext } from "../../../Contexts/PathnameContext";
25
- import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
25
+
26
+ import { FocusableGroup } from "../../FocusableGroup";
27
+ import { Screen } from "../../Screen/TV/index.web";
28
+
29
+ export const ScreenDataContext = React.createContext(null);
30
+
31
+ const styles = StyleSheet.create({
32
+ container: {
33
+ position: "absolute",
34
+ width: 1920,
35
+ height: 1080,
36
+ backgroundColor: "black",
37
+ // opacity: 0.5,
38
+
39
+ borderWidth: 4,
40
+ borderColor: "magenta",
41
+ },
42
+ });
26
43
 
27
44
  type Components = {
28
45
  NavBar: React.ComponentType<any>;
@@ -30,20 +47,77 @@ type Components = {
30
47
  };
31
48
 
32
49
  type ComponentsExtraProps = {
33
- Background?: Record<string, any>;
34
50
  NavBar?: Record<string, any>;
51
+ Background?: Record<string, any>;
35
52
  };
36
53
 
37
54
  type Props = {
38
55
  Components: Components;
39
- ComponentsExtraProps?: ComponentsExtraProps;
40
- children: React.ReactNode;
56
+ componentsExtraProps?: ComponentsExtraProps;
57
+ };
58
+
59
+ const StackNavigator = ({ Components }: Props) => {
60
+ // @ts-ignore
61
+ const { mainStack, currentRoute } = useNavigation();
62
+
63
+ // console.log("debug_2", "DEBUG", { mainStack });
64
+
65
+ const renderScreen = ({ route, action, key, state }, index) => {
66
+ const pathAttributes = getPathAttributes({ pathname: route });
67
+
68
+ if (R.isEmpty(pathAttributes)) {
69
+ return null;
70
+ }
71
+
72
+ // console.log("debug_2", "StackNavigator - renderScreen", {
73
+ // index,
74
+ // route,
75
+ // state,
76
+ // key,
77
+ // action,
78
+ // });
79
+
80
+ const id = `${route}`;
81
+
82
+ return (
83
+ <FocusableGroup
84
+ id={id}
85
+ preferredFocus={route === currentRoute}
86
+ excludeFromFocusSearching
87
+ key={id}
88
+ >
89
+ <View style={styles.container}>
90
+ <ScreenDataContext.Provider value={state}>
91
+ <PathnameContext.Provider value={route}>
92
+ <Screen route={route} Components={Components} />
93
+ </PathnameContext.Provider>
94
+ </ScreenDataContext.Provider>
95
+ </View>
96
+ </FocusableGroup>
97
+ );
98
+ };
99
+
100
+ return mainStack.map(renderScreen);
41
101
  };
42
102
 
103
+ const TransitionerTV = ({ componentsExtraProps, Components }: Props) => {
104
+ return (
105
+ <>
106
+ <ScreenLayoutContextProvider>
107
+ <StackNavigator
108
+ componentsExtraProps={componentsExtraProps}
109
+ Components={Components}
110
+ />
111
+ </ScreenLayoutContextProvider>
112
+ </>
113
+ );
114
+ };
115
+
116
+ // @ts-ignore
43
117
  const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
44
118
  const navigator = useNavigation();
45
119
  const theme = useTheme();
46
- const { title } = useNavbarState();
120
+ const { title, visible } = useNavbarState();
47
121
  const { activeRiver, currentRoute } = navigator;
48
122
 
49
123
  const {
@@ -80,66 +154,75 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
80
154
  []
81
155
  );
82
156
 
83
- const navBarVisible = useIsNavBarVisible();
84
-
85
157
  const [navBarReady, setNavBarReady] = React.useState(false);
86
158
 
159
+ const navBarContainer = (
160
+ <NavBarContainer isVisible={visible} onReady={setNavBarReady}>
161
+ <NavBar
162
+ ref={ComponentsExtraProps?.NavBar?.ref}
163
+ isVisible={visible && !routeIsPlayerScreen(currentRoute)}
164
+ menuPlugin={menuPlugin}
165
+ navigationProps={navigationProps}
166
+ {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
167
+ />
168
+ </NavBarContainer>
169
+ );
170
+
171
+ const isTVOS = isApplePlatform();
172
+
87
173
  if (!appReady) {
88
174
  return null;
89
175
  }
90
176
 
91
177
  return (
92
- <LayoutContainer>
93
- <ScreenLayoutContextProvider>
94
- <Components.Background
95
- backgroundColor={backgroundColor}
96
- backgroundImageUrl={backgroundImageUrl}
97
- {...R.omit(["ref"])(ComponentsExtraProps?.Background)}
98
- >
99
- {!isApplePlatform() ? (
100
- <NavBarContainer isVisible={navBarVisible} onReady={setNavBarReady}>
101
- <NavBar
102
- ref={ComponentsExtraProps?.NavBar?.ref}
103
- isVisible={navBarVisible && !routeIsPlayerScreen(currentRoute)}
104
- menuPlugin={menuPlugin}
105
- navigationProps={navigationProps}
106
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
107
- />
108
- </NavBarContainer>
109
- ) : null}
110
-
111
- {navBarReady ? (
112
- /**
178
+ // @ts-ignore
179
+ <TransitionerTV
180
+ componentsExtraProps={ComponentsExtraProps}
181
+ Components={Components}
182
+ >
183
+ <LayoutContainer>
184
+ <ScreenLayoutContextProvider>
185
+ <Components.Background
186
+ backgroundColor={backgroundColor}
187
+ backgroundImageUrl={backgroundImageUrl}
188
+ {...R.omit(["ref"])(ComponentsExtraProps?.Background)}
189
+ >
190
+ {!isTVOS ? navBarContainer : null}
191
+ {navBarReady ? (
192
+ /**
113
193
  Need to re-mount this component on each navigation event
114
194
  It's a hack to work around the fact that we don't support
115
195
  correct screen rendering in our navigator (shared currentRoute state)
116
196
  **/
117
- <PathnameContext.Provider value={navigator.currentRoute}>
118
- <ScreenContainer>{children}</ScreenContainer>
119
- </PathnameContext.Provider>
120
- ) : null}
121
-
122
- {isApplePlatform() ? (
123
- /**
124
- Render NavBarContainer over ScreenContainer to let tvOS native
125
- focus manager works correctly to focus nav bar items first
126
- **/
127
- <NavBarContainer isVisible={navBarVisible} onReady={setNavBarReady}>
128
- <NavBar
129
- ref={ComponentsExtraProps?.NavBar?.ref}
130
- isVisible={navBarVisible && !routeIsPlayerScreen(currentRoute)}
131
- menuPlugin={menuPlugin}
132
- navigationProps={navigationProps}
133
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
134
- />
135
- </NavBarContainer>
136
- ) : null}
137
-
138
- <TransitionOverlay />
139
- </Components.Background>
140
- </ScreenLayoutContextProvider>
141
- </LayoutContainer>
197
+ <PathnameContext.Provider value={navigator.currentRoute}>
198
+ <ScreenContainer>{children}</ScreenContainer>
199
+ </PathnameContext.Provider>
200
+ ) : null}
201
+ {/** Render NavBarContainer over ScreenContainer to let tvOS native
202
+ focus manager works correctly to focus nav bar items first **/}
203
+ {isTVOS ? navBarContainer : null}
204
+ <TransitionOverlay />
205
+ </Components.Background>
206
+ </ScreenLayoutContextProvider>
207
+ </LayoutContainer>
208
+ </TransitionerTV>
142
209
  );
143
210
  };
144
211
 
145
212
  export default Layout;
213
+
214
+ /// Transitioner:
215
+ /*
216
+ Component: Transitioner
217
+ Responsibilities:
218
+ - Transitione between screens.
219
+ Tehere is no transition on Tv so no need for transitioner.
220
+
221
+ Component: StackNavigator
222
+ Responsibilities:
223
+ - Render the screens in the stack.
224
+ - Render the NavBar? I guess navbar should be part of the screen
225
+ - Render the screen.
226
+
227
+ Q
228
+ */
@@ -152,7 +152,6 @@ export const BorderContainerView = (props: Props) => {
152
152
  ...updatedPaddings,
153
153
  width: updatedWidth,
154
154
  height: updatedHeight,
155
- ...borderStyleForMissingBorder,
156
155
  };
157
156
 
158
157
  return (
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  compact,
3
3
  ifElseFocusedSelected,
4
+ ifElseSelected,
4
5
  } from "@applicaster/zapp-react-native-utils/cellUtils";
5
6
 
6
7
  import { getPositionStyles } from "./utils";
@@ -12,9 +13,15 @@ type Props = {
12
13
  value: Function;
13
14
  state: string;
14
15
  visible?: Boolean;
16
+ isMobile?: Boolean;
15
17
  };
16
18
 
17
- export const CellBadge = ({ value, state, visible = true }: Props) => {
19
+ export const CellBadge = ({
20
+ value,
21
+ state,
22
+ visible = true,
23
+ isMobile = false,
24
+ }: Props) => {
18
25
  if (!value("cell_badge_switch") || !visible) {
19
26
  return null;
20
27
  }
@@ -45,13 +52,19 @@ export const CellBadge = ({ value, state, visible = true }: Props) => {
45
52
  data: [
46
53
  {
47
54
  func: () => {
48
- return ifElseFocusedSelected(
49
- state,
50
- value("cell_badge_focused"),
51
- value("cell_badge_selected"),
52
- value("cell_badge_focused_selected"),
53
- value("cell_badge_default")
54
- );
55
+ return isMobile
56
+ ? ifElseSelected(
57
+ state,
58
+ value("cell_badge_selected"),
59
+ value("cell_badge_default")
60
+ )
61
+ : ifElseFocusedSelected(
62
+ state,
63
+ value("cell_badge_focused"),
64
+ value("cell_badge_selected"),
65
+ value("cell_badge_focused_selected"),
66
+ value("cell_badge_default")
67
+ );
55
68
  },
56
69
  args: [],
57
70
  propName: "uri",
@@ -1,11 +1,11 @@
1
1
  import * as React from "react";
2
2
  import { ImageStyle, View } from "react-native";
3
3
  import * as R from "ramda";
4
- import ImageComponent from "@applicaster/zapp-react-native-ui-components/Components/FastImage";
4
+ import { QBImage } from "@applicaster/zapp-react-native-ui-components/Components/Image";
5
5
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
6
- import { toFiniteNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
7
6
 
8
7
  import { useImageSourceWithDefault, useCheckFailedUri } from "./hooks";
8
+ import useImageSize from "./hooks/useImageSize";
9
9
 
10
10
  type Source = {
11
11
  uri: string;
@@ -19,32 +19,13 @@ type Props = Record<string, any> & {
19
19
  withDimensions: (source: Source) => Source;
20
20
  };
21
21
 
22
- const MemoizedImage = React.memo(ImageComponent, R.equals);
23
-
24
- const normalize = Math.ceil;
22
+ const MemoizedImage = React.memo(QBImage, R.equals);
25
23
 
26
24
  const isValidExternalSource = (source): boolean =>
27
25
  source?.uri?.startsWith("http") ||
28
26
  source?.uri?.startsWith("data:image") ||
29
27
  source?.uri?.startsWith("file://");
30
28
 
31
- const isValidSize = (size: unknown): boolean =>
32
- toFiniteNumberWithDefault(0, size) > 0;
33
-
34
- const getSourceWithMaxSizes = (applyMaxSize, style, source) => {
35
- const { width, height } = style;
36
-
37
- if (!applyMaxSize || !isValidSize(width) || !isValidSize(height)) {
38
- return source;
39
- }
40
-
41
- return {
42
- ...source,
43
- maxWidth: normalize(width),
44
- maxHeight: normalize(height),
45
- };
46
- };
47
-
48
29
  export default function Image({
49
30
  style,
50
31
  uri,
@@ -82,10 +63,12 @@ export default function Image({
82
63
 
83
64
  const applyMaxSize = toBooleanWithDefaultFalse(otherProps?.applyMaxSize);
84
65
 
85
- const sourceWithMaxSizes = React.useMemo(
86
- () => withDimensions(getSourceWithMaxSizes(applyMaxSize, style, source)),
87
- [applyMaxSize, style?.height, style?.width, source?.uri, withDimensions]
88
- );
66
+ const sourceWithMaxSizes = useImageSize({
67
+ style,
68
+ applyMaxSize,
69
+ source,
70
+ withDimensions,
71
+ });
89
72
 
90
73
  if (isFailedToLoadUri(uri) || !isValidExternalSource(source)) {
91
74
  return <View style={style} />;
@@ -43,14 +43,16 @@ function Image({
43
43
  [source, error]
44
44
  );
45
45
 
46
+ const _source = shouldRenderImg
47
+ ? withDimensions(source)
48
+ : defaultPlaceHolderImage;
49
+
46
50
  return (
47
51
  // @ts-ignore
48
52
  <MemoizedImage
49
53
  style={style as ImageStyle}
50
54
  onError={() => setErrorState(true)}
51
- source={
52
- shouldRenderImg ? withDimensions(source) : defaultPlaceHolderImage
53
- }
55
+ source={_source?.uri ? _source : undefined}
54
56
  {...R.omit(["source"], otherProps)}
55
57
  />
56
58
  );
@@ -0,0 +1,65 @@
1
+ import * as React from "react";
2
+ import { ImageStyle } from "react-native";
3
+ import { toFiniteNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
4
+
5
+ type Source = {
6
+ uri: string;
7
+ };
8
+
9
+ type Props = Record<string, any> & {
10
+ style: ImageStyle;
11
+ uri?: string;
12
+ placeholderImage?: string;
13
+ entry?: ZappEntry | ZappFeed;
14
+ withDimensions: (source: Source) => Source;
15
+ };
16
+
17
+ const normalize = Math.ceil;
18
+
19
+ const isValidSize = (size: unknown): boolean =>
20
+ toFiniteNumberWithDefault(0, size) > 0;
21
+
22
+ type WidthDimensions = { aspectRatio?: number; width: number; height?: number };
23
+ type HeightDimensions = {
24
+ aspectRatio?: number;
25
+ width?: number;
26
+ height: number;
27
+ };
28
+ type FullDimensions = { aspectRatio?: number; width: number; height: number };
29
+ type Dimensions = WidthDimensions | HeightDimensions | FullDimensions;
30
+
31
+ const calculateDimensions = ({ aspectRatio, width, height }: Dimensions) => {
32
+ if (aspectRatio) {
33
+ return {
34
+ width: width || height * aspectRatio,
35
+ height: height || width / aspectRatio,
36
+ };
37
+ }
38
+
39
+ return { width, height };
40
+ };
41
+
42
+ const getSourceWithMaxSizes = (applyMaxSize, style, source) => {
43
+ const { width, height } = calculateDimensions(style);
44
+
45
+ if (!applyMaxSize || !isValidSize(width) || !isValidSize(height)) {
46
+ return source;
47
+ }
48
+
49
+ return {
50
+ ...source,
51
+ maxWidth: normalize(width),
52
+ maxHeight: normalize(height),
53
+ };
54
+ };
55
+
56
+ export default function useImageSize(props: Props) {
57
+ const { style, applyMaxSize, source, withDimensions } = props;
58
+
59
+ const sourceWithMaxSizes = React.useMemo(
60
+ () => withDimensions(getSourceWithMaxSizes(applyMaxSize, style, source)),
61
+ [applyMaxSize, style?.height, style?.width, source?.uri, withDimensions]
62
+ );
63
+
64
+ return sourceWithMaxSizes;
65
+ }