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

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>
@@ -3,8 +3,6 @@ import * as React from "react";
3
3
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
4
4
  import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
5
5
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
6
- import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
7
-
8
6
  import { isAppleTV } from "../../Helpers/Platform";
9
7
  import { useCellState } from "../MasterCell/utils";
10
8
 
@@ -37,19 +35,18 @@ const useCellFocusedState = (groupId: string, id: string) => {
37
35
  };
38
36
 
39
37
  type Props = {
40
- item: ZappEntry;
41
- CellRenderer: React.ComponentType<{ item: Object; state: string }>;
42
- id: string;
43
- groupId: string;
44
- onFocus: Function;
45
- index: number;
46
- scrollTo: Function;
47
- preferredFocus?: boolean;
48
- skipFocusManagerRegistration?: boolean;
49
- isFocusable?: boolean;
50
- behavior: Behavior;
51
- selected?: boolean;
52
- focused?: boolean;
38
+ item: ZappEntry,
39
+ CellRenderer: React.ComponentType<{ item: Object, state: string }>,
40
+ id: string,
41
+ groupId: string,
42
+ onFocus: Function,
43
+ index: number,
44
+ scrollTo: Function,
45
+ preferredFocus?: boolean,
46
+ skipFocusManagerRegistration?: boolean,
47
+ isFocusable?: boolean,
48
+ behavior: Behavior,
49
+ selected?: boolean,
53
50
  };
54
51
 
55
52
  export function CellWithFocusable(props: Props) {
@@ -65,19 +62,11 @@ export function CellWithFocusable(props: Props) {
65
62
  skipFocusManagerRegistration,
66
63
  isFocusable,
67
64
  behavior,
68
- selected,
69
- focused,
65
+ selected
70
66
  } = props;
71
67
 
72
68
  const isFocused = useCellFocusedState(groupId, id);
73
-
74
- const state = useCellState({
75
- id: item.id,
76
- behavior,
77
- focused: isFocused || toBooleanWithDefaultFalse(focused),
78
- selected,
79
- });
80
-
69
+ const state = useCellState({ id: item.id, behavior, focused: isFocused, selected });
81
70
  const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
82
71
 
83
72
  // for horizontal scrolling
@@ -106,7 +95,6 @@ export function CellWithFocusable(props: Props) {
106
95
  preferredFocus={preferredFocus}
107
96
  skipFocusManagerRegistration={skipFocusManagerRegistration}
108
97
  isFocusable={isFocusable}
109
- focused={focused}
110
98
  />
111
99
  );
112
100
  }
@@ -226,7 +226,13 @@ export class TvOSCellComponent extends React.Component<Props, State> {
226
226
 
227
227
  hasReceivedFocus() {}
228
228
 
229
- scrollTo(index) {}
229
+ scrollTo(index) {
230
+ // Workaround for HL autoscroll/autoloop feature, we scroll manually on tvOS.
231
+ // Should be removed after refactoring autoscroll/autoloop feature
232
+ if (this.props.component?.component_type !== "horizontal_list_qb") {
233
+ this.props?.scrollToIndex?.(index);
234
+ }
235
+ }
230
236
 
231
237
  render() {
232
238
  const {
@@ -243,7 +249,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
243
249
  hasReceivedFocus,
244
250
  groupId,
245
251
  isFocusable,
246
- behavior,
252
+ behavior
247
253
  } = this.props;
248
254
 
249
255
  const { id } = item;
@@ -273,7 +279,6 @@ export class TvOSCellComponent extends React.Component<Props, State> {
273
279
  index={index}
274
280
  scrollTo={this.scrollTo}
275
281
  preferredFocus={preferredFocus}
276
- focused={this.props.focused}
277
282
  behavior={behavior}
278
283
  />
279
284
  </View>
@@ -305,7 +310,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
305
310
  item,
306
311
  focused: this.props.focused || selectedCell || focused,
307
312
  scrollTo: this.scrollTo,
308
- behavior,
313
+ behavior
309
314
  }}
310
315
  />
311
316
  );
