@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5882013252 → 12.0.0-alpha.6254111934
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/Cell/Cell.tsx +2 -2
- package/Components/Cell/CellWithFocusable.tsx +21 -14
- package/Components/Cell/TvOSCellComponent.tsx +2 -2
- package/Components/ErrorScreen/index.tsx +1 -1
- package/Components/FocusableCell/index.tsx +7 -7
- 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 -6
- package/Components/Image/Image.android.tsx +3 -22
- package/Components/Image/Image.tsx +18 -2
- package/Components/Image/utils/index.ts +39 -0
- package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
- 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 +17 -2
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
- package/Components/MasterCell/utils/index.ts +16 -5
- 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/PlayerContainer.tsx +56 -29
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
- package/Components/PlayerImageBackground/index.tsx +34 -8
- 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/__tests__/componentsMap.test.js +7 -0
- 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 +48 -36
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +20 -6
- package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
- package/Components/Screen/index.tsx +92 -44
- package/Components/Screen/navigationHandler.ts +0 -82
- package/Components/Screen/orientationHandler.ts +1 -1
- package/Components/ScreenResolver/index.tsx +1 -1
- package/Components/Tabs/TV/styles.ts +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 +45 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +22 -27
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +335 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +144 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
- package/Components/VideoModal/PlayerDetails.tsx +3 -0
- package/Components/VideoModal/PlayerWrapper.tsx +119 -95
- package/Components/VideoModal/VideoModal.tsx +8 -25
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +8 -3
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +242 -166
- package/Components/VideoModal/hooks/useModalSize.ts +13 -4
- package/Components/VideoModal/utils.ts +3 -3
- 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/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
- package/Decorators/RiverResolver/index.tsx +0 -4
- package/Decorators/index.tsx +0 -4
- package/package.json +5 -6
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
|
@@ -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",
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -202,7 +202,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
202
202
|
groupId,
|
|
203
203
|
isFocusable = true,
|
|
204
204
|
skipFocusManagerRegistration,
|
|
205
|
-
behavior
|
|
205
|
+
behavior,
|
|
206
206
|
} = this.props;
|
|
207
207
|
|
|
208
208
|
const { id } = item;
|
|
@@ -263,7 +263,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
263
263
|
item,
|
|
264
264
|
focused: this.isCellFocused(focused),
|
|
265
265
|
scrollTo: this.scrollToIndex(event),
|
|
266
|
-
behavior
|
|
266
|
+
behavior,
|
|
267
267
|
}}
|
|
268
268
|
/>
|
|
269
269
|
);
|
|
@@ -35,18 +35,18 @@ const useCellFocusedState = (groupId: string, id: string) => {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
type Props = {
|
|
38
|
-
item: ZappEntry
|
|
39
|
-
CellRenderer: React.ComponentType<{ item: Object
|
|
40
|
-
id: string
|
|
41
|
-
groupId: string
|
|
42
|
-
onFocus: Function
|
|
43
|
-
index: number
|
|
44
|
-
scrollTo: Function
|
|
45
|
-
preferredFocus?: boolean
|
|
46
|
-
skipFocusManagerRegistration?: boolean
|
|
47
|
-
isFocusable?: boolean
|
|
48
|
-
behavior: Behavior
|
|
49
|
-
selected?: boolean
|
|
38
|
+
item: ZappEntry;
|
|
39
|
+
CellRenderer: React.ComponentType<{ item: Object; state: string }>;
|
|
40
|
+
id: string;
|
|
41
|
+
groupId: string;
|
|
42
|
+
onFocus: Function;
|
|
43
|
+
index: number;
|
|
44
|
+
scrollTo: Function;
|
|
45
|
+
preferredFocus?: boolean;
|
|
46
|
+
skipFocusManagerRegistration?: boolean;
|
|
47
|
+
isFocusable?: boolean;
|
|
48
|
+
behavior: Behavior;
|
|
49
|
+
selected?: boolean;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
export function CellWithFocusable(props: Props) {
|
|
@@ -62,11 +62,18 @@ export function CellWithFocusable(props: Props) {
|
|
|
62
62
|
skipFocusManagerRegistration,
|
|
63
63
|
isFocusable,
|
|
64
64
|
behavior,
|
|
65
|
-
selected
|
|
65
|
+
selected,
|
|
66
66
|
} = props;
|
|
67
67
|
|
|
68
68
|
const isFocused = useCellFocusedState(groupId, id);
|
|
69
|
-
|
|
69
|
+
|
|
70
|
+
const state = useCellState({
|
|
71
|
+
id: item.id,
|
|
72
|
+
behavior,
|
|
73
|
+
focused: isFocused,
|
|
74
|
+
selected,
|
|
75
|
+
});
|
|
76
|
+
|
|
70
77
|
const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
|
|
71
78
|
|
|
72
79
|
// for horizontal scrolling
|
|
@@ -249,7 +249,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
249
249
|
hasReceivedFocus,
|
|
250
250
|
groupId,
|
|
251
251
|
isFocusable,
|
|
252
|
-
behavior
|
|
252
|
+
behavior,
|
|
253
253
|
} = this.props;
|
|
254
254
|
|
|
255
255
|
const { id } = item;
|
|
@@ -310,7 +310,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
310
310
|
item,
|
|
311
311
|
focused: this.props.focused || selectedCell || focused,
|
|
312
312
|
scrollTo: this.scrollTo,
|
|
313
|
-
behavior
|
|
313
|
+
behavior,
|
|
314
314
|
}}
|
|
315
315
|
/>
|
|
316
316
|
);
|
|
@@ -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 = {
|
|
@@ -3,12 +3,12 @@ import { Platform } from "react-native";
|
|
|
3
3
|
import { useCellState } from "../MasterCell/utils";
|
|
4
4
|
|
|
5
5
|
type Props = {
|
|
6
|
-
index: number
|
|
7
|
-
item: ZappEntry
|
|
8
|
-
focused: boolean
|
|
9
|
-
scrollTo?: (index: number) => void
|
|
10
|
-
CellRenderer: React.ComponentType<{ item: Object
|
|
11
|
-
behavior: Behavior
|
|
6
|
+
index: number;
|
|
7
|
+
item: ZappEntry;
|
|
8
|
+
focused: boolean;
|
|
9
|
+
scrollTo?: (index: number) => void;
|
|
10
|
+
CellRenderer: React.ComponentType<{ item: Object; state: string }>;
|
|
11
|
+
behavior: Behavior;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
const isAndroid = Platform.OS === "android";
|
|
@@ -20,7 +20,7 @@ export function FocusableCell(props: Props) {
|
|
|
20
20
|
CellRenderer,
|
|
21
21
|
focused,
|
|
22
22
|
scrollTo = null,
|
|
23
|
-
behavior
|
|
23
|
+
behavior,
|
|
24
24
|
} = props;
|
|
25
25
|
|
|
26
26
|
const state = useCellState({ id: item.id, behavior, focused });
|
|
@@ -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 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator/";
|
|
4
|
-
import { HookRenderer as HookRendererComponent } from "./HookRenderer";
|
|
5
|
-
|
|
6
|
-
export const HookRenderer = R.compose(withNavigator)(HookRendererComponent);
|
|
1
|
+
export { HookRenderer } from "./HookRenderer";
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
3
2
|
import FastImage, {
|
|
4
3
|
FastImageProps,
|
|
5
4
|
} from "@applicaster/react-native-fast-image";
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
const source = React.useMemo(() => {
|
|
9
|
-
if (typeof props.source === "number") {
|
|
10
|
-
return props.source;
|
|
11
|
-
}
|
|
6
|
+
import { useImageSource } from "./utils";
|
|
12
7
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
headers: props.source.headers,
|
|
16
|
-
priority: props.source.priority,
|
|
17
|
-
cache: props.source.cache,
|
|
18
|
-
};
|
|
19
|
-
}, [
|
|
20
|
-
...(typeof props.source === "object"
|
|
21
|
-
? [
|
|
22
|
-
props.source?.uri,
|
|
23
|
-
props.source?.priority,
|
|
24
|
-
props.source?.cache,
|
|
25
|
-
props.source?.headers,
|
|
26
|
-
]
|
|
27
|
-
: []),
|
|
28
|
-
]);
|
|
8
|
+
export const QBImage = (props: FastImageProps) => {
|
|
9
|
+
const source = useImageSource(props.source);
|
|
29
10
|
|
|
30
11
|
return <FastImage {...props} source={source} />;
|
|
31
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
|
+
};
|