@24i/bigscreen-sdk 1.0.11-alpha.2225 → 1.0.11
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 +2 -1
- package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoProvider.ts +25 -3
- package/packages/developer-tools/src/TechnicalInfo/__mocks__/Device.ts +4 -0
- package/packages/developer-tools/src/TechnicalInfo/translations.ts +2 -0
- package/packages/driver-androidtv/src/DeviceAndroidTV.ts +7 -1
- package/packages/driver-androidtv/src/__mocks__/javaScriptBridge.ts +4 -0
- package/packages/driver-androidtv/src/types.ts +19 -1
- package/packages/epg/src/v2/DataManager.ts +99 -51
- package/packages/menu/src/MenuAndContentContainer/MenuAndContentContainer.tsx +31 -3
- package/packages/menu/src/MenuAndContentContainer/interface.ts +8 -0
- package/packages/player-ui/src/Seekbar.tsx +23 -1
- package/packages/utils/README.md +13 -0
- package/packages/utils/src/forceReflow.ts +14 -0
- package/packages/utils/src/index.ts +1 -0
- package/packages/utils/src/xhr/xhrSend.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@24i/bigscreen-sdk",
|
|
3
|
-
"version": "1.0.11
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "SmartApps BIGscreen SDK monorepo",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -260,6 +260,7 @@
|
|
|
260
260
|
"./utils/debounce": "./packages/utils/src/debounce.ts",
|
|
261
261
|
"./utils/displayToggler": "./packages/utils/src/displayToggler.ts",
|
|
262
262
|
"./utils/elementUtils": "./packages/utils/src/elementUtils.ts",
|
|
263
|
+
"./utils/forceReflow": "./packages/utils/src/forceReflow.ts",
|
|
263
264
|
"./utils/generateUuid": "./packages/utils/src/generateUuid.ts",
|
|
264
265
|
"./utils/memoryInfo": "./packages/utils/src/memoryInfo.ts",
|
|
265
266
|
"./utils/nTimes": "./packages/utils/src/nTimes.ts",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DeviceBase } from '@24i/bigscreen-sdk/driver-base';
|
|
2
|
+
import { DeviceAndroidTV } from '@24i/bigscreen-sdk/driver-androidtv';
|
|
2
3
|
import { IStorage } from '@24i/bigscreen-sdk/storage/interface';
|
|
3
4
|
import { getUsedJSHeapSize, getTotalJSHeapSize } from '@24i/bigscreen-sdk/utils/memoryInfo';
|
|
4
5
|
import { ipify } from '@24i/bigscreen-sdk/ipify';
|
|
@@ -270,14 +271,23 @@ class TechnicalInfoProvider implements ITechnicalInfoProvider {
|
|
|
270
271
|
return this.props.appCoreVersions || unknown;
|
|
271
272
|
}
|
|
272
273
|
|
|
273
|
-
|
|
274
|
+
async getWrapperVersion() {
|
|
275
|
+
let value;
|
|
276
|
+
const { unknown } = this.translations;
|
|
277
|
+
try {
|
|
278
|
+
value = await (this.props.device as DeviceAndroidTV).getWrapperVersion();
|
|
279
|
+
} catch (e) {}
|
|
280
|
+
return value || unknown;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async getSourceDataLayout() {
|
|
274
284
|
const {
|
|
275
285
|
username, profile, appVersion, firmwareVersion, deviceModel,
|
|
276
286
|
deviceManufacturer, platform, player, serialNumber, localIpAddress,
|
|
277
287
|
publicIpAddress, connectionType, macAddress, memoryHeapSize,
|
|
278
288
|
usedLocalStorage, timeZone, dateAndTime, flavour, userAgent,
|
|
279
289
|
emeSupport, emeDrmSystems, mseSupport, fourKSupport, resolution, baseUrl,
|
|
280
|
-
appCoreVersions,
|
|
290
|
+
appCoreVersions, androidWrapperVersion,
|
|
281
291
|
} = this.translations;
|
|
282
292
|
const dataLayout: SourceDataLayout = [
|
|
283
293
|
{ label: username, getter: this.getUserName },
|
|
@@ -307,9 +317,21 @@ class TechnicalInfoProvider implements ITechnicalInfoProvider {
|
|
|
307
317
|
{ label: resolution, getter: this.getAppResolution },
|
|
308
318
|
{ label: baseUrl, getter: this.getBackendBaseUrl },
|
|
309
319
|
];
|
|
320
|
+
|
|
321
|
+
if (await this.isAndroidTV()) {
|
|
322
|
+
dataLayout.push(
|
|
323
|
+
{ label: androidWrapperVersion, getter: this.getWrapperVersion },
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
310
327
|
return dataLayout;
|
|
311
328
|
}
|
|
312
329
|
|
|
330
|
+
async isAndroidTV() {
|
|
331
|
+
const platformName = await this.props.device.getPlatformName();
|
|
332
|
+
return platformName === 'AndroidTV';
|
|
333
|
+
}
|
|
334
|
+
|
|
313
335
|
async loadDataLayout(dataLayout: SourceDataLayout) {
|
|
314
336
|
const promises = map(dataLayout, async (item) => item.getter.call(this));
|
|
315
337
|
const values = await Promise.all(promises);
|
|
@@ -319,7 +341,7 @@ class TechnicalInfoProvider implements ITechnicalInfoProvider {
|
|
|
319
341
|
}
|
|
320
342
|
|
|
321
343
|
async getInfoData() {
|
|
322
|
-
const sourceDataLayout = this.getSourceDataLayout();
|
|
344
|
+
const sourceDataLayout = await this.getSourceDataLayout();
|
|
323
345
|
return this.loadDataLayout(sourceDataLayout);
|
|
324
346
|
}
|
|
325
347
|
}
|
|
@@ -3,6 +3,7 @@ export type Translations = TranslationKeys | { [K in keyof TranslationKeys]?: ne
|
|
|
3
3
|
export type TranslationKeys = {
|
|
4
4
|
unknown: string
|
|
5
5
|
anonymous: string,
|
|
6
|
+
androidWrapperVersion: string,
|
|
6
7
|
yes: string,
|
|
7
8
|
no: string,
|
|
8
9
|
prefixed: string,
|
|
@@ -41,6 +42,7 @@ export type TranslationKeys = {
|
|
|
41
42
|
export const defaultTranslations = {
|
|
42
43
|
unknown: 'UNKNOWN',
|
|
43
44
|
anonymous: 'ANONYMOUS',
|
|
45
|
+
androidWrapperVersion: 'Android wrapper version',
|
|
44
46
|
yes: 'Yes',
|
|
45
47
|
no: 'No',
|
|
46
48
|
prefixed: 'prefixed',
|
|
@@ -154,6 +154,10 @@ export class DeviceAndroidTV extends DeviceBase {
|
|
|
154
154
|
return VolumeRange.UNSUPPORTED;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
async getWrapperVersion(): Promise<string> {
|
|
158
|
+
return this.platformInfo.appVersion;
|
|
159
|
+
}
|
|
160
|
+
|
|
157
161
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
158
162
|
async setVolume(volumePercentage: number): Promise<void> {
|
|
159
163
|
// not supported on AndroidTV platform
|
|
@@ -195,7 +199,9 @@ export class DeviceAndroidTV extends DeviceBase {
|
|
|
195
199
|
}
|
|
196
200
|
|
|
197
201
|
async getLocalIP(): Promise<string> {
|
|
198
|
-
|
|
202
|
+
const ipv4RegExp = /\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/;
|
|
203
|
+
const ip = this.platformInfo.ipLocal.toString().match(ipv4RegExp);
|
|
204
|
+
if (ip) return ip.toString();
|
|
199
205
|
return '';
|
|
200
206
|
}
|
|
201
207
|
|
|
@@ -7,6 +7,10 @@ export const mockJavaScriptBridge: IJavaScriptBridge = {
|
|
|
7
7
|
deviceBrand: 'Sony',
|
|
8
8
|
deviceModel: 'BRAVIA 4K 2015',
|
|
9
9
|
osVersion: '8.0.0',
|
|
10
|
+
appVersion: '0.0.1',
|
|
11
|
+
appFlavor: 'appstage-bigscreen',
|
|
12
|
+
drmKeySystems: '["W3C Clear Key", "Google Widevine"]',
|
|
13
|
+
ipLocal: '127.0.0.1',
|
|
10
14
|
})
|
|
11
15
|
),
|
|
12
16
|
bridgeJavaScriptToAndroid_Back: () => {},
|
|
@@ -2,7 +2,9 @@ interface JavaScriptBridge {
|
|
|
2
2
|
/**
|
|
3
3
|
* It returns a JSON string with device info.
|
|
4
4
|
* @return JSON string with the information about the device brand, model and Android version.
|
|
5
|
-
* Ex. '{"deviceBrand": "Sony", "deviceModel": "BRAVIA 4K 2015", "osVersion": "7.0"
|
|
5
|
+
* Ex. '{"deviceBrand": "Sony", "deviceModel": "BRAVIA 4K 2015", "osVersion": "7.0",
|
|
6
|
+
* "appFlavor": "appstage-bigscreen", "drmKeySystems": ["Widewine", "W3C ClearKey"],
|
|
7
|
+
* "ipLocal": "fe80::475:3045:2928:3a32%wlan0127.0.0.1", "appVersion": '0.0.1' }'
|
|
6
8
|
*/
|
|
7
9
|
bridgeJavaScriptToAndroid_GetDeviceInfo: () => string,
|
|
8
10
|
/**
|
|
@@ -24,6 +26,22 @@ export type DeviceInfo = {
|
|
|
24
26
|
* Android version. Ex. "7.0"
|
|
25
27
|
*/
|
|
26
28
|
osVersion: string,
|
|
29
|
+
/**
|
|
30
|
+
* Android wrapper version. Ex. "0.0.1"
|
|
31
|
+
*/
|
|
32
|
+
appVersion: string,
|
|
33
|
+
/**
|
|
34
|
+
* Android flavor. Ex. "appstage-bigscreen"
|
|
35
|
+
*/
|
|
36
|
+
appFlavor: string,
|
|
37
|
+
/**
|
|
38
|
+
* Android DRM key systems. Ex. ["Widewine", "W3C ClearKey"]
|
|
39
|
+
*/
|
|
40
|
+
drmKeySystems: Array<string>,
|
|
41
|
+
/**
|
|
42
|
+
* Android local IP adress in array Ex. "fe80::475:3045:2928:3a32%wlan0127.0.0.1"
|
|
43
|
+
*/
|
|
44
|
+
ipLocal: string,
|
|
27
45
|
};
|
|
28
46
|
|
|
29
47
|
export interface IJavaScriptBridge {
|
|
@@ -84,67 +84,115 @@ export class DataManager implements IDataManager {
|
|
|
84
84
|
return [data[0].program!.startTime, data[data.length - 1].program!.endTime] as DataRange;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
private isInterceptingDataRanges = (firstDataRange: DataRange, secondDataRange: DataRange) => (
|
|
88
|
+
(firstDataRange[START] < secondDataRange[END]
|
|
89
|
+
&& firstDataRange[START] > secondDataRange[START])
|
|
90
|
+
|| (secondDataRange[START] < firstDataRange[END]
|
|
91
|
+
&& secondDataRange[START] > firstDataRange[START])
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
private findRangeBeforeAndAfter = (currentRange: DataRange) => {
|
|
95
|
+
const rangeAfterIndex = findIndex(
|
|
96
|
+
this.dataRanges,
|
|
97
|
+
(dataRange) => dataRange[END] >= currentRange[END],
|
|
98
|
+
);
|
|
99
|
+
if (rangeAfterIndex === -1) {
|
|
100
|
+
return {
|
|
101
|
+
rangeAfter: undefined,
|
|
102
|
+
rangeBefore: this.dataRanges[this.dataRanges.length - 1],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const rangeAfter = this.dataRanges[rangeAfterIndex];
|
|
106
|
+
const rangeBefore = this.dataRanges[rangeAfterIndex - 1];
|
|
107
|
+
return { rangeAfter, rangeBefore };
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
private generateDataRangesForward = (start: number, end: number, cellSize: number) => {
|
|
111
|
+
const dataRanges: DataRange[] = [[start, start + cellSize]];
|
|
112
|
+
let currentStart = start + cellSize;
|
|
113
|
+
let currentEnd = currentStart + cellSize;
|
|
114
|
+
while (currentStart < end) {
|
|
115
|
+
if (currentEnd >= end) {
|
|
116
|
+
dataRanges.push([currentStart, end]);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
dataRanges.push([currentStart, currentEnd]);
|
|
120
|
+
currentStart += cellSize;
|
|
121
|
+
currentEnd += cellSize;
|
|
122
|
+
}
|
|
123
|
+
return dataRanges;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
private generateDataRangesBackward = (start: number, end: number, cellSize: number) => {
|
|
127
|
+
const dataRanges: DataRange[] = [[start - cellSize, start]];
|
|
128
|
+
let currentEnd = start - cellSize;
|
|
129
|
+
let currentStart = currentEnd - cellSize;
|
|
130
|
+
while (currentEnd > start) {
|
|
131
|
+
if (currentStart <= start) {
|
|
132
|
+
dataRanges.push([start, currentEnd]);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
dataRanges.push([currentStart, currentEnd]);
|
|
136
|
+
currentStart -= cellSize;
|
|
137
|
+
currentEnd -= cellSize;
|
|
138
|
+
}
|
|
139
|
+
return dataRanges;
|
|
140
|
+
};
|
|
141
|
+
|
|
88
142
|
/* eslint-disable complexity */
|
|
89
143
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
90
144
|
private getRangesMissingFromDataInRange([start, end]: DataRange) {
|
|
91
|
-
const
|
|
145
|
+
const currentRange = [start, end] as DataRange;
|
|
92
146
|
const cellSize = TIMELINE_WIDTHS_TO_FETCH * this.timelineWidthMs;
|
|
93
|
-
if (this.dataRanges.length === 0) return [
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
] as DataRange[];
|
|
101
|
-
}
|
|
102
|
-
const lastRangeFrom = this.dataRanges[rangesLength - 1][START];
|
|
103
|
-
const lastRangeTo = this.dataRanges[rangesLength - 1][END];
|
|
104
|
-
if (end > lastRangeTo && start <= lastRangeTo) {
|
|
105
|
-
return [
|
|
106
|
-
[lastRangeTo, lastRangeTo + cellSize],
|
|
107
|
-
] as DataRange[];
|
|
108
|
-
}
|
|
109
|
-
if (start >= lastRangeTo && end >= lastRangeTo && start - lastRangeTo >= cellSize) {
|
|
110
|
-
return [
|
|
111
|
-
[start, end],
|
|
112
|
-
] as DataRange[];
|
|
113
|
-
}
|
|
114
|
-
const ranges: DataRange[] = [];
|
|
115
|
-
let newRange: DataRange = [start, end];
|
|
116
|
-
for (let i = 0; i < rangesLength; i++) {
|
|
117
|
-
const [rangeFrom, rangeTo] = this.dataRanges[i];
|
|
118
|
-
if (start >= rangeTo) {
|
|
119
|
-
if (start - rangeTo <= cellSize) {
|
|
120
|
-
newRange[START] = rangeTo;
|
|
121
|
-
} else {
|
|
122
|
-
const newStart = lastRangeFrom - cellSize;
|
|
123
|
-
newRange[START] = newStart;
|
|
147
|
+
if (this.dataRanges.length === 0) return [currentRange] as DataRange[];
|
|
148
|
+
const { rangeBefore, rangeAfter } = this.findRangeBeforeAndAfter(currentRange);
|
|
149
|
+
if (rangeAfter == null) {
|
|
150
|
+
const lastDataRange = this.dataRanges[this.dataRanges.length - 1];
|
|
151
|
+
if (this.isInterceptingDataRanges(lastDataRange, currentRange)) {
|
|
152
|
+
if (end > lastDataRange[END]) {
|
|
153
|
+
return this.generateDataRangesForward(lastDataRange[END], end, cellSize);
|
|
124
154
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
if (start < rangeFrom) {
|
|
129
|
-
if (end <= rangeFrom) {
|
|
130
|
-
if (newRange[START] !== newRange[END]) ranges.push(newRange);
|
|
131
|
-
return ranges;
|
|
155
|
+
if (start < lastDataRange[START]) {
|
|
156
|
+
return this.generateDataRangesBackward(start, lastDataRange[START], cellSize);
|
|
132
157
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
158
|
+
}
|
|
159
|
+
return [currentRange] as DataRange[];
|
|
160
|
+
}
|
|
161
|
+
if (rangeBefore == null) {
|
|
162
|
+
const firstDataRange = this.dataRanges[0];
|
|
163
|
+
if (this.isInterceptingDataRanges(firstDataRange, currentRange)) {
|
|
164
|
+
if (end > firstDataRange[END]) {
|
|
165
|
+
return this.generateDataRangesForward(firstDataRange[END], end, cellSize);
|
|
137
166
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (end <= rangeTo) {
|
|
141
|
-
return ranges;
|
|
167
|
+
if (start < firstDataRange[START]) {
|
|
168
|
+
return this.generateDataRangesBackward(firstDataRange[START], start, cellSize);
|
|
142
169
|
}
|
|
143
|
-
newRange = [rangeTo, end];
|
|
144
170
|
}
|
|
171
|
+
return [currentRange] as DataRange[];
|
|
172
|
+
}
|
|
173
|
+
const rangeAfterFrom = rangeAfter[START];
|
|
174
|
+
const rangeBeforeTo = rangeBefore[END];
|
|
175
|
+
// Ranges are collapsed
|
|
176
|
+
if (rangeBeforeTo === rangeAfterFrom) return [];
|
|
177
|
+
// Both are not null and don't intercept
|
|
178
|
+
if (
|
|
179
|
+
!this.isInterceptingDataRanges(rangeAfter, currentRange)
|
|
180
|
+
&& !this.isInterceptingDataRanges(rangeBefore, currentRange)
|
|
181
|
+
) {
|
|
182
|
+
return [currentRange];
|
|
183
|
+
}
|
|
184
|
+
// Left intercepts
|
|
185
|
+
if (this.isInterceptingDataRanges(rangeBefore, currentRange)) {
|
|
186
|
+
return [rangeBefore, ...this.generateDataRangesForward(rangeBeforeTo, end, cellSize)];
|
|
187
|
+
}
|
|
188
|
+
// Right intercepts
|
|
189
|
+
if (this.isInterceptingDataRanges(rangeAfter, currentRange)) {
|
|
190
|
+
return [
|
|
191
|
+
...this.generateDataRangesBackward(rangeAfterFrom, start, cellSize),
|
|
192
|
+
rangeAfter,
|
|
193
|
+
];
|
|
145
194
|
}
|
|
146
|
-
|
|
147
|
-
return ranges;
|
|
195
|
+
return [currentRange] as DataRange[];
|
|
148
196
|
}
|
|
149
197
|
|
|
150
198
|
private getMissingRanges(range: DataRange) {
|
|
@@ -100,7 +100,7 @@ export class MenuAndContentContainer<T extends string = string>
|
|
|
100
100
|
* Handles opening with mouse.
|
|
101
101
|
* @param event mouse event
|
|
102
102
|
*/
|
|
103
|
-
|
|
103
|
+
onMouseDown = (event: MouseEvent) => {
|
|
104
104
|
const menu = this.menu.current!;
|
|
105
105
|
if (this.isMenuAvailable() && !menu.isOpen()) {
|
|
106
106
|
menu.open();
|
|
@@ -108,6 +108,30 @@ export class MenuAndContentContainer<T extends string = string>
|
|
|
108
108
|
}
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Handles hover with mouse.
|
|
113
|
+
* @param event mouse event
|
|
114
|
+
*/
|
|
115
|
+
onMouseEnter = (event: MouseEvent) => {
|
|
116
|
+
const menu = this.menu.current!;
|
|
117
|
+
if (this.isMenuAvailable() && !menu.isOpen() && menu.mrcuEnter) {
|
|
118
|
+
menu.mrcuEnter();
|
|
119
|
+
stopEvent(event);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Handles hover end with mouse.
|
|
125
|
+
* @param event mouse event
|
|
126
|
+
*/
|
|
127
|
+
onMouseLeave = (event: MouseEvent) => {
|
|
128
|
+
const menu = this.menu.current!;
|
|
129
|
+
if (this.isMenuAvailable() && !menu.isOpen() && menu.mrcuLeave) {
|
|
130
|
+
menu.mrcuLeave();
|
|
131
|
+
stopEvent(event);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
111
135
|
/**
|
|
112
136
|
* Handles adding/removing mouse listeners based on whether the mouse is used or not.
|
|
113
137
|
* @param event mouse active event
|
|
@@ -137,7 +161,9 @@ export class MenuAndContentContainer<T extends string = string>
|
|
|
137
161
|
if (!this.listensToMouse) {
|
|
138
162
|
this.listensToMouse = true;
|
|
139
163
|
if (!this.menu.current!.isOpen()) this.mouseTriggerElementDisplayToggler.show();
|
|
140
|
-
this.mouseTriggerElement.current!.addEventListener('
|
|
164
|
+
this.mouseTriggerElement.current!.addEventListener('mousedown', this.onMouseDown);
|
|
165
|
+
this.mouseTriggerElement.current!.addEventListener('mouseenter', this.onMouseEnter);
|
|
166
|
+
this.mouseTriggerElement.current!.addEventListener('mouseleave', this.onMouseLeave);
|
|
141
167
|
}
|
|
142
168
|
}
|
|
143
169
|
|
|
@@ -148,7 +174,9 @@ export class MenuAndContentContainer<T extends string = string>
|
|
|
148
174
|
if (this.listensToMouse) {
|
|
149
175
|
this.listensToMouse = false;
|
|
150
176
|
if (!this.menu.current!.isOpen()) this.mouseTriggerElementDisplayToggler.hide();
|
|
151
|
-
this.mouseTriggerElement.current!.removeEventListener('
|
|
177
|
+
this.mouseTriggerElement.current!.removeEventListener('mousedown', this.onMouseDown);
|
|
178
|
+
this.mouseTriggerElement.current!.removeEventListener('mouseenter', this.onMouseEnter);
|
|
179
|
+
this.mouseTriggerElement.current!.removeEventListener('mouseleave', this.onMouseLeave);
|
|
152
180
|
}
|
|
153
181
|
}
|
|
154
182
|
|
|
@@ -112,6 +112,14 @@ export interface Menu<
|
|
|
112
112
|
* Function to close the menu.
|
|
113
113
|
*/
|
|
114
114
|
close(): void,
|
|
115
|
+
/**
|
|
116
|
+
* Function for "hover" effect on the menu.
|
|
117
|
+
*/
|
|
118
|
+
mrcuEnter?(): void,
|
|
119
|
+
/**
|
|
120
|
+
* Function for ending "hover" effect on the menu.
|
|
121
|
+
*/
|
|
122
|
+
mrcuLeave?(): void,
|
|
115
123
|
/**
|
|
116
124
|
* Renders new menu items.
|
|
117
125
|
* @param items new items to render
|
|
@@ -4,6 +4,7 @@ import { stopEvent } from '@24i/bigscreen-sdk/utils/stopEvent';
|
|
|
4
4
|
import { ITimeUpdateEvent, IDurationChangeEvent } from '@24i/player-base';
|
|
5
5
|
import { createTimeout } from '@24i/bigscreen-sdk/utils/timers';
|
|
6
6
|
import { switchByKey } from '@24i/bigscreen-sdk/device/keymap';
|
|
7
|
+
import { getDisplayToggler } from '@24i/bigscreen-sdk/utils/displayToggler';
|
|
7
8
|
import { PlayerTime } from './PlayerTime';
|
|
8
9
|
import { getLiveProgressBasedOnCurrentTime } from './timeUtils';
|
|
9
10
|
import { PlayerUICommonProps } from './types';
|
|
@@ -26,6 +27,8 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
26
27
|
|
|
27
28
|
seekTime = createRef<PlayerTime>();
|
|
28
29
|
|
|
30
|
+
displaySeekPoint = getDisplayToggler(this.seekPoint);
|
|
31
|
+
|
|
29
32
|
leftConsecutiveness = 0;
|
|
30
33
|
|
|
31
34
|
rightConsecutiveness = 0;
|
|
@@ -40,6 +43,8 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
40
43
|
|
|
41
44
|
isMouseDownPressed = false;
|
|
42
45
|
|
|
46
|
+
seekingDisabled = false;
|
|
47
|
+
|
|
43
48
|
static defaultProps = {
|
|
44
49
|
className: '',
|
|
45
50
|
};
|
|
@@ -67,7 +72,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
onMouseMove = (event: MouseEvent) => {
|
|
70
|
-
if (!this.isMouseDownPressed) return;
|
|
75
|
+
if (!this.isMouseDownPressed || this.seekingDisabled) return;
|
|
71
76
|
const { ui: { seeking } } = this.props;
|
|
72
77
|
const wrapRect = this.wrap.current!.getBoundingClientRect();
|
|
73
78
|
const clientX = event.clientX - wrapRect.left;
|
|
@@ -79,6 +84,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
79
84
|
};
|
|
80
85
|
|
|
81
86
|
onMouseClick = (event: MouseEvent) => {
|
|
87
|
+
if (this.seekingDisabled) return;
|
|
82
88
|
const { ui: { seeking } } = this.props;
|
|
83
89
|
const wrapWidth = this.wrap.current!.offsetWidth;
|
|
84
90
|
const percentage = (TO_PERCENT * event.offsetX) / wrapWidth;
|
|
@@ -115,6 +121,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
115
121
|
};
|
|
116
122
|
|
|
117
123
|
onLeft = () => {
|
|
124
|
+
if (this.seekingDisabled) return true;
|
|
118
125
|
const { ui } = this.props;
|
|
119
126
|
this.leftConsecutiveness += 1;
|
|
120
127
|
if (ui.seeking.isAutomaticallySeeking()) {
|
|
@@ -128,6 +135,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
128
135
|
};
|
|
129
136
|
|
|
130
137
|
onRight = () => {
|
|
138
|
+
if (this.seekingDisabled) return true;
|
|
131
139
|
const { ui } = this.props;
|
|
132
140
|
const { seekTime } = ui.seeking;
|
|
133
141
|
if (seekTime == null && this.currentTime + SLOW_TIME >= this.duration) return true;
|
|
@@ -222,6 +230,20 @@ export class Seekbar extends Component<Props> implements IFocusable {
|
|
|
222
230
|
this.seekPoint.current!.style.left = `${percentTime}%`;
|
|
223
231
|
}
|
|
224
232
|
|
|
233
|
+
disableSeeking() {
|
|
234
|
+
this.seekingDisabled = true;
|
|
235
|
+
this.displaySeekPoint.hide();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
enableSeeking() {
|
|
239
|
+
this.seekingDisabled = false;
|
|
240
|
+
this.displaySeekPoint.show();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
isSeekingDisabled() {
|
|
244
|
+
return this.seekingDisabled;
|
|
245
|
+
}
|
|
246
|
+
|
|
225
247
|
render() {
|
|
226
248
|
const { className } = this.props;
|
|
227
249
|
return (
|
package/packages/utils/README.md
CHANGED
|
@@ -21,6 +21,7 @@ import { generateUuid } from '@24i/bigscreen-sdk/utils/generateUuid';
|
|
|
21
21
|
- **[addClass](#addClass)** - safely adds class to reference.
|
|
22
22
|
- **[debounce](#debounce)** - debounced function is only executed again after a period of not being called, supports leading, trailing (default) and both executions.
|
|
23
23
|
- **[displayToggler](#displayToggler)** - exports `getDisplayToggler` that allows you to easily show/hide an element with guard preventing unnecessary DOM calls.
|
|
24
|
+
- **[forceReflow](#forceReflow)** - To force a DOM reflow on given DOM element.
|
|
24
25
|
- **[generateUuid](#generateUuid)** - function to get UUIDv4 according to RFC 4122.
|
|
25
26
|
- **[isMouseUsed](#isMouseUsed)** - **DEPRECATED** moved to `device` package.
|
|
26
27
|
- **[memoryInfo](#memoryInfo)** - two functions that returns currently active segment size and total allocated size of JS heap, in bytes.
|
|
@@ -92,6 +93,18 @@ And returns `IDisplayToggler` interface with 4 functions:
|
|
|
92
93
|
- `isVisible: () => boolean;` - returns true if the element is visible, false otherwise
|
|
93
94
|
- `isHidden: () => boolean;` - returns true if the element is hidden, false otherwise
|
|
94
95
|
|
|
96
|
+
### forceReflow
|
|
97
|
+
To force a DOM reflow on given DOM element. It can be needed for transitions
|
|
98
|
+
or other purposes.
|
|
99
|
+
|
|
100
|
+
It takes 1 param:
|
|
101
|
+
- `elementOrReference: HTMLElement | Reference<HTMLElement>` - DOM element or
|
|
102
|
+
reference to element on which reflow is called.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
forceReflow(elementRef);
|
|
106
|
+
```
|
|
107
|
+
|
|
95
108
|
### generateUuid
|
|
96
109
|
Returns an UUIDv4 according to RFC 4122, like ex. "123e4567-e89b-12d3-a456-426614174000".
|
|
97
110
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Reference, unwrapReference } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* To force a DOM reflow on given DOM element. It can be needed for transitions
|
|
5
|
+
* or other purposes.
|
|
6
|
+
* @param elementOrReference DOM element or reference to element on which reflow is called.
|
|
7
|
+
*/
|
|
8
|
+
export const forceReflow = (
|
|
9
|
+
elementOrReference: HTMLElement | Reference<HTMLElement>,
|
|
10
|
+
) => {
|
|
11
|
+
const element = unwrapReference(elementOrReference);
|
|
12
|
+
if (!element) return;
|
|
13
|
+
void element.offsetHeight; // eslint-disable-line no-void
|
|
14
|
+
};
|
|
@@ -6,6 +6,7 @@ export { addClass } from './addClass';
|
|
|
6
6
|
export { removeClass } from './removeClass';
|
|
7
7
|
export { debounce } from './debounce';
|
|
8
8
|
export { wait } from './wait';
|
|
9
|
+
export { forceReflow } from './forceReflow';
|
|
9
10
|
export { scaledImage } from './scaledImage';
|
|
10
11
|
export { nTimes } from './nTimes';
|
|
11
12
|
export { getDisplayToggler, DISPLAY_NONE } from './displayToggler';
|
|
@@ -84,7 +84,9 @@ function xhrSend(url: string, options: Partial<XhrOptions> = {}): Promise<XhrRes
|
|
|
84
84
|
const xhr = new XMLHttpRequest();
|
|
85
85
|
|
|
86
86
|
function onLoad() {
|
|
87
|
-
const dataText = 'response' in xhr
|
|
87
|
+
const dataText = 'response' in (xhr as XMLHttpRequest)
|
|
88
|
+
? xhr.response
|
|
89
|
+
: xhr.responseText;
|
|
88
90
|
const dataJson = parseJson(dataText);
|
|
89
91
|
const status = xhr.status === undefined ? HttpStatusCode.OK : xhr.status;
|
|
90
92
|
const statusText = xhr.statusText === undefined ? 'OK' : xhr.statusText;
|