@applicaster/zapp-react-native-ui-components 12.0.0-alpha.9262886003 → 12.0.0-alpha.9531194637

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.
@@ -202,7 +202,7 @@ export class CellComponent extends React.Component<Props> {
202
202
  groupId,
203
203
  isFocusable = true,
204
204
  skipFocusManagerRegistration,
205
- behavior
205
+ behavior,
206
206
  } = this.props;
207
207
 
208
208
  const { id } = item;
@@ -263,7 +263,7 @@ export class CellComponent extends React.Component<Props> {
263
263
  item,
264
264
  focused: this.isCellFocused(focused),
265
265
  scrollTo: this.scrollToIndex(event),
266
- behavior
266
+ behavior,
267
267
  }}
268
268
  />
269
269
  );
@@ -35,18 +35,18 @@ const useCellFocusedState = (groupId: string, id: string) => {
35
35
  };
36
36
 
37
37
  type Props = {
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,
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;
50
50
  };
51
51
 
52
52
  export function CellWithFocusable(props: Props) {
@@ -62,11 +62,18 @@ export function CellWithFocusable(props: Props) {
62
62
  skipFocusManagerRegistration,
63
63
  isFocusable,
64
64
  behavior,
65
- selected
65
+ selected,
66
66
  } = props;
67
67
 
68
68
  const isFocused = useCellFocusedState(groupId, id);
69
- const state = useCellState({ id: item.id, behavior, focused: isFocused, selected });
69
+
70
+ const state = useCellState({
71
+ id: item.id,
72
+ behavior,
73
+ focused: isFocused,
74
+ selected,
75
+ });
76
+
70
77
  const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
71
78
 
72
79
  // for horizontal scrolling
@@ -249,7 +249,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
249
249
  hasReceivedFocus,
250
250
  groupId,
251
251
  isFocusable,
252
- behavior
252
+ behavior,
253
253
  } = this.props;
254
254
 
255
255
  const { id } = item;
@@ -310,7 +310,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
310
310
  item,
311
311
  focused: this.props.focused || selectedCell || focused,
312
312
  scrollTo: this.scrollTo,
313
- behavior
313
+ behavior,
314
314
  }}
315
315
  />
316
316
  );
@@ -3,12 +3,12 @@ import { Platform } from "react-native";
3
3
  import { useCellState } from "../MasterCell/utils";
4
4
 
5
5
  type Props = {
6
- index: number,
7
- item: ZappEntry,
8
- focused: boolean,
9
- scrollTo?: (index: number) => void,
10
- CellRenderer: React.ComponentType<{ item: Object, state: string }>,
11
- behavior: Behavior
6
+ index: number;
7
+ item: ZappEntry;
8
+ focused: boolean;
9
+ scrollTo?: (index: number) => void;
10
+ CellRenderer: React.ComponentType<{ item: Object; state: string }>;
11
+ behavior: Behavior;
12
12
  };
13
13
 
14
14
  const isAndroid = Platform.OS === "android";
@@ -20,7 +20,7 @@ export function FocusableCell(props: Props) {
20
20
  CellRenderer,
21
21
  focused,
22
22
  scrollTo = null,
23
- behavior
23
+ behavior,
24
24
  } = props;
25
25
 
26
26
  const state = useCellState({ id: item.id, behavior, focused });
@@ -1,19 +1,29 @@
1
+ import FastImage, { Source } from "@applicaster/react-native-fast-image";
1
2
  import { useMemo } from "react";
3
+ import { ImageRequireSource } from "react-native";
2
4
 
