@applicaster/zapp-react-native-utils 13.0.0-alpha.3755455151 → 13.0.0-alpha.4097222141
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/actionsExecutor/ActionExecutor.ts +16 -9
- package/actionsExecutor/ActionExecutorContext.tsx +59 -8
- package/alertUtils/alert.ts +148 -0
- package/alertUtils/index.ts +1 -148
- package/appUtils/HooksManager/Hook.ts +2 -2
- package/appUtils/HooksManager/types.ts +5 -2
- package/appUtils/contextKeysManager/contextResolver.ts +77 -0
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +1 -0
- package/appUtils/focusManager/index.ts +11 -3
- package/appUtils/focusManagerAux/utils/index.ts +4 -3
- package/appUtils/platform/const.ts +14 -0
- package/appUtils/platform/platformUtils.ts +47 -4
- package/appUtils/playerManager/player.ts +2 -2
- package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
- package/idleUtils/index.ts +1 -1
- package/idleUtils/withTimeout.ts +15 -2
- package/logger/const.ts +9 -67
- package/manifestUtils/__tests__/createConfig.test.js +0 -2
- package/navigationUtils/index.ts +3 -3
- package/numberUtils/index.ts +7 -5
- package/package.json +2 -2
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +5 -7
- package/reactHooks/autoscrolling/useTrackedView.ts +12 -1
- package/reactHooks/cell-click/__tests__/index.test.js +5 -0
- package/reactHooks/cell-click/index.ts +7 -1
- package/reactHooks/feed/useFeedLoader.tsx +1 -1
- package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
- package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
- package/reactHooks/navigation/useGetTabBarHeight.ts +1 -3
- package/reactHooks/state/useRefWithInitialValue.ts +14 -0
- package/reactHooks/state/useStateFromSubscribe.ts +23 -0
- package/reactHooks/usePluginConfiguration.ts +1 -1
- package/reactHooks/useSubscriberFor.ts +4 -3
- package/screenState/index.ts +24 -10
- package/theme/index.ts +1 -1
- package/time/Timer.ts +5 -2
- package/types.ts +1 -0
- package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
|
@@ -17,9 +17,10 @@ class ActionExecutor {
|
|
|
17
17
|
|
|
18
18
|
handleAction = async (
|
|
19
19
|
action: ActionType,
|
|
20
|
-
|
|
20
|
+
context?: Record<string, any>
|
|
21
21
|
): Promise<ActionResult> => {
|
|
22
22
|
const handler = this.registeredActions[action.type];
|
|
23
|
+
const entry = context?.entry as ZappEntry;
|
|
23
24
|
|
|
24
25
|
if (!handler) {
|
|
25
26
|
log_error(
|
|
@@ -38,11 +39,11 @@ class ActionExecutor {
|
|
|
38
39
|
);
|
|
39
40
|
|
|
40
41
|
try {
|
|
41
|
-
return handler(action,
|
|
42
|
+
return handler(action, context);
|
|
42
43
|
} catch (error) {
|
|
43
44
|
log_error(
|
|
44
45
|
`handleAction: error handling action type: ${action.type}, message: ${error.message}`,
|
|
45
|
-
{ action,
|
|
46
|
+
{ action, context, error }
|
|
46
47
|
);
|
|
47
48
|
|
|
48
49
|
throw error;
|
|
@@ -51,11 +52,11 @@ class ActionExecutor {
|
|
|
51
52
|
|
|
52
53
|
handleActions = async (
|
|
53
54
|
actionTypes: ActionType[],
|
|
54
|
-
|
|
55
|
+
context?: Record<string, any>
|
|
55
56
|
): Promise<ActionResult> => {
|
|
56
57
|
for (const action of actionTypes) {
|
|
57
58
|
// TODO: Handle action result error
|
|
58
|
-
const result = await this.handleAction(action,
|
|
59
|
+
const result = await this.handleAction(action, context);
|
|
59
60
|
|
|
60
61
|
if (result === ActionResult.Cancel) {
|
|
61
62
|
log_info(`handleActions: action: ${action.type} canceled`);
|
|
@@ -67,7 +68,10 @@ class ActionExecutor {
|
|
|
67
68
|
return ActionResult.Success;
|
|
68
69
|
};
|
|
69
70
|
|
|
70
|
-
handleEntryActions = async (
|
|
71
|
+
handleEntryActions = async (
|
|
72
|
+
entry: ZappEntry,
|
|
73
|
+
context?: Record<string, any>
|
|
74
|
+
): Promise<ActionResult> => {
|
|
71
75
|
const tapActions = entry.extensions?.tap_actions?.actions;
|
|
72
76
|
|
|
73
77
|
if (!tapActions) {
|
|
@@ -77,7 +81,7 @@ class ActionExecutor {
|
|
|
77
81
|
if (!Array.isArray(tapActions)) {
|
|
78
82
|
log_error(
|
|
79
83
|
`handleEntryActions: tapActions is not an array for id: ${entry.id} title: ${entry.title}`,
|
|
80
|
-
{ entry }
|
|
84
|
+
{ context, entry }
|
|
81
85
|
);
|
|
82
86
|
|
|
83
87
|
return;
|
|
@@ -87,7 +91,7 @@ class ActionExecutor {
|
|
|
87
91
|
return;
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
await this.handleActions(tapActions, entry);
|
|
94
|
+
await this.handleActions(tapActions, { ...context, entry });
|
|
91
95
|
};
|
|
92
96
|
|
|
93
97
|
unregisterAction = (actionType: string) => {
|
|
@@ -96,7 +100,10 @@ class ActionExecutor {
|
|
|
96
100
|
|
|
97
101
|
registerAction = (
|
|
98
102
|
type: string,
|
|
99
|
-
handler: (
|
|
103
|
+
handler: (
|
|
104
|
+
action: ActionType,
|
|
105
|
+
context?: Record<string, any>
|
|
106
|
+
) => Promise<ActionResult>
|
|
100
107
|
) => {
|
|
101
108
|
if (this.registeredActions[type]) {
|
|
102
109
|
log_error(`registerAction: action type: ${type} already registered`);
|
|
@@ -13,6 +13,12 @@ import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
|
|
|
13
13
|
import { createLogger } from "../logger";
|
|
14
14
|
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
15
15
|
import { ACTIVE_LAYOUT_ID_STORAGE_KEY } from "@applicaster/quick-brick-core/App/remoteContextReloader/consts";
|
|
16
|
+
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
17
|
+
import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
18
|
+
import {
|
|
19
|
+
EntryResolver,
|
|
20
|
+
resolveObjectValues,
|
|
21
|
+
} from "../appUtils/contextKeysManager/contextResolver";
|
|
16
22
|
|
|
17
23
|
const { log_error, log_info } = createLogger({
|
|
18
24
|
subsystem: "ActionExecutorContext",
|
|
@@ -22,15 +28,24 @@ const { log_error, log_info } = createLogger({
|
|
|
22
28
|
type ActionExecutorContextType = {
|
|
23
29
|
registerAction: (
|
|
24
30
|
type: string,
|
|
25
|
-
handler: (
|
|
31
|
+
handler: (
|
|
32
|
+
action: ActionType,
|
|
33
|
+
context?: Record<string, any>
|
|
34
|
+
) => Promise<ActionResult>
|
|
26
35
|
) => void;
|
|
27
36
|
unregisterAction: (type: string) => void;
|
|
28
|
-
handleAction: (
|
|
37
|
+
handleAction: (
|
|
38
|
+
action: ActionType,
|
|
39
|
+
context?: Record<string, any>
|
|
40
|
+
) => Promise<ActionResult>;
|
|
29
41
|
handleActions: (
|
|
30
42
|
actions: ActionType[],
|
|
31
|
-
|
|
43
|
+
context: Record<string, any>
|
|
44
|
+
) => Promise<ActionResult>;
|
|
45
|
+
handleEntryActions: (
|
|
46
|
+
entry: ZappEntry,
|
|
47
|
+
context?: Record<string, any>
|
|
32
48
|
) => Promise<ActionResult>;
|
|
33
|
-
handleEntryActions: (entry: ZappEntry) => Promise<ActionResult>;
|
|
34
49
|
};
|
|
35
50
|
type Props = {
|
|
36
51
|
children: React.ReactNode;
|
|
@@ -45,6 +60,31 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
45
60
|
return ActionResult.Success;
|
|
46
61
|
});
|
|
47
62
|
|
|
63
|
+
actionExecutor.registerAction(
|
|
64
|
+
"refreshComponent",
|
|
65
|
+
async (_action, context) => {
|
|
66
|
+
const dispatch = appStore.getDispatch();
|
|
67
|
+
|
|
68
|
+
log_info("handleAction: refreshComponent event");
|
|
69
|
+
|
|
70
|
+
const dataSource = context?.component?.data?.source;
|
|
71
|
+
|
|
72
|
+
// TODO: Later we can pass component ids to do refresh instead of current one
|
|
73
|
+
// TODO: In theory we should wait callback to complete, before completing the action, but now it's not needed
|
|
74
|
+
// TODO: handle focused item removal
|
|
75
|
+
dispatch(
|
|
76
|
+
loadPipesData(dataSource, {
|
|
77
|
+
silentRefresh: false,
|
|
78
|
+
clearCache: true,
|
|
79
|
+
callback: (_data) => {},
|
|
80
|
+
riverId: context?.screenData?.id,
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return ActionResult.Success;
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
|
|
48
88
|
actionExecutor.registerAction("switchLayout", async (action) => {
|
|
49
89
|
log_info("handleAction: switchLayout event");
|
|
50
90
|
|
|
@@ -80,13 +120,21 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
80
120
|
return confirmationPromise;
|
|
81
121
|
});
|
|
82
122
|
|
|
83
|
-
actionExecutor.registerAction("sendCloudEvent", async (action,
|
|
123
|
+
actionExecutor.registerAction("sendCloudEvent", async (action, context) => {
|
|
84
124
|
try {
|
|
85
125
|
const options = action.options;
|
|
86
126
|
|
|
127
|
+
const entry = context?.entry || {};
|
|
128
|
+
const entryResolver = new EntryResolver(entry);
|
|
129
|
+
|
|
130
|
+
const data =
|
|
131
|
+
options?.data && options.inflateData
|
|
132
|
+
? await resolveObjectValues(options.data, { entry: entryResolver })
|
|
133
|
+
: options?.data || entry;
|
|
134
|
+
|
|
87
135
|
const cloudEvent = await createCloudEvent({
|
|
88
136
|
type: options.type || "com.applicaster.selector.action.v1",
|
|
89
|
-
data
|
|
137
|
+
data,
|
|
90
138
|
subject: options.subject || entry?.id,
|
|
91
139
|
});
|
|
92
140
|
|
|
@@ -117,9 +165,12 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
117
165
|
|
|
118
166
|
actionExecutor.registerAction(
|
|
119
167
|
"localStorageToggleFlag",
|
|
120
|
-
async (
|
|
168
|
+
async (
|
|
169
|
+
action: ActionType,
|
|
170
|
+
context?: Record<string, any>
|
|
171
|
+
): Promise<ActionResult> => {
|
|
121
172
|
const keyNamespace = action.options?.key;
|
|
122
|
-
const tag = entry?.extensions?.tag;
|
|
173
|
+
const tag = context?.entry?.extensions?.tag;
|
|
123
174
|
|
|
124
175
|
if (keyNamespace && tag) {
|
|
125
176
|
const multiSelectProvider =
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Alert } from "react-native";
|
|
2
|
+
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
3
|
+
import { confirmationDialogStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ConfirmDialogState";
|
|
4
|
+
|
|
5
|
+
// #region "Alert Dialog"
|
|
6
|
+
|
|
7
|
+
const globalAny: any = global;
|
|
8
|
+
|
|
9
|
+
const showWebAlertDialog = ({ message, completion }: AlertWebDialog) => {
|
|
10
|
+
globalAny?.alert?.(message);
|
|
11
|
+
completion?.();
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const showNativeAlertDialog = ({
|
|
15
|
+
title,
|
|
16
|
+
message,
|
|
17
|
+
okButtonText,
|
|
18
|
+
completion,
|
|
19
|
+
}: AlertDialogType) => {
|
|
20
|
+
Alert.alert(title, message, [
|
|
21
|
+
{
|
|
22
|
+
text: okButtonText,
|
|
23
|
+
onPress: completion,
|
|
24
|
+
},
|
|
25
|
+
]);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const showAlertDialog = ({
|
|
29
|
+
title,
|
|
30
|
+
message,
|
|
31
|
+
okButtonText,
|
|
32
|
+
completion,
|
|
33
|
+
}: AlertDialogType) => {
|
|
34
|
+
if (isWeb()) {
|
|
35
|
+
showWebAlertDialog({ message, completion });
|
|
36
|
+
} else {
|
|
37
|
+
showNativeAlertDialog({
|
|
38
|
+
title,
|
|
39
|
+
message,
|
|
40
|
+
okButtonText,
|
|
41
|
+
completion,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// #endregion "Alert Dialog"
|
|
47
|
+
|
|
48
|
+
// #region "Confirmation Dialog"
|
|
49
|
+
|
|
50
|
+
const showWebDialog = ({
|
|
51
|
+
message,
|
|
52
|
+
confirmCompletion,
|
|
53
|
+
cancelCompletion,
|
|
54
|
+
}: WebConfirmationDialog) => {
|
|
55
|
+
const isConfirmed = globalAny?.confirm?.(message);
|
|
56
|
+
|
|
57
|
+
if (isConfirmed) {
|
|
58
|
+
confirmCompletion?.();
|
|
59
|
+
} else {
|
|
60
|
+
cancelCompletion?.();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const showNativeDialog = ({
|
|
65
|
+
title,
|
|
66
|
+
message,
|
|
67
|
+
okButtonText,
|
|
68
|
+
cancelButtonText,
|
|
69
|
+
confirmCompletion,
|
|
70
|
+
cancelCompletion,
|
|
71
|
+
}: ConfirmationDialog) => {
|
|
72
|
+
Alert.alert(title, message, [
|
|
73
|
+
{
|
|
74
|
+
text: cancelButtonText,
|
|
75
|
+
onPress: cancelCompletion,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
text: okButtonText,
|
|
79
|
+
style: "destructive",
|
|
80
|
+
onPress: confirmCompletion,
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const handleCustomDialog = (data) => {
|
|
86
|
+
const {
|
|
87
|
+
showDialog,
|
|
88
|
+
hideDialog,
|
|
89
|
+
setConfirmAction,
|
|
90
|
+
setCancelAction,
|
|
91
|
+
setMessages,
|
|
92
|
+
} = confirmationDialogStore.getState();
|
|
93
|
+
|
|
94
|
+
setMessages(data.messages);
|
|
95
|
+
|
|
96
|
+
if (data?.cancelCompletion) {
|
|
97
|
+
setCancelAction(() => {
|
|
98
|
+
data.cancelCompletion();
|
|
99
|
+
hideDialog();
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (data?.confirmCompletion) {
|
|
104
|
+
setConfirmAction(() => {
|
|
105
|
+
data.confirmCompletion();
|
|
106
|
+
hideDialog();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
showDialog();
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const showConfirmationDialog = ({
|
|
114
|
+
title,
|
|
115
|
+
message,
|
|
116
|
+
okButtonText,
|
|
117
|
+
cancelButtonText,
|
|
118
|
+
confirmCompletion,
|
|
119
|
+
cancelCompletion,
|
|
120
|
+
}: CustomConfirmationDialog): void => {
|
|
121
|
+
if (isWeb()) {
|
|
122
|
+
if (cancelCompletion) {
|
|
123
|
+
handleCustomDialog({
|
|
124
|
+
messages: {
|
|
125
|
+
title,
|
|
126
|
+
message,
|
|
127
|
+
okButtonText,
|
|
128
|
+
cancelButtonText,
|
|
129
|
+
},
|
|
130
|
+
confirmCompletion,
|
|
131
|
+
cancelCompletion,
|
|
132
|
+
});
|
|
133
|
+
} else {
|
|
134
|
+
showWebDialog({ message, confirmCompletion, cancelCompletion });
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
showNativeDialog({
|
|
138
|
+
title,
|
|
139
|
+
message,
|
|
140
|
+
okButtonText,
|
|
141
|
+
cancelButtonText,
|
|
142
|
+
confirmCompletion,
|
|
143
|
+
cancelCompletion,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// #endregion "Confirmation Dialog"
|
package/alertUtils/index.ts
CHANGED
|
@@ -1,148 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
3
|
-
import { confirmationDialogStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ConfirmDialogState";
|
|
4
|
-
|
|
5
|
-
// #region "Alert Dialog"
|
|
6
|
-
|
|
7
|
-
const globalAny: any = global;
|
|
8
|
-
|
|
9
|
-
const showWebAlertDialog = ({ message, completion }: AlertWebDialog) => {
|
|
10
|
-
globalAny?.alert?.(message);
|
|
11
|
-
completion?.();
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const showNativeAlertDialog = ({
|
|
15
|
-
title,
|
|
16
|
-
message,
|
|
17
|
-
okButtonText,
|
|
18
|
-
completion,
|
|
19
|
-
}: AlertDialogType) => {
|
|
20
|
-
Alert.alert(title, message, [
|
|
21
|
-
{
|
|
22
|
-
text: okButtonText,
|
|
23
|
-
onPress: completion,
|
|
24
|
-
},
|
|
25
|
-
]);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const showAlertDialog = ({
|
|
29
|
-
title,
|
|
30
|
-
message,
|
|
31
|
-
okButtonText,
|
|
32
|
-
completion,
|
|
33
|
-
}: AlertDialogType) => {
|
|
34
|
-
if (isWeb()) {
|
|
35
|
-
showWebAlertDialog({ message, completion });
|
|
36
|
-
} else {
|
|
37
|
-
showNativeAlertDialog({
|
|
38
|
-
title,
|
|
39
|
-
message,
|
|
40
|
-
okButtonText,
|
|
41
|
-
completion,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// #endregion "Alert Dialog"
|
|
47
|
-
|
|
48
|
-
// #region "Confirmation Dialog"
|
|
49
|
-
|
|
50
|
-
const showWebDialog = ({
|
|
51
|
-
message,
|
|
52
|
-
confirmCompletion,
|
|
53
|
-
cancelCompletion,
|
|
54
|
-
}: WebConfirmationDialog) => {
|
|
55
|
-
const isConfirmed = globalAny?.confirm?.(message);
|
|
56
|
-
|
|
57
|
-
if (isConfirmed) {
|
|
58
|
-
confirmCompletion?.();
|
|
59
|
-
} else {
|
|
60
|
-
cancelCompletion?.();
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const showNativeDialog = ({
|
|
65
|
-
title,
|
|
66
|
-
message,
|
|
67
|
-
okButtonText,
|
|
68
|
-
cancelButtonText,
|
|
69
|
-
confirmCompletion,
|
|
70
|
-
cancelCompletion,
|
|
71
|
-
}: ConfirmationDialog) => {
|
|
72
|
-
Alert.alert(title, message, [
|
|
73
|
-
{
|
|
74
|
-
text: cancelButtonText,
|
|
75
|
-
onPress: cancelCompletion,
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
text: okButtonText,
|
|
79
|
-
style: "destructive",
|
|
80
|
-
onPress: confirmCompletion,
|
|
81
|
-
},
|
|
82
|
-
]);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const handleCustomDialog = (data) => {
|
|
86
|
-
const {
|
|
87
|
-
showDialog,
|
|
88
|
-
hideDialog,
|
|
89
|
-
setConfirmAction,
|
|
90
|
-
setCancelAction,
|
|
91
|
-
setMessages,
|
|
92
|
-
} = confirmationDialogStore.getState();
|
|
93
|
-
|
|
94
|
-
setMessages(data.messages);
|
|
95
|
-
|
|
96
|
-
if (data?.cancelCompletion) {
|
|
97
|
-
setCancelAction(() => {
|
|
98
|
-
data.cancelCompletion();
|
|
99
|
-
hideDialog();
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (data?.confirmCompletion) {
|
|
104
|
-
setConfirmAction(() => {
|
|
105
|
-
data.confirmCompletion();
|
|
106
|
-
hideDialog();
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
showDialog();
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export const showConfirmationDialog = ({
|
|
114
|
-
title,
|
|
115
|
-
message,
|
|
116
|
-
okButtonText,
|
|
117
|
-
cancelButtonText,
|
|
118
|
-
confirmCompletion,
|
|
119
|
-
cancelCompletion,
|
|
120
|
-
}: CustomConfirmationDialog): void => {
|
|
121
|
-
if (isWeb()) {
|
|
122
|
-
if (cancelCompletion) {
|
|
123
|
-
handleCustomDialog({
|
|
124
|
-
messages: {
|
|
125
|
-
title,
|
|
126
|
-
message,
|
|
127
|
-
okButtonText,
|
|
128
|
-
cancelButtonText,
|
|
129
|
-
},
|
|
130
|
-
confirmCompletion,
|
|
131
|
-
cancelCompletion,
|
|
132
|
-
});
|
|
133
|
-
} else {
|
|
134
|
-
showWebDialog({ message, confirmCompletion, cancelCompletion });
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
showNativeDialog({
|
|
138
|
-
title,
|
|
139
|
-
message,
|
|
140
|
-
okButtonText,
|
|
141
|
-
cancelButtonText,
|
|
142
|
-
confirmCompletion,
|
|
143
|
-
cancelCompletion,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
// #endregion "Confirmation Dialog"
|
|
1
|
+
export { showAlertDialog, showConfirmationDialog } from "./alert";
|
|
@@ -16,7 +16,7 @@ const BASE_HOOK_PROPERTIES = ["screen_id", "identifier", "weight"];
|
|
|
16
16
|
* @returns {number} index
|
|
17
17
|
*/
|
|
18
18
|
const hookState: (
|
|
19
|
-
arg0: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS]
|
|
19
|
+
arg0: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS]
|
|
20
20
|
) => number = R.indexOf(R.__, R.values(HOOKS_EVENTS));
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -62,7 +62,7 @@ export class Hook implements HookInterface {
|
|
|
62
62
|
* @param {Array<Any>} args variadic arguments to invoke the handler with
|
|
63
63
|
*/
|
|
64
64
|
setStateAndNotify(
|
|
65
|
-
event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
|
|
65
|
+
event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
|
|
66
66
|
...args
|
|
67
67
|
) {
|
|
68
68
|
this.state = hookState(event);
|
|
@@ -4,6 +4,8 @@ import { HOOKS_EVENTS } from "./constants";
|
|
|
4
4
|
export interface HookConfiguration {}
|
|
5
5
|
|
|
6
6
|
/* existing Hook Plugn props: sample */
|
|
7
|
+
|
|
8
|
+
/*
|
|
7
9
|
interface _HookModulePlugin {
|
|
8
10
|
Component:
|
|
9
11
|
| React.FC<HookPluginProps>
|
|
@@ -23,6 +25,7 @@ interface _HookModulePlugin {
|
|
|
23
25
|
presentUI: (payload?: HookPluginProps["payload"]) => void
|
|
24
26
|
) => any;
|
|
25
27
|
}
|
|
28
|
+
*/
|
|
26
29
|
|
|
27
30
|
//* Derived from usage */
|
|
28
31
|
export interface HookModule {
|
|
@@ -100,7 +103,7 @@ export interface Hook<T extends HookModule = HookModule> {
|
|
|
100
103
|
identifier: string;
|
|
101
104
|
configuration: T["configuration"];
|
|
102
105
|
setStateAndNotify(
|
|
103
|
-
event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
|
|
106
|
+
event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
|
|
104
107
|
opts: {
|
|
105
108
|
error?: typeof Error;
|
|
106
109
|
route?: string;
|
|
@@ -109,7 +112,7 @@ export interface Hook<T extends HookModule = HookModule> {
|
|
|
109
112
|
}
|
|
110
113
|
);
|
|
111
114
|
general?: {
|
|
112
|
-
transition_type: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS];
|
|
115
|
+
transition_type: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS];
|
|
113
116
|
allow_screen_plugin_presentation: boolean;
|
|
114
117
|
is_flow_blocker: boolean;
|
|
115
118
|
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createLogger } from "../../logger";
|
|
2
|
+
import { ContextKeysManager } from "./index";
|
|
3
|
+
import * as R from "ramda";
|
|
4
|
+
|
|
5
|
+
const { log_error } = createLogger({
|
|
6
|
+
subsystem: "contextResolver",
|
|
7
|
+
category: "General",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
interface IResolver {
|
|
11
|
+
resolve: (string) => Promise<string | number | object>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class EntryResolver implements IResolver {
|
|
15
|
+
entry: ZappEntry;
|
|
16
|
+
|
|
17
|
+
constructor(entry: ZappEntry) {
|
|
18
|
+
this.entry = entry;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async resolve(key: string) {
|
|
22
|
+
if (!key || key.length === 0) {
|
|
23
|
+
return this.entry;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return R.view(R.lensPath(key.split(".")), this.entry);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class ContextResolver implements IResolver {
|
|
31
|
+
resolve = async (compositeKey: string) =>
|
|
32
|
+
ContextKeysManager.instance.getKey(compositeKey);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const resolveObjectValues = async (
|
|
36
|
+
data: Record<string, any>,
|
|
37
|
+
resolvers: Record<string, IResolver> = null
|
|
38
|
+
) => {
|
|
39
|
+
const entries = Object.entries(data);
|
|
40
|
+
|
|
41
|
+
const exResolvers = { ctx: new ContextResolver(), ...resolvers };
|
|
42
|
+
|
|
43
|
+
const resolvedEntries = await Promise.all(
|
|
44
|
+
entries.map(async ([key, value]) => {
|
|
45
|
+
if (typeof value !== "string") {
|
|
46
|
+
return [key, value];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!value.startsWith("@")) {
|
|
50
|
+
return [key, value];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const regex = /@{([^/]+)\/([^}]*)}/;
|
|
54
|
+
|
|
55
|
+
const match = (value as string).match(regex);
|
|
56
|
+
|
|
57
|
+
if (match) {
|
|
58
|
+
const contextResolverName = match[1];
|
|
59
|
+
const compositeKey = match[2];
|
|
60
|
+
|
|
61
|
+
const resolver = exResolvers[contextResolverName] || exResolvers.ctx;
|
|
62
|
+
const resolvedValue = await resolver.resolve(compositeKey);
|
|
63
|
+
|
|
64
|
+
return [key, resolvedValue];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
log_error("resolveObjectValues: invalid context string", {
|
|
68
|
+
key,
|
|
69
|
+
value,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return [key, null];
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return Object.fromEntries(resolvedEntries);
|
|
77
|
+
};
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { subscriber } from "../../functionUtils";
|
|
14
14
|
import { coreLogger } from "../../logger";
|
|
15
15
|
import { ACTION } from "./utils/enums";
|
|
16
|
+
|
|
16
17
|
const logger = coreLogger.addSubsystem("focusManager");
|
|
17
18
|
|
|
18
19
|
const isFocusEnabled = (focusableItem): boolean => {
|
|
@@ -325,8 +326,6 @@ export const focusManager = (function () {
|
|
|
325
326
|
},
|
|
326
327
|
});
|
|
327
328
|
|
|
328
|
-
currentFocusNode = focusCandidate;
|
|
329
|
-
|
|
330
329
|
focusableItem && setFocus(focusCandidate.id, null);
|
|
331
330
|
|
|
332
331
|
return { success: true };
|
|
@@ -346,6 +345,14 @@ export const focusManager = (function () {
|
|
|
346
345
|
});
|
|
347
346
|
}
|
|
348
347
|
|
|
348
|
+
function pressIn() {
|
|
349
|
+
const currentFocusable = getCurrentFocus();
|
|
350
|
+
|
|
351
|
+
if (currentFocusable) {
|
|
352
|
+
currentFocusable.pressIn(null);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
349
356
|
/**
|
|
350
357
|
* calls the `press` method on the current focus component
|
|
351
358
|
* @public
|
|
@@ -477,7 +484,7 @@ export const focusManager = (function () {
|
|
|
477
484
|
function isCurrentFocusOnTheTopScreen() {
|
|
478
485
|
const routes = R.pathOr([], ["root", "children"], focusableTree);
|
|
479
486
|
|
|
480
|
-
if (routes.length <= 1) {
|
|
487
|
+
if (currentFocusNode && routes.length <= 1) {
|
|
481
488
|
// there is only one or zero routes
|
|
482
489
|
return true;
|
|
483
490
|
}
|
|
@@ -553,6 +560,7 @@ export const focusManager = (function () {
|
|
|
553
560
|
invokeHandler,
|
|
554
561
|
removeHandler,
|
|
555
562
|
longPress,
|
|
563
|
+
pressIn,
|
|
556
564
|
pressOut,
|
|
557
565
|
enableFocus,
|
|
558
566
|
setInitialFocus,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
2
|
-
import { find, last,
|
|
2
|
+
import { find, last, pathOr, startsWith } from "ramda";
|
|
3
3
|
import {
|
|
4
|
-
QUICK_BRICK_NAVBAR,
|
|
5
4
|
QUICK_BRICK_CONTENT,
|
|
5
|
+
QUICK_BRICK_NAVBAR,
|
|
6
6
|
} from "@applicaster/quick-brick-core/const";
|
|
7
7
|
|
|
8
8
|
// run check each 300 ms
|
|
@@ -66,7 +66,8 @@ export const getContentNode = (focusableTree) => {
|
|
|
66
66
|
const content = find(
|
|
67
67
|
(child) =>
|
|
68
68
|
startsWith(QUICK_BRICK_CONTENT, child.id) ||
|
|
69
|
-
startsWith("player", child.id)
|
|
69
|
+
startsWith("player", child.id) ||
|
|
70
|
+
startsWith("/hooks", child?.parent?.id), // For startup hooks case
|
|
70
71
|
getActiveScreenChildren(focusableTree)
|
|
71
72
|
);
|
|
72
73
|
|