@24i/bigscreen-sdk 1.0.12 → 1.0.13-alpha.2281

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/README.md CHANGED
@@ -8,7 +8,7 @@ sidebar_label: README
8
8
  # SmartApps BIGscreen SDK
9
9
 
10
10
  [![Build Status](https://travis-ci.com/24i/smartapps-bigscreen-sdk.svg?token=TvpGGSB2Z1L12QwPagEp&branch=development)](https://travis-ci.com/24i/smartapps-bigscreen-sdk)
11
- [![Coverage Status](https://coveralls.io/repos/github/24i/smartapps-bigscreen-sdk/badge.svg?branch=development&t=dGc701&kill_cache=1)](https://coveralls.io/github/24i/smartapps-bigscreen-sdk?branch=development)
11
+ [![Coverage Status](https://coveralls.io/repos/github/24i/smartapps-bigscreen-sdk/badge.svg?branch=development&t=8n9LTd&kill_cache=1)](https://coveralls.io/github/24i/smartapps-bigscreen-sdk?branch=development)
12
12
 
13
13
  * [GitHub](https://github.com/24i/smartapps-bigscreen-sdk)
14
14
  * [Confluence](https://24imedia.atlassian.net/wiki/spaces/PRDNGBIGSCR/overview)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@24i/bigscreen-sdk",
3
- "version": "1.0.12",
3
+ "version": "1.0.13-alpha.2281",
4
4
  "description": "SmartApps BIGscreen SDK monorepo",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -17,8 +17,8 @@
17
17
  "lintcheck:cached": "npm run eslint -- --cache && npm run stylelint -- --cache",
18
18
  "typecheck": "tsc --noEmit",
19
19
  "typecheck:cached": "npm run typecheck -- --incremental",
20
- "test": "npm run jest -- --no-cache && npm run lintcheck",
21
- "test:cached": "npm run jest && npm run lintcheck:cached",
20
+ "test": "npm run jest -- --no-cache",
21
+ "test:cached": "npm run jest",
22
22
  "coverage": "npm run jest -- --runInBand --coverage && coveralls < coverage/lcov.info",
23
23
  "branchlint": "branchlint",
24
24
  "generate-changelog": "smartapps-bigscreen-changelog-generator",
@@ -37,11 +37,11 @@
37
37
  },
38
38
  "homepage": "https://github.com/24i/smartapps-bigscreen-sdk#readme",
39
39
  "dependencies": {
40
- "@24i/appstage-shared-analytics": "1.0.7",
41
- "@24i/appstage-shared-events-manager": "1.0.5",
40
+ "@24i/appstage-shared-analytics": "1.0.1-alpha1",
41
+ "@24i/appstage-shared-events-manager": "1.0.7",
42
42
  "@24i/appstage-shared-perf-utils": "1.0.5",
43
43
  "@24i/player-base": "6.10.0",
44
- "@24i/smartapps-datalayer": "3.0.6-alpha.978",
44
+ "@24i/smartapps-datalayer": "3.0.7-alpha.990",
45
45
  "@sentry/browser": "7.35.0",
46
46
  "@sentry/types": "7.35.0",
47
47
  "@types/gtag.js": "^0.0.12",
@@ -55,15 +55,15 @@
55
55
  "@24i/bigscreen-sdk": "file:.",
56
56
  "@24i/eslint-config-smartapps-bigscreen-linters": "file:./libs/linters",
57
57
  "@24i/smartapps-bigscreen-changelog-generator": "0.17.0",
58
- "@babel/core": "^7.19.0",
58
+ "@babel/core": "^7.21.0",
59
59
  "@babel/preset-env": "^7.20.2",
60
60
  "@types/fs-extra": "^11.0.1",
61
61
  "@types/inquirer": "^9.0.3",
62
62
  "@types/jest": "^29.2.3",
63
63
  "@types/minimist": "^1.2.2",
64
64
  "@types/node": "^18.7.18",
65
- "@types/react": "^18.0.26",
66
- "babel-jest": "^29.4.1",
65
+ "@types/react": "^18.0.28",
66
+ "babel-jest": "^29.4.3",
67
67
  "chalk": "^5.2.0",
68
68
  "coveralls": "^3.1.1",
69
69
  "cross-env": "^7.0.3",
@@ -34,15 +34,20 @@ export class GoogleAnalytics implements AnalyticsClient {
34
34
  cid: '',
35
35
  sid: 0,
36
36
  uamb: 0,
37
- uap: '',
38
- uapv: '',
39
- uam: '',
40
37
  seg: 0,
41
38
  sct: 0,
42
39
  _p: generateUuid(),
40
+ 'up.device_manufacturer': '',
41
+ 'up.device_platform': '',
42
+ 'up.device_platform_version': '',
43
+ 'up.app_version': '',
43
44
  };
44
45
 
45
- a24iOperational = false;
46
+ manufacturer = '';
47
+
48
+ platform = '';
49
+
50
+ platformVersion = '';
46
51
 
47
52
  lastOnEvent: number | undefined = undefined;
48
53
 
@@ -58,7 +63,7 @@ export class GoogleAnalytics implements AnalyticsClient {
58
63
 
59
64
  firstVisit: boolean | undefined = undefined;
60
65
 
61
- constructor(private id: string) {
66
+ constructor(private id: string, private appVersion: string = '') {
62
67
  this.init();
63
68
  }
64
69
 
@@ -73,16 +78,20 @@ export class GoogleAnalytics implements AnalyticsClient {
73
78
  if (this.firstVisit) {
74
79
  await Storage.setItem(GA_FIRST_VISIT, '0');
75
80
  }
81
+ this.manufacturer = await device.getManufacturerName();
82
+ this.platform = await device.getPlatformName();
83
+ this.platformVersion = await device.getPlatformVersion();
76
84
  await this.startSession();
77
- params.uap = await device.getPlatformName();
78
- params.uapv = await device.getPlatformVersion();
79
- params.uam = await device.getModelName();
80
85
  }
81
86
 
82
87
  async startSession() {
83
88
  const sessionNumber = parseInt(await Storage.getItem(GA_SESSION_COUNTER) ?? '0', 10) + 1;
84
89
  this.constantUrlParams.sct = sessionNumber;
85
90
  this.constantUrlParams.sid = generateSessionId();
91
+ this.constantUrlParams['up.device_manufacturer'] = this.manufacturer;
92
+ this.constantUrlParams['up.device_platform'] = this.platform;
93
+ this.constantUrlParams['up.device_platform_version'] = this.platformVersion;
94
+ this.constantUrlParams['up.app_version'] = this.appVersion;
86
95
  await Storage.setItem(GA_SESSION_COUNTER, sessionNumber.toString());
87
96
  this.isSessionActive = true;
88
97
  this.setSessionTimeout();
@@ -113,11 +122,14 @@ export class GoogleAnalytics implements AnalyticsClient {
113
122
  const engagementTime = this.lastOnEvent ? now - this.lastOnEvent : undefined;
114
123
  this.lastOnEvent = now;
115
124
  await Promise.all(events.map(async (event, index) => {
116
- if (event === 'a24i_operational' && !this.shouldContinueWithA24iOperational()) return;
125
+ const sessionInfo = await this.getSessionInfo(
126
+ index === 0 ? engagementTime : undefined,
127
+ );
117
128
  const gtagPayload = mapPayload(
118
- event, triggerName, await this.getSessionInfo(
119
- index === 0 ? engagementTime : undefined,
120
- ),
129
+ event, triggerName, {
130
+ ...payload,
131
+ ...sessionInfo,
132
+ },
121
133
  );
122
134
  const urlParams = mapEventParamsToUrlParams(payload as SceneInfo);
123
135
  this.send(event, gtagPayload, urlParams);
@@ -162,12 +174,6 @@ export class GoogleAnalytics implements AnalyticsClient {
162
174
 
163
175
  private sendQueueWithDelay = debounce(this.sendQueue, SEND_DEBOUNCE_MS);
164
176
 
165
- private shouldContinueWithA24iOperational() {
166
- const { a24iOperational } = this;
167
- if (!a24iOperational) this.a24iOperational = true;
168
- return !a24iOperational;
169
- }
170
-
171
177
  private async getSessionInfo(engagementTime: number | undefined): Promise<SessionInfo> {
172
178
  const sessionStarted = !this.sessionStartSent;
173
179
  this.sessionStartSent = true;
@@ -176,6 +182,9 @@ export class GoogleAnalytics implements AnalyticsClient {
176
182
  const { firstVisit } = this;
177
183
  this.firstVisit = false;
178
184
  return {
185
+ appVersion: this.appVersion,
186
+ manufacturer: this.manufacturer,
187
+ platform: this.platform,
179
188
  sessionStarted,
180
189
  engagementTime,
181
190
  firstEvent,
@@ -1,7 +1,12 @@
1
1
  import { GAEventsNames } from './interface';
2
2
 
3
+ const stringParameter = 'ep';
4
+ const numericParameter = 'epn';
5
+
3
6
  export const GOOGLE_ANALYTICS_TRIGGERS = [
7
+ 'scene_view',
4
8
  'app_close',
9
+ // player triggers
5
10
  'playback_10',
6
11
  'playback_25',
7
12
  'playback_50',
@@ -12,42 +17,92 @@ export const GOOGLE_ANALYTICS_TRIGGERS = [
12
17
  'playback_stop',
13
18
  'player_close',
14
19
  'player_open',
15
- 'scene_view',
20
+ 'heartbeat_5',
21
+ // scroll triggers
16
22
  'scroll_25',
17
23
  'scroll_50',
18
24
  'scroll_75',
19
25
  'scroll_90',
26
+ // additional triggers
27
+ 'app_error',
28
+ 'toggle_favorite',
29
+ 'search',
30
+ 'rate_content',
31
+ // ads triggers
32
+ 'ad_loaded',
33
+ 'ad_skipped',
34
+ // user triggers
35
+ 'login',
36
+ 'logout',
37
+ 'sign_up',
38
+ // purchases
39
+ 'purchase_cancel',
40
+ 'purchase_complete',
41
+ 'purchase_start',
42
+
20
43
  ] as const;
21
44
 
22
45
  export const TRIGGER_NAME_TO_GA_EVENTS: Record<
23
46
  typeof GOOGLE_ANALYTICS_TRIGGERS[number], GAEventsNames[]
24
47
  > = {
25
48
  // App
26
- app_close: ['app_close', 'video_progress'],
49
+ app_close: ['close_player_session', 'video_progress'],
27
50
 
28
51
  // Playback
52
+ heartbeat_5: ['video_progress'],
29
53
  playback_10: ['video_progress'],
30
54
  playback_25: ['video_progress'],
31
55
  playback_50: ['video_progress'],
32
56
  playback_75: ['video_progress'],
33
- playback_90: ['video_progress'],
57
+ playback_90: ['video_complete'],
34
58
  playback_pause: ['video_progress'],
35
59
  playback_start: ['video_start'],
36
60
  playback_stop: ['video_progress'],
37
61
 
38
62
  // Player
39
- player_close: ['a24i_content', 'video_progress'],
40
- player_open: ['a24i_content'],
63
+ player_close: ['close_player_session', 'video_progress'],
64
+ player_open: ['open_player_session'],
41
65
 
42
66
  // Scenes
43
- scene_view: [
44
- 'page_view',
45
- 'a24i_operational',
46
- ],
67
+ scene_view: ['page_view'],
47
68
 
48
69
  // Scrolling in scene
49
70
  scroll_25: ['scroll'],
50
71
  scroll_50: ['scroll'],
51
72
  scroll_75: ['scroll'],
52
73
  scroll_90: ['scroll'],
74
+
75
+ // purchases
76
+ purchase_cancel: [],
77
+ purchase_complete: [],
78
+ purchase_start: [],
79
+
80
+ // additional triggers
81
+ app_error: [],
82
+ toggle_favorite: [],
83
+ search: [],
84
+ rate_content: [],
85
+
86
+ // ads triggers
87
+ ad_loaded: [],
88
+ ad_skipped: [],
89
+
90
+ // user triggers
91
+ login: ['login'],
92
+ logout: [],
93
+ sign_up: [],
94
+ };
95
+
96
+ export const gtagPayloadParams: Record<string, string> = {
97
+ contentType: `${stringParameter}.content_type`,
98
+ episodeNumber: `${numericParameter}.episode_number`,
99
+ seasonNumber: `${numericParameter}.season_number`,
100
+ currentTime: `${numericParameter}.video_current_time`,
101
+ duration: `${numericParameter}.video_duration`,
102
+ percent: `${numericParameter}.video_current_percent`,
103
+ provider: `${stringParameter}.video_provider`,
104
+ title: `${stringParameter}.video_title`,
105
+ seriesTitle: `${stringParameter}.video_series_title`,
106
+ url: `${stringParameter}.video_url`,
107
+ assetId: `${stringParameter}.video_asset_id`,
53
108
  };
@@ -1,12 +1,19 @@
1
1
  export type GAEventsNames = (
2
- | 'a24i_content'
3
- | 'a24i_operational'
4
- | 'app_close'
5
- | 'buffering_start'
6
- | 'page_view'
7
- | 'scroll'
8
- | 'video_progress'
9
- | 'video_start'
2
+ | 'app_close' // When the playback is active at the time the app or website is closing.
3
+ | 'page_view' // Each time the page loads or the browser history state is changed
4
+ | 'scroll' // The first time a user reaches the bottom of each page
5
+ | 'video_progress' // When the video progresses past 10%, 25%, 50%, and 75% duration time
6
+ | 'video_start' // When the video starts playing
7
+ | 'video_complete' // When the video ends
8
+ | 'open_player_session' // When the user opens a player scene and the player is initiated
9
+ | 'close_player_session' // When the user exits the player scene with initiated player
10
+ | 'select_content' // When a user has selected content
11
+ | 'login' // When a user logs in
12
+ | 'sign_up' // When a user has signed up Allows you to see which methods of signup are popular
13
+ | 'search' // When a user searches your content
14
+ | 'purchase' // When a user completes a purchase
15
+ | 'share' // When a user has shared content
16
+ | 'user_engagement' // Periodically, while the app is in the foreground
10
17
  );
11
18
 
12
19
  export type QueuedEvent = {
@@ -16,6 +23,9 @@ export type QueuedEvent = {
16
23
  };
17
24
 
18
25
  export type SessionInfo = {
26
+ appVersion: string,
27
+ manufacturer: string,
28
+ platform: string,
19
29
  engagementTime: number | undefined,
20
30
  sessionStarted: boolean,
21
31
  firstEvent: boolean,
@@ -29,18 +39,20 @@ export type ConstantUrlParams = {
29
39
  sid: number,
30
40
  /** 1 for mobile devices, 0 otherwise */
31
41
  uamb: number,
32
- /** Platform name */
33
- uap: string,
34
- /** Platform version */
35
- uapv: string,
36
- /** Device model name */
37
- uam: string,
38
42
  /** Session engagement 0 for first event of session, 1 otherwise */
39
43
  seg: number,
40
44
  /** Session count */
41
45
  sct: number,
42
46
  /** Random page hash */
43
47
  _p: string,
48
+ /** Device manufacturer e.g. 'Samsung' */
49
+ 'up.device_manufacturer': string,
50
+ /** Platform e.g. 'Tizen' */
51
+ 'up.device_platform': string,
52
+ /** Platform version e.g. '5.0' */
53
+ 'up.device_platform_version': string,
54
+ /** Version of application 'v1.0.0' */
55
+ 'up.app_version': string,
44
56
  };
45
57
 
46
58
  export type EventUrlParams = {
@@ -1,29 +1,46 @@
1
- import type { AnalyticsEventsNames } from '../../interface';
2
- import type { EventUrlParams, GAEventsNames, SessionInfo } from './interface';
1
+ import type { AnalyticsEventsNames, AnyPayload } from '../../interface';
2
+ import type { EventUrlParams, GAEventsNames } from './interface';
3
+ import { gtagPayloadParams } from './constants';
3
4
 
4
- export const mapEventParamsToUrlParams = (eventParams: Record<string, any>) => {
5
- const urlParams: Partial<EventUrlParams> = {};
6
- if (eventParams.language) urlParams.ul = eventParams.language;
7
- if (eventParams.resolution) urlParams.sr = eventParams.resolution;
8
- if (eventParams.sceneId) urlParams.dl = eventParams.sceneId;
9
- if (eventParams.sceneName) urlParams.dt = eventParams.sceneName;
5
+ const map: Record<string, string> = {
6
+ language: 'ul',
7
+ resolution: 'sr',
8
+ sceneId: 'dl',
9
+ sceneName: 'dt',
10
+ };
11
+
12
+ export const mapEventParamsToUrlParams = (eventParams: Record<string, any>)
13
+ : EventUrlParams => {
14
+ const urlParams = {};
15
+ Object.entries(eventParams).forEach(([key]) => {
16
+ if (map[key]) {
17
+ Object.assign(urlParams, {
18
+ [map[key]]: eventParams[key] || '',
19
+ });
20
+ }
21
+ });
10
22
  return urlParams as EventUrlParams;
11
23
  };
12
24
 
13
25
  export const mapPayload = (
14
26
  eventName: GAEventsNames,
15
27
  triggerName: AnalyticsEventsNames,
16
- sessionInfo: SessionInfo,
28
+ payload: AnyPayload,
17
29
  ) => {
18
30
  const gtagPayload: Record<string, any> = {
19
31
  'ep.event_trigger': triggerName,
20
- _et: sessionInfo.engagementTime ?? 0,
21
- _ee: sessionInfo.firstEvent ? 1 : 0,
22
- _fv: sessionInfo.firstVisit ? 1 : 0,
23
- _ss: sessionInfo.sessionStarted ? 1 : 0,
32
+ _et: payload.engagementTime ?? 0,
33
+ _ee: payload.firstEvent ? 1 : 0,
34
+ _fv: payload.firstVisit ? 1 : 0,
35
+ _ss: payload.sessionStarted ? 1 : 0,
24
36
  };
25
37
  if (eventName === 'scroll') {
26
- gtagPayload['epn.percent_scroll'] = parseInt(triggerName.split('_')[1], 10);
38
+ gtagPayload['epn.percent_scrolled'] = parseInt(triggerName.split('_')[1], 10);
27
39
  }
40
+ Object.keys(payload).forEach((key: keyof typeof payload) => {
41
+ if (gtagPayloadParams[key] !== undefined) {
42
+ gtagPayload[gtagPayloadParams[key]] = payload[key];
43
+ }
44
+ });
28
45
  return gtagPayload;
29
46
  };
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.main = void 0;
5
+ const path = require("path");
6
+ const fs = require("fs");
7
+ const fse = require("fs-extra");
8
+ const chalk = require("chalk");
9
+ const minimist = require("minimist");
10
+ const questions_1 = require("./questionnaire/questions");
11
+ const Settings_1 = require("./settings/Settings");
12
+ async function isDirectoryEmpty(dirPath) {
13
+ const files = await fs.promises.readdir(dirPath);
14
+ return !files.length;
15
+ }
16
+ async function copyTemplateFiles(templateDir, targetDir) {
17
+ return fse.copy(templateDir, targetDir);
18
+ }
19
+ function updatePackageJsonFile(filePath, options) {
20
+ let data = fs.readFileSync(filePath, 'utf8');
21
+ const keywords = options.keywords.map((word) => `"${word}"`).join(', ');
22
+ data = data.replace(/("name": ")(.*)(")/, `$1${options.name}$3`);
23
+ data = data.replace(/("version": ")(.*)(")/, `$1${options.version}$3`);
24
+ data = data.replace(/("description": ")(.*)(")/, `$1${options.description}$3`);
25
+ data = data.replace(/("keywords": \[)(.*)(\])/, `$1${keywords}$3`);
26
+ data = data.replace(/("author": ")(.*)(")/, `$1${options.author}$3`);
27
+ fs.writeFileSync(filePath, data);
28
+ }
29
+ function parseArguments(rawArgv) {
30
+ const argv = minimist(rawArgv.slice(2));
31
+ const dirName = argv._[0];
32
+ if (!dirName) {
33
+ console.error('Error: Missing package name');
34
+ process.exit(1);
35
+ }
36
+ return {
37
+ dirName,
38
+ };
39
+ }
40
+ async function main() {
41
+ const { dirName: destDirName } = parseArguments(process.argv);
42
+ const destDir = path.join(process.cwd(), 'packages/', destDirName);
43
+ if (fs.existsSync(destDir)) {
44
+ console.error(`Error: Target directory "${destDir}" already exists`);
45
+ process.exit(1);
46
+ }
47
+ fs.mkdirSync(destDir, { recursive: true });
48
+ const isDirEmpty = await isDirectoryEmpty(destDir);
49
+ if (!isDirEmpty) {
50
+ console.error(`Error: Target directory "${destDir}" is not empty.`);
51
+ process.exit(1);
52
+ }
53
+ const settings = Object.assign({}, Settings_1.Settings);
54
+ settings.name = `${Settings_1.Settings.name}${destDirName}`.toLowerCase();
55
+ const details = await (0, questions_1.promptPackageDetails)(settings);
56
+ const templateDir = path.join(__dirname, '..', 'templates/typescript');
57
+ await copyTemplateFiles(templateDir, destDir);
58
+ const packageJsonFile = path.join(destDir, 'package.json');
59
+ updatePackageJsonFile(packageJsonFile, details);
60
+ const docsSymlinkTarget = path.join('../../../packages/', destDirName, '/README.md');
61
+ const docsSymlinkPath = path.join(process.cwd(), 'docs/packages/', destDirName, '/README.md');
62
+ await fse.ensureSymlink(docsSymlinkTarget, docsSymlinkPath);
63
+ console.log(`${chalk.green('Success')}, package has been initialized!`);
64
+ }
65
+ exports.main = main;
66
+ //# sourceMappingURL=createPackage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPackage.js","sourceRoot":"","sources":["../src/createPackage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const createPackage_1 = require("./createPackage");
4
+ (0, createPackage_1.main)();
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,mDAAuC;AAEvC,IAAA,oBAAI,GAAE,CAAC"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.promptPackageDetails = void 0;
4
+ const inquirer = require("inquirer");
5
+ async function promptPackageDetails(defaultValues) {
6
+ return inquirer.prompt([
7
+ {
8
+ type: 'input',
9
+ name: 'name',
10
+ message: 'Package name:',
11
+ default: defaultValues.name,
12
+ }, {
13
+ type: 'input',
14
+ name: 'version',
15
+ message: 'Version:',
16
+ default: defaultValues.version,
17
+ }, {
18
+ type: 'input',
19
+ name: 'description',
20
+ message: 'Description:',
21
+ }, {
22
+ type: 'input',
23
+ name: 'keywords',
24
+ message: 'Keywords:',
25
+ filter: (ans) => ans.split(/[\s,]+/),
26
+ }, {
27
+ type: 'input',
28
+ name: 'author',
29
+ message: 'Author:',
30
+ default: defaultValues.author,
31
+ },
32
+ ]);
33
+ }
34
+ exports.promptPackageDetails = promptPackageDetails;
35
+ //# sourceMappingURL=questions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"questions.js","sourceRoot":"","sources":["../../src/questionnaire/questions.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AAWrC,KAAK,UAAU,oBAAoB,CAAC,aAA4C;IAC5E,OAAO,QAAQ,CAAC,MAAM,CAAC;QACnB;YACI,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,eAAe;YACxB,OAAO,EAAE,aAAa,CAAC,IAAI;SAC9B,EAAE;YACC,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,UAAU;YACnB,OAAO,EAAE,aAAa,CAAC,OAAO;SACjC,EAAE;YACC,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,cAAc;SAC1B,EAAE;YACC,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,WAAW;YACpB,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;SACvC,EAAE;YACC,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE,aAAa,CAAC,MAAM;SAChC;KACJ,CAAC,CAAC;AACP,CAAC;AAEQ,oDAAoB"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Settings = void 0;
4
+ const Settings = {
5
+ name: '@24i/smartapps-bigscreen-',
6
+ version: '0.0.1',
7
+ author: '24i',
8
+ };
9
+ exports.Settings = Settings;
10
+ //# sourceMappingURL=Settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Settings.js","sourceRoot":"","sources":["../../src/settings/Settings.ts"],"names":[],"mappings":";;;AAAA,MAAM,QAAQ,GAAG;IACb,IAAI,EAAE,2BAA2B;IACjC,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,KAAK;CAChB,CAAC;AAEO,4BAAQ"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -52,6 +52,7 @@ export class DeviceAndroidTV extends DeviceBase {
52
52
  * on the active (focused) element in the DOM tree.
53
53
  * @param event keyboard event
54
54
  */
55
+ // eslint-disable-next-line complexity
55
56
  relaunchKeyEvent = (event: CustomKeyboardEvent) => {
56
57
  if (event.bigscreenSdkRelaunched) { // prevent to relaunch event in loop
57
58
  return;
@@ -60,6 +61,16 @@ export class DeviceAndroidTV extends DeviceBase {
60
61
  const { key } = event;
61
62
  let { keyCode } = event;
62
63
 
64
+ // KeyCodes collisions for some key sent from Android wrapper or JavaScript (webView)
65
+ if (
66
+ key === 'u' // keyCode 85, same like PLAYPAUSE
67
+ || key === 'v' // keyCode 86, same like STOP
68
+ || key === 'y' // keyCode 89, same like REW
69
+ || key === 'z' // keyCode 90, same like FF
70
+ ) {
71
+ return;
72
+ }
73
+
63
74
  /**
64
75
  * Remap KeyCode by its key value.
65
76
  * On Android all colors keys and some others coming with "0" keyCode.
@@ -12,21 +12,25 @@ export class Key {
12
12
 
13
13
  alternativeKeyCodes: number[];
14
14
 
15
+ key: string;
16
+
15
17
  constructor({
16
18
  id,
17
19
  code = '',
18
20
  keyCode = 0,
19
21
  alternativeCodes = [],
20
22
  alternativeKeyCodes = [],
23
+ key = '',
21
24
  }: Partial<KeyConfig> = {}) {
22
25
  this.id = id!;
23
26
  this.code = code;
24
27
  this.keyCode = keyCode;
25
28
  this.alternativeCodes = alternativeCodes;
26
29
  this.alternativeKeyCodes = alternativeKeyCodes;
30
+ this.key = key;
27
31
  }
28
32
 
29
- is({ keyCode, code }: KeyboardEvent) {
33
+ is({ keyCode, code, key }: KeyboardEvent) {
30
34
  return Boolean(
31
35
  code && ( // empty string code means unknown/invalid --> should not compare
32
36
  code === this.code
@@ -35,6 +39,9 @@ export class Key {
35
39
  || keyCode && ( // keyCode 0 means unknown/invalid --> should not compare
36
40
  keyCode === this.keyCode
37
41
  || this.alternativeKeyCodes.length && includes(this.alternativeKeyCodes, keyCode)
42
+ )
43
+ || key && ( // empty string code means unknown/invalid --> should not compare
44
+ key === this.key
38
45
  ),
39
46
  );
40
47
  }
@@ -4,4 +4,5 @@ export interface KeyConfig {
4
4
  code: string,
5
5
  alternativeKeyCodes: number[],
6
6
  alternativeCodes: string[],
7
+ key : string,
7
8
  }
@@ -6,11 +6,12 @@ import * as KeyMap from './KeyMap';
6
6
  export const overrideValues = (map: Partial<Record<keyof KeycodeKeyMap, Partial<Key>>>) => {
7
7
  // @ts-ignore - map and KeyMap have same keys
8
8
  forEach(Object.entries(map), ([keyName, {
9
- keyCode, code, alternativeKeyCodes, alternativeCodes,
9
+ keyCode, code, alternativeKeyCodes, alternativeCodes, key,
10
10
  }]: [keyof typeof import('./KeyMap'), Partial<Key>]) => {
11
11
  if (typeof keyCode === 'number') KeyMap[keyName].keyCode = keyCode;
12
12
  if (typeof code === 'string') KeyMap[keyName].code = code;
13
13
  if (alternativeKeyCodes) KeyMap[keyName].alternativeKeyCodes = alternativeKeyCodes;
14
14
  if (alternativeCodes) KeyMap[keyName].alternativeCodes = alternativeCodes;
15
+ if (key) KeyMap[keyName].key = key;
15
16
  });
16
17
  };
@@ -2,7 +2,7 @@ import { generateKeyCodeKeyMap, overrideValues } from '@24i/bigscreen-sdk/driver
2
2
 
3
3
  export const getKeyMap = () => {
4
4
  overrideValues({
5
- BACK: { keyCode: 461 },
5
+ BACK: { keyCode: 461, key: 'RCUBack' },
6
6
  TXT: { keyCode: 110 },
7
7
  SUBTITLES: { keyCode: 460 },
8
8
  });
@@ -126,12 +126,14 @@ export class Input extends Component<Props> implements IFocusable {
126
126
  const range = new Range();
127
127
  range.selectNode(textNode);
128
128
  const wholeText = range.getBoundingClientRect();
129
- range.setStart(textNode, position);
129
+ range.setStart(textNode, 0);
130
130
  range.setEnd(textNode, position);
131
131
  const caretText = range.getBoundingClientRect();
132
- const offset = isRtl()
133
- ? wholeText.left - caretText.left
134
- : wholeText.left + wholeText.width - caretText.left;
132
+ const [initialCaretPosition, currentCarretPosition, offsetBase] = isRtl()
133
+ ? [wholeText.right, caretText.left, wholeText.left]
134
+ : [wholeText.left, caretText.right, wholeText.right];
135
+ const caretPos = position === 0 ? initialCaretPosition : currentCarretPosition;
136
+ const offset = offsetBase - caretPos;
135
137
  offsetPosition(this.caret, { x: -offset }, false);
136
138
  }
137
139
 
@@ -220,7 +222,7 @@ export class Input extends Component<Props> implements IFocusable {
220
222
  >
221
223
  {placeholder}
222
224
  </div>
223
- <div ref={this.text} className="text" dir="auto">
225
+ <div ref={this.text} className="text">
224
226
  {this.filterText(value)}
225
227
  </div>
226
228
  <div ref={this.caret} className="caret" />
@@ -783,10 +783,10 @@ declare namespace React {
783
783
 
784
784
  /** Ensures that the props do not include ref at all */
785
785
  type PropsWithoutRef<P> =
786
- // Pick would not be sufficient for this. We'd like to avoid unnecessary mapping and need a distributive conditional to support unions.
786
+ // Omit would not be sufficient for this. We'd like to avoid unnecessary mapping and need a distributive conditional to support unions.
787
787
  // see: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
788
788
  // https://github.com/Microsoft/TypeScript/issues/28339
789
- P extends any ? ('ref' extends keyof P ? Pick<P, Exclude<keyof P, 'ref'>> : P) : P;
789
+ P extends any ? ('ref' extends keyof P ? Omit<P, 'ref'> : P) : P;
790
790
  /** Ensures that the props do not include string ref, which cannot be forwarded */
791
791
  type PropsWithRef<P> =
792
792
  // Just "P extends { ref?: infer R }" looks sufficient, but R will infer as {} if P is {}.
@@ -1941,7 +1941,7 @@ declare namespace React {
1941
1941
  content?: string | undefined;
1942
1942
  controls?: boolean | undefined;
1943
1943
  coords?: string | undefined;
1944
- crossOrigin?: string | undefined;
1944
+ crossOrigin?: "anonymous" | "use-credentials" | "" | undefined;
1945
1945
  data?: string | undefined;
1946
1946
  dateTime?: string | undefined;
1947
1947
  default?: boolean | undefined;
@@ -2229,7 +2229,7 @@ declare namespace React {
2229
2229
  autoFocus?: boolean | undefined;
2230
2230
  capture?: boolean | 'user' | 'environment' | undefined; // https://www.w3.org/TR/html-media-capture/#the-capture-attribute
2231
2231
  checked?: boolean | undefined;
2232
- crossOrigin?: string | undefined;
2232
+ crossOrigin?: "anonymous" | "use-credentials" | "" | undefined;
2233
2233
  disabled?: boolean | undefined;
2234
2234
  enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send' | undefined;
2235
2235
  form?: string | undefined;
@@ -2281,7 +2281,7 @@ declare namespace React {
2281
2281
 
2282
2282
  interface LinkHTMLAttributes<T> extends HTMLAttributes<T> {
2283
2283
  as?: string | undefined;
2284
- crossOrigin?: string | undefined;
2284
+ crossOrigin?: "anonymous" | "use-credentials" | "" | undefined;
2285
2285
  href?: string | undefined;
2286
2286
  hrefLang?: string | undefined;
2287
2287
  integrity?: string | undefined;
@@ -2307,7 +2307,7 @@ declare namespace React {
2307
2307
  autoPlay?: boolean | undefined;
2308
2308
  controls?: boolean | undefined;
2309
2309
  controlsList?: string | undefined;
2310
- crossOrigin?: string | undefined;
2310
+ crossOrigin?: "anonymous" | "use-credentials" | "" | undefined;
2311
2311
  loop?: boolean | undefined;
2312
2312
  mediaGroup?: string | undefined;
2313
2313
  muted?: boolean | undefined;
@@ -2392,7 +2392,7 @@ declare namespace React {
2392
2392
  async?: boolean | undefined;
2393
2393
  /** @deprecated */
2394
2394
  charSet?: string | undefined;
2395
- crossOrigin?: string | undefined;
2395
+ crossOrigin?: "anonymous" | "use-credentials" | "" | undefined;
2396
2396
  defer?: boolean | undefined;
2397
2397
  integrity?: string | undefined;
2398
2398
  noModule?: boolean | undefined;