@applicaster/zapp-react-native-ui-components 12.0.0-alpha.7528906949 → 12.0.0-alpha.7531504237

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/Components/Cell/Cell.tsx +26 -5
  2. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  3. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  4. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  5. package/Components/Layout/TV/__tests__/index.test.tsx +2 -1
  6. package/Components/Layout/TV/index.tsx +11 -65
  7. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
  8. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -7
  9. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +57 -0
  10. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  11. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  12. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  13. package/Components/MasterCell/dataAdapter.ts +21 -7
  14. package/Components/MasterCell/index.tsx +5 -3
  15. package/Components/Navigator/StackNavigator.tsx +4 -1
  16. package/Components/PlayerContainer/PlayerContainer.tsx +2 -5
  17. package/Components/Screen/TV/index.web.tsx +9 -30
  18. package/Components/Screen/index.tsx +27 -58
  19. package/Components/Screen/navigationHandler.ts +5 -0
  20. package/Components/ScreenResolver/index.tsx +6 -11
  21. package/Components/Transitioner/Scene.tsx +12 -11
  22. package/Components/Transitioner/Transitioner.tsx +17 -15
  23. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
  24. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  25. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
  26. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  27. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +31 -7
  28. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +9 -2
  29. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +23 -5
  30. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +28 -8
  31. package/Components/VideoModal/ModalAnimation/utils.ts +1 -0
  32. package/Components/VideoModal/PlayerWrapper.tsx +1 -1
  33. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +48 -2
  34. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  35. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  36. package/package.json +5 -5
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { join, path, merge } from "ramda";
2
+ import { join, merge, path } from "ramda";
3
3
  import { View } from "react-native";
4
4
 
5
5
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
@@ -11,6 +11,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
11
 
12
12
  import { CellWithFocusable } from "./CellWithFocusable";
13
13
  import { BaseFocusable } from "../BaseFocusable";
14
+ import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
14
15
 
