@applicaster/zapp-react-native-ui-components 15.1.0-rc.6 → 15.1.0-rc.8
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/Layout/TV/ScreenContainer.tsx +5 -0
- package/Components/Screen/TV/hooks/__tests__/useAfterPaint.test.ts +60 -0
- package/Components/Screen/TV/hooks/index.ts +2 -0
- package/Components/Screen/TV/hooks/useAfterPaint.ts +23 -0
- package/Components/Screen/TV/index.web.tsx +16 -7
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +1 -1
- package/package.json +5 -5
|
@@ -133,6 +133,11 @@ export const ScreenContainer = React.memo(function ScreenContainer({
|
|
|
133
133
|
[]
|
|
134
134
|
);
|
|
135
135
|
|
|
136
|
+
// We need to render menu first and then proceed with screen content,
|
|
137
|
+
// otherwise screen will stay black until everything is loaded and screen
|
|
138
|
+
// rendering put huge load the CPU pushing rendering even further.
|
|
139
|
+
// With this approach, menu will be rendered immediately and screen content
|
|
140
|
+
// will be rendered after paint, which makes it more responsive and prevents black screen.
|
|
136
141
|
const [navBarReady, setNavBarReady] = React.useState(false);
|
|
137
142
|
|
|
138
143
|
const navBarContainer = (
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { renderHook, act } from "@testing-library/react-native";
|
|
2
|
+
|
|
3
|
+
import { useAfterPaint } from "../useAfterPaint";
|
|
4
|
+
|
|
5
|
+
describe("useAfterPaint", () => {
|
|
6
|
+
let frameCallbacks: FrameRequestCallback[];
|
|
7
|
+
let originalRaf: typeof requestAnimationFrame;
|
|
8
|
+
let originalCancelRaf: typeof cancelAnimationFrame;
|
|
9
|
+
|
|
10
|
+
const flushFrame = () => {
|
|
11
|
+
const callbacks = frameCallbacks;
|
|
12
|
+
frameCallbacks = [];
|
|
13
|
+
|
|
14
|
+
act(() => {
|
|
15
|
+
callbacks.forEach((cb) => cb(0));
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
frameCallbacks = [];
|
|
21
|
+
originalRaf = global.requestAnimationFrame;
|
|
22
|
+
originalCancelRaf = global.cancelAnimationFrame;
|
|
23
|
+
|
|
24
|
+
global.requestAnimationFrame = jest.fn((cb: FrameRequestCallback) => {
|
|
25
|
+
frameCallbacks.push(cb);
|
|
26
|
+
|
|
27
|
+
return frameCallbacks.length;
|
|
28
|
+
}) as unknown as typeof requestAnimationFrame;
|
|
29
|
+
|
|
30
|
+
global.cancelAnimationFrame = jest.fn();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
global.requestAnimationFrame = originalRaf;
|
|
35
|
+
global.cancelAnimationFrame = originalCancelRaf;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("returns false on the initial render", () => {
|
|
39
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
40
|
+
|
|
41
|
+
expect(result.current).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("stays false after only one animation frame (before paint completes)", () => {
|
|
45
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
46
|
+
|
|
47
|
+
flushFrame();
|
|
48
|
+
|
|
49
|
+
expect(result.current).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("returns true after two animation frames (a real post-paint boundary)", () => {
|
|
53
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
54
|
+
|
|
55
|
+
flushFrame();
|
|
56
|
+
flushFrame();
|
|
57
|
+
|
|
58
|
+
expect(result.current).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export const useAfterPaint = (): boolean => {
|
|
4
|
+
const [painted, setPainted] = React.useState(false);
|
|
5
|
+
|
|
6
|
+
React.useEffect(() => {
|
|
7
|
+
let secondFrame: number | undefined;
|
|
8
|
+
|
|
9
|
+
const firstFrame = requestAnimationFrame(() => {
|
|
10
|
+
secondFrame = requestAnimationFrame(() => setPainted(true));
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return () => {
|
|
14
|
+
cancelAnimationFrame(firstFrame);
|
|
15
|
+
|
|
16
|
+
if (secondFrame !== undefined) {
|
|
17
|
+
cancelAnimationFrame(secondFrame);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
|
|
22
|
+
return painted;
|
|
23
|
+
};
|
|
@@ -20,7 +20,7 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
|
|
|
20
20
|
|
|
21
21
|
import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
|
|
22
22
|
import { ScreenResolver } from "../../ScreenResolver";
|
|
23
|
-
import { useInitialFocus } from "./hooks";
|
|
23
|
+
import { useInitialFocus, useAfterPaint } from "./hooks";
|
|
24
24
|
import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
25
25
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
26
26
|
import { FreezeWithCallback } from "../../FreezeWithCallback";
|
|
@@ -155,6 +155,13 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
155
155
|
|
|
156
156
|
const isScreenActive = useIsScreenActive();
|
|
157
157
|
|
|
158
|
+
// We need to render menu first and then proceed with screen content,
|
|
159
|
+
// otherwise screen will stay black until everything is loaded and screen
|
|
160
|
+
// rendering put huge load the CPU pushing rendering even further.
|
|
161
|
+
// With this approach, menu will be rendered immediately and screen content
|
|
162
|
+
// will be rendered after paint, which makes it more responsive and prevents black screen.
|
|
163
|
+
const isContentReady = useAfterPaint();
|
|
164
|
+
|
|
158
165
|
return (
|
|
159
166
|
<FreezeWithCallback freeze={!isScreenActive} onRelease={onRelease}>
|
|
160
167
|
<View style={[styles.container, { backgroundColor }]}>
|
|
@@ -165,12 +172,14 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
165
172
|
navigationProps={navigationProps}
|
|
166
173
|
/>
|
|
167
174
|
</NavBarContainer>
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
{isContentReady ? (
|
|
176
|
+
<ScreenResolver
|
|
177
|
+
screenType={screenType}
|
|
178
|
+
screenId={screenId}
|
|
179
|
+
screenData={screenData}
|
|
180
|
+
groupId={route}
|
|
181
|
+
/>
|
|
182
|
+
) : null}
|
|
174
183
|
</View>
|
|
175
184
|
</FreezeWithCallback>
|
|
176
185
|
);
|
|
@@ -77,7 +77,7 @@ export const withScreenRevealManager = (Component) => {
|
|
|
77
77
|
|
|
78
78
|
if (isFirstComponentScreenPicker(componentsToRender)) {
|
|
79
79
|
// for screen-picker with have additional internal ComponentsMap, no need to add this wrapper
|
|
80
|
-
return <Component {...props} />;
|
|
80
|
+
return <Component {...props} initialNumberToLoad={1} />;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
return (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "15.1.0-rc.
|
|
3
|
+
"version": "15.1.0-rc.8",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "15.1.0-rc.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "15.1.0-rc.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "15.1.0-rc.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "15.1.0-rc.
|
|
31
|
+
"@applicaster/applicaster-types": "15.1.0-rc.8",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "15.1.0-rc.8",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "15.1.0-rc.8",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "15.1.0-rc.8",
|
|
35
35
|
"fast-json-stable-stringify": "^2.1.0",
|
|
36
36
|
"promise": "^8.3.0",
|
|
37
37
|
"url": "^0.11.0",
|