@applicaster/zapp-react-native-ui-components 12.0.0-rc.99 → 12.0.2-alpha.1558929238
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 +29 -10
- package/Components/Focusable/__tests__/index.android.test.tsx +72 -0
- package/Components/Focusable/index.android.tsx +15 -9
- package/Components/FocusableList/FocusableChild.ts +2 -2
- package/Components/FocusableList/index.tsx +11 -12
- package/Components/FocusableScrollView/index.tsx +1 -1
- package/Components/FreezeWithCallback/Freeze.tsx +31 -0
- package/Components/FreezeWithCallback/LICENSE +21 -0
- package/Components/FreezeWithCallback/Suspender.tsx +17 -0
- package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
- package/Components/FreezeWithCallback/index.tsx +3 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +67 -7
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +53 -9
- package/Components/Image/Image.android.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +11 -7
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -7
- package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +6 -1
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +12 -0
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +6 -5
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/DefaultComponents/index.ts +2 -0
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
- package/Components/MasterCell/dataAdapter.ts +21 -7
- package/Components/MasterCell/index.tsx +5 -3
- package/Components/MasterCell/utils/index.ts +3 -4
- package/Components/PlayerContainer/PlayerContainer.tsx +14 -8
- package/Components/Screen/TV/hooks/index.ts +0 -2
- package/Components/Screen/TV/index.web.tsx +32 -19
- package/Components/Screen/__tests__/Screen.test.tsx +0 -49
- package/Components/Screen/index.tsx +2 -20
- package/Components/Screen/navigationHandler.ts +1 -3
- package/Components/Screen/orientationHandler.ts +18 -7
- package/Components/Screen/utils.ts +16 -0
- package/Components/ScreenResolver/index.tsx +6 -11
- package/Components/Transitioner/Scene.tsx +9 -2
- package/Components/Transitioner/Transitioner.tsx +38 -23
- package/Components/Transitioner/__tests__/Scene.test.js +7 -0
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +5 -0
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +3 -9
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +87 -41
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +20 -9
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +41 -22
- package/Components/VideoModal/PlayerDetails.tsx +16 -2
- package/Components/VideoModal/PlayerWrapper.tsx +84 -66
- package/Components/VideoModal/VideoModal.tsx +33 -27
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +7 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +72 -10
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +8 -3
- package/Components/ZappFrameworkComponents/BarView/Buttons/BackButton.tsx +7 -2
- package/Components/ZappFrameworkComponents/BarView/Buttons/CloseButton.tsx +7 -2
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +87 -0
- package/Components/ZappFrameworkComponents/Buttons/ActionButton.tsx +9 -4
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
- package/Contexts/CachedDimensionsContext/index.ts +13 -9
- package/Contexts/ConfirmDialogState/index.ts +1 -1
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +18 -11
- package/Contexts/ScreenContext/index.tsx +6 -1
- package/const.ts +6 -0
- package/index.js +3 -0
- package/package.json +5 -5
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +0 -22
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/// <reference types="@applicaster/applicaster-types" />
|
|
2
2
|
import React from "react";
|
|
3
|
-
import * as R from "ramda";
|
|
4
3
|
import { View } from "react-native";
|
|
5
4
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
6
5
|
import {
|
|
@@ -27,7 +26,7 @@ import { getNavigationPluginModule } from "@applicaster/zapp-react-native-app/Ap
|
|
|
27
26
|
|
|
28
27
|
import { RouteManager } from "../RouteManager";
|
|
29
28
|
import { useScreenConfiguration } from "../River/useScreenConfiguration";
|
|
30
|
-
import {
|
|
29
|
+
import { isValidColor } from "./utils";
|
|
31
30
|
|
|
32
31
|
const screenStyles = {
|
|
33
32
|
flex: 1,
|
|
@@ -37,21 +36,6 @@ const screenStyles = {
|
|
|
37
36
|
// paddingRight: insets.right, // Should be applied directly by UI plugin
|
|
38
37
|
};
|
|
39
38
|
|
|
40
|
-
function colorIsNotTransparent(color) {
|
|
41
|
-
const layers = R.compose(
|
|
42
|
-
R.map(R.trim),
|
|
43
|
-
R.split(","),
|
|
44
|
-
R.replace(")", ""),
|
|
45
|
-
R.replace("rgba(", "")
|
|
46
|
-
)(color);
|
|
47
|
-
|
|
48
|
-
return Number(layers?.[3]) > 0;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function isValidColor(string) {
|
|
52
|
-
return string && string !== "transparent" && colorIsNotTransparent(string);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
39
|
type Props = {
|
|
56
40
|
pathname: unknown;
|
|
57
41
|
screenData: unknown;
|
|
@@ -127,8 +111,6 @@ export function Screen(_props: Props) {
|
|
|
127
111
|
const targetScreenData =
|
|
128
112
|
currentScreenData || (screenData as any)?.targetScreen || screenData;
|
|
129
113
|
|
|
130
|
-
useScreenOrientationHandler({ screenData: targetScreenData });
|
|
131
|
-
|
|
132
114
|
const orientation = useGetScreenOrientation(targetScreenData);
|
|
133
115
|
|
|
134
116
|
// We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
|
|
@@ -146,7 +128,7 @@ export function Screen(_props: Props) {
|
|
|
146
128
|
<View style={style}>
|
|
147
129
|
{navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
|
|
148
130
|
|
|
149
|
-
<OfflineFallbackScreen
|
|
131
|
+
<OfflineFallbackScreen>
|
|
150
132
|
{/* @TODO RouteManager doesn't use props, can they be removed ? */}
|
|
151
133
|
<RouteManager pathname={pathname} screenData={screenData} />
|
|
152
134
|
</OfflineFallbackScreen>
|
|
@@ -26,9 +26,7 @@ export function isMenuVisible(route, screenData) {
|
|
|
26
26
|
if (screenData?.hookPlugin) {
|
|
27
27
|
const hookPlugin = screenData?.hookPlugin?.module;
|
|
28
28
|
|
|
29
|
-
return
|
|
30
|
-
hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true || false
|
|
31
|
-
);
|
|
29
|
+
return hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
if (
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import React, { useLayoutEffect } from "react";
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
4
|
allowedOrientationsForScreen,
|
|
4
5
|
ORIENTATIONS,
|
|
5
6
|
getOrientation,
|
|
6
7
|
useGetScreenOrientation,
|
|
7
8
|
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
8
|
-
|
|
9
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
9
10
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
10
11
|
import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
11
12
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
|
+
|
|
12
14
|
import { ZappHookModalContext } from "../../Contexts";
|
|
13
15
|
import { HookModalContextT } from "../../Contexts/ZappHookModalContext";
|
|
14
16
|
|
|
@@ -79,14 +81,23 @@ export function useNewOrientationForScreenData({
|
|
|
79
81
|
screenOrientation;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
screenData
|
|
84
|
-
|
|
84
|
+
type Props = {
|
|
85
|
+
screenData: {
|
|
86
|
+
screen: {};
|
|
87
|
+
};
|
|
88
|
+
isActive: boolean;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export function useScreenOrientationHandler({ screenData, isActive }: Props) {
|
|
85
92
|
const { isHooksExecutionInProgress } = React.useContext<HookModalContextT>(
|
|
86
93
|
ZappHookModalContext.ReactContext
|
|
87
94
|
);
|
|
88
95
|
|
|
89
|
-
const
|
|
96
|
+
const prevIsActive = usePrevious(isActive);
|
|
97
|
+
|
|
98
|
+
const newOrientation = useNewOrientationForScreenData({
|
|
99
|
+
screenData: screenData.screen,
|
|
100
|
+
});
|
|
90
101
|
|
|
91
102
|
useLayoutEffect(() => {
|
|
92
103
|
// Null means screen does not have orientation preference, so we can skip rotate
|
|
@@ -100,12 +111,12 @@ export function useScreenOrientationHandler({
|
|
|
100
111
|
return;
|
|
101
112
|
}
|
|
102
113
|
|
|
103
|
-
if (newOrientation !== current) {
|
|
114
|
+
if (!prevIsActive && isActive && newOrientation !== current) {
|
|
104
115
|
current = newOrientation;
|
|
105
116
|
|
|
106
117
|
setOrientation(newOrientation);
|
|
107
118
|
}
|
|
108
|
-
}, [newOrientation, isHooksExecutionInProgress]);
|
|
119
|
+
}, [newOrientation, isHooksExecutionInProgress, prevIsActive, isActive]);
|
|
109
120
|
}
|
|
110
121
|
|
|
111
122
|
export function useOrientationHandler({ screenData }: OrientationHookArgs) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { map, split, replace, compose, trim } from "ramda";
|
|
2
|
+
|
|
3
|
+
function colorIsNotTransparent(color) {
|
|
4
|
+
const layers = compose(
|
|
5
|
+
map(trim),
|
|
6
|
+
split(","),
|
|
7
|
+
replace(")", ""),
|
|
8
|
+
replace("rgba(", "")
|
|
9
|
+
)(color);
|
|
10
|
+
|
|
11
|
+
return Number(layers?.[3]) > 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function isValidColor(string) {
|
|
15
|
+
return string && string !== "transparent" && colorIsNotTransparent(string);
|
|
16
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
3
|
-
import { useDispatch } from "react-redux";
|
|
2
|
+
import { path, prop } from "ramda";
|
|
4
3
|
import {
|
|
5
4
|
findPluginByType,
|
|
6
5
|
findPluginByIdentifier,
|
|
@@ -15,7 +14,6 @@ import { componentsLogger } from "../../Helpers/logger";
|
|
|
15
14
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
16
15
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
17
16
|
import { useScreenAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
|
|
18
|
-
import { setAppStateHasFinishedTransitioning } from "@applicaster/zapp-react-native-redux/appState";
|
|
19
17
|
|
|
20
18
|
const logger = componentsLogger.addSubsystem("ScreenResolver");
|
|
21
19
|
|
|
@@ -54,11 +52,8 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
54
52
|
|
|
55
53
|
const [, setScreenContext] = ZappPipesScreenContext.useZappPipesContext();
|
|
56
54
|
|
|
57
|
-
const dispatch = useDispatch();
|
|
58
|
-
|
|
59
55
|
React.useEffect(() => {
|
|
60
56
|
setScreenContext(rivers[screenId]);
|
|
61
|
-
dispatch(setAppStateHasFinishedTransitioning());
|
|
62
57
|
}, [screenId]);
|
|
63
58
|
|
|
64
59
|
const ScreenPlugin =
|
|
@@ -100,14 +95,14 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
100
95
|
}
|
|
101
96
|
|
|
102
97
|
const ScreenComponent =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
98
|
+
path(["module", "Component"], ScreenPlugin) ||
|
|
99
|
+
prop("module", ScreenPlugin) ||
|
|
100
|
+
prop("Component", ScreenPlugin) ||
|
|
106
101
|
ScreenPlugin;
|
|
107
102
|
|
|
108
103
|
const configuration =
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
prop("configuration", ScreenPlugin) ||
|
|
105
|
+
prop("__plugin_configuration", ScreenComponent);
|
|
111
106
|
|
|
112
107
|
if (ScreenComponent) {
|
|
113
108
|
return (
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Animated, ViewProps, ViewStyle } from "react-native";
|
|
3
3
|
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
4
|
+
|
|
5
|
+
import { useScreenOrientationHandler } from "@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler";
|
|
6
|
+
|
|
4
7
|
import { PathnameContext } from "../../Contexts/PathnameContext";
|
|
5
8
|
import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
|
|
6
9
|
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
@@ -42,6 +45,11 @@ export function Scene({
|
|
|
42
45
|
}: Props) {
|
|
43
46
|
const [initialScreenData, setInitialScreenData] = React.useState(screenData);
|
|
44
47
|
|
|
48
|
+
useScreenOrientationHandler({
|
|
49
|
+
screenData,
|
|
50
|
+
isActive,
|
|
51
|
+
});
|
|
52
|
+
|
|
45
53
|
React.useLayoutEffect(() => {
|
|
46
54
|
if (isActive) {
|
|
47
55
|
setInitialScreenData(screenData);
|
|
@@ -49,13 +57,12 @@ export function Scene({
|
|
|
49
57
|
}, [screenData, isActive]);
|
|
50
58
|
|
|
51
59
|
const frame = useSafeAreaFrame();
|
|
52
|
-
|
|
53
60
|
const isAnimating = animating && overlayStyle;
|
|
54
61
|
|
|
55
62
|
const dimensions = isAnimating
|
|
56
63
|
? {
|
|
57
|
-
height: "100%",
|
|
58
64
|
width: "100%",
|
|
65
|
+
height: "100%",
|
|
59
66
|
}
|
|
60
67
|
: frame;
|
|
61
68
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import
|
|
3
|
+
import { update, compose, tail, append, take, identity, isNil } from "ramda";
|
|
4
4
|
|
|
5
5
|
import { AnimationManager } from "./AnimationManager";
|
|
6
6
|
import { Scene } from "./Scene";
|
|
@@ -46,10 +46,14 @@ function prepareScene(children) {
|
|
|
46
46
|
*/
|
|
47
47
|
function scenesForBackTransition(props: SceneProps, { scenes }) {
|
|
48
48
|
return scenes.length > 1
|
|
49
|
-
?
|
|
49
|
+
? identity(scenes)
|
|
50
50
|
: [prepareScene(props.children), scenes[0]];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
const isModalClosed = (navigator) => {
|
|
54
|
+
return !!isNil(navigator?.modalData);
|
|
55
|
+
};
|
|
56
|
+
|
|
53
57
|
type Props = {
|
|
54
58
|
transitionConfig: any;
|
|
55
59
|
children: React.ReactNode;
|
|
@@ -110,7 +114,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
110
114
|
pushTransitionStart() {
|
|
111
115
|
this.setState(
|
|
112
116
|
{
|
|
113
|
-
scenes:
|
|
117
|
+
scenes: append(prepareScene(this.props.children), this.state.scenes),
|
|
114
118
|
...this.animationManager.stateForAction(this.state, NAV_ACTION_PUSH),
|
|
115
119
|
},
|
|
116
120
|
() => {
|
|
@@ -166,21 +170,23 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
166
170
|
|
|
167
171
|
transitionWithoutAnimation(resetState) {
|
|
168
172
|
const { scenes } = this.state;
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
173
|
+
const newScene = prepareScene(this.props.children);
|
|
174
|
+
const isLastSceneHook = scenes[scenes.length - 1].key.startsWith("/hook");
|
|
175
|
+
|
|
176
|
+
let newState;
|
|
177
|
+
|
|
178
|
+
if (resetState) {
|
|
179
|
+
newState = {
|
|
180
|
+
scenes: [newScene],
|
|
181
|
+
to: { index: 0 },
|
|
182
|
+
};
|
|
183
|
+
} else if (isLastSceneHook || scenes.length === 1) {
|
|
184
|
+
newState = { scenes: update(scenes.length - 1, newScene, scenes) };
|
|
185
|
+
} else {
|
|
186
|
+
newState = {
|
|
187
|
+
scenes: compose(tail, append(newScene))(scenes),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
184
190
|
|
|
185
191
|
this.setState(newState);
|
|
186
192
|
}
|
|
@@ -223,7 +229,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
223
229
|
this.shouldSkipAnimationForRoute(previousRoute) ||
|
|
224
230
|
this.shouldSkipAnimationForRoute(currentRoute)
|
|
225
231
|
) {
|
|
226
|
-
|
|
232
|
+
// we are going back, in this case we need to have only one scene using resetState
|
|
233
|
+
const resetState = isGoingBack ? true : undefined;
|
|
234
|
+
|
|
235
|
+
return this.transitionWithoutAnimation(resetState);
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
switch (this.props.navigator.previousAction) {
|
|
@@ -266,7 +275,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
266
275
|
backTransitionEnd(stepsBack) {
|
|
267
276
|
this.setState({
|
|
268
277
|
animating: false,
|
|
269
|
-
scenes:
|
|
278
|
+
scenes: take(this.state.scenes.length - stepsBack, this.state.scenes),
|
|
270
279
|
});
|
|
271
280
|
}
|
|
272
281
|
|
|
@@ -282,7 +291,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
282
291
|
<View style={styles.container}>
|
|
283
292
|
{scenes[to.index] && (
|
|
284
293
|
<Scene
|
|
285
|
-
{...{ style: to
|
|
294
|
+
{...{ style: to?.style || {} }}
|
|
286
295
|
pathname={pathname}
|
|
287
296
|
isActive={pathname === this.props.navigator.currentRoute}
|
|
288
297
|
contentStyle={contentStyle}
|
|
@@ -308,7 +317,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
308
317
|
<Scene
|
|
309
318
|
key={scenes[from.index].key}
|
|
310
319
|
pathname={scenes[from.index].key}
|
|
311
|
-
isActive={
|
|
320
|
+
isActive={
|
|
321
|
+
scenes[from.index].key === this.props.navigator.currentRoute &&
|
|
322
|
+
isModalClosed(this.props.navigator)
|
|
323
|
+
}
|
|
312
324
|
style={from.style}
|
|
313
325
|
pointerEvents="none"
|
|
314
326
|
overlayStyle={from.overlayStyle}
|
|
@@ -324,7 +336,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
324
336
|
const toScene = scenes[to.index] && (
|
|
325
337
|
<Scene
|
|
326
338
|
pathname={scenes[to.index].key}
|
|
327
|
-
isActive={
|
|
339
|
+
isActive={
|
|
340
|
+
scenes[to.index].key === this.props.navigator.currentRoute &&
|
|
341
|
+
isModalClosed(this.props.navigator)
|
|
342
|
+
}
|
|
328
343
|
key={scenes[to.index].key}
|
|
329
344
|
style={to.style}
|
|
330
345
|
overlayStyle={to.overlayStyle}
|
|
@@ -16,6 +16,13 @@ jest.mock("react-native-safe-area-context", () => ({
|
|
|
16
16
|
})),
|
|
17
17
|
}));
|
|
18
18
|
|
|
19
|
+
jest.mock(
|
|
20
|
+
"@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler",
|
|
21
|
+
() => ({
|
|
22
|
+
useScreenOrientationHandler: jest.fn(),
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
|
|
19
26
|
const { Scene } = require("../Scene");
|
|
20
27
|
|
|
21
28
|
const wrapper = shallow(
|
|
@@ -45,15 +45,9 @@ export const AnimatedPlayerModalWrapper = (props: Props) => {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
React.useEffect(() => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
setStartComponentsAnimation(true);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return () => {
|
|
55
|
-
translateYListener && translateY.removeListener(translateYListener);
|
|
56
|
-
};
|
|
48
|
+
(playerAnimationState === PlayerAnimationStateEnum.minimize ||
|
|
49
|
+
playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
|
|
50
|
+
setStartComponentsAnimation(true);
|
|
57
51
|
}, [playerAnimationState]);
|
|
58
52
|
|
|
59
53
|
return (
|
|
@@ -61,29 +61,32 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
61
61
|
setStartComponentsAnimation,
|
|
62
62
|
} = useModalAnimationContext();
|
|
63
63
|
|
|
64
|
+
const [enableGesture, setIEnableGesture] = React.useState<boolean>(true);
|
|
64
65
|
const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
|
|
65
66
|
|
|
66
67
|
const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
|
|
67
68
|
useNavigation();
|
|
68
69
|
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
70
|
+
const { mode: videoModalMode, item: videoModalItem } = videoModalState;
|
|
71
|
+
const isMaximazedModal = videoModalMode === "MAXIMIZED";
|
|
72
|
+
const isMinimizedModal = videoModalMode === "MINIMIZED";
|
|
73
|
+
const previousItemId = usePrevious(videoModalItem?.id);
|
|
72
74
|
|
|
73
75
|
const isNotMinimizeMaximazeAnimation =
|
|
74
76
|
playerAnimationState !== PlayerAnimationStateEnum.minimize &&
|
|
75
77
|
playerAnimationState !== PlayerAnimationStateEnum.maximaze;
|
|
76
78
|
|
|
77
79
|
const isEnablePanGesture =
|
|
80
|
+
enableGesture &&
|
|
78
81
|
!isLanguageOverlayVisible &&
|
|
79
82
|
isNotMinimizeMaximazeAnimation &&
|
|
80
83
|
(isMaximazedModal || isMinimizedModal);
|
|
81
84
|
|
|
82
85
|
const isAudioItem = React.useMemo(
|
|
83
86
|
() =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
[
|
|
87
|
+
videoModalItem?.content?.type?.includes?.("audio") ||
|
|
88
|
+
videoModalItem?.type?.value === "audio",
|
|
89
|
+
[videoModalItem]
|
|
87
90
|
);
|
|
88
91
|
|
|
89
92
|
// Refs for components
|
|
@@ -114,7 +117,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
114
117
|
const preparedTranslationY =
|
|
115
118
|
Math.abs(translationY) - lastScrollYValue.current;
|
|
116
119
|
|
|
117
|
-
if (
|
|
120
|
+
if (videoModalMode === "MAXIMIZED") {
|
|
118
121
|
const endOffsetY =
|
|
119
122
|
lastSnap + preparedTranslationY + dragToss * velocityY + 150;
|
|
120
123
|
|
|
@@ -161,22 +164,38 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
161
164
|
resetPlayerAnimationState();
|
|
162
165
|
}
|
|
163
166
|
},
|
|
164
|
-
[lastSnap, modalSnapPoints, playerAnimationState,
|
|
167
|
+
[lastSnap, modalSnapPoints, playerAnimationState, videoModalMode]
|
|
165
168
|
);
|
|
166
169
|
|
|
167
170
|
const onScroll = React.useCallback(({ nativeEvent }) => {
|
|
168
171
|
scrollPosition.current = nativeEvent.contentOffset.y;
|
|
169
172
|
}, []);
|
|
170
173
|
|
|
174
|
+
// Workaround for onMomentumScrollEnd issue
|
|
175
|
+
// https://github.com/facebook/react-native/issues/32696#issuecomment-1104217223
|
|
176
|
+
const canMomentum = React.useRef(false);
|
|
177
|
+
|
|
178
|
+
const onMomentumScrollBegin = React.useCallback(() => {
|
|
179
|
+
canMomentum.current = true;
|
|
180
|
+
}, []);
|
|
181
|
+
|
|
171
182
|
const onMomentumScrollEnd = React.useCallback(
|
|
172
183
|
({ nativeEvent }) => {
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
if (canMomentum.current && !isActiveGesture) {
|
|
185
|
+
if (nativeEvent.contentOffset.y === 0) {
|
|
186
|
+
resetScrollAnimatedValues(
|
|
187
|
+
lastScrollY,
|
|
188
|
+
lastScrollYValue,
|
|
189
|
+
dragScrollY,
|
|
190
|
+
dragVideoPlayerY
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
setIEnableGesture(true);
|
|
194
|
+
} else {
|
|
195
|
+
setIEnableGesture(false);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
canMomentum.current = false;
|
|
180
199
|
}
|
|
181
200
|
},
|
|
182
201
|
[isActiveGesture]
|
|
@@ -196,23 +215,42 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
196
215
|
}, []);
|
|
197
216
|
|
|
198
217
|
React.useEffect(() => {
|
|
218
|
+
const { mode, previousMode, item } = videoModalState;
|
|
219
|
+
|
|
199
220
|
if (
|
|
200
|
-
|
|
201
|
-
|
|
221
|
+
mode === "MAXIMIZED" &&
|
|
222
|
+
!enableGesture &&
|
|
223
|
+
scrollPosition.current === 0
|
|
202
224
|
) {
|
|
203
|
-
|
|
225
|
+
setIEnableGesture(true);
|
|
204
226
|
}
|
|
205
227
|
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
228
|
+
if (mode === "MINIMIZED" && previousMode === "MAXIMIZED") {
|
|
229
|
+
// set animation to the minimize values if moving from the player to another screen
|
|
230
|
+
if (playerAnimationState === null) {
|
|
231
|
+
setScrollModalAnimatedValue(
|
|
232
|
+
translateYOffset,
|
|
233
|
+
modalSnapPoints[1],
|
|
234
|
+
setLastSnap
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
resetScrollAnimatedValues(
|
|
238
|
+
lastScrollY,
|
|
239
|
+
lastScrollYValue,
|
|
240
|
+
dragScrollY,
|
|
241
|
+
dragVideoPlayerY
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
} else if (
|
|
245
|
+
playerAnimationState === null &&
|
|
246
|
+
((previousItemId === item?.id &&
|
|
247
|
+
mode === "MAXIMIZED" &&
|
|
248
|
+
(previousMode === "MINIMIZED" || previousMode === "MAXIMIZED")) ||
|
|
249
|
+
(previousItemId !== item?.id && mode !== "FULLSCREEN"))
|
|
211
250
|
) {
|
|
212
251
|
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
213
|
-
setTimeout(() => resetPlayerAnimationState());
|
|
214
252
|
}
|
|
215
|
-
}, [videoModalState
|
|
253
|
+
}, [videoModalState]);
|
|
216
254
|
|
|
217
255
|
React.useEffect(() => {
|
|
218
256
|
if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
|
|
@@ -237,22 +275,22 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
237
275
|
translateYOffset,
|
|
238
276
|
getAnimatedConfig(modalSnapPoints[1])
|
|
239
277
|
).start(() => {
|
|
240
|
-
|
|
241
|
-
minimiseVideoModal();
|
|
278
|
+
minimiseVideoModal();
|
|
242
279
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
280
|
+
setScrollModalAnimatedValue(
|
|
281
|
+
translateYOffset,
|
|
282
|
+
modalSnapPoints[1],
|
|
283
|
+
setLastSnap
|
|
284
|
+
);
|
|
248
285
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
286
|
+
resetScrollAnimatedValues(
|
|
287
|
+
lastScrollY,
|
|
288
|
+
lastScrollYValue,
|
|
289
|
+
dragScrollY,
|
|
290
|
+
dragVideoPlayerY
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
resetPlayerAnimationState();
|
|
256
294
|
});
|
|
257
295
|
} else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
|
|
258
296
|
Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
|
|
@@ -269,7 +307,9 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
269
307
|
resetPlayerAnimationState();
|
|
270
308
|
});
|
|
271
309
|
}
|
|
310
|
+
}, [playerAnimationState]);
|
|
272
311
|
|
|
312
|
+
React.useEffect(() => {
|
|
273
313
|
const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
|
|
274
314
|
lastScrollYValue.current = value;
|
|
275
315
|
});
|
|
@@ -295,7 +335,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
295
335
|
lastScrollY.removeListener(lastScrollYListenerId);
|
|
296
336
|
dragScrollY.removeListener(dragListenerId);
|
|
297
337
|
};
|
|
298
|
-
}, [playerAnimationState, isAudioItem,
|
|
338
|
+
}, [playerAnimationState, isAudioItem, isMinimizedModal]);
|
|
299
339
|
|
|
300
340
|
const Wrapper = React.useMemo(
|
|
301
341
|
() => (Platform.OS === "android" ? GestureHandlerRootView : View),
|
|
@@ -333,6 +373,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
333
373
|
bounces={false}
|
|
334
374
|
onScrollBeginDrag={onRegisterLastScroll}
|
|
335
375
|
onScroll={onScroll}
|
|
376
|
+
onMomentumScrollBegin={onMomentumScrollBegin}
|
|
336
377
|
onMomentumScrollEnd={onMomentumScrollEnd}
|
|
337
378
|
scrollEventThrottle={1}
|
|
338
379
|
showsVerticalScrollIndicator={false}
|
|
@@ -349,7 +390,12 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
349
390
|
};
|
|
350
391
|
|
|
351
392
|
export const AnimatedScrollModal = ({ children }: Props) => {
|
|
352
|
-
const
|
|
393
|
+
const {
|
|
394
|
+
videoModalState: { visible },
|
|
395
|
+
} = useNavigation();
|
|
396
|
+
|
|
397
|
+
const Component =
|
|
398
|
+
!isTV() && visible ? AnimatedScrollModalComponent : React.Fragment;
|
|
353
399
|
|
|
354
400
|
return <Component>{children}</Component>;
|
|
355
401
|
};
|