15
16
  type Props = {
16
17
  item: {
@@ -66,6 +67,10 @@ type Props = {
66
67
  behavior: Behavior;
67
68
  };
68
69
 
70
+ type State = {
71
+ hasFocusableInside: boolean;
72
+ };
73
+
69
74
  const baseCellStyles = {
70
75
  height: "100%",
71
76
  display: "flex",
@@ -77,7 +82,7 @@ const touchableStyles = {
77
82
  height: "100%",
78
83
  } as const;
79
84
 
80
- export class CellComponent extends React.Component<Props> {
85
+ export class CellComponent extends React.Component<Props, State> {
81
86
  constructor(props) {
82
87
  super(props);
83
88
  this.onPress = this.onPress.bind(this);
@@ -87,6 +92,10 @@ export class CellComponent extends React.Component<Props> {
87
92
  this.hasReceivedFocus = this.hasReceivedFocus.bind(this);
88
93
  this.scrollVertically = this.scrollVertically.bind(this);
89
94
  this.scrollToIndex = this.scrollToIndex.bind(this);
95
+
96
+ this.state = {
97
+ hasFocusableInside: props.CellRenderer.hasFocusableInside?.(props.item),
98
+ };
90
99
  }
91
100
 
92
101
  setScreenLayout(componentAnchorPointY, screenLayout) {
@@ -139,6 +148,10 @@ export class CellComponent extends React.Component<Props> {
139
148
  shouldScrollVertically?.(mouse, focusable, id, title)
140
149
  ) {
141
150
  this.scrollVertically(focusable);
151
+
152
+ const accessibilityManager = AccessibilityManager.getInstance();
153
+ // Text from DSP should be localized already
154
+ accessibilityManager.readText({ text: title });
142
155
  }
143
156
  }
144
157
  }
@@ -187,6 +200,16 @@ export class CellComponent extends React.Component<Props> {
187
200
  return !isFocusable ? false : focused || focusableFocused;
188
201
  }
189
202
 
203
+ componentDidUpdate(prevProps: Readonly<Props>) {
204
+ if (prevProps.item !== this.props.item) {
205
+ this.setState({
206
+ hasFocusableInside: this.props.CellRenderer.hasFocusableInside?.(
207
+ this.props.item
208
+ ),
209
+ });
210
+ }
211
+ }
212
+
190
213
  render() {
191
214
  const {
192
215
  item,
@@ -215,9 +238,7 @@ export class CellComponent extends React.Component<Props> {
215
238
  this.onFocus(focusable, mouse);
216
239
  };
217
240
 
218
- const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
219
-
220
- if (hasFocusableInside) {
241
+ if (this.state.hasFocusableInside) {
221
242
  return (
222
243
  <CellWithFocusable
223
244
  CellRenderer={CellRenderer}
@@ -5,13 +5,30 @@ import * as R from "ramda";
5
5
  import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext";
6
6
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
7
7
  import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
8
- import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
8
+ import {
9
+ useCurrentScreenData,
10
+ useNavbarState,
11
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
9
12
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
10
13
 
11
14
  import { useScreenConfiguration } from "../../River/useScreenConfiguration";
12
- import { routeIsPlayerScreen } from "@applicaster/zapp-react-native-utils/navigationUtils";
15
+ import {
16
+ findMenuPlugin,
17
+ getNavigationProps,
18
+ routeIsPlayerScreen,
19
+ } from "@applicaster/zapp-react-native-utils/navigationUtils";
20
+ import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
21
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
22
+ import { NavBarContainer } from "./NavBarContainer";
23
+
24
+ type ComponentsExtraProps = {
25
+ Background?: Record<string, any>;
26
+ NavBar?: Record<string, any>;
27
+ };
13
28
 
14
29
  type Props = {
30
+ ComponentsExtraProps?: ComponentsExtraProps;
31
+ NavBar: React.ComponentType<any>;
15
32
  children: React.ReactNode;
16
33
  };
17
34
 
@@ -30,9 +47,13 @@ const styles = StyleSheet.create({
30
47
  container: { flex: 1, height: "100%", width: "100%" },
31
48
  });
32
49
 
50
+ const isTVOS = isApplePlatform();
51
+
33
52
  // eslint-disable-next-line react/display-name
34
53
  export const ScreenContainer = React.memo(function ScreenContainer({
35
54
  children,
55
+ ComponentsExtraProps,
56
+ NavBar,
36
57
  }: Props) {
37
58
  const { screenMarginBottom } = React.useContext(ScreenLayoutContext);
38
59
  const { currentRoute, screenData } = useNavigation();
@@ -80,9 +101,62 @@ export const ScreenContainer = React.memo(function ScreenContainer({
80
101
  [themeStyles]
81
102
  );
82
103
 
104
+ const navigator = useNavigation();
105
+ const { activeRiver } = navigator;
106
+ const { title, visible } = useNavbarState();
107
+
108
+ const { plugins = [] } = usePickFromState([
109
+ "appState",
110
+ "remoteConfigurations",
111
+ "plugins",
112
+ ]);
113
+
114
+ const navigationProps = getNavigationProps({
115
+ navigator,
116
+ title,
117
+ category: "menu",
118
+ });
119
+
120
+ const menuPlugin = React.useMemo(
121
+ () => findMenuPlugin(activeRiver?.navigations, plugins),
122
+ [activeRiver?.navigations]
123
+ );
124
+
125
+ const NavBarComponent = React.useMemo(
126
+ () => NavBar || (menuPlugin.module as React.ComponentType<any>),
127
+ []
128
+ );
129
+
130
+ const [navBarReady, setNavBarReady] = React.useState(false);
131
+
132
+ const navBarContainer = (
133
+ <NavBarContainer isVisible={visible} onReady={setNavBarReady}>
134
+ <NavBarComponent
135
+ ref={ComponentsExtraProps?.NavBar?.ref}
136
+ isVisible={visible}
137
+ menuPlugin={menuPlugin}
138
+ navigationProps={navigationProps}
139
+ {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
140
+ />
141
+ </NavBarContainer>
142
+ );
143
+
83
144
  return (
84
- <View testID="screen-container" style={viewStyles}>
85
- {children}
86
- </View>
145
+ <>
146
+ {!isTVOS ? navBarContainer : null}
147
+ {navBarReady ? (
148
+ /**
149
+ Need to re-mount this component on each navigation event
150
+ It's a hack to work around the fact that we don't support
151
+ correct screen rendering in our navigator (shared currentRoute state)
152
+ **/
153
+ <View testID="screen-container" style={viewStyles}>
154
+ {children}
155
+ </View>
156
+ ) : null}
157
+ {/** Render NavBarContainer over ScreenContainer to let tvOS native
158
+ focus manager works correctly to focus nav bar items first **/}
159
+ {isTVOS ? navBarContainer : null}
160
+ </>
87
161
  );
88
162
  });
@@ -1,14 +1,27 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { render } from "@testing-library/react-native";
3
+ import { render, waitFor } from "@testing-library/react-native";
4
+ import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
4
5
 
5
6
  import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext";
6
7
 
7
8
  const navigator_mock = {
8
9
  currentRoute: "/river/A1234",
9
10
  screenData: {},
11
+ activeRiver: {
12
+ navigations: {},
13
+ id: "A1234",
14
+ home: false,
15
+ },
10
16
  };
11
17
 
18
+ jest.mock("@applicaster/zapp-react-native-utils/navigationUtils", () => ({
19
+ ...jest.requireActual<any>(
20
+ "@applicaster/zapp-react-native-utils/navigationUtils"
21
+ ),
22
+ findMenuPlugin: () => ({}),
23
+ }));
24
+
12
25
  jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
13
26
  useRiverInitialState: () => ({}),
14
27
  }));
@@ -17,13 +30,13 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
17
30
  useNavigation: () => navigator_mock,
18
31
  }));
19
32
 
20
- jest.mock("../../../River/useScreenConfiguration.ts", () => ({
33
+ jest.mock("../../../River/useScreenConfiguration", () => ({
21
34
  useScreenConfiguration: () => ({}),
22
35
  }));
23
36
 
24
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
25
- useCurrentScreenData: jest.fn(() => ({})),
26
- }));
37
+ jest.mock(
38
+ "@applicaster/zapp-react-native-utils/reactHooks/screen/useCurrentScreenData"
39
+ );
27
40
 
28
41
  jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
29
42
  useTheme: () => ({}),
@@ -44,42 +57,39 @@ describe("ScreenContainer", () => {
44
57
  const setScreenLayout = () => {};
45
58
 
46
59
  const wrapper = ({ children }) => (
47
- <ScreenLayoutContext.Provider value={{ ...screenLayout, setScreenLayout }}>
48
- {children}
49
- </ScreenLayoutContext.Provider>
60
+ <WrappedWithProviders>
61
+ <ScreenLayoutContext.Provider
62
+ value={{ ...screenLayout, setScreenLayout }}
63
+ >
64
+ <ScreenContainer NavBar={View}>{children}</ScreenContainer>
65
+ </ScreenLayoutContext.Provider>
66
+ </WrappedWithProviders>
50
67
  );
51
68
 
52
69
  const TestComp = () => <View testID="test-component" />;
53
70
 
54
71
  it("renders", () => {
55
- const { toJSON } = render(
56
- <ScreenContainer>
57
- <TestComp />
58
- </ScreenContainer>,
59
- { wrapper }
60
- );
72
+ const { toJSON } = render(<TestComp />, { wrapper });
61
73
 
62
74
  expect(toJSON()).toMatchSnapshot();
63
75
  });
64
76
 
65
- it("renders passed component", () => {
66
- const { getByTestId } = render(
67
- <ScreenContainer>
68
- <TestComp />
69
- </ScreenContainer>,
70
- { wrapper }
71
- );
77
+ it("renders passed component", async () => {
78
+ const { getByTestId } = render(<TestComp />, { wrapper });
79
+
80
+ await waitFor(() => {
81
+ return expect(getByTestId("screen-container")).toBeDefined();
82
+ });
72
83
 
73
84
  expect(getByTestId("test-component")).toBeDefined();
74
85
  });
75
86
 
76
- it("sets margins provided by the theme", () => {
77
- const { getByTestId } = render(
78
- <ScreenContainer>
79
- <TestComp />
80
- </ScreenContainer>,
81
- { wrapper }
82
- );
87
+ it("sets margins provided by the theme", async () => {
88
+ const { getByTestId } = render(<TestComp />, { wrapper });
89
+
90
+ await waitFor(() => {
91
+ return expect(getByTestId("screen-container")).toBeDefined();
92
+ });
83
93
 
84
94
  const screen = getByTestId("screen-container");
85
95
  expect(screen.props.style).toMatchSnapshot();
@@ -1,28 +1,40 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`ScreenContainer renders 1`] = `
4
- <View
4
+ <RNCSafeAreaProvider
5
+ onInsetsChange={[Function]}
5
6
  style={
6
7
  Array [
7
8
  Object {
8
9
  "flex": 1,
9
- "height": "100%",
10
- "width": "100%",
11
- },
12
- Object {
13
- "backgroundColor": "transparent",
14
- "marginBottom": 10,
15
- "paddingBottom": 0,
16
- "paddingTop": 0,
17
10
  },
11
+ undefined,
18
12
  ]
19
13
  }
20
- testID="screen-container"
21
14
  >
22
15
  <View
23
- testID="test-component"
24
- />
25
- </View>
16
+ style={
17
+ Array [
18
+ Object {
19
+ "position": "absolute",
20
+ "top": 0,
21
+ "width": 1920,
22
+ "zIndex": 10,
23
+ },
24
+ Object {
25
+ "maxHeight": 10,
26
+ },
27
+ ]
28
+ }
29
+ testID="nav-bar-container"
30
+ >
31
+ <View
32
+ isVisible={true}
33
+ menuPlugin={Object {}}
34
+ navigationProps={null}
35
+ />
36
+ </View>
37
+ </RNCSafeAreaProvider>
26
38
  `;
27
39
 
28
40
  exports[`ScreenContainer sets margins provided by the theme 1`] = `
@@ -21,10 +21,11 @@ const mockStore = configureStore()({
21
21
  describe("Layout TV", () => {
22
22
  const navigator = {
23
23
  currentRoute: "/river/A1234",
24
+ canGoBack: jest.fn(),
24
25
  mainStack: [
25
26
  {
26
27
  route: "/river/A1234",
27
- state: "state",
28
+ state: { screen: {} },
28
29
  },
29
30
  ],
30
31
  };
@@ -4,22 +4,14 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
4
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
5
5
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
6
6
 
7
- import {
8
- getNavigationProps,
9
- resolveNavigationPlugin,
10
- routeIsPlayerScreen,
11
- } from "@applicaster/zapp-react-native-utils/navigationUtils";
12
-
13
7
  import { getBackgroundImageUrl } from "../utils";
14
8
  import { LayoutContainer } from "./LayoutContainer";
15
- import { NavBarContainer } from "./NavBarContainer";
16
9
  import { ScreenContainer } from "./ScreenContainer";
17
10
 
18
11
  import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
19
- import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
20
12
  import { PathnameContext } from "../../../Contexts/PathnameContext";
21
- import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
22
13
  import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
14
+ import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
23
15
 
24
16
  type Components = {
25
17
  NavBar: React.ComponentType<any>;
@@ -40,20 +32,9 @@ type Props = {
40
32
  const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
41
33
  const navigator = useNavigation();
42
34
  const theme = useTheme();
43
- const { title, visible } = useNavbarState();
44
- const { activeRiver, currentRoute } = navigator;
45
-
46
- const {
47
- appState: { appReady = false } = {},
48
- remoteConfigurations,
49
- plugins = [],
50
- } = usePickFromState(["appState", "remoteConfigurations", "plugins"]);
51
35
 
52
- const navigationProps = getNavigationProps({
53
- navigator,
54
- title,
55
- category: "menu",
56
- });
36
+ const { appState: { appReady = false } = {}, remoteConfigurations } =
37
+ usePickFromState(["appState", "remoteConfigurations", "plugins"]);
57
38
 
58
39
  const backgroundColor = React.useMemo(() => theme.app_background_color, []);
59
40
 
@@ -62,37 +43,6 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
62
43
  [remoteConfigurations]
63
44
  );
64
45
 
65
- const menuPlugin = React.useMemo(
66
- () =>
67
- resolveNavigationPlugin({
68
- category: "menu",
69
- navigations: activeRiver?.navigations,
70
- plugins,
71
- }) as QuickBrickPlugin,
72
- []
73
- );
74
-
75
- const NavBar = React.useMemo(
76
- () => Components.NavBar || (menuPlugin.module as React.ComponentType<any>),
77
- []
78
- );
79
-
80
- const [navBarReady, setNavBarReady] = React.useState(false);
81
-
82
- const navBarContainer = (
83
- <NavBarContainer isVisible={visible} onReady={setNavBarReady}>
84
- <NavBar
85
- ref={ComponentsExtraProps?.NavBar?.ref}
86
- isVisible={visible && !routeIsPlayerScreen(currentRoute)}
87
- menuPlugin={menuPlugin}
88
- navigationProps={navigationProps}
89
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
90
- />
91
- </NavBarContainer>
92
- );
93
-
94
- const isTVOS = isApplePlatform();
95
-
96
46
  if (!appReady) {
97
47
  return null;
98
48
  }
@@ -107,18 +57,14 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
107
57
  >
108
58
  <ScreenDataContext.Provider value={navigator.data}>
109
59
  <PathnameContext.Provider value={navigator.currentRoute}>
110
- {!isTVOS ? navBarContainer : null}
111
- {navBarReady ? (
112
- /**
113
- Need to re-mount this component on each navigation event
114
- It's a hack to work around the fact that we don't support
115
- correct screen rendering in our navigator (shared currentRoute state)
116
- **/
117
- <ScreenContainer>{children}</ScreenContainer>
118
- ) : null}
119
- {/** Render NavBarContainer over ScreenContainer to let tvOS native
120
- focus manager works correctly to focus nav bar items first **/}
121
- {isTVOS ? navBarContainer : null}
60
+ <ScreenContextProvider pathname={navigator.currentRoute}>
61
+ <ScreenContainer
62
+ ComponentsExtraProps={ComponentsExtraProps}
63
+ NavBar={Components.NavBar}
64
+ >
65
+ {children}
66
+ </ScreenContainer>
67
+ </ScreenContextProvider>
122
68
  </PathnameContext.Provider>
123
69
  </ScreenDataContext.Provider>
124
70
  </Components.Background>
@@ -53,6 +53,7 @@ export function ActionButton(props: Props) {
53
53
  const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
54
54
  const actionContext = useActions(action?.identifier);
55
55
 
56
+ // TODO: add subscription API for action availability
56
57
  const actionDisabled =
57
58
  typeof actionContext?.isActionAvailable === "function" &&
58
59
  !actionContext.isActionAvailable(item);
@@ -68,7 +69,7 @@ export function ActionButton(props: Props) {
68
69
  if (actionDisabled || !actionContext) return;
69
70
 
70
71
  setActionState(actionContext.initialEntryState(item));
71
- }, [actionDisabled, item?.id]);
72
+ }, [actionDisabled, item?.id, actionContext]);
72
73
 
73
74
  const onPress = useCallback(() => {
74
75
  actionContext.invokeAction(item, {
@@ -117,9 +117,6 @@ export const BorderContainerView = (props: Props) => {
117
117
  children,
118
118
  } = props;
119
119
 
120
- const borderStyleForMissingBorder =
121
- style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
122
-
123
120
  const padding =
124
121
  borderPosition === "outside"
125
122
  ? {
@@ -131,10 +128,7 @@ export const BorderContainerView = (props: Props) => {
131
128
  : {};
132
129
 
133
130
  return (
134
- <View
135
- {...props}
136
- style={[style, styles.container, borderStyleForMissingBorder]}
137
- >
131
+ <View {...props} style={[style, styles.container]} pointerEvents="box-none">
138
132
  <Border style={style} padding={padding} borderPosition={borderPosition} />
139
133
  {children}
140
134
  </View>
@@ -0,0 +1,57 @@
1
+ import { ImageStyle } from "react-native";
2
+
3
+ import {
4
+ getImageContainerMarginStyles,
5
+ ifElseFocusedSelected,
6
+ } from "@applicaster/zapp-react-native-utils/cellUtils";
7
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
8
+
9
+ export const ImageBorderContainer = ({
10
+ value,
11
+ state,
12
+ imageStyles,
13
+ }: {
14
+ value: (key: string) => string;
15
+ state: CellState;
16
+ imageStyles: ImageStyle;
17
+ }) => {
18
+ return {
19
+ type: "BorderContainerView",
20
+ style: {
21
+ ...getImageContainerMarginStyles({ value }),
22
+ position: "absolute",
23
+ top: 0,
24
+ zIndex: 1,
25
+ borderWidth: value("image_border_size"),
26
+ borderColor: ifElseFocusedSelected(
27
+ state,
28
+ value("image_focused_border_color"),
29
+ value("image_selected_border_color"),
30
+ value("image_focused_selected_border_color"),
31
+ value("image_border_color")
32
+ ),
33
+ borderRadius: toNumberWithDefaultZero(value("image_corner_radius")),
34
+ },
35
+ additionalProps: {
36
+ borderPosition: value("image_border_position"),
37
+ borderPaddingTop: toNumberWithDefaultZero(
38
+ value("image_border_padding_top")
39
+ ),
40
+ borderPaddingRight: toNumberWithDefaultZero(
41
+ value("image_border_padding_right")
42
+ ),
43
+ borderPaddingBottom: toNumberWithDefaultZero(
44
+ value("image_border_padding_bottom")
45
+ ),
46
+ borderPaddingLeft: toNumberWithDefaultZero(
47
+ value("image_border_padding_left")
48
+ ),
49
+ },
50
+ elements: [
51
+ {
52
+ type: "View",
53
+ style: imageStyles,
54
+ },
55
+ ],
56
+ };
57
+ };
@@ -108,6 +108,26 @@ const prepareEntry = (entry) => {
108
108
  };
109
109
  }
110
110
 
111
+ const previewPlayback =
112
+ entry.extensions?.["brightcove"]?.["preview_playback"];
113
+
114
+ if (previewPlayback) {
115
+ return {
116
+ ...entry,
117
+ extensions: {
118
+ ...entry.extensions,
119
+ brightcove: {
120
+ ...entry?.extensions?.["brightcove"],
121
+ video_id: previewPlayback,
122
+ },
123
+ },
124
+ };
125
+ }
126
+
127
+ if (entry.extensions?.["brightcove"]?.["video_id"]) {
128
+ return entry;
129
+ }
130
+
111
131
  const src = entry.content?.src;
112
132
 
113
133
  if (!src) {
@@ -15,6 +15,7 @@ import { BorderContainerView } from "./BorderContainerView";
15
15
  import { CellBadge } from "./CellBadge";
16
16
  import { TvActionButtons } from "./tv/TvActionButtons";
17
17
  import { ButtonContainerView } from "./tv/ButtonContainerView";
18
+ import { ImageBorderContainer } from "./ImageBorderContainer";
18
19
 
19
20
  export const defaultComponents = {
20
21
  View,
@@ -28,6 +29,7 @@ export const defaultComponents = {
28
29
  ProgressBar,
29
30
  Toggle,
30
31
  LiveImage,
32
+ ImageBorderContainer,
31
33
  BorderContainerView,
32
34
  DynamicBadge,
33
35
  SecondaryImage,
@@ -5,6 +5,7 @@ import * as R from "ramda";
5
5
 
6
6
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
7
7
  import { normalizeProgressValue } from "./utils";
8
+ import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
8
9
 
9
10
  const ACTION_NAME = "continue-watching";
10
11
  const DEFAULT_FILL = 0;
@@ -27,6 +28,7 @@ const getProgressValue = (
27
28
 
28
29
  export const useFillInPercent = (entry: ZappEntry): number => {
29
30
  const action = useActions(ACTION_NAME);
31
+ const isActive = useIsScreenActive();
30
32
 
31
33
  const [fillInPercent, setFillInPercent] =
32
34
  React.useState<number>(DEFAULT_FILL);
@@ -39,6 +41,10 @@ export const useFillInPercent = (entry: ZappEntry): number => {
39
41
  }, []);
40
42
 
41
43
  React.useEffect(() => {
44
+ if (!isActive) {
45
+ return;
46
+ }
47
+
42
48
  // refresh progress in UI when it was changed in CW
43
49
  const unsubscribe = action?.addDataSourceListener?.(() => {
44
50
  getProgressValue(action, entry, (progress) => {
@@ -49,7 +55,7 @@ export const useFillInPercent = (entry: ZappEntry): number => {
49
55
  return () => {
50
56
  unsubscribe?.();
51
57
  };
52
- }, []);
58
+ }, [isActive]);
53
59
 
54
60
  return fillInPercent;
55
61
  };