@applicaster/zapp-react-native-utils 12.0.0-rc.98 → 13.0.0-alpha.2322412833

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.
Files changed (76) hide show
  1. package/analyticsUtils/AnalyticPlayerListener.ts +141 -0
  2. package/analyticsUtils/PlayerAnalyticsManager.ts +90 -0
  3. package/analyticsUtils/{analyticsTracker.ts → playerAnalyticsTracker.ts} +19 -10
  4. package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
  5. package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +4 -2
  6. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
  7. package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
  8. package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
  9. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  10. package/appUtils/HooksManager/{index.js → index.ts} +121 -112
  11. package/appUtils/HooksManager/types.ts +116 -0
  12. package/appUtils/RiverFocusManager/index.js +17 -12
  13. package/appUtils/accessibilityManager/hooks.ts +16 -7
  14. package/appUtils/accessibilityManager/index.ts +33 -28
  15. package/appUtils/focusManager/treeDataStructure/Tree/index.js +2 -3
  16. package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
  17. package/appUtils/{index.js → index.ts} +1 -1
  18. package/appUtils/keyCodes/__tests__/keyCodes.test.js +3 -3
  19. package/appUtils/keyCodes/{index.js → index.ts} +2 -0
  20. package/appUtils/keyCodes/keys/index.ts +3 -0
  21. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  22. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  23. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  24. package/appUtils/keyCodes/keys/keys.ts +15 -0
  25. package/appUtils/platform/platformUtils.ts +35 -16
  26. package/appUtils/playerManager/index.ts +9 -27
  27. package/appUtils/playerManager/playerFactory.ts +5 -4
  28. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +57 -0
  29. package/appUtils/playerManager/playerNative.ts +1 -1
  30. package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -1
  31. package/appUtils/playerManager/usePlayerState.tsx +19 -34
  32. package/arrayUtils/index.ts +11 -0
  33. package/cellUtils/index.ts +38 -5
  34. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  35. package/focusManager/FocusManager.ts +20 -5
  36. package/focusManager/__tests__/FocusManager.test.ts +0 -1
  37. package/functionUtils/index.ts +53 -11
  38. package/index.d.ts +15 -0
  39. package/manifestUtils/defaultManifestConfigurations/player.js +121 -0
  40. package/manifestUtils/keys.js +2 -1
  41. package/modalState/index.ts +1 -5
  42. package/navigationUtils/index.ts +15 -6
  43. package/numberUtils/__tests__/toNumber.test.ts +2 -2
  44. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +66 -0
  45. package/numberUtils/__tests__/toPositiveNumberWithDefaultZero.test.ts +66 -0
  46. package/numberUtils/index.ts +20 -0
  47. package/package.json +2 -2
  48. package/playerUtils/configurationGenerator.ts +120 -0
  49. package/playerUtils/imaScriptDom.ts +59 -0
  50. package/reactHooks/cell-click/index.ts +17 -3
  51. package/reactHooks/debugging/__tests__/index.test.js +81 -11
  52. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +69 -6
  53. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -2
  54. package/reactHooks/feed/useBatchLoading.ts +52 -28
  55. package/reactHooks/feed/useFeedLoader.tsx +11 -7
  56. package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +134 -0
  57. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -0
  58. package/reactHooks/navigation/index.ts +8 -5
  59. package/reactHooks/player/useAutoSeek.tsx +9 -7
  60. package/reactHooks/resolvers/useCellResolver.ts +5 -1
  61. package/reactHooks/useConfiguration.ts +2 -2
  62. package/reactHooks/utils/index.ts +13 -0
  63. package/reactUtils/index.ts +1 -16
  64. package/services/localStorageServiceSync.web.ts +48 -0
  65. package/services/sessionStorageServiceSync.web.ts +32 -0
  66. package/services/storageServiceSync.web.ts +24 -0
  67. package/services/storageWebUtils.web.ts +10 -0
  68. package/testUtils/index.tsx +42 -9
  69. package/appUtils/keyCodes/keys.ios.js +0 -46
  70. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  71. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  72. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  73. /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
  74. /package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +0 -0
  75. /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
  76. /package/domUtils/{logger.js → logger.ts} +0 -0
