@applicaster/zapp-react-native-ui-components 13.0.0-alpha.2545325570 → 13.0.0-alpha.2614386581

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.
@@ -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
 
@@ -12,6 +12,7 @@ import {
12
12
 
13
13
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
14
14
  import { PlayerContainer } from "../PlayerContainer";
15
+ import { useModalSize } from "../VideoModal/hooks";
15
16
 
16
17
  type Props = {
17
18
  item: ZappEntry;
@@ -136,12 +137,18 @@ export function HandlePlayable({
136
137
 
137
138
  const { width: screenWidth, height: screenHeight } = useDimensions("window");
138
139
 
140
+ const modalSize = useModalSize();
141
+
139
142
  const style = React.useMemo(
140
143
  () => ({
141
- width: isModal ? "100%" : mode === "PIP" ? "100%" : screenWidth,
142
- height: isModal ? "100%" : mode === "PIP" ? "100%" : screenHeight,
144
+ width: isModal ? modalSize.width : mode === "PIP" ? "100%" : screenWidth,
145
+ height: isModal
146
+ ? modalSize.height
147
+ : mode === "PIP"
148
+ ? "100%"
149
+ : screenHeight,
143
150
  }),
144
- [screenWidth, screenHeight, isModal, mode]
151
+ [screenWidth, screenHeight, modalSize, isModal, mode]
145
152
  );
146
153
 
147
154
  const Component = playable?.Component;
@@ -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
 
@@ -644,7 +644,17 @@ const PlayerContainerComponent = (props: Props) => {
644
644
  testID={"player-screen-container"}
645
645
  >
646
646
  {/* Player container */}
647
- <View style={styles.playerWrapper} testID={"player-wrapper"}>
647
+ <View
648
+ style={[
649
+ styles.playerWrapper,
650
+ // eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
651
+ {
652
+ borderWidth: 1,
653
+ borderColor: "transparent",
654
+ } /* @HACK: see GH#7269 */,
655
+ ]}
656
+ testID={"player-wrapper"}
657
+ >
648
658
  <PlayerFocusableWrapperView
649
659
  nextFocusDown={context.bottomFocusableId}
650
660
  >
@@ -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
 
@@ -440,6 +448,10 @@ export const AnimationComponent = (props: Props) => {
440
448
  videoModalState: { visible },
441
449
  } = useNavigation();
442
450
 
451
+ if (additionalData?.disableAnimatedComponent) {
452
+ return <>{props.children}</>;
453
+ }
454
+
443
455
  const useAnimation =
444
456
  visible && !additionalData.disableAnimatedComponent && !isTV();
445
457
 
@@ -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
+ };
@@ -100,6 +100,24 @@ const getEdges = (isTablet: boolean, isInlineModal: boolean) => {
100
100
  return ["top"];
101
101
  };
102
102
 
103
+ const isPercentage = (value: string | number): boolean => {
104
+ if (typeof value === "string") {
105
+ return value.includes("%");
106
+ }
107
+
108
+ return false;
109
+ };
110
+
111
+ const getPercentageOf = (percent: string, value: number) => {
112
+ const percentageValue = parseFloat(percent.replace("%", ""));
113
+
114
+ if (isNaN(percentageValue)) {
115
+ return value;
116
+ }
117
+
118
+ return (value * percentageValue) / 100;
119
+ };
120
+
103
121
  const getTabletWidth = (
104
122
  configuration: Configuration,
105
123
  dimensions: DimensionsT
@@ -108,18 +126,23 @@ const getTabletWidth = (
108
126
  configuration?.tablet_landscape_sidebar_width;
109
127
 
110
128
  const { width } = dimensions;
129
+ let widthValue = Number(width);
130
+
131
+ if (isPercentage(width)) {
132
+ widthValue = getPercentageOf(width.toString(), SCREEN_WIDTH);
133
+ }
111
134
 
112
135
  const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
113
136
 
114
137
  if (tablet_landscape_sidebar_width?.includes("%")) {
115
- return Number(width) * (1 - sidebarWidth / 100);
138
+ return widthValue * (1 - sidebarWidth / 100);
116
139
  }
117
140
 
118
141
  if (Number.isNaN(sidebarWidth)) {
119
- return Number(width) * 0.65;
142
+ return widthValue * 0.65;
120
143
  }
121
144
 
122
- return Number(width) - sidebarWidth;
145
+ return widthValue - sidebarWidth;
123
146
  };
124
147
 
125
148
  const PlayerWrapperComponent = (props: Props) => {
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { equals } from "ramda";
3
- import { StyleSheet, StatusBar } from "react-native";
3
+ import { StyleSheet, StatusBar, View } from "react-native";
4
4
 
5
5
  import { HandlePlayable } from "@applicaster/zapp-react-native-ui-components/Components/HandlePlayable";
6
6
  import {
@@ -30,10 +30,13 @@ import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHook
30
30
  import { requiresAuthentication } from "@applicaster/zapp-react-native-utils/configurationUtils";
31
31
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
32
32
  import { ScreenContextProvider } from "../../Contexts/ScreenContext";
33
+ import { Spinner } from "../Spinner";
33
34
  import { OpaqueLayer } from "./OpaqueLayer";
34
35
 
35
36
  import { AnimatedPlayerModalWrapper } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
36
37
 
38
+ const LOADER_BACKGROUND_COLOR = "rgba(64,64,64,0.5)";
39
+
37
40
  const styles = StyleSheet.create({
38
41
  container: {
39
42
  top: 0,
@@ -42,6 +45,16 @@ const styles = StyleSheet.create({
42
45
  bottom: 0,
43
46
  position: "absolute",
44
47
  },
48
+ loaderContainer: {
49
+ top: 0,
50
+ left: 0,
51
+ right: 0,
52
+ bottom: 0,
53
+ position: "absolute",
54
+ alignItems: "center",
55
+ justifyContent: "center",
56
+ backgroundColor: LOADER_BACKGROUND_COLOR,
57
+ },
45
58
  });
46
59
 
47
60
  const VideoModalComponent = () => {
@@ -131,14 +144,12 @@ const VideoModalComponent = () => {
131
144
  {/* Hide content underneath when we switch to next video in fullscreen mode */}
132
145
  {mode === "FULLSCREEN" && <OpaqueLayer />}
133
146
 
134
- {itemIdHooksFinished === item?.id && (
147
+ {itemIdHooksFinished === item?.id ? (
135
148
  <AnimatedPlayerModalWrapper
136
149
  style={[
137
150
  styles.container,
138
151
  {
139
152
  backgroundColor,
140
- width: modalSize.width,
141
- height: modalSize.height,
142
153
  },
143
154
  ]}
144
155
  >
@@ -148,6 +159,10 @@ const VideoModalComponent = () => {
148
159
  mode={mode}
149
160
  />
150
161
  </AnimatedPlayerModalWrapper>
162
+ ) : (
163
+ <View style={styles.loaderContainer}>
164
+ <Spinner />
165
+ </View>
151
166
  )}
152
167
  </ScreenContextProvider>
153
168
  </PathnameContext.Provider>
@@ -8,7 +8,6 @@ import {
8
8
 
9
9
  import { Placeholder } from "./Placeholder";
10
10
  import { useInitialLoading } from "./hooks";
11
- import { useIsFocusable } from "@applicaster/zapp-react-native-utils/focusManager";
12
11
 
13
12
  type ReactComponent = React.ComponentType<any>;
14
13
 
@@ -138,12 +137,13 @@ New signature: {Component, ErrorComponent, LoadingComponent, options}`
138
137
  );
139
138
 
140
139
  const componentProps = React.useMemo(
141
- () => ({ ...props, parent }),
140
+ () => ({
141
+ ...props,
142
+ parent,
143
+ }),
142
144
  [props, parent]
143
145
  );
144
146
 
145
- useIsFocusable(componentProps);
146
-
147
147
  React.useEffect(() => {
148
148
  if (!skipOnLoadFinished && !isLoading) {
149
149
  onLoadFinished();
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.2545325570",
3
+ "version": "13.0.0-alpha.2614386581",
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",
@@ -31,10 +31,10 @@
31
31
  "redux-mock-store": "^1.5.3"
32
32
  },
33
33
  "dependencies": {
34
- "@applicaster/applicaster-types": "13.0.0-alpha.2545325570",
35
- "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.2545325570",
36
- "@applicaster/zapp-react-native-redux": "13.0.0-alpha.2545325570",
37
- "@applicaster/zapp-react-native-utils": "13.0.0-alpha.2545325570",
34
+ "@applicaster/applicaster-types": "13.0.0-alpha.2614386581",
35
+ "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.2614386581",
36
+ "@applicaster/zapp-react-native-redux": "13.0.0-alpha.2614386581",
37
+ "@applicaster/zapp-react-native-utils": "13.0.0-alpha.2614386581",
38
38
  "promise": "^8.3.0",
39
39
  "react-router-native": "^5.1.2",
40
40
  "url": "^0.11.0",