3
- export const useImageSource = (source) => {
5
+ function getSourceCache(cache: Source["cache"]) {
6
+ return cache || FastImage.cacheControl.web;
7
+ }
8
+
9
+ export const useImageSource = (source?: Source | ImageRequireSource) => {
4
10
  return useMemo(() => {
5
- if (typeof source === "number") {
6
- return source;
11
+ if (source) {
12
+ if (typeof source === "number") {
13
+ return source;
14
+ }
15
+
16
+ return {
17
+ uri: source.uri,
18
+ headers: source.headers,
19
+ priority: source.priority,
20
+ cache: getSourceCache(source?.cache),
21
+ maxWidth: source.maxWidth,
22
+ maxHeight: source.maxHeight,
23
+ };
7
24
  }
8
25
 
9
- return {
10
- uri: source.uri,
11
- headers: source.headers,
12
- priority: source.priority,
13
- cache: source.cache,
14
- maxWidth: source.maxWidth,
15
- maxHeight: source.maxHeight,
16
- };
26
+ return undefined;
17
27
  }, [
18
28
  ...(typeof source === "object"
19
29
  ? [
@@ -23,7 +23,11 @@ export const Toggle = (props: Props) => {
23
23
  iosBackgroundColor,
24
24
  } = style;
25
25
 
26
- const isSelected = React.useMemo(() => (cellState === "selected"), [item?.id, cellState]);
26
+ const isSelected = React.useMemo(
27
+ () => cellState === "selected",
28
+ [item?.id, cellState]
29
+ );
30
+
27
31
  const actionContext = useActions(action?.identifier);
28
32
 
29
33
  const [actionState, setActionState] = useState(
@@ -145,34 +145,30 @@ const renderApplePlayer = ({
145
145
  }) => {
146
146
  const { title, summary } = item || {};
147
147
 
148
- if (!isApplePlatform()) {
148
+ if (!isAppleTV() || !player) {
149
+ return null;
150
+ }
151
+
152
+ if (isAudioContent) {
153
+ return (
154
+ <AudioPlayer
155
+ audio_item={item}
156
+ plugin_configuration={pluginConfiguration}
157
+ />
158
+ );
159
+ }
160
+
161
+ if (!playNextData && player.isPaused() && player.isAd() === false) {
149
162
  return null;
150
163
  }
151
164
 
152
165
  return (
153
- <>
154
- {!playNextData && (
155
- <>
156
- {!isAudioContent &&
157
- !!player?.isPaused() &&
158
- !!player?.isAd() === false && (
159
- <ProgramInfo
160
- title={title}
161
- subtitle={summary}
162
- plugin_configuration={pluginConfiguration}
163
- videoStyle={videoStyle}
164
- />
165
- )}
166
- </>
167
- )}
168
-
169
- {isAudioContent && (
170
- <AudioPlayer
171
- audio_item={item}
172
- plugin_configuration={pluginConfiguration}
173
- />
174
- )}
175
- </>
166
+ <ProgramInfo
167
+ title={title}
168
+ subtitle={summary}
169
+ plugin_configuration={pluginConfiguration}
170
+ videoStyle={videoStyle}
171
+ />
176
172
  );
177
173
  };
178
174
 
@@ -339,6 +335,18 @@ const PlayerContainerComponent = (props: Props) => {
339
335
  }
340
336
  }, [item?.id, item?.extensions?.resumeTime, player]);
341
337
 
338
+ const onVideoFullscreenPlayerWillPresent = React.useCallback(() => {
339
+ playerManager.invokeHandler("toggleFullscreen", {
340
+ fullscreen: true,
341
+ });
342
+ }, []);
343
+
344
+ const onVideoFullscreenPlayerWillDismiss = React.useCallback(() => {
345
+ playerManager.invokeHandler("toggleFullscreen", {
346
+ fullscreen: false,
347
+ });
348
+ }, []);
349
+
342
350
  // Util methods
343
351
  const toggleFullscreen = (event) => {
344
352
  const { fullscreen = false } = event || {};
@@ -381,17 +389,27 @@ const PlayerContainerComponent = (props: Props) => {
381
389
  id: playerContainerId,
382
390
  listener: {
383
391
  onVideoEnd,
384
- onError: onError,
385
- onLoad: onLoad,
392
+ onError,
393
+ onLoad,
386
394
  onPlayerClose: close,
387
395
  onPlayerDetached: close,
396
+ onVideoFullscreenPlayerWillDismiss,
397
+ onVideoFullscreenPlayerWillPresent,
388
398
  },
389
399
  });
390
400
 
391
401
  return () => {
392
402
  player.removeListener(playerContainerId);
393
403
  };
394
- }, [player, onVideoEnd]);
404
+ }, [
405
+ player,
406
+ onVideoEnd,
407
+ onError,
408
+ onLoad,
409
+ close,
410
+ onVideoFullscreenPlayerWillDismiss,
411
+ onVideoFullscreenPlayerWillPresent,
412
+ ]);
395
413
 
396
414
  useEffect(() => {
397
415
  // TODO: We should not use playerManager here to connect buttons to player container
@@ -621,7 +639,7 @@ const PlayerContainerComponent = (props: Props) => {
621
639
  }}
622
640
  focused={isInlineTV ? true : undefined}
623
641
  autoplay={true}
624
- controls={isAppleTV() && !isInlineTV}
642
+ controls={false}
625
643
  disableCastAction={disableCastAction}
626
644
  docked={navigator.isVideoModalDocked()}
627
645
  entry={item}
@@ -83,6 +83,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
83
83
  useNavigation: jest.fn(() => ({ currentRoute: "/river/A1234" })),
84
84
  useRoute: jest.fn(() => ({ pathname: "/river/A1234", screenData })),
85
85
  useProfilerLogging: jest.fn(),
86
+ useIsScreenActive: jest.fn().mockReturnValue(true),
86
87
  }));
87
88
 
88
89
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { create, act } from "react-test-renderer";
3
+ import { act, create } from "react-test-renderer";
4
4
 
5
5
  const Mocked_RouteManager = jest.fn((props) => (
6
6
  <View testID="routeManager" {...props} />
@@ -69,12 +69,16 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
69
69
  isNavBarVisible: mockIsNavBarVisible,
70
70
  useRoute: jest.fn(() => ({
71
71
  pathname: "/river/testId",
72
+ screenData: { id: "testId" },
72
73
  })),
73
74
  useNavigation: jest.fn(() => ({
74
75
  canGoBack: () => false,
75
76
  currentRoute: "/river/testId",
77
+ activeRiver: { id: "testId" },
78
+ screenData: { id: "testId" },
76
79
  data: { screen: { id: "testId" } },
77
80
  })),
81
+ useIsScreenActive: jest.fn().mockReturnValue(true),
78
82
  }));