@@ -0,0 +1,116 @@
1
+ import { SubscriberObj } from "../../functionUtils";
2
+ import { HOOKS_EVENTS } from "./constants";
3
+
4
+ export interface HookConfiguration {}
5
+
6
+ /* existing Hook Plugn props: sample */
7
+ interface _HookModulePlugin {
8
+ Component:
9
+ | React.FC<HookPluginProps>
10
+ | React.Component<HookPluginProps, any>
11
+ | React.ReactNode;
12
+ ModalContainer?: React.FC<ModalProps> | React.Component<ModalProps, any>;
13
+ skipHook?: (payload: ZappRiver | ZappEntry) => boolean;
14
+ presentFullScreen: boolean;
15
+ showNavBar?: boolean;
16
+ isFlowBlocker: (() => boolean) | boolean; // narrow this
17
+ hasPlayerHook?: boolean;
18
+ name: string;
19
+ runInBackground?: (
20
+ item: HookPluginProps["payload"],
21
+ callback: hookCallback,
22
+ hookPlugin: HookScreenData,
23
+ presentUI: (payload?: HookPluginProps["payload"]) => void
24
+ ) => any;
25
+ }
26
+
27
+ //* Derived from usage */
28
+ export interface HookModule {
29
+ ModalContainer?: React.ComponentType<any>;
30
+ Component: React.ComponentType<any>;
31
+ presentFullScreen: boolean;
32
+ run?: (
33
+ arg0: unknown,
34
+ callback: () => void,
35
+ configuration: HookConfiguration
36
+ ) => void; // not sure about optional parameter
37
+ hasPlayerHook?: boolean;
38
+ configuration?: HookConfiguration;
39
+ isFlowBlocker: () => boolean;
40
+ skipHook?: (payload?: ZappRiver | ZappEntry) => boolean;
41
+ runInBackground?: (
42
+ arg0: unknown,
43
+ callback: () => void,
44
+ hookPlugin: Hook,
45
+ presentUI: (payload?: HookPluginProps["payload"]) => void
46
+ ) => void;
47
+ name: string;
48
+ showNavBar?: boolean; // unsure
49
+ }
50
+
51
+ export type HookManagerArgs = {
52
+ rivers: Record<string, ZappRiver>;
53
+ plugins: ZappPlugin[];
54
+ targetScreen: ZappRiver;
55
+ startUpHooksData?: {
56
+ startUpHooks?: unknown[] | "in_process";
57
+ setStartUpHooks?: (arg0: string) => void;
58
+ };
59
+ };
60
+
61
+ export interface HookManager {
62
+ subscriber: SubscriberObj;
63
+ presentScreenHook: (
64
+ hook: Hook,
65
+ payload: unknown,
66
+ callback: (...any) => void
67
+ ) => void;
68
+ executeHook: (
69
+ hook: Hook,
70
+ payload: unknown,
71
+ callback: (...any) => void
72
+ ) => void;
73
+ handleHooks: (payload: unknown) => void;
74
+ runInBackground: (
75
+ hook: Hook,
76
+ payload: unknown,
77
+ callback: (...any) => void,
78
+ presentUI: (payload?: HookPluginProps["payload"]) => void
79
+ ) => void;
80
+ }
81
+
82
+ export type HookIniObj = {
83
+ hook: HookModule & {
84
+ module: HookModule;
85
+ general: unknown;
86
+ screen_id?: string;
87
+ identifier?: string;
88
+ weight?: number | string;
89
+ };
90
+ hooks: Hook<any>[];
91
+ manager: HookManager;
92
+ };
93
+
94
+ export interface Hook<T extends HookModule = HookModule> {
95
+ manager: HookManager;
96
+ lastHook: boolean;
97
+ state: number;
98
+ module: T;
99
+ screen_id: string;
100
+ identifier: string;
101
+ configuration: T["configuration"];
102
+ setStateAndNotify(
103
+ event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
104
+ opts: {
105
+ error?: typeof Error;
106
+ route?: string;
107
+ hookPlugin: Hook<T>;
108
+ payload: unknown;
109
+ }
110
+ );
111
+ general?: {
112
+ transition_type: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS];
113
+ allow_screen_plugin_presentation: boolean;
114
+ is_flow_blocker: boolean;
115
+ };
116
+ }
@@ -26,7 +26,7 @@ export const riverFocusManager = (function () {
26
26
  /**
27
27
  * Retrieve screen focus data by id
28
28
  *
29
- * @param {String} screenFocusableGroupId Id that was used to save screen data.
29
+ * @param {{screenFocusableGroupId: string}} screenFocusableGroupId Unique Id of the screen from layout.json
30
30
  *
31
31
  */
32
32
  function screenFocusableData({ screenFocusableGroupId }) {
@@ -36,8 +36,9 @@ export const riverFocusManager = (function () {
36
36
  /**
37
37
  * Clear screen data for specific screen
38
38
  *
39
- * @param {String} screenId Unique Id of the screen from layout.json
40
- * @param {boolean} isInsideContainer If this screen a screen picker child
39
+ * @param {{ screenId: string, isInsideContainer: boolean }}
40
+ * screenId Unique Id of the screen from layout.json
41
+ * isInsideContainer If this screen a screen picker child
41
42
  *
42
43
  */
43
44
  function clearScreenData({ screenId, isInsideContainer }) {
@@ -60,9 +61,13 @@ export const riverFocusManager = (function () {
60
61
  /**
61
62
  * Focus on selected items
62
63
  *
63
- * @param {String} screenFocusableGroupId Top group id that was saved as screenn
64
- * @param {String} screenFocusedOnItem focusable item to focus
65
- * @param {object} history navigator history object
64
+ * @param {{
65
+ * screenFocusableGroupId: string,
66
+ * screenFocusedOnItem: () => void,
67
+ * previousAction: QuickBrickNavigationActionType,
68
+ * isDeepLink: boolean }} object contains data for focus
69
+ * - `screenFocusedOnItem` focusable item to focus
70
+ * - `previousActionhistory` navigator history object
66
71
  *
67
72
  */
68
73
  function focusOnSelectedItem({
@@ -115,15 +120,15 @@ export const riverFocusManager = (function () {
115
120
 
116
121
  /**
117
122
  * Create unique key that will be used for save focused group data inside specific screen
118
- *
119
- * @param {String} screenId Unique Id of the screen from layout.json
120
- * @param {boolean} isInsideContainer If this screen a screen picker child
123
+ * @param {{ screenId: string, isInsideContainer: boolean }}
124
+ * screenId Unique Id of the screen from layout.json
125
+ * isInsideContainer If this screen a screen picker child
121
126
  *
122
127
  */
123
128
  function screenFocusableGroupId({ screenId, isInsideContainer }) {
124
- return R.isNil(isInsideContainer)
125
- ? `RiverFocusableGroup-${screenId}`
126
- : `RiverFocusableGroup-${screenId}-isInsideContainer`;
129
+ return `RiverFocusableGroup-${screenId}${
130
+ R.isNil(isInsideContainer) ? "" : "-isInsideContainer"
131
+ }`;
127
132
  }
128
133
 
129
134
  return {
@@ -1,18 +1,27 @@
1
1
  import { useEffect, useMemo } from "react";
2
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
2
  import { AccessibilityManager } from "./index";
4
3
 
5
- export const useAccessibilityManager = () => {
6
- const { remoteConfigurations } = usePickFromState(["remoteConfigurations"]);
7
- const { localizations } = remoteConfigurations;
8
-
4
+ /**
5
+ * This hook is used to instantiate the accessibility manager and update localizations used by the class.
6
+ * If the plugin config is not provided or it does not contain any localizations, the accessibility manager will not be updated.
7
+ * We use the plugin configuration because it offers a flattened structure where we can easily access the accessibility labels and hints
8
+ * i.e. pluginConfiguration = {
9
+ * accessibility_close_label: "Close",
10
+ * accessibility_close_hint: "Press here to close",
11
+ * }
12
+ */
13
+ export const useAccessibilityManager = (
14
+ pluginConfiguration: Record<string, any> = {}
15
+ ) => {
9
16
  const accessibilityManager = useMemo(() => {
10
17
  return AccessibilityManager.getInstance();
11
18
  }, []);
12
19
 
13
20
  useEffect(() => {
14
- accessibilityManager.updateLocalizations(localizations);
15
- }, [localizations]);
21
+ if (pluginConfiguration) {
22
+ accessibilityManager.updateLocalizations(pluginConfiguration);
23
+ }
24
+ }, [pluginConfiguration, accessibilityManager]);
16
25
 
17
26
  useEffect(() => {
18
27
  const subscription = accessibilityManager.getStateAsObservable().subscribe({
@@ -1,21 +1,8 @@
1
1
  import { BehaviorSubject } from "rxjs";
2
2
  import { accessibilityManagerLogger as logger } from "./logger";
3
3
  import { TTSManager } from "../platform/platformUtils";
4
- import { getLocalizations } from "../../localizationUtils";
5
4
  import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
6
-
7
- export interface AccessibilityState {
8
- screenReaderEnabled: boolean;
9
- reduceMotionEnabled: boolean;
10
- boldTextEnabled: boolean;
11
- }
12
-
13
- export interface AccessibilityProps {
14
- accessibilityLabel?: string;
15
- accessibilityHint?: string;
16
- "aria-label"?: string;
17
- "aria-description"?: string;
18
- }
5
+ import { AccessibilityRole } from "react-native";
19
6
 
20
7
  export class AccessibilityManager {
21
8
  private static _instance: AccessibilityManager | null = null;
@@ -32,13 +19,9 @@ export class AccessibilityManager {
32
19
  } | null>(null);
33
20
 
34
21
  private ttsManager = TTSManager.getInstance();
35
- private localizations: { [key: string]: string };
22
+ private localizations: { [key: string]: string } = {};
36
23
 
37
- private constructor(localizations?: { [key: string]: string }) {
38
- if (localizations) {
39
- this.localizations = getLocalizations({ localizations });
40
- }
41
- }
24
+ private constructor() {}
42
25
 
43
26
  public static getInstance(): AccessibilityManager {
44
27
  if (!AccessibilityManager._instance) {
@@ -48,8 +31,17 @@ export class AccessibilityManager {
48
31
  return AccessibilityManager._instance;
49
32
  }
50
33
 
34
+ /**
35
+ * The method now accepts any object with localizations using a flattened structure
36
+ *
37
+ * i.e. { accessibility_close_label: "Close", accessibility_close_hint: "Press here to close" }
38
+ *
39
+ * No longer accepts:
40
+ *
41
+ * i.e. localizations: [{ en: { accessibility_close_label: "Close", accessibility_close_hint: "Press here to close" } }]
42
+ */
51
43
  public updateLocalizations(localizations: { [key: string]: string }) {
52
- this.localizations = getLocalizations({ localizations });
44
+ this.localizations = localizations;
53
45
  }
54
46
 
55
47
  public getState(): AccessibilityState {
@@ -71,7 +63,7 @@ export class AccessibilityManager {
71
63
  text: string;
72
64
  keyOfLocalizedText?: string;
73
65
  }) {
74
- logger.debug("Reading text", { text, keyOfLocalizedText });
66
+ let textToRead = text;
75
67
 
76
68
  if (keyOfLocalizedText) {
77
69
  if (!this.localizations) {
@@ -90,16 +82,14 @@ export class AccessibilityManager {
90
82
  return;
91
83
  }
92
84
 
93
- text = localizedMessage;
85
+ textToRead = localizedMessage;
94
86
  }
95
87
 
96
- if (this.ttsManager) {
97
- this.ttsManager.readText(text);
98
- }
88
+ this.ttsManager && this.ttsManager.readText(textToRead);
99
89
 
100
90
  this.announcements$.next({
101
- message: text,
102
- localizedMessage: keyOfLocalizedText ? text : undefined,
91
+ message: textToRead,
92
+ localizedMessage: keyOfLocalizedText ? textToRead : undefined,
103
93
  timestamp: Date.now(),
104
94
  });
105
95
  }
@@ -113,6 +103,8 @@ export class AccessibilityManager {
113
103
  accessibilityHint: `Press button to perform action on ${buttonName}`,
114
104
  "aria-label": buttonName,
115
105
  "aria-description": `Press button to perform action on ${buttonName}`,
106
+ accessibilityRole: "button" as AccessibilityRole,
107
+ "aria-role": "button",
116
108
  };
117
109
  }
118
110
 
@@ -130,6 +122,19 @@ export class AccessibilityManager {
130
122
  accessibilityHint: hint,
131
123
  "aria-label": label,
132
124
  "aria-description": hint,
125
+ accessibilityRole: "button" as AccessibilityRole,
126
+ "aria-role": "button",
127
+ };
128
+ }
129
+
130
+ public getInputAccessibilityProps(inputName: string): AccessibilityProps {
131
+ return {
132
+ accessibilityLabel: inputName,
133
+ accessibilityHint: `Enter text into ${inputName}`,
134
+ "aria-label": inputName,
135
+ "aria-description": `Enter text into ${inputName}`,
136
+ accessibilityRole: "textbox" as AccessibilityRole,
137
+ "aria-role": "textbox",
133
138
  };
134
139
  }
135
140
 
@@ -59,7 +59,7 @@ export class Tree {
59
59
  /**
60
60
  * Update node with provided data from newNode
61
61
  * @private
62
- * @param {Object} node to update
62
+ * @param {Object} currentNode to update
63
63
  * @param {Object} newNode node to take data from
64
64
  */
65
65
  updateNode(currentNode, newNode) {
@@ -175,7 +175,6 @@ export class Tree {
175
175
  * @private
176
176
  * @param {Object} node to check
177
177
  * @returns True if node has defined groupID
178
- * @returns False if node has NOT defined groupID
179
178
  */
180
179
  hasGroupID(node) {
181
180
  return node.component && node.component.props.groupId;
@@ -191,7 +190,7 @@ export class Tree {
191
190
  const findChildNode = this.findInTree(node.component.props.groupId);
192
191
 
193
192
  if (findChildNode) {
194
- this.root.children.pop(findChildNode);
193
+ this.root.children.pop();
195
194
  node.children.push(findChildNode);
196
195
  }
197
196
  }
@@ -191,7 +191,6 @@ const toDistance = ({ target, direction, comparisonRect }) => {
191
191
  * Get target in shortest distance in specified direction
192
192
  * @private
193
193
  * @param {Object} direction of the navigation, which led to this focus change
194
- * @param {Object} excludedNode node which should be excluded from target group
195
194
  * @param {Array} targetNodes array of input target nodes
196
195
  * @param {Object} comparisonRect rectangle to compare sides in direction.
197
196
  * @returns {Object} target in direction.
@@ -300,8 +299,7 @@ export function findFocusableNode(direction, currentFocusNode) {
300
299
  * @public
301
300
  * @param {Object} direction of the navigation, which led to this focus change
302
301
  * @param {Object} component - object to check props.prioritiseFocusOn
303
- * @returns {Boolean} TRUE if object has priority in direction.
304
- * @returns {Boolean} FALSE if object has NO priority in direction.
302
+ * @returns {Boolean} TRUE if object has priority in direction. FALSE if object has NO priority in direction.
305
303
  */
306
304
  export function hasPriorityInDirection(direction, component) {
307
305
  const { prioritiseFocusOn = 0 } = component.props;
@@ -9,7 +9,7 @@ export { KEYS, ARROW_KEYS } from "./keyCodes/keys";
9
9
 
10
10
  export { playerManager } from "./playerManager";
11
11
 
12
- export { accessibilityManager } from "./accessibilityManager";
12
+ export { AccessibilityManager } from "./accessibilityManager";
13
13
 
14
14
  export function deprecationMessage(fn, replacement) {
15
15
  if (__DEV__ && process.env.NODE_ENV !== "test") {
@@ -13,7 +13,7 @@ const globalTizen = {
13
13
  describe("keyCodes", () => {
14
14
  describe("keyCode", () => {
15
15
  const { keyCode } = require("..");
16
- const { KEYS } = require("../keys.web");
16
+ const { KEYS } = require("../keys/keys.web");
17
17
 
18
18
  it("returns an object for a given key event", () => {
19
19
  expect(keyCode(KEYS.Enter)).toMatchSnapshot();
@@ -63,7 +63,7 @@ describe("keyCodes", () => {
63
63
  it("uses the proper keyCode for the environment", () => {
64
64
  Platform.OS = "samsung_tv";
65
65
  const { keyCode } = require("../");
66
- const { KEYS } = require("../keys.web");
66
+ const { KEYS } = require("../keys/keys.web");
67
67
 
68
68
  expect(globalTizen.tvinputdevice.registerKeyBatch).toHaveBeenCalledWith([
69
69
  "MediaPlay",
@@ -97,7 +97,7 @@ describe("keyCodes", () => {
97
97
  it("uses the proper keyCode for the environment", () => {
98
98
  Platform.OS = "lg_tv";
99
99
  const { keyCode } = require("..");
100
- const { KEYS } = require("../keys.web");
100
+ const { KEYS } = require("../keys/keys.web");
101
101
  // Back is reserved on LG
102
102
  expect(keyCode({ keyCode: 417 }).matches(KEYS.Forward)).toBeTruthy();
103
103
  });
@@ -6,6 +6,8 @@ import * as R from "ramda";
6
6
  import { directionHelper } from "../directionHelper";
7
7
  import { KEYS, ARROW_KEYS } from "./keys";
8
8
 
9
+ export { KEYS, ARROW_KEYS, keyEventMapper } from "./keys";
10
+
9
11
  /**
10
12
  * @typedef KeyCode
11
13
  * @property {Object} value of the Key
@@ -0,0 +1,3 @@
1
+ export * from "./keys";
2
+
3
+ export { keyEventMapper } from "./keyEventMapper";
@@ -1,22 +1,3 @@
1
- export const KEYS = {
2
- Enter: { code: "Enter", keyCode: 13 },
3
- EnterKeyboard: { code: "EnterKeyboard", keyCode: 66 },
4
- Back: { code: "Back", keyCode: 8 },
5
- Space: { code: "Space", keyCode: 32 },
6
- m: { code: "m", keyCode: 77 },
7
- ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
8
- ArrowUp: { code: "ArrowUp", keyCode: 38 },
9
- ArrowRight: { code: "ArrowRight", keyCode: 39 },
10
- ArrowDown: { code: "ArrowDown", keyCode: 40 },
11
- };
12
-
13
- export const ARROW_KEYS = [
14
- KEYS.ArrowUp,
15
- KEYS.ArrowLeft,
16
- KEYS.ArrowDown,
17
- KEYS.ArrowRight,
18
- ];
19
-
20
1
  export function keyEventMapper(keyCode) {
21
2
  switch (keyCode) {
22
3
  case 19: // ArrowUp
@@ -0,0 +1,18 @@
1
+ export const KEYS = {
2
+ Enter: { code: "Enter", keyCode: 13 },
3
+ EnterKeyboard: { code: "EnterKeyboard", keyCode: 66 },
4
+ Back: { code: "Back", keyCode: 8 },
5
+ Space: { code: "Space", keyCode: 32 },
6
+ m: { code: "m", keyCode: 77 },
7
+ ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
8
+ ArrowUp: { code: "ArrowUp", keyCode: 38 },
9
+ ArrowRight: { code: "ArrowRight", keyCode: 39 },
10
+ ArrowDown: { code: "ArrowDown", keyCode: 40 },
11
+ };
12
+
13
+ export const ARROW_KEYS = [
14
+ KEYS.ArrowUp,
15
+ KEYS.ArrowLeft,
16
+ KEYS.ArrowDown,
17
+ KEYS.ArrowRight,
18
+ ];
@@ -0,0 +1,25 @@
1
+ export const KEYS = {
2
+ Enter: { code: "Enter", keyCode: 13 },
3
+ Space: { code: "Space", keyCode: 32 },
4
+ m: { code: "m", keyCode: 77 },
5
+ ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
6
+ ArrowUp: { code: "ArrowUp", keyCode: 38 },
7
+ ArrowRight: { code: "ArrowRight", keyCode: 39 },
8
+ ArrowDown: { code: "ArrowDown", keyCode: 40 },
9
+ Back: { code: "Backspace", keyCode: 8 },
10
+ Play: { code: "PlayPause", keyCode: 179 },
11
+ Pause: { code: "Pause", keyCode: 179 },
12
+ Forward: { code: "Forward", keyCode: 176 },
13
+ Rewind: { code: "Rewind", keyCode: 177 },
14
+ VolumeUp: { code: "VolumeUp", keyCode: 175 },
15
+ VolumeDown: { code: "VolumeDown", keyCode: 174 },
16
+ ToggleMute: { code: "VolumeMute", keyCode: 173 },
17
+ Stop: { code: "Q", keyCode: 81 },
18
+ };
19
+
20
+ export const ARROW_KEYS = [
21
+ KEYS.ArrowUp,
22
+ KEYS.ArrowLeft,
23
+ KEYS.ArrowDown,
24
+ KEYS.ArrowRight,
25
+ ];
@@ -0,0 +1,15 @@
1
+ // dummy file to make sure the folder structure is created
2
+ export const KEYS: Record<string, { code: string; keyCode: number }> = {
3
+ ArrowLeft: { code: "ArrowLeft", keyCode: -1 },
4
+ ArrowUp: { code: "ArrowUp", keyCode: -1 },
5
+ ArrowRight: { code: "ArrowRight", keyCode: -1 },
6
+ ArrowDown: { code: "ArrowDown", keyCode: -1 },
7
+ Back: { code: "Back", keyCode: -1 },
8
+ };
9
+
10
+ export const ARROW_KEYS = [
11
+ KEYS.ArrowUp,
12
+ KEYS.ArrowLeft,
13
+ KEYS.ArrowDown,
14
+ KEYS.ArrowRight,
15
+ ];
@@ -1,32 +1,21 @@
1
1
  import { BehaviorSubject } from "rxjs";
2
2
 
3
3
  import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
4
+ import {
5
+ isLgPlatform,
6
+ isSamsungPlatform,
7
+ } from "@applicaster/zapp-react-dom-app/App/Loader/utils/platform";
4
8
 
5
9
  import { PLATFORM_KEYS, PLATFORMS } from "./const";
6
10
  import { createLogger, utilsLogger } from "../../logger";
7
11
 
8
- declare global {
9
- interface Window {
10
- VIZIO?: {
11
- exitApplication: () => void;
12
- Chromevox: {
13
- play: (text: string) => void;
14
- };
15
- setClosedCaptionHandler: (
16
- callback: (isCCEnabled: boolean) => void
17
- ) => void;
18
- };
19
- }
20
- }
21
-
22
12
  const { log_debug } = createLogger({
23
13
  category: "General",
24
14
  subsystem: "PlatformUtils",
25
15
  parent: utilsLogger,
26
16
  });
27
17
 
28
- export const getUserAgent = () =>
29
- window?.navigator?.userAgent || global?.navigator?.userAgent;
18
+ export const getUserAgent = () => window?.navigator?.userAgent;
30
19
 
31
20
  /** VIZIO UTILS */
32
21
 
@@ -39,6 +28,8 @@ export const getUserAgent = () =>
39
28
  export const isVizioPlatform = () => {
40
29
  const userAgent = getUserAgent();
41
30
 
31
+ if (!userAgent) return false;
32
+
42
33
  const isVizioAgent =
43
34
  userAgent.includes(PLATFORMS.vizio) ||
44
35
  userAgent.includes(PLATFORMS.smartcast) ||
@@ -178,6 +169,34 @@ export class TTSManager {
178
169
  }
179
170
 
180
171
  readText(text: string) {
172
+ if (isSamsungPlatform() && window.speechSynthesis) {
173
+ const utterance = new SpeechSynthesisUtterance(text);
174
+ window.speechSynthesis.speak(utterance);
175
+ }
176
+
177
+ if (isLgPlatform() && window.webOS?.service) {
178
+ try {
179
+ window.webOS.service.request("luna://com.webos.service.tts", {
180
+ method: "speak",
181
+ onFailure(error: any) {
182
+ log_debug("There was a failure setting up webOS TTS service", {
183
+ error,
184
+ });
185
+ },
186
+ onSuccess(response: any) {
187
+ log_debug("webOS TTS service is configured successfully", {
188
+ response,
189
+ });
190
+ },
191
+ parameters: {
192
+ text,
193
+ },
194
+ });
195
+ } catch (error) {
196
+ log_debug("webOS TTS service error", { error });
197
+ }
198
+ }
199
+
181
200
  if (!window.VIZIO?.Chromevox) return;
182
201
 
183
202
  window.VIZIO.Chromevox.play(text);
@@ -3,7 +3,6 @@ import * as R from "ramda";
3
3
  import { subscriber } from "../../functionUtils";
4
4
  import { utilsLogger, createLogger } from "../../logger";
5
5
  import { Player } from "./player";
6
- import { AnalyticsTracker } from "../../analyticsUtils/analyticsTracker";
7
6
  import {
8
7
  hasTizenAPIs,
9
8
  subscribeToDeviceNetworkChanges,
@@ -37,7 +36,10 @@ export interface PlayerLifecycleListener {
37
36
  }
38
37
 
39
38
  type PlayersMap = {
40
- [id: string]: { player: Player; isInViewport: boolean };
39
+ [id: string]: {
40
+ player: Player;
41
+ isInViewport: boolean;
42
+ };
41
43
  };
42
44
 
43
45
  export class PlayerManager {
@@ -46,7 +48,6 @@ export class PlayerManager {
46
48
  private playersMap: PlayersMap = {};
47
49
  private manager = subscriber();
48
50
  private castingReceiver: Player;
49
- private analyticsTracker: AnalyticsTracker;
50
51
  private lifecycleListeners: PlayerLifecycleListener[] = [];
51
52
 
52
53
  public static getInstance() {
@@ -57,7 +58,7 @@ export class PlayerManager {
57
58
  return PlayerManager.instance;
58
59
  }
59
60
 
60
- public getActivePlayerId = (): String | null => {
61
+ public getActivePlayerId = (): string | null => {
61
62
  return this.activePlayerId;
62
63
  };
63
64
 
@@ -102,7 +103,10 @@ export class PlayerManager {
102
103
  }
103
104
 
104
105
  private addPlayer = (id: string, player: Player) => {
105
- this.playersMap[id] = { player: player, isInViewport: false };
106
+ this.playersMap[id] = {
107
+ player: player,
108
+ isInViewport: false,
109
+ };
106
110
  };
107
111
 
108
112
  public isPlayerRegistered = (id: string) => !!this.playersMap[id];
@@ -251,28 +255,6 @@ export class PlayerManager {
251
255
  this.castingReceiver = null;
252
256
  }
253
257
 
254
- /**
255
- * Handles analytic events, generates a new analytics tracker and transmits events
256
- * Passes entry data, and playerState to the tracker for additional context
257
- * The end result is an event formatted and passed to AnalyticsBridge.postEvent
258
- * When we get the synthetic event we need to pull the data in the e object
259
- * e contains the return value from native
260
- */
261
- public handleAnalyticEvent(event, data = {}, entry: ZappEntry) {
262
- const playerState = this.getActivePlayer()?.getState();
263
-
264
- if (!this.analyticsTracker?.handleAnalyticEvent) {
265
- this.analyticsTracker = new AnalyticsTracker(entry);
266
- }
267
-
268
- this.analyticsTracker?.handleAnalyticEvent?.(
269
- event,
270
- data,
271
- entry,
272
- playerState
273
- );
274
- }
275
-
276
258
  /**
277
259
  * Method retrieves the instantiated player instance controller
278
260
  * Instance controller exposes methods like getContentDuration, getContentPosision