@applicaster/zapp-react-native-ui-components 13.0.0-alpha.3528549047 → 13.0.0-alpha.3592913150

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.
@@ -61,6 +61,7 @@ type Props = {
61
61
  skipFocusManagerRegistration?: boolean;
62
62
  shouldUpdate: boolean;
63
63
  behavior: Behavior;
64
+ componentsMapOffset: number;
64
65
  };
65
66
 
66
67
  type State = {
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  import * as R from "ramda";
3
3
  import { View, StyleSheet } from "react-native";
4
4
 
5
- import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
5
+ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
6
6
  import { FocusableCell } from "@applicaster/zapp-react-native-ui-components/Components/FocusableCell";
7
7
  import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtils";
8
8
  import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
@@ -65,6 +65,7 @@ type Props = {
65
65
  isFocusable: boolean;
66
66
  shouldUpdate: boolean;
67
67
  behavior: Behavior;
68
+ componentsMapOffset: number;
68
69
  };
69
70
 
70
71
  type State = {
@@ -179,6 +180,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
179
180
  groupId,
180
181
  component,
181
182
  index,
183
+ componentsMapOffset,
182
184
  } = this.props;
183
185
 
184
186
  this.setScreenLayout(componentAnchorPointY, screenLayout);
@@ -193,13 +195,11 @@ export class TvOSCellComponent extends React.Component<Props, State> {
193
195
  const extraAnchorPointYOffset =
194
196
  screenLayout?.extraAnchorPointYOffset || 0;
195
197
 
196
- const marginTop = screenLayout?.screenMarginTop || 0;
197
-
198
198
  const totalOffset =
199
199
  headerOffset +
200
- (componentAnchorPointY || 0) +
201
- extraAnchorPointYOffset -
202
- marginTop;
200
+ (componentAnchorPointY || 0) +
201
+ extraAnchorPointYOffset -
202
+ componentsMapOffset || 0;
203
203
 
204
204
  mainOffsetUpdater?.(
205
205
  { tag: this.target },
@@ -247,7 +247,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
247
247
 
248
248
  const focusableId = R.join("-", [component?.id, id, index]);
249
249
 
250
- const handleFocus = (arg1: any, index: number) => {
250
+ const handleFocus = (arg1: any, index?: number) => {
251
251
  const focusFn = onFocus || noop;
252
252
  focusFn(arg1, index);
253
253
 
@@ -280,7 +280,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
280
280
  <View onLayout={this.onLayout} style={styles.container}>
281
281
  <Focusable
282
282
  id={focusableId}
283
- groupId={groupId || component?.id}
283
+ groupId={String(groupId || component?.id)}
284
284
  onFocus={handleFocus}
285
285
  onBlur={onBlur || this.onBlur}
286
286
  isParallaxDisabled={this.layout?.width > 1740}
@@ -292,20 +292,18 @@ export class TvOSCellComponent extends React.Component<Props, State> {
292
292
  style={baseCellStyles}
293
293
  isFocusable={isFocusable}
294
294
  >
295
- {(focused) => {
296
- return (
297
- <FocusableCell
298
- {...{
299
- index,
300
- CellRenderer,
301
- item,
302
- focused: this.props.focused || selectedCell || focused,
303
- scrollTo: this.scrollTo,
304
- behavior,
305
- }}
306
- />
307
- );
308
- }}
295
+ {(focused) => (
296
+ <FocusableCell
297
+ {...{
298
+ index,
299
+ CellRenderer,
300
+ item,
301
+ focused: !!(this.props.focused || selectedCell || focused),
302
+ scrollTo: this.scrollTo,
303
+ behavior,
304
+ }}
305
+ />
306
+ )}
309
307
  </Focusable>
310
308
  </View>
311
309
  );
@@ -11,6 +11,7 @@ import { ScreenScrollingContext } from "../../Contexts/ScreenScrollingContext";
11
11
 
12
12
  import { ScreenLayoutContextConsumer } from "../../Contexts/ScreenLayoutContext";
13
13
  import { createContext } from "@applicaster/zapp-react-native-utils/reactUtils/createContext";
14
+ import { withComponentsMapOffsetContextConsumer } from "../../Contexts/ComponentsMapOffsetContext";
14
15
 
15
16
  // TODO | Gallery QB | Extract this
16
17
  export const ScrollInterceptorContext = createContext(
@@ -30,5 +31,6 @@ export const Cell = R.compose(
30
31
  RiverOffsetContext.withConsumer,
31
32
  HorizontalScrollContext.withConsumer,
32
33
  withConsumer,
33
- ScreenLayoutContextConsumer
34
+ ScreenLayoutContextConsumer,
35
+ withComponentsMapOffsetContextConsumer
34
36
  )(Component);
@@ -9,7 +9,7 @@ import {
9
9
  focusManager,
10
10
  forceFocusableFocus,
11
11
  } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
12
- import { findNodeHandle } from "react-native";
12
+ import { findNodeHandle, ViewStyle } from "react-native";
13
13
 
14
14
  function noop() {}
15
15
 
@@ -35,6 +35,10 @@ type Props = {
35
35
  forceFocus?: boolean;
36
36
  initialFocus?: boolean;
37
37
  onLayout?: (e: any) => void;
38
+ willReceiveFocus: () => void;
39
+ hasReceivedFocus: () => void;
40
+ offsetUpdater: (arg1: string, arg2: number) => number;
41
+ style: ViewStyle;
38
42
  };
39
43
 
40
44
  export class Focusable extends BaseFocusable<Props> {
@@ -15,6 +15,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
15
15
 
16
16
  import { useParentFocus, useCheckItemIdsForUnique } from "./hooks";
17
17
  import { FocusableListItemWrapper } from "./FocusableListItemWrapper";
18
+ import { FocusableScrollView } from "../FocusableScrollView";
18
19
 
19
20
  const mapIndexed = R.addIndex(R.map);
20
21
 
@@ -54,6 +55,7 @@ export type Props<ItemT> = FlatListProps<ItemT> & {
54
55
  disableNextFocusUp?: boolean;
55
56
  disableNextFocusLeft?: boolean;
56
57
  disableNextFocusRight?: boolean;
58
+ useScrollView?: boolean;
57
59
  } & ParentFocus;
58
60
 
59
61
  function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
@@ -88,6 +90,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
88
90
  data = [],
89
91
  // eslint-disable-next-line unused-imports/no-unused-vars
90
92
  omitPropsPropagation = [],
93
+ useScrollView = false,
91
94
  } = props;
92
95
 
93
96
  useCheckItemIdsForUnique({ componentId: props.id, items: data });
@@ -273,6 +276,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
273
276
  "initialFocusDirection",
274
277
  "withStateMemory",
275
278
  "useSequentialLoading",
279
+ "useScrollView",
276
280
  ...omitPropsPropagation,
277
281
  ],
278
282
  R.__
@@ -295,15 +299,27 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
295
299
  return (
296
300
  // @ts-ignore
297
301
  <ChildrenFocusDeactivatorView flex={1}>
298
- <FlatList
299
- focusable={false}
300
- scrollEnabled={false}
301
- ref={ref}
302
- {...getFlatListProps(props)}
303
- renderItem={renderItem}
304
- onEndReached={onEndReached}
305
- initialNumToRender={initialNumToRender}
306
- />
302
+ {useScrollView ? (
303
+ <FocusableScrollView
304
+ ref={ref}
305
+ {...getFlatListProps(props)}
306
+ onEndReached={onEndReached}
307
+ initialNumToRender={initialNumToRender}
308
+ renderItem={renderItem}
309
+ focused={focused}
310
+ data={data}
311
+ />
312
+ ) : (
313
+ <FlatList
314
+ focusable={false}
315
+ scrollEnabled={false}
316
+ ref={ref}
317
+ {...getFlatListProps(props)}
318
+ renderItem={renderItem}
319
+ onEndReached={onEndReached}
320
+ initialNumToRender={initialNumToRender}
321
+ />
322
+ )}
307
323
  </ChildrenFocusDeactivatorView>
308
324
  );
309
325
  }
@@ -11,6 +11,13 @@ import {
11
11
  useInitialFocus,
12
12
  } from "@applicaster/zapp-react-native-utils/focusManager";
13
13
 
14
+ export type FocusableScrollViewRenderItem = (info: {
15
+ item: ZappUIComponent;
16
+ index: number;
17
+ focused: boolean;
18
+ parentFocus: ParentFocus;
19
+ }) => React.ReactElement;
20
+
14
21
  export type Props = ScrollViewProps & {
15
22
  id?: number | string;
16
23
  horizontal?: boolean;
@@ -32,17 +39,27 @@ export type Props = ScrollViewProps & {
32
39
  initialFocusDirection?: FocusManager.Android.FocusNavigationDirections;
33
40
  onAllComponentsLoaded?: () => void;
34
41
  omitPropsPropagation?: Array<keyof FlatListProps<any>>;
35
- renderItem: (info: {
36
- item: ZappUIComponent;
37
- index: number;
38
- focused: boolean;
39
- parentFocus: ParentFocus;
40
- }) => React.ReactElement;
42
+ renderItem: FocusableScrollViewRenderItem;
41
43
  } & ParentFocus;
42
44
 
43
45
  type State = boolean[];
44
46
  type Action = { index?: number; isFocusable: boolean; type?: string };
45
47
 
48
+ const unwrapArray = (maybeArray) =>
49
+ Array.isArray(maybeArray) ? maybeArray[0] : maybeArray;
50
+
51
+ function getEntry<T>(data: T | T[], index: unknown): T {
52
+ let entry;
53
+
54
+ if (R.isNil(index)) {
55
+ entry = unwrapArray(data);
56
+ } else if (typeof index === "number") {
57
+ entry = unwrapArray(data[index]);
58
+ }
59
+
60
+ return entry;
61
+ }
62
+
46
63
  const focusableStateReducer = (
47
64
  state: State,
48
65
  { index = null, isFocusable, type = null }: Action
@@ -73,7 +90,7 @@ const extendScrollViewRef = (_ref, childCompsMeasurementsMap) => {
73
90
  };
74
91
 
75
92
  _ref.scrollToIndex = (params) => {
76
- const { index, viewOffset } = params;
93
+ const { index, viewOffset = 0 } = params;
77
94
 
78
95
  const itemByIndex = R.find(R.propEq("index", index))(
79
96
  R.values(childCompsMeasurementsMap)
@@ -129,8 +146,11 @@ function FocusableScrollViewComponent(props: Props, ref) {
129
146
  );
130
147
 
131
148
  const getFocusableEntryId = React.useCallback(
132
- (_entry: ZappEntry, index?: number) => {
133
- const entry = R.isNil(index) ? _entry : data[index];
149
+ (_entry: ZappEntry | null, index?: number) => {
150
+ const entry: { id?: string } = getEntry(
151
+ R.isNil(index) ? _entry : data,
152
+ index
153
+ );
134
154
 
135
155
  return entry ? `${props.id}--${entry?.id}` : undefined;
136
156
  },
@@ -273,11 +293,18 @@ function FocusableScrollViewComponent(props: Props, ref) {
273
293
  const renderItem = React.useCallback(
274
294
  (item, index) => {
275
295
  const renderArgs = { item, index };
276
- const id = `${props.id}--${renderArgs?.item?.id}`;
277
- const nextFocus = getNextFocus(renderArgs?.index);
296
+
297
+ const id = getFocusableEntryId(
298
+ Array.isArray(item) ? item[0] : item,
299
+ index
300
+ );
301
+
302
+ const nextFocus = getNextFocus(index);
278
303
 
279
304
  const onItemLayout = (event) => {
280
- childCompsMeasurementsMap.current[item.id] = {
305
+ childCompsMeasurementsMap.current[
306
+ Array.isArray(item) ? index : item.id
307
+ ] = {
281
308
  index,
282
309
  layout: event.nativeEvent.layout,
283
310
  };
@@ -1,7 +1,5 @@
1
1
  import * as React from "react";
2
2
  import { View, StyleSheet } from "react-native";
3
- import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext";
4
- import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
5
3
  import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
6
4
  import { useScreenConfiguration } from "../../River/useScreenConfiguration";
7
5
 
@@ -12,12 +10,15 @@ type Props = {
12
10
  };
13
11
 
14
12
  const styles = StyleSheet.create({
15
- container: { position: "absolute", top: 0, zIndex: 10, width: 1920 },
13
+ container: {
14
+ position: "absolute",
15
+ top: 0,
16
+ zIndex: 10,
17
+ width: 1920,
18
+ },
16
19
  });
17
20
 
18
21
  export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
19
- const screenLayout = React.useContext(ScreenLayoutContext);
20
- const screenMarginTop = screenLayout?.screenMarginTop || 0;
21
22
  const screen = useCurrentScreenData();
22
23
  const screenConfig = useScreenConfiguration(screen?.id);
23
24
 
@@ -26,9 +27,9 @@ export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
26
27
  // limits the height of the focusable container of the TopMenuBarTV component
27
28
  // to prevent it from being overlapped by the screen content,
28
29
  // as it makes TopMenuBarTV unfocusable on tvOS
29
- maxHeight: ifEmptyUseFallback(screenConfig?.marginTop, screenMarginTop),
30
+ maxHeight: 1,
30
31
  }),
31
- [screenLayout, screenConfig]
32
+ [screenConfig]
32
33
  );
33
34
 
34
35
  React.useEffect(() => {
@@ -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);
@@ -81,13 +81,6 @@ const mockScreenData = {
81
81
  id: "A1234",
82
82
  };
83
83
 
84
- jest.mock("@applicaster/zapp-react-native-redux/AppStore", () => ({
85
- appStore: {
86
- get: jest.fn((prop) => mockStore[prop]),
87
- getState: jest.fn(),
88
- },
89
- }));
90
-
91
84
  jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
92
85
  useIsRTL: jest.fn(() => mock_rtl_flag),
93
86
  }));
@@ -160,13 +153,7 @@ const plugins = [];
160
153
  const navigation = {};
161
154
 
162
155
  const props = { components, cellStyles, riverComponents, navigation };
163
-
164
- const store = mockStore({
165
- components,
166
- cellStyles,
167
- plugins,
168
- getState: jest.fn(),
169
- });
156
+ const store = mockStore({ components, cellStyles, plugins });
170
157
 
171
158
  jest.useFakeTimers();
172
159
 
@@ -10,8 +10,7 @@ import { Edge, SafeAreaView } from "react-native-safe-area-context";
10
10
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
11
11
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
12
12
  import { PlayerDetails } from "./PlayerDetails";
13
- import { playerDimensionsHack } from "./utils";
14
- import { useDelayedPlayerDetails } from "./hooks";
13
+ import { playerDimesionsHack } from "./utils";
15
14
 
16
15
  import {
17
16
  AnimatedScrollModal,
@@ -122,6 +121,34 @@ const getTabletWidth = (
122
121
  return Number(width) - sidebarWidth;
123
122
  };
124
123
 
124
+ const showDetails = (
125
+ isMobile: boolean,
126
+ docked: boolean,
127
+ isInlineModal,
128
+ pip
129
+ ): boolean => {
130
+ if (pip) {
131
+ return false;
132
+ }
133
+
134
+ if (!isInlineModal) {
135
+ return false;
136
+ }
137
+
138
+ // for mobile we always show details. Mounting of it very heavy operation.
139
+ if (isMobile) {
140
+ return true;
141
+ }
142
+
143
+ // workaround for tablets we need to mount/unmount in order to avoid PlayerDetails content dissappearing
144
+ // FIXME - find out the reason of dissapearing of content
145
+ if (docked) {
146
+ return false;
147
+ }
148
+
149
+ return true;
150
+ };
151
+
125
152
  const PlayerWrapperComponent = (props: Props) => {
126
153
  const {
127
154
  entry,
@@ -140,15 +167,7 @@ const PlayerWrapperComponent = (props: Props) => {
140
167
 
141
168
  const isInlineModal = inline && isModal;
142
169
 
143
- // Mounting the PlayerDetails component is a resource-intensive process.
144
- // Therefore, for performance reasons, we mount it with a delay to make the rotation process as smooth as possible.
145
- // The flow is as follows: the rotation occurs first, and then, after a short delay, we mount the PlayerDetails component.
146
- // This helps to avoid blocking the rotation and any animations related to the rotation.
147
- const isShowPlayerDetails = useDelayedPlayerDetails({
148
- isInline: isInlineModal,
149
- isDocked: docked,
150
- isPip: pip,
151
- });
170
+ // const style = getStyles(baseStyle, !isTablet, isInlineModal, pip);
152
171
 
153
172
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
154
173
 
@@ -184,8 +203,8 @@ const PlayerWrapperComponent = (props: Props) => {
184
203
  const WrapperView = React.useMemo(() => (isTV() ? View : SafeAreaView), []);
185
204
 
186
205
  const childrenStyles = React.useMemo(
187
- () => ({ ...playerDimensions, ...playerDimensionsHack }),
188
- [containerDimensions, playerDimensionsHack]
206
+ () => ({ ...playerDimensions, ...playerDimesionsHack }),
207
+ [containerDimensions, playerDimesionsHack]
189
208
  );
190
209
 
191
210
  return (
@@ -194,7 +213,7 @@ const PlayerWrapperComponent = (props: Props) => {
194
213
  style={[
195
214
  safeAreaStyles(configuration, isTablet),
196
215
  style,
197
- playerDimensionsHack,
216
+ playerDimesionsHack,
198
217
  ]}
199
218
  >
200
219
  <AnimationComponent
@@ -208,7 +227,7 @@ const PlayerWrapperComponent = (props: Props) => {
208
227
  defaultStyles.playerContainer,
209
228
  containerDimensions,
210
229
  containerStyle,
211
- playerDimensionsHack,
230
+ playerDimesionsHack,
212
231
  ]}
213
232
  >
214
233
  <AnimationComponent
@@ -227,7 +246,7 @@ const PlayerWrapperComponent = (props: Props) => {
227
246
  </View>
228
247
 
229
248
  <AnimatedScrollModal>
230
- {isShowPlayerDetails && (
249
+ {showDetails(!isTablet, docked, isInlineModal, pip) && (
231
250
  <AnimationComponent
232
251
  animationType={ComponentAnimationType.componentFade}
233
252
  style={defaultStyles.flex}
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
- import { equals } from "ramda";
3
- import { StyleSheet, StatusBar } from "react-native";
2
+ import * as R from "ramda";
3
+ import { StyleSheet, View, StatusBar } from "react-native";
4
4
 
5
5
  import { HandlePlayable } from "@applicaster/zapp-react-native-ui-components/Components/HandlePlayable";
6
6
  import {
@@ -17,20 +17,17 @@ import {
17
17
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
18
18
 
19
19
  import { withModalNavigationContextProvider } from "../../Contexts/ModalNavigationContext";
20
- import {
21
- useModalSize,
22
- useBackgroundColor,
23
- useInitialPlayerState,
24
- } from "./hooks";
25
-
20
+ import { useModalSize } from "./hooks/useModalSize";
21
+ import { useBackgroundColor } from "./hooks/useBackgroundColor";
22
+ import { useInitialPlayerState } from "./hooks/useInitialPlayerState";
26
23
  import { APP_EVENTS } from "@applicaster/zapp-react-native-utils/appUtils/events";
24
+ import { Spinner } from "../Spinner";
27
25
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
28
26
  import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
29
27
  import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
30
28
  import { requiresAuthentication } from "@applicaster/zapp-react-native-utils/configurationUtils";
31
29
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
32
30
  import { ScreenContextProvider } from "../../Contexts/ScreenContext";
33
- import { OpaqueLayer } from "./OpaqueLayer";
34
31
 
35
32
  import { AnimatedPlayerModalWrapper } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
36
33
 
@@ -42,6 +39,17 @@ const styles = StyleSheet.create({
42
39
  bottom: 0,
43
40
  position: "absolute",
44
41
  },
42
+ // eslint-disable-next-line react-native/no-color-literals
43
+ loaderContainer: {
44
+ top: 0,
45
+ left: 0,
46
+ right: 0,
47
+ bottom: 0,
48
+ position: "absolute",
49
+ alignItems: "center",
50
+ justifyContent: "center",
51
+ backgroundColor: "rgba(64,64,64,.5)",
52
+ },
45
53
  });
46
54
 
47
55
  const VideoModalComponent = () => {
@@ -92,7 +100,7 @@ const VideoModalComponent = () => {
92
100
 
93
101
  const onHooksSuccess = ({ payload }) => {
94
102
  // set new modified entry
95
- if (!equals(payload, item)) {
103
+ if (!R.equals(payload, item)) {
96
104
  onVideoModalHookSuccessAnalyticsEvent();
97
105
  setVideoModalItem(payload);
98
106
  }
@@ -128,10 +136,7 @@ const VideoModalComponent = () => {
128
136
 
129
137
  <PathnameContext.Provider value={pathname}>
130
138
  <ScreenContextProvider pathname={pathname}>
131
- {/* Hide content underneath when we switch to next video in fullscreen mode */}
132
- {mode === "FULLSCREEN" && <OpaqueLayer />}
133
-
134
- {itemIdHooksFinished === item?.id && (
139
+ {itemIdHooksFinished === item?.id ? (
135
140
  <AnimatedPlayerModalWrapper
136
141
  style={[
137
142
  styles.container,
@@ -148,6 +153,10 @@ const VideoModalComponent = () => {
148
153
  mode={mode}
149
154
  />
150
155
  </AnimatedPlayerModalWrapper>
156
+ ) : (
157
+ <View style={styles.loaderContainer}>
158
+ <Spinner />
159
+ </View>
151
160
  )}
152
161
  </ScreenContextProvider>
153
162
  </PathnameContext.Provider>
@@ -62,7 +62,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
62
62
  })),
63
63
  }));
64
64
 
65
- jest.mock("../utils", () => ({ playerDimensionsHack: {} }));
65
+ jest.mock("../utils", () => ({ playerDimesionsHack: {} }));
66
66
 
67
67
  const { PlayerWrapper } = require("../PlayerWrapper");
68
68
 
@@ -71,6 +71,36 @@ exports[`PlayerWrapper renders inline 1`] = `
71
71
  }
72
72
  testID="test-player-container"
73
73
  />
74
+ <View
75
+ animationType="componentFade"
76
+ style={
77
+ {
78
+ "flex": 1,
79
+ }
80
+ }
81
+ >
82
+ <View
83
+ configuration={
84
+ {
85
+ "tablet_landscape_player_container_background_color": "red",
86
+ "tablet_landscape_sidebar_width": "35%",
87
+ }
88
+ }
89
+ entry={
90
+ {
91
+ "id": "test",
92
+ }
93
+ }
94
+ isTablet={false}
95
+ isTabletLandscape={false}
96
+ style={
97
+ {
98
+ "flex": 1,
99
+ "paddingTop": 20,
100
+ }
101
+ }
102
+ />
103
+ </View>
74
104
  </View>
75
105
  </RNCSafeAreaView>
76
106
  </RNCSafeAreaProvider>
@@ -147,6 +177,36 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
147
177
  }
148
178
  testID="test-player-container"
149
179
  />
180
+ <View
181
+ animationType="componentFade"
182
+ style={
183
+ {
184
+ "flex": 1,
185
+ }
186
+ }
187
+ >
188
+ <View
189
+ configuration={
190
+ {
191
+ "tablet_landscape_player_container_background_color": "red",
192
+ "tablet_landscape_sidebar_width": "35%",
193
+ }
194
+ }
195
+ entry={
196
+ {
197
+ "id": "test",
198
+ }
199
+ }
200
+ isTablet={false}
201
+ isTabletLandscape={false}
202
+ style={
203
+ {
204
+ "flex": 1,
205
+ "paddingTop": 20,
206
+ }
207
+ }
208
+ />
209
+ </View>
150
210
  </View>
151
211
  </RNCSafeAreaView>
152
212
  </RNCSafeAreaProvider>
@@ -239,6 +299,36 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
239
299
  }
240
300
  />
241
301
  </View>
302
+ <View
303
+ animationType="componentFade"
304
+ style={
305
+ {
306
+ "flex": 1,
307
+ }
308
+ }
309
+ >
310
+ <View
311
+ configuration={
312
+ {
313
+ "tablet_landscape_player_container_background_color": "red",
314
+ "tablet_landscape_sidebar_width": "35%",
315
+ }
316
+ }
317
+ entry={
318
+ {
319
+ "id": "test",
320
+ }
321
+ }
322
+ isTablet={true}
323
+ isTabletLandscape={true}
324
+ style={
325
+ {
326
+ "flex": 1,
327
+ "paddingTop": 20,
328
+ }
329
+ }
330
+ />
331
+ </View>
242
332
  </View>
243
333
  </RNCSafeAreaView>
244
334
  </RNCSafeAreaProvider>
@@ -35,36 +35,3 @@ export const orientationWasChangedFromPortraitToLandscape = ({
35
35
  isOrientationLandscape(toOrientation)
36
36
  );
37
37
  };
38
-
39
- export const showDetails = ({
40
- isMobile,
41
- isInline,
42
- isDocked,
43
- isPip,
44
- }: {
45
- isMobile: boolean;
46
- isInline: boolean;
47
- isDocked: boolean;
48
- isPip: boolean;
49
- }): boolean => {
50
- if (isPip) {
51
- return false;
52
- }
53
-
54
- if (isDocked) {
55
- return false;
56
- }
57
-
58
- // for mobile with inline mode(rotation is portrait) we always show details.
59
- if (isMobile && isInline) {
60
- return true;
61
- }
62
-
63
- // for mobile with landscape rotation(player is fullscreen) we always hide details. Mounting of it is very heavy operation.
64
- if (isMobile && !isInline) {
65
- return false;
66
- }
67
-
68
- // for tablets we always show details
69
- return true;
70
- };
@@ -52,7 +52,7 @@ const fullSize = {
52
52
  height: "100%",
53
53
  };
54
54
 
55
- export const playerDimensionsHack = platformSelect({
55
+ export const playerDimesionsHack = platformSelect({
56
56
  android_tv: fullSize,
57
57
  amazon: fullSize,
58
58
  lg_tv: fullSize,
@@ -0,0 +1,46 @@
1
+ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
2
+ import React, { PropsWithChildren } from "react";
3
+
4
+ export const ComponentsMapOffsetContext = React.createContext({
5
+ setComponentsMapOffset: (_offset: number) => void 0,
6
+ componentsMapOffset: 0,
7
+ });
8
+
9
+ export const ComponentsMapOffsetContextProvider = ({
10
+ children,
11
+ }: PropsWithChildren<{}>) => {
12
+ const theme = useTheme<BaseThemePropertiesTV>();
13
+
14
+ const [componentsMapOffset, setComponentsMapOffset] = React.useState(
15
+ theme?.screen_margin_top
16
+ );
17
+
18
+ const contextValue = {
19
+ componentsMapOffset,
20
+ setComponentsMapOffset,
21
+ };
22
+
23
+ return (
24
+ <ComponentsMapOffsetContext.Provider value={contextValue}>
25
+ {children}
26
+ </ComponentsMapOffsetContext.Provider>
27
+ );
28
+ };
29
+
30
+ export const withComponentsMapOffsetContext = (Component: any) =>
31
+ function ComponentsMapOffsetContextProviderWrapper(props: {}) {
32
+ return (
33
+ <ComponentsMapOffsetContextProvider>
34
+ <Component {...props} />
35
+ </ComponentsMapOffsetContextProvider>
36
+ );
37
+ };
38
+
39
+ export const withComponentsMapOffsetContextConsumer = (Component: any) =>
40
+ function ComponentsMapOffsetContextConsumerWrapper(props: {}) {
41
+ const { componentsMapOffset } = React.useContext(
42
+ ComponentsMapOffsetContext
43
+ );
44
+
45
+ return <Component {...props} componentsMapOffset={componentsMapOffset} />;
46
+ };
@@ -1,12 +1,10 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
  /// <reference types="@applicaster/zapp-react-native-ui-components" />
3
3
  import React, { useEffect, useMemo } from "react";
4
- import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
5
-
6
4
  import * as R from "ramda";
7
5
  import { Platform } from "react-native";
8
6
  import Url from "url";
9
- import { ENDPOINT_TAGS } from "@applicaster/zapp-react-native-utils/types";
7
+
10
8
  import { favoritesListener } from "@applicaster/zapp-react-native-bridge/Favorites";
11
9
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
12
10
  import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
@@ -21,12 +19,6 @@ import { ZappPipesSearchContext } from "@applicaster/zapp-react-native-ui-compon
21
19
  import { useScreenContext } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
22
20
 
23
21
  import { isVerticalListOrGrid } from "./utils";
24
- import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
25
- import {
26
- findEndpointForURL,
27
- HTTP_METHODS,
28
- } from "@applicaster/zapp-pipes-v2-client";
29
- import { getNamespaceAndKey } from "@applicaster/zapp-react-native-utils/appUtils/contextKeysManager/utils";
30
22
 
31
23
  type Props = {
32
24
  component: ZappUIComponent;
@@ -299,28 +291,6 @@ export function zappPipesDataConnector(
299
291
  if (addListener) {
300
292
  return addListener(reloadData);
301
293
  }
302
- } else {
303
- const pipesEndpoints = appStore.get("pipesEndpoints");
304
-
305
- const endpointURL = findEndpointForURL(
306
- dataSourceUrl,
307
- pipesEndpoints,
308
- HTTP_METHODS.GET
309
- );
310
-
311
- const endpoint = pipesEndpoints?.[endpointURL];
312
-
313
- if (endpoint?.tags?.includes(ENDPOINT_TAGS.observe_storage)) {
314
- const subscriptions: (() => void)[] = endpoint.context_obj.map(
315
- (data: Record<string, any>) => {
316
- const { namespace, key } = getNamespaceAndKey(data.key);
317
-
318
- return localStorage.addListener({ key, namespace }, reloadData);
319
- }
320
- );
321
-
322
- return () => subscriptions.forEach((listener) => listener());
323
- }
324
294
  }
325
295
  }, [dataSourceUrl, reloadData]);
326
296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "13.0.0-alpha.3528549047",
3
+ "version": "13.0.0-alpha.3592913150",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -34,10 +34,10 @@
34
34
  "redux-mock-store": "^1.5.3"
35
35
  },
36
36
  "dependencies": {
37
- "@applicaster/applicaster-types": "13.0.0-alpha.3528549047",
38
- "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.3528549047",
39
- "@applicaster/zapp-react-native-redux": "13.0.0-alpha.3528549047",
40
- "@applicaster/zapp-react-native-utils": "13.0.0-alpha.3528549047",
37
+ "@applicaster/applicaster-types": "13.0.0-alpha.3592913150",
38
+ "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.3592913150",
39
+ "@applicaster/zapp-react-native-redux": "13.0.0-alpha.3592913150",
40
+ "@applicaster/zapp-react-native-utils": "13.0.0-alpha.3592913150",
41
41
  "promise": "^8.3.0",
42
42
  "react-router-native": "^5.1.2",
43
43
  "url": "^0.11.0",
@@ -1,33 +0,0 @@
1
- import * as React from "react";
2
- import { StyleSheet, View } from "react-native";
3
-
4
- import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
5
-
6
- import { Spinner } from "../Spinner";
7
-
8
- const styles = StyleSheet.create({
9
- container: {
10
- ...StyleSheet.absoluteFillObject,
11
- alignItems: "center",
12
- justifyContent: "center",
13
- },
14
- });
15
-
16
- export const OpaqueLayer = () => {
17
- const theme = useTheme();
18
-
19
- return (
20
- <View
21
- style={[
22
- styles.container,
23
- {
24
- // we assume that it's non-transparent and we could show spinner always until it will be covered by player
25
- // this spinner hides all content under modal
26
- backgroundColor: theme?.app_background_color,
27
- },
28
- ]}
29
- >
30
- <Spinner />
31
- </View>
32
- );
33
- };
@@ -1,89 +0,0 @@
1
- import { renderHook } from "@testing-library/react-hooks";
2
- import { useDelayedPlayerDetails } from "../useDelayedPlayerDetails";
3
- import { withTimeout$ } from "@applicaster/zapp-react-native-utils/idleUtils";
4
- import { showDetails } from "../utils";
5
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
6
-
7
- jest.mock("@applicaster/zapp-react-native-utils/idleUtils", () => ({
8
- withTimeout$: jest.fn(),
9
- }));
10
-
11
- jest.mock("../utils", () => ({
12
- showDetails: jest.fn(),
13
- }));
14
-
15
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
16
- useIsTablet: jest.fn(),
17
- }));
18
-
19
- describe("useDelayedPlayerDetails", () => {
20
- beforeEach(() => {
21
- jest.clearAllMocks();
22
- });
23
-
24
- it("should return false initially", () => {
25
- (withTimeout$ as jest.Mock).mockReturnValue({
26
- subscribe: jest.fn().mockReturnValue({ unsubscribe: jest.fn() }),
27
- });
28
-
29
- const { result } = renderHook(() =>
30
- useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
31
- );
32
-
33
- expect(result.current).toBe(false);
34
- });
35
-
36
- it("should return true if showDetails returns true", () => {
37
- (withTimeout$ as jest.Mock).mockReturnValue({
38
- subscribe: (callback) => {
39
- callback.next();
40
-
41
- return { unsubscribe: jest.fn() };
42
- },
43
- });
44
-
45
- (showDetails as jest.Mock).mockReturnValue(true);
46
- (useIsTablet as jest.Mock).mockReturnValue(false);
47
-
48
- const { result } = renderHook(() =>
49
- useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
50
- );
51
-
52
- expect(result.current).toBe(true);
53
- });
54
-
55
- it("should return false if showDetails returns false", () => {
56
- (withTimeout$ as jest.Mock).mockReturnValue({
57
- subscribe: (callback) => {
58
- callback.next();
59
-
60
- return { unsubscribe: jest.fn() };
61
- },
62
- });
63
-
64
- (showDetails as jest.Mock).mockReturnValue(false);
65
- (useIsTablet as jest.Mock).mockReturnValue(false);
66
-
67
- const { result } = renderHook(() =>
68
- useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
69
- );
70
-
71
- expect(result.current).toBe(false);
72
- });
73
-
74
- it("should unsubscribe on unmount", () => {
75
- const unsubscribeMock = jest.fn();
76
-
77
- (withTimeout$ as jest.Mock).mockReturnValue({
78
- subscribe: jest.fn().mockReturnValue({ unsubscribe: unsubscribeMock }),
79
- });
80
-
81
- const { unmount } = renderHook(() =>
82
- useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
83
- );
84
-
85
- unmount();
86
-
87
- expect(unsubscribeMock).toHaveBeenCalled();
88
- });
89
- });
@@ -1,7 +0,0 @@
1
- export { useBackgroundColor } from "./useBackgroundColor";
2
-
3
- export { useDelayedPlayerDetails } from "./useDelayedPlayerDetails";
4
-
5
- export { useInitialPlayerState } from "./useInitialPlayerState";
6
-
7
- export { useModalSize } from "./useModalSize";
@@ -1,49 +0,0 @@
1
- import * as React from "react";
2
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
3
- import { withTimeout$ } from "@applicaster/zapp-react-native-utils/idleUtils";
4
-
5
- import { showDetails } from "./utils";
6
-
7
- const TIMEOUT = 100; // ms
8
-
9
- type Props = { isInline: boolean; isDocked: boolean; isPip: boolean };
10
-
11
- /**
12
- * Custom hook to determine whether to show player details with a delay.
13
- *
14
- * @param {Object} params - The parameters object.
15
- * @param {boolean} params.isInline - Indicates if the player is inline.
16
- * @param {boolean} params.isDocked - Indicates if the player is docked.
17
- * @param {boolean} params.isPip - Indicates if the player is in PIP mode.
18
- * @returns {boolean} - Returns true if player details should be shown, otherwise false.
19
- */
20
- export const useDelayedPlayerDetails = ({
21
- isInline,
22
- isDocked,
23
- isPip,
24
- }: Props): boolean => {
25
- const [shouldShowDetails, setShouldShowDetails] = React.useState(false);
26
-
27
- const isTablet = useIsTablet();
28
-
29
- React.useEffect(() => {
30
- const subscription = withTimeout$(TIMEOUT).subscribe({
31
- next: () => {
32
- setShouldShowDetails(() => {
33
- return showDetails({
34
- isMobile: !isTablet,
35
- isInline,
36
- isDocked,
37
- isPip,
38
- });
39
- });
40
- },
41
- });
42
-
43
- return () => {
44
- subscription.unsubscribe();
45
- };
46
- }, [isDocked, isTablet, isInline, isPip]);
47
-
48
- return shouldShowDetails;
49
- };
@@ -1,91 +0,0 @@
1
- import { showDetails } from "..";
2
-
3
- describe("showDetails", () => {
4
- it("should return false if isPip is true", () => {
5
- const result = showDetails({
6
- isMobile: true,
7
- isInline: true,
8
- isDocked: false,
9
- isPip: true,
10
- });
11
-
12
- expect(result).toBe(false);
13
- });
14
-
15
- it("should return false if isDocked is true", () => {
16
- const result = showDetails({
17
- isMobile: true,
18
- isInline: true,
19
- isDocked: true,
20
- isPip: false,
21
- });
22
-
23
- expect(result).toBe(false);
24
- });
25
-
26
- it("should return true if isMobile is true and isInline is true", () => {
27
- const result = showDetails({
28
- isMobile: true,
29
- isInline: true,
30
- isDocked: false,
31
- isPip: false,
32
- });
33
-
34
- expect(result).toBe(true);
35
- });
36
-
37
- it("should return false if isMobile is true and isInline is false", () => {
38
- const result = showDetails({
39
- isMobile: true,
40
- isInline: false,
41
- isDocked: false,
42
- isPip: false,
43
- });
44
-
45
- expect(result).toBe(false);
46
- });
47
-
48
- it("should return true if isMobile is false", () => {
49
- const result = showDetails({
50
- isMobile: false,
51
- isInline: true,
52
- isDocked: false,
53
- isPip: false,
54
- });
55
-
56
- expect(result).toBe(true);
57
- });
58
-
59
- it("should return true if isMobile is false and isInline is false", () => {
60
- const result = showDetails({
61
- isMobile: false,
62
- isInline: false,
63
- isDocked: false,
64
- isPip: false,
65
- });
66
-
67
- expect(result).toBe(true);
68
- });
69
-
70
- it("should return false if all properties are false except isMobile", () => {
71
- const result = showDetails({
72
- isMobile: true,
73
- isInline: false,
74
- isDocked: false,
75
- isPip: false,
76
- });
77
-
78
- expect(result).toBe(false);
79
- });
80
-
81
- it("should return true if all properties are false except isInline", () => {
82
- const result = showDetails({
83
- isMobile: false,
84
- isInline: true,
85
- isDocked: false,
86
- isPip: false,
87
- });
88
-
89
- expect(result).toBe(true);
90
- });
91
- });