79
83
 
80
84
  jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
@@ -19,7 +19,11 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
19
19
  <View>
20
20
  <View
21
21
  pathname="/river/testId"
22
- screenData={Object {}}
22
+ screenData={
23
+ Object {
24
+ "id": "testId",
25
+ }
26
+ }
23
27
  testID="routeManager"
24
28
  />
25
29
  </View>
@@ -45,7 +49,11 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
45
49
  <View>
46
50
  <View
47
51
  pathname="/river/testId"
48
- screenData={Object {}}
52
+ screenData={
53
+ Object {
54
+ "id": "testId",
55
+ }
56
+ }
49
57
  testID="routeManager"
50
58
  />
51
59
  </View>
@@ -23,6 +23,17 @@ import { RouteManager } from "../RouteManager";
23
23
  import { useScreenConfiguration } from "../River/useScreenConfiguration";
24
24
  import { useScreenOrientationHandler } from "./orientationHandler";
25
25
 
26
+ const getScreenId = (
27
+ screenData: LegacyNavigationScreenData,
28
+ fallbackRiver: ZappRiver
29
+ ) => {
30
+ return screenData?.targetScreen
31
+ ? screenData?.targetScreen?.id ?? fallbackRiver.id
32
+ : "screen_id" in screenData
33
+ ? screenData.screen_id
34
+ : fallbackRiver.id;
35
+ };
36
+
26
37
  function colorIsNotTransparent(color) {
27
38
  const layers = R.compose(
28
39
  R.map(R.trim),
@@ -41,17 +52,11 @@ function isValidColor(string) {
41
52
  }
42
53
 
43
54
  type Props = {
44
- pathname: string;
45
- screenData: Record<string, any>;
46
55
  setToggleMenu: () => void;
47
56
  setCloseMenu: () => void;
48
57
  };
49
58
 
50
- export function Screen({
51
- setToggleMenu,
52
- setCloseMenu,
53
- screenData: _screenData,
54
- }: Props) {
59
+ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
55
60
  const theme = useTheme<BaseThemePropertiesMobile>();
56
61
  const navigation = useNavigation();
57
62
  const { plugins } = usePickFromState(["plugins"]);
@@ -68,10 +73,7 @@ export function Screen({
68
73
  const routeData = useRoute();
69
74
 
70
75
  const currentRiver = useScreenData(
71
- (routeData.screenData as ZappRiver)?.targetScreen
72
- ? (routeData.screenData as ZappRiver)?.targetScreen?.id ??
73
- navigation.activeRiver.id
74
- : (routeData.screenData as ZappRiver)?.screen_id
76
+ getScreenId(routeData.screenData, navigation.activeRiver)
75
77
  );
76
78
 
77
79
  const { title } = useNavbarState();
@@ -135,9 +137,9 @@ export function Screen({
135
137
  {...{ ...(navBarProps as MobileNavBarPluginProps), id: pathname }}
136
138
  />
137
139
 
138
- <OfflineFallbackScreen screenData={screenData}>
140
+ <OfflineFallbackScreen screenData={targetScreenData}>
139
141
  {/* @TODO RouteManager doesn't use props, can they be removed ? */}
140
- <RouteManager pathname={pathname} screenData={_screenData} />
142
+ <RouteManager pathname={pathname} screenData={screenData} />
141
143
  </OfflineFallbackScreen>
142
144
  </View>
143
145
  </ScreenContextProvider>
@@ -78,7 +78,7 @@ export const getStyles = (config): Partial<TVTabsStyles> => {
78
78
  },
79
79
  tvos: {
80
80
  marginTop: -1,
81
- }
81
+ },
82
82
  }),
83
83
  },
84
84
  tabsBackground: {
@@ -4,6 +4,7 @@ import { render } from "@testing-library/react-native";
4
4
  import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
5
5
  import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
6
6
  import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
7
+ import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
7
8
 
8
9
  import { PlayerLiveImage } from "../PlayerLiveImageComponent";
9
10
 
@@ -18,6 +19,8 @@ jest.mock(
18
19
  })
19
20
  );
20
21
 
22
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
23
+
21
24
  const Wrapper = ({ children }: { children: React.ReactChildren }) => (
22
25
  <ThemeContext.Provider
23
26
  value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
@@ -46,6 +49,8 @@ describe("PlayerLiveImageComponent", () => {
46
49
  controller: new Player({}),
47
50
  Component: () => null,
48
51
  }));
52
+
53
+ jest.spyOn(navigationHooks, "useIsScreenActive").mockReturnValue(true);
49
54
  });
