@applicaster/zapp-react-native-ui-components 11.0.0-rc.99 → 12.0.0-rc.1

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 (53) hide show
  1. package/Components/BaseFocusable/index.ios.ts +1 -1
  2. package/Components/Cell/Cell.tsx +5 -13
  3. package/Components/Cell/{CellWithFocusable.js → CellWithFocusable.tsx} +13 -11
  4. package/Components/Cell/TvOSCellComponent.tsx +12 -10
  5. package/Components/FastImage/index.ios.js +3 -0
  6. package/Components/Focusable/FocusableTvOS.tsx +4 -1
  7. package/Components/FocusableCell/{index.js → index.tsx} +8 -5
  8. package/Components/FocusableGroup/FocusableTvOS.tsx +2 -2
  9. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +13 -8
  10. package/Components/HandlePlayable/HandlePlayable.tsx +2 -2
  11. package/Components/HookRenderer/HookRenderer.tsx +9 -6
  12. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +1 -1
  13. package/Components/Layout/TV/index.tsx +9 -13
  14. package/Components/Layout/index.tsx +9 -1
  15. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +3 -1
  16. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +22 -19
  17. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +1 -0
  18. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +4 -1
  19. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +2 -0
  20. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/CollapsibleTextContainer.tsx +9 -3
  21. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/__snapshots__/index.test.tsx.snap +7 -1
  22. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +12 -4
  23. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +23 -9
  24. package/Components/MasterCell/hoc/withAsyncRender.tsx +8 -4
  25. package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +12 -6
  26. package/Components/MasterCell/hooks/useAsyncRendering/__tests__/MasterCellAsyncRenderManager.test.ts +21 -0
  27. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +15 -13
  28. package/Components/MasterCell/utils/index.ts +143 -19
  29. package/Components/PlayerContainer/PlayerContainer.tsx +10 -6
  30. package/Components/River/ComponentsMap/ComponentsMap.tsx +4 -1
  31. package/Components/River/River.tsx +3 -4
  32. package/Components/River/TV/River.tsx +9 -4
  33. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -0
  34. package/Components/River/index.tsx +3 -1
  35. package/Components/Screen/__tests__/Screen.test.tsx +6 -3
  36. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
  37. package/Components/Screen/index.tsx +12 -44
  38. package/Components/Screen/navigationHandler.ts +1 -1
  39. package/Components/Spinner/SpinnerComponent.tsx +6 -2
  40. package/Components/VideoLive/LiveImageManager.ts +24 -9
  41. package/Components/VideoLive/PlayerLiveImageComponent.tsx +23 -1
  42. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +74 -0
  43. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +47 -0
  44. package/Components/VideoLive/__tests__/utils.test.ts +109 -0
  45. package/Components/VideoLive/utils.ts +40 -0
  46. package/Components/VideoModal/PlayerDetails.tsx +42 -6
  47. package/Components/VideoModal/PlayerWrapper.tsx +32 -29
  48. package/Components/VideoModal/VideoModal.tsx +20 -17
  49. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +21 -9
  50. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +14 -24
  51. package/Contexts/InteractionManagerContext/index.ts +0 -2
  52. package/Contexts/ScreenContext/index.tsx +118 -0
  53. package/package.json +5 -5
@@ -1,19 +1,15 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
  import React, { useMemo } from "react";
3
3
  import * as R from "ramda";
4
- import { Platform, StatusBar, View } from "react-native";
4
+ import { View } from "react-native";
5
5
  import { RouteManager } from "../RouteManager";
6
6
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
7
- import {
8
- useNavBarStateForScreen,
9
- useNavigation,
10
- } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
11
7
  import { useScreenOrientationHandler } from "./orientationHandler";
12
- import { isNavBarVisible } from "./navigationHandler";
13
8
  import { useScreenConfiguration } from "../River/useScreenConfiguration";
14
9
  import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
15
10
  import type { ZappNavigationProps } from "@applicaster/zapp-react-native-flow-types/index";
16
11
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
12
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
17
13
 
