@applicaster/zapp-react-native-ui-components 15.0.0-alpha.2463014505 → 15.0.0-alpha.2835124704
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 +69 -26
- package/Components/Cell/FocusableWrapper.tsx +44 -0
- package/Components/Cell/TvOSCellComponent.tsx +92 -17
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +9 -11
- package/Components/HandlePlayable/HandlePlayable.tsx +14 -65
- package/Components/HandlePlayable/const.ts +3 -0
- package/Components/HandlePlayable/utils.ts +74 -0
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +16 -14
- package/Components/PlayerContainer/PlayerContainer.tsx +1 -16
- package/Components/PlayerImageBackground/index.tsx +3 -22
- package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
- package/Components/Screen/index.tsx +22 -5
- package/Components/ScreenResolver/index.tsx +8 -2
- package/Components/ScreenRevealManager/utils/index.ts +23 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +54 -24
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +114 -171
- package/Components/VideoModal/ModalAnimation/index.ts +2 -13
- package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
- package/Components/VideoModal/PlayerWrapper.tsx +14 -88
- package/Components/VideoModal/VideoModal.tsx +1 -5
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
- package/Components/VideoModal/hooks/useModalSize.ts +10 -5
- package/Components/VideoModal/playerWrapperStyle.ts +70 -0
- package/Components/VideoModal/playerWrapperUtils.ts +91 -0
- package/Components/VideoModal/utils.ts +7 -0
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
- package/Helpers/DataSourceHelper/index.js +4 -0
- package/package.json +5 -5
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
|
@@ -6,10 +6,6 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
6
6
|
|
|
7
7
|
type AnimatedInterpolatedStyle = any;
|
|
8
8
|
|
|
9
|
-
// type AnimatedInterpolatedStyle =
|
|
10
|
-
// | Animated.AnimatedInterpolation
|
|
11
|
-
// | [{ [Key: string]: Animated.AnimatedInterpolation }];
|
|
12
|
-
|
|
13
9
|
type AnimationConfig = {
|
|
14
10
|
duration: number;
|
|
15
11
|
easing: EasingFunction;
|
|
@@ -45,32 +41,57 @@ export function AnimatedInOut({
|
|
|
45
41
|
children,
|
|
46
42
|
}: Props) {
|
|
47
43
|
const [animatedValue] = React.useState(new Animated.Value(visible ? 1 : 0));
|
|
48
|
-
const
|
|
44
|
+
const animationRef = React.useRef<Animated.CompositeAnimation | null>(null);
|
|
45
|
+
const delayTimerRef = React.useRef<NodeJS.Timeout | null>(null);
|
|
49
46
|
|
|
50
47
|
const previousVisible = usePrevious(toBooleanWithDefaultFalse(visible));
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
const startAnimation = React.useCallback(
|
|
50
|
+
(toValue: number, config: AnimationConfig) => {
|
|
51
|
+
if (delayTimerRef.current) {
|
|
52
|
+
clearTimeout(delayTimerRef.current);
|
|
53
|
+
delayTimerRef.current = null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (animationRef.current) {
|
|
57
|
+
animationRef.current.stop();
|
|
58
|
+
animationRef.current = null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { duration, easing, delay = 0, onAnimationEnd = noop } = config;
|
|
62
|
+
|
|
63
|
+
const runAnimation = () => {
|
|
64
|
+
animationRef.current = Animated.timing(animatedValue, {
|
|
65
|
+
duration,
|
|
66
|
+
toValue,
|
|
67
|
+
easing,
|
|
68
|
+
useNativeDriver: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
animationRef.current.start(({ finished }) => {
|
|
72
|
+
if (finished) {
|
|
73
|
+
animationRef.current = null;
|
|
74
|
+
onAnimationEnd();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
if (delay > 0) {
|
|
80
|
+
delayTimerRef.current = setTimeout(runAnimation, delay);
|
|
81
|
+
} else {
|
|
82
|
+
runAnimation();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
[animatedValue]
|
|
86
|
+
);
|
|
58
87
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
easing,
|
|
63
|
-
delay,
|
|
64
|
-
useNativeDriver: true,
|
|
65
|
-
}).start(() => {
|
|
66
|
-
setAnimating(undefined);
|
|
67
|
-
onAnimationEnd();
|
|
68
|
-
});
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
if (previousVisible === undefined) {
|
|
90
|
+
animatedValue.setValue(visible ? 1 : 0);
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
72
94
|
|
|
73
|
-
React.useEffect(() => {
|
|
74
95
|
if (!previousVisible && visible) {
|
|
75
96
|
startAnimation(1.0, getAnimation(animationConfig, "in"));
|
|
76
97
|
}
|
|
@@ -78,7 +99,29 @@ export function AnimatedInOut({
|
|
|
78
99
|
if (previousVisible && !visible) {
|
|
79
100
|
startAnimation(0.0, getAnimation(animationConfig, "out"));
|
|
80
101
|
}
|
|
81
|
-
}, [
|
|
102
|
+
}, [
|
|
103
|
+
visible,
|
|
104
|
+
previousVisible,
|
|
105
|
+
animatedValue,
|
|
106
|
+
startAnimation,
|
|
107
|
+
animationConfig,
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
React.useEffect(() => {
|
|
111
|
+
return () => {
|
|
112
|
+
if (delayTimerRef.current) {
|
|
113
|
+
clearTimeout(delayTimerRef.current);
|
|
114
|
+
delayTimerRef.current = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (animationRef.current) {
|
|
118
|
+
animationRef.current.stop();
|
|
119
|
+
animationRef.current = null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
animatedValue.stopAnimation();
|
|
123
|
+
};
|
|
124
|
+
}, [animatedValue]);
|
|
82
125
|
|
|
83
126
|
const styles = visible
|
|
84
127
|
? getAnimation(animationConfig, "in").styles
|
|
@@ -86,7 +129,7 @@ export function AnimatedInOut({
|
|
|
86
129
|
|
|
87
130
|
return (
|
|
88
131
|
<Animated.View
|
|
89
|
-
renderToHardwareTextureAndroid={
|
|
132
|
+
renderToHardwareTextureAndroid={!!animationRef.current}
|
|
90
133
|
style={[styles(animatedValue), staticStyles]}
|
|
91
134
|
>
|
|
92
135
|
{children}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
|
|
3
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
id: string;
|
|
7
|
+
groupId: string;
|
|
8
|
+
isParallaxDisabled: boolean;
|
|
9
|
+
applyWrapper: boolean;
|
|
10
|
+
children: (focused: boolean) => React.ReactNode;
|
|
11
|
+
onFocus: (arg1: any, index?: number) => void;
|
|
12
|
+
onBlur: Callback;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const FocusableWrapper = ({
|
|
16
|
+
id,
|
|
17
|
+
groupId,
|
|
18
|
+
isParallaxDisabled,
|
|
19
|
+
children,
|
|
20
|
+
applyWrapper,
|
|
21
|
+
onFocus,
|
|
22
|
+
onBlur,
|
|
23
|
+
}: Props) => {
|
|
24
|
+
if (applyWrapper) {
|
|
25
|
+
return (
|
|
26
|
+
<Focusable
|
|
27
|
+
id={id}
|
|
28
|
+
groupId={groupId}
|
|
29
|
+
isParallaxDisabled={isParallaxDisabled}
|
|
30
|
+
onFocus={onFocus}
|
|
31
|
+
onBlur={onBlur}
|
|
32
|
+
willReceiveFocus={noop}
|
|
33
|
+
hasReceivedFocus={noop}
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
offsetUpdater={noop}
|
|
36
|
+
isFocusable
|
|
37
|
+
>
|
|
38
|
+
{(focused) => children(focused)}
|
|
39
|
+
</Focusable>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return <>{children(false)}</>;
|
|
44
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { View, StyleSheet } from "react-native";
|
|
4
|
+
import { first, filter } from "rxjs/operators";
|
|
5
|
+
|
|
6
|
+
import { compose } from "@applicaster/zapp-react-native-utils/utils";
|
|
4
7
|
|
|
5
8
|
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
|
|
6
9
|
import { FocusableCell } from "@applicaster/zapp-react-native-ui-components/Components/FocusableCell";
|
|
@@ -9,7 +12,12 @@ import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUti
|
|
|
9
12
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
10
13
|
import { sendSelectCellEvent } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
11
14
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
15
|
+
import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
12
16
|
import { CellWithFocusable } from "./CellWithFocusable";
|
|
17
|
+
import { FocusableWrapper } from "./FocusableWrapper";
|
|
18
|
+
|
|
19
|
+
import { focusableButtonsRegistration$ } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
20
|
+
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
13
21
|
|
|
14
22
|
type Props = {
|
|
15
23
|
item: ZappEntry;
|
|
@@ -30,6 +38,9 @@ type Props = {
|
|
|
30
38
|
component: {
|
|
31
39
|
id: number | string;
|
|
32
40
|
component_type: string;
|
|
41
|
+
styles?: {
|
|
42
|
+
component_margin_top?: number;
|
|
43
|
+
};
|
|
33
44
|
};
|
|
34
45
|
selected: boolean;
|
|
35
46
|
CellRenderer: React.FunctionComponent<any> & {
|
|
@@ -66,6 +77,8 @@ type Props = {
|
|
|
66
77
|
shouldUpdate: boolean;
|
|
67
78
|
behavior: Behavior;
|
|
68
79
|
componentsMapOffset: number;
|
|
80
|
+
applyFocusableWrapper: boolean;
|
|
81
|
+
hasFocusableInside: boolean;
|
|
69
82
|
};
|
|
70
83
|
|
|
71
84
|
type State = {
|
|
@@ -82,7 +95,7 @@ const baseCellStyles = {
|
|
|
82
95
|
flex: 1,
|
|
83
96
|
} as const;
|
|
84
97
|
|
|
85
|
-
|
|
98
|
+
class TvOSCell extends React.Component<Props, State> {
|
|
86
99
|
cell: any;
|
|
87
100
|
target: any;
|
|
88
101
|
layout: any;
|
|
@@ -195,11 +208,16 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
195
208
|
const extraAnchorPointYOffset =
|
|
196
209
|
screenLayout?.extraAnchorPointYOffset || 0;
|
|
197
210
|
|
|
211
|
+
const componentMarginTop = toNumberWithDefaultZero(
|
|
212
|
+
component?.styles?.component_margin_top
|
|
213
|
+
);
|
|
214
|
+
|
|
198
215
|
const totalOffset =
|
|
199
216
|
headerOffset +
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
217
|
+
(componentAnchorPointY || 0) +
|
|
218
|
+
extraAnchorPointYOffset -
|
|
219
|
+
(componentsMapOffset || 0) +
|
|
220
|
+
componentMarginTop;
|
|
203
221
|
|
|
204
222
|
mainOffsetUpdater?.(
|
|
205
223
|
{ tag: this.target },
|
|
@@ -239,6 +257,8 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
239
257
|
groupId,
|
|
240
258
|
isFocusable,
|
|
241
259
|
behavior,
|
|
260
|
+
applyFocusableWrapper,
|
|
261
|
+
hasFocusableInside,
|
|
242
262
|
} = this.props;
|
|
243
263
|
|
|
244
264
|
const { id } = item;
|
|
@@ -254,24 +274,33 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
254
274
|
this.onFocus(arg1, index);
|
|
255
275
|
};
|
|
256
276
|
|
|
257
|
-
const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
|
|
258
|
-
|
|
259
277
|
if (hasFocusableInside) {
|
|
260
278
|
return (
|
|
261
279
|
<View onLayout={this.onLayout}>
|
|
262
|
-
<
|
|
263
|
-
CellRenderer={CellRenderer}
|
|
264
|
-
item={item}
|
|
280
|
+
<FocusableWrapper
|
|
265
281
|
id={focusableId}
|
|
266
|
-
groupId={(groupId || component?.id)
|
|
282
|
+
groupId={String(groupId || component?.id)}
|
|
283
|
+
isParallaxDisabled={this.layout?.width > 1740}
|
|
267
284
|
onFocus={handleFocus}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
285
|
+
onBlur={onBlur || this.onBlur}
|
|
286
|
+
applyWrapper={applyFocusableWrapper}
|
|
287
|
+
>
|
|
288
|
+
{(focused) => (
|
|
289
|
+
<CellWithFocusable
|
|
290
|
+
CellRenderer={CellRenderer}
|
|
291
|
+
item={item}
|
|
292
|
+
id={focusableId}
|
|
293
|
+
groupId={(groupId || component?.id).toString()}
|
|
294
|
+
onFocus={handleFocus}
|
|
295
|
+
index={index}
|
|
296
|
+
scrollTo={this.scrollTo}
|
|
297
|
+
preferredFocus={preferredFocus}
|
|
298
|
+
focused={focused || this.props.focused}
|
|
299
|
+
behavior={behavior}
|
|
300
|
+
isFocusable={isFocusable}
|
|
301
|
+
/>
|
|
302
|
+
)}
|
|
303
|
+
</FocusableWrapper>
|
|
275
304
|
</View>
|
|
276
305
|
);
|
|
277
306
|
}
|
|
@@ -309,3 +338,49 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
309
338
|
);
|
|
310
339
|
}
|
|
311
340
|
}
|
|
341
|
+
|
|
342
|
+
export function withFocusableWrapperHOC(Component) {
|
|
343
|
+
return function WrappedComponent(props) {
|
|
344
|
+
const [focusableViewIsRendered, setFocusableViewIsRendered] =
|
|
345
|
+
React.useState(false);
|
|
346
|
+
|
|
347
|
+
const { CellRenderer, item, groupId, component } = props;
|
|
348
|
+
|
|
349
|
+
const isFocusable = toBooleanWithDefaultTrue(props?.isFocusable);
|
|
350
|
+
|
|
351
|
+
const focusableGroupId = String(groupId || component?.id);
|
|
352
|
+
|
|
353
|
+
const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
|
|
354
|
+
|
|
355
|
+
React.useEffect(() => {
|
|
356
|
+
// start waiting any first registration of FocusableButton inside this focusableGroup
|
|
357
|
+
// after it we could get rid of applying focusable-wrapper
|
|
358
|
+
const subscription = focusableButtonsRegistration$(focusableGroupId)
|
|
359
|
+
.pipe(
|
|
360
|
+
filter(() => isFocusable),
|
|
361
|
+
first()
|
|
362
|
+
)
|
|
363
|
+
.subscribe(() => {
|
|
364
|
+
setFocusableViewIsRendered(true);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
return () => {
|
|
368
|
+
subscription.unsubscribe();
|
|
369
|
+
};
|
|
370
|
+
}, [isFocusable, focusableGroupId]);
|
|
371
|
+
|
|
372
|
+
const applyFocusableWrapper = React.useMemo(() => {
|
|
373
|
+
return isFocusable && hasFocusableInside && !focusableViewIsRendered;
|
|
374
|
+
}, [isFocusable, hasFocusableInside, focusableViewIsRendered]);
|
|
375
|
+
|
|
376
|
+
return (
|
|
377
|
+
<Component
|
|
378
|
+
{...props}
|
|
379
|
+
applyFocusableWrapper={applyFocusableWrapper}
|
|
380
|
+
hasFocusableInside={hasFocusableInside}
|
|
381
|
+
/>
|
|
382
|
+
);
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export const TvOSCellComponent = compose(withFocusableWrapperHOC)(TvOSCell);
|
|
@@ -142,17 +142,15 @@ export const useCurationAPI = (
|
|
|
142
142
|
const url = path(SOURCE_PATH, component);
|
|
143
143
|
const mapping = path(MAPPING_PATH, component);
|
|
144
144
|
|
|
145
|
-
map[component.id] =
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
})
|
|
155
|
-
: url;
|
|
145
|
+
map[component.id] = getInflatedDataSourceUrl({
|
|
146
|
+
source: url,
|
|
147
|
+
contexts: {
|
|
148
|
+
entry: entryContext,
|
|
149
|
+
screen: screenContext,
|
|
150
|
+
search: getSearchContext(searchContext, mapping),
|
|
151
|
+
},
|
|
152
|
+
mapping,
|
|
153
|
+
});
|
|
156
154
|
});
|
|
157
155
|
|
|
158
156
|
return map;
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
|
-
import {
|
|
4
|
-
findPluginByType,
|
|
5
|
-
findPluginByIdentifier,
|
|
6
|
-
} from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
7
2
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
8
3
|
import {
|
|
9
4
|
useDimensions,
|
|
@@ -16,6 +11,7 @@ import { PlayerContainer } from "../PlayerContainer";
|
|
|
16
11
|
import { useModalSize } from "../VideoModal/hooks";
|
|
17
12
|
import { ViewStyle } from "react-native";
|
|
18
13
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
14
|
+
import { findCastPlugin, getPlayer } from "./utils";
|
|
19
15
|
|
|
20
16
|
type Props = {
|
|
21
17
|
item: ZappEntry;
|
|
@@ -26,62 +22,6 @@ type Props = {
|
|
|
26
22
|
groupId?: string;
|
|
27
23
|
};
|
|
28
24
|
|
|
29
|
-
const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
|
|
30
|
-
const CHROMECAST_PLUGIN_ID = "chromecast_qb";
|
|
31
|
-
|
|
32
|
-
const getPlayerWithModuleProperties = (
|
|
33
|
-
PlayerModule: ZappPlugin
|
|
34
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
35
|
-
const getPlayerModuleProperties = R.ifElse(
|
|
36
|
-
R.is(Object) && R.has("Component"),
|
|
37
|
-
R.omit(["Component"]),
|
|
38
|
-
() => ({})
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
return [
|
|
42
|
-
PlayerModule?.Component || PlayerModule,
|
|
43
|
-
getPlayerModuleProperties(PlayerModule),
|
|
44
|
-
];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const getPlayer = (
|
|
48
|
-
item: ZappEntry,
|
|
49
|
-
state
|
|
50
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
51
|
-
const {
|
|
52
|
-
plugins,
|
|
53
|
-
contentTypes,
|
|
54
|
-
rivers,
|
|
55
|
-
appData: { layoutVersion },
|
|
56
|
-
} = state;
|
|
57
|
-
|
|
58
|
-
let PlayerModule;
|
|
59
|
-
|
|
60
|
-
if (layoutVersion === "v2") {
|
|
61
|
-
const { screen_id } = contentTypes?.[item?.type?.value] || {};
|
|
62
|
-
const { type } = rivers?.[screen_id] || {};
|
|
63
|
-
|
|
64
|
-
if (type) {
|
|
65
|
-
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
66
|
-
|
|
67
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (item?.content?.type === "youtube-id") {
|
|
72
|
-
PlayerModule = findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins)?.module;
|
|
73
|
-
|
|
74
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
PlayerModule = findPluginByType(
|
|
78
|
-
"playable",
|
|
79
|
-
plugins.filter(({ identifier }) => identifier !== YOUTUBE_PLUGIN_ID)
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
25
|
type PlayableComponent = {
|
|
86
26
|
Component: React.ComponentType<any>;
|
|
87
27
|
};
|
|
@@ -99,14 +39,23 @@ export function HandlePlayable({
|
|
|
99
39
|
mode,
|
|
100
40
|
groupId,
|
|
101
41
|
}: Props): React.ReactElement | null {
|
|
102
|
-
const
|
|
42
|
+
const { plugins, contentTypes, rivers, appData } = usePickFromState([
|
|
43
|
+
"plugins",
|
|
44
|
+
"contentTypes",
|
|
45
|
+
"rivers",
|
|
46
|
+
"appData",
|
|
47
|
+
]);
|
|
103
48
|
|
|
104
49
|
const { closeVideoModal } = useNavigation();
|
|
105
50
|
|
|
106
|
-
const [Player, playerModuleProperties] = getPlayer(item,
|
|
51
|
+
const [Player, playerModuleProperties] = getPlayer(item, {
|
|
52
|
+
plugins,
|
|
53
|
+
contentTypes,
|
|
54
|
+
rivers,
|
|
55
|
+
appData,
|
|
56
|
+
});
|
|
107
57
|
|
|
108
|
-
const { module: CastPlugin } =
|
|
109
|
-
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
|
|
58
|
+
const { module: CastPlugin } = findCastPlugin(plugins);
|
|
110
59
|
|
|
111
60
|
const [playable, setPlayable] =
|
|
112
61
|
React.useState<Nullable<PlayableComponent>>(null);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findPluginByIdentifier,
|
|
3
|
+
findPluginByType,
|
|
4
|
+
} from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
5
|
+
|
|
6
|
+
import { CHROMECAST_PLUGIN_ID, YOUTUBE_PLUGIN_ID } from "./const";
|
|
7
|
+
import { omit } from "@applicaster/zapp-react-native-utils/utils";
|
|
8
|
+
|
|
9
|
+
const getPlayerModuleProperties = (PlayerModule: ZappPlugin) => {
|
|
10
|
+
if (PlayerModule?.Component && typeof PlayerModule.Component === "object") {
|
|
11
|
+
return omit(["Component"], PlayerModule);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getPlayerWithModuleProperties = (
|
|
18
|
+
PlayerModule: ZappPlugin
|
|
19
|
+
): [ZappPlugin, PlayerModuleProperties] => {
|
|
20
|
+
return [
|
|
21
|
+
PlayerModule?.Component || PlayerModule,
|
|
22
|
+
getPlayerModuleProperties(PlayerModule),
|
|
23
|
+
];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const findCastPlugin = (plugins: ZappPlugin[]) =>
|
|
27
|
+
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, plugins, true) || {};
|
|
28
|
+
|
|
29
|
+
export const findYoutubePlugin = (plugins: ZappPlugin[]) =>
|
|
30
|
+
findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins, true) || {};
|
|
31
|
+
|
|
32
|
+
export const getPlayer = (
|
|
33
|
+
item: ZappEntry,
|
|
34
|
+
{
|
|
35
|
+
plugins,
|
|
36
|
+
contentTypes,
|
|
37
|
+
rivers,
|
|
38
|
+
appData: { layoutVersion },
|
|
39
|
+
}: {
|
|
40
|
+
plugins: ZappPlugin[];
|
|
41
|
+
contentTypes: Record<string, any>;
|
|
42
|
+
rivers: Record<string, any>;
|
|
43
|
+
appData: { layoutVersion: string };
|
|
44
|
+
}
|
|
45
|
+
): [ZappPlugin, PlayerModuleProperties] => {
|
|
46
|
+
let PlayerModule;
|
|
47
|
+
|
|
48
|
+
if (layoutVersion === "v2") {
|
|
49
|
+
const screen_id = contentTypes?.[item?.type?.value]?.screen_id;
|
|
50
|
+
const type = rivers?.[screen_id]?.type;
|
|
51
|
+
|
|
52
|
+
if (type) {
|
|
53
|
+
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
54
|
+
|
|
55
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (item?.content?.type === "youtube-id") {
|
|
60
|
+
PlayerModule = findYoutubePlugin(plugins)?.module;
|
|
61
|
+
|
|
62
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
PlayerModule = findPluginByType(
|
|
66
|
+
"playable",
|
|
67
|
+
(plugins as any[]).filter(
|
|
68
|
+
({ identifier }: { identifier: string }) =>
|
|
69
|
+
identifier !== YOUTUBE_PLUGIN_ID
|
|
70
|
+
)
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
74
|
+
};
|
|
@@ -32,6 +32,7 @@ export default function Image({
|
|
|
32
32
|
placeholderImage,
|
|
33
33
|
entry,
|
|
34
34
|
withDimensions,
|
|
35
|
+
source: sourceProp,
|
|
35
36
|
...otherProps
|
|
36
37
|
}: Props) {
|
|
37
38
|
const [showDefault, setShowDefault] = React.useState(false);
|
|
@@ -48,7 +49,10 @@ export default function Image({
|
|
|
48
49
|
entry,
|
|
49
50
|
showDefault,
|
|
50
51
|
placeholderImage: placeholderImage || "",
|
|
51
|
-
otherProps
|
|
52
|
+
otherProps: {
|
|
53
|
+
source: sourceProp,
|
|
54
|
+
state: otherProps.state,
|
|
55
|
+
},
|
|
52
56
|
});
|
|
53
57
|
|
|
54
58
|
const onError = React.useCallback(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Image as RnImage, ImageStyle } from "react-native";
|
|
3
|
-
import { equals
|
|
3
|
+
import { equals } from "ramda";
|
|
4
4
|
|
|
5
5
|
import { useImageSource } from "./hooks";
|
|
6
6
|
|
|
@@ -25,11 +25,19 @@ function Image({
|
|
|
25
25
|
placeholderImage,
|
|
26
26
|
entry,
|
|
27
27
|
withDimensions,
|
|
28
|
+
source: sourceProp,
|
|
28
29
|
...otherProps
|
|
29
30
|
}: Props) {
|
|
30
31
|
const [error, setErrorState] = React.useState(null);
|
|
31
32
|
|
|
32
|
-
const source = useImageSource({
|
|
33
|
+
const source = useImageSource({
|
|
34
|
+
uri,
|
|
35
|
+
entry,
|
|
36
|
+
otherProps: {
|
|
37
|
+
source: sourceProp,
|
|
38
|
+
state: otherProps.state,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
33
41
|
|
|
34
42
|
React.useEffect(() => {
|
|
35
43
|
// reset error state on URI change as the error is referencing previous uri
|
|
@@ -49,7 +57,7 @@ function Image({
|
|
|
49
57
|
onError={React.useCallback(() => setErrorState(true), [])}
|
|
50
58
|
// as we have defaults as "" for placeholder image, we need to pass undefined to source to not throw warnings
|
|
51
59
|
source={_source?.uri ? _source : undefined}
|
|
52
|
-
{...
|
|
60
|
+
{...otherProps}
|
|
53
61
|
/>
|
|
54
62
|
);
|
|
55
63
|
}
|
|
@@ -23,9 +23,17 @@ function Image({
|
|
|
23
23
|
placeholderImage,
|
|
24
24
|
entry,
|
|
25
25
|
withDimensions,
|
|
26
|
+
source: sourceProp,
|
|
26
27
|
...otherProps
|
|
27
28
|
}: Props) {
|
|
28
|
-
const source = useImageSource({
|
|
29
|
+
const source = useImageSource({
|
|
30
|
+
uri,
|
|
31
|
+
entry,
|
|
32
|
+
otherProps: {
|
|
33
|
+
source: sourceProp,
|
|
34
|
+
state: otherProps.state,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
29
37
|
|
|
30
38
|
const updatedSource = source ? withDimensions(source) : { uri: "" };
|
|
31
39
|
|