@applicaster/zapp-react-native-utils 14.0.0-alpha.1661204539 → 14.0.0-alpha.1718713411
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 +82 -53
- 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 +5 -2
- package/appUtils/contextKeysManager/contextResolver.ts +1 -15
- 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__/getArtworkImage.test.ts +144 -0
- package/audioPlayerUtils/__tests__/getBackgroundImage.test.ts +72 -0
- package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +110 -0
- package/audioPlayerUtils/assets/index.ts +2 -0
- package/audioPlayerUtils/index.ts +242 -0
- 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/index.js +4 -0
- package/manifestUtils/keys.js +12 -0
- package/manifestUtils/progressBar/__tests__/mobileProgressBar.test.js +0 -30
- package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +7 -2
- 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 +59 -0
- package/playerUtils/useValidatePlayerConfig.tsx +22 -19
- package/reactHooks/cell-click/index.ts +1 -5
- package/reactHooks/feed/useBatchLoading.ts +3 -3
- package/reactHooks/feed/useFeedLoader.tsx +6 -13
- 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 +16 -1
- package/actionsExecutor/ScreenActions.ts +0 -90
- package/actionsExecutor/StorageActions.ts +0 -110
- package/actionsExecutor/screenResolver.ts +0 -8
- package/playerUtils/configurationGenerator.ts +0 -2572
- package/storage/ScreenSingleValueProvider.ts +0 -92
- package/storage/ScreenStateMultiSelectProvider.ts +0 -119
- package/storage/StorageMultiSelectProvider.ts +0 -192
- package/storage/StorageSingleSelectProvider.ts +0 -108
package/manifestUtils/index.js
CHANGED
|
@@ -29,6 +29,9 @@ const {
|
|
|
29
29
|
getUpdatedSecondaryImageKeys,
|
|
30
30
|
} = require("./secondaryImage");
|
|
31
31
|
|
|
32
|
+
const DEFAULT_GRADIENT_IMAGE =
|
|
33
|
+
"data:image/png;base64,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";
|
|
34
|
+
|
|
32
35
|
module.exports = {
|
|
33
36
|
fontKey,
|
|
34
37
|
fontKeyTV,
|
|
@@ -47,5 +50,6 @@ module.exports = {
|
|
|
47
50
|
tvProgressBar,
|
|
48
51
|
secondaryImage,
|
|
49
52
|
getUpdatedSecondaryImageKeys,
|
|
53
|
+
DEFAULT_GRADIENT_IMAGE,
|
|
50
54
|
compact,
|
|
51
55
|
};
|
package/manifestUtils/keys.js
CHANGED
|
@@ -485,6 +485,18 @@ const TV_MENU_LABEL_FIELDS = [
|
|
|
485
485
|
type: ZAPPIFEST_FIELDS.number_input,
|
|
486
486
|
suffix: "LG letter spacing",
|
|
487
487
|
},
|
|
488
|
+
{
|
|
489
|
+
type: ZAPPIFEST_FIELDS.font_selector.roku,
|
|
490
|
+
suffix: "Roku font family",
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
type: ZAPPIFEST_FIELDS.number_input,
|
|
494
|
+
suffix: "Roku font size",
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
type: ZAPPIFEST_FIELDS.number_input,
|
|
498
|
+
suffix: "Roku line height",
|
|
499
|
+
},
|
|
488
500
|
{
|
|
489
501
|
type: ZAPPIFEST_FIELDS.select,
|
|
490
502
|
suffix: "text transform",
|
|
@@ -18,36 +18,6 @@ describe("mobileProgressBar", () => {
|
|
|
18
18
|
]),
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
// const timeRemainingLabelConditions = (condition) => ({
|
|
22
|
-
// rules: "all_conditions",
|
|
23
|
-
// conditional_fields: compact([
|
|
24
|
-
// {
|
|
25
|
-
// key: "assets/progress_bar_switch",
|
|
26
|
-
// condition_value: true,
|
|
27
|
-
// },
|
|
28
|
-
// {
|
|
29
|
-
// key: "assets/progress_bar_time_remaining_label_enable",
|
|
30
|
-
// condition_value: true,
|
|
31
|
-
// },
|
|
32
|
-
// condition,
|
|
33
|
-
// ]),
|
|
34
|
-
// });
|
|
35
|
-
|
|
36
|
-
// const watchedLabelConditions = (condition) => ({
|
|
37
|
-
// rules: "all_conditions",
|
|
38
|
-
// conditional_fields: compact([
|
|
39
|
-
// {
|
|
40
|
-
// key: "assets/progress_bar_switch",
|
|
41
|
-
// condition_value: true,
|
|
42
|
-
// },
|
|
43
|
-
// {
|
|
44
|
-
// key: "assets/progress_bar_watched_label_enable",
|
|
45
|
-
// condition_value: true,
|
|
46
|
-
// },
|
|
47
|
-
// condition,
|
|
48
|
-
// ]),
|
|
49
|
-
// });
|
|
50
|
-
|
|
51
21
|
it("generate progress-bar configuration - enabled and with bottom_of_cell", () => {
|
|
52
22
|
const enable = true;
|
|
53
23
|
const hideUnwatched = true;
|
|
@@ -8,7 +8,6 @@ const {
|
|
|
8
8
|
conditional_horizontal_type,
|
|
9
9
|
conditional_vertical_type,
|
|
10
10
|
conditional_horizontal_type_item_fixed,
|
|
11
|
-
conditional_horizontal_type_item_dynamic,
|
|
12
11
|
conditional_horizontal_asset_on,
|
|
13
12
|
conditional_horizontal_display_type_fixed,
|
|
14
13
|
} = require("./utils");
|
|
@@ -48,7 +47,7 @@ const componentConfigurationFields = [
|
|
|
48
47
|
{ text: "Right", value: "right" },
|
|
49
48
|
{ text: "Center", value: "center" },
|
|
50
49
|
],
|
|
51
|
-
...
|
|
50
|
+
...conditional_horizontal_type,
|
|
52
51
|
},
|
|
53
52
|
{
|
|
54
53
|
type: "select",
|
|
@@ -425,6 +424,12 @@ const titleFields = [
|
|
|
425
424
|
key: "vizio_font_family",
|
|
426
425
|
initial_value: fontFamily,
|
|
427
426
|
},
|
|
427
|
+
{
|
|
428
|
+
type: "roku_font_selector",
|
|
429
|
+
label: "Roku TV Font Family",
|
|
430
|
+
key: "roku_font_family",
|
|
431
|
+
initial_value: fontFamily,
|
|
432
|
+
},
|
|
428
433
|
...generateFontConfiguration(),
|
|
429
434
|
// text transform
|
|
430
435
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "14.0.0-alpha.
|
|
3
|
+
"version": "14.0.0-alpha.1718713411",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "14.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "14.0.0-alpha.1718713411",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -1,72 +1,8 @@
|
|
|
1
1
|
import * as utils from "../configurationUtils";
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
const configuration = {
|
|
6
|
-
general: { fields: [{ key: "general_1", initial_value: true }] },
|
|
7
|
-
styles: { fields: [{ key: "styles_1", initial_value: true }] },
|
|
8
|
-
localizations: {
|
|
9
|
-
fields: [{ key: "localizations_1", initial_value: true, label: "label" }],
|
|
10
|
-
},
|
|
11
|
-
custom_configuration_fields: [
|
|
12
|
-
{ key: "custom_configuration_fields_1", initial_value: true },
|
|
13
|
-
{ key: "custom_configuration_fields_2", initial_value: "black" },
|
|
14
|
-
{
|
|
15
|
-
group: true,
|
|
16
|
-
fields: [{ key: "custom_configuration_fields_3", initial_value: "red" }],
|
|
17
|
-
},
|
|
18
|
-
],
|
|
19
|
-
};
|
|
3
|
+
const { parseLanguageTracks } = utils;
|
|
20
4
|
|
|
21
5
|
describe("utilities", () => {
|
|
22
|
-
describe("modifyDefaultConfigValues", () => {
|
|
23
|
-
it("should not modify the configuration if a map key doesn't exist in configuration ", function () {
|
|
24
|
-
const res = modifyDefaultConfigValues(configuration, {
|
|
25
|
-
custom_configuration_fields: {
|
|
26
|
-
non_existing_key: { initial_value: "true" },
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
expect(res).toEqual(configuration);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("should modify the key from mapping", function () {
|
|
34
|
-
const currentResult = modifyDefaultConfigValues(configuration, {
|
|
35
|
-
styles: { styles_1: { initial_value: false } },
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
expect(currentResult.styles.fields[0].initial_value).toBe(false);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("should add extra keys the key from mapping", function () {
|
|
42
|
-
const currentResult = modifyDefaultConfigValues(configuration, {
|
|
43
|
-
styles: { styles_1: { extra_key: false } },
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
expect(currentResult.styles.fields[0].extra_key).toBeDefined();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("should not remove existing keys that aren't being overwritten", function () {
|
|
50
|
-
const currentResult = modifyDefaultConfigValues(configuration, {
|
|
51
|
-
localizations: { localizations_1: { initial_value: false } },
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
expect(currentResult.localizations.fields[0].label).toBeDefined();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("should modify values in groups as well", function () {
|
|
58
|
-
const currentResult = modifyDefaultConfigValues(configuration, {
|
|
59
|
-
custom_configuration_fields: {
|
|
60
|
-
custom_configuration_fields_3: { initial_value: "blue" },
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
expect(
|
|
65
|
-
currentResult.custom_configuration_fields[2].fields[0].initial_value
|
|
66
|
-
).toBe("blue");
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
6
|
describe("parseLanguageTracks", () => {
|
|
71
7
|
const textTrack = { index: 0, id: "text-0" };
|
|
72
8
|
const audioTrack = { index: 0, id: "audio-0" };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getPlayerActionButtons } from "../getPlayerActionButtons";
|
|
2
|
+
import { selectActionButtons } from "../../conf/player/selectors";
|
|
3
|
+
|
|
4
|
+
jest.mock("../../conf/player/selectors", () => ({
|
|
5
|
+
selectActionButtons: jest.fn(),
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
describe("getPlayerActionButtons", () => {
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
jest.clearAllMocks();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("returns an empty array if selectActionButtons returns undefined", () => {
|
|
14
|
+
(selectActionButtons as jest.Mock).mockReturnValue(undefined);
|
|
15
|
+
const result = getPlayerActionButtons({});
|
|
16
|
+
expect(result).toEqual([]);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("returns an empty array if selectActionButtons returns null", () => {
|
|
20
|
+
(selectActionButtons as jest.Mock).mockReturnValue(null);
|
|
21
|
+
const result = getPlayerActionButtons({});
|
|
22
|
+
expect(result).toEqual([]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns an empty array if selectActionButtons returns empty string", () => {
|
|
26
|
+
(selectActionButtons as jest.Mock).mockReturnValue("");
|
|
27
|
+
const result = getPlayerActionButtons({});
|
|
28
|
+
expect(result).toEqual([]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("returns the first two trimmed action buttons", () => {
|
|
32
|
+
(selectActionButtons as jest.Mock).mockReturnValue(" play , pause , stop ");
|
|
33
|
+
const result = getPlayerActionButtons({});
|
|
34
|
+
expect(result).toEqual(["play", "pause"]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns only one button if only one is present", () => {
|
|
38
|
+
(selectActionButtons as jest.Mock).mockReturnValue(" play ");
|
|
39
|
+
const result = getPlayerActionButtons({});
|
|
40
|
+
expect(result).toEqual(["play"]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("trims whitespace from button names", () => {
|
|
44
|
+
(selectActionButtons as jest.Mock).mockReturnValue(" play , pause ");
|
|
45
|
+
const result = getPlayerActionButtons({});
|
|
46
|
+
expect(result).toEqual(["play", "pause"]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("returns an empty array if selectActionButtons returns only commas", () => {
|
|
50
|
+
(selectActionButtons as jest.Mock).mockReturnValue(" , , ");
|
|
51
|
+
const result = getPlayerActionButtons({});
|
|
52
|
+
expect(result).toEqual(["", ""]);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getAllFields, getConfigurationDiff } from "../utils";
|
|
2
|
+
|
|
3
|
+
describe("getAllFields", () => {
|
|
4
|
+
it("should return all field keys from flat configs", () => {
|
|
5
|
+
const config1 = {
|
|
6
|
+
fields: [{ key: "foo" }, { key: "bar" }],
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const config2 = {
|
|
10
|
+
fields: [{ key: "baz" }],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
expect(getAllFields(config1, config2)).toEqual(["foo", "bar", "baz"]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should handle grouped fields", () => {
|
|
17
|
+
const config = {
|
|
18
|
+
fields: [
|
|
19
|
+
{
|
|
20
|
+
group: true,
|
|
21
|
+
fields: [{ key: "grouped1" }, { key: "grouped2" }],
|
|
22
|
+
},
|
|
23
|
+
{ key: "single" },
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
expect(getAllFields(config)).toEqual(["grouped1", "grouped2", "single"]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should filter out fields without a key", () => {
|
|
31
|
+
const config = {
|
|
32
|
+
fields: [{ key: "foo" }, { notAKey: "bar" }],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
expect(getAllFields(config)).toEqual(["foo"]);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should return an empty array if no fields are present", () => {
|
|
39
|
+
expect(getAllFields({})).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("getConfigurationDiff", () => {
|
|
44
|
+
it("should return keys in defaultConfig not present in config", () => {
|
|
45
|
+
const defaultConfig = ["foo", "bar", "baz"];
|
|
46
|
+
const config = { foo: 1, baz: 2 };
|
|
47
|
+
|
|
48
|
+
expect(getConfigurationDiff(defaultConfig, config)).toEqual(["bar"]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should return all keys if config is empty", () => {
|
|
52
|
+
const defaultConfig = ["foo", "bar"];
|
|
53
|
+
const config = {};
|
|
54
|
+
|
|
55
|
+
expect(getConfigurationDiff(defaultConfig, config)).toEqual(["foo", "bar"]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should return an empty array if all keys are present", () => {
|
|
59
|
+
const defaultConfig = ["foo"];
|
|
60
|
+
const config = { foo: 1 };
|
|
61
|
+
|
|
62
|
+
expect(getConfigurationDiff(defaultConfig, config)).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("should return defaultConfig if config has no matching keys", () => {
|
|
66
|
+
const defaultConfig = ["foo", "bar"];
|
|
67
|
+
const config = { baz: 1 };
|
|
68
|
+
|
|
69
|
+
expect(getConfigurationDiff(defaultConfig, config)).toEqual(["foo", "bar"]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./utils";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
flatMap,
|
|
3
|
+
get,
|
|
4
|
+
flatten,
|
|
5
|
+
difference,
|
|
6
|
+
} from "@applicaster/zapp-react-native-utils/utils";
|
|
7
|
+
|
|
8
|
+
const extractFields = (field: any) => {
|
|
9
|
+
if (field.group === true) {
|
|
10
|
+
return field.fields;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return field;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const getAllFields = (...configs: any[]) => {
|
|
17
|
+
const allFields = flatMap(configs, (config) => get(config, "fields", []));
|
|
18
|
+
|
|
19
|
+
const processedFields = flatten(allFields.map(extractFields))
|
|
20
|
+
.map((field) => get(field, "key"))
|
|
21
|
+
.filter(Boolean);
|
|
22
|
+
|
|
23
|
+
return processedFields;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const getConfigurationDiff = (
|
|
27
|
+
defaultConfig,
|
|
28
|
+
config: Record<string, any>
|
|
29
|
+
) => {
|
|
30
|
+
return difference(defaultConfig, Object.keys(config));
|
|
31
|
+
};
|
|
@@ -1,50 +1,6 @@
|
|
|
1
1
|
import { parseJsonIfNeeded } from "../functionUtils";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
|
|
4
|
-
import { getNativeName as nativeNameUtil } from "../localizationUtils/localeLanguage";
|
|
5
|
-
|
|
6
|
-
export const modifyDefaultConfigValues = (
|
|
7
|
-
configuration: ConfigurationKeys,
|
|
8
|
-
mapping: ConfigValuesMapping
|
|
9
|
-
): DefaultConfiguration => {
|
|
10
|
-
return R.mapObjIndexed((value, key) => {
|
|
11
|
-
const isFieldlessKey = key === "custom_configuration_fields";
|
|
12
|
-
const keyMapping = mapping[key];
|
|
13
|
-
const fields = value?.fields || value;
|
|
14
|
-
|
|
15
|
-
if (!keyMapping) {
|
|
16
|
-
return value;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const mapper = (obj) => {
|
|
20
|
-
if (obj.fields) {
|
|
21
|
-
return R.mergeLeft({ fields: R.map(mapper)(obj.fields) })(obj);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return R.mergeLeft(keyMapping?.[obj.key])(obj);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const mappedFields = R.map(mapper)(fields);
|
|
28
|
-
|
|
29
|
-
return R.unless(() => isFieldlessKey, R.objOf("fields"))(mappedFields);
|
|
30
|
-
})(configuration);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function nativeName(localeCode) {
|
|
34
|
-
try {
|
|
35
|
-
const {
|
|
36
|
-
getNativeName,
|
|
37
|
-
} = require("@applicaster/zapp-react-native-utils/localizationUtils/localeLanguage");
|
|
38
|
-
|
|
39
|
-
return getNativeName(localeCode);
|
|
40
|
-
} catch (error) {
|
|
41
|
-
// eslint-disable-next-line no-console
|
|
42
|
-
console.warn("Could not load localeLanguage utils from QB", error);
|
|
43
|
-
|
|
44
|
-
return nativeNameUtil(localeCode);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
4
|
const setTrackType = R.curry(
|
|
49
5
|
(
|
|
50
6
|
type: QuickBrickPlayer.TrackType,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { map, take, trim } from "../utils";
|
|
2
|
+
import { selectActionButtons } from "../conf/player/selectors";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the first two action buttons from the configuration.
|
|
6
|
+
* @param {Object} configuration - The player configuration object.
|
|
7
|
+
* @returns {Array} An array containing the first two action buttons.
|
|
8
|
+
*/
|
|
9
|
+
export const getPlayerActionButtons = (configuration: any) => {
|
|
10
|
+
const buttonsString = selectActionButtons(configuration);
|
|
11
|
+
|
|
12
|
+
if (!buttonsString) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return take(map(buttonsString.split(","), trim), 2);
|
|
17
|
+
};
|
package/playerUtils/index.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
3
3
|
import { isString } from "@applicaster/zapp-react-native-utils/typeGuards";
|
|
4
|
+
import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
5
|
+
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
6
|
|
|
5
7
|
import { getBoolFromConfigValue } from "../configurationUtils";
|
|
8
|
+
import { Dimensions } from "react-native";
|
|
9
|
+
|
|
10
|
+
export { getPlayerActionButtons } from "./getPlayerActionButtons";
|
|
6
11
|
|
|
7
12
|
/**
|
|
8
13
|
* Gets duration value from player manager, and from extensions
|
|
@@ -89,3 +94,57 @@ export const isAudioItem = (item: Option<ZappEntry>) => {
|
|
|
89
94
|
|
|
90
95
|
return false;
|
|
91
96
|
};
|
|
97
|
+
|
|
98
|
+
export const isInlineTV = (screenData) => {
|
|
99
|
+
return isTV() && isFilledArray(screenData?.ui_components);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const isPercentage = (value: string | number): boolean => {
|
|
103
|
+
if (typeof value === "string") {
|
|
104
|
+
return value.includes("%");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return false;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const getPercentageOf = (percent: string, value: number) => {
|
|
111
|
+
const percentageValue = parseFloat(percent.replace("%", ""));
|
|
112
|
+
|
|
113
|
+
if (isNaN(percentageValue)) {
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (value * percentageValue) / 100;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
type DimensionsT = {
|
|
121
|
+
width: number | string;
|
|
122
|
+
height: number | string | undefined;
|
|
123
|
+
aspectRatio?: number;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const getTabletWidth = (
|
|
127
|
+
tablet_landscape_sidebar_width,
|
|
128
|
+
dimensions: DimensionsT
|
|
129
|
+
) => {
|
|
130
|
+
const { width: SCREEN_WIDTH } = Dimensions.get("screen");
|
|
131
|
+
|
|
132
|
+
const { width } = dimensions;
|
|
133
|
+
let widthValue = Number(width);
|
|
134
|
+
|
|
135
|
+
if (isPercentage(width)) {
|
|
136
|
+
widthValue = getPercentageOf(width.toString(), SCREEN_WIDTH);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
|
|
140
|
+
|
|
141
|
+
if (tablet_landscape_sidebar_width?.includes("%")) {
|
|
142
|
+
return widthValue * (1 - sidebarWidth / 100);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (Number.isNaN(sidebarWidth)) {
|
|
146
|
+
return widthValue * 0.65;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return widthValue - sidebarWidth;
|
|
150
|
+
};
|
|
@@ -1,34 +1,37 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
|
-
import generateConfiguration from "./configurationGenerator";
|
|
4
2
|
import { createLogger } from "../logger";
|
|
3
|
+
import { createConfig } from "../manifestUtils/createConfig";
|
|
4
|
+
import { getAllFields, getConfigurationDiff } from "./_internals";
|
|
5
5
|
|
|
6
6
|
export const logger = createLogger({
|
|
7
7
|
category: "useValidatePlayerConfig",
|
|
8
8
|
subsystem: "useValidatePlayerConfig",
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/** Default Player Configuration */
|
|
12
|
+
const {
|
|
13
|
+
styles,
|
|
14
|
+
general,
|
|
15
|
+
localizations,
|
|
16
|
+
custom_configuration_fields,
|
|
17
|
+
}: DefaultConfiguration = createConfig(
|
|
18
|
+
() => {
|
|
19
|
+
return {};
|
|
20
|
+
},
|
|
21
|
+
{ extend: "player" }
|
|
22
|
+
) as any;
|
|
23
|
+
|
|
24
|
+
const QBPlayerConfigFields = getAllFields(
|
|
25
|
+
styles,
|
|
26
|
+
general,
|
|
27
|
+
localizations,
|
|
28
|
+
custom_configuration_fields
|
|
29
|
+
);
|
|
12
30
|
|
|
13
31
|
export const useValidatePlayerConfig = (config) => {
|
|
14
32
|
React.useEffect(() => {
|
|
15
33
|
try {
|
|
16
|
-
const
|
|
17
|
-
R.map(R.prop("key")),
|
|
18
|
-
R.flatten,
|
|
19
|
-
R.map(R.compose(R.when(R.propEq("group", true), R.prop("fields")))),
|
|
20
|
-
R.concat
|
|
21
|
-
)(
|
|
22
|
-
configuration.styles.fields,
|
|
23
|
-
configuration.general.fields,
|
|
24
|
-
configuration.localizations.fields,
|
|
25
|
-
configuration.custom_configuration_fields
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
const diff = R.compose(
|
|
29
|
-
R.difference(QBPlayerConfigFields),
|
|
30
|
-
R.keys
|
|
31
|
-
)(config);
|
|
34
|
+
const diff = getConfigurationDiff(QBPlayerConfigFields, config);
|
|
32
35
|
|
|
33
36
|
logger.log_info(
|
|
34
37
|
"Missing following configuration properties. Some elements of the player may not work correctly. Check QuickBrickPlayerPlugin for the configuration reference https://github.com/applicaster/QuickBrick/tree/main/plugins/zapp-react-native-default-player/manifests",
|
|
@@ -16,7 +16,7 @@ import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/acti
|
|
|
16
16
|
import { isFunction, noop } from "../../functionUtils";
|
|
17
17
|
import { useSendAnalyticsOnPress } from "../analytics";
|
|
18
18
|
import { logOnPress, warnEmptyContentType } from "./helpers";
|
|
19
|
-
import { useCurrentScreenData
|
|
19
|
+
import { useCurrentScreenData } from "../screen";
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* If onCellTap is defined execute the function and
|
|
@@ -46,7 +46,6 @@ export const useCellClick = ({
|
|
|
46
46
|
const onCellTap: Option<Function> = React.useContext(CellTapContext);
|
|
47
47
|
const actionExecutor = React.useContext(ActionExecutorContext);
|
|
48
48
|
const screenData = useCurrentScreenData();
|
|
49
|
-
const screenState = useScreenContext()?.options;
|
|
50
49
|
|
|
51
50
|
const cellSelectable = toBooleanWithDefaultTrue(
|
|
52
51
|
component?.rules?.component_cells_selectable
|
|
@@ -84,8 +83,6 @@ export const useCellClick = ({
|
|
|
84
83
|
await actionExecutor?.handleEntryActions(selectedItem, {
|
|
85
84
|
component,
|
|
86
85
|
screenData,
|
|
87
|
-
screenState,
|
|
88
|
-
screenRoute: pathname,
|
|
89
86
|
});
|
|
90
87
|
}
|
|
91
88
|
|
|
@@ -120,7 +117,6 @@ export const useCellClick = ({
|
|
|
120
117
|
push,
|
|
121
118
|
sendAnalyticsOnPress,
|
|
122
119
|
screenData,
|
|
123
|
-
screenState,
|
|
124
120
|
]
|
|
125
121
|
);
|
|
126
122
|
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
getSearchContext,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
12
|
import { isGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
13
|
-
import { useScreenContext } from "../screen
|
|
13
|
+
import { useScreenContext } from "../screen";
|
|
14
14
|
|
|
15
15
|
type Options = {
|
|
16
16
|
initialBatchSize?: number;
|
|
@@ -144,11 +144,11 @@ export const useBatchLoading = (
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
});
|
|
147
|
-
}, [feedUrls]);
|
|
147
|
+
}, [feedUrls, feeds]);
|
|
148
148
|
|
|
149
149
|
React.useEffect(() => {
|
|
150
150
|
runBatchLoading();
|
|
151
|
-
}, []);
|
|
151
|
+
}, [runBatchLoading]); // Adding runBatchLoading as a dependency to ensure that it reloads feeds when clearPipesData is called
|
|
152
152
|
|
|
153
153
|
React.useEffect(() => {
|
|
154
154
|
// check if all feeds are ready and set hasEverBeenReady to true
|