18
14
  type Props = {
19
15
  pathname: string;
@@ -71,12 +67,8 @@ export function Screen(props: Props) {
71
67
 
72
68
  // Gets the data for the current screen configuration
73
69
  const currentScreenData = useCurrentScreenData();
74
-
75
70
  const theme = useTheme();
76
-
77
- const navigator = useNavigation();
78
- const screenConfig = useScreenConfiguration(currentScreenData.id);
79
- const { backgroundColor } = useMemo(() => screenConfig, [pathname]);
71
+ const { backgroundColor } = useScreenConfiguration(currentScreenData.id);
80
72
 
81
73
  const style = React.useMemo(
82
74
  () => ({
@@ -88,44 +80,20 @@ export function Screen(props: Props) {
88
80
  [theme.app_background_color, backgroundColor]
89
81
  );
90
82
 
91
- const { isNavBarVisible: showNavBar, canGoBack } =
92
- useNavBarStateForScreen(pathname);
93
-
94
- const navBarVisible = useMemo(
95
- () =>
96
- isNavBarVisible(
97
- pathname,
98
- currentScreenData || screenData,
99
- showNavBar,
100
- canGoBack(),
101
- navigator.videoModalState
102
- ),
103
- [pathname, showNavBar, navigator.videoModalState]
104
- );
105
-
106
- const navBarProps = useMemo(() => props.navBarProps, []);
107
-
108
83
  const targetScreenData =
109
84
  currentScreenData || screenData?.targetScreen || screenData;
110
85
 
111
86
  useScreenOrientationHandler({ screenData: targetScreenData });
112
87
 
113
- const shouldHideStatusBar = useMemo(
114
- () =>
115
- !navBarVisible &&
116
- navigator.videoModalState?.mode === "FULLSCREEN" &&
117
- navigator.videoModalState?.visible === true,
118
- [navBarVisible, navigator.videoModalState]
119
- );
120
-
121
88
  return (
122
- <View style={style}>
123
- {navBarVisible && <NavBar key={pathname} {...navBarProps} />}
124
- {shouldHideStatusBar && <StatusBar hidden={Platform.OS === "android"} />}
125
-
126
- <OfflineFallbackScreen screenData={screenData}>
127
- <RouteManager pathname={pathname} screenData={screenData} />
128
- </OfflineFallbackScreen>
129
- </View>
89
+ <ScreenContextProvider pathname={pathname}>
90
+ <View style={style}>
91
+ <NavBar key={pathname} {...props.navBarProps} />
92
+
93
+ <OfflineFallbackScreen screenData={screenData}>
94
+ <RouteManager pathname={pathname} screenData={screenData} />
95
+ </OfflineFallbackScreen>
96
+ </View>
97
+ </ScreenContextProvider>
130
98
  );
131
99
  }
@@ -19,7 +19,7 @@ export function isNavBarVisible(
19
19
  screenData,
20
20
  showNavBar,
21
21
  canGoBack,
22
- videoModalState = null
22
+ videoModalState: QuickBrickVideoModalState | null = null
23
23
  ) {
24
24
  /* screenData is not actual navigator.data
25
25
  * or navigator.screenData,
@@ -8,11 +8,15 @@ type ActivityIndicatorThemeValues = {
8
8
  loading_spinner_color: ActivityIndicatorProps["color"];
9
9
  };
10
10
 
11
- export function SpinnerComponent(props: ActivityIndicatorProps) {
11
+ type Props = ActivityIndicatorProps & { showAnyway?: boolean };
12
+
13
+ export function SpinnerComponent(props: Props) {
12
14
  const { loading_spinner_size, loading_spinner_color } =
13
15
  useTheme() as ActivityIndicatorThemeValues;
14
16
 
15
- if (isAndroidTVPlatform()) {
17
+ const { showAnyway = false } = props;
18
+
19
+ if (isAndroidTVPlatform() && !showAnyway) {
16
20
  return null;
17
21
  }
18
22
 
@@ -351,9 +351,11 @@ export class LiveImageManager implements PlayerLifecycleListener {
351
351
  }, primaryPlayerId: ${this.primaryPlayer?.playerId}`
352
352
  );
353
353
 
354
+ const isCurrentItemEnded = this.currentlyPlaying === item;
355
+
354
356
  // TODO: This branch was used when we had play button to toggle replay.
355
357
  // Now we mute button instead but we keep it just in case.
356
- if (IS_ALLOWED_REPLAY && !isTV() && this.currentlyPlaying === item) {
358
+ if (IS_ALLOWED_REPLAY && !isTV() && isCurrentItemEnded) {
357
359
  this.currentlyPlaying.player.seekTo(0);
358
360
  this.currentlyPlaying.player.pause();
359
361
 
@@ -362,14 +364,16 @@ export class LiveImageManager implements PlayerLifecycleListener {
362
364
  item.setMode(LiveImageType.Image);
363
365
  }
364
366
 
365
- this.invokeListenersUpdate({
366
- callbackName: "onEnd",
367
- event: {
368
- item,
369
- playerId: this.currentlyPlaying?.playerId,
370
- primaryPlayerId: this.primaryPlayer?.playerId,
371
- },
372
- });
367
+ // Prevent receiving onEnd event from both `close` and `end` player events
368
+ isCurrentItemEnded &&
369
+ this.invokeListenersUpdate({
370
+ callbackName: "onEnd",
371
+ event: {
372
+ item,
373
+ playerId: this.currentlyPlaying?.playerId,
374
+ primaryPlayerId: this.primaryPlayer?.playerId,
375
+ },
376
+ });
373
377
  };
374
378
 
375
379
  onLiveImageError = (item: LiveImage, error: Error) => {
@@ -484,4 +488,15 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
484
488
 
485
489
  LiveImageManager.instance.onLiveImageEnded(this);
486
490
  };
491
+
492
+ onPlayerClose = () => {
493
+ log_info(
494
+ `onPlayerClose: live-image, player closed, switching back to image, ${playerInfo(
495
+ this.player
496
+ )}`
497
+ );
498
+
499
+ // TODO: we maybe want to add onPlayerClose to separate completion behavior
500
+ LiveImageManager.instance.onLiveImageEnded(this);
501
+ };
487
502
  }
@@ -24,6 +24,7 @@ import { overlayFadeIn } from "./animationUtils";
24
24
  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
+ import { getAutoplaySettings } from "./utils";
27
28
 
28
29
  const { log_error } = loggerLiveImageComponent;
29
30
 
@@ -114,6 +115,11 @@ const PlayerLiveImageComponent = (props: Props) => {
114
115
  }
115
116
  }, [playerId, item?.id]);
116
117
 
118
+ const { start, end } = React.useMemo(
119
+ () => getAutoplaySettings(item),
120
+ [item?.id]
121
+ );
122
+
117
123
  const controller = liveImageItem.getPlayer();
118
124
  const player = usePlayer(playerId);
119
125
 
@@ -121,6 +127,10 @@ const PlayerLiveImageComponent = (props: Props) => {
121
127
  ref.current = component;
122
128
  };
123
129
 
130
+ const onStop = React.useCallback(() => {
131
+ LiveImageManager.instance.pauseLiveImage(liveImageItem);
132
+ }, [liveImageItem]);
133
+
124
134
  React.useEffect(() => {
125
135
  // FIXME - find a more elegant way to disable live-image on cell for measurement
126
136
  if (isMeasurement(item)) {
@@ -147,8 +157,20 @@ const PlayerLiveImageComponent = (props: Props) => {
147
157
  id: "mute-action-button",
148
158
  listener: {
149
159
  onLoad: () => {
160
+ start && player.seekTo(start);
150
161
  setIsReady(true);
151
162
  },
163
+ onVideoProgress: ({ currentTime }) => {
164
+ if (start && currentTime < start) {
165
+ // fixes the case when the video is not seekable in onLoad callback
166
+ player.seekTo(start);
167
+ }
168
+
169
+ if (end && currentTime > end) {
170
+ onStop();
171
+ setIsReady(false);
172
+ }
173
+ },
152
174
  onPlayerMute: () => {
153
175
  setMuted(true);
154
176
  },
@@ -160,7 +182,7 @@ const PlayerLiveImageComponent = (props: Props) => {
160
182
  },
161
183
  },
162
184
  });
163
- }, [player]);
185
+ }, [player, onStop]);
164
186
 
165
187
  React.useEffect(() => {
166
188
  const subscription = AppState.addEventListener(
@@ -0,0 +1,74 @@
1
+ /* eslint-disable react/display-name */
2
+ import * as React from "react";
3
+ import { render } from "@testing-library/react-native";
4
+ import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
5
+ import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
6
+ import { PlayerLiveImage } from "../PlayerLiveImageComponent";
7
+
8
+ const seekTo = jest.fn();
9
+
10
+ jest.mock(
11
+ "@applicaster/zapp-react-native-utils/appUtils/playerManager/player",
12
+ () => ({
13
+ Player: {
14
+ seekTo,
15
+ },
16
+ })
17
+ );
18
+
19
+ describe("PlayerLiveImageComponent", () => {
20
+ const defaultProps = {
21
+ item: { id: "1", title: "Test", type: { value: "" } },
22
+ style: {},
23
+ playerId: "player1",
24
+ imageKey: "image1",
25
+ audioMutedByDefault: false,
26
+ screenConfig: {},
27
+ };
28
+
29
+ const autoplay_settings = {
30
+ start_time: "00:10",
31
+ end_time: "00:35",
32
+ };
33
+
34
+ beforeAll(() => {
35
+ jest.spyOn(PlayerFactory, "playerFactory").mockImplementation(() => ({
36
+ controller: new Player({}),
37
+ Component: () => null,
38
+ }));
39
+ });
40
+
41
+ it("should render correctly with default props", () => {
42
+ const component = render(<PlayerLiveImage {...defaultProps} />);
43
+
44
+ expect(component.toJSON()).toMatchSnapshot();
45
+ });
46
+
47
+ it("should call seekTo() on video loaded with autoplay settings", () => {
48
+ const props = {
49
+ ...defaultProps,
50
+ item: {
51
+ ...defaultProps.item,
52
+ extensions: { autoplay_settings },
53
+ },
54
+ };
55
+
56
+ render(<PlayerLiveImage {...props} />);
57
+
58
+ // TODO: implement this test
59
+ });
60
+
61
+ it("should call pauseLiveImage() on video reached end timestamp", () => {
62
+ const props = {
63
+ ...defaultProps,
64
+ item: {
65
+ ...defaultProps.item,
66
+ extensions: { autoplay_settings },
67
+ },
68
+ };
69
+
70
+ render(<PlayerLiveImage {...props} />);
71
+
72
+ // TODO: implement this test
73
+ });
74
+ });
@@ -0,0 +1,47 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`PlayerLiveImageComponent should render correctly with default props 1`] = `
4
+ <TrackedView
5
+ onPositionUpdated={[Function]}
6
+ testId="tracked-view-player1-Test"
7
+ >
8
+ <View
9
+ collapsable={false}
10
+ style={
11
+ Object {
12
+ "opacity": 1,
13
+ }
14
+ }
15
+ >
16
+ <View
17
+ accessibilityIgnoresInvertColors={true}
18
+ style={Object {}}
19
+ >
20
+ <Image
21
+ resizeMode="cover"
22
+ source={
23
+ Object {
24
+ "uri": undefined,
25
+ }
26
+ }
27
+ style={
28
+ Array [
29
+ Object {
30
+ "bottom": 0,
31
+ "left": 0,
32
+ "position": "absolute",
33
+ "right": 0,
34
+ "top": 0,
35
+ },
36
+ Object {
37
+ "height": undefined,
38
+ "width": undefined,
39
+ },
40
+ undefined,
41
+ ]
42
+ }
43
+ />
44
+ </View>
45
+ </View>
46
+ </TrackedView>
47
+ `;
@@ -0,0 +1,109 @@
1
+ import { parseTime, getAutoplaySettings } from "../utils";
2
+
3
+ describe("parseTime", () => {
4
+ it("should return the parsed time in seconds", () => {
5
+ expect(parseTime("01:30")).toBe(90);
6
+ expect(parseTime("00:45")).toBe(45);
7
+ expect(parseTime("10:00")).toBe(600);
8
+ });
9
+
10
+ it("should throw error for invalid time formats", () => {
11
+ const error = "Invalid time format";
12
+ expect(() => parseTime("")).toThrow(error);
13
+ expect(() => parseTime("abc")).toThrow(error);
14
+ expect(() => parseTime("12")).toThrow(error);
15
+ expect(() => parseTime(":12")).toThrow(error);
16
+ expect(() => parseTime("00:60")).toThrow(error);
17
+ expect(() => parseTime("-10:00")).toThrow(error);
18
+ });
19
+ });
20
+
21
+ describe("getAutoplaySettings", () => {
22
+ it("should return the autoplay settings with parsed start and end times", () => {
23
+ const item = {
24
+ extensions: {
25
+ autoplay_settings: {
26
+ start_time: "01:30",
27
+ end_time: "02:00",
28
+ },
29
+ },
30
+ };
31
+
32
+ const { start, end } = getAutoplaySettings(item);
33
+
34
+ expect(start).toBe(90);
35
+ expect(end).toBe(120);
36
+ });
37
+
38
+ it("should return null for missing start or end times", () => {
39
+ const item = {
40
+ extensions: {
41
+ autoplay_settings: {
42
+ start_time: "01:30",
43
+ },
44
+ },
45
+ };
46
+
47
+ const { start, end } = getAutoplaySettings(item);
48
+
49
+ expect(start).toBe(90);
50
+ expect(end).toBeNull();
51
+ });
52
+
53
+ it("should return null for invalid start or end times", () => {
54
+ const item = {
55
+ extensions: {
56
+ autoplay_settings: {
57
+ start_time: "abc",
58
+ end_time: "def",
59
+ },
60
+ },
61
+ };
62
+
63
+ const { start, end } = getAutoplaySettings(item);
64
+
65
+ expect(start).toBeNull();
66
+ expect(end).toBeNull();
67
+ });
68
+
69
+ it("should return null end time if start time greater than end time", () => {
70
+ const item = {
71
+ extensions: {
72
+ autoplay_settings: {
73
+ start_time: "02:00",
74
+ end_time: "01:30",
75
+ },
76
+ },
77
+ };
78
+
79
+ const { start, end } = getAutoplaySettings(item);
80
+
81
+ expect(start).toBe(120);
82
+ expect(end).toBeNull();
83
+ });
84
+
85
+ it("should return null end time if start time equal to end time", () => {
86
+ const item = {
87
+ extensions: {
88
+ autoplay_settings: {
89
+ start_time: "00:30",
90
+ end_time: "00:30",
91
+ },
92
+ },
93
+ };
94
+
95
+ const { start, end } = getAutoplaySettings(item);
96
+
97
+ expect(start).toBe(30);
98
+ expect(end).toBeNull();
99
+ });
100
+
101
+ it("should return null for missing autoplay settings", () => {
102
+ const item = {};
103
+
104
+ const result = getAutoplaySettings(item);
105
+
106
+ expect(result.start).toBeNull();
107
+ expect(result.end).toBeNull();
108
+ });
109
+ });
@@ -0,0 +1,40 @@
1
+ import { parseTimeToSeconds } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/utils";
2
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
3
+ import { loggerLiveImageComponent } from "./loggerHelper";
4
+
5
+ const { log_error } = loggerLiveImageComponent;
6
+
7
+ type AutoplaySettings = {
8
+ start: number | null;
9
+ end: number | null;
10
+ };
11
+
12
+ export const parseTime = (time: string): number => {
13
+ const seconds = toNumberWithDefaultZero(parseTimeToSeconds(time));
14
+
15
+ return Math.max(seconds, 0);
16
+ };
17
+
18
+ export const getAutoplaySettings = (item: ZappEntry): AutoplaySettings => {
19
+ const autoplay_settings = item?.extensions?.autoplay_settings;
20
+
21
+ let start: number | null = null;
22
+ let end: number | null = null;
23
+
24
+ if (autoplay_settings) {
25
+ const { start_time, end_time } = autoplay_settings;
26
+
27
+ try {
28
+ start = start_time ? parseTime(start_time) : null;
29
+ end = end_time ? parseTime(end_time) : null;
30
+
31
+ if (start && end && start >= end) {
32
+ end = null;
33
+ }
34
+ } catch (error) {
35
+ log_error(`PlayerLiveImageComponent: ${error}`);
36
+ }
37
+ }
38
+
39
+ return { start, end };
40
+ };
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import { StyleProp, View, ViewStyle } from "react-native";
1
+ import React, { useEffect, useRef } from "react";
2
+ import { StyleProp, ViewStyle, Animated, Easing } from "react-native";
3
3
  import { useTargetScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
4
4
  import { ComponentsMap } from "@applicaster/zapp-react-native-ui-components/Components/River/ComponentsMap";
5
5
  import { useSafeAreaInsets } from "react-native-safe-area-context";
@@ -28,7 +28,7 @@ export const PlayerDetails = ({
28
28
  style,
29
29
  configuration,
30
30
  isTabletLandscape,
31
- isAudioPlayer
31
+ isAudioPlayer,
32
32
  }: Props) => {
33
33
  const screenData = useTargetScreenData(entry);
34
34
  const insets = useSafeAreaInsets();
@@ -36,11 +36,47 @@ export const PlayerDetails = ({
36
36
  const extraTabletStyles = !isAudioPlayer
37
37
  ? isTabletLandscape
38
38
  ? { marginTop: -insets.top, paddingTop: insets.top + 20 }
39
- : { marginTop: -8, paddingTop: -8 } // makes sure the colored container is correct
39
+ : { marginTop: -8, paddingTop: -8 }
40
40
  : {};
41
41
 
42
+ // Animation setup
43
+ const translateY = useRef(new Animated.Value(100)).current;
44
+ const opacity = useRef(new Animated.Value(0)).current;
45
+
46
+ const runAnimation = () => {
47
+ Animated.timing(translateY, {
48
+ toValue: 0,
49
+ duration: 500,
50
+ easing: Easing.inOut(Easing.ease),
51
+ useNativeDriver: true,
52
+ }).start();
53
+
54
+ Animated.timing(opacity, {
55
+ toValue: 1,
56
+ duration: 500,
57
+ easing: Easing.inOut(Easing.ease),
58
+ useNativeDriver: true,
59
+ }).start();
60
+ };
61
+
62
+ useEffect(() => {
63
+ if (isAudioPlayer) {
64
+ setTimeout(() => runAnimation(), 1000);
65
+ }
66
+ }, [isAudioPlayer]);
67
+
42
68
  return (
43
- <View style={[style, extraTabletStyles, containerStyle(configuration)]}>
69
+ <Animated.View
70
+ style={[
71
+ style,
72
+ extraTabletStyles,
73
+ containerStyle(configuration),
74
+ isAudioPlayer && {
75
+ transform: [{ translateY }],
76
+ opacity,
77
+ },
78
+ ]}
79
+ >
44
80
  {screenData && (
45
81
  <ComponentsMap
46
82
  riverId={screenData.id}
@@ -48,6 +84,6 @@ export const PlayerDetails = ({
48
84
  riverComponents={screenData.ui_components}
49
85
  />
50
86
  )}
51
- </View>
87
+ </Animated.View>
52
88
  );
53
89
  };
@@ -8,6 +8,7 @@ import { PlayerDetails } from "./PlayerDetails";
8
8
  import { playerDimesionsHack } from "./utils";
9
9
  import { PathnameContext } from "../../Contexts/PathnameContext";
10
10
  import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
11
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
11
12
 
12
13
  type Dimensions = {
13
14
  width: number;
@@ -181,35 +182,37 @@ export const PlayerWrapper = (props: Props) => {
181
182
  playerDimesionsHack,
182
183
  ]}
183
184
  >
184
- <PathnameContext.Provider value={"videoModal"}>
185
- <View
186
- testID={`${entry?.id}-player-container`}
187
- style={[
188
- defaultStyles.playerContainer,
189
- containerDimensions,
190
- containerStyle,
191
- {
192
- height:
193
- isInlineModal && !docked
194
- ? containerDimensions.height + 10
195
- : containerDimensions.height,
196
- },
197
- playerDimesionsHack,
198
- ]}
199
- >
200
- {children(childrenStyles)}
201
- </View>
202
- {isInlineModal && !docked ? (
203
- <PlayerDetails
204
- configuration={configuration}
205
- style={defaultStyles.playerDetails}
206
- entry={entry}
207
- isTabletLandscape={isTabletLandscape}
208
- />
209
- ) : (
210
- <View style={defaultStyles.playerDetails} />
211
- )}
212
- </PathnameContext.Provider>
185
+ <ScreenContextProvider pathname={"videoModal"}>
186
+ <PathnameContext.Provider value={"videoModal"}>
187
+ <View
188
+ testID={`${entry?.id}-player-container`}
189
+ style={[
190
+ defaultStyles.playerContainer,
191
+ containerDimensions,
192
+ containerStyle,
193
+ {
194
+ height:
195
+ isInlineModal && !docked
196
+ ? containerDimensions.height + 10
197
+ : containerDimensions.height,
198
+ },
199
+ playerDimesionsHack,
200
+ ]}
201
+ >
202
+ {children(childrenStyles)}
203
+ </View>
204
+ {isInlineModal && !docked ? (
205
+ <PlayerDetails
206
+ configuration={configuration}
207
+ style={defaultStyles.playerDetails}
208
+ entry={entry}
209
+ isTabletLandscape={isTabletLandscape}
210
+ />
211
+ ) : (
212
+ <View style={defaultStyles.playerDetails} />
213
+ )}
214
+ </PathnameContext.Provider>
215
+ </ScreenContextProvider>
213
216
  </WrapperView>
214
217
  );
215
218
  };