@applicaster/zapp-react-native-utils 14.0.0-alpha.4011674803 → 14.0.0-alpha.4055325032
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/ActionExecutorContext.tsx +1 -1
- package/analyticsUtils/AnalyticsEvents/helper.ts +81 -0
- package/analyticsUtils/AnalyticsEvents/sendOnClickEvent.ts +14 -4
- package/analyticsUtils/__tests__/analyticsUtils.test.js +14 -0
- package/analyticsUtils/events.ts +8 -0
- package/appUtils/accessibilityManager/index.ts +3 -3
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +0 -15
- package/appUtils/playerManager/useChapterMarker.tsx +0 -1
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +16 -0
- package/arrayUtils/__tests__/isEmptyArray.test.ts +63 -0
- package/arrayUtils/__tests__/isFilledArray.test.ts +1 -1
- package/arrayUtils/index.ts +7 -2
- package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +54 -0
- package/audioPlayerUtils/index.ts +135 -22
- package/conf/player/__tests__/selectors.test.ts +34 -0
- package/conf/player/selectors.ts +10 -0
- package/configurationUtils/__tests__/configurationUtils.test.js +0 -31
- package/configurationUtils/__tests__/getMediaItems.test.ts +65 -0
- package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +34 -0
- package/configurationUtils/index.ts +63 -34
- package/focusManager/FocusManager.ts +26 -16
- package/focusManager/Tree.ts +25 -21
- package/focusManager/__tests__/FocusManager.test.ts +50 -8
- package/manifestUtils/_internals/getDefaultConfiguration.js +28 -0
- package/manifestUtils/{_internals.js → _internals/index.js} +2 -25
- package/manifestUtils/createConfig.js +4 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +2431 -1244
- package/manifestUtils/keys.js +12 -0
- package/manifestUtils/progressBar/__tests__/mobileProgressBar.test.js +0 -30
- package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +6 -0
- package/package.json +2 -2
- package/playerUtils/__tests__/configurationUtils.test.ts +1 -65
- package/playerUtils/__tests__/getPlayerActionButtons.test.ts +54 -0
- package/playerUtils/_internals/__tests__/utils.test.ts +71 -0
- package/playerUtils/_internals/index.ts +1 -0
- package/playerUtils/_internals/utils.ts +31 -0
- package/playerUtils/configurationUtils.ts +0 -44
- package/playerUtils/getPlayerActionButtons.ts +17 -0
- package/playerUtils/index.ts +53 -0
- package/playerUtils/useValidatePlayerConfig.tsx +22 -19
- package/reactHooks/feed/useBatchLoading.ts +3 -3
- package/reactHooks/feed/usePipesCacheReset.ts +1 -1
- package/reactHooks/layout/isTablet/index.ts +12 -5
- package/reactHooks/navigation/useIsScreenActive.ts +9 -5
- package/reactHooks/screen/useScreenContext.ts +1 -1
- package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +2 -1
- package/riverComponetsMeasurementProvider/index.tsx +1 -1
- package/services/js2native.ts +1 -0
- package/time/BackgroundTimer.ts +5 -3
- package/utils/index.ts +8 -2
- package/playerUtils/configurationGenerator.ts +0 -2572
- package/utils/isPresent.ts +0 -4
|
@@ -4,9 +4,12 @@ import {
|
|
|
4
4
|
ANALYTICS_COMPONENT_EVENTS,
|
|
5
5
|
ANALYTICS_CORE_EVENTS,
|
|
6
6
|
ANALYTICS_ENTRY_EVENTS,
|
|
7
|
+
ANALYTICS_PREFERENCES_EVENTS,
|
|
7
8
|
DOWNLOADS_EVENTS,
|
|
8
9
|
} from "../events";
|
|
9
10
|
import { isEmptyOrNil } from "../../cellUtils";
|
|
11
|
+
import { get } from "lodash";
|
|
12
|
+
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
10
13
|
|
|
11
14
|
export enum OfflineItemState {
|
|
12
15
|
notExist = "NOT_EXISTS",
|
|
@@ -102,6 +105,84 @@ export function eventForComponent(
|
|
|
102
105
|
return analyticsProps;
|
|
103
106
|
}
|
|
104
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Checks if an item is currently selected in localStorage based on its actions
|
|
110
|
+
* @param item - The item to check
|
|
111
|
+
* @returns boolean indicating if the item is currently selected
|
|
112
|
+
*/
|
|
113
|
+
function isItemPreviouslySelected(item: any): boolean {
|
|
114
|
+
const actions = item?.extensions?.tap_actions?.actions;
|
|
115
|
+
|
|
116
|
+
if (!actions) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const localStorageAction = actions.find(
|
|
121
|
+
(action) => action?.type === "localStorageToggleFlag"
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (!localStorageAction?.options?.key) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const keyNamespace = localStorageAction.options.key;
|
|
129
|
+
|
|
130
|
+
const tag = localStorageAction.options?.selector
|
|
131
|
+
? get(item, localStorageAction.options.selector)
|
|
132
|
+
: (item.extensions?.tag ?? item.id);
|
|
133
|
+
|
|
134
|
+
if (!tag) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const multiSelectProvider =
|
|
140
|
+
StorageMultiSelectProvider.getProvider(keyNamespace);
|
|
141
|
+
|
|
142
|
+
const selectedItems = multiSelectProvider.getSelectedItems();
|
|
143
|
+
|
|
144
|
+
return selectedItems.includes(tag);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function getLocalStorageSetPayload(extraProps) {
|
|
151
|
+
const { item } = extraProps;
|
|
152
|
+
|
|
153
|
+
const hasLocalStorageSetAction = item?.extensions?.tap_actions?.actions?.some(
|
|
154
|
+
(action) => action?.type === "localStorageSet"
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (!hasLocalStorageSetAction) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
[ANALYTICS_PREFERENCES_EVENTS.ITEM_SELECTED_STATUS]: true,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function getLocalStorageToggleFlagPayload(extraProps) {
|
|
167
|
+
const { item } = extraProps;
|
|
168
|
+
|
|
169
|
+
const hasLocalStorageToggleAction =
|
|
170
|
+
item?.extensions?.tap_actions?.actions?.some(
|
|
171
|
+
(action) => action?.type === "localStorageToggleFlag"
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
if (!hasLocalStorageToggleAction) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const previouslySelected = isItemPreviouslySelected(item);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
[ANALYTICS_PREFERENCES_EVENTS.ITEM_SELECTED_STATUS]: !previouslySelected,
|
|
182
|
+
[ANALYTICS_PREFERENCES_EVENTS.PREVIOUS_SELECTED_STATE]: previouslySelected,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
105
186
|
export function playEventForType(item) {
|
|
106
187
|
const itemType = item?.type && item.type?.value;
|
|
107
188
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { log_error, log_debug } from "../logger";
|
|
2
|
-
|
|
3
|
-
import { ANALYTICS_CORE_EVENTS } from "../events";
|
|
4
|
-
|
|
2
|
+
import { ANALYTICS_CORE_EVENTS, ACTION_TYPE } from "../events";
|
|
5
3
|
import { postAnalyticEvent } from "../manager";
|
|
6
4
|
import {
|
|
7
5
|
replaceAnalyticsPropsNils,
|
|
8
6
|
eventForEntry,
|
|
9
7
|
eventForComponent,
|
|
10
8
|
extensionsEvents,
|
|
9
|
+
getLocalStorageSetPayload,
|
|
10
|
+
getLocalStorageToggleFlagPayload,
|
|
11
11
|
} from "./helper";
|
|
12
12
|
|
|
13
13
|
declare type AnalyticsDefaultHelperProperties = {
|
|
@@ -26,7 +26,16 @@ export const sendOnClickEvent = ({
|
|
|
26
26
|
const castedExtraProps: ExtraProps = extraProps;
|
|
27
27
|
const componentData = component || extraProps.component;
|
|
28
28
|
const data = zappPipesData || extraProps.zappPipesData;
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
const actionCellPayload =
|
|
31
|
+
extraProps?.item?.type?.value === ACTION_TYPE
|
|
32
|
+
? getLocalStorageSetPayload(extraProps) ||
|
|
33
|
+
getLocalStorageToggleFlagPayload(extraProps)
|
|
34
|
+
: null;
|
|
35
|
+
|
|
36
|
+
const eventName = actionCellPayload
|
|
37
|
+
? ANALYTICS_CORE_EVENTS.TAP_SELECTABLE_CELL
|
|
38
|
+
: ANALYTICS_CORE_EVENTS.TAP_CELL;
|
|
30
39
|
|
|
31
40
|
if (!analyticsScreenData) {
|
|
32
41
|
log_error(
|
|
@@ -44,6 +53,7 @@ export const sendOnClickEvent = ({
|
|
|
44
53
|
...replaceAnalyticsPropsNils({
|
|
45
54
|
...analyticsScreenData,
|
|
46
55
|
}),
|
|
56
|
+
...actionCellPayload,
|
|
47
57
|
};
|
|
48
58
|
|
|
49
59
|
if (analyticsCustomProperties) {
|
|
@@ -3,8 +3,22 @@ import { ANALYTICS_CORE_EVENTS } from "../events";
|
|
|
3
3
|
|
|
4
4
|
jest.mock("@applicaster/zapp-react-native-utils/reactUtils", () => ({
|
|
5
5
|
isWeb: jest.fn(),
|
|
6
|
+
platformSelect: jest.fn(
|
|
7
|
+
(options) => options.android || options.ios || options.web
|
|
8
|
+
),
|
|
6
9
|
}));
|
|
7
10
|
|
|
11
|
+
jest.mock(
|
|
12
|
+
"@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider",
|
|
13
|
+
() => ({
|
|
14
|
+
StorageMultiSelectProvider: {
|
|
15
|
+
getProvider: jest.fn(() => ({
|
|
16
|
+
getSelectedItems: jest.fn(() => []),
|
|
17
|
+
})),
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
|
|
8
22
|
const mock_postAnalyticEvent = jest.fn();
|
|
9
23
|
const mock_startAnalyticsTimedEvent = jest.fn();
|
|
10
24
|
const mock_endAnalyticsTimedEvent = jest.fn();
|
package/analyticsUtils/events.ts
CHANGED
|
@@ -17,8 +17,11 @@ export const SCREEN_VIEW_EVENTS = {
|
|
|
17
17
|
TIME_ON_SCREEN: "time_on_screen",
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
export const ACTION_TYPE = "action";
|
|
21
|
+
|
|
20
22
|
export const TAPPING_EVENTS = {
|
|
21
23
|
TAP_CELL: "tap_cell",
|
|
24
|
+
TAP_SELECTABLE_CELL: "tap_selectable_cell",
|
|
22
25
|
TAP_MENU: "tap_menu",
|
|
23
26
|
TAP_NAVBAR_BACK_BUTTON: "tap_navbar_back_button",
|
|
24
27
|
};
|
|
@@ -99,6 +102,11 @@ export const ANALYTICS_COMPONENT_EVENTS = {
|
|
|
99
102
|
COMPONENT_SOURCE: "component_source",
|
|
100
103
|
};
|
|
101
104
|
|
|
105
|
+
export const ANALYTICS_PREFERENCES_EVENTS = {
|
|
106
|
+
ITEM_SELECTED_STATUS: "item_selected_status",
|
|
107
|
+
PREVIOUS_SELECTED_STATE: "previous_selected_state",
|
|
108
|
+
};
|
|
109
|
+
|
|
102
110
|
// ---------------- EVENTS ---------------------
|
|
103
111
|
export const AD_EVENT = {
|
|
104
112
|
ad_break_start: "player_ad_break_start",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
2
|
import { accessibilityManagerLogger as logger } from "./logger";
|
|
3
|
-
import { TTSManager } from "../platform
|
|
3
|
+
import { TTSManager } from "../platform";
|
|
4
4
|
import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
|
|
5
5
|
import { AccessibilityRole } from "react-native";
|
|
6
|
-
import
|
|
6
|
+
import { toString } from "../../utils";
|
|
7
7
|
|
|
8
8
|
export class AccessibilityManager {
|
|
9
9
|
private static _instance: AccessibilityManager | null = null;
|
|
@@ -137,7 +137,7 @@ export class AccessibilityManager {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
public getButtonAccessibilityProps(name: string): AccessibilityProps {
|
|
140
|
-
const buttonName =
|
|
140
|
+
const buttonName = toString(name);
|
|
141
141
|
|
|
142
142
|
const buttonConfig = BUTTON_ACCESSIBILITY_KEYS[buttonName];
|
|
143
143
|
|
|
@@ -18,13 +18,6 @@ export const { log_verbose, log_debug, log_info, log_error } = createLogger({
|
|
|
18
18
|
parent: utilsLogger,
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
type ActionChapter = {
|
|
22
|
-
type: string;
|
|
23
|
-
options?: {
|
|
24
|
-
title: string;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
21
|
type ChapterMarkerOriginal = {
|
|
29
22
|
id: string;
|
|
30
23
|
title: string;
|
|
@@ -33,14 +26,6 @@ type ChapterMarkerOriginal = {
|
|
|
33
26
|
actions: ActionChapter[];
|
|
34
27
|
};
|
|
35
28
|
|
|
36
|
-
export type ChapterMarkerEvent = {
|
|
37
|
-
id: string;
|
|
38
|
-
title: string;
|
|
39
|
-
start_time: number;
|
|
40
|
-
end_time: number;
|
|
41
|
-
actions: ActionChapter[];
|
|
42
|
-
};
|
|
43
|
-
|
|
44
29
|
export type TitleSummaryEvent = {
|
|
45
30
|
title: string | number;
|
|
46
31
|
summary: string | number;
|
|
@@ -5,6 +5,9 @@ import { playerManager } from "./index";
|
|
|
5
5
|
import { useValidatePlayerConfig } from "../../playerUtils/useValidatePlayerConfig";
|
|
6
6
|
import { PlayerRole } from "./conts";
|
|
7
7
|
import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
|
|
8
|
+
import { TVSeekController } from "../../reactHooks/player/TVSeekControlller/TVSeekController";
|
|
9
|
+
import { KeyInputHandler } from "../keyInputHandler/KeyInputHandler";
|
|
10
|
+
import { isTV } from "../../reactUtils";
|
|
8
11
|
|
|
9
12
|
// TODO: Rename to ControllerType
|
|
10
13
|
export const usePlayerControllerSetup = ({
|
|
@@ -76,5 +79,18 @@ export const usePlayerControllerSetup = ({
|
|
|
76
79
|
};
|
|
77
80
|
}, [playerId, playerController]);
|
|
78
81
|
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (!isTV()) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (playerController) {
|
|
88
|
+
const seekController = new TVSeekController(playerController);
|
|
89
|
+
playerController.seekController = seekController;
|
|
90
|
+
|
|
91
|
+
return KeyInputHandler.getInstance().addListener(seekController);
|
|
92
|
+
}
|
|
93
|
+
}, [playerController]);
|
|
94
|
+
|
|
79
95
|
return playerController;
|
|
80
96
|
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { isEmptyArray } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isEmptyArray", () => {
|
|
4
|
+
it("non-empty array is not empty", () => {
|
|
5
|
+
const value = [1, 2, 3];
|
|
6
|
+
|
|
7
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("empty array is empty", () => {
|
|
11
|
+
const value = [];
|
|
12
|
+
|
|
13
|
+
expect(isEmptyArray(value)).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("number is not array", () => {
|
|
17
|
+
const value = 123;
|
|
18
|
+
|
|
19
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("string is not array", () => {
|
|
23
|
+
const value = "vfnjdk";
|
|
24
|
+
|
|
25
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("empty string is not array", () => {
|
|
29
|
+
const value = "";
|
|
30
|
+
|
|
31
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("NaN is not array", () => {
|
|
35
|
+
const value = NaN;
|
|
36
|
+
|
|
37
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("object is not array", () => {
|
|
41
|
+
const value = { test: 1 };
|
|
42
|
+
|
|
43
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("empty object is not array", () => {
|
|
47
|
+
const value = {};
|
|
48
|
+
|
|
49
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("undefined is not array", () => {
|
|
53
|
+
const value = undefined;
|
|
54
|
+
|
|
55
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("null is not array", () => {
|
|
59
|
+
const value = null;
|
|
60
|
+
|
|
61
|
+
expect(isEmptyArray(value)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
package/arrayUtils/index.ts
CHANGED
|
@@ -99,12 +99,17 @@ export const makeListOf = (value: unknown, size: number): number[] => {
|
|
|
99
99
|
|
|
100
100
|
/** Checks if a value is a non-empty array */
|
|
101
101
|
export function isFilledArray(value: unknown): boolean {
|
|
102
|
-
return
|
|
102
|
+
return Array.isArray(value) && value.length > 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Checks if a value is a empty array */
|
|
106
|
+
export function isEmptyArray(value: unknown): boolean {
|
|
107
|
+
return Array.isArray(value) && value.length === 0;
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
// get random item from the list
|
|
106
111
|
export const sample = (xs: unknown[]): unknown => {
|
|
107
|
-
invariant(
|
|
112
|
+
invariant(Array.isArray(xs), `input value is not an array: ${xs}`);
|
|
108
113
|
invariant(isFilledArray(xs), `input array is empty: ${xs}`);
|
|
109
114
|
|
|
110
115
|
const index = Math.floor(Math.random() * xs.length);
|
|
@@ -53,4 +53,58 @@ describe("getImageFromEntry", () => {
|
|
|
53
53
|
|
|
54
54
|
expect(result).toBeUndefined();
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
it("returns undefined for non string src", () => {
|
|
58
|
+
const entryWithNonStringSrc = {
|
|
59
|
+
media_group: [
|
|
60
|
+
{
|
|
61
|
+
media_item: [
|
|
62
|
+
{
|
|
63
|
+
key: "image_base_key",
|
|
64
|
+
src: 123,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: "thumb_1",
|
|
68
|
+
src: null,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
type: "image",
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const result = getImageFromEntry({
|
|
77
|
+
entry: entryWithNonStringSrc,
|
|
78
|
+
imageKey: "image_base_key",
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(result).toBeUndefined();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("returns undefined for empty src", () => {
|
|
85
|
+
const entryWithEmptySrc = {
|
|
86
|
+
media_group: [
|
|
87
|
+
{
|
|
88
|
+
media_item: [
|
|
89
|
+
{
|
|
90
|
+
key: "image_base_key",
|
|
91
|
+
src: "",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
key: "thumb_1",
|
|
95
|
+
src: null,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
type: "image",
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const result = getImageFromEntry({
|
|
104
|
+
entry: entryWithEmptySrc,
|
|
105
|
+
imageKey: "image_base_key",
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(result).toBeUndefined();
|
|
109
|
+
});
|
|
56
110
|
});
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { get, has } from "@applicaster/zapp-react-native-utils/utils";
|
|
3
|
+
import { useZStore } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
4
|
+
import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
|
+
|
|
6
|
+
import { isNotEmptyString } from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
7
|
+
import { getMediaItems } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
2
8
|
|
|
3
9
|
import { DEFAULT_IMAGE } from "./assets";
|
|
4
10
|
|
|
@@ -9,20 +15,9 @@ export function getImageFromEntry({
|
|
|
9
15
|
entry: ZappEntry;
|
|
10
16
|
imageKey: Option<string>;
|
|
11
17
|
}): Option<string> {
|
|
12
|
-
const
|
|
18
|
+
const mediaItems = getMediaItems(entry);
|
|
13
19
|
|
|
14
|
-
if (!
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Find all media_items from groups of type 'image'
|
|
19
|
-
const mediaItems = mediaGroup
|
|
20
|
-
.filter((group) => group.type === "image")
|
|
21
|
-
.flatMap((group) =>
|
|
22
|
-
Array.isArray(group.media_item) ? group.media_item : [group.media_item]
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
if (!Array.isArray(mediaItems) || mediaItems.length === 0) {
|
|
20
|
+
if (!mediaItems) {
|
|
26
21
|
return undefined;
|
|
27
22
|
}
|
|
28
23
|
|
|
@@ -31,15 +26,28 @@ export function getImageFromEntry({
|
|
|
31
26
|
const src = found?.src;
|
|
32
27
|
|
|
33
28
|
// Special case for react native - uri cannot be an empty string (yellow warning).
|
|
34
|
-
return
|
|
29
|
+
return isNotEmptyString(src) ? src : undefined;
|
|
35
30
|
}
|
|
36
31
|
|
|
37
|
-
const getPropertyFromExtensions = (
|
|
32
|
+
const getPropertyFromExtensions = (
|
|
33
|
+
key: string,
|
|
34
|
+
entry: ZappEntry
|
|
35
|
+
): Option<string> => entry?.extensions?.[key];
|
|
38
36
|
|
|
39
|
-
const getPropertyFromConfiguration = (
|
|
40
|
-
|
|
37
|
+
const getPropertyFromConfiguration = (
|
|
38
|
+
key: string,
|
|
39
|
+
plugin_configuration: Record<string, any>
|
|
40
|
+
) => plugin_configuration?.[key];
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
type GetBackgroundImageParams = {
|
|
43
|
+
entry: ZappEntry;
|
|
44
|
+
plugin_configuration: Record<string, any>;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const getBackgroundImage = ({
|
|
48
|
+
entry,
|
|
49
|
+
plugin_configuration,
|
|
50
|
+
}: GetBackgroundImageParams): string => {
|
|
43
51
|
// 1) image_key from extensions
|
|
44
52
|
const imageKeyFromExtensions = getPropertyFromExtensions("image_key", entry);
|
|
45
53
|
|
|
@@ -58,7 +66,7 @@ export const getBackgroundImage = ({ entry, plugin_configuration }): string => {
|
|
|
58
66
|
entry
|
|
59
67
|
);
|
|
60
68
|
|
|
61
|
-
if (audioPlayerBackgroundImageFromExtensions) {
|
|
69
|
+
if (isNotEmptyString(audioPlayerBackgroundImageFromExtensions)) {
|
|
62
70
|
return audioPlayerBackgroundImageFromExtensions;
|
|
63
71
|
}
|
|
64
72
|
|
|
@@ -84,7 +92,7 @@ export const getBackgroundImage = ({ entry, plugin_configuration }): string => {
|
|
|
84
92
|
plugin_configuration
|
|
85
93
|
);
|
|
86
94
|
|
|
87
|
-
if (audioPlayerBackgroundImageFromConfiguration) {
|
|
95
|
+
if (isNotEmptyString(audioPlayerBackgroundImageFromConfiguration)) {
|
|
88
96
|
return audioPlayerBackgroundImageFromConfiguration;
|
|
89
97
|
}
|
|
90
98
|
|
|
@@ -92,11 +100,17 @@ export const getBackgroundImage = ({ entry, plugin_configuration }): string => {
|
|
|
92
100
|
return DEFAULT_IMAGE;
|
|
93
101
|
};
|
|
94
102
|
|
|
103
|
+
type GetArtworkImageParams = {
|
|
104
|
+
key: string;
|
|
105
|
+
entry: ZappEntry;
|
|
106
|
+
plugin_configuration: Record<string, any>;
|
|
107
|
+
};
|
|
108
|
+
|
|
95
109
|
export const getArtworkImage = ({
|
|
96
110
|
key,
|
|
97
111
|
entry,
|
|
98
112
|
plugin_configuration,
|
|
99
|
-
}): string => {
|
|
113
|
+
}: GetArtworkImageParams): string => {
|
|
100
114
|
// 1) image_key from extensions
|
|
101
115
|
const imageKeyFromExtensions = getPropertyFromExtensions(key, entry);
|
|
102
116
|
|
|
@@ -127,3 +141,102 @@ export const getArtworkImage = ({
|
|
|
127
141
|
// default image
|
|
128
142
|
return DEFAULT_IMAGE;
|
|
129
143
|
};
|
|
144
|
+
|
|
145
|
+
const useAdjustedKeyFromScreenData = ({ config, keys }) => {
|
|
146
|
+
const { screenData } = useRoute();
|
|
147
|
+
|
|
148
|
+
const adjustedConfig = { ...config };
|
|
149
|
+
|
|
150
|
+
keys.forEach((key) => {
|
|
151
|
+
const path = ["targetScreen", "styles", key];
|
|
152
|
+
|
|
153
|
+
if (has(screenData, path)) {
|
|
154
|
+
const value = get(screenData, path);
|
|
155
|
+
|
|
156
|
+
adjustedConfig[key] = value;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return adjustedConfig;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const AUDIO_PLAYER_ARTWORK_IMAGE_KEY = "audio_player_artwork_image_key";
|
|
164
|
+
|
|
165
|
+
const audioPlayerArtworkImageKeySelector = (config) =>
|
|
166
|
+
config?.[AUDIO_PLAYER_ARTWORK_IMAGE_KEY];
|
|
167
|
+
|
|
168
|
+
export const useArtworkImage = (entry: ZappEntry): string => {
|
|
169
|
+
const configuration = useZStore("playerConfiguration");
|
|
170
|
+
|
|
171
|
+
const audio_player_artwork_image_key_value = configuration(
|
|
172
|
+
audioPlayerArtworkImageKeySelector
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const pluginConfiguration = React.useMemo(
|
|
176
|
+
() => ({
|
|
177
|
+
audio_player_artwork_image_key: audio_player_artwork_image_key_value,
|
|
178
|
+
}),
|
|
179
|
+
[audio_player_artwork_image_key_value]
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// HACK: for override [key] from screenData, because we treat empty string value as missing key and replace it to initial_value from manifest(which is wrong)
|
|
183
|
+
const adjustedPluginConfiguration = useAdjustedKeyFromScreenData({
|
|
184
|
+
keys: [AUDIO_PLAYER_ARTWORK_IMAGE_KEY],
|
|
185
|
+
config: pluginConfiguration,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return React.useMemo(
|
|
189
|
+
() =>
|
|
190
|
+
getArtworkImage({
|
|
191
|
+
key: AUDIO_PLAYER_ARTWORK_IMAGE_KEY,
|
|
192
|
+
entry,
|
|
193
|
+
plugin_configuration: adjustedPluginConfiguration,
|
|
194
|
+
}),
|
|
195
|
+
[]
|
|
196
|
+
);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const AUDIO_PLAYER_IMAGE_KEY = "audio_player_image_key";
|
|
200
|
+
const AUDIO_PLAYER_BACKGROUND_IMAGE = "audio_player_background_image";
|
|
201
|
+
|
|
202
|
+
const audioPlayerImageKeySelector = (config) =>
|
|
203
|
+
config?.[AUDIO_PLAYER_IMAGE_KEY];
|
|
204
|
+
|
|
205
|
+
const audioPlayerBackgroundImageSelector = (config) =>
|
|
206
|
+
config?.[AUDIO_PLAYER_BACKGROUND_IMAGE];
|
|
207
|
+
|
|
208
|
+
export const useBackgroundImage = (entry: ZappEntry): { uri: string } => {
|
|
209
|
+
const configuration = useZStore("playerConfiguration");
|
|
210
|
+
|
|
211
|
+
const audio_player_image_key_value = configuration(
|
|
212
|
+
audioPlayerImageKeySelector
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const audio_player_background_image_value = configuration(
|
|
216
|
+
audioPlayerBackgroundImageSelector
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const pluginConfiguration = React.useMemo(
|
|
220
|
+
() => ({
|
|
221
|
+
audio_player_image_key: audio_player_image_key_value,
|
|
222
|
+
audio_player_background_image: audio_player_background_image_value,
|
|
223
|
+
}),
|
|
224
|
+
[audio_player_image_key_value, audio_player_background_image_value]
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
// HACK: for override [key] from screenData, because we treat empty string value as missing key and replace it to initial_value from manifest(which is wrong)
|
|
228
|
+
const adjustedPluginConfiguration = useAdjustedKeyFromScreenData({
|
|
229
|
+
keys: [AUDIO_PLAYER_IMAGE_KEY, AUDIO_PLAYER_BACKGROUND_IMAGE],
|
|
230
|
+
config: pluginConfiguration,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
return React.useMemo(
|
|
234
|
+
() => ({
|
|
235
|
+
uri: getBackgroundImage({
|
|
236
|
+
entry,
|
|
237
|
+
plugin_configuration: adjustedPluginConfiguration,
|
|
238
|
+
}),
|
|
239
|
+
}),
|
|
240
|
+
[entry, adjustedPluginConfiguration]
|
|
241
|
+
);
|
|
242
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { selectActionButtons } from "@applicaster/zapp-react-native-utils/conf/player/selectors";
|
|
2
|
+
|
|
3
|
+
describe("selectActionButtons", () => {
|
|
4
|
+
it("returns the player_action_buttons array if present", () => {
|
|
5
|
+
const pluginConf = {
|
|
6
|
+
player_action_buttons: [
|
|
7
|
+
{ id: "like", label: "Like" },
|
|
8
|
+
{ id: "share", label: "Share" },
|
|
9
|
+
],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
expect(selectActionButtons(pluginConf)).toEqual(
|
|
13
|
+
pluginConf.player_action_buttons
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("returns null if player_action_buttons is not present", () => {
|
|
18
|
+
const pluginConf = { some_other_key: [] };
|
|
19
|
+
expect(selectActionButtons(pluginConf)).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("returns null if pluginConf is undefined", () => {
|
|
23
|
+
expect(selectActionButtons(undefined)).toBeNull();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("returns null if pluginConf is null", () => {
|
|
27
|
+
expect(selectActionButtons(null)).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("returns null if player_action_buttons is explicitly set to null", () => {
|
|
31
|
+
const pluginConf = { player_action_buttons: null };
|
|
32
|
+
expect(selectActionButtons(pluginConf)).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { get } from "@applicaster/zapp-react-native-utils/utils";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Selects the action buttons from the player configuration.
|
|
5
|
+
* @param {Object} pluginConf - player plugin config
|
|
6
|
+
* @returns {Array|null} An array of action buttons or null if not found.
|
|
7
|
+
*/
|
|
8
|
+
export const selectActionButtons = (pluginConf: any) => {
|
|
9
|
+
return get(pluginConf, "player_action_buttons", null);
|
|
10
|
+
};
|