50
55
 
51
56
  it("should render correctly with default props", () => {
@@ -12,11 +12,16 @@ export function withComponentsMapProvider(Component: React.ComponentType<any>) {
12
12
  };
13
13
 
14
14
  const setComponentHeightById = (id: string | number, height: number) => {
15
- componentsHeightMapRef.current = { ...componentsHeightMapRef.current, [id]: height };
15
+ componentsHeightMapRef.current = {
16
+ ...componentsHeightMapRef.current,
17
+ [id]: height,
18
+ };
16
19
  };
17
20
 
18
21
  return (
19
- <ComponentsMapProvider {...{ setComponentHeightById, getComponentHeightById }}>
22
+ <ComponentsMapProvider
23
+ {...{ setComponentHeightById, getComponentHeightById }}
24
+ >
20
25
  <Component {...props} />
21
26
  </ComponentsMapProvider>
22
27
  );
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.9262886003",
3
+ "version": "12.0.0-alpha.9531194637",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -34,10 +34,10 @@
34
34
  "redux-mock-store": "^1.5.3"
35
35
  },
36
36
  "dependencies": {
37
- "@applicaster/applicaster-types": "12.0.0-alpha.9262886003",
38
- "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.9262886003",
39
- "@applicaster/zapp-react-native-redux": "12.0.0-alpha.9262886003",
40
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.9262886003",
37
+ "@applicaster/applicaster-types": "12.0.0-alpha.9531194637",
38
+ "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.9531194637",
39
+ "@applicaster/zapp-react-native-redux": "12.0.0-alpha.9531194637",
40
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.9531194637",
41
41
  "promise": "^8.3.0",
42
42
  "react-router-native": "^5.1.2",
43
43
  "url": "^0.11.0",