@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5786305091 → 12.0.0-alpha.5812543239
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/AnimatedInOut/index.tsx +18 -10
- package/Components/Image/Image.android.tsx +34 -2
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +78 -249
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +4 -7
- package/Components/VideoModal/PlayerWrapper.tsx +63 -62
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +3 -2
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +10 -18
- package/package.json +5 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Animated, EasingFunction, StyleProp, ViewStyle } from "react-native";
|
|
3
|
-
|
|
3
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
4
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
4
5
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
5
6
|
|
|
6
7
|
type AnimatedInterpolatedStyle =
|
|
@@ -35,11 +36,16 @@ function getAnimation(config: AnimatedInConfig, phase: "in" | "out") {
|
|
|
35
36
|
return config[phase] || config;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
export function AnimatedInOut(
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
export function AnimatedInOut({
|
|
40
|
+
visible,
|
|
41
|
+
animationConfig,
|
|
42
|
+
staticStyles = {},
|
|
43
|
+
children,
|
|
44
|
+
}: Props) {
|
|
41
45
|
const [animatedValue] = React.useState(new Animated.Value(visible ? 1 : 0));
|
|
42
|
-
const [animating, setAnimating] = React.useState(
|
|
46
|
+
const [animating, setAnimating] = React.useState(undefined);
|
|
47
|
+
|
|
48
|
+
const previousVisible = usePrevious(toBooleanWithDefaultFalse(visible));
|
|
43
49
|
|
|
44
50
|
function startAnimation(toValue, config) {
|
|
45
51
|
if (animating) {
|
|
@@ -55,7 +61,7 @@ export function AnimatedInOut(props: Props) {
|
|
|
55
61
|
delay,
|
|
56
62
|
useNativeDriver: true,
|
|
57
63
|
}).start(() => {
|
|
58
|
-
setAnimating(
|
|
64
|
+
setAnimating(undefined);
|
|
59
65
|
onAnimationEnd();
|
|
60
66
|
});
|
|
61
67
|
|
|
@@ -63,12 +69,14 @@ export function AnimatedInOut(props: Props) {
|
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
React.useEffect(() => {
|
|
66
|
-
if (visible) {
|
|
72
|
+
if (!previousVisible && visible) {
|
|
67
73
|
startAnimation(1.0, getAnimation(animationConfig, "in"));
|
|
68
|
-
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (previousVisible && !visible) {
|
|
69
77
|
startAnimation(0.0, getAnimation(animationConfig, "out"));
|
|
70
78
|
}
|
|
71
|
-
}, [visible,
|
|
79
|
+
}, [visible, previousVisible]);
|
|
72
80
|
|
|
73
81
|
const styles = visible
|
|
74
82
|
? getAnimation(animationConfig, "in").styles
|
|
@@ -77,7 +85,7 @@ export function AnimatedInOut(props: Props) {
|
|
|
77
85
|
return (
|
|
78
86
|
<Animated.View
|
|
79
87
|
renderToHardwareTextureAndroid={animating}
|
|
80
|
-
style={[styles(animatedValue),
|
|
88
|
+
style={[styles(animatedValue), staticStyles]}
|
|
81
89
|
>
|
|
82
90
|
{children}
|
|
83
91
|
</Animated.View>
|
|
@@ -1,3 +1,35 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from "react";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import FastImage, {
|
|
4
|
+
FastImageProps,
|
|
5
|
+
} from "@applicaster/react-native-fast-image";
|
|
6
|
+
|
|
7
|
+
export const QBImage = (props: FastImageProps) => {
|
|
8
|
+
const source = React.useMemo(() => {
|
|
9
|
+
if (typeof props.source === "number") {
|
|
10
|
+
return props.source;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
uri: props.source.uri,
|
|
15
|
+
headers: props.source.headers,
|
|
16
|
+
priority: props.source.priority,
|
|
17
|
+
cache: props.source.cache,
|
|
18
|
+
maxWidth: props.source.maxWidth,
|
|
19
|
+
maxHeight: props.source.maxHeight,
|
|
20
|
+
};
|
|
21
|
+
}, [
|
|
22
|
+
...(typeof props.source === "object"
|
|
23
|
+
? [
|
|
24
|
+
props.source?.uri,
|
|
25
|
+
props.source?.priority,
|
|
26
|
+
props.source?.cache,
|
|
27
|
+
props.source?.headers,
|
|
28
|
+
props.source?.maxWidth,
|
|
29
|
+
props.source?.maxHeight,
|
|
30
|
+
]
|
|
31
|
+
: []),
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
return <FastImage {...props} source={source} />;
|
|
35
|
+
};
|
|
@@ -1,43 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
import { View, StyleSheet, LayoutChangeEvent } from "react-native";
|
|
3
|
-
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
1
|
+
/* eslint react/prop-types: off */
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type LayoutDimensions = {
|
|
11
|
-
width: number;
|
|
12
|
-
height: number;
|
|
13
|
-
};
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { View, StyleSheet } from "react-native";
|
|
5
|
+
import * as R from "ramda";
|
|
6
|
+
import { v4 } from "uuid";
|
|
14
7
|
|
|
15
|
-
type
|
|
16
|
-
width: number;
|
|
17
|
-
height: number;
|
|
18
|
-
index?: number;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
type MeasurementsPortalProps = {
|
|
8
|
+
type Props = {
|
|
22
9
|
Component: React.ElementType;
|
|
23
|
-
onLayout: (
|
|
24
|
-
componentProps?: Record<
|
|
25
|
-
onLoadFinished?: () => void;
|
|
10
|
+
onLayout: (LayoutChangeEvent) => void;
|
|
11
|
+
componentProps?: Record<any, any>;
|
|
26
12
|
};
|
|
27
13
|
|
|
28
|
-
|
|
29
|
-
measureComponent: (
|
|
30
|
-
comp: React.ElementType,
|
|
31
|
-
props: Record<string, any>
|
|
32
|
-
) => Promise<MeasurementResult>;
|
|
33
|
-
measuringInProgress: boolean;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
type MeasurementsPortalContextProviderProps = {
|
|
37
|
-
children: ReactNode;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const isError = (possibleError: any): boolean => possibleError instanceof Error;
|
|
14
|
+
const isError = (possibleError): boolean => possibleError instanceof Error;
|
|
41
15
|
|
|
42
16
|
const styles = StyleSheet.create({
|
|
43
17
|
container: {
|
|
@@ -51,245 +25,100 @@ const styles = StyleSheet.create({
|
|
|
51
25
|
wrapper: {},
|
|
52
26
|
});
|
|
53
27
|
|
|
54
|
-
|
|
55
|
-
component: React.ElementType;
|
|
56
|
-
componentProps: Record<string, any> | null;
|
|
57
|
-
measureComponentCallback: ((result: MeasurementResult) => void) | null;
|
|
58
|
-
onLoadFinishedIsCalled: boolean;
|
|
59
|
-
measuringInProgress: boolean;
|
|
60
|
-
layout: LayoutDimensions;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
type Action =
|
|
64
|
-
| { type: "SET_COMPONENT"; payload: React.ElementType }
|
|
65
|
-
| { type: "SET_COMPONENT_PROPS"; payload: Record<string, any> | null }
|
|
66
|
-
| {
|
|
67
|
-
type: "SET_MEASURE_CALLBACK";
|
|
68
|
-
payload: ((result: MeasurementResult) => void) | null;
|
|
69
|
-
}
|
|
70
|
-
| { type: "SET_ON_LOAD_FINISHED"; payload: boolean }
|
|
71
|
-
| { type: "SET_MEASURING_PROGRESS"; payload: boolean }
|
|
72
|
-
| { type: "SET_LAYOUT"; payload: LayoutDimensions };
|
|
73
|
-
|
|
74
|
-
const MEASUREMENT_ACTIONS = {
|
|
75
|
-
setComponent: "SET_COMPONENT",
|
|
76
|
-
setComponentProps: "SET_COMPONENT_PROPS",
|
|
77
|
-
setMeasureCallback: "SET_MEASURE_CALLBACK",
|
|
78
|
-
setOnLoadFinished: "SET_ON_LOAD_FINISHED",
|
|
79
|
-
setMeasuringProgress: "SET_MEASURING_PROGRESS",
|
|
80
|
-
setLayout: "SET_LAYOUT",
|
|
81
|
-
} as const;
|
|
82
|
-
|
|
83
|
-
const reducer = (state: State, action: Action): State => {
|
|
84
|
-
switch (action.type) {
|
|
85
|
-
case MEASUREMENT_ACTIONS.setComponent:
|
|
86
|
-
return { ...state, component: action.payload };
|
|
87
|
-
case MEASUREMENT_ACTIONS.setComponentProps:
|
|
88
|
-
return { ...state, componentProps: action.payload };
|
|
89
|
-
case MEASUREMENT_ACTIONS.setMeasureCallback:
|
|
90
|
-
return { ...state, measureComponentCallback: action.payload };
|
|
91
|
-
case MEASUREMENT_ACTIONS.setOnLoadFinished:
|
|
92
|
-
return { ...state, onLoadFinishedIsCalled: action.payload };
|
|
93
|
-
case MEASUREMENT_ACTIONS.setMeasuringProgress:
|
|
94
|
-
return { ...state, measuringInProgress: action.payload };
|
|
95
|
-
case MEASUREMENT_ACTIONS.setLayout:
|
|
96
|
-
return { ...state, layout: action.payload };
|
|
97
|
-
default:
|
|
98
|
-
return state;
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const initialState: State = {
|
|
103
|
-
component: null,
|
|
104
|
-
componentProps: null,
|
|
105
|
-
measureComponentCallback: null,
|
|
106
|
-
onLoadFinishedIsCalled: false,
|
|
107
|
-
measuringInProgress: false,
|
|
108
|
-
layout: { width: 0, height: 0 },
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Handles layout changes for the MeasurementsPortal component
|
|
113
|
-
*/
|
|
114
|
-
const onLayout =
|
|
115
|
-
(dispatch) =>
|
|
116
|
-
({ nativeEvent: { layout: newLayout } }: LayoutChangeEvent) => {
|
|
117
|
-
log_debug("Rendered measurement layout", { newLayout });
|
|
118
|
-
dispatch({ type: MEASUREMENT_ACTIONS.setLayout, payload: newLayout });
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* MeasurementsPortal is a component that is used to measure the size of a component
|
|
123
|
-
* It is not rendered to the main tree, but it actually uses a component and its props to measure the size of the component.
|
|
124
|
-
* The <Component> comes from the measureComponent method of the MeasurementPortalContext.
|
|
125
|
-
*/
|
|
126
|
-
const MeasurementsPortal = ({
|
|
127
|
-
Component,
|
|
128
|
-
onLayout,
|
|
129
|
-
componentProps,
|
|
130
|
-
}: MeasurementsPortalProps) => {
|
|
131
|
-
if (!Component) {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
|
|
28
|
+
const MeasurementsPortal = ({ Component, onLayout, componentProps }: Props) => {
|
|
135
29
|
return (
|
|
136
30
|
<View style={styles.container} testID="MeasurementsPortal">
|
|
137
|
-
<View style={styles.wrapper} onLayout={onLayout}>
|
|
31
|
+
<View style={styles.wrapper} onLayout={onLayout} key={v4()}>
|
|
138
32
|
<Component {...componentProps} />
|
|
139
33
|
</View>
|
|
140
34
|
</View>
|
|
141
35
|
);
|
|
142
36
|
};
|
|
143
37
|
|
|
144
|
-
const MeasurementPortalContext =
|
|
145
|
-
React.createContext<MeasurementPortalContextValue | null>(null);
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* The MeasurementsPortalContextProvider provides a measureComponent method, and a measuringInProgress flag
|
|
149
|
-
* With these we can pre-render a component and measure its size before rendering it to the main tree to avoid layout shifts
|
|
150
|
-
*/
|
|
151
|
-
const MeasurementsPortalContextProvider = ({
|
|
152
|
-
children,
|
|
153
|
-
}: MeasurementsPortalContextProviderProps) => {
|
|
154
|
-
const [state, dispatch] = useReducer(reducer, initialState);
|
|
155
|
-
|
|
156
|
-
const onLoadFinishedRef =
|
|
157
|
-
React.useRef<MeasurementsPortalProps["onLoadFinished"]>(null);
|
|
38
|
+
const MeasurementPortalContext = React.createContext(null);
|
|
158
39
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
*/
|
|
163
|
-
const finalize = useCallback(() => {
|
|
164
|
-
if (state.measureComponentCallback) {
|
|
165
|
-
log_debug("Finalize measurement process", {
|
|
166
|
-
layout: state.layout,
|
|
167
|
-
componentProps: state.componentProps,
|
|
168
|
-
});
|
|
40
|
+
const MeasurementsPortalContextProvider = ({ children }) => {
|
|
41
|
+
const Component = React.useRef(View);
|
|
42
|
+
const [measuringInProgress, setMeasuringInProgress] = React.useState(false);
|
|
169
43
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
index: state.componentProps?.index,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
44
|
+
const measureComponentCallback = React.useRef(null);
|
|
45
|
+
const componentProps = React.useRef(null);
|
|
46
|
+
const onLoadFinishedIsCalled = React.useRef(null);
|
|
176
47
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
type: MEASUREMENT_ACTIONS.setMeasuringProgress,
|
|
181
|
-
payload: false,
|
|
182
|
-
});
|
|
48
|
+
const setComponent = (comp) => {
|
|
49
|
+
Component.current = comp;
|
|
50
|
+
};
|
|
183
51
|
|
|
184
|
-
|
|
185
|
-
|
|
52
|
+
const setMeasureComponentCallback = (cb) => {
|
|
53
|
+
measureComponentCallback.current = cb;
|
|
54
|
+
};
|
|
186
55
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
56
|
+
const finalize = ({ width, height }) => {
|
|
57
|
+
measureComponentCallback?.current?.({
|
|
58
|
+
width,
|
|
59
|
+
height,
|
|
60
|
+
index: componentProps.current.index,
|
|
192
61
|
});
|
|
193
62
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
onLoadFinishedRef.current
|
|
199
|
-
) {
|
|
200
|
-
finalize();
|
|
201
|
-
}
|
|
202
|
-
}, [state.measureComponentCallback, state.layout, finalize]);
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Utility function that takes, a component and its props, measures the rendered size of the component
|
|
206
|
-
* and creates a promise that does not get resolved with the measurement result (width/height/index)
|
|
207
|
-
* until the onLoadFinished callback is called
|
|
208
|
-
*/
|
|
209
|
-
const measureComponent = useCallback(
|
|
210
|
-
(
|
|
211
|
-
comp: React.ElementType,
|
|
212
|
-
props: { onLoadFinished: () => void; [key: string]: any }
|
|
213
|
-
): Promise<MeasurementResult> => {
|
|
214
|
-
return new Promise((resolve) => {
|
|
215
|
-
log_debug("Measuring process started", { comp, props });
|
|
216
|
-
|
|
217
|
-
dispatch({
|
|
218
|
-
type: MEASUREMENT_ACTIONS.setMeasureCallback,
|
|
219
|
-
payload: resolve,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
dispatch({
|
|
223
|
-
type: MEASUREMENT_ACTIONS.setMeasuringProgress,
|
|
224
|
-
payload: true,
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
dispatch({
|
|
228
|
-
type: MEASUREMENT_ACTIONS.setOnLoadFinished,
|
|
229
|
-
payload: false,
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
dispatch({
|
|
233
|
-
type: MEASUREMENT_ACTIONS.setLayout,
|
|
234
|
-
payload: { width: 0, height: 0 },
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
onLoadFinishedRef.current =
|
|
238
|
-
// eslint-disable-next-line react/prop-types
|
|
239
|
-
props.onLoadFinished as MeasurementsPortalProps["onLoadFinished"];
|
|
240
|
-
|
|
241
|
-
const handleOnLoadFinish = (...args: any[]) => {
|
|
242
|
-
if (args?.[0]?.error && isError(args[0].error)) {
|
|
243
|
-
log_debug(
|
|
244
|
-
"Component called onLoadFinish with an error, completing measurement process",
|
|
245
|
-
{ args }
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
finalize();
|
|
249
|
-
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
log_debug(
|
|
254
|
-
"Component called onLoadFinish, completing measurement process",
|
|
255
|
-
{ args }
|
|
256
|
-
);
|
|
63
|
+
setMeasureComponentCallback(null);
|
|
64
|
+
setMeasuringInProgress(false);
|
|
65
|
+
onLoadFinishedIsCalled.current = false;
|
|
66
|
+
};
|
|
257
67
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
68
|
+
const setComponentProps = (props) => {
|
|
69
|
+
const handleOnLoadFinish = (...args) => {
|
|
70
|
+
const error = R.path([0, "error"], args);
|
|
71
|
+
|
|
72
|
+
if (isError(error)) {
|
|
73
|
+
finalize({ width: 0, height: 0 });
|
|
74
|
+
} else {
|
|
75
|
+
onLoadFinishedIsCalled.current = true;
|
|
76
|
+
props.onLoadFinished(...args);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
componentProps.current = {
|
|
81
|
+
...props,
|
|
82
|
+
onLoadFinished: handleOnLoadFinish,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
262
85
|
|
|
263
|
-
|
|
264
|
-
|
|
86
|
+
const measureComponent = React.useCallback(async (comp, props) => {
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
setMeasureComponentCallback(resolve);
|
|
89
|
+
setMeasuringInProgress(true);
|
|
265
90
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
91
|
+
setComponentProps(props);
|
|
92
|
+
setComponent(comp);
|
|
93
|
+
});
|
|
94
|
+
}, []);
|
|
270
95
|
|
|
271
|
-
|
|
272
|
-
|
|
96
|
+
const onLayout = ({
|
|
97
|
+
nativeEvent: {
|
|
98
|
+
layout: { width, height },
|
|
273
99
|
},
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
[measureComponent, state.measuringInProgress]
|
|
283
|
-
);
|
|
100
|
+
}) => {
|
|
101
|
+
if (measureComponentCallback.current && onLoadFinishedIsCalled.current) {
|
|
102
|
+
finalize({
|
|
103
|
+
width,
|
|
104
|
+
height,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
284
108
|
|
|
285
109
|
return (
|
|
286
110
|
<>
|
|
287
111
|
<MeasurementsPortal
|
|
288
|
-
Component={
|
|
289
|
-
componentProps={
|
|
290
|
-
onLayout={onLayout
|
|
112
|
+
Component={Component.current}
|
|
113
|
+
componentProps={componentProps.current}
|
|
114
|
+
onLayout={onLayout}
|
|
291
115
|
/>
|
|
292
|
-
<MeasurementPortalContext.Provider
|
|
116
|
+
<MeasurementPortalContext.Provider
|
|
117
|
+
value={{
|
|
118
|
+
measureComponent,
|
|
119
|
+
measuringInProgress,
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
293
122
|
{children}
|
|
294
123
|
</MeasurementPortalContext.Provider>
|
|
295
124
|
</>
|
|
@@ -4,7 +4,6 @@ import { Text, TextStyle, View, ViewStyle } from "react-native";
|
|
|
4
4
|
|
|
5
5
|
import { getLocalizations } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
6
6
|
import { getAppStylesColor } from "@applicaster/zapp-react-native-utils/stylesUtils";
|
|
7
|
-
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
|
|
8
7
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
9
8
|
import { styleKeys } from "@applicaster/zapp-react-native-utils/styleKeysUtils";
|
|
10
9
|
|
|
@@ -26,10 +25,10 @@ const textStyles = (appStyles = defaultAppStyles): TextStyle => ({
|
|
|
26
25
|
textAlign: "center",
|
|
27
26
|
});
|
|
28
27
|
|
|
29
|
-
const errorStyles = ({
|
|
28
|
+
const errorStyles = ({ backgroundColor }): ViewStyle => ({
|
|
30
29
|
flex: 1,
|
|
31
|
-
width,
|
|
32
|
-
height,
|
|
30
|
+
width: "100%",
|
|
31
|
+
height: "100%",
|
|
33
32
|
justifyContent: "center",
|
|
34
33
|
alignItems: "center",
|
|
35
34
|
position: "absolute",
|
|
@@ -41,8 +40,6 @@ export function ErrorDisplayComponent({
|
|
|
41
40
|
styles,
|
|
42
41
|
remoteConfigurations: { localizations },
|
|
43
42
|
}: Props) {
|
|
44
|
-
const { width, height } = useDimensions("window");
|
|
45
|
-
|
|
46
43
|
const theme = useTheme();
|
|
47
44
|
const backgroundColor = theme?.app_background_color;
|
|
48
45
|
|
|
@@ -53,7 +50,7 @@ export function ErrorDisplayComponent({
|
|
|
53
50
|
const appStyles = R.prop(styleKeys.style_namespace, styles);
|
|
54
51
|
|
|
55
52
|
return (
|
|
56
|
-
<View style={errorStyles({
|
|
53
|
+
<View style={errorStyles({ backgroundColor })}>
|
|
57
54
|
<Text style={textStyles(appStyles)}>{stream_error_message}</Text>
|
|
58
55
|
</View>
|
|
59
56
|
);
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Dimensions,
|
|
4
|
+
Platform,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
View,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from "react-native";
|
|
3
9
|
import { Edge, SafeAreaView } from "react-native-safe-area-context";
|
|
4
10
|
|
|
5
11
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
@@ -7,12 +13,12 @@ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/dev
|
|
|
7
13
|
import { PlayerDetails } from "./PlayerDetails";
|
|
8
14
|
import { playerDimesionsHack } from "./utils";
|
|
9
15
|
import { PathnameContext } from "../../Contexts/PathnameContext";
|
|
10
|
-
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
11
16
|
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
12
17
|
|
|
13
|
-
type
|
|
14
|
-
width: number;
|
|
15
|
-
height: number;
|
|
18
|
+
type DimensionsT = {
|
|
19
|
+
width: number | string;
|
|
20
|
+
height: number | string;
|
|
21
|
+
aspectRatio?: number;
|
|
16
22
|
};
|
|
17
23
|
|
|
18
24
|
type Configuration = {
|
|
@@ -23,14 +29,14 @@ type Configuration = {
|
|
|
23
29
|
|
|
24
30
|
type Props = {
|
|
25
31
|
entry: ZappEntry;
|
|
26
|
-
style: ViewStyle &
|
|
32
|
+
style: ViewStyle & DimensionsT;
|
|
27
33
|
containerStyle?: ViewStyle;
|
|
28
34
|
inline?: boolean;
|
|
29
35
|
docked?: boolean;
|
|
30
36
|
isModal?: boolean;
|
|
31
37
|
fullscreen?: boolean;
|
|
32
38
|
isTabletPortrait?: boolean;
|
|
33
|
-
children: (playerDimensions:
|
|
39
|
+
children: (playerDimensions: DimensionsT) => React.ReactNode;
|
|
34
40
|
configuration: Configuration;
|
|
35
41
|
};
|
|
36
42
|
|
|
@@ -52,6 +58,15 @@ const directionStyles = (isTabletLandscape: boolean): ViewStyle => {
|
|
|
52
58
|
return orientationStyles.portrait;
|
|
53
59
|
};
|
|
54
60
|
|
|
61
|
+
const getScreenAspectRatio = () => {
|
|
62
|
+
const { width, height } = Dimensions.get("screen");
|
|
63
|
+
|
|
64
|
+
const longEdge = Math.max(width, height);
|
|
65
|
+
const shortEdge = Math.min(width, height);
|
|
66
|
+
|
|
67
|
+
return longEdge / shortEdge;
|
|
68
|
+
};
|
|
69
|
+
|
|
55
70
|
const safeAreaStyles = (
|
|
56
71
|
configuration: Configuration,
|
|
57
72
|
isTablet: boolean
|
|
@@ -66,34 +81,6 @@ const safeAreaStyles = (
|
|
|
66
81
|
};
|
|
67
82
|
};
|
|
68
83
|
|
|
69
|
-
const getTabletWidth = (
|
|
70
|
-
configuration: Configuration,
|
|
71
|
-
dimensions: Dimensions
|
|
72
|
-
) => {
|
|
73
|
-
const tablet_landscape_sidebar_width =
|
|
74
|
-
configuration?.tablet_landscape_sidebar_width;
|
|
75
|
-
|
|
76
|
-
const { width } = dimensions;
|
|
77
|
-
|
|
78
|
-
const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
|
|
79
|
-
|
|
80
|
-
if (tablet_landscape_sidebar_width?.includes("%")) {
|
|
81
|
-
return width * (1 - sidebarWidth / 100);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (Number.isNaN(sidebarWidth)) {
|
|
85
|
-
return width * 0.65;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return width - sidebarWidth;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export const defaultAspectRatioHeight = (width: number): number =>
|
|
92
|
-
(width / 16) * 9;
|
|
93
|
-
|
|
94
|
-
export const defaultAspectRatioWidth = (height: number): number =>
|
|
95
|
-
(height / 9) * 16;
|
|
96
|
-
|
|
97
84
|
const getEdges = (
|
|
98
85
|
isTablet: boolean,
|
|
99
86
|
docked: boolean,
|
|
@@ -115,6 +102,28 @@ const getEdges = (
|
|
|
115
102
|
return ["top"];
|
|
116
103
|
};
|
|
117
104
|
|
|
105
|
+
const getTabletWidth = (
|
|
106
|
+
configuration: Configuration,
|
|
107
|
+
dimensions: DimensionsT
|
|
108
|
+
) => {
|
|
109
|
+
const tablet_landscape_sidebar_width =
|
|
110
|
+
configuration?.tablet_landscape_sidebar_width;
|
|
111
|
+
|
|
112
|
+
const { width } = dimensions;
|
|
113
|
+
|
|
114
|
+
const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
|
|
115
|
+
|
|
116
|
+
if (tablet_landscape_sidebar_width?.includes("%")) {
|
|
117
|
+
return Number(width) * (1 - sidebarWidth / 100);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (Number.isNaN(sidebarWidth)) {
|
|
121
|
+
return Number(width) * 0.65;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return Number(width) - sidebarWidth;
|
|
125
|
+
};
|
|
126
|
+
|
|
118
127
|
export const PlayerWrapper = (props: Props) => {
|
|
119
128
|
const {
|
|
120
129
|
entry,
|
|
@@ -136,40 +145,38 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
136
145
|
|
|
137
146
|
const tabletWidth = getTabletWidth(configuration, style);
|
|
138
147
|
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
const containerDimensions: Dimensions = React.useMemo(
|
|
148
|
+
const baseDimensions: DimensionsT = React.useMemo(
|
|
142
149
|
() => ({
|
|
143
150
|
width:
|
|
144
|
-
isInlineModal && !docked && isTabletLandscape
|
|
145
|
-
|
|
146
|
-
: style.width,
|
|
147
|
-
height:
|
|
148
|
-
isInlineModal && !docked
|
|
149
|
-
? defaultAspectRatioHeight(
|
|
150
|
-
isTabletLandscape ? tabletWidth : screenWidth
|
|
151
|
-
)
|
|
152
|
-
: style.height,
|
|
151
|
+
isInlineModal && !docked && isTabletLandscape ? tabletWidth : "100%",
|
|
152
|
+
height: isInlineModal && docked ? style.height : undefined,
|
|
153
153
|
}),
|
|
154
|
-
[isInlineModal,
|
|
154
|
+
[isInlineModal, tabletWidth, style.height, docked]
|
|
155
155
|
);
|
|
156
156
|
|
|
157
|
-
const playerDimensions:
|
|
157
|
+
const playerDimensions: DimensionsT = React.useMemo(
|
|
158
158
|
() => ({
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
159
|
+
...baseDimensions,
|
|
160
|
+
width: isInlineModal && docked ? undefined : baseDimensions.width,
|
|
161
|
+
aspectRatio: !isInlineModal ? getScreenAspectRatio() : 16 / 9,
|
|
162
|
+
}),
|
|
163
|
+
[baseDimensions, isInlineModal]
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const containerDimensions: DimensionsT = React.useMemo(
|
|
167
|
+
() => ({
|
|
168
|
+
...baseDimensions,
|
|
169
|
+
aspectRatio:
|
|
170
|
+
isInlineModal && docked ? undefined : playerDimensions.aspectRatio,
|
|
164
171
|
}),
|
|
165
|
-
[isInlineModal, docked,
|
|
172
|
+
[baseDimensions, isInlineModal, docked, playerDimensions.aspectRatio]
|
|
166
173
|
);
|
|
167
174
|
|
|
168
175
|
const WrapperView = React.useMemo(() => (isTV() ? View : SafeAreaView), []);
|
|
169
176
|
|
|
170
177
|
const childrenStyles = React.useMemo(
|
|
171
178
|
() => ({ ...playerDimensions, ...playerDimesionsHack }),
|
|
172
|
-
[
|
|
179
|
+
[containerDimensions, playerDimesionsHack]
|
|
173
180
|
);
|
|
174
181
|
|
|
175
182
|
return (
|
|
@@ -190,12 +197,6 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
190
197
|
defaultStyles.playerContainer,
|
|
191
198
|
containerDimensions,
|
|
192
199
|
containerStyle,
|
|
193
|
-
{
|
|
194
|
-
height:
|
|
195
|
-
isInlineModal && !docked
|
|
196
|
-
? containerDimensions.height + 10
|
|
197
|
-
: containerDimensions.height,
|
|
198
|
-
},
|
|
199
200
|
playerDimesionsHack,
|
|
200
201
|
]}
|
|
201
202
|
>
|
|
@@ -50,7 +50,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
|
50
50
|
|
|
51
51
|
jest.mock("../utils", () => ({ playerDimesionsHack: {} }));
|
|
52
52
|
|
|
53
|
-
const { PlayerWrapper
|
|
53
|
+
const { PlayerWrapper } = require("../PlayerWrapper");
|
|
54
54
|
|
|
55
55
|
jest.useFakeTimers();
|
|
56
56
|
const children = jest.fn(() => {});
|
|
@@ -110,7 +110,8 @@ describe("PlayerWrapper", () => {
|
|
|
110
110
|
|
|
111
111
|
const expectDimensions = {
|
|
112
112
|
...dimensions,
|
|
113
|
-
width:
|
|
113
|
+
width: undefined,
|
|
114
|
+
aspectRatio: 16 / 9,
|
|
114
115
|
};
|
|
115
116
|
|
|
116
117
|
expect(element).toMatchSnapshot();
|
|
@@ -35,13 +35,11 @@ exports[`PlayerWrapper renders inline 1`] = `
|
|
|
35
35
|
"zIndex": 200,
|
|
36
36
|
},
|
|
37
37
|
Object {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
38
|
+
"aspectRatio": 1.7777777777777777,
|
|
39
|
+
"height": undefined,
|
|
40
|
+
"width": "100%",
|
|
40
41
|
},
|
|
41
42
|
Object {},
|
|
42
|
-
Object {
|
|
43
|
-
"height": 431.875,
|
|
44
|
-
},
|
|
45
43
|
Object {},
|
|
46
44
|
]
|
|
47
45
|
}
|
|
@@ -105,13 +103,11 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
|
|
|
105
103
|
"zIndex": 200,
|
|
106
104
|
},
|
|
107
105
|
Object {
|
|
106
|
+
"aspectRatio": undefined,
|
|
108
107
|
"height": 50,
|
|
109
|
-
"width":
|
|
108
|
+
"width": "100%",
|
|
110
109
|
},
|
|
111
110
|
Object {},
|
|
112
|
-
Object {
|
|
113
|
-
"height": 50,
|
|
114
|
-
},
|
|
115
111
|
Object {},
|
|
116
112
|
]
|
|
117
113
|
}
|
|
@@ -163,13 +159,11 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
|
|
|
163
159
|
"zIndex": 200,
|
|
164
160
|
},
|
|
165
161
|
Object {
|
|
166
|
-
"
|
|
162
|
+
"aspectRatio": 1.7777777777777777,
|
|
163
|
+
"height": undefined,
|
|
167
164
|
"width": 195,
|
|
168
165
|
},
|
|
169
166
|
Object {},
|
|
170
|
-
Object {
|
|
171
|
-
"height": 119.6875,
|
|
172
|
-
},
|
|
173
167
|
Object {},
|
|
174
168
|
]
|
|
175
169
|
}
|
|
@@ -233,13 +227,11 @@ exports[`PlayerWrapper renders properly 1`] = `
|
|
|
233
227
|
"zIndex": 200,
|
|
234
228
|
},
|
|
235
229
|
Object {
|
|
236
|
-
"
|
|
237
|
-
"
|
|
230
|
+
"aspectRatio": 1.7786666666666666,
|
|
231
|
+
"height": undefined,
|
|
232
|
+
"width": "100%",
|
|
238
233
|
},
|
|
239
234
|
Object {},
|
|
240
|
-
Object {
|
|
241
|
-
"height": 800,
|
|
242
|
-
},
|
|
243
235
|
Object {},
|
|
244
236
|
]
|
|
245
237
|
}
|
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.5812543239",
|
|
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",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"redux-mock-store": "^1.5.3"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
39
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.
|
|
40
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.
|
|
41
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
38
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.5812543239",
|
|
39
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.5812543239",
|
|
40
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.5812543239",
|
|
41
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.5812543239",
|
|
42
42
|
"promise": "^8.3.0",
|
|
43
43
|
"react-router-native": "^5.1.2",
|
|
44
44
|
"url": "^0.11.0",
|