@applicaster/zapp-react-native-ui-components 14.0.0-alpha.5222319560 → 14.0.0-alpha.5234792518
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/FeedLoader/FeedLoader.tsx +1 -1
- package/Components/Focusable/Focusable.tsx +1 -1
- package/Components/Focusable/FocusableTvOS.tsx +2 -2
- package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
- package/Components/FocusableList/index.tsx +2 -2
- package/Components/PlayerContainer/PlayerContainer.tsx +4 -1
- package/Components/River/RiverItem.tsx +5 -0
- package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
- package/Components/Screen/navigationHandler.ts +20 -2
- package/Components/Tabs/TV/Tabs.android.tsx +1 -1
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +294 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +93 -0
- package/package.json +5 -5
|
@@ -8,7 +8,7 @@ type Props = {
|
|
|
8
8
|
typeof import("@applicaster/zapp-react-native-utils/reactHooks/feed").useLoadPipesDataDispatch
|
|
9
9
|
>;
|
|
10
10
|
feedUrl: string;
|
|
11
|
-
children: (feed: ZappFeed) => React.
|
|
11
|
+
children: (feed: ZappFeed) => React.ReactNode;
|
|
12
12
|
onFeedLoaded: (feed: ZappFeed) => {};
|
|
13
13
|
onError: (error: ZappPipesData["error"]) => {};
|
|
14
14
|
refreshing: boolean;
|
|
@@ -20,7 +20,7 @@ type Props = {
|
|
|
20
20
|
onPressOut?: () => void;
|
|
21
21
|
onLongPress?: () => void;
|
|
22
22
|
handleFocus?: ({ mouse }: { mouse: boolean }) => void;
|
|
23
|
-
children: (boolean, string) => React.
|
|
23
|
+
children: (boolean, string) => React.ReactNode;
|
|
24
24
|
selected?: boolean;
|
|
25
25
|
style?: ViewStyle[] | ViewStyle;
|
|
26
26
|
};
|
|
@@ -19,7 +19,7 @@ type Props = {
|
|
|
19
19
|
onPress?: (nativeEvent: any) => void;
|
|
20
20
|
onFocus?: (nativeEvent: any) => void;
|
|
21
21
|
onBlur?: (nativeEvent: any) => void;
|
|
22
|
-
children: (focused?: boolean) => React.ReactNode;
|
|
22
|
+
children: ((focused?: boolean) => React.ReactNode) | React.ReactNode;
|
|
23
23
|
isParallaxDisabled: boolean;
|
|
24
24
|
preferredFocus?: boolean;
|
|
25
25
|
selected?: boolean;
|
|
@@ -204,7 +204,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
204
204
|
{...this.nextFocusableReactTags}
|
|
205
205
|
{...otherProps}
|
|
206
206
|
>
|
|
207
|
-
{
|
|
207
|
+
{typeof children === "function" ? children(focused) : children}
|
|
208
208
|
</FocusableItemNative>
|
|
209
209
|
);
|
|
210
210
|
}
|
|
@@ -20,11 +20,11 @@ import { FocusableScrollView } from "../FocusableScrollView";
|
|
|
20
20
|
const mapIndexed = R.addIndex(R.map);
|
|
21
21
|
|
|
22
22
|
export type IListRenderItem<ItemT> = (
|
|
23
|
-
info:
|
|
23
|
+
info: {
|
|
24
24
|
focused: boolean;
|
|
25
25
|
onLoadFinished: () => void;
|
|
26
26
|
onLoadFailed: () => void;
|
|
27
|
-
}
|
|
27
|
+
} & IListRenderItemInfo<ItemT>
|
|
28
28
|
) => React.ReactElement | null;
|
|
29
29
|
|
|
30
30
|
export const getFocusableId = (parentId, index) =>
|
|
@@ -423,7 +423,10 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
423
423
|
id: playerContainerId,
|
|
424
424
|
listener: {
|
|
425
425
|
onVideoEnd,
|
|
426
|
-
onError
|
|
426
|
+
onError: (err: Error) => {
|
|
427
|
+
// Adapt Error to the expected shape for onError
|
|
428
|
+
onError({ error: err });
|
|
429
|
+
},
|
|
427
430
|
onLoad,
|
|
428
431
|
onPlayerClose: close,
|
|
429
432
|
onPlayerDetached: close,
|
|
@@ -13,6 +13,9 @@ import { riverLogger } from "./logger";
|
|
|
13
13
|
import { tvPluginsWithCellRenderer } from "../../const";
|
|
14
14
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
15
15
|
import type { BehaviorSubject } from "rxjs";
|
|
16
|
+
import {
|
|
17
|
+
useCallBackNavigationAction
|
|
18
|
+
} from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/callbackNavigationAction";
|
|
16
19
|
|
|
17
20
|
export type RiverItemType = {
|
|
18
21
|
item: ZappUIComponent;
|
|
@@ -85,6 +88,7 @@ function RiverItemComponent(props: RiverItemType) {
|
|
|
85
88
|
loadingState,
|
|
86
89
|
} = props;
|
|
87
90
|
|
|
91
|
+
const navigationActionCallback = useCallBackNavigationAction(item);
|
|
88
92
|
const readyToBeDisplayed = useLoadingState(index, loadingState);
|
|
89
93
|
|
|
90
94
|
const feedUrl = getFeedUrl(feed, index);
|
|
@@ -155,6 +159,7 @@ function RiverItemComponent(props: RiverItemType) {
|
|
|
155
159
|
groupId={groupId}
|
|
156
160
|
feedUrl={feedUrl}
|
|
157
161
|
isLast={isLast}
|
|
162
|
+
navigationActionCallback={navigationActionCallback}
|
|
158
163
|
/>
|
|
159
164
|
);
|
|
160
165
|
}
|
|
@@ -3,61 +3,172 @@ import { isMenuVisible } from "../navigationHandler";
|
|
|
3
3
|
describe("NavigationHandler", () => {
|
|
4
4
|
describe("isMenuVisible", () => {
|
|
5
5
|
it("returns false when the route is a player route", () => {
|
|
6
|
-
const menuVisible = isMenuVisible("/playable/some_vod_item", {}
|
|
6
|
+
const menuVisible = isMenuVisible("/playable/some_vod_item", {}, [
|
|
7
|
+
{
|
|
8
|
+
identifier: "quick-brick-bottom-tabs",
|
|
9
|
+
category: "menu",
|
|
10
|
+
name: "Bottom Tabs",
|
|
11
|
+
},
|
|
12
|
+
]);
|
|
13
|
+
|
|
7
14
|
expect(menuVisible).toBe(false);
|
|
8
15
|
});
|
|
9
16
|
|
|
10
17
|
describe("when screen is a hook", () => {
|
|
11
18
|
it("returns true if the `showNavBar` flag is set to true", () => {
|
|
12
|
-
const menuVisible = isMenuVisible(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
const menuVisible = isMenuVisible(
|
|
20
|
+
"",
|
|
21
|
+
{
|
|
22
|
+
hookPlugin: {
|
|
23
|
+
module: {
|
|
24
|
+
showNavBar: true,
|
|
25
|
+
},
|
|
16
26
|
},
|
|
27
|
+
navigations: [
|
|
28
|
+
{
|
|
29
|
+
navigation_type: "quick-brick-bottom-tabs",
|
|
30
|
+
identifier: "quick-brick-bottom-tabs",
|
|
31
|
+
category: "menu",
|
|
32
|
+
name: "Bottom Tabs",
|
|
33
|
+
},
|
|
34
|
+
],
|
|
17
35
|
},
|
|
18
|
-
|
|
36
|
+
[
|
|
37
|
+
{
|
|
38
|
+
identifier: "quick-brick-bottom-tabs",
|
|
39
|
+
category: "menu",
|
|
40
|
+
name: "Bottom Tabs",
|
|
41
|
+
},
|
|
42
|
+
]
|
|
43
|
+
);
|
|
19
44
|
|
|
20
45
|
expect(menuVisible).toBe(true);
|
|
21
46
|
});
|
|
22
47
|
|
|
23
48
|
it("returns true if presentFullScreen flag is set to false", () => {
|
|
24
|
-
const menuVisible = isMenuVisible(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
49
|
+
const menuVisible = isMenuVisible(
|
|
50
|
+
"",
|
|
51
|
+
{
|
|
52
|
+
hookPlugin: {
|
|
53
|
+
module: {
|
|
54
|
+
presentFullScreen: false,
|
|
55
|
+
},
|
|
28
56
|
},
|
|
57
|
+
navigations: [
|
|
58
|
+
{
|
|
59
|
+
navigation_type: "quick-brick-bottom-tabs",
|
|
60
|
+
identifier: "quick-brick-bottom-tabs",
|
|
61
|
+
category: "menu",
|
|
62
|
+
name: "Bottom Tabs",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
29
65
|
},
|
|
30
|
-
|
|
66
|
+
[
|
|
67
|
+
{
|
|
68
|
+
identifier: "quick-brick-bottom-tabs",
|
|
69
|
+
category: "menu",
|
|
70
|
+
name: "Bottom Tabs",
|
|
71
|
+
},
|
|
72
|
+
]
|
|
73
|
+
);
|
|
31
74
|
|
|
32
75
|
expect(menuVisible).toBe(true);
|
|
33
76
|
});
|
|
34
77
|
|
|
35
78
|
it("returns false if presentFullScreen flag is set to true", () => {
|
|
36
|
-
const menuVisible = isMenuVisible(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
79
|
+
const menuVisible = isMenuVisible(
|
|
80
|
+
"",
|
|
81
|
+
{
|
|
82
|
+
hookPlugin: {
|
|
83
|
+
module: {
|
|
84
|
+
presentFullScreen: true,
|
|
85
|
+
},
|
|
40
86
|
},
|
|
87
|
+
navigations: [
|
|
88
|
+
{
|
|
89
|
+
navigation_type: "quick-brick-bottom-tabs",
|
|
90
|
+
identifier: "quick-brick-bottom-tabs",
|
|
91
|
+
category: "menu",
|
|
92
|
+
name: "Bottom Tabs",
|
|
93
|
+
},
|
|
94
|
+
],
|
|
41
95
|
},
|
|
42
|
-
|
|
96
|
+
[
|
|
97
|
+
{
|
|
98
|
+
identifier: "quick-brick-bottom-tabs",
|
|
99
|
+
category: "menu",
|
|
100
|
+
name: "Bottom Tabs",
|
|
101
|
+
},
|
|
102
|
+
]
|
|
103
|
+
);
|
|
43
104
|
|
|
44
105
|
expect(menuVisible).toBe(false);
|
|
45
106
|
});
|
|
46
107
|
});
|
|
47
108
|
|
|
48
109
|
it("returns false if the screen's general settings allow screen presentation", () => {
|
|
49
|
-
const menuVisible = isMenuVisible(
|
|
50
|
-
|
|
51
|
-
|
|
110
|
+
const menuVisible = isMenuVisible(
|
|
111
|
+
"",
|
|
112
|
+
{
|
|
113
|
+
general: {
|
|
114
|
+
allow_screen_plugin_presentation: true,
|
|
115
|
+
},
|
|
116
|
+
navigations: [
|
|
117
|
+
{
|
|
118
|
+
navigation_type: "quick-brick-bottom-tabs",
|
|
119
|
+
identifier: "quick-brick-bottom-tabs",
|
|
120
|
+
category: "menu",
|
|
121
|
+
name: "Bottom Tabs",
|
|
122
|
+
},
|
|
123
|
+
],
|
|
52
124
|
},
|
|
53
|
-
|
|
125
|
+
[
|
|
126
|
+
{
|
|
127
|
+
identifier: "quick-brick-bottom-tabs",
|
|
128
|
+
category: "menu",
|
|
129
|
+
name: "Bottom Tabs",
|
|
130
|
+
},
|
|
131
|
+
]
|
|
132
|
+
);
|
|
54
133
|
|
|
55
134
|
expect(menuVisible).toBe(false);
|
|
56
135
|
});
|
|
57
136
|
|
|
58
|
-
it("returns
|
|
59
|
-
const menuVisible = isMenuVisible(
|
|
137
|
+
it("returns false otherwise", () => {
|
|
138
|
+
const menuVisible = isMenuVisible(
|
|
139
|
+
"any",
|
|
140
|
+
{
|
|
141
|
+
navigations: [
|
|
142
|
+
{
|
|
143
|
+
navigation_type: "quick-brick-bottom-tabs",
|
|
144
|
+
identifier: "quick-brick-bottom-tabs",
|
|
145
|
+
category: "menu",
|
|
146
|
+
name: "Bottom Tabs",
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
[
|
|
151
|
+
{
|
|
152
|
+
identifier: "quick-brick-bottom-tabs",
|
|
153
|
+
category: "menu",
|
|
154
|
+
name: "Bottom Tabs",
|
|
155
|
+
},
|
|
156
|
+
]
|
|
157
|
+
);
|
|
158
|
+
|
|
60
159
|
expect(menuVisible).toBe(true);
|
|
61
160
|
});
|
|
161
|
+
|
|
162
|
+
it("returns false otherwise", () => {
|
|
163
|
+
const menuVisible = isMenuVisible("", {}, [
|
|
164
|
+
{
|
|
165
|
+
identifier: "quick-brick-bottom-tabs",
|
|
166
|
+
category: "menu",
|
|
167
|
+
name: "Bottom Tabs",
|
|
168
|
+
},
|
|
169
|
+
]);
|
|
170
|
+
|
|
171
|
+
expect(menuVisible).toBe(false);
|
|
172
|
+
});
|
|
62
173
|
});
|
|
63
174
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveNavigationPlugin } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* This function helps to decide wether the menu should be presented on the screen
|
|
3
5
|
* based on route and / or screen Data
|
|
@@ -14,12 +16,28 @@
|
|
|
14
16
|
* @param {Object} screenData payload associated with the currently presented screen
|
|
15
17
|
* @returns {Boolean}
|
|
16
18
|
*/
|
|
17
|
-
export function isMenuVisible(route, screenData) {
|
|
19
|
+
export function isMenuVisible(route, screenData, plugins) {
|
|
20
|
+
const plugin = resolveNavigationPlugin({
|
|
21
|
+
category: "menu",
|
|
22
|
+
navigations:
|
|
23
|
+
screenData?.navigations || screenData?.targetScreen?.navigations,
|
|
24
|
+
plugins,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const isBottomTabsPlugin = plugin?.identifier === "quick-brick-bottom-tabs";
|
|
28
|
+
|
|
29
|
+
if (!isBottomTabsPlugin) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
if (route.includes("playable")) {
|
|
19
34
|
return false;
|
|
20
35
|
}
|
|
21
36
|
|
|
22
|
-
if (
|
|
37
|
+
if (
|
|
38
|
+
screenData.type === "qb_search_screen" ||
|
|
39
|
+
screenData?.targetScreen?.type === "qb_search_screen"
|
|
40
|
+
) {
|
|
23
41
|
return false;
|
|
24
42
|
}
|
|
25
43
|
|
|
@@ -62,7 +62,7 @@ const TabsComponent = ({
|
|
|
62
62
|
);
|
|
63
63
|
|
|
64
64
|
const renderItem = useCallback(
|
|
65
|
-
({ item, index, focused }) => {
|
|
65
|
+
({ item, index, focused }: { item: any; index: any; focused?: any }) => {
|
|
66
66
|
const itemId = generateFocusableId(getId(item));
|
|
67
67
|
|
|
68
68
|
const isSelected = R.equals(index, selectedEntryIndex);
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Animated, StyleSheet, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
PlayerAnimationStateEnum,
|
|
8
|
+
useModalAnimationContext,
|
|
9
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
10
|
+
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
11
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
resetScrollAnimatedValues,
|
|
15
|
+
setScrollModalAnimatedValue,
|
|
16
|
+
} from "./utils";
|
|
17
|
+
|
|
18
|
+
import { DURATION_TO_MINIMIZE } from "./const";
|
|
19
|
+
|
|
20
|
+
const getAnimatedConfig = (toValue) => {
|
|
21
|
+
return {
|
|
22
|
+
toValue,
|
|
23
|
+
duration: DURATION_TO_MINIMIZE,
|
|
24
|
+
useNativeDriver: true,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const generalStyles = StyleSheet.create({
|
|
29
|
+
container: {
|
|
30
|
+
flex: 1,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
type Props = {
|
|
35
|
+
children: React.ReactNode;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
39
|
+
const {
|
|
40
|
+
isActiveGesture,
|
|
41
|
+
playerAnimationState,
|
|
42
|
+
setPlayerAnimationState,
|
|
43
|
+
resetPlayerAnimationState,
|
|
44
|
+
animatedValues: {
|
|
45
|
+
lastScrollY,
|
|
46
|
+
dragScrollY,
|
|
47
|
+
dragVideoPlayerY,
|
|
48
|
+
translateYOffset,
|
|
49
|
+
},
|
|
50
|
+
lastScrollYValue,
|
|
51
|
+
scrollPosition,
|
|
52
|
+
modalSnapPoints,
|
|
53
|
+
setLastSnap,
|
|
54
|
+
setStartComponentsAnimation,
|
|
55
|
+
} = useModalAnimationContext();
|
|
56
|
+
|
|
57
|
+
const [enableGesture, setIEnableGesture] = React.useState<boolean>(true);
|
|
58
|
+
|
|
59
|
+
const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
|
|
60
|
+
useNavigation();
|
|
61
|
+
|
|
62
|
+
const {
|
|
63
|
+
mode: videoModalMode,
|
|
64
|
+
previousMode: previousVideoModalMode,
|
|
65
|
+
item: videoModalItem,
|
|
66
|
+
} = videoModalState;
|
|
67
|
+
|
|
68
|
+
const isMaximizedModal: boolean = videoModalMode === "MAXIMIZED";
|
|
69
|
+
const isMinimizedModal: boolean = videoModalMode === "MINIMIZED";
|
|
70
|
+
const previousItemId = usePrevious(videoModalItem?.id);
|
|
71
|
+
|
|
72
|
+
const isNotMinimizeMaximazeAnimation =
|
|
73
|
+
playerAnimationState !== PlayerAnimationStateEnum.minimize &&
|
|
74
|
+
playerAnimationState !== PlayerAnimationStateEnum.maximize;
|
|
75
|
+
|
|
76
|
+
const isAudioItem = React.useMemo(
|
|
77
|
+
() =>
|
|
78
|
+
videoModalItem?.content?.type?.includes?.("audio") ||
|
|
79
|
+
videoModalItem?.type?.value === "audio",
|
|
80
|
+
[videoModalItem]
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const onRegisterLastScroll = Animated.event(
|
|
84
|
+
[{ nativeEvent: { contentOffset: { y: lastScrollY } } }],
|
|
85
|
+
{ useNativeDriver: true }
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const onScroll = React.useCallback(({ nativeEvent }) => {
|
|
89
|
+
scrollPosition.current = nativeEvent.contentOffset.y;
|
|
90
|
+
}, []);
|
|
91
|
+
|
|
92
|
+
// Workaround for onMomentumScrollEnd issue
|
|
93
|
+
// https://github.com/facebook/react-native/issues/32696#issuecomment-1104217223
|
|
94
|
+
const canMomentum = React.useRef(false);
|
|
95
|
+
|
|
96
|
+
const onMomentumScrollBegin = React.useCallback(() => {
|
|
97
|
+
canMomentum.current = true;
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
const onMomentumScrollEnd = React.useCallback(
|
|
101
|
+
({ nativeEvent }) => {
|
|
102
|
+
if (canMomentum.current && !isActiveGesture) {
|
|
103
|
+
if (nativeEvent.contentOffset.y === 0) {
|
|
104
|
+
resetScrollAnimatedValues(
|
|
105
|
+
lastScrollY,
|
|
106
|
+
lastScrollYValue,
|
|
107
|
+
dragScrollY,
|
|
108
|
+
dragVideoPlayerY
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
setIEnableGesture(true);
|
|
112
|
+
} else {
|
|
113
|
+
setIEnableGesture(false);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
canMomentum.current = false;
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
[isActiveGesture]
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
React.useEffect(() => {
|
|
123
|
+
return () => {
|
|
124
|
+
scrollPosition.current = 0;
|
|
125
|
+
|
|
126
|
+
resetScrollAnimatedValues(
|
|
127
|
+
lastScrollY,
|
|
128
|
+
lastScrollYValue,
|
|
129
|
+
dragScrollY,
|
|
130
|
+
dragVideoPlayerY
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
React.useEffect(() => {
|
|
136
|
+
if (
|
|
137
|
+
videoModalMode === "MAXIMIZED" &&
|
|
138
|
+
!enableGesture &&
|
|
139
|
+
scrollPosition.current === 0
|
|
140
|
+
) {
|
|
141
|
+
setIEnableGesture(true);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
videoModalMode === "MINIMIZED" &&
|
|
146
|
+
previousVideoModalMode === "MAXIMIZED"
|
|
147
|
+
) {
|
|
148
|
+
// set animation to the minimize values if moving from the player to another screen
|
|
149
|
+
if (playerAnimationState === null) {
|
|
150
|
+
setScrollModalAnimatedValue(
|
|
151
|
+
translateYOffset,
|
|
152
|
+
modalSnapPoints[1],
|
|
153
|
+
setLastSnap
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
resetScrollAnimatedValues(
|
|
157
|
+
lastScrollY,
|
|
158
|
+
lastScrollYValue,
|
|
159
|
+
dragScrollY,
|
|
160
|
+
dragVideoPlayerY
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
} else if (
|
|
164
|
+
playerAnimationState === null &&
|
|
165
|
+
((previousItemId === videoModalItem?.id &&
|
|
166
|
+
videoModalMode === "MAXIMIZED" &&
|
|
167
|
+
(previousVideoModalMode === "MINIMIZED" ||
|
|
168
|
+
previousVideoModalMode === "MAXIMIZED")) ||
|
|
169
|
+
(previousItemId !== videoModalItem?.id &&
|
|
170
|
+
videoModalMode !== "FULLSCREEN"))
|
|
171
|
+
) {
|
|
172
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximize);
|
|
173
|
+
}
|
|
174
|
+
}, [videoModalMode, previousVideoModalMode, videoModalItem]);
|
|
175
|
+
|
|
176
|
+
React.useEffect(() => {
|
|
177
|
+
if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
|
|
178
|
+
if (
|
|
179
|
+
(scrollPosition.current === 0 &&
|
|
180
|
+
(lastScrollY as any)._value !== 0 &&
|
|
181
|
+
(dragScrollY as any)._value === 0 &&
|
|
182
|
+
(dragVideoPlayerY as any)._value === 0) ||
|
|
183
|
+
(scrollPosition.current !== 0 &&
|
|
184
|
+
((dragScrollY as any)._value !== 0 ||
|
|
185
|
+
(dragVideoPlayerY as any)._value !== 0))
|
|
186
|
+
) {
|
|
187
|
+
resetScrollAnimatedValues(
|
|
188
|
+
lastScrollY,
|
|
189
|
+
lastScrollYValue,
|
|
190
|
+
dragScrollY,
|
|
191
|
+
dragVideoPlayerY
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
Animated.timing(
|
|
196
|
+
translateYOffset,
|
|
197
|
+
getAnimatedConfig(modalSnapPoints[1])
|
|
198
|
+
).start(() => {
|
|
199
|
+
minimiseVideoModal();
|
|
200
|
+
|
|
201
|
+
setScrollModalAnimatedValue(
|
|
202
|
+
translateYOffset,
|
|
203
|
+
modalSnapPoints[1],
|
|
204
|
+
setLastSnap
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
resetScrollAnimatedValues(
|
|
208
|
+
lastScrollY,
|
|
209
|
+
lastScrollYValue,
|
|
210
|
+
dragScrollY,
|
|
211
|
+
dragVideoPlayerY
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
resetPlayerAnimationState();
|
|
215
|
+
});
|
|
216
|
+
} else if (playerAnimationState === PlayerAnimationStateEnum.maximize) {
|
|
217
|
+
Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
|
|
218
|
+
maximiseVideoModal();
|
|
219
|
+
setScrollModalAnimatedValue(translateYOffset, 0, setLastSnap);
|
|
220
|
+
|
|
221
|
+
resetScrollAnimatedValues(
|
|
222
|
+
lastScrollY,
|
|
223
|
+
lastScrollYValue,
|
|
224
|
+
dragScrollY,
|
|
225
|
+
dragVideoPlayerY
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
resetPlayerAnimationState();
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}, [playerAnimationState]);
|
|
232
|
+
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
|
|
235
|
+
lastScrollYValue.current = value;
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const dragListenerId = dragScrollY.addListener(({ value }) => {
|
|
239
|
+
const preparedValue =
|
|
240
|
+
isMinimizedModal && value >= 0
|
|
241
|
+
? 0
|
|
242
|
+
: Math.round(isAudioItem ? Math.abs(value) : value);
|
|
243
|
+
|
|
244
|
+
if (
|
|
245
|
+
preparedValue > 0 &&
|
|
246
|
+
scrollPosition.current === 0 &&
|
|
247
|
+
playerAnimationState !== PlayerAnimationStateEnum.drag_player &&
|
|
248
|
+
playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
|
|
249
|
+
) {
|
|
250
|
+
isMinimizedModal && setStartComponentsAnimation(true);
|
|
251
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.drag_scroll);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
return () => {
|
|
256
|
+
lastScrollY.removeListener(lastScrollYListenerId);
|
|
257
|
+
dragScrollY.removeListener(dragListenerId);
|
|
258
|
+
};
|
|
259
|
+
}, [playerAnimationState, isAudioItem, isMinimizedModal]);
|
|
260
|
+
|
|
261
|
+
const scrollEnabled = isMaximizedModal && isNotMinimizeMaximazeAnimation;
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<View style={generalStyles.container}>
|
|
265
|
+
<View pointerEvents="box-none">
|
|
266
|
+
<Animated.View>
|
|
267
|
+
<Animated.ScrollView
|
|
268
|
+
scrollEnabled={scrollEnabled}
|
|
269
|
+
bounces={false}
|
|
270
|
+
onScrollBeginDrag={onRegisterLastScroll}
|
|
271
|
+
onScroll={onScroll}
|
|
272
|
+
onMomentumScrollBegin={onMomentumScrollBegin}
|
|
273
|
+
onMomentumScrollEnd={onMomentumScrollEnd}
|
|
274
|
+
scrollEventThrottle={1}
|
|
275
|
+
showsVerticalScrollIndicator={false}
|
|
276
|
+
>
|
|
277
|
+
{children}
|
|
278
|
+
</Animated.ScrollView>
|
|
279
|
+
</Animated.View>
|
|
280
|
+
</View>
|
|
281
|
+
</View>
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export const AnimatedScrollModal = ({ children }: Props) => {
|
|
286
|
+
const {
|
|
287
|
+
videoModalState: { visible },
|
|
288
|
+
} = useNavigation();
|
|
289
|
+
|
|
290
|
+
const Component =
|
|
291
|
+
!isTV() && visible ? AnimatedScrollModalComponent : React.Fragment;
|
|
292
|
+
|
|
293
|
+
return <Component>{children}</Component>;
|
|
294
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Animated, StyleSheet } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
useModalAnimationContext,
|
|
8
|
+
PlayerAnimationStateEnum,
|
|
9
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
10
|
+
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
11
|
+
|
|
12
|
+
const generalStyles = StyleSheet.create({
|
|
13
|
+
container: {
|
|
14
|
+
flex: 1,
|
|
15
|
+
width: "100%",
|
|
16
|
+
position: "absolute",
|
|
17
|
+
zIndex: 201,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
type Props = {
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const AnimatedVideoPlayer = ({ children }: Props) => {
|
|
26
|
+
const {
|
|
27
|
+
playerAnimationState,
|
|
28
|
+
setPlayerAnimationState,
|
|
29
|
+
animatedValues: { translateYOffset, dragVideoPlayerY },
|
|
30
|
+
modalSnapPoints,
|
|
31
|
+
setStartComponentsAnimation,
|
|
32
|
+
} = useModalAnimationContext();
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
videoModalState: { mode: videoModalMode },
|
|
36
|
+
} = useNavigation();
|
|
37
|
+
|
|
38
|
+
const isMaximazedModal = videoModalMode === "MAXIMIZED";
|
|
39
|
+
const isMinimizedModal = videoModalMode === "MINIMIZED";
|
|
40
|
+
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
|
|
43
|
+
({ value }) => {
|
|
44
|
+
if (
|
|
45
|
+
(isMinimizedModal && value >= 0) ||
|
|
46
|
+
(isMaximazedModal && value <= 0)
|
|
47
|
+
) {
|
|
48
|
+
if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
|
|
49
|
+
translateYOffset.setValue(
|
|
50
|
+
modalSnapPoints[isMinimizedModal ? 1 : 0]
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
const preparedValue = Math.round(Math.abs(value));
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
preparedValue > 0 &&
|
|
58
|
+
playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
|
|
59
|
+
) {
|
|
60
|
+
if (playerAnimationState !== PlayerAnimationStateEnum.drag_player) {
|
|
61
|
+
isMinimizedModal && setStartComponentsAnimation(true);
|
|
62
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.drag_player);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
translateYOffset.setValue(
|
|
66
|
+
isMaximazedModal
|
|
67
|
+
? preparedValue
|
|
68
|
+
: modalSnapPoints[1] - preparedValue
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
dragVideoPlayerY.removeListener(dragVideoPlayerYListenerId);
|
|
77
|
+
};
|
|
78
|
+
}, [playerAnimationState, isMinimizedModal, isMaximazedModal]);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<Animated.View style={generalStyles.container}>{children}</Animated.View>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const AnimatedVideoPlayerComponent = ({ children }: Props) => {
|
|
86
|
+
const {
|
|
87
|
+
videoModalState: { visible },
|
|
88
|
+
} = useNavigation();
|
|
89
|
+
|
|
90
|
+
const Component = !isTV() && visible ? AnimatedVideoPlayer : React.Fragment;
|
|
91
|
+
|
|
92
|
+
return <Component>{children}</Component>;
|
|
93
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "14.0.0-alpha.
|
|
3
|
+
"version": "14.0.0-alpha.5234792518",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "14.0.0-alpha.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "14.0.0-alpha.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "14.0.0-alpha.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "14.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "14.0.0-alpha.5234792518",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "14.0.0-alpha.5234792518",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "14.0.0-alpha.5234792518",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "14.0.0-alpha.5234792518",
|
|
35
35
|
"promise": "^8.3.0",
|
|
36
36
|
"url": "^0.11.0",
|
|
37
37
|
"uuid": "^3.3.2"
|