@applicaster/zapp-react-native-ui-components 12.0.0-rc.2 → 12.0.0-rc.21

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.
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { Animated, EasingFunction, StyleProp, ViewStyle } from "react-native";
3
-
3
+ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
4
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
4
5
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
5
6
 
6
7
  type AnimatedInterpolatedStyle =
@@ -35,11 +36,16 @@ function getAnimation(config: AnimatedInConfig, phase: "in" | "out") {
35
36
  return config[phase] || config;
36
37
  }
37
38
 
38
- export function AnimatedInOut(props: Props) {
39
- const { visible, animationConfig, children } = props;
40
-
39
+ export function AnimatedInOut({
40
+ visible,
41
+ animationConfig,
42
+ staticStyles = {},
43
+ children,
44
+ }: Props) {
41
45
  const [animatedValue] = React.useState(new Animated.Value(visible ? 1 : 0));
42
- const [animating, setAnimating] = React.useState(null);
46
+ const [animating, setAnimating] = React.useState(undefined);
47
+
48
+ const previousVisible = usePrevious(toBooleanWithDefaultFalse(visible));
43
49
 
44
50
  function startAnimation(toValue, config) {
45
51
  if (animating) {
@@ -55,7 +61,7 @@ export function AnimatedInOut(props: Props) {
55
61
  delay,
56
62
  useNativeDriver: true,
57
63
  }).start(() => {
58
- setAnimating(null);
64
+ setAnimating(undefined);
59
65
  onAnimationEnd();
60
66
  });
61
67
 
@@ -63,12 +69,14 @@ export function AnimatedInOut(props: Props) {
63
69
  }
64
70
 
65
71
  React.useEffect(() => {
66
- if (visible) {
72
+ if (!previousVisible && visible) {
67
73
  startAnimation(1.0, getAnimation(animationConfig, "in"));
68
- } else {
74
+ }
75
+
76
+ if (previousVisible && !visible) {
69
77
  startAnimation(0.0, getAnimation(animationConfig, "out"));
70
78
  }
71
- }, [visible, animating]);
79
+ }, [visible, previousVisible]);
72
80
 
73
81
  const styles = visible
74
82
  ? getAnimation(animationConfig, "in").styles
@@ -77,7 +85,7 @@ export function AnimatedInOut(props: Props) {
77
85
  return (
78
86
  <Animated.View
79
87
  renderToHardwareTextureAndroid={animating}
80
- style={[styles(animatedValue), props?.staticStyles || {}]}
88
+ style={[styles(animatedValue), staticStyles]}
81
89
  >
82
90
  {children}
83
91
  </Animated.View>
@@ -52,13 +52,13 @@ export const GeneralContentScreen = ({
52
52
  React.useState(actionsInitialStateSetters.length === 0);
53
53
 
54
54
  useEffect(() => {
55
- log_info(
56
- `ScreenContainer: starting to check river action provider ready, current status: ${riverActionProvidersReady}`,
57
- { actionsInitialStateSetters }
58
- );
59
-
60
55
  if (!riverActionProvidersReady) {
61
56
  if (actionsInitialStateSetters.length > 0) {
57
+ log_info(
58
+ "ScreenContainer: starting to check river action providers to initialize",
59
+ { actionsInitialStateSetters }
60
+ );
61
+
62
62
  allSettled(actionsInitialStateSetters).finally(() => {
63
63
  log_info(
64
64
  "ScreenContainer: action provider ready, completed. Starting to present screen"
@@ -104,7 +104,7 @@ export function HandlePlayable({
104
104
  const [Player, playerModuleProperties] = getPlayer(item, state);
105
105
 
106
106
  const { module: CastPlugin } =
107
- findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins) || {};
107
+ findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
108
108
 
109
109
  const [playable, setPlayable] =
110
110
  React.useState<Nullable<PlayableComponent>>(null);
@@ -1,3 +1,34 @@
1
- import FastImage from "@applicaster/react-native-fast-image";
1
+ import React from "react";
2
+ import FastImage, {
3
+ FastImageProps,
4
+ } from "@applicaster/react-native-fast-image";
2
5
 
3
- export const QBImage = FastImage;
6
+ export const QBImage = (props: FastImageProps) => {
7
+ const source = React.useMemo(() => {
8
+ if (typeof props.source === "number") {
9
+ return props.source;
10
+ }
11
+
12
+ return {
13
+ uri: props.source.uri,
14
+ headers: props.source.headers,
15
+ priority: props.source.priority,
16
+ cache: props.source.cache,
17
+ maxWidth: props.source.maxWidth,
18
+ maxHeight: props.source.maxHeight,
19
+ };
20
+ }, [
21
+ ...(typeof props.source === "object"
22
+ ? [
23
+ props.source?.uri,
24
+ props.source?.priority,
25
+ props.source?.cache,
26
+ props.source?.headers,
27
+ props.source?.maxWidth,
28
+ props.source?.maxHeight,
29
+ ]
30
+ : []),
31
+ ]);
32
+
33
+ return <FastImage {...props} source={source} />;
34
+ };
@@ -152,7 +152,6 @@ export const BorderContainerView = (props: Props) => {
152
152
  ...updatedPaddings,
153
153
  width: updatedWidth,
154
154
  height: updatedHeight,
155
- ...borderStyleForMissingBorder,
156
155
  };
157
156
 
158
157
  return (
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  compact,
3
3
  ifElseFocusedSelected,
4
+ ifElseSelected,
4
5
  } from "@applicaster/zapp-react-native-utils/cellUtils";
5
6
 
6
7
  import { getPositionStyles } from "./utils";
@@ -12,9 +13,15 @@ type Props = {
12
13
  value: Function;
13
14
  state: string;
14
15
  visible?: Boolean;
16
+ isMobile?: Boolean;
15
17
  };
16
18
 
17
- export const CellBadge = ({ value, state, visible = true }: Props) => {
19
+ export const CellBadge = ({
20
+ value,
21
+ state,
22
+ visible = true,
23
+ isMobile = false,
24
+ }: Props) => {
18
25
  if (!value("cell_badge_switch") || !visible) {
19
26
  return null;
20
27
  }
@@ -45,13 +52,19 @@ export const CellBadge = ({ value, state, visible = true }: Props) => {
45
52
  data: [
46
53
  {
47
54
  func: () => {
48
- return ifElseFocusedSelected(
49
- state,
50
- value("cell_badge_focused"),
51
- value("cell_badge_selected"),
52
- value("cell_badge_focused_selected"),
53
- value("cell_badge_default")
54
- );
55
+ return isMobile
56
+ ? ifElseSelected(
57
+ state,
58
+ value("cell_badge_selected"),
59
+ value("cell_badge_default")
60
+ )
61
+ : ifElseFocusedSelected(
62
+ state,
63
+ value("cell_badge_focused"),
64
+ value("cell_badge_selected"),
65
+ value("cell_badge_focused_selected"),
66
+ value("cell_badge_default")
67
+ );
55
68
  },
56
69
  args: [],
57
70
  propName: "uri",
@@ -50,13 +50,17 @@ export const CollapsibleTextContainer = ({
50
50
  func: (data) => {
51
51
  const value = getValue("background_color");
52
52
 
53
- // check if value is a reference to an extension
54
- if (value.startsWith("extensions")) {
55
- return pathOr(value, value.split("."), data);
56
- } else {
57
- // return default value
58
- return additionalStyles.backgroundColor;
53
+ const valueFromData = pathOr(value, value.split("."), data);
54
+
55
+ if (
56
+ valueFromData &&
57
+ (valueFromData.startsWith("#") || valueFromData.startsWith("rgba("))
58
+ ) {
59
+ return valueFromData;
59
60
  }
61
+
62
+ // return default value
63
+ return additionalStyles.backgroundColor;
60
64
  },
61
65
  propName: "backgroundColor",
62
66
  },
@@ -4,7 +4,6 @@ import { Text, TextStyle, View, ViewStyle } from "react-native";
4
4
 
5
5
  import { getLocalizations } from "@applicaster/zapp-react-native-utils/localizationUtils";
6
6
  import { getAppStylesColor } from "@applicaster/zapp-react-native-utils/stylesUtils";
7
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
8
7
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
9
8
  import { styleKeys } from "@applicaster/zapp-react-native-utils/styleKeysUtils";
10
9
 
@@ -26,10 +25,10 @@ const textStyles = (appStyles = defaultAppStyles): TextStyle => ({
26
25
  textAlign: "center",
27
26
  });
28
27
 
29
- const errorStyles = ({ width, height, backgroundColor }): ViewStyle => ({
28
+ const errorStyles = ({ backgroundColor }): ViewStyle => ({
30
29
  flex: 1,
31
- width,
32
- height,
30
+ width: "100%",
31
+ height: "100%",
33
32
  justifyContent: "center",
34
33
  alignItems: "center",
35
34
  position: "absolute",
@@ -41,8 +40,6 @@ export function ErrorDisplayComponent({
41
40
  styles,
42
41
  remoteConfigurations: { localizations },
43
42
  }: Props) {
44
- const { width, height } = useDimensions("window");
45
-
46
43
  const theme = useTheme();
47
44
  const backgroundColor = theme?.app_background_color;
48
45
 
@@ -53,7 +50,7 @@ export function ErrorDisplayComponent({
53
50
  const appStyles = R.prop(styleKeys.style_namespace, styles);
54
51
 
55
52
  return (
56
- <View style={errorStyles({ width, height, backgroundColor })}>
53
+ <View style={errorStyles({ backgroundColor })}>
57
54
  <Text style={textStyles(appStyles)}>{stream_error_message}</Text>
58
55
  </View>
59
56
  );
@@ -1,13 +1,10 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
+ import { GeneralContentScreen } from "@applicaster/zapp-react-native-ui-components/Components/GeneralContentScreen";
3
4
 
4
5
  import { FeedLoader } from "../FeedLoader";
5
6
  import { ScreenResolver } from "../ScreenResolver";
6
7
 
7
- import type { ZappScreenProps } from "@applicaster/zapp-react-native-flow-types";
8
-
9
- import { GeneralContentScreen } from "../GeneralContentScreen";
10
-
11
8
  type Props = ZappScreenProps & {
12
9
  feedUrl?: string;
13
10
  isInsideContainer?: boolean;
@@ -18,6 +15,12 @@ type Props = ZappScreenProps & {
18
15
  | import("react-native").FlatListProps<any>
19
16
  ) &
20
17
  Record<string, any>;
18
+ appData: AppDataKeys;
19
+ screenTitle: string;
20
+ screenSummary: string;
21
+ setIsScreenWrappedInContainer: (isInsideContainer: boolean) => void;
22
+ screenContext: ZappRiver;
23
+ river: ZappRiver;
21
24
  };
22
25
 
23
26
  type State = {
@@ -27,7 +30,7 @@ type State = {
27
30
  export class RiverComponent extends React.Component<Props, State> {
28
31
  private currentScreenTitle: string;
29
32
  private currentScreenSummary: string;
30
- constructor(props) {
33
+ constructor(props: Props) {
31
34
  super(props);
32
35
 
33
36
  this.state = {
@@ -1,7 +1,7 @@
1
1
  import * as R from "ramda";
2
2
 
3
3
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
4
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
5
5
  import { toCamelCase } from "@applicaster/zapp-react-native-utils/stringUtils";
6
6
  import { useMemo } from "react";
7
7
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
@@ -47,7 +47,7 @@ const stylingKeys = [
47
47
 
48
48
  export function useScreenConfiguration(screenId: string): ScreenConfiguration {
49
49
  const { rivers } = usePickFromState(["rivers"]);
50
- const { deviceInfo } = useDimensions("screen", { deviceInfo: true });
50
+ const isTablet = useIsTablet();
51
51
 
52
52
  return useMemo(() => {
53
53
  const config = {} as ScreenConfiguration;
@@ -56,8 +56,7 @@ export function useScreenConfiguration(screenId: string): ScreenConfiguration {
56
56
  if (screenData) {
57
57
  const { styles } = screenData;
58
58
 
59
- const keyPrefix =
60
- deviceInfo?.isTablet && styles?.tablet_theme ? "tablet_" : "";
59
+ const keyPrefix = isTablet && styles?.tablet_theme ? "tablet_" : "";
61
60
 
62
61
  stylingKeys.forEach(([key, castFn]) => {
63
62
  const styleKey = `${keyPrefix}${key}`;
@@ -2,8 +2,6 @@ import * as React from "react";
2
2
  import { View } from "react-native";
3
3
  import { create, act } from "react-test-renderer";
4
4
 
5
- import { ORIENTATIONS } from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
6
-
7
5
  const Mocked_RouteManager = jest.fn((props) => (
8
6
  <View testID="routeManager" {...props} />
9
7
  ));
@@ -144,44 +142,44 @@ describe("<Screen Component />", () => {
144
142
  });
145
143
  });
146
144
 
147
- it("invokes the orientation hook when the route changes", () => {
148
- act(() => {
149
- wrapper = create(<Screen {...screenProps} />);
150
- });
151
-
152
- // @ts-ignore
153
- useCurrentScreenData.mockReturnValue({
154
- id: "player-testId",
155
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
156
- plugin_type: "player",
157
- });
158
-
159
- act(() => {
160
- wrapper.update(
161
- <Screen
162
- {...screenProps}
163
- pathname="/playable"
164
- screenData={{
165
- id: "player-testId",
166
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
167
- plugin_type: "player",
168
- }}
169
- />
170
- );
171
- });
172
-
173
- useCurrentScreenData.mockReturnValue({
174
- id: "player-testId",
175
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
176
- });
177
-
178
- act(() => {
179
- wrapper.update(<Screen {...screenProps} />);
180
- });
181
-
182
- expect(allowedOrientationsForScreen).toHaveBeenNthCalledWith(
183
- 1,
184
- ORIENTATIONS.landscapeSensor
185
- );
186
- });
145
+ // it("invokes the orientation hook when the route changes", () => {
146
+ // act(() => {
147
+ // wrapper = create(<Screen {...screenProps} />);
148
+ // });
149
+
150
+ // // @ts-ignore
151
+ // useCurrentScreenData.mockReturnValue({
152
+ // id: "player-testId",
153
+ // general: { screen_orientation: ORIENTATIONS.landscapeSensor },
154
+ // plugin_type: "player",
155
+ // });
156
+
157
+ // act(() => {
158
+ // wrapper.update(
159
+ // <Screen
160
+ // {...screenProps}
161
+ // pathname="/playable"
162
+ // screenData={{
163
+ // id: "player-testId",
164
+ // general: { screen_orientation: ORIENTATIONS.landscapeSensor },
165
+ // plugin_type: "player",
166
+ // }}
167
+ // />
168
+ // );
169
+ // });
170
+
171
+ // useCurrentScreenData.mockReturnValue({
172
+ // id: "player-testId",
173
+ // general: { screen_orientation: ORIENTATIONS.landscapeSensor },
174
+ // });
175
+
176
+ // act(() => {
177
+ // wrapper.update(<Screen {...screenProps} />);
178
+ // });
179
+
180
+ // expect(allowedOrientationsForScreen).toHaveBeenNthCalledWith(
181
+ // 1,
182
+ // ORIENTATIONS.landscapeSensor
183
+ // );
184
+ // });
187
185
  });
@@ -7,7 +7,6 @@ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
7
7
  import { useScreenOrientationHandler } from "./orientationHandler";
8
8
  import { useScreenConfiguration } from "../River/useScreenConfiguration";
9
9
  import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
10
- import type { ZappNavigationProps } from "@applicaster/zapp-react-native-flow-types/index";
11
10
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
12
11
  import { ScreenContextProvider } from "../../Contexts/ScreenContext";
13
12
 
@@ -8,7 +8,7 @@ import {
8
8
 
9
9
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
10
10
  import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
11
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
11
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
12
12
  import { ZappHookModalContext } from "../../Contexts";
13
13
  import { HookModalContextT } from "../../Contexts/ZappHookModalContext";
14
14
 
@@ -17,9 +17,12 @@ type TrackedViewProps = {
17
17
  export const TrackedView = memo(function TrackedView(props: TrackedViewProps) {
18
18
  const children = props.children;
19
19
 
20
- const onPositionUpdated = useCallback((event: TrackedViewNativeProps) => {
21
- props?.onPositionUpdated(event.nativeEvent);
22
- }, []);
20
+ const onPositionUpdated = useCallback(
21
+ (event: TrackedViewNativeProps) => {
22
+ props.onPositionUpdated(event.nativeEvent);
23
+ },
24
+ [props.onPositionUpdated]
25
+ );
23
26
 
24
27
  if (isTV()) {
25
28
  return <View {...(props as any)}>{children}</View>;
@@ -209,6 +209,11 @@ export class LiveImageManager implements PlayerLifecycleListener {
209
209
  this.pauseItem(item);
210
210
  };
211
211
 
212
+ public onLiveImageCompleted = (item: LiveImage) => {
213
+ // TODO: Notify listeners that player has died
214
+ // Do not try look for new playable, otherwise you will restart video finish to play
215
+ };
216
+
212
217
  public muteAll = () => {
213
218
  log_debug("muteAll");
214
219
 
@@ -235,6 +240,14 @@ export class LiveImageManager implements PlayerLifecycleListener {
235
240
  const playerItem = this.findNextPlayableItem();
236
241
 
237
242
  if (playerItem) {
243
+ if (!playerItem.isFullyVisible) {
244
+ log_error(
245
+ `checkPlayerPosition: trying to start playback currently invisible item: ${playerInfo(
246
+ playerItem.player
247
+ )}`
248
+ );
249
+ }
250
+
238
251
  // Will also check if it's item that already playing
239
252
  this.playLiveImage(playerItem);
240
253
  }
@@ -379,7 +392,9 @@ export class LiveImageManager implements PlayerLifecycleListener {
379
392
  onLiveImageError = (item: LiveImage, error: Error) => {
380
393
  item.setMode(LiveImageType.Image);
381
394
 
382
- if (this.currentlyPlaying === item) {
395
+ const currentItem = this.currentlyPlaying;
396
+
397
+ if (currentItem === item) {
383
398
  this.currentlyPlaying = null;
384
399
  // TODO: ...Maybe player some other item
385
400
  }
@@ -389,8 +404,8 @@ export class LiveImageManager implements PlayerLifecycleListener {
389
404
  event: {
390
405
  item,
391
406
  error,
392
- playerId: this.currentlyPlaying?.playerId,
393
- primaryPlayerId: this.primaryPlayer?.playerId,
407
+ playerId: currentItem?.playerId,
408
+ primaryPlayerId: currentItem?.playerId,
394
409
  },
395
410
  });
396
411
  };
@@ -25,12 +25,12 @@ import { loggerLiveImageComponent } from "./loggerHelper";
25
25
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
26
26
  import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/conts";
27
27
  import { getAutoplaySettings } from "./utils";
28
+ import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
28
29
 
29
30
  const { log_error } = loggerLiveImageComponent;
30
31
 
31
- const isMeasurement = (item) => {
32
- return item.id.startsWith("pre-measurement-");
33
- };
32
+ const isMeasurement = (item: ZappEntry) =>
33
+ isString(item.id) && item.id.startsWith("pre-measurement-");
34
34
 
35
35
  type Props = {
36
36
  item: ZappEntry;
@@ -80,6 +80,7 @@ const PlayerLiveImageComponent = (props: Props) => {
80
80
  } else {
81
81
  if (timeoutRef.current) {
82
82
  clearTimeout(timeoutRef.current);
83
+ timeoutRef.current = null;
83
84
  }
84
85
 
85
86
  setMode(type);
@@ -127,6 +128,10 @@ const PlayerLiveImageComponent = (props: Props) => {
127
128
  ref.current = component;
128
129
  };
129
130
 
131
+ const onLiveImageCompleted = React.useCallback(() => {
132
+ LiveImageManager.instance.onLiveImageCompleted(liveImageItem);
133
+ }, [liveImageItem]);
134
+
130
135
  const onStop = React.useCallback(() => {
131
136
  LiveImageManager.instance.pauseLiveImage(liveImageItem);
132
137
  }, [liveImageItem]);
@@ -144,9 +149,10 @@ const PlayerLiveImageComponent = (props: Props) => {
144
149
 
145
150
  if (timeoutRef.current) {
146
151
  clearTimeout(timeoutRef.current);
152
+ timeoutRef.current = null;
147
153
  }
148
154
  };
149
- }, [liveImageItem, item]);
155
+ }, [liveImageItem, item, timeoutRef.current]);
150
156
 
151
157
  React.useEffect(() => {
152
158
  if (!player) {
@@ -178,11 +184,12 @@ const PlayerLiveImageComponent = (props: Props) => {
178
184
  setMuted(false);
179
185
  },
180
186
  onPlayerClose: () => {
187
+ onLiveImageCompleted();
181
188
  setIsReady(false);
182
189
  },
183
190
  },
184
191
  });
185
- }, [player, onStop]);
192
+ }, [player, onStop, onLiveImageCompleted, start, end]);
186
193
 
187
194
  React.useEffect(() => {
188
195
  const subscription = AppState.addEventListener(
@@ -233,40 +240,43 @@ const PlayerLiveImageComponent = (props: Props) => {
233
240
  };
234
241
  }
235
242
  }
236
- }, [liveImageItem]);
243
+ }, [liveImageItem, playerId, controller]);
237
244
 
238
- const onPositionUpdated = (data) => {
239
- const normalizedRect = (rect) => {
240
- if (!rect) {
241
- return null;
242
- }
245
+ const onPositionUpdated = React.useCallback(
246
+ (data) => {
247
+ const normalizedRect = (rect) => {
248
+ if (!rect) {
249
+ return null;
250
+ }
243
251
 
244
- const { left, right, top, bottom } = rect;
252
+ const { left, right, top, bottom } = rect;
245
253
 
246
- return {
247
- left: left / dimensions.width,
248
- right: right / dimensions.width,
249
- top: top / dimensions.height,
250
- bottom: bottom / dimensions.height,
251
- centerX: (left + right) / 2 / dimensions.width,
252
- centerY: (top + bottom) / 2 / dimensions.height,
254
+ return {
255
+ left: left / dimensions.width,
256
+ right: right / dimensions.width,
257
+ top: top / dimensions.height,
258
+ bottom: bottom / dimensions.height,
259
+ centerX: (left + right) / 2 / dimensions.width,
260
+ centerY: (top + bottom) / 2 / dimensions.height,
261
+ };
253
262
  };
254
- };
255
263
 
256
- liveImageItem.position = normalizedRect(data.rect);
264
+ liveImageItem.position = normalizedRect(data.rect);
257
265
 
258
- const newIsFullyVisible = !!data.rect;
266
+ const newIsFullyVisible = !!data.rect;
259
267
 
260
- if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
261
- liveImageItem.isFullyVisible = newIsFullyVisible;
268
+ if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
269
+ liveImageItem.isFullyVisible = newIsFullyVisible;
262
270
 
263
- liveImageItem.isFullyVisible
264
- ? LiveImageManager.instance.onViewportEnter(liveImageItem)
265
- : LiveImageManager.instance.onViewportLeave(liveImageItem);
266
- } else {
267
- LiveImageManager.instance.checkPlayerPosition(liveImageItem);
268
- }
269
- };
271
+ liveImageItem.isFullyVisible
272
+ ? LiveImageManager.instance.onViewportEnter(liveImageItem)
273
+ : LiveImageManager.instance.onViewportLeave(liveImageItem);
274
+ } else {
275
+ LiveImageManager.instance.checkPlayerPosition(liveImageItem);
276
+ }
277
+ },
278
+ [liveImageItem, item?.id, playerId, dimensions]
279
+ );
270
280
 
271
281
  const platformSpecificProps = isApplePlatform()
272
282
  ? { hideNativeControls: true, controls: false }
@@ -1,18 +1,24 @@
1
1
  import * as React from "react";
2
- import { Platform, StyleSheet, View, ViewStyle } from "react-native";
2
+ import {
3
+ Dimensions,
4
+ Platform,
5
+ StyleSheet,
6
+ View,
7
+ ViewStyle,
8
+ } from "react-native";
3
9
  import { Edge, SafeAreaView } from "react-native-safe-area-context";
4
10
 
5
11
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
6
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device";
12
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
7
13
  import { PlayerDetails } from "./PlayerDetails";
8
14
  import { playerDimesionsHack } from "./utils";
9
15
  import { PathnameContext } from "../../Contexts/PathnameContext";
10
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
11
16
  import { ScreenContextProvider } from "../../Contexts/ScreenContext";
12
17
 
13
- type Dimensions = {
14
- width: number;
15
- height: number;
18
+ type DimensionsT = {
19
+ width: number | string;
20
+ height: number | string;
21
+ aspectRatio?: number;
16
22
  };
17
23
 
18
24
  type Configuration = {
@@ -23,14 +29,15 @@ type Configuration = {
23
29
 
24
30
  type Props = {
25
31
  entry: ZappEntry;
26
- style: ViewStyle & Dimensions;
32
+ style: ViewStyle & DimensionsT;
27
33
  containerStyle?: ViewStyle;
28
34
  inline?: boolean;
29
35
  docked?: boolean;
36
+ pip?: boolean;
30
37
  isModal?: boolean;
31
38
  fullscreen?: boolean;
32
39
  isTabletPortrait?: boolean;
33
- children: (playerDimensions: Dimensions) => React.ReactNode;
40
+ children: (playerDimensions: DimensionsT) => React.ReactNode;
34
41
  configuration: Configuration;
35
42
  };
36
43
 
@@ -52,6 +59,15 @@ const directionStyles = (isTabletLandscape: boolean): ViewStyle => {
52
59
  return orientationStyles.portrait;
53
60
  };
54
61
 
62
+ const getScreenAspectRatio = () => {
63
+ const { width, height } = Dimensions.get("screen");
64
+
65
+ const longEdge = Math.max(width, height);
66
+ const shortEdge = Math.min(width, height);
67
+
68
+ return longEdge / shortEdge;
69
+ };
70
+
55
71
  const safeAreaStyles = (
56
72
  configuration: Configuration,
57
73
  isTablet: boolean
@@ -66,34 +82,6 @@ const safeAreaStyles = (
66
82
  };
67
83
  };
68
84
 
69
- const getTabletWidth = (
70
- configuration: Configuration,
71
- dimensions: Dimensions
72
- ) => {
73
- const tablet_landscape_sidebar_width =
74
- configuration?.tablet_landscape_sidebar_width;
75
-
76
- const { width } = dimensions;
77
-
78
- const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
79
-
80
- if (tablet_landscape_sidebar_width?.includes("%")) {
81
- return width * (1 - sidebarWidth / 100);
82
- }
83
-
84
- if (Number.isNaN(sidebarWidth)) {
85
- return width * 0.65;
86
- }
87
-
88
- return width - sidebarWidth;
89
- };
90
-
91
- export const defaultAspectRatioHeight = (width: number): number =>
92
- (width / 16) * 9;
93
-
94
- export const defaultAspectRatioWidth = (height: number): number =>
95
- (height / 9) * 16;
96
-
97
85
  const getEdges = (
98
86
  isTablet: boolean,
99
87
  docked: boolean,
@@ -115,6 +103,28 @@ const getEdges = (
115
103
  return ["top"];
116
104
  };
117
105
 
106
+ const getTabletWidth = (
107
+ configuration: Configuration,
108
+ dimensions: DimensionsT
109
+ ) => {
110
+ const tablet_landscape_sidebar_width =
111
+ configuration?.tablet_landscape_sidebar_width;
112
+
113
+ const { width } = dimensions;
114
+
115
+ const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
116
+
117
+ if (tablet_landscape_sidebar_width?.includes("%")) {
118
+ return Number(width) * (1 - sidebarWidth / 100);
119
+ }
120
+
121
+ if (Number.isNaN(sidebarWidth)) {
122
+ return Number(width) * 0.65;
123
+ }
124
+
125
+ return Number(width) - sidebarWidth;
126
+ };
127
+
118
128
  export const PlayerWrapper = (props: Props) => {
119
129
  const {
120
130
  entry,
@@ -126,6 +136,7 @@ export const PlayerWrapper = (props: Props) => {
126
136
  children,
127
137
  isTabletPortrait,
128
138
  configuration,
139
+ pip,
129
140
  } = props;
130
141
 
131
142
  const isTablet = useIsTablet();
@@ -136,40 +147,38 @@ export const PlayerWrapper = (props: Props) => {
136
147
 
137
148
  const tabletWidth = getTabletWidth(configuration, style);
138
149
 
139
- const { width: screenWidth } = useDimensions("screen");
140
-
141
- const containerDimensions: Dimensions = React.useMemo(
150
+ const baseDimensions: DimensionsT = React.useMemo(
142
151
  () => ({
143
152
  width:
144
- isInlineModal && !docked && isTabletLandscape
145
- ? tabletWidth
146
- : style.width,
147
- height:
148
- isInlineModal && !docked
149
- ? defaultAspectRatioHeight(
150
- isTabletLandscape ? tabletWidth : screenWidth
151
- )
152
- : style.height,
153
+ isInlineModal && !docked && isTabletLandscape ? tabletWidth : "100%",
154
+ height: isInlineModal && docked ? style.height : undefined,
153
155
  }),
154
- [isInlineModal, docked, isTabletLandscape, tabletWidth, style, screenWidth]
156
+ [isInlineModal, tabletWidth, style.height, docked]
155
157
  );
156
158
 
157
- const playerDimensions: Dimensions = React.useMemo(
159
+ const playerDimensions: DimensionsT = React.useMemo(
158
160
  () => ({
159
- width:
160
- isInlineModal && docked
161
- ? defaultAspectRatioWidth(containerDimensions.height)
162
- : containerDimensions.width,
163
- height: containerDimensions.height,
161
+ ...baseDimensions,
162
+ width: isInlineModal && docked ? undefined : baseDimensions.width,
163
+ aspectRatio: !isInlineModal && !pip ? getScreenAspectRatio() : 16 / 9,
164
+ }),
165
+ [baseDimensions, isInlineModal, pip]
166
+ );
167
+
168
+ const containerDimensions: DimensionsT = React.useMemo(
169
+ () => ({
170
+ ...baseDimensions,
171
+ aspectRatio:
172
+ isInlineModal && docked ? undefined : playerDimensions.aspectRatio,
164
173
  }),
165
- [isInlineModal, docked, containerDimensions]
174
+ [baseDimensions, isInlineModal, docked, playerDimensions.aspectRatio]
166
175
  );
167
176
 
168
177
  const WrapperView = React.useMemo(() => (isTV() ? View : SafeAreaView), []);
169
178
 
170
179
  const childrenStyles = React.useMemo(
171
180
  () => ({ ...playerDimensions, ...playerDimesionsHack }),
172
- [playerDimensions, playerDimesionsHack]
181
+ [containerDimensions, playerDimesionsHack]
173
182
  );
174
183
 
175
184
  return (
@@ -190,12 +199,6 @@ export const PlayerWrapper = (props: Props) => {
190
199
  defaultStyles.playerContainer,
191
200
  containerDimensions,
192
201
  containerStyle,
193
- {
194
- height:
195
- isInlineModal && !docked
196
- ? containerDimensions.height + 10
197
- : containerDimensions.height,
198
- },
199
202
  playerDimesionsHack,
200
203
  ]}
201
204
  >
@@ -50,7 +50,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
50
50
 
51
51
  jest.mock("../utils", () => ({ playerDimesionsHack: {} }));
52
52
 
53
- const { PlayerWrapper, defaultAspectRatioWidth } = require("../PlayerWrapper");
53
+ const { PlayerWrapper } = require("../PlayerWrapper");
54
54
 
55
55
  jest.useFakeTimers();
56
56
  const children = jest.fn(() => {});
@@ -110,7 +110,8 @@ describe("PlayerWrapper", () => {
110
110
 
111
111
  const expectDimensions = {
112
112
  ...dimensions,
113
- width: defaultAspectRatioWidth(dimensions.height),
113
+ width: undefined,
114
+ aspectRatio: 16 / 9,
114
115
  };
115
116
 
116
117
  expect(element).toMatchSnapshot();
@@ -35,13 +35,11 @@ exports[`PlayerWrapper renders inline 1`] = `
35
35
  "zIndex": 200,
36
36
  },
37
37
  Object {
38
- "height": 421.875,
39
- "width": 300,
38
+ "aspectRatio": 1.7777777777777777,
39
+ "height": undefined,
40
+ "width": "100%",
40
41
  },
41
42
  Object {},
42
- Object {
43
- "height": 431.875,
44
- },
45
43
  Object {},
46
44
  ]
47
45
  }
@@ -105,13 +103,11 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
105
103
  "zIndex": 200,
106
104
  },
107
105
  Object {
106
+ "aspectRatio": undefined,
108
107
  "height": 50,
109
- "width": 300,
108
+ "width": "100%",
110
109
  },
111
110
  Object {},
112
- Object {
113
- "height": 50,
114
- },
115
111
  Object {},
116
112
  ]
117
113
  }
@@ -163,13 +159,11 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
163
159
  "zIndex": 200,
164
160
  },
165
161
  Object {
166
- "height": 109.6875,
162
+ "aspectRatio": 1.7777777777777777,
163
+ "height": undefined,
167
164
  "width": 195,
168
165
  },
169
166
  Object {},
170
- Object {
171
- "height": 119.6875,
172
- },
173
167
  Object {},
174
168
  ]
175
169
  }
@@ -233,13 +227,11 @@ exports[`PlayerWrapper renders properly 1`] = `
233
227
  "zIndex": 200,
234
228
  },
235
229
  Object {
236
- "height": 800,
237
- "width": 300,
230
+ "aspectRatio": 1.7786666666666666,
231
+ "height": undefined,
232
+ "width": "100%",
238
233
  },
239
234
  Object {},
240
- Object {
241
- "height": 800,
242
- },
243
235
  Object {},
244
236
  ]
245
237
  }
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import * as React from "react";
2
2
  import { Dimensions } from "react-native";
3
3
  import { useIsTabletLandscape } from "@applicaster/zapp-react-native-utils/reactHooks/device/useMemoizedIsTablet";
4
4
  import {
@@ -39,13 +39,22 @@ export const useModalSize = (): Size => {
39
39
  MODAL_SIZE_FOR_PORTRAIT
40
40
  );
41
41
 
42
- const setNewModalSize = (size, log) => {
43
- setModalSize(size);
42
+ const setNewModalSize = React.useCallback((newSize, log) => {
43
+ setModalSize((oldSize) => {
44
+ if (
45
+ oldSize.height === newSize.height &&
46
+ oldSize.width === newSize.width
47
+ ) {
48
+ return oldSize;
49
+ }
50
+
51
+ return newSize;
52
+ });
44
53
 
45
54
  logger.debug({
46
55
  message: log,
47
56
  });
48
- };
57
+ }, []);
49
58
 
50
59
  const isTabletLandscape = useIsTabletLandscape();
51
60
 
@@ -1,9 +1,5 @@
1
1
  import * as React from "react";
2
2
 
3
- import type {
4
- ZappComponent,
5
- ZappRivers,
6
- } from "@applicaster/zapp-react-native-flow-types";
7
3
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
8
4
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
9
5
  import { usePathname } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
@@ -1,9 +1,5 @@
1
1
  import { zappPipesDataConnector } from "./ZappPipesDataConnector";
2
2
  import * as R from "ramda";
3
- import type {
4
- ZappComponent,
5
- ZappDecorator,
6
- } from "@applicaster/zapp-react-native-flow-types";
7
3
 
8
4
  import { withNavigator } from "./Navigator";
9
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "12.0.0-rc.2",
3
+ "version": "12.0.0-rc.21",
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",
@@ -29,16 +29,15 @@
29
29
  },
30
30
  "homepage": "https://github.com/applicaster/quickbrick#readme",
31
31
  "devDependencies": {
32
- "@applicaster/zapp-react-native-flow-types": "1.5.0",
33
32
  "@types/react": "17.0.2",
34
33
  "@types/react-native": "0.69.6",
35
34
  "redux-mock-store": "^1.5.3"
36
35
  },
37
36
  "dependencies": {
38
- "@applicaster/applicaster-types": "12.0.0-rc.2",
39
- "@applicaster/zapp-react-native-bridge": "12.0.0-rc.2",
40
- "@applicaster/zapp-react-native-redux": "12.0.0-rc.2",
41
- "@applicaster/zapp-react-native-utils": "12.0.0-rc.2",
37
+ "@applicaster/applicaster-types": "12.0.0-rc.21",
38
+ "@applicaster/zapp-react-native-bridge": "12.0.0-rc.21",
39
+ "@applicaster/zapp-react-native-redux": "12.0.0-rc.21",
40
+ "@applicaster/zapp-react-native-utils": "12.0.0-rc.21",
42
41
  "promise": "^8.3.0",
43
42
  "react-router-native": "^5.1.2",
44
43
  "url": "^0.11.0",