@applicaster/zapp-react-native-ui-components 13.0.0-alpha.6179233127 → 13.0.0-alpha.6234681660

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 (32) hide show
  1. package/Components/Cell/Cell.tsx +3 -13
  2. package/Components/Cell/CellWithFocusable.tsx +18 -14
  3. package/Components/Cell/CellWrapper.ts +5 -0
  4. package/Components/Cell/styles.ts +17 -0
  5. package/Components/ErrorScreen/index.tsx +8 -0
  6. package/Components/FocusableCell/index.tsx +1 -1
  7. package/Components/HandlePlayable/HandlePlayable.tsx +14 -27
  8. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +4 -3
  9. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
  10. package/Components/MasterCell/utils/behaviorProvider.ts +4 -1
  11. package/Components/MasterCell/utils/index.ts +6 -6
  12. package/Components/ModalComponent/Button/assets.ts +1 -1
  13. package/Components/OfflineHandler/utils/index.ts +1 -1
  14. package/Components/River/ComponentsMap/ComponentsMap.tsx +3 -0
  15. package/Components/Screen/TV/index.web.tsx +5 -6
  16. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +3 -1
  17. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +17 -9
  18. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
  19. package/Components/VideoModal/ModalAnimation/const.ts +5 -0
  20. package/Components/VideoModal/ModalAnimation/index.ts +2 -0
  21. package/Components/VideoModal/ModalAnimation/utils.ts +36 -0
  22. package/Components/VideoModal/VideoModal.tsx +2 -2
  23. package/Decorators/RiverResolver/index.tsx +5 -7
  24. package/Decorators/ZappPipesDataConnector/index.tsx +2 -1
  25. package/package.json +5 -6
  26. package/.babelrc +0 -8
  27. package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
  28. package/Components/Cell/CellStyles/Hero/index.js +0 -111
  29. package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
  30. package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
  31. package/Components/Cell/CellStyles/colors.js +0 -40
  32. package/Components/Cell/CellStyles/index.js +0 -15
@@ -12,6 +12,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
12
12
  import { CellWithFocusable } from "./CellWithFocusable";
13
13
  import { BaseFocusable } from "../BaseFocusable";
14
14
  import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
15
+ import { styles } from "./styles";
15
16
 