@@ -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
+ };
@@ -4,7 +4,6 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
4
4
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
5
  import * as R from "ramda";
6
6
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
7
- import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
8
7
 
9
8
  const { Logger } = getXray();
10
9
 
@@ -36,9 +35,7 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
36
35
 
37
36
  const focusableId = getFocusableId(prefixId, suffixId);
38
37
 
39
- const focused =
40
- focusableId === focusedButtonId ||
41
- toBooleanWithDefaultFalse(otherProps.focused);
38
+ const focused = focusableId === focusedButtonId;
42
39
 
43
40
  const additionalStyles = focused ? focusedStyles : normalStyles;
44
41
 
@@ -31,10 +31,6 @@ function Image({
31
31
 
32
32
  const source = useImageSource({ uri, entry, otherProps });
33
33
 
34
- // const source = {
35
- // uri: `https://placehold.co/392x221/blue/FFFFFF.png?text=${otherProps?.item?.index}`,
36
- // };
37
-
38
34
  React.useEffect(() => {
39
35
  // reset error state on URI change as the error is referencing previous uri
40
36
  setErrorState(null);
@@ -61,10 +61,7 @@ export function ButtonContainerView({
61
61
  <View style={applyRTLStylesIfNeeded(style, isRTL)}>
62
62
  {insertBetween(
63
63
  (index) => (
64
- <HorizontalSeparator
65
- key={`separator_${index}`}
66
- width={horizontalGutter}
67
- />
64
+ <HorizontalSeparator key={index} width={horizontalGutter} />
68
65
  ),
69
66
  cloneElementsWithIds(buttonIds, filteredChildren)
70
67
  )}
@@ -7,10 +7,6 @@ import type {
7
7
  ContainerProps,
8
8
  ContainerChildren,
9
9
  } from "./types";
10
- import {
11
- useIsRTL,
12
- applyRTLStylesIfNeeded,
13
- } from "@applicaster/zapp-react-native-utils/localizationUtils";
14
10
 
15
11
  const HorizontalSeparator = ({ width }: HorizontalSeparatorProps) => (
16
12
  <View style={{ width }} />
@@ -21,7 +17,6 @@ export function ButtonContainerView({
21
17
  children,
22
18
  ...otherProps
23
19
  }: ContainerProps) {
24
- const isRTL = useIsRTL();
25
20
  const horizontalGutter = R.pathOr(0, ["horizontalGutter"], otherProps);
26
21
 
27
22
  const filteredChildren = useFilterChildren<ContainerChildren>(children);
@@ -31,13 +26,10 @@ export function ButtonContainerView({
31
26
  }
32
27
 
33
28
  return (
34
- <View style={applyRTLStylesIfNeeded(style, isRTL)}>
29
+ <View style={style}>
35
30
  {insertBetween(
36
31
  (index) => (
37
- <HorizontalSeparator
38
- key={`separator_${index}`}
39
- width={horizontalGutter}
40
- />
32
+ <HorizontalSeparator key={index} width={horizontalGutter} />
41
33
  ),
42
34
  filteredChildren
43
35
  )}
@@ -9,13 +9,4 @@ describe("insertBetween", () => {
9
9
 
10
10
  expect(result).toEqual([1, "|", 2, "|", 3]);
11
11
  });
12
-
13
- it("insertBetween", () => {
14
- const separator = (index) => `separator:${index}`;
15
- const items = [1, 2, 3];
16
-
17
- const result = insertBetween(separator, items);
18
-
19
- expect(result).toEqual([1, "separator:0", 2, "separator:1", 3]);
20
- });
21
12
  });
@@ -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
 
@@ -9,12 +9,7 @@ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
9
9
 
10
10
  const { log_debug, log_info, log_error } = loggerLiveImageManager;
11
11
 
12
- export type LiveImageManagerEvent =
13
- | "onEnd"
14
- | "onStart"
15
- | "onError"
16
- | "onDestroy"
17
- | "onPlayerClose";
12
+ export type LiveImageManagerEvent = "onEnd" | "onStart" | "onError";
18
13
 
19
14
  export type LiveImageManagerListenerData = {
20
15
  id: string;
@@ -105,15 +100,6 @@ export class LiveImageManager implements PlayerLifecycleListener {
105
100
  }
106
101
 
107
102
  this.items = this.items.filter((i) => i !== item);
108
-
109
- this.invokeListenersUpdate({
110
- callbackName: "onDestroy",
111
- event: {
112
- item,
113
- playerId: this.currentlyPlaying?.playerId,
114
- primaryPlayerId: this.primaryPlayer?.playerId,
115
- },
116
- });
117
103
  };
118
104
 
119
105
  public onViewportEnter = (item: LiveImage) => {
@@ -390,29 +376,12 @@ export class LiveImageManager implements PlayerLifecycleListener {
390
376
  });
391
377
  };
392
378
 
393
- onLiveImagePlayerClose = (item: LiveImage) => {
394
- log_debug(
395
- `onLiveImagePlayerClose: live-image ${playerInfo(
396
- item.player
397
- )}, currentPlayingId: ${
398
- this.currentlyPlaying?.playerId
399
- }, primaryPlayerId: ${this.primaryPlayer?.playerId}`
400
- );
401
-
402
- this.invokeListenersUpdate({
403
- callbackName: "onPlayerClose",
404
- event: {
405
- item,
406
- playerId: this.currentlyPlaying?.playerId,
407
- primaryPlayerId: this.primaryPlayer?.playerId,
408
- },
409
- });
410
- };
411
-
412
379
  onLiveImageError = (item: LiveImage, error: Error) => {
413
380
  item.setMode(LiveImageType.Image);
414
381
 
415
- if (this.currentlyPlaying === item) {
382
+ const currentItem = this.currentlyPlaying;
383
+
384
+ if (currentItem === item) {
416
385
  this.currentlyPlaying = null;
417
386
  // TODO: ...Maybe player some other item
418
387
  }
@@ -422,8 +391,8 @@ export class LiveImageManager implements PlayerLifecycleListener {
422
391
  event: {
423
392
  item,
424
393
  error,
425
- playerId: this.currentlyPlaying?.playerId,
426
- primaryPlayerId: this.primaryPlayer?.playerId,
394
+ playerId: currentItem?.playerId,
395
+ primaryPlayerId: currentItem?.playerId,
427
396
  },
428
397
  });
429
398
  };
@@ -512,16 +481,6 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
512
481
  LiveImageManager.instance.onLiveImageError(this, error);
513
482
  };
514
483
 
515
- onVideoError = (error: Error) => {
516
- log_error(
517
- `onVideoError: live-image, fail to play, switching back to image. error: ${
518
- error?.message
519
- }, ${playerInfo(this.player)}`
520
- );
521
-
522
- LiveImageManager.instance.onLiveImageError(this, error);
523
- };
524
-
525
484
  onVideoEnd = (_event) => {
526
485
  log_info(
527
486
  `onVideoEnd: live-image, video completed, switching back to image, ${playerInfo(
@@ -540,7 +499,6 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
540
499
  );
541
500
 
542
501
  // TODO: we maybe want to add onPlayerClose to separate completion behavior
543
- LiveImageManager.instance.onLiveImagePlayerClose(this);
544
502
  LiveImageManager.instance.onLiveImageEnded(this);
545
503
  };
546
504
  }
@@ -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]
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-alpha.5035843303",
3
+ "version": "12.0.0-alpha.5114122134",
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-alpha.5035843303",
39
- "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5035843303",
40
- "@applicaster/zapp-react-native-redux": "12.0.0-alpha.5035843303",
41
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.5035843303",
37
+ "@applicaster/applicaster-types": "12.0.0-alpha.5114122134",
38
+ "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5114122134",
39
+ "@applicaster/zapp-react-native-redux": "12.0.0-alpha.5114122134",
40
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.5114122134",
42
41
  "promise": "^8.3.0",
43
42
  "react-router-native": "^5.1.2",
44
43
  "url": "^0.11.0",