@applicaster/zapp-react-native-utils 12.0.0-alpha.9388848580 → 12.0.0-alpha.9417984401
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/analyticsUtils/AnalyticPlayerListener.ts +141 -0
- package/analyticsUtils/PlayerAnalyticsManager.ts +90 -0
- package/analyticsUtils/{analyticsTracker.ts → playerAnalyticsTracker.ts} +19 -10
- package/appUtils/accessibilityManager/index.ts +11 -0
- package/appUtils/platform/platformUtils.ts +32 -0
- package/appUtils/playerManager/index.ts +9 -27
- package/appUtils/playerManager/playerFactory.ts +1 -1
- package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +57 -0
- package/appUtils/playerManager/playerNative.ts +1 -1
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -1
- package/appUtils/playerManager/usePlayerState.tsx +19 -34
- package/cellUtils/index.ts +33 -0
- package/functionUtils/index.ts +38 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +121 -0
- package/manifestUtils/keys.js +2 -1
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +120 -0
- package/reactHooks/debugging/__tests__/index.test.js +81 -11
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -0
- package/reactHooks/player/useAutoSeek.tsx +9 -7
- package/reactHooks/resolvers/useCellResolver.ts +5 -1
- package/reactHooks/useConfiguration.ts +2 -2
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { PlayerAnalyticsTracker } from "./playerAnalyticsTracker";
|
|
2
|
+
import { Player } from "../appUtils/playerManager/player";
|
|
3
|
+
import { AD_EVENT, GENERAL_EVENT, PLAYBACK_EVENT, QOS_EVENT } from "./events";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
analyticsTracker: any;
|
|
7
|
+
player: any;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/* eslint brace-style: 0 */ // --> OFF
|
|
11
|
+
export class AnalyticPlayerListener
|
|
12
|
+
implements QuickBrickPlayer.SharedPlayerCallBacks
|
|
13
|
+
{
|
|
14
|
+
static analyticsListenerID = "analytics-listener";
|
|
15
|
+
private analyticsTracker: PlayerAnalyticsTracker;
|
|
16
|
+
private player: Player;
|
|
17
|
+
|
|
18
|
+
private onVideoLoadCalled; // android only
|
|
19
|
+
|
|
20
|
+
constructor(props: Props) {
|
|
21
|
+
this.analyticsTracker = props.analyticsTracker;
|
|
22
|
+
this.player = props.player;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
handleAnalyticEvent = (event, data = {}) => {
|
|
26
|
+
if (this.analyticsTracker?.handleAnalyticEvent) {
|
|
27
|
+
this.analyticsTracker?.handleAnalyticEvent?.(event, {
|
|
28
|
+
...data,
|
|
29
|
+
player_type: this.player.playerPluginId,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
onVideoEnd = () => {
|
|
35
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.complete);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
onError = (err: Error) => {
|
|
39
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.error, err); // TODO: Check error format
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
onPlayerPause = (event) => {
|
|
43
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.pause, event);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
onPlayerResume = (event) => {
|
|
47
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.play, event);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
onPlayerSeekComplete = (event) => {
|
|
51
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.seek_complete, event);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
onPlayerSeekStart = (event) => {
|
|
55
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.seek_start, event);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
onBufferStart = (event) => {
|
|
59
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.buffer_start, event);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
onBufferComplete = (event) => {
|
|
63
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.buffer_complete, event);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Not implemented
|
|
67
|
+
onPlayerStop = (event) => {
|
|
68
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.stop, event);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// TODO: Implement method on native
|
|
72
|
+
onVideoBandwidthUpdate = (event) => {
|
|
73
|
+
this.handleAnalyticEvent(QOS_EVENT.bitrate_changed, event);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
onAdBegin = (event) => {
|
|
77
|
+
this.handleAnalyticEvent(AD_EVENT.ad_start, event);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
onAdBreakBegin = (event) => {
|
|
81
|
+
this.handleAnalyticEvent(AD_EVENT.ad_break_start, event);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
onAdBreakEnd = (event) => {
|
|
85
|
+
this.handleAnalyticEvent(AD_EVENT.ad_break_completed, event);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
onAdEnd = (event) => {
|
|
89
|
+
this.handleAnalyticEvent(AD_EVENT.ad_complete, event);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
onAdError = (event) => {
|
|
93
|
+
this.handleAnalyticEvent(AD_EVENT.ad_error, event);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
onAdRequest = (event) => {
|
|
97
|
+
this.handleAnalyticEvent(AD_EVENT.ad_request, event);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
onAdClicked = (event) => {
|
|
101
|
+
this.handleAnalyticEvent(AD_EVENT.ad_clicked, event);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
onAdTapped = (event) => {
|
|
105
|
+
this.handleAnalyticEvent(AD_EVENT.ad_tapped, event);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
onVideoLoad = () => {
|
|
109
|
+
// if (!this.state.isAd && !this.onVideoLoadCalled) {
|
|
110
|
+
if (!this.player.isAd() && !this.onVideoLoadCalled) {
|
|
111
|
+
this.onVideoLoadCalled = true;
|
|
112
|
+
|
|
113
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.load_video, {
|
|
114
|
+
player_type: this.player.playerPluginId,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
onPlayerSessionEnd = () => {
|
|
120
|
+
// TODO: Implement method on native android, ios exists
|
|
121
|
+
this.handleAnalyticEvent(GENERAL_EVENT.session_end);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
onPlayerSessionStart = () => {
|
|
125
|
+
// TODO: Implement method on native android, ios exists
|
|
126
|
+
|
|
127
|
+
this.handleAnalyticEvent(GENERAL_EVENT.session_start);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
onPlayerNext = ({ nativeEvent }) => {
|
|
131
|
+
// TODO: Implement method on native
|
|
132
|
+
|
|
133
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.next, nativeEvent);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
onPlayerPrevious = ({ nativeEvent }) => {
|
|
137
|
+
// TODO: Implement method on native
|
|
138
|
+
|
|
139
|
+
this.handleAnalyticEvent(PLAYBACK_EVENT.previous, nativeEvent);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PlayerAnalyticsTracker,
|
|
3
|
+
PlayerAnalyticsTrackerI,
|
|
4
|
+
} from "./playerAnalyticsTracker";
|
|
5
|
+
import {
|
|
6
|
+
PlayerLifecycleListener,
|
|
7
|
+
PlayerManager,
|
|
8
|
+
} from "../appUtils/playerManager";
|
|
9
|
+
import { Player } from "../appUtils/playerManager/player";
|
|
10
|
+
import { AnalyticPlayerListener } from "./AnalyticPlayerListener";
|
|
11
|
+
import { PlayerRole } from "../appUtils/playerManager/conts";
|
|
12
|
+
|
|
13
|
+
enum PlayerAnalyticsTrackerType {
|
|
14
|
+
PlayerAnalyticsTracker = "PlayerAnalyticsTracker",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class PlayerAnalyticsTrackerFactory {
|
|
18
|
+
createTracker(type: PlayerAnalyticsTrackerType) {
|
|
19
|
+
switch (type) {
|
|
20
|
+
case PlayerAnalyticsTrackerType.PlayerAnalyticsTracker:
|
|
21
|
+
return new PlayerAnalyticsTracker();
|
|
22
|
+
default:
|
|
23
|
+
return new PlayerAnalyticsTracker();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class PlayerAnalyticsManager implements PlayerLifecycleListener {
|
|
29
|
+
static instance: PlayerAnalyticsManager;
|
|
30
|
+
private trackers: Record<string, PlayerAnalyticsTrackerI> = {};
|
|
31
|
+
private trackerFactory: PlayerAnalyticsTrackerFactory;
|
|
32
|
+
|
|
33
|
+
public getTracker(
|
|
34
|
+
id: string,
|
|
35
|
+
type: PlayerAnalyticsTrackerType = PlayerAnalyticsTrackerType.PlayerAnalyticsTracker
|
|
36
|
+
): PlayerAnalyticsTrackerI {
|
|
37
|
+
if (!this.trackers[id]) {
|
|
38
|
+
this.trackers[id] = this.trackerFactory.createTracker(type);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return this.trackers[id];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
constructor(trackerFactory: PlayerAnalyticsTrackerFactory) {
|
|
45
|
+
this.trackerFactory = trackerFactory;
|
|
46
|
+
this.startListenPlayerManager();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static getInstance(
|
|
50
|
+
trackerFactory: PlayerAnalyticsTrackerFactory = new PlayerAnalyticsTrackerFactory()
|
|
51
|
+
): PlayerAnalyticsManager {
|
|
52
|
+
if (!PlayerAnalyticsManager.instance) {
|
|
53
|
+
PlayerAnalyticsManager.instance = new PlayerAnalyticsManager(
|
|
54
|
+
trackerFactory
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return PlayerAnalyticsManager.instance;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private startListenPlayerManager() {
|
|
62
|
+
PlayerManager.getInstance().addLifecycleListener(this);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// PlayerLifecycleListener
|
|
66
|
+
|
|
67
|
+
onRegistered = (player: Player) => {
|
|
68
|
+
if (player.playerRole !== PlayerRole.Primary) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const tracker = this.getTracker(player.playerId);
|
|
73
|
+
tracker.setPlayer(player);
|
|
74
|
+
|
|
75
|
+
const analyticsListener = new AnalyticPlayerListener({
|
|
76
|
+
analyticsTracker: tracker,
|
|
77
|
+
player,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
player.addListener({
|
|
81
|
+
id: AnalyticPlayerListener.analyticsListenerID,
|
|
82
|
+
listener: analyticsListener,
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
onUnRegistered = (player: Player) => {
|
|
87
|
+
player.removeListener(AnalyticPlayerListener.analyticsListenerID);
|
|
88
|
+
delete this.trackers[player.playerId];
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -5,16 +5,25 @@ import { postAnalyticEvent } from "./manager";
|
|
|
5
5
|
import { isLive } from "../playerUtils";
|
|
6
6
|
import { extensionsEvents } from "./AnalyticsEvents/helper";
|
|
7
7
|
import { AD_EVENT, EVENT_TYPES, PLAYER_DISPLAY_STATES } from "./events";
|
|
8
|
+
import { Player } from "../appUtils/playerManager/player";
|
|
8
9
|
|
|
9
|
-
export
|
|
10
|
+
export interface PlayerAnalyticsTrackerI {
|
|
11
|
+
handleAnalyticEvent(
|
|
12
|
+
event: QuickBrickPlayer.Events,
|
|
13
|
+
eventData?: QuickBrickPlayer.EventData
|
|
14
|
+
): void;
|
|
15
|
+
setPlayer(player: Player): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class PlayerAnalyticsTracker implements PlayerAnalyticsTrackerI {
|
|
10
19
|
adTime: number | string;
|
|
11
20
|
mediaTime: number | string;
|
|
12
|
-
entry: ZappEntry;
|
|
13
21
|
eventType: string;
|
|
14
22
|
playerState: QuickBrickPlayer.NativePlayerState;
|
|
23
|
+
private player: Player;
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
this.
|
|
25
|
+
setPlayer(player: Player) {
|
|
26
|
+
this.player = player;
|
|
18
27
|
}
|
|
19
28
|
|
|
20
29
|
isAdBreak(event: string): boolean {
|
|
@@ -30,6 +39,10 @@ export class AnalyticsTracker {
|
|
|
30
39
|
return !!isAdBreak;
|
|
31
40
|
}
|
|
32
41
|
|
|
42
|
+
get entry(): ZappEntry {
|
|
43
|
+
return this.player?.getEntry();
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
getDuration(
|
|
34
47
|
event: QuickBrickPlayer.Events,
|
|
35
48
|
eventData: QuickBrickPlayer.EventData
|
|
@@ -215,13 +228,9 @@ export class AnalyticsTracker {
|
|
|
215
228
|
|
|
216
229
|
handleAnalyticEvent(
|
|
217
230
|
event: QuickBrickPlayer.Events,
|
|
218
|
-
eventData: QuickBrickPlayer.EventData = {}
|
|
219
|
-
entry: ZappEntry,
|
|
220
|
-
playerState = null
|
|
231
|
+
eventData: QuickBrickPlayer.EventData = {}
|
|
221
232
|
) {
|
|
222
|
-
this.
|
|
223
|
-
this.playerState = playerState;
|
|
224
|
-
|
|
233
|
+
this.playerState = this.player?.getState();
|
|
225
234
|
postAnalyticEvent(event, this.prepareAnalyticPayload(event, eventData));
|
|
226
235
|
}
|
|
227
236
|
}
|
|
@@ -138,6 +138,17 @@ export class AccessibilityManager {
|
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
public getInputAccessibilityProps(inputName: string): AccessibilityProps {
|
|
142
|
+
return {
|
|
143
|
+
accessibilityLabel: inputName,
|
|
144
|
+
accessibilityHint: `Enter text into ${inputName}`,
|
|
145
|
+
"aria-label": inputName,
|
|
146
|
+
"aria-description": `Enter text into ${inputName}`,
|
|
147
|
+
accessibilityRole: "textbox" as AccessibilityRole,
|
|
148
|
+
"aria-role": "textbox",
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
141
152
|
public getLocalizedMessage(key: string): string | void {
|
|
142
153
|
if (!key) return;
|
|
143
154
|
|
|
@@ -1,6 +1,10 @@
|
|
|
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";
|
|
@@ -178,6 +182,34 @@ export class TTSManager {
|
|
|
178
182
|
}
|
|
179
183
|
|
|
180
184
|
readText(text: string) {
|
|
185
|
+
if (isSamsungPlatform() && window.speechSynthesis) {
|
|
186
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
187
|
+
window.speechSynthesis.speak(utterance);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (isLgPlatform() && window.webOS?.service) {
|
|
191
|
+
try {
|
|
192
|
+
window.webOS.service.request("luna://com.webos.service.tts", {
|
|
193
|
+
method: "speak",
|
|
194
|
+
onFailure(error: any) {
|
|
195
|
+
log_debug("There was a failure setting up webOS TTS service", {
|
|
196
|
+
error,
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
onSuccess(response: any) {
|
|
200
|
+
log_debug("webOS TTS service is configured successfully", {
|
|
201
|
+
response,
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
parameters: {
|
|
205
|
+
text,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
} catch (error) {
|
|
209
|
+
log_debug("webOS TTS service error", { error });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
181
213
|
if (!window.VIZIO?.Chromevox) return;
|
|
182
214
|
|
|
183
215
|
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]: {
|
|
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 = ():
|
|
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] = {
|
|
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
|
|
@@ -46,7 +46,7 @@ export const playerFactory = (
|
|
|
46
46
|
|
|
47
47
|
// TODO: Fix type:
|
|
48
48
|
const playerProtocol: PlayerConstructor =
|
|
49
|
-
playerPlugin?.module?.playerProtocol(config?.screenConfig);
|
|
49
|
+
playerPlugin?.module?.playerProtocol(config?.screenConfig, config?.entry);
|
|
50
50
|
|
|
51
51
|
const playerView = (playerProtocol as any)?.Component || null;
|
|
52
52
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from "react";
|
|
2
|
+
import { Player } from "../player";
|
|
3
|
+
import { usePlayer } from "../usePlayer";
|
|
4
|
+
import { useThrottle } from "../../../functionUtils";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param listenerId - A unique identifier for the listener.
|
|
9
|
+
* @param playerId - (Optional) The ID of the player to observe.
|
|
10
|
+
* @returns The current playback time in seconds.
|
|
11
|
+
*/
|
|
12
|
+
export const usePlayerCurrentTime = (
|
|
13
|
+
listenerId: string,
|
|
14
|
+
playerId?: string
|
|
15
|
+
): number | null => {
|
|
16
|
+
const [currentTime, setCurrentTime] = useState<number | null>(null);
|
|
17
|
+
const player: Player = usePlayer(playerId);
|
|
18
|
+
|
|
19
|
+
const updateCurrentTime = useCallback(() => {
|
|
20
|
+
if (player) {
|
|
21
|
+
const newCurrentTime = player.getContentPosition();
|
|
22
|
+
|
|
23
|
+
setCurrentTime((prevTime) =>
|
|
24
|
+
prevTime !== newCurrentTime ? newCurrentTime : prevTime
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}, [player]);
|
|
28
|
+
|
|
29
|
+
const { throttledFunction: throttledUpdate, cancel } = useThrottle(
|
|
30
|
+
updateCurrentTime,
|
|
31
|
+
1000
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (player) {
|
|
36
|
+
throttledUpdate();
|
|
37
|
+
|
|
38
|
+
const listeners = {
|
|
39
|
+
onVideoProgress: throttledUpdate,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const id = `${listenerId}_player_current_time`;
|
|
43
|
+
|
|
44
|
+
player.addListener({
|
|
45
|
+
id: id,
|
|
46
|
+
listener: listeners,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
player.removeListener(id);
|
|
51
|
+
cancel();
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}, [player, listenerId, throttledUpdate, cancel]);
|
|
55
|
+
|
|
56
|
+
return currentTime;
|
|
57
|
+
};
|
|
@@ -61,7 +61,7 @@ export class PlayerNative extends Player {
|
|
|
61
61
|
currentPlayerComponent = (): ReactComponent<PlayerProps> =>
|
|
62
62
|
this.playerComponent?.current;
|
|
63
63
|
|
|
64
|
-
getState = () => this.
|
|
64
|
+
getState = () => this.playerState;
|
|
65
65
|
|
|
66
66
|
// TODO: Try to add module interface
|
|
67
67
|
invokeNativeFunction = (funcName: string, ...params: any[]): boolean => {
|
|
@@ -16,24 +16,28 @@ export const usePlayerState = (
|
|
|
16
16
|
listenerId: string,
|
|
17
17
|
playerId?: string
|
|
18
18
|
): PlayerState => {
|
|
19
|
-
const [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const [state, setState] = React.useState<PlayerState>({
|
|
20
|
+
currentTime: null,
|
|
21
|
+
duration: null,
|
|
22
|
+
seekableDuration: null,
|
|
23
|
+
isLive: null,
|
|
24
|
+
isPaused: null,
|
|
25
|
+
isBuffering: false,
|
|
26
|
+
isReadyToPlay: false,
|
|
27
|
+
});
|
|
26
28
|
|
|
27
29
|
const player: Player = usePlayer(playerId);
|
|
28
30
|
|
|
29
31
|
const onPlayerChangeState = React.useCallback(() => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
setState({
|
|
33
|
+
currentTime: player.getContentPosition(),
|
|
34
|
+
duration: player.getDuration(),
|
|
35
|
+
seekableDuration: player.getSeekableDuration(),
|
|
36
|
+
isLive: player.isLive(),
|
|
37
|
+
isPaused: player.isPaused(),
|
|
38
|
+
isBuffering: player.isBuffering(),
|
|
39
|
+
isReadyToPlay: player.isReadyToPlay(),
|
|
40
|
+
});
|
|
37
41
|
}, [player]);
|
|
38
42
|
|
|
39
43
|
React.useEffect(() => {
|
|
@@ -55,24 +59,5 @@ export const usePlayerState = (
|
|
|
55
59
|
}
|
|
56
60
|
}, [player]);
|
|
57
61
|
|
|
58
|
-
return
|
|
59
|
-
() => ({
|
|
60
|
-
currentTime,
|
|
61
|
-
duration,
|
|
62
|
-
seekableDuration,
|
|
63
|
-
isLive,
|
|
64
|
-
isPaused,
|
|
65
|
-
isBuffering,
|
|
66
|
-
isReadyToPlay,
|
|
67
|
-
}),
|
|
68
|
-
[
|
|
69
|
-
currentTime,
|
|
70
|
-
duration,
|
|
71
|
-
seekableDuration,
|
|
72
|
-
isLive,
|
|
73
|
-
isPaused,
|
|
74
|
-
isBuffering,
|
|
75
|
-
isReadyToPlay,
|
|
76
|
-
]
|
|
77
|
-
);
|
|
62
|
+
return state;
|
|
78
63
|
};
|
package/cellUtils/index.ts
CHANGED
|
@@ -468,3 +468,36 @@ export const getColorFromData = ({
|
|
|
468
468
|
|
|
469
469
|
return valueFromLayout;
|
|
470
470
|
};
|
|
471
|
+
|
|
472
|
+
export const getImageStyles = ({
|
|
473
|
+
image,
|
|
474
|
+
value,
|
|
475
|
+
}: {
|
|
476
|
+
image: any;
|
|
477
|
+
value: any;
|
|
478
|
+
}) => {
|
|
479
|
+
return {
|
|
480
|
+
width: image.imageContentWidth,
|
|
481
|
+
height: image.imageContentHeight,
|
|
482
|
+
aspectRatio: image.aspectRatio,
|
|
483
|
+
borderRadius: toNumberWithDefaultZero(value("image_corner_radius")),
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
export const getImageContainerPaddingStyles = ({ value }: { value: any }) => {
|
|
488
|
+
return {
|
|
489
|
+
paddingTop: value("image_padding_top"),
|
|
490
|
+
paddingBottom: value("image_padding_bottom"),
|
|
491
|
+
paddingLeft: value("image_padding_left"),
|
|
492
|
+
paddingRight: value("image_padding_right"),
|
|
493
|
+
};
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
export const getImageContainerMarginStyles = ({ value }: { value: any }) => {
|
|
497
|
+
return {
|
|
498
|
+
marginTop: value("image_margin_top"),
|
|
499
|
+
marginBottom: value("image_margin_bottom"),
|
|
500
|
+
marginLeft: value("image_margin_left"),
|
|
501
|
+
marginRight: value("image_margin_right"),
|
|
502
|
+
};
|
|
503
|
+
};
|
package/functionUtils/index.ts
CHANGED
|
@@ -1,4 +1,42 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param callback - The function to throttle.
|
|
7
|
+
* @param delay - The delay in milliseconds.
|
|
8
|
+
* @returns A throttled version of the callback.
|
|
9
|
+
*/
|
|
10
|
+
export const useThrottle = (callback: () => void, delay: number) => {
|
|
11
|
+
const lastCallRef = useRef<number>(0);
|
|
12
|
+
const timeoutRef = useRef<any | null>(null);
|
|
13
|
+
|
|
14
|
+
const throttledFunction = () => {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
|
|
17
|
+
if (now - lastCallRef.current >= delay) {
|
|
18
|
+
callback();
|
|
19
|
+
lastCallRef.current = now;
|
|
20
|
+
} else if (!timeoutRef.current) {
|
|
21
|
+
const remainingTime = delay - (now - lastCallRef.current);
|
|
22
|
+
|
|
23
|
+
timeoutRef.current = setTimeout(() => {
|
|
24
|
+
callback();
|
|
25
|
+
lastCallRef.current = Date.now();
|
|
26
|
+
timeoutRef.current = null;
|
|
27
|
+
}, remainingTime);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const cancel = () => {
|
|
32
|
+
if (timeoutRef.current) {
|
|
33
|
+
clearTimeout(timeoutRef.current);
|
|
34
|
+
timeoutRef.current = null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return { throttledFunction, cancel };
|
|
39
|
+
};
|
|
2
40
|
|
|
3
41
|
/**
|
|
4
42
|
* standard debounce function.
|
|
@@ -18,6 +18,7 @@ function getDevice(platform) {
|
|
|
18
18
|
case "lg_tv":
|
|
19
19
|
case "samsung_tv":
|
|
20
20
|
case "web":
|
|
21
|
+
case "vizio":
|
|
21
22
|
return "tv";
|
|
22
23
|
}
|
|
23
24
|
}
|
|
@@ -1795,6 +1796,30 @@ function getPlayerConfiguration({ platform }) {
|
|
|
1795
1796
|
key: "menu_header_samsung_letter_spacing",
|
|
1796
1797
|
initial_value: 0,
|
|
1797
1798
|
},
|
|
1799
|
+
{
|
|
1800
|
+
type: "vizio_font_selector",
|
|
1801
|
+
label: "Vizio Font Family",
|
|
1802
|
+
key: "menu_header_vizio_font_family",
|
|
1803
|
+
initial_value: "SmsungOneUI-Bold",
|
|
1804
|
+
},
|
|
1805
|
+
{
|
|
1806
|
+
type: "number_input",
|
|
1807
|
+
label: "Vizio Font Size",
|
|
1808
|
+
key: "menu_header_vizio_font_size",
|
|
1809
|
+
initial_value: 30,
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
type: "number_input",
|
|
1813
|
+
label: "Vizio Line Height",
|
|
1814
|
+
key: "menu_header_vizio_line_height",
|
|
1815
|
+
initial_value: 60,
|
|
1816
|
+
},
|
|
1817
|
+
{
|
|
1818
|
+
type: "number_input",
|
|
1819
|
+
label: "Vizio Letter Spacing",
|
|
1820
|
+
key: "menu_header_vizio_letter_spacing",
|
|
1821
|
+
initial_value: 0,
|
|
1822
|
+
},
|
|
1798
1823
|
]
|
|
1799
1824
|
),
|
|
1800
1825
|
// Captions Menu - Item Text Label
|
|
@@ -1874,6 +1899,30 @@ function getPlayerConfiguration({ platform }) {
|
|
|
1874
1899
|
key: "menu_item_samsung_letter_spacing",
|
|
1875
1900
|
initial_value: 0,
|
|
1876
1901
|
},
|
|
1902
|
+
{
|
|
1903
|
+
type: "vizio_font_selector",
|
|
1904
|
+
label: "Vizio Font Family",
|
|
1905
|
+
key: "menu_item_vizio_font_family",
|
|
1906
|
+
initial_value: "SmsungOneUI-Bold",
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
type: "number_input",
|
|
1910
|
+
label: "Vizio Font Size",
|
|
1911
|
+
key: "menu_item_vizio_font_size",
|
|
1912
|
+
initial_value: 25,
|
|
1913
|
+
},
|
|
1914
|
+
{
|
|
1915
|
+
type: "number_input",
|
|
1916
|
+
label: "Vizio Line Height",
|
|
1917
|
+
key: "menu_item_vizio_line_height",
|
|
1918
|
+
initial_value: 40,
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
type: "number_input",
|
|
1922
|
+
label: "Vizio Letter Spacing",
|
|
1923
|
+
key: "menu_item_vizio_letter_spacing",
|
|
1924
|
+
initial_value: 0,
|
|
1925
|
+
},
|
|
1877
1926
|
]
|
|
1878
1927
|
),
|
|
1879
1928
|
// Captions Menu - Item Border
|
|
@@ -2017,6 +2066,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2017
2066
|
key: "samsung_tv_video_player_title_font_size",
|
|
2018
2067
|
initial_value: 64,
|
|
2019
2068
|
},
|
|
2069
|
+
{
|
|
2070
|
+
type: "vizio_font_selector",
|
|
2071
|
+
label: "Vizio Font Family",
|
|
2072
|
+
key: "vizio_video_player_title_font_family",
|
|
2073
|
+
initial_value: "Ubuntu-Bold",
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
type: "number_input",
|
|
2077
|
+
label: "Vizio Font Size",
|
|
2078
|
+
key: "vizio_video_player_title_font_size",
|
|
2079
|
+
initial_value: 64,
|
|
2080
|
+
},
|
|
2020
2081
|
{
|
|
2021
2082
|
type: "tvos_font_selector",
|
|
2022
2083
|
label: "tvOS Font Family",
|
|
@@ -2090,6 +2151,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2090
2151
|
key: "samsung_tv_video_player_summary_font_size",
|
|
2091
2152
|
initial_value: 30,
|
|
2092
2153
|
},
|
|
2154
|
+
{
|
|
2155
|
+
type: "vizio_font_selector",
|
|
2156
|
+
label: "Vizio Font Family",
|
|
2157
|
+
key: "vizio_video_player_summary_font_family",
|
|
2158
|
+
initial_value: "Ubuntu-Bold",
|
|
2159
|
+
},
|
|
2160
|
+
{
|
|
2161
|
+
type: "number_input",
|
|
2162
|
+
label: "Vizio Font Size",
|
|
2163
|
+
key: "vizio_video_player_summary_font_size",
|
|
2164
|
+
initial_value: 30,
|
|
2165
|
+
},
|
|
2093
2166
|
{
|
|
2094
2167
|
type: "tvos_font_selector",
|
|
2095
2168
|
label: "tvOS Font Family",
|
|
@@ -2157,6 +2230,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2157
2230
|
key: "samsung_tv_audio_player_title_font_size",
|
|
2158
2231
|
initial_value: 38,
|
|
2159
2232
|
},
|
|
2233
|
+
{
|
|
2234
|
+
type: "vizio_font_selector",
|
|
2235
|
+
label: "Vizio Font Family",
|
|
2236
|
+
key: "vizio_tv_audio_player_title_font_family",
|
|
2237
|
+
initial_value: "Ubuntu-Bold",
|
|
2238
|
+
},
|
|
2239
|
+
{
|
|
2240
|
+
type: "number_input",
|
|
2241
|
+
label: "Vizio Font Size",
|
|
2242
|
+
key: "vizio_audio_player_title_font_size",
|
|
2243
|
+
initial_value: 38,
|
|
2244
|
+
},
|
|
2160
2245
|
{
|
|
2161
2246
|
type: "tvos_font_selector",
|
|
2162
2247
|
label: "tvOS Font Family",
|
|
@@ -2212,6 +2297,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2212
2297
|
key: "samsung_tv_audio_player_summary_font_size",
|
|
2213
2298
|
initial_value: 20,
|
|
2214
2299
|
},
|
|
2300
|
+
{
|
|
2301
|
+
type: "vizio_font_selector",
|
|
2302
|
+
label: "Vizio Font Family",
|
|
2303
|
+
key: "vizio_audio_player_summary_font_family",
|
|
2304
|
+
initial_value: "Ubuntu-Bold",
|
|
2305
|
+
},
|
|
2306
|
+
{
|
|
2307
|
+
type: "number_input",
|
|
2308
|
+
label: "Vizio Font Size",
|
|
2309
|
+
key: "vizio_audio_player_summary_font_size",
|
|
2310
|
+
initial_value: 20,
|
|
2311
|
+
},
|
|
2215
2312
|
{
|
|
2216
2313
|
type: "tvos_font_selector",
|
|
2217
2314
|
label: "tvOS Font Family",
|
|
@@ -2267,6 +2364,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2267
2364
|
key: "samsung_tv_player_time_font_size",
|
|
2268
2365
|
initial_value: 20,
|
|
2269
2366
|
},
|
|
2367
|
+
{
|
|
2368
|
+
type: "vizio_font_selector",
|
|
2369
|
+
label: "Vizio Font Family",
|
|
2370
|
+
key: "vizio_player_time_font_family",
|
|
2371
|
+
initial_value: "Ubuntu-Bold",
|
|
2372
|
+
},
|
|
2373
|
+
{
|
|
2374
|
+
type: "number_input",
|
|
2375
|
+
label: "Vizio Font Size",
|
|
2376
|
+
key: "vizio_player_time_font_size",
|
|
2377
|
+
initial_value: 20,
|
|
2378
|
+
},
|
|
2270
2379
|
{
|
|
2271
2380
|
type: "android_font_selector",
|
|
2272
2381
|
label: "Android TV Font Family",
|
|
@@ -2322,6 +2431,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2322
2431
|
key: "samsung_tv_audio_player_run_time_font_size",
|
|
2323
2432
|
initial_value: 20,
|
|
2324
2433
|
},
|
|
2434
|
+
{
|
|
2435
|
+
type: "vizio_font_selector",
|
|
2436
|
+
label: "Vizio Font Family",
|
|
2437
|
+
key: "vizio_audio_player_run_time_font_family",
|
|
2438
|
+
initial_value: "Ubuntu-Bold",
|
|
2439
|
+
},
|
|
2440
|
+
{
|
|
2441
|
+
type: "number_input",
|
|
2442
|
+
label: "Vizio Font Size",
|
|
2443
|
+
key: "vizio_audio_player_run_time_font_size",
|
|
2444
|
+
initial_value: 20,
|
|
2445
|
+
},
|
|
2325
2446
|
{
|
|
2326
2447
|
type: "tvos_font_selector",
|
|
2327
2448
|
label: "tvOS Font Family",
|
package/manifestUtils/keys.js
CHANGED
|
@@ -17,10 +17,11 @@ const ZAPPIFEST_FIELDS = {
|
|
|
17
17
|
lg: "lg_tv_font_selector",
|
|
18
18
|
samsung: "samsung_font_selector",
|
|
19
19
|
roku: "roku_font_selector",
|
|
20
|
+
vizio: "vizio_font_selector",
|
|
20
21
|
},
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
const TV_PLATFORMS = ["tvOS", "android", "LG", "samsung", "roku"];
|
|
24
|
+
const TV_PLATFORMS = ["tvOS", "android", "LG", "samsung", "roku", "vizio"];
|
|
24
25
|
|
|
25
26
|
const FontPropsForTVPlatform = (platform) => ({
|
|
26
27
|
[`${R.toLower(platform)}FontFamily`]: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.9417984401",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.9417984401",
|
|
32
32
|
"buffer": "^5.2.1",
|
|
33
33
|
"camelize": "^1.0.0",
|
|
34
34
|
"create-react-context": "^0.2.3",
|
|
@@ -1798,6 +1798,30 @@ function getPlayerConfiguration({ platform }) {
|
|
|
1798
1798
|
key: "menu_header_samsung_letter_spacing",
|
|
1799
1799
|
initial_value: 0,
|
|
1800
1800
|
},
|
|
1801
|
+
{
|
|
1802
|
+
type: "vizio_font_selector",
|
|
1803
|
+
label: "Vizio Font Family",
|
|
1804
|
+
key: "menu_header_vizio_font_family",
|
|
1805
|
+
initial_value: "Ubuntu-Bold",
|
|
1806
|
+
},
|
|
1807
|
+
{
|
|
1808
|
+
type: "number_input",
|
|
1809
|
+
label: "Vizio Font Size",
|
|
1810
|
+
key: "menu_header_vizio_font_size",
|
|
1811
|
+
initial_value: 30,
|
|
1812
|
+
},
|
|
1813
|
+
{
|
|
1814
|
+
type: "number_input",
|
|
1815
|
+
label: "Vizio Line Height",
|
|
1816
|
+
key: "menu_header_vizio_line_height",
|
|
1817
|
+
initial_value: 60,
|
|
1818
|
+
},
|
|
1819
|
+
{
|
|
1820
|
+
type: "number_input",
|
|
1821
|
+
label: "Vizio Letter Spacing",
|
|
1822
|
+
key: "menu_header_vizio_letter_spacing",
|
|
1823
|
+
initial_value: 0,
|
|
1824
|
+
},
|
|
1801
1825
|
]
|
|
1802
1826
|
),
|
|
1803
1827
|
// Captions Menu - Item Text Label
|
|
@@ -1877,6 +1901,30 @@ function getPlayerConfiguration({ platform }) {
|
|
|
1877
1901
|
key: "menu_item_samsung_letter_spacing",
|
|
1878
1902
|
initial_value: 0,
|
|
1879
1903
|
},
|
|
1904
|
+
{
|
|
1905
|
+
type: "vizio_font_selector",
|
|
1906
|
+
label: "Vizio Font Family",
|
|
1907
|
+
key: "menu_item_vizio_font_family",
|
|
1908
|
+
initial_value: "Ubuntu-Medium",
|
|
1909
|
+
},
|
|
1910
|
+
{
|
|
1911
|
+
type: "number_input",
|
|
1912
|
+
label: "Vizio Font Size",
|
|
1913
|
+
key: "menu_item_vizio_font_size",
|
|
1914
|
+
initial_value: 25,
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
type: "number_input",
|
|
1918
|
+
label: "Vizio Line Height",
|
|
1919
|
+
key: "menu_item_vizio_line_height",
|
|
1920
|
+
initial_value: 40,
|
|
1921
|
+
},
|
|
1922
|
+
{
|
|
1923
|
+
type: "number_input",
|
|
1924
|
+
label: "Vizio Letter Spacing",
|
|
1925
|
+
key: "menu_item_vizio_letter_spacing",
|
|
1926
|
+
initial_value: 0,
|
|
1927
|
+
},
|
|
1880
1928
|
]
|
|
1881
1929
|
),
|
|
1882
1930
|
// Captions Menu - Item Border
|
|
@@ -2020,6 +2068,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2020
2068
|
key: "samsung_tv_video_player_title_font_size",
|
|
2021
2069
|
initial_value: 58,
|
|
2022
2070
|
},
|
|
2071
|
+
{
|
|
2072
|
+
type: "vizio_font_selector",
|
|
2073
|
+
label: "Vizio Font Family",
|
|
2074
|
+
key: "vizio_video_player_title_font_family",
|
|
2075
|
+
initial_value: "Ubuntu-Bold",
|
|
2076
|
+
},
|
|
2077
|
+
{
|
|
2078
|
+
type: "number_input",
|
|
2079
|
+
label: "Vizio Font Size",
|
|
2080
|
+
key: "vizio_video_player_title_font_size",
|
|
2081
|
+
initial_value: 58,
|
|
2082
|
+
},
|
|
2023
2083
|
{
|
|
2024
2084
|
type: "tvos_font_selector",
|
|
2025
2085
|
label: "tvOS Font Family",
|
|
@@ -2093,6 +2153,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2093
2153
|
key: "samsung_tv_video_player_summary_font_size",
|
|
2094
2154
|
initial_value: 30,
|
|
2095
2155
|
},
|
|
2156
|
+
{
|
|
2157
|
+
type: "vizio_font_selector",
|
|
2158
|
+
label: "Vizio Font Family",
|
|
2159
|
+
key: "vizio_video_player_summary_font_family",
|
|
2160
|
+
initial_value: "Ubuntu-Medium",
|
|
2161
|
+
},
|
|
2162
|
+
{
|
|
2163
|
+
type: "number_input",
|
|
2164
|
+
label: "Vizio Font Size",
|
|
2165
|
+
key: "vizio_video_player_summary_font_size",
|
|
2166
|
+
initial_value: 30,
|
|
2167
|
+
},
|
|
2096
2168
|
{
|
|
2097
2169
|
type: "tvos_font_selector",
|
|
2098
2170
|
label: "tvOS Font Family",
|
|
@@ -2160,6 +2232,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2160
2232
|
key: "samsung_tv_audio_player_title_font_size",
|
|
2161
2233
|
initial_value: 40,
|
|
2162
2234
|
},
|
|
2235
|
+
{
|
|
2236
|
+
type: "vizio_font_selector",
|
|
2237
|
+
label: "Vizio Font Family",
|
|
2238
|
+
key: "vizio_audio_player_title_font_family",
|
|
2239
|
+
initial_value: "Ubuntu-Bold",
|
|
2240
|
+
},
|
|
2241
|
+
{
|
|
2242
|
+
type: "number_input",
|
|
2243
|
+
label: "Vizio Font Size",
|
|
2244
|
+
key: "vizio_audio_player_title_font_size",
|
|
2245
|
+
initial_value: 40,
|
|
2246
|
+
},
|
|
2163
2247
|
{
|
|
2164
2248
|
type: "tvos_font_selector",
|
|
2165
2249
|
label: "tvOS Font Family",
|
|
@@ -2215,6 +2299,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2215
2299
|
key: "samsung_tv_audio_player_summary_font_size",
|
|
2216
2300
|
initial_value: 22,
|
|
2217
2301
|
},
|
|
2302
|
+
{
|
|
2303
|
+
type: "vizio_font_selector",
|
|
2304
|
+
label: "Vizio Font Family",
|
|
2305
|
+
key: "vizio_audio_player_summary_font_family",
|
|
2306
|
+
initial_value: "Ubuntu-Medium",
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
type: "number_input",
|
|
2310
|
+
label: "Vizio Font Size",
|
|
2311
|
+
key: "vizio_audio_player_summary_font_size",
|
|
2312
|
+
initial_value: 22,
|
|
2313
|
+
},
|
|
2218
2314
|
{
|
|
2219
2315
|
type: "tvos_font_selector",
|
|
2220
2316
|
label: "tvOS Font Family",
|
|
@@ -2270,6 +2366,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2270
2366
|
key: "samsung_tv_player_time_font_size",
|
|
2271
2367
|
initial_value: 20,
|
|
2272
2368
|
},
|
|
2369
|
+
{
|
|
2370
|
+
type: "vizio_font_selector",
|
|
2371
|
+
label: "Vizio Font Family",
|
|
2372
|
+
key: "vizio_player_time_font_family",
|
|
2373
|
+
initial_value: "Ubuntu-Medium",
|
|
2374
|
+
},
|
|
2375
|
+
{
|
|
2376
|
+
type: "number_input",
|
|
2377
|
+
label: "Vizio Font Size",
|
|
2378
|
+
key: "vizio_player_time_font_size",
|
|
2379
|
+
initial_value: 20,
|
|
2380
|
+
},
|
|
2273
2381
|
{
|
|
2274
2382
|
type: "android_font_selector",
|
|
2275
2383
|
label: "Android TV Font Family",
|
|
@@ -2325,6 +2433,18 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2325
2433
|
key: "samsung_tv_audio_player_run_time_font_size",
|
|
2326
2434
|
initial_value: 20,
|
|
2327
2435
|
},
|
|
2436
|
+
{
|
|
2437
|
+
type: "vizio_font_selector",
|
|
2438
|
+
label: "Vizio Font Family",
|
|
2439
|
+
key: "vizio_audio_player_run_time_font_family",
|
|
2440
|
+
initial_value: "Ubuntu-Medium",
|
|
2441
|
+
},
|
|
2442
|
+
{
|
|
2443
|
+
type: "number_input",
|
|
2444
|
+
label: "Vizio Font Size",
|
|
2445
|
+
key: "vizio_audio_player_run_time_font_size",
|
|
2446
|
+
initial_value: 20,
|
|
2447
|
+
},
|
|
2328
2448
|
{
|
|
2329
2449
|
type: "tvos_font_selector",
|
|
2330
2450
|
label: "tvOS Font Family",
|
|
@@ -4,38 +4,77 @@ import {
|
|
|
4
4
|
timers,
|
|
5
5
|
} from "@applicaster/zapp-react-native-utils/reactHooks/debugging";
|
|
6
6
|
|
|
7
|
-
jest.useFakeTimers();
|
|
8
|
-
|
|
9
7
|
describe("Debug utils", () => {
|
|
8
|
+
let performanceNowMock;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
jest.useFakeTimers();
|
|
12
|
+
// Clear the timers object
|
|
13
|
+
Object.keys(timers).forEach((key) => delete timers[key]);
|
|
14
|
+
|
|
15
|
+
// Mock performance.now()
|
|
16
|
+
// eslint-disable-next-line no-undef
|
|
17
|
+
performanceNowMock = jest.spyOn(performance, "now");
|
|
18
|
+
performanceNowMock.mockReturnValue(0); // Initial value
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
jest.useRealTimers();
|
|
23
|
+
jest.restoreAllMocks();
|
|
24
|
+
performanceNowMock.mockRestore();
|
|
25
|
+
});
|
|
26
|
+
|
|
10
27
|
describe("Unit Test: time", () => {
|
|
11
28
|
it("should create new timer if timer with a label does not exist", () => {
|
|
29
|
+
performanceNowMock.mockReturnValue(1000);
|
|
12
30
|
time("timer1");
|
|
13
31
|
expect(timers["timer1"]).toBeDefined();
|
|
32
|
+
expect(timers["timer1"].startTime).toBe(1000);
|
|
14
33
|
});
|
|
15
34
|
|
|
16
35
|
it("should update start time of timer if timer with a label exists", () => {
|
|
36
|
+
// First call to time()
|
|
37
|
+
performanceNowMock.mockReturnValue(1000);
|
|
38
|
+
time("timer1");
|
|
17
39
|
const previousStartTime = timers["timer1"].startTime;
|
|
18
|
-
|
|
40
|
+
|
|
41
|
+
// Second call to time()
|
|
42
|
+
performanceNowMock.mockReturnValue(2000);
|
|
19
43
|
time("timer1");
|
|
20
44
|
const currentStartTime = timers["timer1"].startTime;
|
|
21
|
-
|
|
45
|
+
|
|
46
|
+
expect(previousStartTime).toBe(1000);
|
|
47
|
+
expect(currentStartTime).toBe(2000);
|
|
22
48
|
});
|
|
23
49
|
});
|
|
24
50
|
|
|
25
51
|
describe("Unit Test: timeEnd", () => {
|
|
26
|
-
beforeEach(() =>
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
jest.spyOn(console, "log").mockImplementation(() => {});
|
|
54
|
+
});
|
|
27
55
|
|
|
28
56
|
it("should log elapsed time", () => {
|
|
29
57
|
const logSpy = jest.spyOn(console, "log");
|
|
30
58
|
|
|
59
|
+
performanceNowMock.mockReturnValue(1000);
|
|
60
|
+
time("timer1");
|
|
61
|
+
|
|
62
|
+
performanceNowMock.mockReturnValue(2000);
|
|
31
63
|
timeEnd("timer1");
|
|
32
64
|
|
|
33
|
-
expect(logSpy).
|
|
65
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
66
|
+
"timer1: 1000.000ms 2",
|
|
67
|
+
expect.any(Object)
|
|
68
|
+
);
|
|
34
69
|
});
|
|
35
70
|
|
|
36
71
|
it("should not log elapsed time if accumulative: true in settings", () => {
|
|
37
72
|
const logSpy = jest.spyOn(console, "log");
|
|
38
73
|
|
|
74
|
+
performanceNowMock.mockReturnValue(1000);
|
|
75
|
+
time("timer1");
|
|
76
|
+
|
|
77
|
+
performanceNowMock.mockReturnValue(2000);
|
|
39
78
|
timeEnd("timer1", { accumulative: true });
|
|
40
79
|
|
|
41
80
|
expect(logSpy).not.toHaveBeenCalled();
|
|
@@ -43,21 +82,52 @@ describe("Debug utils", () => {
|
|
|
43
82
|
});
|
|
44
83
|
|
|
45
84
|
describe("Integration Test: time and timeEnd", () => {
|
|
46
|
-
beforeEach(() =>
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
jest.spyOn(console, "log").mockImplementation(() => {});
|
|
87
|
+
});
|
|
47
88
|
|
|
48
89
|
it("should log elapsed time on timeEnd call", () => {
|
|
49
90
|
const logSpy = jest.spyOn(console, "log");
|
|
91
|
+
|
|
92
|
+
performanceNowMock.mockReturnValue(1000);
|
|
50
93
|
time("timer1");
|
|
94
|
+
|
|
95
|
+
performanceNowMock.mockReturnValue(2000);
|
|
51
96
|
timeEnd("timer1");
|
|
52
|
-
|
|
97
|
+
|
|
98
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
99
|
+
"timer1: 1000.000ms 2",
|
|
100
|
+
expect.objectContaining({
|
|
101
|
+
label: "timer1",
|
|
102
|
+
settings: undefined,
|
|
103
|
+
})
|
|
104
|
+
);
|
|
53
105
|
});
|
|
54
106
|
|
|
55
|
-
it("should log total and average time
|
|
107
|
+
it("should log total and average time when accumulative timing is complete", () => {
|
|
56
108
|
const logSpy = jest.spyOn(console, "log");
|
|
109
|
+
|
|
110
|
+
// First timing
|
|
111
|
+
performanceNowMock.mockReturnValue(1000);
|
|
57
112
|
time("timer2");
|
|
113
|
+
|
|
114
|
+
performanceNowMock.mockReturnValue(2000);
|
|
58
115
|
timeEnd("timer2", { accumulative: true });
|
|
59
|
-
|
|
60
|
-
|
|
116
|
+
|
|
117
|
+
// Second timing
|
|
118
|
+
performanceNowMock.mockReturnValue(3000);
|
|
119
|
+
time("timer2");
|
|
120
|
+
|
|
121
|
+
performanceNowMock.mockReturnValue(5000);
|
|
122
|
+
timeEnd("timer2"); // This will log because timer is accumulative (callCount > 1)
|
|
123
|
+
|
|
124
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
125
|
+
"timer2: 2000.000ms 2",
|
|
126
|
+
expect.objectContaining({
|
|
127
|
+
label: "timer2",
|
|
128
|
+
settings: undefined,
|
|
129
|
+
})
|
|
130
|
+
);
|
|
61
131
|
});
|
|
62
132
|
});
|
|
63
133
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { useEffect, useState } from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
2
|
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
4
3
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
5
4
|
import {
|
|
@@ -17,10 +16,6 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
|
|
|
17
16
|
const intervalTimer = React.useRef(null);
|
|
18
17
|
const prevRunning = usePrevious(isRunning);
|
|
19
18
|
|
|
20
|
-
const setIntervalTimer = (cb) => {
|
|
21
|
-
intervalTimer.current = setInterval(cb, ON_HOLD_INTERVAL);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
19
|
const clearIntervalTimer = () => {
|
|
25
20
|
try {
|
|
26
21
|
clearInterval(intervalTimer.current);
|
|
@@ -29,6 +24,11 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
|
|
|
29
24
|
}
|
|
30
25
|
};
|
|
31
26
|
|
|
27
|
+
const setIntervalTimer = (cb) => {
|
|
28
|
+
clearIntervalTimer();
|
|
29
|
+
intervalTimer.current = setInterval(cb, ON_HOLD_INTERVAL);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
32
|
const resetState = () => {
|
|
33
33
|
setIsRunning(false);
|
|
34
34
|
setDirection(null);
|
|
@@ -42,7 +42,7 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
|
|
|
42
42
|
if (!player) return;
|
|
43
43
|
|
|
44
44
|
if (direction) {
|
|
45
|
-
player[direction](
|
|
45
|
+
player[direction](Math.min(MAX_SEEK_TIME, SKIP_TIME_BASE * multiplier));
|
|
46
46
|
resetHUDTimer();
|
|
47
47
|
}
|
|
48
48
|
}, [multiplier, direction]);
|
|
@@ -50,7 +50,9 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
|
|
|
50
50
|
useEffect(() => {
|
|
51
51
|
if (isRunning && isRunning !== prevRunning) {
|
|
52
52
|
setIntervalTimer(() => {
|
|
53
|
-
setMultiplier(
|
|
53
|
+
setMultiplier((prev) => {
|
|
54
|
+
return prev + 1;
|
|
55
|
+
});
|
|
54
56
|
});
|
|
55
57
|
} else if (!isRunning && isRunning !== prevRunning) {
|
|
56
58
|
resetState();
|
|
@@ -48,7 +48,11 @@ export function useCellResolver({
|
|
|
48
48
|
...cellResolverOptions
|
|
49
49
|
}: Props) {
|
|
50
50
|
let _component = Object.assign({}, component);
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
const { width, height } = useDimensions("screen", {
|
|
53
|
+
updateForInactiveScreens: false,
|
|
54
|
+
});
|
|
55
|
+
|
|
52
56
|
const { plugins, cellStyles } = usePickFromState(["plugins", "cellStyles"]);
|
|
53
57
|
const isRTL = useIsRTL();
|
|
54
58
|
|
|
@@ -67,7 +67,7 @@ export const useConfiguration = ({
|
|
|
67
67
|
if (component) {
|
|
68
68
|
const remappedStylesConfiguration = remapUpdatedKeys(
|
|
69
69
|
pluginManifest,
|
|
70
|
-
component
|
|
70
|
+
component
|
|
71
71
|
);
|
|
72
72
|
|
|
73
73
|
R.forEachObjIndexed((value, key) => {
|
|
@@ -83,7 +83,7 @@ export const useConfiguration = ({
|
|
|
83
83
|
|
|
84
84
|
const styles = populateConfigurationValues(
|
|
85
85
|
pluginManifest?.styles?.fields,
|
|
86
|
-
remappedStylesConfiguration,
|
|
86
|
+
remappedStylesConfiguration.styles,
|
|
87
87
|
skipDefaults
|
|
88
88
|
);
|
|
89
89
|
|