16
17
  type Props = {
17
18
  item: ZappEntry;
@@ -68,17 +69,6 @@ type State = {
68
69
  hasFocusableInside: boolean;
69
70
  };
70
71
 
71
- const baseCellStyles = {
72
- height: "100%",
73
- display: "flex",
74
- flex: 1,
75
- } as const;
76
-
77
- const touchableStyles = {
78
- flex: 1,
79
- height: "100%",
80
- } as const;
81
-
82
72
  export class CellComponent extends React.Component<Props, State> {
83
73
  constructor(props) {
84
74
  super(props);
@@ -252,7 +242,7 @@ export class CellComponent extends React.Component<Props, State> {
252
242
  <View
253
243
  testID={`${component?.id}-${id}`}
254
244
  accessible={false}
255
- style={touchableStyles}
245
+ style={styles.touchableCell}
256
246
  >
257
247
  <Focusable
258
248
  id={focusableId}
@@ -264,7 +254,7 @@ export class CellComponent extends React.Component<Props, State> {
264
254
  hasReceivedFocus={hasReceivedFocus || this.hasReceivedFocus}
265
255
  preferredFocus={preferredFocus}
266
256
  offsetUpdater={offsetUpdater}
267
- style={baseCellStyles}
257
+ style={styles.baseCell}
268
258
  isFocusable={isFocusable}
269
259
  skipFocusManagerRegistration={skipFocusManagerRegistration}
270
260
  >
@@ -5,6 +5,8 @@ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/
5
5
 
6
6
  import { useCellState } from "../MasterCell/utils";
7
7
  import { FocusableGroup } from "../FocusableGroup";
8
+ import { CellWrapper } from "./CellWrapper";
9
+ import { styles } from "./styles";
8
10
 
9
11
  type Props = {
10
12
  item: ZappEntry;
@@ -40,7 +42,7 @@ export function CellWithFocusable(props: Props) {
40
42
  const [isFocused, setIsFocused] = React.useState(false);
41
43
 
42
44
  const state = useCellState({
43
- id: item.id,
45
+ item,
44
46
  behavior,
45
47
  focused: isFocused || toBooleanWithDefaultFalse(focused),
46
48
  });
@@ -88,19 +90,21 @@ export function CellWithFocusable(props: Props) {
88
90
  onBlur={onGroupBlur}
89
91
  skipFocusManagerRegistration={skipFocusManagerRegistration}
90
92
  >
91
- <CellRenderer
92
- testID={"cell-with-focusable-cell-renderer"}
93
- item={item}
94
- groupId={`focusable-cell-wrapper-${id}`}
95
- onToggleFocus={handleToggleFocus}
96
- state={state}
97
- prefixId={id}
98
- focusedButtonId={focusedButtonId}
99
- preferredFocus={true}
100
- skipFocusManagerRegistration={skipFocusManagerRegistration}
101
- isFocusable={isFocusable}
102
- focused={focused}
103
- />
93
+ <CellWrapper style={styles.cellWrapper}>
94
+ <CellRenderer
95
+ testID={"cell-with-focusable-cell-renderer"}
96
+ item={item}
97
+ groupId={`focusable-cell-wrapper-${id}`}
98
+ onToggleFocus={handleToggleFocus}
99
+ state={state}
100
+ prefixId={id}
101
+ focusedButtonId={focusedButtonId}
102
+ preferredFocus={true}
103
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
104
+ isFocusable={isFocusable}
105
+ focused={focused}
106
+ />
107
+ </CellWrapper>
104
108
  </FocusableGroup>
105
109
  );
106
110
  }
@@ -0,0 +1,5 @@
1
+ import { isTvOSPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
2
+ import React from "react";
3
+ import { View } from "react-native";
4
+
5
+ export const CellWrapper = isTvOSPlatform() ? View : React.Fragment;
@@ -0,0 +1,17 @@
1
+ import { StyleSheet } from "react-native";
2
+
3
+ export const styles = StyleSheet.create({
4
+ cellWrapper: {
5
+ flex: 0,
6
+ height: "100%",
7
+ },
8
+ baseCell: {
9
+ height: "100%",
10
+ display: "flex",
11
+ flex: 1,
12
+ },
13
+ touchableCell: {
14
+ flex: 1,
15
+ height: "100%",
16
+ },
17
+ });
@@ -105,6 +105,11 @@ const defaultProps = {
105
105
  alignItems: "center",
106
106
  justifyContent: "center",
107
107
  },
108
+ focusedButton: {
109
+ backgroundColor: "#3a3a3a",
110
+ borderColor: "#ffffff",
111
+ borderWidth: 2,
112
+ },
108
113
  buttonText: {
109
114
  fontFamily: platformSelect({
110
115
  ios: "SFProText-Medium",
@@ -116,6 +121,9 @@ const defaultProps = {
116
121
  color: "rgba(255, 255, 255, 1)",
117
122
  textTransform: "uppercase",
118
123
  },
124
+ focusedText: {
125
+ color: "#ffffff",
126
+ },
119
127
  },
120
128
  };
121
129
 
@@ -23,7 +23,7 @@ export function FocusableCell(props: Props) {
23
23
  behavior,
24
24
  } = props;
25
25
 
26
- const state = useCellState({ id: item.id, behavior, focused });
26
+ const state = useCellState({ item, behavior, focused });
27
27
 
28
28
  React.useEffect(() => {
29
29
  if (focused && scrollTo && !isAndroid) {
@@ -1,14 +1,14 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { ViewStyle } from "react-native";
4
3
  import {
5
4
  findPluginByType,
6
5
  findPluginByIdentifier,
7
6
  } from "@applicaster/zapp-react-native-utils/pluginUtils";
8
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
9
7
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
10
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
11
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
8
+ import {
9
+ useDimensions,
10
+ useNavigation,
11
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
12
12
 
13
13
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
14
14
  import { PlayerContainer } from "../PlayerContainer";
@@ -78,12 +78,6 @@ const getPlayer = (
78
78
  return getPlayerWithModuleProperties(PlayerModule);
79
79
  };
80
80
 
81
- const dimensionsContext: "window" | "screen" = platformSelect({
82
- android_tv: "window",
83
- amazon: "window",
84
- default: "screen",
85
- });
86
-
87
81
  type PlayableComponent = {
88
82
  Component: React.ComponentType<any>;
89
83
  };
@@ -91,16 +85,11 @@ type PlayableComponent = {
91
85
  export function HandlePlayable({
92
86
  item,
93
87
  isModal,
94
- modalHeight,
95
- modalWidth,
96
88
  mode,
97
89
  groupId,
98
90
  }: Props): React.ReactElement | null {
99
91
  const state = usePickFromState();
100
92
 
101
- const { width: screenWidth, height: screenHeight } =
102
- useDimensions(dimensionsContext);
103
-
104
93
  const { closeVideoModal } = useNavigation();
105
94
 
106
95
  const [Player, playerModuleProperties] = getPlayer(item, state);
@@ -118,9 +107,7 @@ export function HandlePlayable({
118
107
  if (!isModal) {
119
108
  closeVideoModal();
120
109
  }
121
- }, []);
122
110
 
123
- React.useEffect(() => {
124
111
  const castStateHandler = async () => {
125
112
  const castState = await CastPlugin?.getCastState();
126
113
  setCasting(castState === "Connected");
@@ -142,23 +129,23 @@ export function HandlePlayable({
142
129
  }, []);
143
130
 
144
131
  React.useEffect(() => {
145
- if (casting) {
146
- setPlayable({ Component: CastPlugin?.CastHandler });
147
- } else {
148
- setPlayable({ Component: PlayerContainer });
149
- }
132
+ setPlayable({
133
+ Component: casting ? CastPlugin?.CastHandler : PlayerContainer,
134
+ });
150
135
  }, [casting]);
151
136
 
152
- const Component = playable?.Component;
137
+ const { width: screenWidth, height: screenHeight } = useDimensions("window");
153
138
 
154
139
  const style = React.useMemo(
155
140
  () => ({
156
- width: isModal ? modalWidth : mode === "PIP" ? "100%" : screenWidth,
157
- height: isModal ? modalHeight : mode === "PIP" ? "100%" : screenHeight,
141
+ width: isModal ? "100%" : mode === "PIP" ? "100%" : screenWidth,
142
+ height: isModal ? "100%" : mode === "PIP" ? "100%" : screenHeight,
158
143
  }),
159
- [screenWidth, screenHeight, modalHeight, modalWidth, isModal, mode]
144
+ [screenWidth, screenHeight, isModal, mode]
160
145
  );
161
146
 
147
+ const Component = playable?.Component;
148
+
162
149
  if (Component) {
163
150
  return (
164
151
  <Component
@@ -174,5 +161,5 @@ export function HandlePlayable({
174
161
  );
175
162
  }
176
163
 
177
- return !isModal ? <BufferAnimation videoStyle={style as ViewStyle} /> : null;
164
+ return !isModal ? <BufferAnimation videoStyle={style} /> : null;
178
165
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Image as RnImage, ImageStyle } from "react-native";
3
- import * as R from "ramda";
3
+ import { equals, omit } from "ramda";
4
4
 
5
5
  import { useImageSource } from "./hooks";
6
6
 
@@ -17,7 +17,7 @@ type Props = Record<string, any> & {
17
17
  withDimensions: (source: Source) => Source;
18
18
  };
19
19
 
20
- const MemoizedImage = React.memo(RnImage, R.equals);
20
+ const MemoizedImage = React.memo(RnImage, equals);
21
21
 
22
22
  function Image({
23
23
  style,
@@ -44,11 +44,12 @@ function Image({
44
44
 
45
45
  return (
46
46
  <MemoizedImage
47
+ key={_source?.uri || "no-image"}
47
48
  style={style as ImageStyle}
48
49
  onError={React.useCallback(() => setErrorState(true), [])}
49
50
  // as we have defaults as "" for placeholder image, we need to pass undefined to source to not throw warnings
50
51
  source={_source?.uri ? _source : undefined}
51
- {...R.omit(["source"], otherProps)}
52
+ {...omit(["source"], otherProps)}
52
53
  />
53
54
  );
54
55
  }
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
2
+ import { path } from "ramda";
3
3
 
4
4
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
5
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
@@ -7,9 +7,13 @@ import { extractAsset } from "./utils";
7
7
 
8
8
  type Return = { uri: string } | null;
9
9
 
10
+ const getSourceContext = path(["source", "context"]);
11
+ const getSourceUri = path(["source", "uri"]);
12
+ const getState = path(["state"]);
13
+
10
14
  export const useImageSource = ({ uri, entry, otherProps }): Return => {
11
- const uriContext = R.path(["source", "context"], otherProps);
12
- const uriState = R.path(["state"], otherProps);
15
+ const uriContext = getSourceContext(otherProps);
16
+ const uriState = getState(otherProps);
13
17
 
14
18
  const action = useActions(uriContext);
15
19
 
@@ -34,7 +38,7 @@ export const useImageSource = ({ uri, entry, otherProps }): Return => {
34
38
  return { uri };
35
39
  }
36
40
 
37
- const uriFromSource = R.path(["source", "uri"], otherProps);
41
+ const uriFromSource = getSourceUri(otherProps);
38
42
 
39
43
  if (uriFromSource) {
40
44
  return { uri: uriFromSource };
@@ -56,7 +60,7 @@ const getSource = (uri, showDefault, placeholderImage, otherProps) => {
56
60
  return { uri };
57
61
  }
58
62
 
59
- const uriFromSource = R.path(["source", "uri"], otherProps);
63
+ const uriFromSource = getSourceUri(otherProps);
60
64
 
61
65
  if (uriFromSource) {
62
66
  return { uri: uriFromSource };
@@ -72,8 +76,8 @@ export const useImageSourceWithDefault = ({
72
76
  placeholderImage,
73
77
  otherProps,
74
78
  }): Return => {
75
- const uriContext = R.path(["source", "context"], otherProps);
76
- const uriState = R.path(["state"], otherProps);
79
+ const uriContext = getSourceContext(otherProps);
80
+ const uriState = getState(otherProps);
77
81
 
78
82
  const action = useActions(uriContext);
79
83
 
@@ -6,6 +6,7 @@ import React, { useEffect } from "react";
6
6
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
7
7
  import { BehaviorSubject } from "rxjs";
8
8
  import { masterCellLogger } from "../logger";
9
+ import get from "lodash/get";
9
10
 
10
11
  const parseContextKey = (key: string): string | null => {
11
12
  if (!key?.startsWith("@{ctx/")) return null;
@@ -72,11 +73,13 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
72
73
  // We cant use async in this function (its inside render),
73
74
  // so we rely on useBehaviorUpdate to update current value and trigger re-render
74
75
  export const isCellSelected = (
75
- id: string | number,
76
+ item: ZappEntry,
76
77
  behavior?: Behavior
77
78
  ): boolean => {
78
79
  if (!behavior) return false;
79
80
 
81
+ const id = behavior.selector ? get(item, behavior.selector) : item.id;
82
+
80
83
  if (behavior.selection_source === "now_playing") {
81
84
  const player = playerManager.getActivePlayer();
82
85
 
@@ -190,24 +190,24 @@ export const getFocusedButtonId = (focusable) => {
190
190
  });
191
191
  };
192
192
 
193
- export const isSelected = (id: string | number, behavior?: Behavior) => {
194
- return isCellSelected(id, behavior);
193
+ export const isSelected = (item: ZappEntry, behavior?: Behavior) => {
194
+ return isCellSelected(item, behavior);
195
195
  };
196
196
 
197
197
  export const useCellState = ({
198
- id,
198
+ item,
199
199
  behavior,
200
200
  focused,
201
201
  }: {
202
- id: string | number;
202
+ item: ZappEntry;
203
203
  behavior: Behavior;
204
204
  focused: boolean;
205
205
  }): CellState => {
206
206
  const lastUpdate = useBehaviorUpdate(behavior);
207
207
 
208
208
  const _isSelected = useMemo(
209
- () => isSelected(id, behavior),
210
- [behavior, id, lastUpdate]
209
+ () => isSelected(item, behavior),
210
+ [behavior, item, lastUpdate]
211
211
  );
212
212
 
213
213
  return getCellState({ focused, selected: _isSelected });
@@ -1,4 +1,4 @@
1
1
  /* eslint-disable max-len */
2
2
 
3
3
  export const defaultSelectedAsset: string =
4
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGsSURBVHgB7drdaYRAFIbhk2yuBTuwlXSQDrKdrOnErSSlpATBe0nOBxEMEXV+nDnjfg8MwiK4vKjMDIoQERERERERERHRY+j7vtHxJvTfb5wvHd/DMLyLpyc5IcTRw6eOZvrtcrlcq6q6i6PTBVqKM/GJdKpAa3EmrpGe5ST2xIFxHF/FwSnuoL1x1L2u66s4KD7QkXGg6EBHx4FiA6WIA0UGShUHiguUMg4UFSh1HCgmUI44UESgXHEgaCatf/wWslLeeY1GMsWBF/GEOHpodeouGkl8Vso7rtFIxjjg9YhNcea/+W4nrFyjkcxxwDnQUpxJrEhW4oBToLU4k9BIluKA60t6M6i+kzrfF7e1OODziLV6uG2d53onWYwDvi/pViJGshoHvCeKsSJZjgNBM+nQSNbjQPBSwzdSCXEgylrMNVIpcSDaYnVvJPWhA9OAZuO87HEg6mreIdIWE3Eg+nZHhEhm4sAh+0EBkUzFgcM2zDwimYsDh+4oOkQyGQcO33LdEclsHEiyJ70SyXScpBAJX3vNRif01yxSJ7SMH1USEREREREREREV7Ad//SBSU+GIIAAAAABJRU5ErkJggg==";
4
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAACXBIWXMAACE4AAAhOAFFljFgAAAA+0lEQVR4nO3a3QnCQBBF4ZRiSXZgKVqKnVnCQBpQwb0QJA752ZjszPlg3/JwOU8b2K4DAAAAAAAAkIOZnczsvPeOQypxHmb27Pv+sveeQxnG0SFSMRaHSIUXJ32kKXHKue+99e+I4yCOgzgO4jiI4yCOgzgO4jiajfMedd366t50nK3/b0LE2SpSqDi1I4WMUytSs3G6z/jbhOGLIzUdR7aKFCKO1I4UKo7UihQyjqyNFDqOLI2UIo7MjZQqjkyNVL7LFUdmRMoXRypEihtHVkSKH0cWRMoTR2ZEyhdHJkTKG0ecSMSRkUjE+TaIRJxfeFQJAAAAAAAANOwFT0Mt2UgcaMoAAAAASUVORK5CYII=";
@@ -57,7 +57,7 @@ export const useNotificationHeight = () => {
57
57
 
58
58
  const navBarHeight = platformSelect({ ios: 44, android: 56 });
59
59
 
60
- const statusHeight = Platform.OS === "android" ? 0 : insets.top;
60
+ const statusHeight = insets.top;
61
61
  const notificationHeight = statusHeight + navBarHeight;
62
62
 
63
63
  return { statusHeight, notificationHeight };
@@ -34,6 +34,7 @@ type Props = {
34
34
  getStaticComponentFeed: any;
35
35
  pullToRefreshPipesV1RefreshingStateUpdater: () => boolean;
36
36
  refreshingPipesV1?: boolean;
37
+ stickyHeaderIndices?: number[];
37
38
  };
38
39
 
39
40
  const styles = StyleSheet.create({
@@ -61,6 +62,7 @@ function ComponentsMapComponent(props: Props) {
61
62
  // TODO: Remove when pipes v1 is deprecated.
62
63
  pullToRefreshPipesV1RefreshingStateUpdater,
63
64
  refreshingPipesV1,
65
+ stickyHeaderIndices,
64
66
  } = props;
65
67
 
66
68
  const flatListRef = React.useRef<FlatList | null>(null);
@@ -274,6 +276,7 @@ function ComponentsMapComponent(props: Props) {
274
276
  overScrollMode={Platform.OS === "android" ? "never" : "auto"}
275
277
  scrollIndicatorInsets={scrollIndicatorInsets}
276
278
  extraData={feed}
279
+ stickyHeaderIndices={stickyHeaderIndices}
277
280
  onLayout={handleOnLayout}
278
281
  removeClippedSubviews
279
282
  initialNumToRender={3}
@@ -92,6 +92,10 @@ const getNavigations = ({
92
92
  return fallbackNavigations;
93
93
  };
94
94
 
95
+ const onRelease = () => {
96
+ focusManager.setInitialFocus();
97
+ };
98
+
95
99
  export const Screen = ({ route, Components }: Props) => {
96
100
  if (isNilOrEmpty(route)) {
97
101
  throw Error("Required props: route is missing");
@@ -152,12 +156,7 @@ export const Screen = ({ route, Components }: Props) => {
152
156
  const isScreenActive = useIsScreenActive();
153
157
 
154
158
  return (
155
- <FreezeWithCallback
156
- freeze={!isScreenActive}
157
- onRelease={() => {
158
- focusManager.setInitialFocus();
159
- }}
160
- >
159
+ <FreezeWithCallback freeze={!isScreenActive} onRelease={onRelease}>
161
160
  <View style={[styles.container, { backgroundColor }]}>
162
161
  <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
163
162
  <NavBar
@@ -23,10 +23,12 @@ import {
23
23
  setScrollModalAnimatedValue,
24
24
  } from "./utils";
25
25
 
26
+ import { DURATION_TO_MINIMIZE } from "./const";
27
+
26
28
  const getAnimatedConfig = (toValue) => {
27
29
  return {
28
30
  toValue,
29
- duration: 200,
31
+ duration: DURATION_TO_MINIMIZE,
30
32
  useNativeDriver: true,
31
33
  };
32
34
  };
@@ -24,8 +24,11 @@ import {
24
24
  gestureListenerHelper,
25
25
  getAnimationDefaultValue,
26
26
  getAnimationStyle,
27
+ getMoveUpValue,
27
28
  } from "./utils";
28
29
 
30
+ import { DURATION_TO_MINIMIZE, DEFAULT_DURATION_FOR_ANIMATION } from "./const";
31
+
29
32
  type Props = {
30
33
  animationType: string;
31
34
  children: React.ReactNode;
@@ -97,14 +100,16 @@ export const AnimationView = ({
97
100
 
98
101
  const inlineAudioPlayer = additionalData.inlineAudioPlayer;
99
102
 
100
- const moveUpValue = additionalData.saveArea
101
- ? -insets.top + (isAudioItem ? 0 : progressBarHeight)
102
- : isTablet
103
- ? isTabletLandscape &&
104
- (!isAudioItem || (isAudioItem && inlineAudioPlayer))
105
- ? -tabletLandscapePlayerTopPosition + progressBarHeight
106
- : -130
107
- : -50 + progressBarHeight;
103
+ const moveUpValue = getMoveUpValue({
104
+ additionalData,
105
+ insets,
106
+ isAudioItem,
107
+ progressBarHeight,
108
+ isTablet,
109
+ isTabletLandscape,
110
+ inlineAudioPlayer,
111
+ tabletLandscapePlayerTopPosition,
112
+ });
108
113
 
109
114
  const moveComponentHorizontalValue = additionalData.moveValue
110
115
  ? isRTL
@@ -119,7 +124,10 @@ export const AnimationView = ({
119
124
  (animationType, state) => {
120
125
  const defaultConfig = {
121
126
  toValue: 0,
122
- duration: state === PlayerAnimationStateEnum.minimize ? 150 : 100,
127
+ duration:
128
+ state === PlayerAnimationStateEnum.minimize
129
+ ? DURATION_TO_MINIMIZE
130
+ : DEFAULT_DURATION_FOR_ANIMATION,
123
131
  useNativeDriver: true,
124
132
  };
125
133
 
@@ -0,0 +1,108 @@
1
+ import { getMoveUpValue } from "../utils";
2
+
3
+ describe("getMoveUpValue", () => {
4
+ it("returns correct value when additionalData.saveArea is true and isAudioItem is false", () => {
5
+ const result = getMoveUpValue({
6
+ additionalData: { saveArea: true },
7
+ insets: { top: 20 },
8
+ isAudioItem: false,
9
+ progressBarHeight: 10,
10
+ isTablet: false,
11
+ isTabletLandscape: false,
12
+ inlineAudioPlayer: false,
13
+ tabletLandscapePlayerTopPosition: 100,
14
+ });
15
+
16
+ expect(result).toBe(-20 + 10);
17
+ });
18
+
19
+ it("returns correct value when additionalData.saveArea is true and isAudioItem is true", () => {
20
+ const result = getMoveUpValue({
21
+ additionalData: { saveArea: true },
22
+ insets: { top: 15 },
23
+ isAudioItem: true,
24
+ progressBarHeight: 5,
25
+ isTablet: false,
26
+ isTabletLandscape: false,
27
+ inlineAudioPlayer: false,
28
+ tabletLandscapePlayerTopPosition: 100,
29
+ });
30
+
31
+ expect(result).toBe(-15 + 0);
32
+ });
33
+
34
+ it("returns correct value for audio item (tablet or not)", () => {
35
+ const result = getMoveUpValue({
36
+ additionalData: { marginTop: 30 },
37
+ insets: { top: 0 },
38
+ isAudioItem: true,
39
+ progressBarHeight: 0,
40
+ isTablet: false,
41
+ isTabletLandscape: false,
42
+ inlineAudioPlayer: false,
43
+ tabletLandscapePlayerTopPosition: 0,
44
+ });
45
+
46
+ expect(result).toBe(-30);
47
+ });
48
+
49
+ it("returns correct value for tablet landscape with inline audio player", () => {
50
+ const result = getMoveUpValue({
51
+ additionalData: {},
52
+ insets: { top: 0 },
53
+ isAudioItem: true,
54
+ progressBarHeight: 8,
55
+ isTablet: true,
56
+ isTabletLandscape: true,
57
+ inlineAudioPlayer: true,
58
+ tabletLandscapePlayerTopPosition: 50,
59
+ });
60
+
61
+ expect(result).toBe(-0);
62
+ });
63
+
64
+ it("returns correct value for tablet landscape without audio item", () => {
65
+ const result = getMoveUpValue({
66
+ additionalData: {},
67
+ insets: { top: 0 },
68
+ isAudioItem: false,
69
+ progressBarHeight: 12,
70
+ isTablet: true,
71
+ isTabletLandscape: true,
72
+ inlineAudioPlayer: false,
73
+ tabletLandscapePlayerTopPosition: 60,
74
+ });
75
+
76
+ expect(result).toBe(-60 + 12);
77
+ });
78
+
79
+ it("returns -130 for tablet portrait (not landscape)", () => {
80
+ const result = getMoveUpValue({
81
+ additionalData: {},
82
+ insets: { top: 0 },
83
+ isAudioItem: false,
84
+ progressBarHeight: 0,
85
+ isTablet: true,
86
+ isTabletLandscape: false,
87
+ inlineAudioPlayer: false,
88
+ tabletLandscapePlayerTopPosition: 0,
89
+ });
90
+
91
+ expect(result).toBe(-130);
92
+ });
93
+
94
+ it("returns -50 + progressBarHeight for mobile audio player in docked mode", () => {
95
+ const result = getMoveUpValue({
96
+ additionalData: {},
97
+ insets: { top: 0 },
98
+ isAudioItem: false,
99
+ progressBarHeight: 7,
100
+ isTablet: false,
101
+ isTabletLandscape: false,
102
+ inlineAudioPlayer: false,
103
+ tabletLandscapePlayerTopPosition: 0,
104
+ });
105
+
106
+ expect(result).toBe(-50 + 7);
107
+ });
108
+ });
@@ -0,0 +1,5 @@
1
+ export const DURATION_TO_MINIMIZE = 200; // old value 200
2
+
3
+ export const DURATION_TO_MAXIMIZE = 0;
4
+
5
+ export const DEFAULT_DURATION_FOR_ANIMATION = 200; // old value 100
@@ -14,3 +14,5 @@ export { useModalAnimationContext } from "./useModalAnimationContext";
14
14
  export { AnimationComponent } from "./AnimationComponent";
15
15
 
16
16
  export { ComponentAnimationType, defaultAspectRatioWidth } from "./utils";
17
+
18
+ export { DURATION_TO_MINIMIZE, DURATION_TO_MAXIMIZE } from "./const";
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable padding-line-between-statements */
2
2
 
3
3
  import { PlayerAnimationStateEnum } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
4
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
4
5
 
5
6
  export enum ComponentAnimationType {
6
7
  bottomBar = "bottomBar",
@@ -300,3 +301,38 @@ export const resetScrollAnimatedValues = (
300
301
  dragScrollY.setValue(0);
301
302
  dragVideoPlayerY.setValue(0);
302
303
  };
304
+
305
+ export const getMoveUpValue = ({
306
+ additionalData,
307
+ insets,
308
+ isAudioItem,
309
+ progressBarHeight,
310
+ isTablet,
311
+ isTabletLandscape,
312
+ inlineAudioPlayer,
313
+ tabletLandscapePlayerTopPosition,
314
+ }) => {
315
+ if (additionalData.saveArea) {
316
+ return -insets.top + (isAudioItem ? 0 : progressBarHeight);
317
+ }
318
+
319
+ if (isAudioItem) {
320
+ // for any layouts in audioPlayer
321
+ return -1 * toNumberWithDefaultZero(additionalData?.marginTop);
322
+ }
323
+
324
+ if (isTablet) {
325
+ if (
326
+ isTabletLandscape &&
327
+ (!isAudioItem || (isAudioItem && inlineAudioPlayer))
328
+ ) {
329
+ return -tabletLandscapePlayerTopPosition + progressBarHeight;
330
+ }
331
+
332
+ // for audioPlayer(tablet/isTabletPortrait) in docked mode
333
+ return -130;
334
+ }
335
+
336
+ // for audioPlayer(mobile) in docked mode
337
+ return -50 + progressBarHeight;
338
+ };
@@ -137,14 +137,14 @@ const VideoModalComponent = () => {
137
137
  styles.container,
138
138
  {
139
139
  backgroundColor,
140
+ width: modalSize.width,
141
+ height: modalSize.height,
140
142
  },
141
143
  ]}
142
144
  >
143
145
  <HandlePlayable
144
146
  item={item}
145
147
  isModal={mode !== "PIP"}
146
- modalHeight={modalSize.height}
147
- modalWidth={modalSize.width}
148
148
  mode={mode}
149
149
  />
150
150
  </AnimatedPlayerModalWrapper>
@@ -1,8 +1,8 @@
1
1
  import * as React from "react";
2
2
 
3
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
3
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
5
4
  import { usePathname } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/usePathname";
5
+ import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks";
6
6
 
7
7
  type Props = ZappUIComponentProps & {
8
8
  rivers: ZappRivers;
@@ -12,27 +12,25 @@ type Props = ZappUIComponentProps & {
12
12
 
13
13
  export function withRiver(Component: ZappComponent): ZappComponent {
14
14
  const RiverWithData = ({ screenId, ...otherProps }: Props) => {
15
- const { rivers } = usePickFromState(["rivers"]);
15
+ const river = useRivers()?.[screenId];
16
16
  const pathname = usePathname();
17
- const river = rivers[screenId];
18
17
 
19
18
  if (!river) {
20
19
  return null;
21
20
  }
22
21
 
23
- if (!otherProps.screenData) {
24
- otherProps.screenData = river;
25
- }
26
-
27
22
  return (
28
23
  <Component
29
24
  screenId={screenId}
30
25
  river={river}
31
26
  key={isTV() ? pathname : undefined}
32
27
  {...otherProps}
28
+ screenData={otherProps.screenData || river}
33
29
  />
34
30
  );
35
31
  };
36
32
 
33
+ RiverWithData.displayName = `RiverWithData(${Component.displayName || Component.name})`;
34
+
37
35
  return RiverWithData;
38
36
  }
@@ -230,7 +230,8 @@ export function zappPipesDataConnector(
230
230
  const entryContext =
231
231
  (shouldUseNestedContext && screenContextData?.nested?.entry
232
232
  ? screenContextData?.nested?.entry
233
- : screenContextData?.entry) || {};
233
+ : (screenContextData?.entry?.payload ?? screenContextData?.entry)) ||
234
+ {};
234
235
 
235
236
  const screenContext =
236
237
  (shouldUseNestedContext && screenContextData?.nested?.screen
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "13.0.0-alpha.6179233127",
3
+ "version": "13.0.0-alpha.6234681660",
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",
7
7
  "scripts": {
8
- "test": "jest -w=2",
9
8
  "build": "echo skipping hybrid typescript build for now"
10
9
  },
11
10
  "publishConfig": {
@@ -32,10 +31,10 @@
32
31
  "redux-mock-store": "^1.5.3"
33
32
  },
34
33
  "dependencies": {
35
- "@applicaster/applicaster-types": "13.0.0-alpha.6179233127",
36
- "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.6179233127",
37
- "@applicaster/zapp-react-native-redux": "13.0.0-alpha.6179233127",
38
- "@applicaster/zapp-react-native-utils": "13.0.0-alpha.6179233127",
34
+ "@applicaster/applicaster-types": "13.0.0-alpha.6234681660",
35
+ "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.6234681660",
36
+ "@applicaster/zapp-react-native-redux": "13.0.0-alpha.6234681660",
37
+ "@applicaster/zapp-react-native-utils": "13.0.0-alpha.6234681660",
39
38
  "promise": "^8.3.0",
40
39
  "react-router-native": "^5.1.2",
41
40
  "url": "^0.11.0",
package/.babelrc DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "presets": ["react-native", "flow", "react-native-stage-0/decorator-support"],
3
- "env": {
4
- "test": {
5
- "presets": [["env", { "modules": "commonjs" }], "react-native", "flow"]
6
- }
7
- }
8
- }
@@ -1,157 +0,0 @@
1
- import {
2
- getColor,
3
- ACTIVE_COLOR,
4
- BACKGROUND_COLOR,
5
- MAIN_TEXT_COLOR,
6
- FOCUSED_TEXT_COLOR,
7
- } from "../colors";
8
-
9
- const Image = "Image";
10
- const View = "View";
11
- const Text = "Text";
12
-
13
- const containerStyles = (styles) => ({
14
- flex: 1,
15
- flexDirection: "column",
16
- width: 384,
17
- height: 436,
18
- borderRadius: 4,
19
- backgroundColor: getColor(BACKGROUND_COLOR, styles),
20
- marginRight: 48,
21
- marginBottom: 48,
22
- });
23
-
24
- const focusedContainerStyles = (styles) => ({
25
- ...containerStyles(styles),
26
- backgroundColor: getColor(ACTIVE_COLOR, styles),
27
- });
28
-
29
- const imageStyle = {
30
- width: 384,
31
- height: 216,
32
- borderTopRightRadius: 4,
33
- borderTopLeftRadius: 4,
34
- };
35
-
36
- const titleContainerStyles = {
37
- width: 336,
38
- height: 60,
39
- marginHorizontal: 24,
40
- marginTop: 24,
41
- overflow: "hidden",
42
- };
43
-
44
- const titleStyles = (styles) => ({
45
- fontSize: 26,
46
- color: getColor(MAIN_TEXT_COLOR, styles),
47
- fontWeight: "bold",
48
- fontStyle: "normal",
49
- });
50
-
51
- const focusedTitleStyles = (styles) => ({
52
- ...titleStyles(styles),
53
- color: getColor(FOCUSED_TEXT_COLOR, styles),
54
- });
55
-
56
- const subtitleContainerStyles = {
57
- width: 336,
58
- height: 88,
59
- marginHorizontal: 24,
60
- marginTop: 24,
61
- overflow: "hidden",
62
- };
63
-
64
- const subtitleStyles = (styles) => ({
65
- fontSize: 24,
66
- fontWeight: "normal",
67
- opacity: 0.8,
68
- color: getColor(MAIN_TEXT_COLOR, styles),
69
- fontStyle: "normal",
70
- });
71
-
72
- const focusedSubtitleStyles = (styles) => ({
73
- ...subtitleStyles(styles),
74
- color: getColor(FOCUSED_TEXT_COLOR, styles),
75
- });
76
-
77
- const viewTree = (state, styles) => [
78
- {
79
- type: View,
80
- style:
81
- state === "focused"
82
- ? focusedContainerStyles(styles)
83
- : containerStyles(styles),
84
- elements: [
85
- {
86
- type: Image,
87
- style: imageStyle,
88
- data: [
89
- {
90
- func: "image_src_from_media_item",
91
- args: ["thumbnail-small"],
92
- propName: "uri",
93
- },
94
- ],
95
- },
96
- {
97
- type: View,
98
- style: titleContainerStyles,
99
- elements: [
100
- {
101
- type: Text,
102
- style:
103
- state === "focused"
104
- ? focusedTitleStyles(styles)
105
- : titleStyles(styles),
106
- data: [
107
- {
108
- func: "path",
109
- args: ["title"],
110
- propName: "label",
111
- },
112
- ],
113
- additionalProps: {
114
- numberOfLines: 2,
115
- },
116
- },
117
- ],
118
- },
119
- {
120
- type: View,
121
- style: subtitleContainerStyles,
122
- elements: [
123
- {
124
- type: Text,
125
- style:
126
- state === "focused"
127
- ? focusedSubtitleStyles(styles)
128
- : subtitleStyles(styles),
129
- data: [
130
- {
131
- func: "path",
132
- args: ["summary"],
133
- propName: "label",
134
- },
135
- ],
136
- additionalProps: {
137
- numberOfLines: 3,
138
- },
139
- },
140
- ],
141
- },
142
- ],
143
- },
144
- ];
145
-
146
- export const fallbackCellStyle = (styles) => ({
147
- content_types: {
148
- default: {
149
- states: {
150
- default: viewTree("default", styles),
151
- focused: viewTree("focused", styles),
152
- selected: viewTree("selected", styles),
153
- focused_selected: viewTree("focused_selected", styles),
154
- },
155
- },
156
- },
157
- });
@@ -1,111 +0,0 @@
1
- import {
2
- getColor,
3
- ACTIVE_COLOR,
4
- BACKGROUND_COLOR,
5
- MAIN_TEXT_COLOR,
6
- FOCUSED_TEXT_COLOR,
7
- } from "../colors";
8
-
9
- const Image = "Image";
10
- const View = "View";
11
- const Text = "Text";
12
-
13
- const containerStyles = (styles) => ({
14
- flex: 1,
15
- flexDirection: "column",
16
- width: 1280,
17
- height: 436,
18
- borderRadius: 4,
19
- backgroundColor: getColor(BACKGROUND_COLOR, styles),
20
- marginRight: 48,
21
- marginBottom: 48,
22
- });
23
-
24
- const focusedContainerStyles = (styles) => ({
25
- ...containerStyles(styles),
26
- backgroundColor: getColor(ACTIVE_COLOR, styles),
27
- });
28
-
29
- const imageStyle = {
30
- width: 1280,
31
- height: 352,
32
- borderTopRightRadius: 4,
33
- borderTopLeftRadius: 4,
34
- };
35
-
36
- const titleContainerStyles = {
37
- width: 1184,
38
- height: 60,
39
- marginHorizontal: 24,
40
- marginTop: 24,
41
- overflow: "hidden",
42
- };
43
-
44
- const titleStyles = (styles) => ({
45
- fontSize: 26,
46
- color: getColor(MAIN_TEXT_COLOR, styles),
47
- fontWeight: "bold",
48
- fontStyle: "normal",
49
- });
50
-
51
- const focusedTitleStyles = (styles) => ({
52
- ...titleStyles(styles),
53
- color: getColor(FOCUSED_TEXT_COLOR, styles),
54
- });
55
-
56
- const viewTree = (state, styles) => [
57
- {
58
- type: View,
59
- style:
60
- state === "focused"
61
- ? focusedContainerStyles(styles)
62
- : containerStyles(styles),
63
- elements: [
64
- {
65
- type: Image,
66
- style: imageStyle,
67
- data: [
68
- {
69
- func: "image_src_from_media_item",
70
- args: ["thumbnail-small"],
71
- propName: "uri",
72
- },
73
- ],
74
- },
75
- {
76
- type: View,
77
- style: titleContainerStyles,
78
- elements: [
79
- {
80
- type: Text,
81
- style:
82
- state === "focused"
83
- ? focusedTitleStyles(styles)
84
- : titleStyles(styles),
85
- data: [
86
- {
87
- func: "path",
88
- args: ["title"],
89
- propName: "label",
90
- },
91
- ],
92
- additionalProps: {
93
- numberOfLines: 2,
94
- },
95
- },
96
- ],
97
- },
98
- ],
99
- },
100
- ];
101
-
102
- export const hero = (styles) => ({
103
- content_types: {
104
- default: {
105
- states: {
106
- default: viewTree("default", styles),
107
- focused: viewTree("focused", styles),
108
- },
109
- },
110
- },
111
- });
@@ -1,68 +0,0 @@
1
- const viewTree = (state) => [
2
- {
3
- type: "View",
4
- style: {
5
- flex: 1,
6
- // aspectRatio: 1.0487804878,
7
- paddingTop: 14,
8
- paddingBottom: 14,
9
- paddingRight: 30,
10
- },
11
- elements: [
12
- {
13
- type: "View",
14
-
15
- elements: [
16
- {
17
- type: "Text",
18
-
19
- style: {
20
- // paddingHorizontal: "15%",
21
- paddingTop: "2%",
22
- paddingBottom: "2%",
23
- fontSize: 26,
24
- lineHeight: 32,
25
- color:
26
- state === "focused" || state === "selected"
27
- ? "rgba(239,239,239,1.0)"
28
- : "rgba(239,239,239,0.61)",
29
- fontWeight: "700",
30
- },
31
- data: [
32
- {
33
- func: "path",
34
- args: ["title"],
35
- propName: "label",
36
- },
37
- ],
38
- additionalProps: {
39
- numberOfLines: 2,
40
- },
41
- },
42
- {
43
- type: "View",
44
- style: {
45
- height: 10,
46
- alignItems: "center",
47
- justifyContent: "center",
48
- borderColor: state === "focused" ? "#FC461B" : "transparent",
49
- borderBottomWidth: 6,
50
- },
51
- },
52
- ],
53
- },
54
- ],
55
- },
56
- ];
57
-
58
- export const screenSelector = {
59
- content_types: {
60
- default: {
61
- states: {
62
- default: viewTree("default"),
63
- focused: viewTree("focused"),
64
- selected: viewTree("selected"),
65
- },
66
- },
67
- },
68
- };
@@ -1,19 +0,0 @@
1
- import * as R from "ramda";
2
-
3
- import { cellStyles } from "./index";
4
-
5
- type Props = {
6
- cellStyle: string | null | undefined;
7
- componentType: string | null | undefined;
8
- };
9
-
10
- export function cellStylesResolver({ cellStyle, componentType }: Props) {
11
- const componentCellStyles =
12
- R.prop(componentType, cellStyles) || cellStyles.default;
13
-
14
- const result =
15
- R.prop(cellStyle || "fallbackCellStyle", componentCellStyles) ||
16
- componentCellStyles.fallbackCellStyle;
17
-
18
- return result;
19
- }
@@ -1,40 +0,0 @@
1
- import { transformColorCode as fixColorHexCode } from "@applicaster/zapp-react-native-utils/transform";
2
- import * as R from "ramda";
3
-
4
- export const ACTIVE_COLOR = "ACTIVE_COLOR";
5
-
6
- export const BACKGROUND_COLOR = "BACKGROUND_COLOR";
7
-
8
- export const MAIN_TEXT_COLOR = "MAIN_TEXT_COLOR";
9
-
10
- export const FOCUSED_TEXT_COLOR = "FOCUSED_TEXT_COLOR";
11
-
12
- const colorKeyPath = (keyName) => ["tv", keyName, "color"];
13
-
14
- const COLORS = {
15
- [ACTIVE_COLOR]: {
16
- path: colorKeyPath("active"),
17
- default: "#FC461B",
18
- },
19
- [BACKGROUND_COLOR]: {
20
- path: colorKeyPath("background"),
21
- default: "#2F2F2F",
22
- },
23
- [MAIN_TEXT_COLOR]: {
24
- path: colorKeyPath("main_text"),
25
- default: "#EFEFEF",
26
- },
27
- [FOCUSED_TEXT_COLOR]: {
28
- path: colorKeyPath("focused_text_color"),
29
- default: "#FFFFFF",
30
- },
31
- };
32
-
33
- export const getColor = (name, styles) => {
34
- const colorKeyPath = R.path([name, "path"], COLORS);
35
-
36
- return (
37
- fixColorHexCode(R.path(colorKeyPath, styles)) ||
38
- R.path([name, "default"], COLORS)
39
- );
40
- };
@@ -1,15 +0,0 @@
1
- import { fallbackCellStyle } from "./FallbackCellStyle";
2
- import { hero } from "./Hero";
3
- import { screenSelector } from "./ScreenSelector";
4
-
5
- export const cellStyles = {
6
- default: {
7
- default: fallbackCellStyle,
8
- },
9
- hero: {
10
- default: hero,
11
- },
12
- screenSelector: {
13
- default: screenSelector,
14
- },
15
- };