@24i/bigscreen-sdk 1.0.12-alpha.2237 → 1.0.12-alpha.2260
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/package.json +12 -8
- package/packages/analytics/README.md +1 -58
- package/packages/analytics/src/A.ts +1 -51
- package/packages/analytics/src/Analytics.ts +1 -114
- package/packages/analytics/src/analyticsOnScroll.ts +1 -11
- package/packages/analytics/src/clients/ConsoleAnalytics/ConsoleAnalytics.ts +1 -12
- package/packages/analytics/src/constants.ts +1 -56
- package/packages/analytics/src/interface.ts +1 -82
- package/packages/developer-tools/src/DeveloperToolsService/DeveloperToolsList.tsx +11 -0
- package/packages/device/src/getKeyDigit.ts +2 -2
- package/packages/driver-androidtv/src/DeviceAndroidTV.ts +3 -1
- package/packages/driver-androidtv/src/keymap.ts +14 -1
- package/packages/driver-webos/src/DeviceWebos.ts +8 -0
- package/packages/driver-xbox/src/keymap.ts +1 -1
- package/packages/epg/README.md +3 -1
- package/packages/epg/src/v2/Cell.tsx +16 -2
- package/packages/epg/src/v2/DataManager.ts +9 -3
- package/packages/epg/src/v2/Epg.tsx +3 -1
- package/packages/epg/src/v2/Row.tsx +3 -1
- package/packages/epg/src/v2/basic/CellsManager.tsx +7 -2
- package/packages/epg/src/v2/basic/RowsManager.tsx +3 -1
- package/packages/epg/src/v2/interface.ts +13 -0
- package/packages/events-manager/src/EventsManager.ts +1 -56
- package/packages/jsx/src/index.ts +1 -1
- package/packages/list/src/Base/Base.tsx +6 -1
- package/packages/list/src/Base/interface.ts +2 -2
- package/packages/list/src/EdgeOffsetList/EdgeOffsetList.tsx +2 -2
- package/packages/logger/src/loggers/SentryLogger/Sentry.ts +1 -0
- package/packages/logger/src/loggers/SentryLogger/SentryLogger.ts +2 -2
- package/packages/perf-utils/README.md +1 -120
- package/packages/perf-utils/src/array/filter.ts +1 -54
- package/packages/perf-utils/src/array/find.ts +1 -43
- package/packages/perf-utils/src/array/findIndex.ts +1 -43
- package/packages/perf-utils/src/array/forEach.ts +1 -48
- package/packages/perf-utils/src/array/includes.ts +1 -41
- package/packages/perf-utils/src/array/includesNaN.ts +1 -32
- package/packages/perf-utils/src/array/index.ts +1 -7
- package/packages/perf-utils/src/array/map.ts +1 -52
- package/packages/player-ui/src/PlayerUI.tsx +15 -9
- package/packages/player-ui/src/Seekbar.tsx +4 -2
- package/packages/player-ui/src/index.ts +1 -0
- package/packages/player-ui/src/mocks.ts +3 -3
- package/packages/player-ui/src/types.ts +3 -1
- package/packages/router/src/Route.tsx +14 -0
- package/packages/utils/src/wait.ts +3 -1
- package/packages/utils/src/xhr/xhrSendRetry.ts +3 -1
- package/packages/zapping/src/ChannelZapping.ts +9 -0
- package/packages/zapping/src/Zapping.tsx +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@24i/bigscreen-sdk",
|
|
3
|
-
"version": "1.0.12-alpha.
|
|
3
|
+
"version": "1.0.12-alpha.2260",
|
|
4
4
|
"description": "SmartApps BIGscreen SDK monorepo",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -37,14 +37,18 @@
|
|
|
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",
|
|
42
|
+
"@24i/appstage-shared-perf-utils": "1.0.5",
|
|
40
43
|
"@24i/player-base": "6.10.0",
|
|
41
44
|
"@24i/smartapps-datalayer": "3.0.6-alpha.978",
|
|
42
|
-
"@sentry/browser": "
|
|
45
|
+
"@sentry/browser": "7.35.0",
|
|
46
|
+
"@sentry/types": "7.35.0",
|
|
43
47
|
"@types/gtag.js": "^0.0.12",
|
|
44
48
|
"@types/prop-types": "^15.7.5",
|
|
45
49
|
"@types/scheduler": "^0.16.2",
|
|
46
50
|
"csstype": "^3.1.1",
|
|
47
|
-
"lottie-web": "5.
|
|
51
|
+
"lottie-web": "5.10.2",
|
|
48
52
|
"prop-types": "^15.8.1"
|
|
49
53
|
},
|
|
50
54
|
"devDependencies": {
|
|
@@ -53,31 +57,31 @@
|
|
|
53
57
|
"@24i/smartapps-bigscreen-changelog-generator": "0.17.0",
|
|
54
58
|
"@babel/core": "^7.19.0",
|
|
55
59
|
"@babel/preset-env": "^7.20.2",
|
|
56
|
-
"@types/fs-extra": "^
|
|
60
|
+
"@types/fs-extra": "^11.0.1",
|
|
57
61
|
"@types/inquirer": "^9.0.3",
|
|
58
62
|
"@types/jest": "^29.2.3",
|
|
59
63
|
"@types/minimist": "^1.2.2",
|
|
60
64
|
"@types/node": "^18.7.18",
|
|
61
65
|
"@types/react": "^18.0.26",
|
|
62
|
-
"babel-jest": "^29.
|
|
66
|
+
"babel-jest": "^29.4.1",
|
|
63
67
|
"chalk": "^5.2.0",
|
|
64
68
|
"coveralls": "^3.1.1",
|
|
65
69
|
"cross-env": "^7.0.3",
|
|
66
|
-
"fs-extra": "^
|
|
70
|
+
"fs-extra": "^11.1.0",
|
|
67
71
|
"full-icu": "^1.5.0",
|
|
68
72
|
"identity-obj-proxy": "^3.0.0",
|
|
69
73
|
"inquirer": "^9.1.4",
|
|
70
74
|
"jest": "^29.3.1",
|
|
71
75
|
"jest-canvas-mock": "^2.4.0",
|
|
72
76
|
"jest-environment-jsdom": "^29.0.3",
|
|
73
|
-
"minimist": "^1.2.
|
|
77
|
+
"minimist": "^1.2.7",
|
|
74
78
|
"patch-package": "^6.5.0",
|
|
75
79
|
"sass": "^1.54.9",
|
|
76
80
|
"sass-true": "^6.1.0",
|
|
77
81
|
"ts-jest": "^29.0.3",
|
|
78
82
|
"ts-node": "^10.9.1",
|
|
79
83
|
"tsconfig-paths-jest": "0.0.1",
|
|
80
|
-
"typescript": "^4.
|
|
84
|
+
"typescript": "^4.9.5"
|
|
81
85
|
},
|
|
82
86
|
"exports": {
|
|
83
87
|
"./adobe-heartbeat": "./packages/adobe-heartbeat/src/index.ts",
|
|
@@ -5,61 +5,4 @@ hide_title: true
|
|
|
5
5
|
sidebar_label: Analytics
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
This package contains general implementation of analytics and implementation for these clients:
|
|
10
|
-
- ConsoleAnalytics - debugging analytics that dump triggers to the console.
|
|
11
|
-
|
|
12
|
-
## analytics
|
|
13
|
-
Single instance `analytics` is a general manager for analytics clients. It provides a unified
|
|
14
|
-
interface for use by the app without it needing to know any specific analytics client implementation.
|
|
15
|
-
It also adds some general app info to each trigger call (e.g. resolution, language, etc.)
|
|
16
|
-
|
|
17
|
-
## A
|
|
18
|
-
`A` is a shorthand utility function to simplify sending analytics information. It allows setting
|
|
19
|
-
a basic payload that is sent with each trigger call and shallowly merged with trigger payload.
|
|
20
|
-
Trigger payload can override values inside this basic payload.
|
|
21
|
-
|
|
22
|
-
### Usage
|
|
23
|
-
```typescript
|
|
24
|
-
import { A } from '@24i/bigscreen-sdk/analytics';
|
|
25
|
-
|
|
26
|
-
class DetailScene {
|
|
27
|
-
a = A.of({ sceneType: SceneType.DETAIL });
|
|
28
|
-
|
|
29
|
-
activate(params: RouteParams) {
|
|
30
|
-
this.a.addToPayload({
|
|
31
|
-
sceneId: `/detail/${params.assetType}/${params.id}`,
|
|
32
|
-
sceneName: `Detail - ${data.type} - [unknown]`,
|
|
33
|
-
asset: undefined,
|
|
34
|
-
});
|
|
35
|
-
// ...
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async loadAndRenderData() {
|
|
39
|
-
this.a('buffering_start');
|
|
40
|
-
const data = await dataProvider();
|
|
41
|
-
this.a.addToPayload({
|
|
42
|
-
sceneName: `Detail - ${data.type} - ${data.name}`,
|
|
43
|
-
asset: data,
|
|
44
|
-
});
|
|
45
|
-
this.a('buffering_stop');
|
|
46
|
-
// render
|
|
47
|
-
this.a('scene_view');
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
It is better to store shorthand `a` function inside the component instance. Some scenes can be
|
|
52
|
-
instantiated multiple times by the router (e.g. Browse in WL). Therefore it cannot use a single
|
|
53
|
-
instance from a local `./analytics'` import for example.
|
|
54
|
-
|
|
55
|
-
## Clients
|
|
56
|
-
Analytics client is the integration to the specific analytics provider (e.g. Google Analytics).
|
|
57
|
-
It needs to implement `AnalyticsClient` interface and register its instance to receive the events.
|
|
58
|
-
|
|
59
|
-
Clients have to opt-in to events they wish to listen to. This can be done by listing all events or by
|
|
60
|
-
using a regular expression.
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
analytics.addClient(new GoogleAnalytics(), ['scene_view', 'buffering_start', 'buffering_stop']);
|
|
64
|
-
analytics.addClient(new ConsoleAnalytics(), /.*/);
|
|
65
|
-
```
|
|
8
|
+
https://github.com/24i/appstage-shared-packages/blob/main/packages/analytics/README.md
|
|
@@ -1,51 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { AnalyticsEventsMap, AnalyticsEventsNames, AnyPayload, AFunction } from './interface';
|
|
3
|
-
|
|
4
|
-
interface PrivateAFunction extends AFunction {
|
|
5
|
-
payload: AnyPayload,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export class A {
|
|
9
|
-
/**
|
|
10
|
-
* Creates an analytics 'a' function for easy triggering of events.
|
|
11
|
-
* @param payload basic payload that is added to each payload of the returned
|
|
12
|
-
* function call.
|
|
13
|
-
* @returns a function for triggering analytics events
|
|
14
|
-
* @example
|
|
15
|
-
* ```typescript
|
|
16
|
-
* // Creates a function and sets the basic payload.
|
|
17
|
-
* const a = A.of({ sceneType: 'HOME', sceneId: 'home' });
|
|
18
|
-
*
|
|
19
|
-
* // Sends 'scene_view' event with the basic payload.
|
|
20
|
-
* a('scene_view');
|
|
21
|
-
*
|
|
22
|
-
* // Sends 'buffering_stop' with shallow merge of the basic payload and { asset } object.
|
|
23
|
-
* a('buffering_stop', { asset });
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
static of(payload: AnyPayload) {
|
|
27
|
-
const a: PrivateAFunction = (<
|
|
28
|
-
EventName extends AnalyticsEventsNames,
|
|
29
|
-
P extends Partial<Parameters<AnalyticsEventsMap[EventName]>[0]>,
|
|
30
|
-
>(eventName: EventName, eventPayload: P) => {
|
|
31
|
-
analytics.triggerEvent(eventName, {
|
|
32
|
-
...a.payload,
|
|
33
|
-
...eventPayload,
|
|
34
|
-
} as unknown as Parameters<AnalyticsEventsMap[EventName]>[0]);
|
|
35
|
-
}) as unknown as PrivateAFunction;
|
|
36
|
-
a.payload = payload;
|
|
37
|
-
a.addToPayload = (extendedPayload: AnyPayload) => {
|
|
38
|
-
a.payload = {
|
|
39
|
-
...a.payload,
|
|
40
|
-
...extendedPayload,
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
a.setPayload = (newPayload: AnyPayload) => {
|
|
44
|
-
a.payload = newPayload;
|
|
45
|
-
};
|
|
46
|
-
a.clearPayload = () => {
|
|
47
|
-
a.payload = {};
|
|
48
|
-
};
|
|
49
|
-
return a as AFunction;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
1
|
+
export { A } from '@24i/appstage-shared-analytics';
|
|
@@ -1,114 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { i18n } from '@24i/bigscreen-sdk/i18n';
|
|
3
|
-
import type {
|
|
4
|
-
AnalyticsEventsMap,
|
|
5
|
-
AnalyticsEventsNames,
|
|
6
|
-
AnalyticsClient,
|
|
7
|
-
GeneralAppData,
|
|
8
|
-
AppInfo,
|
|
9
|
-
UserInfo,
|
|
10
|
-
} from './interface';
|
|
11
|
-
import { EVENT_NAMES, ONLY_ONCE_EVENTS, UNREPEATABLE_EVENTS } from './constants';
|
|
12
|
-
|
|
13
|
-
class Analytics {
|
|
14
|
-
private events = new EventsManager<AnalyticsEventsMap>();
|
|
15
|
-
|
|
16
|
-
private onlyOnceAlreadySent: string[] = [];
|
|
17
|
-
|
|
18
|
-
private lastPayloadForEvent: Partial<Record<AnalyticsEventsNames, string>> = {};
|
|
19
|
-
|
|
20
|
-
private clients: Record<string, {
|
|
21
|
-
client: AnalyticsClient
|
|
22
|
-
registeredEvents: Partial<Record<AnalyticsEventsNames, Function>>,
|
|
23
|
-
}> = {};
|
|
24
|
-
|
|
25
|
-
private generalAppData: Partial<GeneralAppData> = {
|
|
26
|
-
language: i18n.getLanguage(),
|
|
27
|
-
resolution: `${window.innerWidth}x${window.innerHeight}`,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
private appInfo: Partial<AppInfo> = {};
|
|
31
|
-
|
|
32
|
-
private userInfo: Partial<UserInfo> = {};
|
|
33
|
-
|
|
34
|
-
constructor() {
|
|
35
|
-
i18n.addEventListener('languagechange', this.onLanguageChange);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
addClient(client: AnalyticsClient, events: AnalyticsEventsNames[] | RegExp) {
|
|
39
|
-
if (this.clients[client.name]) {
|
|
40
|
-
throw new Error(`${client.name} analytics client is already registered.`);
|
|
41
|
-
}
|
|
42
|
-
const eventsToRegister = Array.isArray(events)
|
|
43
|
-
? events
|
|
44
|
-
: EVENT_NAMES.filter(events.test.bind(events));
|
|
45
|
-
const registeredEvents: Partial<Record<AnalyticsEventsNames, Function>> = {};
|
|
46
|
-
eventsToRegister.forEach((eventName) => {
|
|
47
|
-
const listener = (payload: any) => {
|
|
48
|
-
client.onEvent(eventName, payload);
|
|
49
|
-
};
|
|
50
|
-
this.events.addEventListener(eventName, listener);
|
|
51
|
-
registeredEvents[eventName] = listener;
|
|
52
|
-
});
|
|
53
|
-
this.clients[client.name] = {
|
|
54
|
-
client,
|
|
55
|
-
registeredEvents,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
removeClient(client: AnalyticsClient) {
|
|
60
|
-
if (this.clients[client.name]) {
|
|
61
|
-
const { registeredEvents } = this.clients[client.name];
|
|
62
|
-
Object.keys(registeredEvents).forEach((eventName) => {
|
|
63
|
-
// @ts-ignore - specific payload typing
|
|
64
|
-
this.events.removeEventListener(eventName, registeredEvents[eventName]!);
|
|
65
|
-
});
|
|
66
|
-
delete this.clients[client.name];
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
triggerEvent<Event extends AnalyticsEventsNames>(
|
|
71
|
-
event: Event,
|
|
72
|
-
triggerPayload: Parameters<AnalyticsEventsMap[Event]>[0] = undefined,
|
|
73
|
-
) {
|
|
74
|
-
const fullPayload = {
|
|
75
|
-
...this.generalAppData,
|
|
76
|
-
...this.appInfo,
|
|
77
|
-
...this.userInfo,
|
|
78
|
-
...triggerPayload,
|
|
79
|
-
};
|
|
80
|
-
if (ONLY_ONCE_EVENTS.includes(event)) {
|
|
81
|
-
const serializedPayload = `${event} - ${JSON.stringify(fullPayload)}`;
|
|
82
|
-
if (this.onlyOnceAlreadySent.includes(serializedPayload)) return;
|
|
83
|
-
this.onlyOnceAlreadySent.push(serializedPayload);
|
|
84
|
-
}
|
|
85
|
-
if (UNREPEATABLE_EVENTS.includes(event)) {
|
|
86
|
-
const serializedPayload = JSON.stringify(fullPayload);
|
|
87
|
-
if (this.lastPayloadForEvent[event] === serializedPayload) return;
|
|
88
|
-
this.lastPayloadForEvent[event] = serializedPayload;
|
|
89
|
-
}
|
|
90
|
-
this.tryFillUpMissingData();
|
|
91
|
-
// @ts-ignore - payload typing
|
|
92
|
-
this.events.triggerEvent(event, fullPayload);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
setAppInfo(data: Partial<AppInfo>) {
|
|
96
|
-
this.appInfo = data;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
setUserInfo(data: Partial<UserInfo>) {
|
|
100
|
-
this.userInfo = data;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private onLanguageChange = () => {
|
|
104
|
-
this.generalAppData.language = i18n.getLanguage();
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
private tryFillUpMissingData() {
|
|
108
|
-
if (!this.generalAppData.language) {
|
|
109
|
-
this.generalAppData.language = i18n.getLanguage();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export const analytics = new Analytics();
|
|
1
|
+
export { analytics } from '@24i/appstage-shared-analytics';
|
|
@@ -1,11 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const analyticsOnScroll = (a: AFunction, itemsTotal: number) => (_: any, index: number) => {
|
|
4
|
-
const percent = (index + 1) / itemsTotal;
|
|
5
|
-
/* eslint-disable no-magic-numbers */
|
|
6
|
-
if (percent >= 0.9) a('scroll_90');
|
|
7
|
-
else if (percent >= 0.75) a('scroll_75');
|
|
8
|
-
else if (percent >= 0.50) a('scroll_50');
|
|
9
|
-
else if (percent >= 0.25) a('scroll_25');
|
|
10
|
-
/* eslint-enable no-magic-numbers */
|
|
11
|
-
};
|
|
1
|
+
export { analyticsOnScroll } from '@24i/appstage-shared-analytics';
|
|
@@ -1,12 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Simple debugging client that dumps all triggers to the console.
|
|
5
|
-
*/
|
|
6
|
-
export class ConsoleAnalytics implements AnalyticsClient {
|
|
7
|
-
name = 'ConsoleAnalytics';
|
|
8
|
-
|
|
9
|
-
onEvent(eventName: string, payload: any) {
|
|
10
|
-
console.info('CA: ', eventName, payload);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
1
|
+
export { ConsoleAnalytics } from '@24i/appstage-shared-analytics/dist/clients/ConsoleAnalytics';
|
|
@@ -1,56 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const EVENT_NAMES = [
|
|
4
|
-
// App
|
|
5
|
-
'app_close',
|
|
6
|
-
|
|
7
|
-
// Data loading / Player buffering
|
|
8
|
-
'buffering_start',
|
|
9
|
-
'buffering_stop',
|
|
10
|
-
|
|
11
|
-
// Heartbeat
|
|
12
|
-
'heartbeat_5',
|
|
13
|
-
|
|
14
|
-
// Playback
|
|
15
|
-
'playback_10',
|
|
16
|
-
'playback_25',
|
|
17
|
-
'playback_50',
|
|
18
|
-
'playback_75',
|
|
19
|
-
'playback_90',
|
|
20
|
-
'playback_pause',
|
|
21
|
-
'playback_start',
|
|
22
|
-
'playback_stop',
|
|
23
|
-
|
|
24
|
-
// Player
|
|
25
|
-
'player_close',
|
|
26
|
-
'player_open',
|
|
27
|
-
|
|
28
|
-
// Scenes
|
|
29
|
-
'scene_view',
|
|
30
|
-
|
|
31
|
-
// Scrolling in scene
|
|
32
|
-
'scroll_25',
|
|
33
|
-
'scroll_50',
|
|
34
|
-
'scroll_75',
|
|
35
|
-
'scroll_90',
|
|
36
|
-
] as const;
|
|
37
|
-
|
|
38
|
-
export const ONLY_ONCE_EVENTS: AnalyticsEventsNames[] = [
|
|
39
|
-
// Playback
|
|
40
|
-
'playback_10',
|
|
41
|
-
'playback_25',
|
|
42
|
-
'playback_50',
|
|
43
|
-
'playback_75',
|
|
44
|
-
'playback_90',
|
|
45
|
-
|
|
46
|
-
// Scrolling in scene
|
|
47
|
-
'scroll_25',
|
|
48
|
-
'scroll_50',
|
|
49
|
-
'scroll_75',
|
|
50
|
-
'scroll_90',
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
export const UNREPEATABLE_EVENTS: AnalyticsEventsNames[] = [
|
|
54
|
-
// Scenes
|
|
55
|
-
'scene_view',
|
|
56
|
-
];
|
|
1
|
+
export * from '@24i/appstage-shared-analytics/dist/constants';
|
|
@@ -1,82 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
sceneId: string,
|
|
3
|
-
sceneType: string,
|
|
4
|
-
sceneName: string,
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export type AppInfo = {
|
|
8
|
-
applicationId: string,
|
|
9
|
-
serviceId: string,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export type UserInfo = {
|
|
13
|
-
userId: string,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export type GeneralAppData = {
|
|
17
|
-
language: string,
|
|
18
|
-
resolution: string,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* List of all tracked events.
|
|
23
|
-
*/
|
|
24
|
-
export type AnalyticsEventsMap = {
|
|
25
|
-
// App
|
|
26
|
-
'app_close': (payload: void) => void,
|
|
27
|
-
|
|
28
|
-
// Data loading / Player buffering
|
|
29
|
-
'buffering_start': (payload: SceneInfo) => void,
|
|
30
|
-
'buffering_stop': (payload: SceneInfo) => void,
|
|
31
|
-
|
|
32
|
-
// Heartbeat
|
|
33
|
-
'heartbeat_5': (payload: void) => void,
|
|
34
|
-
|
|
35
|
-
// Playback
|
|
36
|
-
'playback_10': (payload: void) => void,
|
|
37
|
-
'playback_25': (payload: void) => void,
|
|
38
|
-
'playback_50': (payload: void) => void,
|
|
39
|
-
'playback_75': (payload: void) => void,
|
|
40
|
-
'playback_90': (payload: void) => void,
|
|
41
|
-
'playback_pause': (payload: void) => void,
|
|
42
|
-
'playback_start': (payload: void) => void,
|
|
43
|
-
'playback_stop': (payload: void) => void,
|
|
44
|
-
|
|
45
|
-
// Player
|
|
46
|
-
'player_close': (payload: void) => void,
|
|
47
|
-
'player_open': (payload: void) => void,
|
|
48
|
-
|
|
49
|
-
// Scenes
|
|
50
|
-
'scene_view': (payload: SceneInfo) => void,
|
|
51
|
-
|
|
52
|
-
// Scrolling in scene
|
|
53
|
-
'scroll_25': (payload: SceneInfo) => void,
|
|
54
|
-
'scroll_50': (payload: SceneInfo) => void,
|
|
55
|
-
'scroll_75': (payload: SceneInfo) => void,
|
|
56
|
-
'scroll_90': (payload: SceneInfo) => void,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export type AnalyticsEventsNames = keyof AnalyticsEventsMap;
|
|
60
|
-
|
|
61
|
-
export interface AnalyticsClient {
|
|
62
|
-
name: string,
|
|
63
|
-
onEvent<Event extends keyof AnalyticsEventsMap>(
|
|
64
|
-
eventName: Event,
|
|
65
|
-
payload: Parameters<AnalyticsEventsMap[Event]>,
|
|
66
|
-
): void;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export type AnyPayload = Record<string, any>;
|
|
70
|
-
|
|
71
|
-
export interface AFunction {
|
|
72
|
-
<
|
|
73
|
-
EventName extends AnalyticsEventsNames,
|
|
74
|
-
P extends Partial<Parameters<AnalyticsEventsMap[EventName]>[0]>,
|
|
75
|
-
>(eventName: EventName, payload?: P): void,
|
|
76
|
-
|
|
77
|
-
addToPayload(payload: AnyPayload): void,
|
|
78
|
-
|
|
79
|
-
setPayload(payload: AnyPayload): void,
|
|
80
|
-
|
|
81
|
-
clearPayload(): void,
|
|
82
|
-
}
|
|
1
|
+
export * from '@24i/appstage-shared-analytics/dist/interface';
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { BACK } from '@24i/bigscreen-sdk/device/keymap';
|
|
8
8
|
import { DISPLAY_NONE, getDisplayToggler, stopEvent } from '@24i/bigscreen-sdk/utils';
|
|
9
9
|
import { map } from '@24i/bigscreen-sdk/perf-utils/array';
|
|
10
|
+
import { Storage } from '@24i/bigscreen-sdk/storage';
|
|
10
11
|
import { IDeveloperTool, DeveloperToolProps } from '../IDeveloperTool';
|
|
11
12
|
import { DeveloperToolItem } from './DeveloperToolItem';
|
|
12
13
|
import { reloadApp } from '../utils/reload';
|
|
@@ -39,6 +40,11 @@ export class DeveloperToolsList extends Component<Props> {
|
|
|
39
40
|
reloadApp();
|
|
40
41
|
};
|
|
41
42
|
|
|
43
|
+
async onClearDataToolPress() {
|
|
44
|
+
await Storage.clear();
|
|
45
|
+
reloadApp();
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
onKeyDown = (event: KeyboardEvent) => {
|
|
43
49
|
if (BACK.is(event)) {
|
|
44
50
|
const { onBack } = this.props;
|
|
@@ -90,6 +96,11 @@ export class DeveloperToolsList extends Component<Props> {
|
|
|
90
96
|
/>
|
|
91
97
|
);
|
|
92
98
|
})}
|
|
99
|
+
<DeveloperToolItem
|
|
100
|
+
ref={this.getNavigationRef()}
|
|
101
|
+
label="Clear data"
|
|
102
|
+
onPress={this.onClearDataToolPress}
|
|
103
|
+
/>
|
|
93
104
|
<DeveloperToolItem
|
|
94
105
|
ref={this.getNavigationRef()}
|
|
95
106
|
label="Restart app"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { KeycodeKeyMap } from '@24i/bigscreen-sdk/driver-base';
|
|
2
2
|
|
|
3
3
|
export const createGetKeyDigit = (
|
|
4
|
-
getKeyMap: () => Partial<KeycodeKeyMap
|
|
5
|
-
|
|
4
|
+
getKeyMap: () => Partial<KeycodeKeyMap>,
|
|
5
|
+
): (event: KeyboardEvent) => number | undefined => {
|
|
6
6
|
const {
|
|
7
7
|
NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9,
|
|
8
8
|
KP_0, KP_1, KP_2, KP_3, KP_4, KP_5, KP_6, KP_7, KP_8, KP_9,
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from '@24i/bigscreen-sdk/driver-base';
|
|
7
7
|
import { IJavaScriptBridge, DeviceInfo } from './types';
|
|
8
8
|
import { getFirmware } from './formatUserAgent';
|
|
9
|
-
import { getKeyMap } from './keymap';
|
|
9
|
+
import { getKeyMap, AndroidKeyMap } from './keymap';
|
|
10
10
|
|
|
11
11
|
interface CustomKeyboardEvent extends KeyboardEvent {
|
|
12
12
|
/** Flag indicating that the driver has already re-emitted this event. */
|
|
@@ -69,6 +69,8 @@ export class DeviceAndroidTV extends DeviceBase {
|
|
|
69
69
|
if (key === 'ColorF2Yellow') keyCode = this.keyMap.YELLOW;
|
|
70
70
|
if (key === 'ColorF3Blue') keyCode = this.keyMap.BLUE;
|
|
71
71
|
if (key === 'ClosedCaptionToggle') keyCode = this.keyMap.SUBTITLES;
|
|
72
|
+
if (keyCode === AndroidKeyMap.STOP) keyCode = this.keyMap.STOP;
|
|
73
|
+
if (keyCode === AndroidKeyMap.PAUSE) keyCode = this.keyMap.PAUSE;
|
|
72
74
|
|
|
73
75
|
if (keyCode === this.keyMap.BACK
|
|
74
76
|
|| keyCode === this.keyMap.STOP
|
|
@@ -4,11 +4,24 @@ import { KeyMap } from '@24i/bigscreen-sdk/driver-base';
|
|
|
4
4
|
export const getKeyMap = () => {
|
|
5
5
|
KeyMap.overrideValues({
|
|
6
6
|
BACK: { keyCode: 4 },
|
|
7
|
-
STOP: { keyCode:
|
|
7
|
+
STOP: { keyCode: 86 },
|
|
8
8
|
FF: { keyCode: 90 },
|
|
9
9
|
REW: { keyCode: 89 },
|
|
10
10
|
PLAY: { keyCode: 126 },
|
|
11
|
+
PAUSE: { keyCode: 127 },
|
|
12
|
+
PLAYPAUSE: { keyCode: 85 },
|
|
11
13
|
SUBTITLES: { keyCode: 175 },
|
|
12
14
|
});
|
|
13
15
|
return KeyMap.generateKeyCodeKeyMap();
|
|
14
16
|
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* For the specific AndroidTV devices like Sony Bravia or Nvidia Shield
|
|
20
|
+
* there are different KeyCodes for some buttons than on other platforms.
|
|
21
|
+
* In that case we need to re-map this specific KeyCodes to the
|
|
22
|
+
* same values as we using in generic KeyMap list for the AndroidTV.
|
|
23
|
+
*/
|
|
24
|
+
export const AndroidKeyMap = {
|
|
25
|
+
STOP: 178,
|
|
26
|
+
PAUSE: 85,
|
|
27
|
+
};
|
|
@@ -95,7 +95,15 @@ export class DeviceWebos extends DeviceBase {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
initMouseActiveListener() {
|
|
98
|
+
// checks if mouse is already being used since startup - PRDSAPPSBW-1005
|
|
99
|
+
const mouseActiveAtStartupHandler = () => {
|
|
100
|
+
document.removeEventListener('mousemove', mouseActiveAtStartupHandler);
|
|
101
|
+
this.isMouseActive = true;
|
|
102
|
+
this.triggerEvent('mouseactive', { isMouseActive: true });
|
|
103
|
+
};
|
|
104
|
+
document.addEventListener('mousemove', mouseActiveAtStartupHandler);
|
|
98
105
|
document.addEventListener('cursorStateChange', (event) => {
|
|
106
|
+
document.removeEventListener('mousemove', mouseActiveAtStartupHandler);
|
|
99
107
|
// @ts-ignore - the LG event has this structure.
|
|
100
108
|
this.isMouseActive = event.detail.visibility;
|
|
101
109
|
this.triggerEvent('mouseactive', {
|
package/packages/epg/README.md
CHANGED
|
@@ -18,6 +18,7 @@ This package contains a prepared Electronic Program Guide component.
|
|
|
18
18
|
- `channelHeaderWidthPx` - the width of the channel headers (the part before programs in a row) in pixels
|
|
19
19
|
- `channelData` - the array of channels of a type that extends `EpgChannel` from the data layer
|
|
20
20
|
- `fetchPrograms` - the function to fetch more programs for a channel in a given time range
|
|
21
|
+
- `smallestAllowedCellPx` - optional - cells with width less than this are marked with `.too-small` class (defaults to `0`)
|
|
21
22
|
- `timelineWidthMs` - optional - the width of the timeline (the part where the programs are) in milliseconds (defaults to `90 minutes`)
|
|
22
23
|
- `scrollStepMs` - optional - the amount of movement step left/right in milliseconds (defaults to `0.5 hours`)
|
|
23
24
|
- `idleTimerMs` - optional - the amount of ms without user input after which epg jumps to the current time (defaults to `scrollStepMs`)
|
|
@@ -80,10 +81,11 @@ then the initial time of EPG will be `13:30` (if not set otherwise)
|
|
|
80
81
|
- `endTime` is always taken as excluded = not the part of the program
|
|
81
82
|
- so the program that gets focused/marked as live / etc. is the one that is just starting
|
|
82
83
|
- when the Program displayed by the cell is currently live, the cell has an `.live` class
|
|
83
|
-
- the Cell has also these following classes based on its width
|
|
84
|
+
- the Cell has also these following classes based on its width, breakpoints defined by `programTextModeResolver` and `smallestAllowedCellPx`
|
|
84
85
|
- `.with-text` - this cell should display full or ellipsis truncated text
|
|
85
86
|
- `.ellipsis-only` - this cell should display only ellipsis. You can use this class to center the text.
|
|
86
87
|
- `.no-text` - this cell is so small that it should be empty
|
|
88
|
+
- `.too-small` - this cell is too small to render the usual way, as in its only several pixels wide, less than the needed margin/border etc.
|
|
87
89
|
- the element of the currently focused row has an `.active` class
|
|
88
90
|
|
|
89
91
|
## Styles
|
|
@@ -17,6 +17,7 @@ const LIVE_CLASS = 'live';
|
|
|
17
17
|
const NO_TEXT_CLASS = 'no-text';
|
|
18
18
|
const ELLIPSIS_ONLY_CLASS = 'ellipsis-only';
|
|
19
19
|
const WITH_TEXT_CLASS = 'with-text';
|
|
20
|
+
const TOO_SMALL_CLASS = 'too-small';
|
|
20
21
|
|
|
21
22
|
const getClassByTextMode = (textMode: ProgramTextMode) => {
|
|
22
23
|
switch (textMode) {
|
|
@@ -40,6 +41,8 @@ export class Cell<
|
|
|
40
41
|
|
|
41
42
|
widthPx = this.props.widthPx;
|
|
42
43
|
|
|
44
|
+
smallestAllowedCellPx = this.props.smallestAllowedCellPx;
|
|
45
|
+
|
|
43
46
|
xOffsetPx = this.props.xOffsetPx;
|
|
44
47
|
|
|
45
48
|
textMode = this.props.programTextModeResolver(this.widthPx);
|
|
@@ -137,6 +140,14 @@ export class Cell<
|
|
|
137
140
|
this.textMode = textMode;
|
|
138
141
|
}
|
|
139
142
|
|
|
143
|
+
private setTooSmallClass() {
|
|
144
|
+
if (this.widthPx < this.smallestAllowedCellPx) {
|
|
145
|
+
addClass(this.div, TOO_SMALL_CLASS);
|
|
146
|
+
} else {
|
|
147
|
+
removeClass(this.div, TOO_SMALL_CLASS);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
140
151
|
focus(options?: FocusOptions) {
|
|
141
152
|
if (!this.wasFocusedWithCurrentItem && document.activeElement === this.div.current) {
|
|
142
153
|
this.onFocusChange();
|
|
@@ -169,6 +180,7 @@ export class Cell<
|
|
|
169
180
|
this.item = item;
|
|
170
181
|
this.setLiveClass();
|
|
171
182
|
this.setTextModeClass(textMode);
|
|
183
|
+
this.setTooSmallClass();
|
|
172
184
|
this.programComponent.current!.updateData(
|
|
173
185
|
this.item!,
|
|
174
186
|
textMode,
|
|
@@ -179,13 +191,15 @@ export class Cell<
|
|
|
179
191
|
|
|
180
192
|
render() {
|
|
181
193
|
const {
|
|
182
|
-
isLoading, xOffsetPx, widthPx,
|
|
194
|
+
isLoading, xOffsetPx, widthPx, smallestAllowedCellPx,
|
|
195
|
+
item, programTextModeResolver, renderProgram,
|
|
183
196
|
} = this.props;
|
|
184
197
|
const textMode = programTextModeResolver(widthPx);
|
|
198
|
+
const tooSmall = widthPx < smallestAllowedCellPx ? TOO_SMALL_CLASS : '';
|
|
185
199
|
return (
|
|
186
200
|
<Interactable
|
|
187
201
|
ref={this.div}
|
|
188
|
-
className={`epg-cell ${getClassByTextMode(textMode)}`}
|
|
202
|
+
className={`epg-cell ${getClassByTextMode(textMode)} ${tooSmall}`}
|
|
189
203
|
style={{
|
|
190
204
|
width: `${widthPx}px`,
|
|
191
205
|
...getXOffsetStyleObject(xOffsetPx),
|