@applicaster/zapp-react-native-ui-components 12.0.0-alpha.3977160850 → 12.0.0-alpha.4337072244
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/BaseFocusable/index.tsx +1 -1
- package/Components/Cell/Cell.tsx +7 -7
- package/Components/Cell/CellWithFocusable.tsx +38 -19
- package/Components/Cell/TvOSCellComponent.tsx +2 -2
- package/Components/ErrorScreen/index.tsx +1 -1
- package/Components/FocusableCell/index.tsx +7 -7
- package/Components/FocusableGroup/index.tsx +1 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/HookRenderer/index.tsx +1 -3
- package/Components/Image/Image.android.tsx +3 -25
- package/Components/Image/Image.tsx +18 -2
- package/Components/Image/utils/index.ts +39 -0
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -10
- package/Components/Layout/TV/__tests__/index.test.tsx +18 -86
- package/Components/Layout/TV/index.tsx +43 -102
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +4 -1
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -3
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
- package/Components/MasterCell/utils/index.ts +18 -7
- package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +64 -31
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
- package/Components/PlayerImageBackground/index.tsx +34 -8
- package/Components/River/ComponentsMap/ComponentsMap.tsx +86 -22
- package/Components/River/RefreshControl.tsx +55 -1
- package/Components/River/TV/River.tsx +0 -23
- package/Components/River/__tests__/componentsMap.test.js +7 -0
- package/Components/RouteManager/index.tsx +2 -2
- package/Components/Screen/TV/hooks/index.ts +3 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +67 -0
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
- package/Components/Screen/TV/index.web.tsx +174 -0
- package/Components/Screen/__tests__/Screen.test.tsx +5 -1
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +14 -0
- package/Components/Screen/index.tsx +48 -28
- package/Components/ScreenResolver/index.tsx +3 -1
- package/Components/Tabs/TV/styles.ts +1 -1
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -28
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
- package/Components/VideoModal/PlayerWrapper.tsx +66 -43
- package/Components/VideoModal/VideoModal.tsx +25 -42
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +6 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
- package/Components/VideoModal/utils.ts +3 -3
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +1 -1
- package/Components/Viewport/ViewportTracker/index.tsx +1 -0
- package/Components/Viewport/utils.js +1 -1
- package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
- package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
- package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
- package/Contexts/ScreenContext/index.tsx +94 -25
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
- package/events/index.ts +1 -0
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
- /package/Contexts/{index.js → index.ts} +0 -0
|
@@ -1,128 +1,69 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import { isEmpty, pathOr } from "ramda";
|
|
3
3
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
4
4
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
getNavigationProps,
|
|
9
|
-
resolveNavigationPlugin,
|
|
10
|
-
routeIsPlayerScreen,
|
|
11
|
-
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
12
|
-
|
|
13
|
-
import { getBackgroundImageUrl } from "../utils";
|
|
14
|
-
import { LayoutContainer } from "./LayoutContainer";
|
|
15
|
-
import { NavBarContainer } from "./NavBarContainer";
|
|
16
|
-
import { ScreenContainer } from "./ScreenContainer";
|
|
17
|
-
import { TransitionOverlay } from "./TransitionOverlay";
|
|
5
|
+
import { getPathAttributes } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
18
6
|
|
|
19
7
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
20
|
-
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
21
8
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
22
|
-
import {
|
|
9
|
+
import { FocusableGroup } from "../../FocusableGroup";
|
|
10
|
+
import { Screen } from "../../Screen/TV/index.web";
|
|
11
|
+
|
|
12
|
+
export const ScreenDataContext = React.createContext(null);
|
|
23
13
|
|
|
24
14
|
type Components = {
|
|
25
15
|
NavBar: React.ComponentType<any>;
|
|
26
16
|
Background: React.ComponentType<any>;
|
|
27
17
|
};
|
|
28
18
|
|
|
29
|
-
type ComponentsExtraProps = {
|
|
30
|
-
Background?: Record<string, any>;
|
|
31
|
-
NavBar?: Record<string, any>;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
19
|
type Props = {
|
|
35
20
|
Components: Components;
|
|
36
|
-
ComponentsExtraProps?: ComponentsExtraProps;
|
|
37
|
-
children: React.ReactNode;
|
|
38
21
|
};
|
|
39
22
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}) as QuickBrickPlugin,
|
|
72
|
-
[]
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const NavBar = React.useMemo(
|
|
76
|
-
() => Components.NavBar || (menuPlugin.module as React.ComponentType<any>),
|
|
77
|
-
[]
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const [navBarReady, setNavBarReady] = React.useState(false);
|
|
81
|
-
|
|
82
|
-
const navBarContainer = (
|
|
83
|
-
<NavBarContainer isVisible={visible} onReady={setNavBarReady}>
|
|
84
|
-
<NavBar
|
|
85
|
-
ref={ComponentsExtraProps?.NavBar?.ref}
|
|
86
|
-
isVisible={visible && !routeIsPlayerScreen(currentRoute)}
|
|
87
|
-
menuPlugin={menuPlugin}
|
|
88
|
-
navigationProps={navigationProps}
|
|
89
|
-
{...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
|
|
90
|
-
/>
|
|
91
|
-
</NavBarContainer>
|
|
92
|
-
);
|
|
23
|
+
const StackNavigator = ({ Components }: Props) => {
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
const { mainStack, currentRoute } = useNavigation();
|
|
26
|
+
|
|
27
|
+
const renderScreen = ({ route, state }) => {
|
|
28
|
+
const pathAttributes = getPathAttributes({ pathname: route });
|
|
29
|
+
|
|
30
|
+
if (isEmpty(pathAttributes)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const id = `${route}`;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<FocusableGroup
|
|
38
|
+
id={id}
|
|
39
|
+
preferredFocus={route === currentRoute}
|
|
40
|
+
excludeFromFocusSearching
|
|
41
|
+
key={id}
|
|
42
|
+
>
|
|
43
|
+
<ScreenDataContext.Provider value={state}>
|
|
44
|
+
<PathnameContext.Provider value={route}>
|
|
45
|
+
<Screen route={route} Components={Components} />
|
|
46
|
+
</PathnameContext.Provider>
|
|
47
|
+
</ScreenDataContext.Provider>
|
|
48
|
+
</FocusableGroup>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return mainStack.map(renderScreen);
|
|
53
|
+
};
|
|
93
54
|
|
|
94
|
-
|
|
55
|
+
const Layout = ({ Components }: Props) => {
|
|
56
|
+
const { appState } = usePickFromState(["appState"]);
|
|
57
|
+
const appReady = pathOr(false, ["appReady"], appState);
|
|
95
58
|
|
|
96
59
|
if (!appReady) {
|
|
97
60
|
return null;
|
|
98
61
|
}
|
|
99
62
|
|
|
100
63
|
return (
|
|
101
|
-
<
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
backgroundColor={backgroundColor}
|
|
105
|
-
backgroundImageUrl={backgroundImageUrl}
|
|
106
|
-
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
107
|
-
>
|
|
108
|
-
{!isTVOS ? navBarContainer : null}
|
|
109
|
-
{navBarReady ? (
|
|
110
|
-
/**
|
|
111
|
-
Need to re-mount this component on each navigation event
|
|
112
|
-
It's a hack to work around the fact that we don't support
|
|
113
|
-
correct screen rendering in our navigator (shared currentRoute state)
|
|
114
|
-
**/
|
|
115
|
-
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
116
|
-
<ScreenContainer>{children}</ScreenContainer>
|
|
117
|
-
</PathnameContext.Provider>
|
|
118
|
-
) : null}
|
|
119
|
-
{/** Render NavBarContainer over ScreenContainer to let tvOS native
|
|
120
|
-
focus manager works correctly to focus nav bar items first **/}
|
|
121
|
-
{!isTVOS ? navBarContainer : null}
|
|
122
|
-
<TransitionOverlay />
|
|
123
|
-
</Components.Background>
|
|
124
|
-
</ScreenLayoutContextProvider>
|
|
125
|
-
</LayoutContainer>
|
|
64
|
+
<ScreenLayoutContextProvider>
|
|
65
|
+
<StackNavigator Components={Components} />
|
|
66
|
+
</ScreenLayoutContextProvider>
|
|
126
67
|
);
|
|
127
68
|
};
|
|
128
69
|
|
|
@@ -25,6 +25,7 @@ type Props = {
|
|
|
25
25
|
testID?: string;
|
|
26
26
|
accessibilityLabel?: string;
|
|
27
27
|
cellUUID?: string;
|
|
28
|
+
extraProps?: Record<string, any>;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
function isStringAsset(asset) {
|
|
@@ -108,6 +109,7 @@ export function ActionButton(props: Props) {
|
|
|
108
109
|
flavour={flavour}
|
|
109
110
|
asset={getAssetValue(asset, flavour)}
|
|
110
111
|
cellUUID={cellUUID}
|
|
112
|
+
{...(props?.extraProps ?? {})}
|
|
111
113
|
/>
|
|
112
114
|
)}
|
|
113
115
|
</TouchableOpacity>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { ImageStyle, View } from "react-native";
|
|
3
3
|
import * as R from "ramda";
|
|
4
|
-
import
|
|
4
|
+
import { QBImage } from "@applicaster/zapp-react-native-ui-components/Components/Image";
|
|
5
5
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
6
|
-
import { toFiniteNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
7
6
|
|
|
8
7
|
import { useImageSourceWithDefault, useCheckFailedUri } from "./hooks";
|
|
8
|
+
import useImageSize from "./hooks/useImageSize";
|
|
9
9
|
|
|
10
10
|
type Source = {
|
|
11
11
|
uri: string;
|
|
@@ -19,32 +19,13 @@ type Props = Record<string, any> & {
|
|
|
19
19
|
withDimensions: (source: Source) => Source;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
const MemoizedImage = React.memo(
|
|
23
|
-
|
|
24
|
-
const normalize = Math.ceil;
|
|
22
|
+
const MemoizedImage = React.memo(QBImage, R.equals);
|
|
25
23
|
|
|
26
24
|
const isValidExternalSource = (source): boolean =>
|
|
27
25
|
source?.uri?.startsWith("http") ||
|
|
28
26
|
source?.uri?.startsWith("data:image") ||
|
|
29
27
|
source?.uri?.startsWith("file://");
|
|
30
28
|
|
|
31
|
-
const isValidSize = (size: unknown): boolean =>
|
|
32
|
-
toFiniteNumberWithDefault(0, size) > 0;
|
|
33
|
-
|
|
34
|
-
const getSourceWithMaxSizes = (applyMaxSize, style, source) => {
|
|
35
|
-
const { width, height } = style;
|
|
36
|
-
|
|
37
|
-
if (!applyMaxSize || !isValidSize(width) || !isValidSize(height)) {
|
|
38
|
-
return source;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
...source,
|
|
43
|
-
maxWidth: normalize(width),
|
|
44
|
-
maxHeight: normalize(height),
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
|
|
48
29
|
export default function Image({
|
|
49
30
|
style,
|
|
50
31
|
uri,
|
|
@@ -82,10 +63,12 @@ export default function Image({
|
|
|
82
63
|
|
|
83
64
|
const applyMaxSize = toBooleanWithDefaultFalse(otherProps?.applyMaxSize);
|
|
84
65
|
|
|
85
|
-
const sourceWithMaxSizes =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
66
|
+
const sourceWithMaxSizes = useImageSize({
|
|
67
|
+
style,
|
|
68
|
+
applyMaxSize,
|
|
69
|
+
source,
|
|
70
|
+
withDimensions,
|
|
71
|
+
});
|
|
89
72
|
|
|
90
73
|
if (isFailedToLoadUri(uri) || !isValidExternalSource(source)) {
|
|
91
74
|
return <View style={style} />;
|
|
@@ -43,14 +43,16 @@ function Image({
|
|
|
43
43
|
[source, error]
|
|
44
44
|
);
|
|
45
45
|
|
|
46
|
+
const _source = shouldRenderImg
|
|
47
|
+
? withDimensions(source)
|
|
48
|
+
: defaultPlaceHolderImage;
|
|
49
|
+
|
|
46
50
|
return (
|
|
47
51
|
// @ts-ignore
|
|
48
52
|
<MemoizedImage
|
|
49
53
|
style={style as ImageStyle}
|
|
50
54
|
onError={() => setErrorState(true)}
|
|
51
|
-
source={
|
|
52
|
-
shouldRenderImg ? withDimensions(source) : defaultPlaceHolderImage
|
|
53
|
-
}
|
|
55
|
+
source={_source?.uri ? _source : undefined}
|
|
54
56
|
{...R.omit(["source"], otherProps)}
|
|
55
57
|
/>
|
|
56
58
|
);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ImageStyle } from "react-native";
|
|
3
|
+
import { toFiniteNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
4
|
+
|
|
5
|
+
type Source = {
|
|
6
|
+
uri: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type Props = Record<string, any> & {
|
|
10
|
+
style: ImageStyle;
|
|
11
|
+
uri?: string;
|
|
12
|
+
placeholderImage?: string;
|
|
13
|
+
entry?: ZappEntry | ZappFeed;
|
|
14
|
+
withDimensions: (source: Source) => Source;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const normalize = Math.ceil;
|
|
18
|
+
|
|
19
|
+
const isValidSize = (size: unknown): boolean =>
|
|
20
|
+
toFiniteNumberWithDefault(0, size) > 0;
|
|
21
|
+
|
|
22
|
+
type WidthDimensions = { aspectRatio?: number; width: number; height?: number };
|
|
23
|
+
type HeightDimensions = {
|
|
24
|
+
aspectRatio?: number;
|
|
25
|
+
width?: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
type FullDimensions = { aspectRatio?: number; width: number; height: number };
|
|
29
|
+
type Dimensions = WidthDimensions | HeightDimensions | FullDimensions;
|
|
30
|
+
|
|
31
|
+
const calculateDimensions = ({ aspectRatio, width, height }: Dimensions) => {
|
|
32
|
+
if (aspectRatio) {
|
|
33
|
+
return {
|
|
34
|
+
width: width || height * aspectRatio,
|
|
35
|
+
height: height || width / aspectRatio,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return { width, height };
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const getSourceWithMaxSizes = (applyMaxSize, style, source) => {
|
|
43
|
+
const { width, height } = calculateDimensions(style);
|
|
44
|
+
|
|
45
|
+
if (!applyMaxSize || !isValidSize(width) || !isValidSize(height)) {
|
|
46
|
+
return source;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...source,
|
|
51
|
+
maxWidth: normalize(width),
|
|
52
|
+
maxHeight: normalize(height),
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default function useImageSize(props: Props) {
|
|
57
|
+
const { style, applyMaxSize, source, withDimensions } = props;
|
|
58
|
+
|
|
59
|
+
const sourceWithMaxSizes = React.useMemo(
|
|
60
|
+
() => withDimensions(getSourceWithMaxSizes(applyMaxSize, style, source)),
|
|
61
|
+
[applyMaxSize, style?.height, style?.width, source?.uri, withDimensions]
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return sourceWithMaxSizes;
|
|
65
|
+
}
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { isVideoPreviewEnabled } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/utils";
|
|
3
3
|
import { LiveImage } from "../LiveImage";
|
|
4
4
|
import PureImage from "../Image";
|
|
5
|
+
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
6
|
|
|
6
7
|
type Props = {
|
|
7
8
|
enable_video_preview: boolean;
|
|
@@ -9,7 +10,10 @@ type Props = {
|
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export const ImageContainer = (props: Props) => {
|
|
12
|
-
const
|
|
13
|
+
const isActive = useIsScreenActive();
|
|
14
|
+
|
|
15
|
+
const Component =
|
|
16
|
+
isVideoPreviewEnabled(props) && isActive ? LiveImage : PureImage;
|
|
13
17
|
|
|
14
18
|
return <Component {...props} />;
|
|
15
19
|
};
|
|
@@ -18,6 +18,7 @@ type LiveImageProps = {
|
|
|
18
18
|
imageKey?: string;
|
|
19
19
|
state: "focused" | "unfocused" | "selected";
|
|
20
20
|
audio_muted_by_default?: boolean;
|
|
21
|
+
uri: string; // cover image url
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
const DEFAULT_PLAYER_IDENTIFIER = "QuickBrickPlayerPlugin";
|
|
@@ -176,10 +177,23 @@ const getPlayerConfig = (player_screen_id, actionIdentifier) => {
|
|
|
176
177
|
const positionAbsolute: ViewStyle = { position: "absolute" };
|
|
177
178
|
|
|
178
179
|
const LiveImageComponent = (props: LiveImageProps) => {
|
|
179
|
-
const {
|
|
180
|
+
const {
|
|
181
|
+
item,
|
|
182
|
+
style: componentStyle,
|
|
183
|
+
cellUUID,
|
|
184
|
+
imageKey,
|
|
185
|
+
actionIdentifier,
|
|
186
|
+
state,
|
|
187
|
+
} = props;
|
|
180
188
|
|
|
181
189
|
const component = useUIComponentContext();
|
|
182
190
|
|
|
191
|
+
// Fix for blinking on state change
|
|
192
|
+
const style = React.useMemo(
|
|
193
|
+
() => ({ ...componentStyle, backgroundColor: "transparent" }),
|
|
194
|
+
[componentStyle]
|
|
195
|
+
);
|
|
196
|
+
|
|
183
197
|
const componentType = React.useMemo(
|
|
184
198
|
() => getPropComponentType(component),
|
|
185
199
|
[component?.id]
|
|
@@ -209,10 +223,11 @@ const LiveImageComponent = (props: LiveImageProps) => {
|
|
|
209
223
|
|
|
210
224
|
return (
|
|
211
225
|
<>
|
|
212
|
-
<Image {...props} />
|
|
226
|
+
<Image {...props} applyMaxSize />
|
|
213
227
|
{isShouldRender && (
|
|
214
228
|
<View style={[style, positionAbsolute]}>
|
|
215
229
|
<PlayerLiveImage
|
|
230
|
+
uri={props.uri}
|
|
216
231
|
playerId={cellUUID}
|
|
217
232
|
playerPluginId={playerPluginId}
|
|
218
233
|
screenConfig={screenConfig}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { isNil } from "ramda";
|
|
3
|
-
import {
|
|
3
|
+
import { ImageStyle, View } from "react-native";
|
|
4
4
|
import {
|
|
5
5
|
FIT_POSITION,
|
|
6
6
|
IMAGE_SIZING_FIT,
|
|
7
7
|
IMAGE_SIZING_FILL,
|
|
8
8
|
} from "@applicaster/zapp-react-native-utils/manifestUtils/secondaryImage";
|
|
9
|
+
import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
|
|
9
10
|
|
|
10
11
|
import { useGetImageDimensions } from "./hooks";
|
|
11
12
|
import {
|
|
@@ -59,7 +60,7 @@ const SecondaryImageComponent = (props: Props) => {
|
|
|
59
60
|
|
|
60
61
|
return (
|
|
61
62
|
<View style={style} onLayout={onAsyncRender}>
|
|
62
|
-
<
|
|
63
|
+
<Image
|
|
63
64
|
{...props}
|
|
64
65
|
source={{ uri }}
|
|
65
66
|
style={{
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Text } from "react-native";
|
|
3
3
|
import { omit } from "ramda";
|
|
4
|
-
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
5
4
|
import {
|
|
6
5
|
textTransform,
|
|
7
6
|
dateFormat,
|
|
@@ -9,6 +8,9 @@ import {
|
|
|
9
8
|
|
|
10
9
|
import { useTextLabel, withFocusedStyles } from "./hooks";
|
|
11
10
|
import { withScaledLineHeight } from "./utils";
|
|
11
|
+
import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
12
|
+
import { MeasurementPortalContext } from "../../../MeasurmentsPortal";
|
|
13
|
+
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
12
14
|
|
|
13
15
|
type Props = {
|
|
14
16
|
style: any;
|
|
@@ -32,14 +34,24 @@ const _Text = ({
|
|
|
32
34
|
...otherProps
|
|
33
35
|
}: Props) => {
|
|
34
36
|
const _label = useTextLabel({ label, entry });
|
|
37
|
+
const isMeasurement = React.useContext(MeasurementPortalContext);
|
|
35
38
|
|
|
36
39
|
if (isNilOrEmpty(_label)) {
|
|
37
40
|
return null;
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
// set maximum possible height for the text in case of measurement
|
|
44
|
+
const height =
|
|
45
|
+
isMeasurement && otherProps.numberOfLines && style.lineHeight
|
|
46
|
+
? toNumber(otherProps.numberOfLines) * toNumber(style.lineHeight)
|
|
47
|
+
: undefined;
|
|
48
|
+
|
|
40
49
|
return (
|
|
41
50
|
<Text
|
|
42
|
-
style={
|
|
51
|
+
style={[
|
|
52
|
+
withScaledLineHeight(withFocusedStyles({ style, otherProps })),
|
|
53
|
+
{ height },
|
|
54
|
+
]}
|
|
43
55
|
{...withoutLabel(otherProps)}
|
|
44
56
|
>
|
|
45
57
|
{dateTransformEnabled
|
|
@@ -23,7 +23,11 @@ export const Toggle = (props: Props) => {
|
|
|
23
23
|
iosBackgroundColor,
|
|
24
24
|
} = style;
|
|
25
25
|
|
|
26
|
-
const isSelected = React.useMemo(
|
|
26
|
+
const isSelected = React.useMemo(
|
|
27
|
+
() => cellState === "selected",
|
|
28
|
+
[item?.id, cellState]
|
|
29
|
+
);
|
|
30
|
+
|
|
27
31
|
const actionContext = useActions(action?.identifier);
|
|
28
32
|
|
|
29
33
|
const [actionState, setActionState] = useState(
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import
|
|
2
|
+
import RN from "react-native";
|
|
3
3
|
import { Provider } from "react-redux";
|
|
4
4
|
import TestRenderer from "react-test-renderer";
|
|
5
|
-
import
|
|
6
|
-
import CustomText from "../Text";
|
|
5
|
+
import configureStoreFn from "redux-mock-store";
|
|
7
6
|
|
|
8
|
-
const
|
|
7
|
+
const mockUseIsRTL = jest.fn(() => true);
|
|
8
|
+
const mockGetIsRTL = jest.fn(() => true);
|
|
9
|
+
const mockUseLocalizedStrings = jest.fn(() => ({}));
|
|
10
|
+
const mockGetUILanguage = jest.fn(() => "he-HE");
|
|
11
|
+
|
|
12
|
+
jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
|
|
13
|
+
useIsRTL: mockUseIsRTL,
|
|
14
|
+
getIsRTL: mockGetIsRTL,
|
|
15
|
+
useLocalizedStrings: mockUseLocalizedStrings,
|
|
16
|
+
getUILanguage: mockGetUILanguage,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const CustomText = require("../Text").default;
|
|
20
|
+
const mockStore = configureStoreFn();
|
|
9
21
|
|
|
10
22
|
const defaultProps = {
|
|
11
23
|
entry: {},
|
|
@@ -22,7 +34,7 @@ const getRenderedText = (label: string, store: any) => {
|
|
|
22
34
|
</Provider>
|
|
23
35
|
);
|
|
24
36
|
|
|
25
|
-
return testRenderer.root.findByType(Text).props.children;
|
|
37
|
+
return testRenderer.root.findByType(RN.Text).props.children;
|
|
26
38
|
};
|
|
27
39
|
|
|
28
40
|
describe("RTL app: Hebrew text contains english word", () => {
|
|
@@ -34,7 +46,7 @@ describe("RTL app: Hebrew text contains english word", () => {
|
|
|
34
46
|
remoteConfigurations: { localizations: { he: {} } },
|
|
35
47
|
appData: {
|
|
36
48
|
languageCode: "he",
|
|
37
|
-
countryCode: "
|
|
49
|
+
countryCode: "IL",
|
|
38
50
|
},
|
|
39
51
|
});
|
|
40
52
|
|
|
@@ -47,18 +59,22 @@ describe("RTL app: Hebrew text contains english word", () => {
|
|
|
47
59
|
|
|
48
60
|
it("Hebrew text contains not first english word", () => {
|
|
49
61
|
const renderedText = getRenderedText(textWithNotFirstEnglishWord, store);
|
|
50
|
-
|
|
51
62
|
expect(renderedText).toEqual(textWithNotFirstEnglishWord);
|
|
52
63
|
});
|
|
53
64
|
|
|
54
65
|
it("Hebrew text doesn't contain english word", () => {
|
|
55
66
|
const renderedText = getRenderedText(textWithoutEnglishWord, store);
|
|
56
|
-
|
|
57
67
|
expect(renderedText).toEqual(textWithoutEnglishWord);
|
|
58
68
|
});
|
|
59
69
|
});
|
|
60
70
|
|
|
61
71
|
describe("LTR app: English text", () => {
|
|
72
|
+
beforeAll(() => {
|
|
73
|
+
mockUseIsRTL.mockReturnValue(false);
|
|
74
|
+
mockGetIsRTL.mockReturnValue(false);
|
|
75
|
+
mockGetUILanguage.mockReturnValue("en-US");
|
|
76
|
+
});
|
|
77
|
+
|
|
62
78
|
const englishText = "Test sentence";
|
|
63
79
|
|
|
64
80
|
const store = mockStore({
|
|
@@ -71,7 +87,6 @@ describe("LTR app: English text", () => {
|
|
|
71
87
|
|
|
72
88
|
it("English text", () => {
|
|
73
89
|
const renderedText = getRenderedText(englishText, store);
|
|
74
|
-
|
|
75
90
|
expect(renderedText).toEqual(englishText);
|
|
76
91
|
});
|
|
77
92
|
});
|
|
@@ -61,7 +61,10 @@ export function ButtonContainerView({
|
|
|
61
61
|
<View style={applyRTLStylesIfNeeded(style, isRTL)}>
|
|
62
62
|
{insertBetween(
|
|
63
63
|
(index) => (
|
|
64
|
-
<HorizontalSeparator
|
|
64
|
+
<HorizontalSeparator
|
|
65
|
+
key={`separator_${index}`}
|
|
66
|
+
width={horizontalGutter}
|
|
67
|
+
/>
|
|
65
68
|
),
|
|
66
69
|
cloneElementsWithIds(buttonIds, filteredChildren)
|
|
67
70
|
)}
|
|
@@ -29,7 +29,10 @@ export function ButtonContainerView({
|
|
|
29
29
|
<View style={style}>
|
|
30
30
|
{insertBetween(
|
|
31
31
|
(index) => (
|
|
32
|
-
<HorizontalSeparator
|
|
32
|
+
<HorizontalSeparator
|
|
33
|
+
key={`separator_${index}`}
|
|
34
|
+
width={horizontalGutter}
|
|
35
|
+
/>
|
|
33
36
|
),
|
|
34
37
|
filteredChildren
|
|
35
38
|
)}
|
|
@@ -51,9 +51,7 @@ export const CollapsibleTextContainer = ({
|
|
|
51
51
|
func: (data) => {
|
|
52
52
|
return getColorFromData({
|
|
53
53
|
data,
|
|
54
|
-
|
|
55
|
-
key: "background_color",
|
|
56
|
-
defaultColor: additionalStyles.backgroundColor,
|
|
54
|
+
valueFromLayout: additionalStyles.backgroundColor,
|
|
57
55
|
});
|
|
58
56
|
},
|
|
59
57
|
propName: "backgroundColor",
|
|
@@ -125,13 +125,24 @@ export const useFilterChildren = <
|
|
|
125
125
|
|
|
126
126
|
const filteredChildren = children.filter((child) => {
|
|
127
127
|
const item = child.props.item;
|
|
128
|
-
const
|
|
128
|
+
const actionIdentifier = child.props.pluginIdentifier;
|
|
129
|
+
const action = actions.actions[actionIdentifier];
|
|
130
|
+
|
|
129
131
|
// context value of specific plugin
|
|
130
|
-
|
|
132
|
+
if (action?.module && action.module.context) {
|
|
133
|
+
const currentValue = action.module.context._currentValue;
|
|
134
|
+
|
|
135
|
+
return currentValue?.isActionAvailable
|
|
136
|
+
? currentValue.isActionAvailable(item)
|
|
137
|
+
: true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
masterCellLogger.error({
|
|
141
|
+
message: `Action plugin for ${actionIdentifier} could not be found, check the configuration of your action button`,
|
|
142
|
+
data: { item, action: child.props.pluginIdentifier },
|
|
143
|
+
});
|
|
131
144
|
|
|
132
|
-
return
|
|
133
|
-
? currentValue.isActionAvailable(item)
|
|
134
|
-
: true;
|
|
145
|
+
return false;
|
|
135
146
|
});
|
|
136
147
|
|
|
137
148
|
return filteredChildren;
|
|
@@ -285,8 +296,8 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
|
|
|
285
296
|
}
|
|
286
297
|
}
|
|
287
298
|
}, [behavior]);
|
|
288
|
-
|
|
289
|
-
|
|
299
|
+
|
|
300
|
+
useEffect(() => {
|
|
290
301
|
if (!behavior) {
|
|
291
302
|
return;
|
|
292
303
|
}
|