@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5053228432 → 12.0.0-alpha.5061452310
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.
- package/Components/Cell/Cell.tsx +2 -2
- package/Components/Cell/CellWithFocusable.tsx +21 -14
- package/Components/Cell/TvOSCellComponent.tsx +2 -2
- package/Components/FocusableCell/index.tsx +7 -7
- package/Components/HookRenderer/index.tsx +1 -3
- package/Components/Image/utils/index.ts +21 -11
- package/Components/Layout/TV/__tests__/index.test.tsx +1 -13
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +14 -1
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
- package/Components/MasterCell/utils/index.ts +18 -7
- package/Components/PlayerContainer/PlayerContainer.tsx +11 -8
- package/Components/PlayerImageBackground/index.tsx +34 -8
- package/Components/River/__tests__/componentsMap.test.js +7 -0
- package/Components/Screen/__tests__/Screen.test.tsx +5 -1
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +10 -2
- package/Components/Screen/index.tsx +15 -13
- package/Components/Tabs/TV/styles.ts +1 -1
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +25 -5
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +335 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +144 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
- package/Components/VideoModal/PlayerWrapper.tsx +64 -41
- package/Components/VideoModal/VideoModal.tsx +8 -25
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +6 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
- package/Components/VideoModal/utils.ts +3 -3
- package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
- package/package.json +5 -5
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
6
|
-
|
|
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
|
? [
|
|
@@ -12,19 +12,7 @@ jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
|
|
|
12
12
|
useRiverInitialState: () => ({}),
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
|
-
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen"
|
|
16
|
-
useCurrentScreenData: jest.fn(() => ({
|
|
17
|
-
navigations: [
|
|
18
|
-
{
|
|
19
|
-
category: "menu",
|
|
20
|
-
navigation_type: "menu",
|
|
21
|
-
styles: {
|
|
22
|
-
hide_secondary_level_menu: false,
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
})),
|
|
27
|
-
}));
|
|
15
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen");
|
|
28
16
|
|
|
29
17
|
const Layout = require("..").default;
|
|
30
18
|
|
|
@@ -177,10 +177,23 @@ const getPlayerConfig = (player_screen_id, actionIdentifier) => {
|
|
|
177
177
|
const positionAbsolute: ViewStyle = { position: "absolute" };
|
|
178
178
|
|
|
179
179
|
const LiveImageComponent = (props: LiveImageProps) => {
|
|
180
|
-
const {
|
|
180
|
+
const {
|
|
181
|
+
item,
|
|
182
|
+
style: componentStyle,
|
|
183
|
+
cellUUID,
|
|
184
|
+
imageKey,
|
|
185
|
+
actionIdentifier,
|
|
186
|
+
state,
|
|
187
|
+
} = props;
|
|
181
188
|
|
|
182
189
|
const component = useUIComponentContext();
|
|
183
190
|
|
|
191
|
+
// Fix for blinking on state change
|
|
192
|
+
const style = React.useMemo(
|
|
193
|
+
() => ({ ...componentStyle, backgroundColor: "transparent" }),
|
|
194
|
+
[componentStyle]
|
|
195
|
+
);
|
|
196
|
+
|
|
184
197
|
const componentType = React.useMemo(
|
|
185
198
|
() => getPropComponentType(component),
|
|
186
199
|
[component?.id]
|
|
@@ -23,7 +23,11 @@ export const Toggle = (props: Props) => {
|
|
|
23
23
|
iosBackgroundColor,
|
|
24
24
|
} = style;
|
|
25
25
|
|
|
26
|
-
const isSelected = React.useMemo(
|
|
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(
|
|
@@ -125,13 +125,24 @@ export const useFilterChildren = <
|
|
|
125
125
|
|
|
126
126
|
const filteredChildren = children.filter((child) => {
|
|
127
127
|
const item = child.props.item;
|
|
128
|
-
const
|
|
128
|
+
const actionIdentifier = child.props.pluginIdentifier;
|
|
129
|
+
const action = actions.actions[actionIdentifier];
|
|
130
|
+
|
|
129
131
|
// context value of specific plugin
|
|
130
|
-
|
|
132
|
+
if (action?.module && action.module.context) {
|
|
133
|
+
const currentValue = action.module.context._currentValue;
|
|
134
|
+
|
|
135
|
+
return currentValue?.isActionAvailable
|
|
136
|
+
? currentValue.isActionAvailable(item)
|
|
137
|
+
: true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
masterCellLogger.error({
|
|
141
|
+
message: `Action plugin for ${actionIdentifier} could not be found, check the configuration of your action button`,
|
|
142
|
+
data: { item, action: child.props.pluginIdentifier },
|
|
143
|
+
});
|
|
131
144
|
|
|
132
|
-
return
|
|
133
|
-
? currentValue.isActionAvailable(item)
|
|
134
|
-
: true;
|
|
145
|
+
return false;
|
|
135
146
|
});
|
|
136
147
|
|
|
137
148
|
return filteredChildren;
|
|
@@ -285,8 +296,8 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
|
|
|
285
296
|
}
|
|
286
297
|
}
|
|
287
298
|
}, [behavior]);
|
|
288
|
-
|
|
289
|
-
|
|
299
|
+
|
|
300
|
+
useEffect(() => {
|
|
290
301
|
if (!behavior) {
|
|
291
302
|
return;
|
|
292
303
|
}
|
|
@@ -54,6 +54,8 @@ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
|
54
54
|
import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayNextOverlay";
|
|
55
55
|
import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
|
|
56
56
|
|
|
57
|
+
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
58
|
+
|
|
57
59
|
type Props = {
|
|
58
60
|
Player: React.ComponentType<any>;
|
|
59
61
|
PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
|
|
@@ -145,13 +147,7 @@ const renderApplePlayer = ({
|
|
|
145
147
|
}) => {
|
|
146
148
|
const { title, summary } = item || {};
|
|
147
149
|
|
|
148
|
-
if (!
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// TODO: Check if it is not breaking default player logic on tvos
|
|
153
|
-
// Also if needs to add on tvos brightcove player for QB player
|
|
154
|
-
if (player.supportsNativeControls()) {
|
|
150
|
+
if (!isAppleTV() || !player) {
|
|
155
151
|
return null;
|
|
156
152
|
}
|
|
157
153
|
|
|
@@ -604,6 +600,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
604
600
|
pluginConfiguration,
|
|
605
601
|
};
|
|
606
602
|
|
|
603
|
+
const { isActiveGesture, startComponentsAnimation } =
|
|
604
|
+
useModalAnimationContext();
|
|
605
|
+
|
|
607
606
|
return (
|
|
608
607
|
<PlayerStateContext.Provider value={value}>
|
|
609
608
|
<PlayerContainerContextProvider
|
|
@@ -647,7 +646,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
647
646
|
autoplay={true}
|
|
648
647
|
controls={false}
|
|
649
648
|
disableCastAction={disableCastAction}
|
|
650
|
-
docked={
|
|
649
|
+
docked={
|
|
650
|
+
navigator.isVideoModalDocked() &&
|
|
651
|
+
!startComponentsAnimation &&
|
|
652
|
+
!isActiveGesture
|
|
653
|
+
}
|
|
651
654
|
entry={item}
|
|
652
655
|
fullscreen={mode === VideoModalMode.FULLSCREEN}
|
|
653
656
|
inline={inline}
|
|
@@ -1,38 +1,64 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from "react";
|
|
2
|
-
import { ImageBackground } from "react-native";
|
|
2
|
+
import { ImageBackground, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
5
|
+
import {
|
|
6
|
+
AnimationComponent,
|
|
7
|
+
ComponentAnimationType,
|
|
8
|
+
useModalAnimationContext,
|
|
9
|
+
PlayerAnimationStateEnum,
|
|
10
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
5
11
|
|
|
6
12
|
type Props = PropsWithChildren<{
|
|
7
13
|
entry: ZappEntry;
|
|
8
14
|
style?: { [K: string]: any };
|
|
9
15
|
imageStyle?: { [K: string]: any };
|
|
10
16
|
imageKey?: string;
|
|
17
|
+
defaultImageDimensions?: { [K: string]: any };
|
|
11
18
|
}>;
|
|
12
19
|
|
|
20
|
+
const imageSize = { width: "100%", height: "100%" };
|
|
21
|
+
|
|
13
22
|
const PlayerImageBackgroundComponent = ({
|
|
14
23
|
entry,
|
|
15
24
|
children,
|
|
16
25
|
style,
|
|
17
26
|
imageStyle,
|
|
18
27
|
imageKey,
|
|
28
|
+
defaultImageDimensions,
|
|
19
29
|
}: Props) => {
|
|
20
30
|
const source = React.useMemo(
|
|
21
31
|
() => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
|
|
22
32
|
[imageKey, entry]
|
|
23
33
|
);
|
|
24
34
|
|
|
35
|
+
const { playerAnimationState } = useModalAnimationContext();
|
|
36
|
+
|
|
25
37
|
if (!source) return <>{children}</>;
|
|
26
38
|
|
|
27
39
|
return (
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
<View
|
|
41
|
+
style={
|
|
42
|
+
playerAnimationState === PlayerAnimationStateEnum.maximaze
|
|
43
|
+
? defaultImageDimensions
|
|
44
|
+
: style
|
|
45
|
+
}
|
|
33
46
|
>
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
<AnimationComponent
|
|
48
|
+
style={style}
|
|
49
|
+
animationType={ComponentAnimationType.player}
|
|
50
|
+
additionalData={defaultImageDimensions}
|
|
51
|
+
>
|
|
52
|
+
<ImageBackground
|
|
53
|
+
resizeMode="cover"
|
|
54
|
+
style={imageSize}
|
|
55
|
+
imageStyle={imageStyle}
|
|
56
|
+
source={source}
|
|
57
|
+
>
|
|
58
|
+
{children}
|
|
59
|
+
</ImageBackground>
|
|
60
|
+
</AnimationComponent>
|
|
61
|
+
</View>
|
|
36
62
|
);
|
|
37
63
|
};
|
|
38
64
|
|
|
@@ -6,6 +6,12 @@ import configureStore from "redux-mock-store";
|
|
|
6
6
|
|
|
7
7
|
import * as themeUtils from "@applicaster/zapp-react-native-utils/theme";
|
|
8
8
|
|
|
9
|
+
// silences the errors related to React-native-gesture-handler in tests
|
|
10
|
+
jest.mock(
|
|
11
|
+
"@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation",
|
|
12
|
+
() => () => null
|
|
13
|
+
);
|
|
14
|
+
|
|
9
15
|
jest.mock("react-native-safe-area-context", () => ({
|
|
10
16
|
useSafeAreaInsets: () => ({ top: 50 }),
|
|
11
17
|
}));
|
|
@@ -83,6 +89,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
|
83
89
|
useNavigation: jest.fn(() => ({ currentRoute: "/river/A1234" })),
|
|
84
90
|
useRoute: jest.fn(() => ({ pathname: "/river/A1234", screenData })),
|
|
85
91
|
useProfilerLogging: jest.fn(),
|
|
92
|
+
useIsScreenActive: jest.fn().mockReturnValue(true),
|
|
86
93
|
}));
|
|
87
94
|
|
|
88
95
|
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 {
|
|
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={
|
|
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={
|
|
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
|
|
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={
|
|
140
|
+
<OfflineFallbackScreen screenData={targetScreenData}>
|
|
139
141
|
{/* @TODO RouteManager doesn't use props, can they be removed ? */}
|
|
140
|
-
<RouteManager pathname={pathname} screenData={
|
|
142
|
+
<RouteManager pathname={pathname} screenData={screenData} />
|
|
141
143
|
</OfflineFallbackScreen>
|
|
142
144
|
</View>
|
|
143
145
|
</ScreenContextProvider>
|
|
@@ -4,8 +4,13 @@ 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";
|
|
10
|
+
import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
11
|
+
|
|
12
|
+
import { Provider } from "react-redux";
|
|
13
|
+
import configureStore from "redux-mock-store";
|
|
9
14
|
|
|
10
15
|
const seekTo = jest.fn();
|
|
11
16
|
|
|
@@ -18,12 +23,25 @@ jest.mock(
|
|
|
18
23
|
})
|
|
19
24
|
);
|
|
20
25
|
|
|
26
|
+
jest
|
|
27
|
+
.spyOn(useNavigationHooks, "useNavigation")
|
|
28
|
+
.mockImplementation(() => ({ videoModalState: { visible: false } }));
|
|
29
|
+
|
|
30
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
|
|
31
|
+
|
|
32
|
+
const mockStore = configureStore();
|
|
33
|
+
|
|
34
|
+
const store = mockStore({ appData: {} });
|
|
35
|
+
|
|
21
36
|
const Wrapper = ({ children }: { children: React.ReactChildren }) => (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
/* @ts-ignore */
|
|
38
|
+
<Provider store={store}>
|
|
39
|
+
<ThemeContext.Provider
|
|
40
|
+
value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
|
|
41
|
+
>
|
|
42
|
+
{children}
|
|
43
|
+
</ThemeContext.Provider>
|
|
44
|
+
</Provider>
|
|
27
45
|
);
|
|
28
46
|
|
|
29
47
|
describe("PlayerLiveImageComponent", () => {
|
|
@@ -46,6 +64,8 @@ describe("PlayerLiveImageComponent", () => {
|
|
|
46
64
|
controller: new Player({}),
|
|
47
65
|
Component: () => null,
|
|
48
66
|
}));
|
|
67
|
+
|
|
68
|
+
jest.spyOn(navigationHooks, "useIsScreenActive").mockReturnValue(true);
|
|
49
69
|
});
|
|
50
70
|
|
|
51
71
|
it("should render correctly with default props", () => {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Animated, ViewStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
useModalAnimationContext,
|
|
6
|
+
PlayerAnimationStateEnum,
|
|
7
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
8
|
+
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
style: ViewStyle[];
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const AnimatedPlayerModalWrapper = (props: Props) => {
|
|
16
|
+
const {
|
|
17
|
+
playerAnimationState,
|
|
18
|
+
animatedValues: { lastScrollY, dragScrollY, translateYOffset },
|
|
19
|
+
modalSnapPoints,
|
|
20
|
+
setStartComponentsAnimation,
|
|
21
|
+
lastScrollYValue,
|
|
22
|
+
} = useModalAnimationContext();
|
|
23
|
+
|
|
24
|
+
const { height: screenHeight } = useDimensions("screen", {
|
|
25
|
+
deviceInfo: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const interpolateConfig: Animated.InterpolationConfigType = React.useMemo(
|
|
29
|
+
() => ({
|
|
30
|
+
inputRange: modalSnapPoints,
|
|
31
|
+
outputRange: modalSnapPoints,
|
|
32
|
+
extrapolate: "clamp",
|
|
33
|
+
}),
|
|
34
|
+
[modalSnapPoints]
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
let translateY;
|
|
38
|
+
|
|
39
|
+
if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
|
|
40
|
+
translateY = translateYOffset.interpolate(interpolateConfig);
|
|
41
|
+
} else {
|
|
42
|
+
const reverseLastScrollY = Animated.multiply(
|
|
43
|
+
new Animated.Value(-1),
|
|
44
|
+
lastScrollY
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
translateY = Animated.add(
|
|
48
|
+
translateYOffset,
|
|
49
|
+
Animated.add(dragScrollY, reverseLastScrollY)
|
|
50
|
+
).interpolate(interpolateConfig);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
const translateYListener = translateY.addListener(({ value }) => {
|
|
55
|
+
const preparedValue = Math.round(
|
|
56
|
+
Math.abs(value) - lastScrollYValue.current
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
(playerAnimationState === PlayerAnimationStateEnum.minimize ||
|
|
60
|
+
playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
|
|
61
|
+
setStartComponentsAnimation(
|
|
62
|
+
preparedValue >= Math.round((screenHeight * 10) / 100)
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
67
|
+
translateYListener && translateY.removeListener(translateYListener);
|
|
68
|
+
};
|
|
69
|
+
}, [playerAnimationState]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Animated.View
|
|
73
|
+
style={[props.style, { transform: [{ translateY: translateY }] }]}
|
|
74
|
+
>
|
|
75
|
+
{props.children}
|
|
76
|
+
</Animated.View>
|
|
77
|
+
);
|
|
78
|
+
};
|