@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5471145113 → 12.0.0-alpha.5522474195
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/BaseFocusable/index.tsx +2 -2
- package/Components/Cell/CellWithFocusable.tsx +6 -4
- package/Components/Cell/TvOSCellComponent.tsx +3 -7
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableGroup/index.tsx +10 -2
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +7 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +6 -1
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +5 -1
- package/Components/Screen/TV/index.web.tsx +9 -2
- package/Components/VideoLive/LiveImageManager.ts +10 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +48 -38
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +40 -33
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +98 -81
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +13 -5
- package/Components/VideoModal/ModalAnimation/utils.ts +6 -4
- package/Components/VideoModal/PlayerWrapper.tsx +1 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -12
- package/Components/VideoModal/utils.ts +5 -2
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/ScreenContext/index.tsx +0 -6
- package/package.json +5 -5
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
|
@@ -71,9 +71,9 @@ export class BaseFocusable<
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
getId(props?: { id: string; groupId: string }) {
|
|
74
|
-
const { id
|
|
74
|
+
const { id } = props || this.props;
|
|
75
75
|
|
|
76
|
-
return
|
|
76
|
+
return id;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
getRect() {
|
|
@@ -3,6 +3,8 @@ import * as React from "react";
|
|
|
3
3
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
4
4
|
import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
|
|
5
5
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
6
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
|
+
|
|
6
8
|
import { isAppleTV } from "../../Helpers/Platform";
|
|
7
9
|
import { useCellState } from "../MasterCell/utils";
|
|
8
10
|
|
|
@@ -54,7 +56,7 @@ type Props = {
|
|
|
54
56
|
skipFocusManagerRegistration?: boolean;
|
|
55
57
|
isFocusable?: boolean;
|
|
56
58
|
behavior: Behavior;
|
|
57
|
-
|
|
59
|
+
focused?: boolean;
|
|
58
60
|
};
|
|
59
61
|
|
|
60
62
|
export function CellWithFocusable(props: Props) {
|
|
@@ -70,7 +72,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
70
72
|
skipFocusManagerRegistration,
|
|
71
73
|
isFocusable,
|
|
72
74
|
behavior,
|
|
73
|
-
|
|
75
|
+
focused,
|
|
74
76
|
} = props;
|
|
75
77
|
|
|
76
78
|
const isFocused = useCellFocusedState(
|
|
@@ -82,8 +84,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
82
84
|
const state = useCellState({
|
|
83
85
|
id: item.id,
|
|
84
86
|
behavior,
|
|
85
|
-
focused: isFocused,
|
|
86
|
-
selected,
|
|
87
|
+
focused: isFocused || toBooleanWithDefaultFalse(focused),
|
|
87
88
|
});
|
|
88
89
|
|
|
89
90
|
const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
|
|
@@ -114,6 +115,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
114
115
|
preferredFocus={preferredFocus}
|
|
115
116
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
116
117
|
isFocusable={isFocusable}
|
|
118
|
+
focused={focused}
|
|
117
119
|
/>
|
|
118
120
|
);
|
|
119
121
|
}
|
|
@@ -226,13 +226,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
226
226
|
|
|
227
227
|
hasReceivedFocus() {}
|
|
228
228
|
|
|
229
|
-
scrollTo(
|
|
230
|
-
// Workaround for HL autoscroll/autoloop feature, we scroll manually on tvOS.
|
|
231
|
-
// Should be removed after refactoring autoscroll/autoloop feature
|
|
232
|
-
if (this.props.component?.component_type !== "horizontal_list_qb") {
|
|
233
|
-
this.props?.scrollToIndex?.(index);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
229
|
+
scrollTo() {}
|
|
236
230
|
|
|
237
231
|
render() {
|
|
238
232
|
const {
|
|
@@ -279,7 +273,9 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
279
273
|
index={index}
|
|
280
274
|
scrollTo={this.scrollTo}
|
|
281
275
|
preferredFocus={preferredFocus}
|
|
276
|
+
focused={this.props.focused}
|
|
282
277
|
behavior={behavior}
|
|
278
|
+
isFocusable={isFocusable}
|
|
283
279
|
/>
|
|
284
280
|
</View>
|
|
285
281
|
);
|
|
@@ -4,6 +4,7 @@ import * as R from "ramda";
|
|
|
4
4
|
import { BaseFocusable } from "../BaseFocusable";
|
|
5
5
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
6
6
|
import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
|
|
7
|
+
import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
9
10
|
initialFocus?: boolean;
|
|
@@ -23,7 +24,7 @@ type Props = {
|
|
|
23
24
|
style?: React.CSSProperties;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
class Focusable extends BaseFocusable<Props> {
|
|
27
28
|
isGroup: boolean;
|
|
28
29
|
mouse: boolean;
|
|
29
30
|
longPressTimeout = null;
|
|
@@ -198,3 +199,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
198
199
|
);
|
|
199
200
|
}
|
|
200
201
|
}
|
|
202
|
+
|
|
203
|
+
const FocusableWithFocusableContext = withFocusableContext(Focusable);
|
|
204
|
+
|
|
205
|
+
export { FocusableWithFocusableContext as Focusable };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
import { BaseFocusable } from "../BaseFocusable";
|
|
4
|
+
import { FocusableGroupContextProvider } from "../../Contexts/FocusableGroupContext";
|
|
5
|
+
import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
|
|
4
6
|
|
|
5
7
|
type Props = {
|
|
6
8
|
testID?: string;
|
|
@@ -29,7 +31,7 @@ type Props = {
|
|
|
29
31
|
excludeFromFocusSearching?: boolean;
|
|
30
32
|
};
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
class FocusableGroup extends BaseFocusable<Props> {
|
|
33
35
|
constructor(props) {
|
|
34
36
|
super(props);
|
|
35
37
|
this.isGroup = true;
|
|
@@ -82,8 +84,14 @@ export class FocusableGroup extends BaseFocusable<Props> {
|
|
|
82
84
|
style={style}
|
|
83
85
|
ref={this.ref}
|
|
84
86
|
>
|
|
85
|
-
{
|
|
87
|
+
<FocusableGroupContextProvider id={id}>
|
|
88
|
+
{children}
|
|
89
|
+
</FocusableGroupContextProvider>
|
|
86
90
|
</div>
|
|
87
91
|
);
|
|
88
92
|
}
|
|
89
93
|
}
|
|
94
|
+
|
|
95
|
+
const FocusableGroupWithFocusableContext = withFocusableContext(FocusableGroup);
|
|
96
|
+
|
|
97
|
+
export { FocusableGroupWithFocusableContext as FocusableGroup };
|
|
@@ -22,6 +22,10 @@ const styles = StyleSheet.create({
|
|
|
22
22
|
borderWidth: 0,
|
|
23
23
|
borderColor: COLOR_TRANSPARENT,
|
|
24
24
|
},
|
|
25
|
+
border: {
|
|
26
|
+
...StyleSheet.absoluteFillObject,
|
|
27
|
+
zIndex: 1,
|
|
28
|
+
},
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
const getBorderPadding = (borderPosition: BorderPosition, borderWidth) => {
|
|
@@ -87,8 +91,9 @@ const Border = ({
|
|
|
87
91
|
|
|
88
92
|
return (
|
|
89
93
|
<View
|
|
94
|
+
pointerEvents="none"
|
|
90
95
|
style={{
|
|
91
|
-
...
|
|
96
|
+
...styles.border,
|
|
92
97
|
right: -containerPadding - paddingRight,
|
|
93
98
|
bottom: -containerPadding - paddingBottom,
|
|
94
99
|
left: -containerPadding - paddingLeft,
|
|
@@ -130,8 +135,8 @@ export const BorderContainerView = (props: Props) => {
|
|
|
130
135
|
{...props}
|
|
131
136
|
style={[style, styles.container, borderStyleForMissingBorder]}
|
|
132
137
|
>
|
|
133
|
-
{children}
|
|
134
138
|
<Border style={style} padding={padding} borderPosition={borderPosition} />
|
|
139
|
+
{children}
|
|
135
140
|
</View>
|
|
136
141
|
);
|
|
137
142
|
};
|
|
@@ -4,6 +4,7 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
|
|
|
4
4
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
7
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
8
|
|
|
8
9
|
const { Logger } = getXray();
|
|
9
10
|
|
|
@@ -35,7 +36,9 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
35
36
|
|
|
36
37
|
const focusableId = getFocusableId(prefixId, suffixId);
|
|
37
38
|
|
|
38
|
-
const focused =
|
|
39
|
+
const focused =
|
|
40
|
+
focusableId === focusedButtonId ||
|
|
41
|
+
toBooleanWithDefaultFalse(otherProps.focused);
|
|
39
42
|
|
|
40
43
|
const additionalStyles = focused ? focusedStyles : normalStyles;
|
|
41
44
|
|
|
@@ -7,6 +7,10 @@ import type {
|
|
|
7
7
|
ContainerProps,
|
|
8
8
|
ContainerChildren,
|
|
9
9
|
} from "./types";
|
|
10
|
+
import {
|
|
11
|
+
useIsRTL,
|
|
12
|
+
applyRTLStylesIfNeeded,
|
|
13
|
+
} from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
10
14
|
|
|
11
15
|
const HorizontalSeparator = ({ width }: HorizontalSeparatorProps) => (
|
|
12
16
|
<View style={{ width }} />
|
|
@@ -17,6 +21,7 @@ export function ButtonContainerView({
|
|
|
17
21
|
children,
|
|
18
22
|
...otherProps
|
|
19
23
|
}: ContainerProps) {
|
|
24
|
+
const isRTL = useIsRTL();
|
|
20
25
|
const horizontalGutter = R.pathOr(0, ["horizontalGutter"], otherProps);
|
|
21
26
|
|
|
22
27
|
const filteredChildren = useFilterChildren<ContainerChildren>(children);
|
|
@@ -26,7 +31,7 @@ export function ButtonContainerView({
|
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
return (
|
|
29
|
-
<View style={style}>
|
|
34
|
+
<View style={applyRTLStylesIfNeeded(style, isRTL)}>
|
|
30
35
|
{insertBetween(
|
|
31
36
|
(index) => (
|
|
32
37
|
<HorizontalSeparator
|
|
@@ -9,4 +9,13 @@ describe("insertBetween", () => {
|
|
|
9
9
|
|
|
10
10
|
expect(result).toEqual([1, "|", 2, "|", 3]);
|
|
11
11
|
});
|
|
12
|
+
|
|
13
|
+
it("insertBetween", () => {
|
|
14
|
+
const separator = (index) => `separator:${index}`;
|
|
15
|
+
const items = [1, 2, 3];
|
|
16
|
+
|
|
17
|
+
const result = insertBetween(separator, items);
|
|
18
|
+
|
|
19
|
+
expect(result).toEqual([1, "separator:0", 2, "separator:1", 3]);
|
|
20
|
+
});
|
|
12
21
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useMemo } from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
import validateColor from "validate-color";
|
|
3
4
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
5
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
6
|
|
|
@@ -52,7 +53,10 @@ function resolveColorForProp(entry, style, colorProp) {
|
|
|
52
53
|
const colorFromProp = style[colorProp];
|
|
53
54
|
const nestedEntryValue = R.path(colorFromProp.split("."), entry);
|
|
54
55
|
|
|
55
|
-
if (
|
|
56
|
+
if (
|
|
57
|
+
nestedEntryValue === undefined &&
|
|
58
|
+
!validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
|
|
59
|
+
) {
|
|
56
60
|
logWarning(colorFromProp, style, entry, nestedEntryValue);
|
|
57
61
|
}
|
|
58
62
|
|
|
@@ -42,6 +42,13 @@ const getPluginType = pathOr("unknown_plugin_type", [
|
|
|
42
42
|
"plugin_type",
|
|
43
43
|
]);
|
|
44
44
|
|
|
45
|
+
export const isPresentFullScreen = pathOr(false, [
|
|
46
|
+
"state",
|
|
47
|
+
"screen",
|
|
48
|
+
"module",
|
|
49
|
+
"presentFullScreen",
|
|
50
|
+
]);
|
|
51
|
+
|
|
45
52
|
const isPlayerPlugin = (routeState): boolean =>
|
|
46
53
|
getPluginType(routeState) === "player";
|
|
47
54
|
|
|
@@ -150,8 +157,9 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
150
157
|
|
|
151
158
|
const isPlayer = isPlayerPlugin(routeState);
|
|
152
159
|
const isLogin = isLoginPlugin(routeState);
|
|
160
|
+
const isFullScreen = isPresentFullScreen(routeState);
|
|
153
161
|
|
|
154
|
-
const isNavBarVisible = !isPlayer && !isLogin;
|
|
162
|
+
const isNavBarVisible = !isPlayer && !isLogin && !isFullScreen;
|
|
155
163
|
|
|
156
164
|
const screenData =
|
|
157
165
|
screenType === "hooks" || isPlayer
|
|
@@ -162,7 +170,6 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
162
170
|
<View style={[styles.container, { backgroundColor }]}>
|
|
163
171
|
<NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
|
|
164
172
|
<NavBar
|
|
165
|
-
groupId={route}
|
|
166
173
|
isVisible={isNavBarVisible}
|
|
167
174
|
menuPlugin={menuPlugin}
|
|
168
175
|
navigationProps={navigationProps}
|
|
@@ -525,6 +525,16 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
|
|
|
525
525
|
LiveImageManager.instance.onLiveImageError(this, error);
|
|
526
526
|
};
|
|
527
527
|
|
|
528
|
+
onVideoError = (error: Error) => {
|
|
529
|
+
log_error(
|
|
530
|
+
`onVideoError: live-image, fail to play, switching back to image. error: ${
|
|
531
|
+
error?.message
|
|
532
|
+
}, ${playerInfo(this.player)}`
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
LiveImageManager.instance.onLiveImageError(this, error);
|
|
536
|
+
};
|
|
537
|
+
|
|
528
538
|
onVideoEnd = (_event) => {
|
|
529
539
|
log_info(
|
|
530
540
|
`onVideoEnd: live-image, video completed, switching back to image, ${playerInfo(
|
|
@@ -100,58 +100,68 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
100
100
|
{ useNativeDriver: true }
|
|
101
101
|
);
|
|
102
102
|
|
|
103
|
-
const onHandlerStateChange = (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
const onHandlerStateChange = React.useCallback(
|
|
104
|
+
({ nativeEvent }) => {
|
|
105
|
+
if (
|
|
106
|
+
nativeEvent.oldState === State.ACTIVE &&
|
|
107
|
+
scrollPosition.current === 0
|
|
108
|
+
) {
|
|
109
|
+
// eslint-disable-next-line prefer-const
|
|
110
|
+
const { velocityY, translationY } = nativeEvent;
|
|
111
|
+
const dragToss = 0.05;
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
const preparedTranslationY =
|
|
114
|
+
Math.abs(translationY) - lastScrollYValue.current;
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
if (videoModalState.mode === "MAXIMIZED") {
|
|
117
|
+
const endOffsetY =
|
|
118
|
+
lastSnap + preparedTranslationY + dragToss * velocityY + 150;
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
let destSnapPoint = modalSnapPoints[0];
|
|
117
121
|
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
for (const snapPoint of modalSnapPoints) {
|
|
123
|
+
const distFromSnap = Math.abs(snapPoint - endOffsetY);
|
|
120
124
|
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
|
|
126
|
+
destSnapPoint = snapPoint;
|
|
127
|
+
}
|
|
123
128
|
}
|
|
124
|
-
}
|
|
125
129
|
|
|
126
|
-
|
|
130
|
+
setLastSnap(destSnapPoint);
|
|
127
131
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
if (destSnapPoint === modalSnapPoints[0]) {
|
|
133
|
+
translateYOffset.extractOffset();
|
|
134
|
+
translateYOffset.setValue(preparedTranslationY);
|
|
135
|
+
translateYOffset.flattenOffset();
|
|
136
|
+
dragScrollY.setValue(0);
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
139
|
+
} else {
|
|
140
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
|
|
141
|
+
}
|
|
135
142
|
} else {
|
|
136
|
-
|
|
143
|
+
if (translationY < 0) {
|
|
144
|
+
// from mini to full
|
|
145
|
+
setLastSnap(modalSnapPoints[0]);
|
|
146
|
+
|
|
147
|
+
translateYOffset.setValue(
|
|
148
|
+
modalSnapPoints[1] - preparedTranslationY
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
dragScrollY.setValue(0);
|
|
152
|
+
|
|
153
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
154
|
+
} else {
|
|
155
|
+
resetPlayerAnimationState();
|
|
156
|
+
}
|
|
137
157
|
}
|
|
138
158
|
} else {
|
|
139
|
-
|
|
140
|
-
// from mini to full
|
|
141
|
-
setLastSnap(modalSnapPoints[0]);
|
|
142
|
-
translateYOffset.setValue(modalSnapPoints[1] - preparedTranslationY);
|
|
143
|
-
dragScrollY.setValue(0);
|
|
144
|
-
|
|
145
|
-
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
146
|
-
} else {
|
|
159
|
+
playerAnimationState === PlayerAnimationStateEnum.drag_scroll &&
|
|
147
160
|
resetPlayerAnimationState();
|
|
148
|
-
}
|
|
149
161
|
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
};
|
|
162
|
+
},
|
|
163
|
+
[lastSnap, modalSnapPoints, playerAnimationState, videoModalState.mode]
|
|
164
|
+
);
|
|
155
165
|
|
|
156
166
|
const onScroll = React.useCallback(({ nativeEvent }) => {
|
|
157
167
|
scrollPosition.current = nativeEvent.contentOffset.y;
|
|
@@ -50,50 +50,57 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
|
|
|
50
50
|
{ useNativeDriver: true }
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
const onHandlerStateChange = (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
const onHandlerStateChange = React.useCallback(
|
|
54
|
+
({ nativeEvent }) => {
|
|
55
|
+
if (nativeEvent.oldState === State.ACTIVE) {
|
|
56
|
+
// eslint-disable-next-line prefer-const
|
|
57
|
+
const { velocityY, translationY } = nativeEvent;
|
|
58
|
+
const preparedTranslationY = Math.abs(translationY);
|
|
59
|
+
const dragToss = 0.05;
|
|
60
|
+
|
|
61
|
+
if (videoModalState.mode === "MAXIMIZED") {
|
|
62
|
+
if (translationY > 0) {
|
|
63
|
+
const endOffsetY =
|
|
64
|
+
lastSnap + preparedTranslationY + dragToss * velocityY + 200;
|
|
65
|
+
|
|
66
|
+
let destSnapPoint = modalSnapPoints[0];
|
|
67
|
+
|
|
68
|
+
for (const snapPoint of modalSnapPoints) {
|
|
69
|
+
const distFromSnap = Math.abs(snapPoint - endOffsetY);
|
|
70
|
+
|
|
71
|
+
if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
|
|
72
|
+
destSnapPoint = snapPoint;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
const distFromSnap = Math.abs(snapPoint - endOffsetY);
|
|
76
|
+
setLastSnap(destSnapPoint);
|
|
69
77
|
|
|
70
|
-
if (
|
|
71
|
-
|
|
78
|
+
if (destSnapPoint === modalSnapPoints[0]) {
|
|
79
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
80
|
+
} else {
|
|
81
|
+
lastScrollY.setValue(0);
|
|
82
|
+
lastScrollYValue.current = 0;
|
|
83
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
|
|
72
84
|
}
|
|
73
85
|
}
|
|
86
|
+
} else if (videoModalState.mode === "MINIMIZED") {
|
|
87
|
+
if (translationY < 0) {
|
|
88
|
+
// from mini to full
|
|
89
|
+
setLastSnap(modalSnapPoints[0]);
|
|
74
90
|
|
|
75
|
-
|
|
91
|
+
translateYOffset.setValue(
|
|
92
|
+
modalSnapPoints[1] - preparedTranslationY
|
|
93
|
+
);
|
|
76
94
|
|
|
77
|
-
if (destSnapPoint === modalSnapPoints[0]) {
|
|
78
95
|
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
79
96
|
} else {
|
|
80
|
-
|
|
81
|
-
lastScrollYValue.current = 0;
|
|
82
|
-
setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
|
|
97
|
+
resetPlayerAnimationState();
|
|
83
98
|
}
|
|
84
99
|
}
|
|
85
|
-
} else if (videoModalState.mode === "MINIMIZED") {
|
|
86
|
-
if (translationY < 0) {
|
|
87
|
-
// from mini to full
|
|
88
|
-
setLastSnap(modalSnapPoints[0]);
|
|
89
|
-
translateYOffset.setValue(modalSnapPoints[1] - preparedTranslationY);
|
|
90
|
-
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
91
|
-
} else {
|
|
92
|
-
resetPlayerAnimationState();
|
|
93
|
-
}
|
|
94
100
|
}
|
|
95
|
-
}
|
|
96
|
-
|
|
101
|
+
},
|
|
102
|
+
[lastSnap, modalSnapPoints, videoModalState.mode]
|
|
103
|
+
);
|
|
97
104
|
|
|
98
105
|
React.useEffect(() => {
|
|
99
106
|
const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import React, { useRef, useState } from "react";
|
|
2
|
-
import { Animated, View
|
|
2
|
+
import { Animated, View } from "react-native";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
useSafeAreaInsets,
|
|
6
|
-
useSafeAreaFrame,
|
|
7
|
-
} from "react-native-safe-area-context";
|
|
4
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
8
5
|
|
|
9
6
|
import {
|
|
10
7
|
useModalAnimationContext,
|
|
@@ -18,6 +15,7 @@ import {
|
|
|
18
15
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
19
16
|
import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
20
17
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
18
|
+
import { useAppState } from "@applicaster/zapp-react-native-utils/reactHooks/app";
|
|
21
19
|
|
|
22
20
|
import {
|
|
23
21
|
gestureListenerHelper,
|
|
@@ -35,10 +33,6 @@ type Props = {
|
|
|
35
33
|
additionalData?: { [key: string]: any };
|
|
36
34
|
};
|
|
37
35
|
|
|
38
|
-
const styles = StyleSheet.create({
|
|
39
|
-
flex: { flex: 1 },
|
|
40
|
-
});
|
|
41
|
-
|
|
42
36
|
export const AnimationView = ({
|
|
43
37
|
animationType,
|
|
44
38
|
style,
|
|
@@ -56,21 +50,21 @@ export const AnimationView = ({
|
|
|
56
50
|
tabletLandscapePlayerTopPosition,
|
|
57
51
|
setTabletLandscapePlayerTopPosition,
|
|
58
52
|
modalSnapPoints,
|
|
53
|
+
startComponentsAnimationDistance,
|
|
59
54
|
} = useModalAnimationContext();
|
|
60
55
|
|
|
61
56
|
const isRTL = useIsRTL();
|
|
57
|
+
const isAppActive = useAppState(true);
|
|
62
58
|
|
|
63
59
|
const {
|
|
64
|
-
|
|
60
|
+
width: screenWidth,
|
|
65
61
|
deviceInfo: { isTablet, isTabletLandscape },
|
|
66
|
-
} = useDimensions("
|
|
62
|
+
} = useDimensions("window", { deviceInfo: true });
|
|
67
63
|
|
|
68
|
-
const startAnimationDistance = Math.round((screenHeight * 60) / 100);
|
|
69
64
|
const { videoModalState } = useNavigation();
|
|
70
65
|
const bottomTabBarHeight = useGetBottomTabBarHeight();
|
|
71
66
|
const minimisedWidth = defaultAspectRatioWidth(minimisedHeight);
|
|
72
67
|
const insets = useSafeAreaInsets();
|
|
73
|
-
const { width: screenWidth } = useSafeAreaFrame();
|
|
74
68
|
const animationComponentRef = useRef(null);
|
|
75
69
|
|
|
76
70
|
// retrieving top position of the player for tablet landscape mode
|
|
@@ -88,13 +82,6 @@ export const AnimationView = ({
|
|
|
88
82
|
getAnimationDefaultValue(animationType, bottomTabBarHeight)
|
|
89
83
|
);
|
|
90
84
|
|
|
91
|
-
const animationValueType: string =
|
|
92
|
-
animationType === ComponentAnimationType.player ? "ValueXY" : "Value";
|
|
93
|
-
|
|
94
|
-
const animatedValue = useRef(
|
|
95
|
-
new Animated[animationValueType](defaultValue)
|
|
96
|
-
).current;
|
|
97
|
-
|
|
98
85
|
const isAudioItem = React.useMemo(
|
|
99
86
|
() =>
|
|
100
87
|
videoModalState.item?.content?.type?.includes?.("audio") ||
|
|
@@ -118,63 +105,8 @@ export const AnimationView = ({
|
|
|
118
105
|
: -additionalData.moveValue
|
|
119
106
|
: 0;
|
|
120
107
|
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
isAudioItem,
|
|
124
|
-
bottomTabBarHeight,
|
|
125
|
-
minimisedHeight,
|
|
126
|
-
minimisedWidth,
|
|
127
|
-
defaultValue,
|
|
128
|
-
moveUpValue,
|
|
129
|
-
moveComponentHorizontalValue,
|
|
130
|
-
isTablet,
|
|
131
|
-
isTabletLandscape,
|
|
132
|
-
isRTL,
|
|
133
|
-
fromMiniPlayer: videoModalState.mode === "MINIMIZED",
|
|
134
|
-
inlineAudioPlayer,
|
|
135
|
-
}),
|
|
136
|
-
[
|
|
137
|
-
bottomTabBarHeight,
|
|
138
|
-
minimisedHeight,
|
|
139
|
-
minimisedWidth,
|
|
140
|
-
defaultValue,
|
|
141
|
-
moveUpValue,
|
|
142
|
-
moveComponentHorizontalValue,
|
|
143
|
-
videoModalState.mode,
|
|
144
|
-
]
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
React.useEffect(() => {
|
|
148
|
-
if (additionalData.resetAnimationValue) {
|
|
149
|
-
animatedValue.setValue(0);
|
|
150
|
-
}
|
|
151
|
-
}, [additionalData.resetAnimationValue]);
|
|
152
|
-
|
|
153
|
-
React.useEffect(() => {
|
|
154
|
-
if (animationType === ComponentAnimationType.player) {
|
|
155
|
-
let width, height;
|
|
156
|
-
|
|
157
|
-
if (additionalData.aspectRatio) {
|
|
158
|
-
width = isTabletLandscape ? additionalData.width : screenWidth;
|
|
159
|
-
|
|
160
|
-
height =
|
|
161
|
-
(isTabletLandscape ? additionalData.width : screenWidth) /
|
|
162
|
-
additionalData.aspectRatio;
|
|
163
|
-
} else {
|
|
164
|
-
width =
|
|
165
|
-
typeof additionalData.width === "number" && additionalData.width;
|
|
166
|
-
|
|
167
|
-
height =
|
|
168
|
-
typeof additionalData.height === "number" && additionalData.height;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (defaultValue.x === 0 && width && height) {
|
|
172
|
-
const value = { x: width, y: height };
|
|
173
|
-
setDefaultValue(value);
|
|
174
|
-
animatedValue.setValue(value);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}, [additionalData, screenWidth]);
|
|
108
|
+
const animationValueType: string =
|
|
109
|
+
animationType === ComponentAnimationType.player ? "ValueXY" : "Value";
|
|
178
110
|
|
|
179
111
|
const getAnimationValue = React.useCallback(
|
|
180
112
|
(animationType, state) => {
|
|
@@ -292,6 +224,90 @@ export const AnimationView = ({
|
|
|
292
224
|
]
|
|
293
225
|
);
|
|
294
226
|
|
|
227
|
+
const getInitialValue = React.useCallback(() => {
|
|
228
|
+
const mode =
|
|
229
|
+
videoModalState.mode === "PIP"
|
|
230
|
+
? videoModalState.previousMode
|
|
231
|
+
: videoModalState.mode;
|
|
232
|
+
|
|
233
|
+
switch (mode) {
|
|
234
|
+
case "MINIMIZED":
|
|
235
|
+
return getAnimationValue(
|
|
236
|
+
animationType,
|
|
237
|
+
PlayerAnimationStateEnum.minimize
|
|
238
|
+
).toValue;
|
|
239
|
+
|
|
240
|
+
case "MAXIMIZED":
|
|
241
|
+
default:
|
|
242
|
+
return getAnimationValue(
|
|
243
|
+
animationType,
|
|
244
|
+
PlayerAnimationStateEnum.maximaze
|
|
245
|
+
).toValue;
|
|
246
|
+
}
|
|
247
|
+
}, [defaultValue, videoModalState]);
|
|
248
|
+
|
|
249
|
+
const animatedValue = useRef(
|
|
250
|
+
new Animated[animationValueType](getInitialValue())
|
|
251
|
+
).current;
|
|
252
|
+
|
|
253
|
+
const calculationData = React.useMemo(
|
|
254
|
+
() => ({
|
|
255
|
+
isAudioItem,
|
|
256
|
+
bottomTabBarHeight,
|
|
257
|
+
minimisedHeight,
|
|
258
|
+
minimisedWidth,
|
|
259
|
+
defaultValue,
|
|
260
|
+
moveUpValue,
|
|
261
|
+
moveComponentHorizontalValue,
|
|
262
|
+
isTablet,
|
|
263
|
+
isTabletLandscape,
|
|
264
|
+
isRTL,
|
|
265
|
+
fromMiniPlayer: videoModalState.mode === "MINIMIZED",
|
|
266
|
+
inlineAudioPlayer,
|
|
267
|
+
}),
|
|
268
|
+
[
|
|
269
|
+
bottomTabBarHeight,
|
|
270
|
+
minimisedHeight,
|
|
271
|
+
minimisedWidth,
|
|
272
|
+
defaultValue,
|
|
273
|
+
moveUpValue,
|
|
274
|
+
moveComponentHorizontalValue,
|
|
275
|
+
videoModalState.mode,
|
|
276
|
+
]
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
React.useEffect(() => {
|
|
280
|
+
if (additionalData.resetAnimationValue) {
|
|
281
|
+
animatedValue.setValue(defaultValue);
|
|
282
|
+
}
|
|
283
|
+
}, [additionalData.resetAnimationValue, defaultValue]);
|
|
284
|
+
|
|
285
|
+
React.useEffect(() => {
|
|
286
|
+
if (animationType === ComponentAnimationType.player) {
|
|
287
|
+
let width, height;
|
|
288
|
+
|
|
289
|
+
if (additionalData.aspectRatio) {
|
|
290
|
+
width = isTabletLandscape ? additionalData.width : screenWidth;
|
|
291
|
+
|
|
292
|
+
height =
|
|
293
|
+
(isTabletLandscape ? additionalData.width : screenWidth) /
|
|
294
|
+
additionalData.aspectRatio;
|
|
295
|
+
} else {
|
|
296
|
+
width =
|
|
297
|
+
typeof additionalData.width === "number" && additionalData.width;
|
|
298
|
+
|
|
299
|
+
height =
|
|
300
|
+
typeof additionalData.height === "number" && additionalData.height;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (defaultValue.x === 0 && width && height) {
|
|
304
|
+
const value = { x: width, y: height };
|
|
305
|
+
setDefaultValue(value);
|
|
306
|
+
animatedValue.setValue(value);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}, [additionalData, screenWidth]);
|
|
310
|
+
|
|
295
311
|
React.useEffect(() => {
|
|
296
312
|
if (
|
|
297
313
|
playerAnimationState === PlayerAnimationStateEnum.minimize &&
|
|
@@ -325,7 +341,7 @@ export const AnimationView = ({
|
|
|
325
341
|
animatedValue,
|
|
326
342
|
calculationData,
|
|
327
343
|
modalSnapPoint: modalSnapPoints[1],
|
|
328
|
-
|
|
344
|
+
startComponentsAnimationDistance,
|
|
329
345
|
startComponentsAnimation,
|
|
330
346
|
setStartComponentsAnimation,
|
|
331
347
|
getAnimationValue,
|
|
@@ -350,7 +366,7 @@ export const AnimationView = ({
|
|
|
350
366
|
animatedValue,
|
|
351
367
|
calculationData,
|
|
352
368
|
modalSnapPoint: modalSnapPoints[1],
|
|
353
|
-
|
|
369
|
+
startComponentsAnimationDistance,
|
|
354
370
|
startComponentsAnimation,
|
|
355
371
|
setStartComponentsAnimation,
|
|
356
372
|
getAnimationValue,
|
|
@@ -372,9 +388,9 @@ export const AnimationView = ({
|
|
|
372
388
|
ref={animationComponentRef}
|
|
373
389
|
style={[
|
|
374
390
|
...preparedStyles,
|
|
375
|
-
additionalData.saveArea ? styles.flex : null,
|
|
376
391
|
(videoModalState.mode === "MAXIMIZED" ||
|
|
377
|
-
videoModalState.mode === "MINIMIZED"
|
|
392
|
+
videoModalState.mode === "MINIMIZED" ||
|
|
393
|
+
(videoModalState.mode === "PIP" && isAppActive)) &&
|
|
378
394
|
getAnimationStyle(animationType, animatedValue),
|
|
379
395
|
]}
|
|
380
396
|
>
|
|
@@ -412,6 +428,7 @@ export const AnimationComponent = (props: Props) => {
|
|
|
412
428
|
delete additionalData.extraAnimation[animationType];
|
|
413
429
|
|
|
414
430
|
return (
|
|
431
|
+
// @ts-ignore
|
|
415
432
|
<Component {...(isReactFragment ? null : props)}>
|
|
416
433
|
<AnimationComponent
|
|
417
434
|
{...animationProps}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useContext } from "react";
|
|
2
2
|
import { Animated } from "react-native";
|
|
3
3
|
|
|
4
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "react-native-
|
|
8
|
-
import { useGetBottomTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
|
+
useGetBottomTabBarHeight,
|
|
7
|
+
useDimensions,
|
|
8
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
9
9
|
|
|
10
10
|
import { useConfiguration } from "../utils";
|
|
11
11
|
|
|
@@ -39,6 +39,7 @@ export type ModalAnimationContextT = {
|
|
|
39
39
|
setLastSnap: (value: number) => void;
|
|
40
40
|
tabletLandscapePlayerTopPosition: number;
|
|
41
41
|
setTabletLandscapePlayerTopPosition: (value: number) => void;
|
|
42
|
+
startComponentsAnimationDistance: number;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
const ReactContext = React.createContext<ModalAnimationContextT>({
|
|
@@ -62,6 +63,7 @@ const ReactContext = React.createContext<ModalAnimationContextT>({
|
|
|
62
63
|
setLastSnap: () => null,
|
|
63
64
|
tabletLandscapePlayerTopPosition: 0,
|
|
64
65
|
setTabletLandscapePlayerTopPosition: () => null,
|
|
66
|
+
startComponentsAnimationDistance: 0,
|
|
65
67
|
});
|
|
66
68
|
|
|
67
69
|
export function useModalAnimationContext() {
|
|
@@ -93,10 +95,15 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
93
95
|
const translateYOffset = React.useRef(new Animated.Value(0)).current;
|
|
94
96
|
const dragVideoPlayerY = React.useRef(new Animated.Value(0)).current;
|
|
95
97
|
|
|
96
|
-
const { height } =
|
|
98
|
+
const { height } = useDimensions("window", { fullDimensions: true });
|
|
97
99
|
const { bottom: bottomSafeArea } = useSafeAreaInsets();
|
|
98
100
|
const bottomTabBarHeight = useGetBottomTabBarHeight();
|
|
99
101
|
|
|
102
|
+
const startComponentsAnimationDistance = React.useMemo(
|
|
103
|
+
() => Math.round((height * 60) / 100),
|
|
104
|
+
[height]
|
|
105
|
+
);
|
|
106
|
+
|
|
100
107
|
/*
|
|
101
108
|
If bottomTabBarHeight is equal 0 it means an app does not use bottomTabBar.
|
|
102
109
|
Because of this we need to minus bottom SafeArea offset.
|
|
@@ -134,6 +141,7 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
|
|
|
134
141
|
setLastSnap,
|
|
135
142
|
tabletLandscapePlayerTopPosition,
|
|
136
143
|
setTabletLandscapePlayerTopPosition,
|
|
144
|
+
startComponentsAnimationDistance,
|
|
137
145
|
}}
|
|
138
146
|
>
|
|
139
147
|
{children}
|
|
@@ -233,7 +233,7 @@ export const gestureListenerHelper = (data) => {
|
|
|
233
233
|
animatedValue,
|
|
234
234
|
calculationData,
|
|
235
235
|
modalSnapPoint,
|
|
236
|
-
|
|
236
|
+
startComponentsAnimationDistance,
|
|
237
237
|
startComponentsAnimation,
|
|
238
238
|
setStartComponentsAnimation,
|
|
239
239
|
getAnimationValue,
|
|
@@ -243,7 +243,7 @@ export const gestureListenerHelper = (data) => {
|
|
|
243
243
|
if (listenerValue <= 0) {
|
|
244
244
|
if (
|
|
245
245
|
preparedValue >= 0 &&
|
|
246
|
-
preparedValue <= modalSnapPoint -
|
|
246
|
+
preparedValue <= modalSnapPoint - startComponentsAnimationDistance
|
|
247
247
|
) {
|
|
248
248
|
!startComponentsAnimation && setStartComponentsAnimation(true);
|
|
249
249
|
|
|
@@ -263,9 +263,11 @@ export const gestureListenerHelper = (data) => {
|
|
|
263
263
|
animatedValue.setValue(value);
|
|
264
264
|
}
|
|
265
265
|
} else {
|
|
266
|
-
if (preparedValue >=
|
|
266
|
+
if (preparedValue >= startComponentsAnimationDistance) {
|
|
267
267
|
!startComponentsAnimation && setStartComponentsAnimation(true);
|
|
268
|
-
const value = Math.round(
|
|
268
|
+
const value = Math.round(
|
|
269
|
+
preparedValue - startComponentsAnimationDistance
|
|
270
|
+
);
|
|
269
271
|
|
|
270
272
|
animatedValue.setValue(
|
|
271
273
|
calculateAnimationValue(animationType, value, calculationData)
|
|
@@ -197,7 +197,7 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
197
197
|
<AnimationComponent
|
|
198
198
|
animationType={ComponentAnimationType.moveUpComponent}
|
|
199
199
|
additionalData={{ saveArea: true }}
|
|
200
|
-
style={directionStyles(isTabletLandscape)}
|
|
200
|
+
style={[directionStyles(isTabletLandscape), defaultStyles.flex]}
|
|
201
201
|
>
|
|
202
202
|
<PathnameContext.Provider value={pathname}>
|
|
203
203
|
<ScreenContextProvider pathname={pathname}>
|
|
@@ -42,9 +42,14 @@ exports[`PlayerWrapper renders inline 1`] = `
|
|
|
42
42
|
}
|
|
43
43
|
animationType="moveUpComponent"
|
|
44
44
|
style={
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
Array [
|
|
46
|
+
Object {
|
|
47
|
+
"flexDirection": "column",
|
|
48
|
+
},
|
|
49
|
+
Object {
|
|
50
|
+
"flex": 1,
|
|
51
|
+
},
|
|
52
|
+
]
|
|
48
53
|
}
|
|
49
54
|
>
|
|
50
55
|
<View
|
|
@@ -120,9 +125,14 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
|
|
|
120
125
|
}
|
|
121
126
|
animationType="moveUpComponent"
|
|
122
127
|
style={
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
Array [
|
|
129
|
+
Object {
|
|
130
|
+
"flexDirection": "column",
|
|
131
|
+
},
|
|
132
|
+
Object {
|
|
133
|
+
"flex": 1,
|
|
134
|
+
},
|
|
135
|
+
]
|
|
126
136
|
}
|
|
127
137
|
>
|
|
128
138
|
<View
|
|
@@ -198,9 +208,14 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
|
|
|
198
208
|
}
|
|
199
209
|
animationType="moveUpComponent"
|
|
200
210
|
style={
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
211
|
+
Array [
|
|
212
|
+
Object {
|
|
213
|
+
"flexDirection": "row",
|
|
214
|
+
},
|
|
215
|
+
Object {
|
|
216
|
+
"flex": 1,
|
|
217
|
+
},
|
|
218
|
+
]
|
|
204
219
|
}
|
|
205
220
|
>
|
|
206
221
|
<View
|
|
@@ -292,9 +307,14 @@ exports[`PlayerWrapper renders properly 1`] = `
|
|
|
292
307
|
}
|
|
293
308
|
animationType="moveUpComponent"
|
|
294
309
|
style={
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
310
|
+
Array [
|
|
311
|
+
Object {
|
|
312
|
+
"flexDirection": "column",
|
|
313
|
+
},
|
|
314
|
+
Object {
|
|
315
|
+
"flex": 1,
|
|
316
|
+
},
|
|
317
|
+
]
|
|
298
318
|
}
|
|
299
319
|
>
|
|
300
320
|
<View
|
|
@@ -33,8 +33,11 @@ export const useConfiguration = () => {
|
|
|
33
33
|
...pluginConfiguration,
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
const {
|
|
37
|
-
|
|
36
|
+
const {
|
|
37
|
+
minimised_height = 0,
|
|
38
|
+
minimised_height_tablet = 0,
|
|
39
|
+
modal_background_color,
|
|
40
|
+
} = config;
|
|
38
41
|
|
|
39
42
|
const minimisedHeight = useIsTablet()
|
|
40
43
|
? minimised_height_tablet
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { FocusableGroupContext } from "./FocusableGroupContext";
|
|
3
|
+
|
|
4
|
+
type ProviderArgs = {
|
|
5
|
+
id: string;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const FocusableGroupContextProvider = ({
|
|
10
|
+
id,
|
|
11
|
+
children,
|
|
12
|
+
}: ProviderArgs) => (
|
|
13
|
+
<FocusableGroupContext.Provider value={id}>
|
|
14
|
+
{children}
|
|
15
|
+
</FocusableGroupContext.Provider>
|
|
16
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import { Text } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { FocusableGroupContextProvider, FocusableGroupContext } from "../";
|
|
5
|
+
|
|
6
|
+
const MockComponent = () => {
|
|
7
|
+
const focusableContext = useContext(FocusableGroupContext) || "default";
|
|
8
|
+
|
|
9
|
+
return <Text testID={focusableContext} />;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe("FocusableGroupContextProvider", () => {
|
|
13
|
+
it("should provide focusable context to the wrapped component", () => {
|
|
14
|
+
const { getByTestId } = render(
|
|
15
|
+
<FocusableGroupContextProvider id="testId">
|
|
16
|
+
<MockComponent />
|
|
17
|
+
</FocusableGroupContextProvider>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
expect(getByTestId("testId")).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { withFocusableContext } from "../withFocusableContext";
|
|
5
|
+
import { FocusableGroupContext } from "../FocusableGroupContext";
|
|
6
|
+
|
|
7
|
+
const MockComponent = ({ groupId }: { groupId: string }) => (
|
|
8
|
+
<Text testID={groupId} />
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const WrappedComponent = withFocusableContext(MockComponent);
|
|
12
|
+
|
|
13
|
+
describe("withFocusableContext HOC", () => {
|
|
14
|
+
it("should provide focusable context to the wrapped component", () => {
|
|
15
|
+
const { getByTestId } = render(<WrappedComponent />, {
|
|
16
|
+
// eslint-disable-next-line react/display-name
|
|
17
|
+
wrapper: ({ children }: { children: React.ReactElement }) => (
|
|
18
|
+
<FocusableGroupContext.Provider value="test">
|
|
19
|
+
{children}
|
|
20
|
+
</FocusableGroupContext.Provider>
|
|
21
|
+
),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(getByTestId("test")).toBeTruthy();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FocusableGroupContext } from "./FocusableGroupContext";
|
|
3
|
+
import { FocusableGroupContextProvider } from "./FocusableGroupContextProvider";
|
|
4
|
+
|
|
5
|
+
export { FocusableGroupContext, FocusableGroupContextProvider };
|
|
6
|
+
|
|
7
|
+
export const useGroupId = () => React.useContext(FocusableGroupContext);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FocusableGroupContext } from "./FocusableGroupContext";
|
|
3
|
+
|
|
4
|
+
export const withFocusableContext = (Component) => {
|
|
5
|
+
// eslint-disable-next-line react/display-name
|
|
6
|
+
return ({ groupId, ...props }: Record<string, any>) => (
|
|
7
|
+
<FocusableGroupContext.Consumer>
|
|
8
|
+
{(groupIdContext: string) => {
|
|
9
|
+
// eslint-disable-next-line react/display-name
|
|
10
|
+
const propsGroupId = groupId || null;
|
|
11
|
+
const providedGroupId = propsGroupId || groupIdContext;
|
|
12
|
+
|
|
13
|
+
return <Component {...props} groupId={providedGroupId} />;
|
|
14
|
+
}}
|
|
15
|
+
</FocusableGroupContext.Consumer>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -2,7 +2,6 @@ import React, {
|
|
|
2
2
|
createContext,
|
|
3
3
|
ReactNode,
|
|
4
4
|
useCallback,
|
|
5
|
-
useEffect,
|
|
6
5
|
useMemo,
|
|
7
6
|
useRef,
|
|
8
7
|
} from "react";
|
|
@@ -114,11 +113,6 @@ export function ScreenContextProvider({
|
|
|
114
113
|
return navBarState;
|
|
115
114
|
}, []);
|
|
116
115
|
|
|
117
|
-
useEffect(() => {
|
|
118
|
-
// purge the getScreenNavBarState store when the pathname changes
|
|
119
|
-
screenNavBarStateRef.current = null;
|
|
120
|
-
}, [pathname]);
|
|
121
|
-
|
|
122
116
|
const screenNavBarState = getScreenNavBarState()(
|
|
123
117
|
useShallow((state) => ({
|
|
124
118
|
visible: state.visible,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.5522474195",
|
|
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",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"redux-mock-store": "^1.5.3"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
38
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.
|
|
39
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.
|
|
40
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
37
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.5522474195",
|
|
38
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5522474195",
|
|
39
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.5522474195",
|
|
40
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.5522474195",
|
|
41
41
|
"promise": "^8.3.0",
|
|
42
42
|
"react-router-native": "^5.1.2",
|
|
43
43
|
"url": "^0.11.0",
|
|
File without changes
|
|
File without changes
|