@applicaster/zapp-react-native-ui-components 16.0.0-alpha.6861239588 → 16.0.0-alpha.6918106967
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/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
- package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
- package/Components/AudioPlayer/tv/index.tsx +5 -1
- package/Components/Cell/Cell.tsx +3 -6
- package/Components/Cell/TvOSCellComponent.tsx +0 -1
- package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +15 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +64 -0
- package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
- package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +18 -0
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +1 -0
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
- package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
- package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +54 -0
- package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +21 -0
- package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
- package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +58 -0
- package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -18
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +32 -27
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +25 -73
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +0 -18
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +166 -84
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +89 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +3 -1
- package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +230 -0
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +332 -0
- package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +385 -60
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
- package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
- package/Components/ModalComponent/Header/index.tsx +20 -7
- package/Components/ModalComponent/Header/utils.ts +1 -1
- package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
- package/Components/ModalComponent/SortableList.tsx +142 -0
- package/Components/ModalComponent/SortableList.web.tsx +34 -0
- package/Components/ModalComponent/TextInputContent.tsx +100 -0
- package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +238 -0
- package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +120 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
- package/Components/ModalComponent/index.tsx +11 -0
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +66 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
- package/Components/ModalComponent/presets/index.ts +27 -0
- package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
- package/Components/ModalComponent/presets/standardCell.tsx +41 -0
- package/Components/ModalComponent/presets/types.ts +35 -0
- package/Components/ModalComponent/showTextInput.ts +43 -0
- package/Components/ModalComponent/utils.ts +82 -21
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
- package/Components/OfflineHandler/__tests__/index.test.tsx +78 -18
- package/Components/OfflineHandler/hooks.ts +111 -0
- package/Components/OfflineHandler/index.tsx +51 -73
- package/Components/OfflineHandler/utils/index.ts +1 -13
- package/Components/PlayerContainer/PlayerContainer.tsx +11 -7
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +66 -13
- package/Components/PreloaderWrapper/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +79 -51
- package/Components/River/River.tsx +4 -0
- package/Components/River/__tests__/resultCallback.test.tsx +47 -0
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +20 -3
- package/Components/TopCutoffOverlay/index.tsx +2 -2
- package/Components/VideoLive/LiveImageManager.ts +1 -1
- package/Hooks/useEntryActionsExpander.ts +63 -0
- package/package.json +6 -5
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
- package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
- /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
|
@@ -7,7 +7,7 @@ import { useMarginTop } from "./hooks";
|
|
|
7
7
|
|
|
8
8
|
interface IProps {
|
|
9
9
|
targetScreenId?: string;
|
|
10
|
-
children
|
|
10
|
+
children: React.ReactElement | null;
|
|
11
11
|
applyTopCutoff?: boolean;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ export const TopCutoffOverlay: React.FC<IProps> = ({
|
|
|
21
21
|
targetScreenId,
|
|
22
22
|
children,
|
|
23
23
|
applyTopCutoff = true,
|
|
24
|
-
}
|
|
24
|
+
}) => {
|
|
25
25
|
const cutoffHeight = useMarginTop(targetScreenId);
|
|
26
26
|
|
|
27
27
|
const { backgroundColor: screenBackgroundColor } =
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
6
6
|
import { setUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
|
|
7
7
|
import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
|
|
8
|
-
import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/
|
|
8
|
+
import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/const";
|
|
9
9
|
import { loggerLiveImageManager } from "./loggerHelper";
|
|
10
10
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
11
11
|
import {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
|
|
4
|
+
import {
|
|
5
|
+
buildEntryActions,
|
|
6
|
+
EntryActionDeps,
|
|
7
|
+
} from "@applicaster/zapp-react-native-utils/entryActions";
|
|
8
|
+
import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
9
|
+
import { useScreenStateStore } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useScreenStateStore";
|
|
10
|
+
import {
|
|
11
|
+
useCurrentScreenData,
|
|
12
|
+
useScreenContext,
|
|
13
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
14
|
+
import { RegisteredAction } from "@applicaster/zapp-react-native-utils/uiActionsRegistrator";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Expands `entry.extensions.entry_action` into invokable actions, against the
|
|
18
|
+
* screen this hook is called from.
|
|
19
|
+
*
|
|
20
|
+
* Entry actions are data on the entry, not an installed capability, so there is
|
|
21
|
+
* nothing to look up by identifier: the surface showing the entry expands them.
|
|
22
|
+
* That also decides which screen they execute against — the one whose tree this
|
|
23
|
+
* hook runs in, rather than whichever screen happened to be current when a
|
|
24
|
+
* global provider was registered.
|
|
25
|
+
*
|
|
26
|
+
* Pass the result to `resolveActionIdentifiers` / `resolvePlayerActions` as
|
|
27
|
+
* `expandEntryActions`.
|
|
28
|
+
*/
|
|
29
|
+
export function useEntryActionsExpander(): (
|
|
30
|
+
entry: ZappEntry | ZappFeed
|
|
31
|
+
) => RegisteredAction[] {
|
|
32
|
+
const { pathname } = useRoute();
|
|
33
|
+
|
|
34
|
+
const screenContext = useScreenContext();
|
|
35
|
+
const screenData = useCurrentScreenData();
|
|
36
|
+
const screenState = screenContext?.options;
|
|
37
|
+
const screenStateStore = useScreenStateStore();
|
|
38
|
+
const actionExecutor = React.useContext(ActionExecutorContext);
|
|
39
|
+
|
|
40
|
+
// Read through a ref so the returned expander keeps a stable identity: it
|
|
41
|
+
// feeds `useMemo` dependency lists on surfaces that re-resolve their actions
|
|
42
|
+
// on every registry change.
|
|
43
|
+
const depsRef = React.useRef<EntryActionDeps>();
|
|
44
|
+
|
|
45
|
+
depsRef.current = {
|
|
46
|
+
actionExecutor,
|
|
47
|
+
actionContext: {
|
|
48
|
+
screenData,
|
|
49
|
+
screenState,
|
|
50
|
+
screenRoute: pathname,
|
|
51
|
+
screenStateStore,
|
|
52
|
+
// From the screen context, the way `useCellClick` builds the same bag.
|
|
53
|
+
// The ZappPipes entry context is a route-keyed map, so reading `.data`
|
|
54
|
+
// off it was always undefined.
|
|
55
|
+
screenEntry: screenContext?.entry,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return React.useCallback(
|
|
60
|
+
(entry: ZappEntry | ZappFeed) => buildEntryActions(entry, depsRef.current),
|
|
61
|
+
[]
|
|
62
|
+
);
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "16.0.0-alpha.
|
|
3
|
+
"version": "16.0.0-alpha.6918106967",
|
|
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,12 +28,13 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "16.0.0-alpha.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "16.0.0-alpha.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "16.0.0-alpha.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "16.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "16.0.0-alpha.6918106967",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "16.0.0-alpha.6918106967",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "16.0.0-alpha.6918106967",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "16.0.0-alpha.6918106967",
|
|
35
35
|
"fast-json-stable-stringify": "^2.1.0",
|
|
36
36
|
"promise": "^8.3.0",
|
|
37
|
+
"react-native-sortables": "1.7.1",
|
|
37
38
|
"url": "^0.11.0",
|
|
38
39
|
"uuid": "^3.3.2"
|
|
39
40
|
},
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
3
|
-
import { useNetworkStatusLocalizations } from "./utils";
|
|
4
|
-
|
|
5
|
-
type Props = {
|
|
6
|
-
children?: React.ReactNode;
|
|
7
|
-
hidden?: boolean;
|
|
8
|
-
online?: boolean;
|
|
9
|
-
previousOnline?: boolean;
|
|
10
|
-
dismiss: () => void;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const NOTIF_DURATION = 4500;
|
|
14
|
-
|
|
15
|
-
const styles: Record<any, React.CSSProperties> = {
|
|
16
|
-
body: {
|
|
17
|
-
position: "absolute",
|
|
18
|
-
bottom: 0,
|
|
19
|
-
width: 1920,
|
|
20
|
-
height: 200,
|
|
21
|
-
background:
|
|
22
|
-
"linear-gradient(180deg, rgba(17,17,17,0.9) 0%, rgba(17,17,17,1) 49%, rgba(0,0,0,0.85) 100%)",
|
|
23
|
-
display: "flex",
|
|
24
|
-
alignItems: "center",
|
|
25
|
-
justifyContent: "center",
|
|
26
|
-
flexDirection: "column",
|
|
27
|
-
color: "#fff",
|
|
28
|
-
paddingBottom: 15,
|
|
29
|
-
},
|
|
30
|
-
title: {
|
|
31
|
-
fontSize: 28,
|
|
32
|
-
margin: 0,
|
|
33
|
-
padding: 0,
|
|
34
|
-
},
|
|
35
|
-
subtitle: {
|
|
36
|
-
fontSize: 20,
|
|
37
|
-
margin: 0,
|
|
38
|
-
padding: 0,
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const NotificationView = (props: Props) => {
|
|
43
|
-
const { children, hidden, dismiss, previousOnline, online } = props;
|
|
44
|
-
|
|
45
|
-
const theme = useTheme<BaseThemePropertiesTV>();
|
|
46
|
-
const storedLocalizations = useNetworkStatusLocalizations();
|
|
47
|
-
|
|
48
|
-
const [open, setOpen] = React.useState<boolean | null>(null);
|
|
49
|
-
|
|
50
|
-
const timeout = React.useRef<NodeJS.Timeout>();
|
|
51
|
-
const wentOnline = !previousOnline && props.online;
|
|
52
|
-
|
|
53
|
-
const onClose = () => {
|
|
54
|
-
setOpen(false);
|
|
55
|
-
dismiss();
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const closeNotification = () => {
|
|
59
|
-
clearTimeout(timeout.current as NodeJS.Timeout);
|
|
60
|
-
|
|
61
|
-
timeout.current = setTimeout(() => {
|
|
62
|
-
setOpen(false);
|
|
63
|
-
}, NOTIF_DURATION);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const openNotification = () => {
|
|
67
|
-
if (!open && !hidden) {
|
|
68
|
-
setOpen(true);
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const handleNotificationChange = () => {
|
|
73
|
-
if (open !== null) {
|
|
74
|
-
openNotification();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
closeNotification();
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
React.useEffect(() => {
|
|
81
|
-
handleNotificationChange();
|
|
82
|
-
}, [hidden, online]);
|
|
83
|
-
|
|
84
|
-
const showOnlineMsg = wentOnline || online;
|
|
85
|
-
|
|
86
|
-
const MSG = showOnlineMsg
|
|
87
|
-
? (theme?.online_notification_title ??
|
|
88
|
-
storedLocalizations?.online_notification_title)
|
|
89
|
-
: (theme?.offline_notification_title ??
|
|
90
|
-
storedLocalizations?.offline_notification_title);
|
|
91
|
-
|
|
92
|
-
const EXTRA_MSG = showOnlineMsg
|
|
93
|
-
? (theme?.online_notification_subtitle ??
|
|
94
|
-
storedLocalizations?.online_notification_subtitle)
|
|
95
|
-
: (theme?.offline_notification_subtitle ??
|
|
96
|
-
storedLocalizations?.offline_notification_subtitle);
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<div onClick={onClose}>
|
|
100
|
-
{children}
|
|
101
|
-
{open ? (
|
|
102
|
-
<div style={styles.body}>
|
|
103
|
-
<div style={styles.title}>
|
|
104
|
-
<h2>{MSG}</h2>
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
<h4 style={styles.subtitle}>{EXTRA_MSG}</h4>
|
|
108
|
-
</div>
|
|
109
|
-
) : null}
|
|
110
|
-
</div>
|
|
111
|
-
);
|
|
112
|
-
};
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
3
|
-
import { useNetworkStatusLocalizations } from "./utils";
|
|
4
|
-
|
|
5
|
-
type Props = {
|
|
6
|
-
children?: React.ReactNode;
|
|
7
|
-
online?: boolean;
|
|
8
|
-
previousOnline?: boolean;
|
|
9
|
-
dismiss: () => void;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const DURATION_TO_HIDE_AFTER_BACK_TO_ONLINE = 4500; // ms
|
|
13
|
-
|
|
14
|
-
const styles: Record<any, React.CSSProperties> = {
|
|
15
|
-
body: {
|
|
16
|
-
position: "absolute",
|
|
17
|
-
top: 0,
|
|
18
|
-
width: 1920,
|
|
19
|
-
height: 200,
|
|
20
|
-
background:
|
|
21
|
-
"linear-gradient(180deg, rgba(17,17,17,0.9) 0%, rgba(17,17,17,1) 49%, rgba(0,0,0,0.85) 100%)",
|
|
22
|
-
display: "flex",
|
|
23
|
-
alignItems: "center",
|
|
24
|
-
justifyContent: "center",
|
|
25
|
-
flexDirection: "column",
|
|
26
|
-
color: "#fff",
|
|
27
|
-
paddingTop: 15,
|
|
28
|
-
},
|
|
29
|
-
title: {
|
|
30
|
-
fontSize: 28,
|
|
31
|
-
margin: 0,
|
|
32
|
-
padding: 0,
|
|
33
|
-
},
|
|
34
|
-
subtitle: {
|
|
35
|
-
fontSize: 20,
|
|
36
|
-
margin: 0,
|
|
37
|
-
padding: 0,
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
let timer: NodeJS.Timeout;
|
|
42
|
-
|
|
43
|
-
export const NotificationView = (props: Props) => {
|
|
44
|
-
const { children, dismiss, previousOnline = true, online } = props;
|
|
45
|
-
|
|
46
|
-
const theme = useTheme<BaseThemePropertiesTV>();
|
|
47
|
-
const storedLocalizations = useNetworkStatusLocalizations();
|
|
48
|
-
|
|
49
|
-
const [shown, setShown] = React.useState<boolean>(false);
|
|
50
|
-
|
|
51
|
-
const onClose = () => {
|
|
52
|
-
setShown(false);
|
|
53
|
-
dismiss();
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
React.useEffect(() => {
|
|
57
|
-
if (previousOnline && online) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!previousOnline && !online) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (previousOnline && !online) {
|
|
66
|
-
// went to offline
|
|
67
|
-
clearTimeout(timer);
|
|
68
|
-
setShown(true);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (!previousOnline && online) {
|
|
72
|
-
// back to online
|
|
73
|
-
setShown(true);
|
|
74
|
-
|
|
75
|
-
timer = setTimeout(() => {
|
|
76
|
-
setShown(false);
|
|
77
|
-
}, DURATION_TO_HIDE_AFTER_BACK_TO_ONLINE);
|
|
78
|
-
}
|
|
79
|
-
}, [online, previousOnline]);
|
|
80
|
-
|
|
81
|
-
const title = online
|
|
82
|
-
? (theme?.online_notification_title ??
|
|
83
|
-
storedLocalizations?.online_notification_title)
|
|
84
|
-
: (theme?.offline_notification_title ??
|
|
85
|
-
storedLocalizations?.offline_notification_title);
|
|
86
|
-
|
|
87
|
-
const subtitle = online
|
|
88
|
-
? (theme?.online_notification_subtitle ??
|
|
89
|
-
storedLocalizations?.online_notification_subtitle)
|
|
90
|
-
: (theme?.offline_notification_subtitle ??
|
|
91
|
-
storedLocalizations?.offline_notification_subtitle);
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<div onClick={onClose}>
|
|
95
|
-
{children}
|
|
96
|
-
{shown ? (
|
|
97
|
-
<div style={styles.body}>
|
|
98
|
-
<div style={styles.title}>
|
|
99
|
-
<h2>{title}</h2>
|
|
100
|
-
</div>
|
|
101
|
-
|
|
102
|
-
<h4 style={styles.subtitle}>{subtitle}</h4>
|
|
103
|
-
</div>
|
|
104
|
-
) : null}
|
|
105
|
-
</div>
|
|
106
|
-
);
|
|
107
|
-
};
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import React, { useRef, useState, useEffect } from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
|
-
import {
|
|
4
|
-
View,
|
|
5
|
-
Text,
|
|
6
|
-
Animated,
|
|
7
|
-
StyleSheet,
|
|
8
|
-
TouchableWithoutFeedback,
|
|
9
|
-
} from "react-native";
|
|
10
|
-
|
|
11
|
-
import { usePlugins } from "@applicaster/zapp-react-native-redux";
|
|
12
|
-
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
13
|
-
import { textTransform } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
14
|
-
import { useNotificationHeight } from "../utils";
|
|
15
|
-
|
|
16
|
-
export const onlinePhrase = "You are back online";
|
|
17
|
-
|
|
18
|
-
export const offlinePhrase = "No internet connection";
|
|
19
|
-
|
|
20
|
-
const styles = StyleSheet.create({
|
|
21
|
-
notificationView: {
|
|
22
|
-
flex: 1,
|
|
23
|
-
position: "absolute",
|
|
24
|
-
alignItems: "center",
|
|
25
|
-
justifyContent: "center",
|
|
26
|
-
top: 0,
|
|
27
|
-
left: 0,
|
|
28
|
-
right: 0,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
type Props = {
|
|
33
|
-
children?: React.ReactNode;
|
|
34
|
-
hidden?: boolean;
|
|
35
|
-
online?: boolean;
|
|
36
|
-
dismiss: () => void;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
type NumberBoolean = 0 | 1;
|
|
40
|
-
|
|
41
|
-
const OFFLINE_EXPERIENCE = "offline-experience";
|
|
42
|
-
|
|
43
|
-
export const NotificationView = ({
|
|
44
|
-
children,
|
|
45
|
-
hidden = true,
|
|
46
|
-
online = true,
|
|
47
|
-
dismiss,
|
|
48
|
-
}: Props) => {
|
|
49
|
-
const plugins = usePlugins();
|
|
50
|
-
const { statusHeight, notificationHeight } = useNotificationHeight();
|
|
51
|
-
|
|
52
|
-
const offlinePlugin = R.find(
|
|
53
|
-
R.propEq("identifier", OFFLINE_EXPERIENCE),
|
|
54
|
-
plugins
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
const { useOfflineExperienceConfiguration } = offlinePlugin.module;
|
|
58
|
-
|
|
59
|
-
const {
|
|
60
|
-
configurationFields,
|
|
61
|
-
localizations,
|
|
62
|
-
}: {
|
|
63
|
-
configurationFields: OfflineExperiencePluginConfiguration;
|
|
64
|
-
localizations: OfflineExperienceLocalizations;
|
|
65
|
-
} = useOfflineExperienceConfiguration?.();
|
|
66
|
-
|
|
67
|
-
const [notificationOpacity, setNotificationOpacity] =
|
|
68
|
-
useState<NumberBoolean>(0);
|
|
69
|
-
|
|
70
|
-
const yPosition = useRef(new Animated.Value(0)).current;
|
|
71
|
-
|
|
72
|
-
const showNotification = () => {
|
|
73
|
-
setNotificationOpacity(1);
|
|
74
|
-
|
|
75
|
-
Animated.timing(yPosition, {
|
|
76
|
-
toValue: 1,
|
|
77
|
-
useNativeDriver: true,
|
|
78
|
-
duration: 300,
|
|
79
|
-
}).start();
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const hideNotification = () => {
|
|
83
|
-
Animated.timing(yPosition, {
|
|
84
|
-
toValue: 0,
|
|
85
|
-
useNativeDriver: true,
|
|
86
|
-
duration: 300,
|
|
87
|
-
}).start(() => {
|
|
88
|
-
setNotificationOpacity(0);
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
hidden ? hideNotification() : showNotification();
|
|
94
|
-
}, [hidden]);
|
|
95
|
-
|
|
96
|
-
const backgroundColor = online
|
|
97
|
-
? configurationFields.offline_toast_online_background_color
|
|
98
|
-
: configurationFields.offline_toast_offline_background_color;
|
|
99
|
-
|
|
100
|
-
const animatedViewStyles = {
|
|
101
|
-
...styles.notificationView,
|
|
102
|
-
transform: [
|
|
103
|
-
{
|
|
104
|
-
translateY: yPosition.interpolate({
|
|
105
|
-
inputRange: [0, 1],
|
|
106
|
-
outputRange: [-notificationHeight, 0],
|
|
107
|
-
}),
|
|
108
|
-
},
|
|
109
|
-
],
|
|
110
|
-
opacity: notificationOpacity,
|
|
111
|
-
height: notificationHeight,
|
|
112
|
-
width: "100%",
|
|
113
|
-
backgroundColor,
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const textStyles = {
|
|
117
|
-
color: online
|
|
118
|
-
? configurationFields.offline_toast_message_online_font_color
|
|
119
|
-
: configurationFields.offline_toast_message_font_color,
|
|
120
|
-
fontFamily: platformSelect({
|
|
121
|
-
ios: configurationFields.offline_toast_message_ios_font_family,
|
|
122
|
-
android: configurationFields.offline_toast_message_android_font_family,
|
|
123
|
-
}),
|
|
124
|
-
fontSize: configurationFields.offline_toast_message_font_size,
|
|
125
|
-
lineHeight: configurationFields.offline_toast_message_line_height,
|
|
126
|
-
letterSpacing: platformSelect({
|
|
127
|
-
ios: configurationFields.offline_toast_message_letter_spacing_ios,
|
|
128
|
-
android: configurationFields.offline_toast_message_letter_spacing_android,
|
|
129
|
-
}),
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const message = textTransform(
|
|
133
|
-
configurationFields.offline_toast_message_text_transform,
|
|
134
|
-
online
|
|
135
|
-
? localizations.online_toast_message
|
|
136
|
-
: localizations.offline_toast_message
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<View style={StyleSheet.absoluteFill}>
|
|
141
|
-
{children}
|
|
142
|
-
<TouchableWithoutFeedback
|
|
143
|
-
style={styles.notificationView}
|
|
144
|
-
onPress={dismiss}
|
|
145
|
-
>
|
|
146
|
-
<Animated.View style={animatedViewStyles}>
|
|
147
|
-
<View style={{ height: statusHeight, backgroundColor }} />
|
|
148
|
-
<Text style={textStyles}>{message}</Text>
|
|
149
|
-
</Animated.View>
|
|
150
|
-
</TouchableWithoutFeedback>
|
|
151
|
-
</View>
|
|
152
|
-
);
|
|
153
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Text, Animated } from "react-native";
|
|
3
|
-
import { render } from "@testing-library/react-native";
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
NotificationView,
|
|
7
|
-
onlinePhrase,
|
|
8
|
-
offlinePhrase,
|
|
9
|
-
} from "../NotificationView";
|
|
10
|
-
|
|
11
|
-
jest.mock("@applicaster/zapp-react-native-redux", () => ({
|
|
12
|
-
...jest.requireActual("@applicaster/zapp-react-native-redux"),
|
|
13
|
-
usePlugins: () => [
|
|
14
|
-
{
|
|
15
|
-
name: "offline experience",
|
|
16
|
-
identifier: "offline-experience",
|
|
17
|
-
type: "general",
|
|
18
|
-
module: {
|
|
19
|
-
useOfflineExperienceConfiguration: () => ({
|
|
20
|
-
configurationFields: {},
|
|
21
|
-
localizations: {
|
|
22
|
-
offline_toast_message: "No internet connection",
|
|
23
|
-
online_toast_message: "You are back online",
|
|
24
|
-
},
|
|
25
|
-
}),
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
jest.mock("react-native-safe-area-context", () => ({
|
|
32
|
-
useSafeAreaInsets: () => ({ top: 44 }),
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
|
-
const dismiss = jest.fn();
|
|
36
|
-
|
|
37
|
-
describe("NotificationView", () => {
|
|
38
|
-
it("Show online message when Online", () => {
|
|
39
|
-
const component = render(<NotificationView online dismiss={dismiss} />);
|
|
40
|
-
|
|
41
|
-
expect(component.UNSAFE_getByType(Text).props.children).toBe(onlinePhrase);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("Show offline message when Online", () => {
|
|
45
|
-
const component = render(
|
|
46
|
-
<NotificationView online={false} dismiss={dismiss} />
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
expect(component.UNSAFE_getByType(Text).props.children).toBe(offlinePhrase);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("When hidden is false to true notification is visible", () => {
|
|
53
|
-
const component = render(
|
|
54
|
-
<NotificationView online={false} hidden={false} dismiss={dismiss} />
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
component.rerender(
|
|
58
|
-
<NotificationView online={false} hidden={true} dismiss={dismiss} />
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
const animatedView = component.UNSAFE_getByType(Animated.View);
|
|
62
|
-
const animatedViewStyles = animatedView.props.style;
|
|
63
|
-
|
|
64
|
-
expect(animatedViewStyles.opacity).toBe(1);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
|
|
3
|
-
|
|
4
|
-
export const NETWORK_STATUS_LOCALIZATIONS_KEY = "network_status_localizations";
|
|
5
|
-
|
|
6
|
-
export const THEME_STORAGE_NAMESPACE = "quick-brick-theme";
|
|
7
|
-
|
|
8
|
-
export function useNetworkStatusLocalizations() {
|
|
9
|
-
const [storedLocalizations, setStoredLocalizations] = React.useState<Record<
|
|
10
|
-
string,
|
|
11
|
-
string
|
|
12
|
-
> | null>(null);
|
|
13
|
-
|
|
14
|
-
React.useEffect(() => {
|
|
15
|
-
async function loadStoredLocalizations() {
|
|
16
|
-
try {
|
|
17
|
-
const stored = await sessionStorage.getItem(
|
|
18
|
-
NETWORK_STATUS_LOCALIZATIONS_KEY,
|
|
19
|
-
THEME_STORAGE_NAMESPACE
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
if (stored) {
|
|
23
|
-
setStoredLocalizations(stored);
|
|
24
|
-
}
|
|
25
|
-
} catch (error) {
|
|
26
|
-
console.error("Error loading network status localizations", error);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
loadStoredLocalizations();
|
|
31
|
-
}, []);
|
|
32
|
-
|
|
33
|
-
return storedLocalizations;
|
|
34
|
-
}
|
|
File without changes
|