@applicaster/zapp-react-native-ui-components 13.0.0-alpha.1177234712 → 13.0.0-alpha.1212224153
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Components/Cell/Cell.tsx +4 -7
- package/Components/Cell/TvOSCellComponent.tsx +20 -22
- package/Components/Cell/index.js +3 -1
- package/Components/Focusable/FocusableTvOS.tsx +5 -1
- package/Components/FocusableList/index.tsx +26 -9
- package/Components/FocusableScrollView/index.tsx +39 -12
- package/Components/Layout/TV/NavBarContainer.tsx +8 -7
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +1 -1
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +1 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -4
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -5
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/River/TV/index.tsx +6 -1
- package/Components/River/__tests__/componentsMap.test.js +1 -14
- package/Components/VideoLive/LiveImageManager.ts +1 -27
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +16 -18
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +1 -51
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +5 -0
- package/Components/VideoModal/PlayerWrapper.tsx +35 -16
- package/Components/VideoModal/VideoModal.tsx +23 -14
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +90 -0
- package/Components/VideoModal/hooks/utils/index.ts +0 -33
- package/Components/VideoModal/utils.ts +1 -1
- package/Contexts/ComponentsMapOffsetContext/index.tsx +46 -0
- package/Decorators/ZappPipesDataConnector/index.tsx +1 -31
- package/package.json +5 -5
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +0 -60
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +0 -110
- package/Components/VideoModal/OpaqueLayer.tsx +0 -33
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +0 -89
- package/Components/VideoModal/hooks/index.ts +0 -7
- package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +0 -49
- package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +0 -91
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -61,6 +61,7 @@ type Props = {
|
|
|
61
61
|
skipFocusManagerRegistration?: boolean;
|
|
62
62
|
shouldUpdate: boolean;
|
|
63
63
|
behavior: Behavior;
|
|
64
|
+
componentsMapOffset: number;
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
type State = {
|
|
@@ -273,14 +274,10 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
273
274
|
if (isFocused) {
|
|
274
275
|
const accessibilityManager = AccessibilityManager.getInstance();
|
|
275
276
|
|
|
276
|
-
const accessibilityTitle =
|
|
277
|
-
item?.extensions?.accessibility?.label || item?.title || "";
|
|
278
|
-
|
|
279
|
-
const accessibilityHint =
|
|
280
|
-
item?.extensions?.accessibility?.hint || "";
|
|
281
|
-
|
|
282
277
|
accessibilityManager.readText({
|
|
283
|
-
text:
|
|
278
|
+
text: String(
|
|
279
|
+
item.extensions?.accessibility?.label || item.title
|
|
280
|
+
),
|
|
284
281
|
});
|
|
285
282
|
}
|
|
286
283
|
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { View, StyleSheet } from "react-native";
|
|
4
4
|
|
|
5
|
-
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
|
|
5
|
+
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
|
|
6
6
|
import { FocusableCell } from "@applicaster/zapp-react-native-ui-components/Components/FocusableCell";
|
|
7
7
|
import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
8
8
|
import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
@@ -65,6 +65,7 @@ type Props = {
|
|
|
65
65
|
isFocusable: boolean;
|
|
66
66
|
shouldUpdate: boolean;
|
|
67
67
|
behavior: Behavior;
|
|
68
|
+
componentsMapOffset: number;
|
|
68
69
|
};
|
|
69
70
|
|
|
70
71
|
type State = {
|
|
@@ -179,6 +180,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
179
180
|
groupId,
|
|
180
181
|
component,
|
|
181
182
|
index,
|
|
183
|
+
componentsMapOffset,
|
|
182
184
|
} = this.props;
|
|
183
185
|
|
|
184
186
|
this.setScreenLayout(componentAnchorPointY, screenLayout);
|
|
@@ -193,13 +195,11 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
193
195
|
const extraAnchorPointYOffset =
|
|
194
196
|
screenLayout?.extraAnchorPointYOffset || 0;
|
|
195
197
|
|
|
196
|
-
const marginTop = screenLayout?.screenMarginTop || 0;
|
|
197
|
-
|
|
198
198
|
const totalOffset =
|
|
199
199
|
headerOffset +
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
(componentAnchorPointY || 0) +
|
|
201
|
+
extraAnchorPointYOffset -
|
|
202
|
+
componentsMapOffset || 0;
|
|
203
203
|
|
|
204
204
|
mainOffsetUpdater?.(
|
|
205
205
|
{ tag: this.target },
|
|
@@ -247,7 +247,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
247
247
|
|
|
248
248
|
const focusableId = R.join("-", [component?.id, id, index]);
|
|
249
249
|
|
|
250
|
-
const handleFocus = (arg1: any, index
|
|
250
|
+
const handleFocus = (arg1: any, index?: number) => {
|
|
251
251
|
const focusFn = onFocus || noop;
|
|
252
252
|
focusFn(arg1, index);
|
|
253
253
|
|
|
@@ -280,7 +280,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
280
280
|
<View onLayout={this.onLayout} style={styles.container}>
|
|
281
281
|
<Focusable
|
|
282
282
|
id={focusableId}
|
|
283
|
-
groupId={groupId || component?.id}
|
|
283
|
+
groupId={String(groupId || component?.id)}
|
|
284
284
|
onFocus={handleFocus}
|
|
285
285
|
onBlur={onBlur || this.onBlur}
|
|
286
286
|
isParallaxDisabled={this.layout?.width > 1740}
|
|
@@ -292,20 +292,18 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
292
292
|
style={baseCellStyles}
|
|
293
293
|
isFocusable={isFocusable}
|
|
294
294
|
>
|
|
295
|
-
{(focused) =>
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
);
|
|
308
|
-
}}
|
|
295
|
+
{(focused) => (
|
|
296
|
+
<FocusableCell
|
|
297
|
+
{...{
|
|
298
|
+
index,
|
|
299
|
+
CellRenderer,
|
|
300
|
+
item,
|
|
301
|
+
focused: !!(this.props.focused || selectedCell || focused),
|
|
302
|
+
scrollTo: this.scrollTo,
|
|
303
|
+
behavior,
|
|
304
|
+
}}
|
|
305
|
+
/>
|
|
306
|
+
)}
|
|
309
307
|
</Focusable>
|
|
310
308
|
</View>
|
|
311
309
|
);
|
package/Components/Cell/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { ScreenScrollingContext } from "../../Contexts/ScreenScrollingContext";
|
|
|
11
11
|
|
|
12
12
|
import { ScreenLayoutContextConsumer } from "../../Contexts/ScreenLayoutContext";
|
|
13
13
|
import { createContext } from "@applicaster/zapp-react-native-utils/reactUtils/createContext";
|
|
14
|
+
import { withComponentsMapOffsetContextConsumer } from "../../Contexts/ComponentsMapOffsetContext";
|
|
14
15
|
|
|
15
16
|
// TODO | Gallery QB | Extract this
|
|
16
17
|
export const ScrollInterceptorContext = createContext(
|
|
@@ -30,5 +31,6 @@ export const Cell = R.compose(
|
|
|
30
31
|
RiverOffsetContext.withConsumer,
|
|
31
32
|
HorizontalScrollContext.withConsumer,
|
|
32
33
|
withConsumer,
|
|
33
|
-
ScreenLayoutContextConsumer
|
|
34
|
+
ScreenLayoutContextConsumer,
|
|
35
|
+
withComponentsMapOffsetContextConsumer
|
|
34
36
|
)(Component);
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
focusManager,
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
|
-
import { findNodeHandle } from "react-native";
|
|
12
|
+
import { findNodeHandle, ViewStyle } from "react-native";
|
|
13
13
|
|
|
14
14
|
function noop() {}
|
|
15
15
|
|
|
@@ -35,6 +35,10 @@ type Props = {
|
|
|
35
35
|
forceFocus?: boolean;
|
|
36
36
|
initialFocus?: boolean;
|
|
37
37
|
onLayout?: (e: any) => void;
|
|
38
|
+
willReceiveFocus: () => void;
|
|
39
|
+
hasReceivedFocus: () => void;
|
|
40
|
+
offsetUpdater: (arg1: string, arg2: number) => number;
|
|
41
|
+
style: ViewStyle;
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
export class Focusable extends BaseFocusable<Props> {
|
|
@@ -15,6 +15,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
15
15
|
|
|
16
16
|
import { useParentFocus, useCheckItemIdsForUnique } from "./hooks";
|
|
17
17
|
import { FocusableListItemWrapper } from "./FocusableListItemWrapper";
|
|
18
|
+
import { FocusableScrollView } from "../FocusableScrollView";
|
|
18
19
|
|
|
19
20
|
const mapIndexed = R.addIndex(R.map);
|
|
20
21
|
|
|
@@ -54,6 +55,7 @@ export type Props<ItemT> = FlatListProps<ItemT> & {
|
|
|
54
55
|
disableNextFocusUp?: boolean;
|
|
55
56
|
disableNextFocusLeft?: boolean;
|
|
56
57
|
disableNextFocusRight?: boolean;
|
|
58
|
+
useScrollView?: boolean;
|
|
57
59
|
} & ParentFocus;
|
|
58
60
|
|
|
59
61
|
function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
@@ -88,6 +90,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
88
90
|
data = [],
|
|
89
91
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
90
92
|
omitPropsPropagation = [],
|
|
93
|
+
useScrollView = false,
|
|
91
94
|
} = props;
|
|
92
95
|
|
|
93
96
|
useCheckItemIdsForUnique({ componentId: props.id, items: data });
|
|
@@ -273,6 +276,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
273
276
|
"initialFocusDirection",
|
|
274
277
|
"withStateMemory",
|
|
275
278
|
"useSequentialLoading",
|
|
279
|
+
"useScrollView",
|
|
276
280
|
...omitPropsPropagation,
|
|
277
281
|
],
|
|
278
282
|
R.__
|
|
@@ -295,15 +299,28 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
295
299
|
return (
|
|
296
300
|
// @ts-ignore
|
|
297
301
|
<ChildrenFocusDeactivatorView flex={1}>
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
302
|
+
{useScrollView ? (
|
|
303
|
+
<FocusableScrollView
|
|
304
|
+
ref={ref}
|
|
305
|
+
{...getFlatListProps(props)}
|
|
306
|
+
onEndReached={onEndReached}
|
|
307
|
+
initialNumToRender={initialNumToRender}
|
|
308
|
+
renderItem={renderItem}
|
|
309
|
+
focused={focused}
|
|
310
|
+
data={data}
|
|
311
|
+
/>
|
|
312
|
+
) : (
|
|
313
|
+
<FlatList
|
|
314
|
+
testID="focusable-list-flat-list"
|
|
315
|
+
focusable={false}
|
|
316
|
+
scrollEnabled={false}
|
|
317
|
+
ref={ref}
|
|
318
|
+
{...getFlatListProps(props)}
|
|
319
|
+
renderItem={renderItem}
|
|
320
|
+
onEndReached={onEndReached}
|
|
321
|
+
initialNumToRender={initialNumToRender}
|
|
322
|
+
/>
|
|
323
|
+
)}
|
|
307
324
|
</ChildrenFocusDeactivatorView>
|
|
308
325
|
);
|
|
309
326
|
}
|
|
@@ -11,6 +11,13 @@ import {
|
|
|
11
11
|
useInitialFocus,
|
|
12
12
|
} from "@applicaster/zapp-react-native-utils/focusManager";
|
|
13
13
|
|
|
14
|
+
export type FocusableScrollViewRenderItem = (info: {
|
|
15
|
+
item: ZappUIComponent;
|
|
16
|
+
index: number;
|
|
17
|
+
focused: boolean;
|
|
18
|
+
parentFocus: ParentFocus;
|
|
19
|
+
}) => React.ReactElement;
|
|
20
|
+
|
|
14
21
|
export type Props = ScrollViewProps & {
|
|
15
22
|
id?: number | string;
|
|
16
23
|
horizontal?: boolean;
|
|
@@ -32,17 +39,27 @@ export type Props = ScrollViewProps & {
|
|
|
32
39
|
initialFocusDirection?: FocusManager.Android.FocusNavigationDirections;
|
|
33
40
|
onAllComponentsLoaded?: () => void;
|
|
34
41
|
omitPropsPropagation?: Array<keyof FlatListProps<any>>;
|
|
35
|
-
renderItem:
|
|
36
|
-
item: ZappUIComponent;
|
|
37
|
-
index: number;
|
|
38
|
-
focused: boolean;
|
|
39
|
-
parentFocus: ParentFocus;
|
|
40
|
-
}) => React.ReactElement;
|
|
42
|
+
renderItem: FocusableScrollViewRenderItem;
|
|
41
43
|
} & ParentFocus;
|
|
42
44
|
|
|
43
45
|
type State = boolean[];
|
|
44
46
|
type Action = { index?: number; isFocusable: boolean; type?: string };
|
|
45
47
|
|
|
48
|
+
const unwrapArray = (maybeArray) =>
|
|
49
|
+
Array.isArray(maybeArray) ? maybeArray[0] : maybeArray;
|
|
50
|
+
|
|
51
|
+
function getEntry<T>(data: T | T[], index: unknown): T {
|
|
52
|
+
let entry;
|
|
53
|
+
|
|
54
|
+
if (R.isNil(index)) {
|
|
55
|
+
entry = unwrapArray(data);
|
|
56
|
+
} else if (typeof index === "number") {
|
|
57
|
+
entry = unwrapArray(data[index]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return entry;
|
|
61
|
+
}
|
|
62
|
+
|
|
46
63
|
const focusableStateReducer = (
|
|
47
64
|
state: State,
|
|
48
65
|
{ index = null, isFocusable, type = null }: Action
|
|
@@ -73,7 +90,7 @@ const extendScrollViewRef = (_ref, childCompsMeasurementsMap) => {
|
|
|
73
90
|
};
|
|
74
91
|
|
|
75
92
|
_ref.scrollToIndex = (params) => {
|
|
76
|
-
const { index, viewOffset } = params;
|
|
93
|
+
const { index, viewOffset = 0 } = params;
|
|
77
94
|
|
|
78
95
|
const itemByIndex = R.find(R.propEq("index", index))(
|
|
79
96
|
R.values(childCompsMeasurementsMap)
|
|
@@ -129,8 +146,11 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
129
146
|
);
|
|
130
147
|
|
|
131
148
|
const getFocusableEntryId = React.useCallback(
|
|
132
|
-
(_entry: ZappEntry, index?: number) => {
|
|
133
|
-
const entry
|
|
149
|
+
(_entry: ZappEntry | null, index?: number) => {
|
|
150
|
+
const entry: { id?: string } = getEntry(
|
|
151
|
+
R.isNil(index) ? _entry : data,
|
|
152
|
+
index
|
|
153
|
+
);
|
|
134
154
|
|
|
135
155
|
return entry ? `${props.id}--${entry?.id}` : undefined;
|
|
136
156
|
},
|
|
@@ -273,11 +293,18 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
273
293
|
const renderItem = React.useCallback(
|
|
274
294
|
(item, index) => {
|
|
275
295
|
const renderArgs = { item, index };
|
|
276
|
-
|
|
277
|
-
const
|
|
296
|
+
|
|
297
|
+
const id = getFocusableEntryId(
|
|
298
|
+
Array.isArray(item) ? item[0] : item,
|
|
299
|
+
index
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
const nextFocus = getNextFocus(index);
|
|
278
303
|
|
|
279
304
|
const onItemLayout = (event) => {
|
|
280
|
-
childCompsMeasurementsMap.current[
|
|
305
|
+
childCompsMeasurementsMap.current[
|
|
306
|
+
Array.isArray(item) ? index : item.id
|
|
307
|
+
] = {
|
|
281
308
|
index,
|
|
282
309
|
layout: event.nativeEvent.layout,
|
|
283
310
|
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View, StyleSheet } from "react-native";
|
|
3
|
-
import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext";
|
|
4
|
-
import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
5
3
|
import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
6
4
|
import { useScreenConfiguration } from "../../River/useScreenConfiguration";
|
|
7
5
|
|
|
@@ -12,12 +10,15 @@ type Props = {
|
|
|
12
10
|
};
|
|
13
11
|
|
|
14
12
|
const styles = StyleSheet.create({
|
|
15
|
-
container: {
|
|
13
|
+
container: {
|
|
14
|
+
position: "absolute",
|
|
15
|
+
top: 0,
|
|
16
|
+
zIndex: 10,
|
|
17
|
+
width: 1920,
|
|
18
|
+
},
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
|
|
19
|
-
const screenLayout = React.useContext(ScreenLayoutContext);
|
|
20
|
-
const screenMarginTop = screenLayout?.screenMarginTop || 0;
|
|
21
22
|
const screen = useCurrentScreenData();
|
|
22
23
|
const screenConfig = useScreenConfiguration(screen?.id);
|
|
23
24
|
|
|
@@ -26,9 +27,9 @@ export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
|
|
|
26
27
|
// limits the height of the focusable container of the TopMenuBarTV component
|
|
27
28
|
// to prevent it from being overlapped by the screen content,
|
|
28
29
|
// as it makes TopMenuBarTV unfocusable on tvOS
|
|
29
|
-
maxHeight:
|
|
30
|
+
maxHeight: 1,
|
|
30
31
|
}),
|
|
31
|
-
[
|
|
32
|
+
[screenConfig]
|
|
32
33
|
);
|
|
33
34
|
|
|
34
35
|
React.useEffect(() => {
|
|
@@ -28,10 +28,7 @@ const styles = StyleSheet.create({
|
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
borderPosition: BorderPosition,
|
|
33
|
-
borderWidth: number
|
|
34
|
-
) => {
|
|
31
|
+
const getBorderPadding = (borderPosition: BorderPosition, borderWidth) => {
|
|
35
32
|
switch (borderPosition) {
|
|
36
33
|
case "inside":
|
|
37
34
|
return 0;
|
|
@@ -38,16 +38,22 @@ function Image({
|
|
|
38
38
|
|
|
39
39
|
const shouldRenderImg = source && !error;
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
// Default placeholder image fallback is empty string because it won't rerender
|
|
42
|
+
// in case of undefined or {uri: undefined} source
|
|
43
|
+
// https://github.com/facebook/react-native/issues/9195
|
|
44
|
+
const defaultPlaceHolderImage = React.useMemo(
|
|
45
|
+
() => ({ uri: placeholderImage || "" }),
|
|
46
|
+
[source, error]
|
|
47
|
+
);
|
|
44
48
|
|
|
45
49
|
return (
|
|
50
|
+
// @ts-ignore
|
|
46
51
|
<MemoizedImage
|
|
47
52
|
style={style as ImageStyle}
|
|
48
53
|
onError={React.useCallback(() => setErrorState(true), [])}
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
source={
|
|
55
|
+
shouldRenderImg ? withDimensions(source) : defaultPlaceHolderImage
|
|
56
|
+
}
|
|
51
57
|
{...R.omit(["source"], otherProps)}
|
|
52
58
|
/>
|
|
53
59
|
);
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import { compose } from "ramda";
|
|
1
2
|
import { River as RiverComponent } from "./River";
|
|
2
3
|
import { withTvEventHandler } from "./withTVEventHandler";
|
|
4
|
+
import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
|
|
3
5
|
|
|
4
|
-
export const River =
|
|
6
|
+
export const River = compose(
|
|
7
|
+
withTvEventHandler,
|
|
8
|
+
withComponentsMapOffsetContext
|
|
9
|
+
)(RiverComponent);
|
|
@@ -81,13 +81,6 @@ const mockScreenData = {
|
|
|
81
81
|
id: "A1234",
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
jest.mock("@applicaster/zapp-react-native-redux/AppStore", () => ({
|
|
85
|
-
appStore: {
|
|
86
|
-
get: jest.fn((prop) => mockStore[prop]),
|
|
87
|
-
getState: jest.fn(),
|
|
88
|
-
},
|
|
89
|
-
}));
|
|
90
|
-
|
|
91
84
|
jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
|
|
92
85
|
useIsRTL: jest.fn(() => mock_rtl_flag),
|
|
93
86
|
}));
|
|
@@ -160,13 +153,7 @@ const plugins = [];
|
|
|
160
153
|
const navigation = {};
|
|
161
154
|
|
|
162
155
|
const props = { components, cellStyles, riverComponents, navigation };
|
|
163
|
-
|
|
164
|
-
const store = mockStore({
|
|
165
|
-
components,
|
|
166
|
-
cellStyles,
|
|
167
|
-
plugins,
|
|
168
|
-
getState: jest.fn(),
|
|
169
|
-
});
|
|
156
|
+
const store = mockStore({ components, cellStyles, plugins });
|
|
170
157
|
|
|
171
158
|
jest.useFakeTimers();
|
|
172
159
|
|
|
@@ -8,8 +8,6 @@ import { loggerLiveImageManager } from "./loggerHelper";
|
|
|
8
8
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
9
9
|
import { Component } from "react";
|
|
10
10
|
|
|
11
|
-
const TIMEOUT_FOR_DELAY_CHECK_PLAYER_POSITION = 500; // ms
|
|
12
|
-
|
|
13
11
|
const { log_debug, log_info, log_error } = loggerLiveImageManager;
|
|
14
12
|
|
|
15
13
|
export type LiveImageManagerEvent =
|
|
@@ -64,9 +62,6 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
64
62
|
protected currentlyPlaying: LiveImage | null = null;
|
|
65
63
|
protected primaryPlayer: Player | null = null;
|
|
66
64
|
|
|
67
|
-
private checkPlayerPositionTimeout: ReturnType<typeof setTimeout> | null =
|
|
68
|
-
null;
|
|
69
|
-
|
|
70
65
|
protected listeners: Record<
|
|
71
66
|
string,
|
|
72
67
|
Record<LiveImageManagerEvent, (event?: Record<string, any>) => void>
|
|
@@ -123,11 +118,6 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
123
118
|
});
|
|
124
119
|
};
|
|
125
120
|
|
|
126
|
-
private cancelCheckPlayerPositionTimeout = () => {
|
|
127
|
-
clearTimeout(this.checkPlayerPositionTimeout);
|
|
128
|
-
this.checkPlayerPositionTimeout = null;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
121
|
public onViewportEnter = (item: LiveImage) => {
|
|
132
122
|
log_debug(
|
|
133
123
|
`onViewportEnter: live-image ${playerInfo(
|
|
@@ -135,21 +125,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
135
125
|
)}, primary ${playerInfo(this.primaryPlayer)}`
|
|
136
126
|
);
|
|
137
127
|
|
|
138
|
-
|
|
139
|
-
// mobile only
|
|
140
|
-
// we have to delay running checkPlayerPosition, because sometimes on fast scrolling we get wrong order onEnter, then onLeave.
|
|
141
|
-
// which could cause select wrong item to play
|
|
142
|
-
|
|
143
|
-
this.cancelCheckPlayerPositionTimeout();
|
|
144
|
-
|
|
145
|
-
this.checkPlayerPositionTimeout = setTimeout(() => {
|
|
146
|
-
this.cancelCheckPlayerPositionTimeout();
|
|
147
|
-
|
|
148
|
-
this.checkPlayerPosition(item);
|
|
149
|
-
}, TIMEOUT_FOR_DELAY_CHECK_PLAYER_POSITION);
|
|
150
|
-
} else {
|
|
151
|
-
this.checkPlayerPosition(item);
|
|
152
|
-
}
|
|
128
|
+
this.checkPlayerPosition(item);
|
|
153
129
|
};
|
|
154
130
|
|
|
155
131
|
public onViewportLeave = (item: LiveImage) => {
|
|
@@ -270,8 +246,6 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
270
246
|
};
|
|
271
247
|
|
|
272
248
|
public checkPlayerPosition = (item: LiveImage) => {
|
|
273
|
-
this.cancelCheckPlayerPositionTimeout();
|
|
274
|
-
|
|
275
249
|
log_debug(
|
|
276
250
|
`checkPlayerPosition: live-image playerId: ${playerInfo(
|
|
277
251
|
item.player
|
|
@@ -244,27 +244,25 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
244
244
|
}, [item.id]);
|
|
245
245
|
|
|
246
246
|
React.useEffect(() => {
|
|
247
|
-
if (
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const isPlayerRegistered = playerManager.isPlayerRegistered(playerId);
|
|
247
|
+
if (playerManager) {
|
|
248
|
+
const isPlayerRegistered = playerManager.isPlayerRegistered(playerId);
|
|
252
249
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
250
|
+
if (isPlayerRegistered) {
|
|
251
|
+
log_error(
|
|
252
|
+
`PlayerLiveImageComponent: player ${playerId} already registered`
|
|
253
|
+
);
|
|
254
|
+
} else {
|
|
255
|
+
playerManager.registerPlayer({
|
|
256
|
+
id: playerId,
|
|
257
|
+
playerController: controller,
|
|
258
|
+
});
|
|
262
259
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
260
|
+
return () => {
|
|
261
|
+
playerManager.unregisterPlayer(playerId);
|
|
262
|
+
};
|
|
263
|
+
}
|
|
266
264
|
}
|
|
267
|
-
}, [liveImageItem, playerId, controller
|
|
265
|
+
}, [liveImageItem, playerId, controller]);
|
|
268
266
|
|
|
269
267
|
const onPositionUpdated = React.useCallback(
|
|
270
268
|
(data) => {
|
|
@@ -4,7 +4,6 @@ import { render } from "@testing-library/react-native";
|
|
|
4
4
|
import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
|
|
5
5
|
import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
|
|
6
6
|
import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
7
|
-
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
8
7
|
|
|
9
8
|
import { PlayerLiveImage } from "../PlayerLiveImageComponent";
|
|
10
9
|
import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
@@ -33,7 +32,7 @@ const mockStore = configureStore();
|
|
|
33
32
|
|
|
34
33
|
const store = mockStore({ appData: {} });
|
|
35
34
|
|
|
36
|
-
const Wrapper = ({ children }: { children: React.
|
|
35
|
+
const Wrapper = ({ children }: { children: React.ReactChildren }) => (
|
|
37
36
|
/* @ts-ignore */
|
|
38
37
|
<Provider store={store}>
|
|
39
38
|
<ThemeContext.Provider
|
|
@@ -119,53 +118,4 @@ describe("PlayerLiveImageComponent", () => {
|
|
|
119
118
|
|
|
120
119
|
// TODO: implement this test
|
|
121
120
|
});
|
|
122
|
-
|
|
123
|
-
it("should register the player for normal item", () => {
|
|
124
|
-
render(
|
|
125
|
-
<Wrapper>
|
|
126
|
-
<PlayerLiveImage {...defaultProps} />
|
|
127
|
-
</Wrapper>
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const isPlayerRegistered = playerManager.isPlayerRegistered(
|
|
131
|
-
defaultProps.playerId
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
expect(isPlayerRegistered).toBe(true);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it("should unregister the player for normal item", () => {
|
|
138
|
-
const component = render(
|
|
139
|
-
<Wrapper>
|
|
140
|
-
<PlayerLiveImage {...defaultProps} />
|
|
141
|
-
</Wrapper>
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
component.unmount();
|
|
145
|
-
|
|
146
|
-
const isPlayerRegistered = playerManager.isPlayerRegistered(
|
|
147
|
-
defaultProps.playerId
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
expect(isPlayerRegistered).toBe(false);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("should not register the player for 'pre-measurement' item", () => {
|
|
154
|
-
const props = {
|
|
155
|
-
...defaultProps,
|
|
156
|
-
item: {
|
|
157
|
-
...defaultProps.item,
|
|
158
|
-
id: "pre-measurement-1",
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
render(
|
|
163
|
-
<Wrapper>
|
|
164
|
-
<PlayerLiveImage {...props} />
|
|
165
|
-
</Wrapper>
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
const isPlayerRegistered = playerManager.isPlayerRegistered(props.playerId);
|
|
169
|
-
expect(isPlayerRegistered).toBe(false);
|
|
170
|
-
});
|
|
171
121
|
});
|