@applicaster/zapp-react-native-ui-components 12.0.0-rc.3 → 12.0.0-rc.31
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/AudioPlayer/AudioPlayer.tsx +9 -1
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
- package/Components/AudioPlayer/helpers.tsx +1 -0
- package/Components/ErrorScreen/index.tsx +1 -1
- package/Components/FocusableList/FocusableChild.ts +24 -14
- package/Components/FocusableList/FocusableItem.tsx +1 -1
- package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
- package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
- package/Components/FocusableList/index.tsx +26 -25
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
- package/Components/HandlePlayable/HandlePlayable.tsx +1 -1
- package/Components/HookRenderer/index.tsx +1 -4
- package/Components/Image/Image.android.tsx +11 -2
- package/Components/Image/Image.tsx +18 -2
- package/Components/Image/utils/index.ts +29 -0
- package/Components/Layout/TV/__tests__/index.test.tsx +0 -21
- package/Components/Layout/TV/index.tsx +20 -36
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
- package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +3 -1
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
- package/Components/MasterCell/utils/index.ts +2 -2
- package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
- package/Components/ModalComponent/Button/Item.tsx +82 -0
- package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
- package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
- package/Components/ModalComponent/Button/assets.ts +4 -0
- package/Components/ModalComponent/Button/index.tsx +111 -0
- package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
- package/Components/ModalComponent/Header/Title.tsx +70 -0
- package/Components/ModalComponent/Header/assets.ts +4 -0
- package/Components/ModalComponent/Header/index.tsx +71 -0
- package/Components/ModalComponent/Header/utils.ts +79 -0
- package/Components/ModalComponent/index.tsx +38 -0
- package/Components/ModalComponent/utils.ts +126 -0
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +4 -7
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +25 -0
- package/Components/River/River.tsx +8 -5
- package/Components/River/TV/River.tsx +2 -2
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
- package/Components/River/useScreenConfiguration.ts +5 -6
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
- package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
- package/Components/RouteManager/index.tsx +5 -3
- package/Components/Screen/__tests__/Screen.test.tsx +43 -35
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +10 -4
- package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
- package/Components/Screen/index.tsx +92 -46
- package/Components/Screen/navigationHandler.ts +0 -82
- package/Components/Screen/orientationHandler.ts +1 -1
- package/Components/ScreenResolver/index.tsx +1 -1
- package/Components/TrackedView/index.tsx +6 -3
- package/Components/VideoLive/LiveImageManager.ts +42 -13
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +25 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +22 -27
- package/Components/VideoModal/PlayerDetails.tsx +3 -0
- package/Components/VideoModal/PlayerWrapper.tsx +66 -63
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +4 -4
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +10 -18
- package/Components/VideoModal/hooks/useModalSize.ts +13 -4
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
- package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
- package/Components/ZappUIComponent/index.tsx +22 -12
- package/Components/index.js +2 -0
- package/Contexts/ScreenContext/index.tsx +1 -4
- package/Decorators/RiverResolver/index.tsx +0 -4
- package/Decorators/index.tsx +0 -4
- package/package.json +5 -6
|
@@ -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>
|
|
@@ -23,6 +23,7 @@ type Props = {
|
|
|
23
23
|
audio_player_summary_color?: string;
|
|
24
24
|
audio_player_rtl?: boolean;
|
|
25
25
|
magic_background?: boolean;
|
|
26
|
+
audio_player_background_image_query?: string;
|
|
26
27
|
start_time?: string;
|
|
27
28
|
end_time?: string;
|
|
28
29
|
};
|
|
@@ -33,6 +34,7 @@ type Props = {
|
|
|
33
34
|
audio_player_summary_color?: string;
|
|
34
35
|
audio_player_rtl?: string;
|
|
35
36
|
magic_background?: string;
|
|
37
|
+
audio_player_background_image_query?: string;
|
|
36
38
|
audio_player_background_image?: string;
|
|
37
39
|
audio_player_artwork_aspect_ratio?: string;
|
|
38
40
|
lg_tv_audio_player_title_font_family?: string;
|
|
@@ -73,6 +75,11 @@ export function AudioPlayer(props: Props) {
|
|
|
73
75
|
const channelIcon = getProp("audio_player_channel_icon");
|
|
74
76
|
const rtlFlag = getProp("audio_player_rtl");
|
|
75
77
|
const magicBackground = getProp("magic_background");
|
|
78
|
+
|
|
79
|
+
const audioPlayerBackgroundImageQuery = getProp(
|
|
80
|
+
"audio_player_background_image_query"
|
|
81
|
+
);
|
|
82
|
+
|
|
76
83
|
const isRTL = rtlFlag === "1" || rtlFlag === "true" || rtlFlag === true;
|
|
77
84
|
|
|
78
85
|
const titleFontFamily = getProp(
|
|
@@ -149,7 +156,8 @@ export function AudioPlayer(props: Props) {
|
|
|
149
156
|
runTimeFontSize,
|
|
150
157
|
artworkAspectRatio,
|
|
151
158
|
channelIcon,
|
|
152
|
-
magicBackground
|
|
159
|
+
magicBackground,
|
|
160
|
+
audioPlayerBackgroundImageQuery,
|
|
153
161
|
};
|
|
154
162
|
}, [getProp]);
|
|
155
163
|
|
|
@@ -5,6 +5,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
5
5
|
config={
|
|
6
6
|
Object {
|
|
7
7
|
"artworkAspectRatio": "1:1",
|
|
8
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
8
9
|
"backgroundColor": "black",
|
|
9
10
|
"backgroundImage": "https://example.com",
|
|
10
11
|
"channelIcon": "https://example.com",
|
|
@@ -26,6 +27,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
26
27
|
config={
|
|
27
28
|
Object {
|
|
28
29
|
"artworkAspectRatio": "1:1",
|
|
30
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
29
31
|
"backgroundColor": "black",
|
|
30
32
|
"backgroundImage": "https://example.com",
|
|
31
33
|
"channelIcon": "https://example.com",
|
|
@@ -47,6 +49,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
47
49
|
config={
|
|
48
50
|
Object {
|
|
49
51
|
"artworkAspectRatio": "1:1",
|
|
52
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
50
53
|
"backgroundColor": "black",
|
|
51
54
|
"backgroundImage": "https://example.com",
|
|
52
55
|
"channelIcon": "https://example.com",
|
|
@@ -68,6 +71,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
68
71
|
config={
|
|
69
72
|
Object {
|
|
70
73
|
"artworkAspectRatio": "1:1",
|
|
74
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
71
75
|
"backgroundColor": "black",
|
|
72
76
|
"backgroundImage": "https://example.com",
|
|
73
77
|
"channelIcon": "https://example.com",
|
|
@@ -96,6 +100,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
96
100
|
config={
|
|
97
101
|
Object {
|
|
98
102
|
"artworkAspectRatio": "1:1",
|
|
103
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
99
104
|
"backgroundColor": "black",
|
|
100
105
|
"backgroundImage": "https://example.com",
|
|
101
106
|
"channelIcon": "https://example.com",
|
|
@@ -3,7 +3,6 @@ import * as R from "ramda";
|
|
|
3
3
|
import {
|
|
4
4
|
View,
|
|
5
5
|
StyleSheet,
|
|
6
|
-
Image,
|
|
7
6
|
Text,
|
|
8
7
|
ViewStyle,
|
|
9
8
|
TextStyle,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
import { defaultAsset } from "./defaultAsset";
|
|
14
13
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
15
14
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
15
|
+
import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
|
|
16
16
|
import { Button } from "./Button";
|
|
17
17
|
|
|
18
18
|
type ButtonProp = {
|
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { isEqual } from "@applicaster/zapp-react-native-utils/equalUtils";
|
|
3
|
-
import {
|
|
3
|
+
import { useFocusable } from "../Focusable/index.android";
|
|
4
4
|
import { useCellState } from "./hooks/useCellState.android";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const nextFocusLeft = props.nextFocusLeft ?? context.nextFocusLeft;
|
|
15
|
-
|
|
16
|
-
const parentFocus = React.useMemo(
|
|
6
|
+
/**
|
|
7
|
+
* returns parent focus from prop or from context
|
|
8
|
+
* */
|
|
9
|
+
const useParentFocus = (
|
|
10
|
+
{ nextFocusDown, nextFocusUp, nextFocusRight, nextFocusLeft },
|
|
11
|
+
context
|
|
12
|
+
) =>
|
|
13
|
+
React.useMemo(
|
|
17
14
|
() => ({
|
|
15
|
+
nextFocusRight: nextFocusRight ?? context.nextFocusRight,
|
|
16
|
+
nextFocusDown: nextFocusDown ?? context.nextFocusDown,
|
|
17
|
+
nextFocusLeft: nextFocusLeft ?? context.nextFocusLeft,
|
|
18
|
+
nextFocusUp: nextFocusUp ?? context.nextFocusUp,
|
|
19
|
+
}),
|
|
20
|
+
[
|
|
18
21
|
nextFocusRight,
|
|
19
22
|
nextFocusDown,
|
|
20
23
|
nextFocusLeft,
|
|
21
24
|
nextFocusUp,
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
context.nextFocusLeft,
|
|
26
|
+
context.nextFocusRight,
|
|
27
|
+
context.nextFocusUp,
|
|
28
|
+
context.nextFocusDown,
|
|
29
|
+
]
|
|
24
30
|
);
|
|
25
31
|
|
|
32
|
+
function FocusableChildComponent(props) {
|
|
33
|
+
const { setIsFocusable, ...focusableContext } = useFocusable();
|
|
34
|
+
const parentFocus = useParentFocus(props, focusableContext);
|
|
35
|
+
|
|
26
36
|
const onLoadFailed = React.useCallback(() => {
|
|
27
37
|
setIsFocusable(false);
|
|
28
38
|
}, []);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { Focusable } from "../Focusable";
|
|
2
|
+
import { Focusable } from "../Focusable/index.android";
|
|
3
3
|
import { FocusableChild } from "./FocusableChild";
|
|
4
4
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
5
5
|
import { IListRenderItem } from "./index";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ListRenderItemInfo as IListRenderItemInfo } from "react-native";
|
|
3
|
+
import { FocusableItem } from "./FocusableItem";
|
|
4
|
+
|
|
5
|
+
export type IListRenderItem<ItemT> = (
|
|
6
|
+
info: IListRenderItemInfo<ItemT> & {
|
|
7
|
+
focused: boolean;
|
|
8
|
+
onLoadFinished: () => void;
|
|
9
|
+
onLoadFailed: () => void;
|
|
10
|
+
}
|
|
11
|
+
) => React.ReactElement | null;
|
|
12
|
+
|
|
13
|
+
type Item = ZappEntry | ZappUIComponent | any;
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
item: Item;
|
|
17
|
+
onFocus: (
|
|
18
|
+
element: FocusManager.FocusableRef,
|
|
19
|
+
renderArgs: { item: Item; index: number },
|
|
20
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
21
|
+
) => void;
|
|
22
|
+
onListElementBlur?: (any, RenderItemProps, Direction) => void;
|
|
23
|
+
onListElementPress?: (any, RenderItemProps) => void;
|
|
24
|
+
onListElementLongPress?: (any, RenderItemProps) => void;
|
|
25
|
+
onListElementPressOut?: (any, RenderItemProps) => void;
|
|
26
|
+
focusableItemProps: any;
|
|
27
|
+
id: string;
|
|
28
|
+
index: number;
|
|
29
|
+
extraData: any;
|
|
30
|
+
extraChildrenData: any;
|
|
31
|
+
renderItem: IListRenderItem<any> | null | undefined;
|
|
32
|
+
getNextFocus: (index: number) => ParentFocus;
|
|
33
|
+
} & ParentFocus;
|
|
34
|
+
|
|
35
|
+
export const FocusableListItemWrapper = React.memo(
|
|
36
|
+
({
|
|
37
|
+
onFocus,
|
|
38
|
+
onListElementBlur,
|
|
39
|
+
onListElementPress,
|
|
40
|
+
onListElementLongPress,
|
|
41
|
+
onListElementPressOut,
|
|
42
|
+
focusableItemProps,
|
|
43
|
+
id,
|
|
44
|
+
getNextFocus,
|
|
45
|
+
item,
|
|
46
|
+
index,
|
|
47
|
+
extraData,
|
|
48
|
+
extraChildrenData,
|
|
49
|
+
renderItem,
|
|
50
|
+
}: Props) => {
|
|
51
|
+
const nextFocus = getNextFocus(index);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<FocusableItem
|
|
55
|
+
nextFocusDown={nextFocus.nextFocusDown}
|
|
56
|
+
nextFocusRight={nextFocus.nextFocusRight}
|
|
57
|
+
nextFocusLeft={nextFocus.nextFocusLeft}
|
|
58
|
+
nextFocusUp={nextFocus.nextFocusUp}
|
|
59
|
+
id={id}
|
|
60
|
+
focusableItemProps={focusableItemProps}
|
|
61
|
+
onFocus={onFocus}
|
|
62
|
+
item={item}
|
|
63
|
+
index={index}
|
|
64
|
+
renderItem={renderItem}
|
|
65
|
+
extraChildrenData={extraChildrenData}
|
|
66
|
+
extraData={extraData}
|
|
67
|
+
onListElementBlur={onListElementBlur}
|
|
68
|
+
onListElementPress={onListElementPress}
|
|
69
|
+
onListElementLongPress={onListElementLongPress}
|
|
70
|
+
onListElementPressOut={onListElementPressOut}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
FocusableListItemWrapper.displayName = "FocusableListItemWrapper";
|
|
@@ -5,7 +5,9 @@ import { useFocusManager } from "@applicaster/zapp-react-native-utils/focusManag
|
|
|
5
5
|
export const useCellState = (id: string) => {
|
|
6
6
|
const focusManager = useFocusManager();
|
|
7
7
|
|
|
8
|
-
const [currentCellFocused, setCurrentCellFocused] = React.useState(
|
|
8
|
+
const [currentCellFocused, setCurrentCellFocused] = React.useState(
|
|
9
|
+
focusManager.isFocused(id)
|
|
10
|
+
);
|
|
9
11
|
|
|
10
12
|
React.useEffect(() => {
|
|
11
13
|
const handler = (focusable) => {
|
|
@@ -12,8 +12,9 @@ import { ChildrenFocusDeactivatorView } from "../ChildrenFocusDeactivatorView";
|
|
|
12
12
|
import { useInitialFocus } from "@applicaster/zapp-react-native-utils/focusManager";
|
|
13
13
|
|
|
14
14
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
import { useParentFocus, useCheckItemIdsForUnique } from "./hooks";
|
|
17
|
+
import { FocusableListItemWrapper } from "./FocusableListItemWrapper";
|
|
17
18
|
|
|
18
19
|
const mapIndexed = R.addIndex(R.map);
|
|
19
20
|
|
|
@@ -74,6 +75,8 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
74
75
|
nextFocusLeft: parentNextFocusLeft,
|
|
75
76
|
nextFocusUp: parentNextFocusUp,
|
|
76
77
|
|
|
78
|
+
numColumns,
|
|
79
|
+
|
|
77
80
|
focused: parentFocused,
|
|
78
81
|
|
|
79
82
|
focusableItemProps,
|
|
@@ -103,8 +106,8 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
103
106
|
});
|
|
104
107
|
|
|
105
108
|
const getFocusableEntryId = React.useCallback(
|
|
106
|
-
(_entry: ZappEntry, index?: number) => {
|
|
107
|
-
const entry = R.isNil(index) ? _entry : data[index];
|
|
109
|
+
(_entry: ZappEntry | null, index?: number) => {
|
|
110
|
+
const entry = R.isNil(index) ? _entry : data[index as number];
|
|
108
111
|
|
|
109
112
|
return entry ? getFocusableId(props.id, index) : undefined;
|
|
110
113
|
},
|
|
@@ -143,7 +146,6 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
143
146
|
const getNextFocus = React.useCallback(
|
|
144
147
|
(index) => {
|
|
145
148
|
const itemCount = R.length(data);
|
|
146
|
-
const { numColumns } = props;
|
|
147
149
|
|
|
148
150
|
const getFocusableEntryIdForIndex = (entryIndex) =>
|
|
149
151
|
getFocusableEntryId(null, entryIndex);
|
|
@@ -160,22 +162,23 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
160
162
|
});
|
|
161
163
|
|
|
162
164
|
const getGridFocus = () => {
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
+
const _numColumns = toFiniteNumberWithDefault(1, numColumns);
|
|
166
|
+
const numberOfRows = Math.ceil(itemCount / _numColumns);
|
|
167
|
+
const currentRowIndex = Math.floor(index / _numColumns);
|
|
165
168
|
const isFirstRow = currentRowIndex === 0;
|
|
166
169
|
const isLastRow = currentRowIndex + 1 === numberOfRows;
|
|
167
|
-
const isLeftEdge = index %
|
|
170
|
+
const isLeftEdge = index % _numColumns === 0;
|
|
168
171
|
|
|
169
172
|
const isRightEdge =
|
|
170
|
-
(index + 1) %
|
|
173
|
+
(index + 1) % _numColumns === 0 || itemCount === index + 1;
|
|
171
174
|
|
|
172
175
|
return {
|
|
173
176
|
nextFocusUp: isFirstRow
|
|
174
177
|
? nextFocusUp
|
|
175
|
-
: getFocusableEntryIdForIndex(index -
|
|
178
|
+
: getFocusableEntryIdForIndex(index - _numColumns),
|
|
176
179
|
nextFocusDown: isLastRow
|
|
177
180
|
? nextFocusDown
|
|
178
|
-
: getFocusableEntryIdForIndex(index +
|
|
181
|
+
: getFocusableEntryIdForIndex(index + _numColumns),
|
|
179
182
|
nextFocusLeft: isLeftEdge
|
|
180
183
|
? nextFocusLeft
|
|
181
184
|
: getFocusableEntryIdForIndex(index - 1),
|
|
@@ -215,26 +218,24 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
215
218
|
const renderItem = React.useCallback(
|
|
216
219
|
({ item, index }) => {
|
|
217
220
|
const id = getFocusableId(props.id, index);
|
|
218
|
-
const nextFocus = getNextFocus(index);
|
|
219
221
|
|
|
220
222
|
return (
|
|
221
|
-
<
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
223
|
+
<FocusableListItemWrapper
|
|
224
|
+
{...{
|
|
225
|
+
onFocus,
|
|
226
|
+
onListElementBlur,
|
|
227
|
+
onListElementPress,
|
|
228
|
+
onListElementLongPress,
|
|
229
|
+
onListElementPressOut,
|
|
230
|
+
}}
|
|
231
|
+
renderItem={props.renderItem}
|
|
227
232
|
focusableItemProps={focusableItemProps}
|
|
228
|
-
|
|
233
|
+
getNextFocus={getNextFocus}
|
|
234
|
+
id={id}
|
|
229
235
|
item={item}
|
|
230
236
|
index={index}
|
|
231
|
-
renderItem={props.renderItem}
|
|
232
|
-
extraChildrenData={props.extraChildrenData}
|
|
233
237
|
extraData={props.extraData}
|
|
234
|
-
|
|
235
|
-
onListElementPress={onListElementPress}
|
|
236
|
-
onListElementLongPress={onListElementLongPress}
|
|
237
|
-
onListElementPressOut={onListElementPressOut}
|
|
238
|
+
extraChildrenData={props.extraChildrenData}
|
|
238
239
|
/>
|
|
239
240
|
);
|
|
240
241
|
},
|
|
@@ -287,7 +288,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
287
288
|
);
|
|
288
289
|
|
|
289
290
|
const initialNumToRender = toFiniteNumberWithDefault(
|
|
290
|
-
|
|
291
|
+
10,
|
|
291
292
|
flatListProps.initialNumToRender
|
|
292
293
|
);
|
|
293
294
|
|
|
@@ -52,13 +52,13 @@ export const GeneralContentScreen = ({
|
|
|
52
52
|
React.useState(actionsInitialStateSetters.length === 0);
|
|
53
53
|
|
|
54
54
|
useEffect(() => {
|
|
55
|
-
log_info(
|
|
56
|
-
`ScreenContainer: starting to check river action provider ready, current status: ${riverActionProvidersReady}`,
|
|
57
|
-
{ actionsInitialStateSetters }
|
|
58
|
-
);
|
|
59
|
-
|
|
60
55
|
if (!riverActionProvidersReady) {
|
|
61
56
|
if (actionsInitialStateSetters.length > 0) {
|
|
57
|
+
log_info(
|
|
58
|
+
"ScreenContainer: starting to check river action providers to initialize",
|
|
59
|
+
{ actionsInitialStateSetters }
|
|
60
|
+
);
|
|
61
|
+
|
|
62
62
|
allSettled(actionsInitialStateSetters).finally(() => {
|
|
63
63
|
log_info(
|
|
64
64
|
"ScreenContainer: action provider ready, completed. Starting to present screen"
|
|
@@ -98,13 +98,16 @@ export const GeneralContentScreen = ({
|
|
|
98
98
|
|
|
99
99
|
const isReady = useRiverActionProviderReady();
|
|
100
100
|
|
|
101
|
+
const contextValue = React.useMemo(
|
|
102
|
+
() => whenMatchingType(Function, cellTapAction) || onCellTapAction,
|
|
103
|
+
[typeof cellTapAction === "function" ? cellTapAction : onCellTapAction]
|
|
104
|
+
);
|
|
105
|
+
|
|
101
106
|
if (!isReady || isNilOrEmpty(components || uiComponents)) return null;
|
|
102
107
|
|
|
103
108
|
return (
|
|
104
109
|
<ScreenTrackedViewPositionsContext.Provider>
|
|
105
|
-
<CellTapContext.Provider
|
|
106
|
-
value={whenMatchingType(Function, cellTapAction) || onCellTapAction}
|
|
107
|
-
>
|
|
110
|
+
<CellTapContext.Provider value={contextValue}>
|
|
108
111
|
<ComponentsMap
|
|
109
112
|
feed={feed}
|
|
110
113
|
riverId={screenId}
|
|
@@ -104,7 +104,7 @@ export function HandlePlayable({
|
|
|
104
104
|
const [Player, playerModuleProperties] = getPlayer(item, state);
|
|
105
105
|
|
|
106
106
|
const { module: CastPlugin } =
|
|
107
|
-
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins) || {};
|
|
107
|
+
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
|
|
108
108
|
|
|
109
109
|
const [playable, setPlayable] =
|
|
110
110
|
React.useState<Nullable<PlayableComponent>>(null);
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import * as R from "ramda";
|
|
2
|
-
|
|
3
|
-
import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator/";
|
|
4
1
|
import { HookRenderer as HookRendererComponent } from "./HookRenderer";
|
|
5
2
|
|
|
6
|
-
export const HookRenderer =
|
|
3
|
+
export const HookRenderer = HookRendererComponent;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from "react";
|
|
2
|
+
import FastImage, {
|
|
3
|
+
FastImageProps,
|
|
4
|
+
} from "@applicaster/react-native-fast-image";
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
import { useImageSource } from "./utils";
|
|
7
|
+
|
|
8
|
+
export const QBImage = (props: FastImageProps) => {
|
|
9
|
+
const source = useImageSource(props.source);
|
|
10
|
+
|
|
11
|
+
return <FastImage {...props} source={source} />;
|
|
12
|
+
};
|
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
ImageBackground,
|
|
5
|
+
ImageProps,
|
|
6
|
+
ImageStyle,
|
|
7
|
+
StyleProp,
|
|
8
|
+
} from "react-native";
|
|
2
9
|
|
|
3
10
|
export interface Props extends ImageProps {
|
|
4
11
|
style?: StyleProp<ImageStyle> | undefined;
|
|
5
12
|
}
|
|
6
13
|
|
|
7
14
|
// TODO - React.FC<Props> QBImage should process incoming url and apply any transformations if needed
|
|
8
|
-
export const QBImage =
|
|
15
|
+
export const QBImage = ({
|
|
16
|
+
children,
|
|
17
|
+
...props
|
|
18
|
+
}: Props & { children?: React.ReactNode }) => {
|
|
19
|
+
if (children) {
|
|
20
|
+
return <ImageBackground {...props}>{children}</ImageBackground>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return <Image {...props} />;
|
|
24
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
export const useImageSource = (source) => {
|
|
4
|
+
return useMemo(() => {
|
|
5
|
+
if (typeof source === "number") {
|
|
6
|
+
return source;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
uri: source.uri,
|
|
11
|
+
headers: source.headers,
|
|
12
|
+
priority: source.priority,
|
|
13
|
+
cache: source.cache,
|
|
14
|
+
maxWidth: source.maxWidth,
|
|
15
|
+
maxHeight: source.maxHeight,
|
|
16
|
+
};
|
|
17
|
+
}, [
|
|
18
|
+
...(typeof source === "object"
|
|
19
|
+
? [
|
|
20
|
+
source?.uri,
|
|
21
|
+
source?.priority,
|
|
22
|
+
source?.cache,
|
|
23
|
+
source?.headers,
|
|
24
|
+
source?.maxWidth,
|
|
25
|
+
source?.maxHeight,
|
|
26
|
+
]
|
|
27
|
+
: []),
|
|
28
|
+
]);
|
|
29
|
+
};
|
|
@@ -125,25 +125,4 @@ describe("Layout TV", () => {
|
|
|
125
125
|
expect(bgComponent.props.testProp).toBe(true);
|
|
126
126
|
});
|
|
127
127
|
});
|
|
128
|
-
|
|
129
|
-
describe("props passed to navbar component", () => {
|
|
130
|
-
it("passes correct props", () => {
|
|
131
|
-
const { getByTestId } = render(
|
|
132
|
-
<Layout
|
|
133
|
-
Components={Components}
|
|
134
|
-
ComponentsExtraProps={{
|
|
135
|
-
NavBar: { testProp: true },
|
|
136
|
-
}}
|
|
137
|
-
>
|
|
138
|
-
<Screen />
|
|
139
|
-
</Layout>,
|
|
140
|
-
{ wrapper }
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
const navbarComponent = getByTestId("nav-bar-component");
|
|
144
|
-
expect(navbarComponent.props.isVisible).toBe(isNavBarVisible);
|
|
145
|
-
expect(navbarComponent.props.menuPlugin).toBe(plugins[0]);
|
|
146
|
-
expect(navbarComponent.props.testProp).toBe(true);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
128
|
});
|