@applicaster/zapp-react-dom-app 12.0.0-alpha.7855034103 → 12.0.0-alpha.7990242848
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/App/InteractionManager/index.tsx +583 -477
- package/App/Loader/utils/const.js +3 -0
- package/App/Loader/utils/platform.js +48 -0
- package/main.css +2 -2
- package/package.json +6 -6
|
@@ -31,14 +31,23 @@ import {
|
|
|
31
31
|
import { PlayerContentContext } from "@applicaster/zapp-react-dom-ui-components/Contexts";
|
|
32
32
|
|
|
33
33
|
import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator";
|
|
34
|
-
import { Platform } from "react-native";
|
|
35
34
|
import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
|
|
36
35
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
37
36
|
import { confirmationDialogStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ConfirmDialogState";
|
|
37
|
+
import {
|
|
38
|
+
isLgPlatform,
|
|
39
|
+
isSamsungPlatform,
|
|
40
|
+
isVizioPlatform,
|
|
41
|
+
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
42
|
+
|
|
43
|
+
import { OnScreenKeyboard } from "@applicaster/zapp-react-dom-ui-components/Components/OnScreenKeyboard";
|
|
38
44
|
|
|
39
45
|
const { withXray } = getXray();
|
|
40
46
|
const globalAny: any = global;
|
|
41
47
|
|
|
48
|
+
const shouldUseOnScreenKeyboard = () =>
|
|
49
|
+
isVizioPlatform() || window.applicaster.useOnScreenKeyboard;
|
|
50
|
+
|
|
42
51
|
type Props = {
|
|
43
52
|
displayState: string;
|
|
44
53
|
setDisplayState: (state: string) => void;
|
|
@@ -56,571 +65,562 @@ type Props = {
|
|
|
56
65
|
};
|
|
57
66
|
};
|
|
58
67
|
|
|
59
|
-
type State = { isKeyboardVisible: boolean };
|
|
68
|
+
type State = { isKeyboardVisible: boolean; keyboardInput: string };
|
|
60
69
|
|
|
61
70
|
type KeyCode = { code: string; keyCode: number | string };
|
|
62
71
|
|
|
63
72
|
export const alertConfirmationMesage =
|
|
64
73
|
"Are you sure you want to exit application?";
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
class InteractionManager extends React.Component<Props, State> {
|
|
76
|
+
onKeyDownListener: (keyCode: KeyCode) => void;
|
|
77
|
+
onMouseDownListener: (event: MouseEvent) => void;
|
|
78
|
+
onMouseMoveListener: (event: MouseEvent) => void;
|
|
79
|
+
onScrollListener: (event: MouseEvent) => void;
|
|
80
|
+
|
|
81
|
+
longKeyPressTimeout: any | null;
|
|
82
|
+
longPressActive: boolean;
|
|
83
|
+
timeout: any | null;
|
|
84
|
+
sequenceTimeout: NodeJS.Timeout | null; // timeoutID
|
|
85
|
+
userSequence: number[] = [];
|
|
86
|
+
confirmDialog: any;
|
|
87
|
+
isDismissing = false;
|
|
88
|
+
|
|
89
|
+
constructor(props) {
|
|
90
|
+
super(props);
|
|
91
|
+
|
|
92
|
+
this.onKeyDownListener = this.onKeyDown.bind(this);
|
|
93
|
+
|
|
94
|
+
this.state = {
|
|
95
|
+
isKeyboardVisible: false,
|
|
96
|
+
keyboardInput: "",
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
this.onMouseMoveListener = debounce({
|
|
100
|
+
fn: this.onMouseMove,
|
|
101
|
+
context: this,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.onScrollListener = debounce({
|
|
105
|
+
fn: this.onScroll,
|
|
106
|
+
wait: 100,
|
|
107
|
+
context: this,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
this.onMouseDownListener = debounce({
|
|
111
|
+
fn: this.onMouseDown,
|
|
112
|
+
context: this,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
this.longKeyPressTimeout = null;
|
|
116
|
+
this.longPressActive = false;
|
|
117
|
+
this.confirmDialog = confirmationDialogStore.getState();
|
|
118
|
+
this.resetHudTimeout = this.resetHudTimeout.bind(this);
|
|
119
|
+
this.cursorVisibilityChange = this.cursorVisibilityChange.bind(this);
|
|
120
|
+
this.onKeyDown = this.onKeyDown.bind(this);
|
|
121
|
+
this.onKeyUp = this.onKeyUp.bind(this);
|
|
122
|
+
this.onMouseMove = this.onMouseMove.bind(this);
|
|
123
|
+
this.onScroll = this.onScroll.bind(this);
|
|
124
|
+
this.onMouseDown = this.onMouseDown.bind(this);
|
|
125
|
+
this.onKeyboardStateChange = this.onKeyboardStateChange.bind(this);
|
|
126
|
+
this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
|
|
127
|
+
this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
|
|
128
|
+
this.performExit = this.performExit.bind(this);
|
|
129
|
+
this.handleInputFocus = this.handleInputFocus.bind(this);
|
|
130
|
+
this.handleInputBlur = this.handleInputBlur.bind(this);
|
|
131
|
+
this.handleKeyboardInput = this.handleKeyboardInput.bind(this);
|
|
132
|
+
this.handleKeyboardDismiss = this.handleKeyboardDismiss.bind(this);
|
|
133
|
+
|
|
134
|
+
this.confirmDialog.setConfirmAction(this.performExit);
|
|
135
|
+
this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
|
|
136
|
+
}
|
|
79
137
|
|
|
80
|
-
|
|
81
|
-
|
|
138
|
+
componentDidMount() {
|
|
139
|
+
window.addEventListener("keydown", this.onKeyDownListener);
|
|
140
|
+
window.addEventListener("keyup", this.onKeyUp);
|
|
141
|
+
window.addEventListener("mousemove", this.onMouseMoveListener);
|
|
82
142
|
|
|
83
|
-
|
|
143
|
+
document.addEventListener("wheel", this.onScrollListener, {
|
|
144
|
+
passive: true,
|
|
145
|
+
});
|
|
84
146
|
|
|
85
|
-
|
|
86
|
-
isKeyboardVisible: false,
|
|
87
|
-
};
|
|
147
|
+
document.addEventListener("mousedown", this.onMouseDownListener);
|
|
88
148
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
149
|
+
document.addEventListener(
|
|
150
|
+
"keyboardStateChange",
|
|
151
|
+
this.onKeyboardStateChange,
|
|
152
|
+
false
|
|
153
|
+
);
|
|
93
154
|
|
|
94
|
-
|
|
95
|
-
fn: this.onScroll,
|
|
96
|
-
wait: 100,
|
|
97
|
-
context: this,
|
|
98
|
-
});
|
|
155
|
+
document.addEventListener("focusin", this.handleInputFocus);
|
|
99
156
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
157
|
+
document.addEventListener(
|
|
158
|
+
"cursorStateChange",
|
|
159
|
+
this.cursorVisibilityChange,
|
|
160
|
+
false
|
|
161
|
+
);
|
|
162
|
+
}
|
|
104
163
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.cursorVisibilityChange = this.cursorVisibilityChange.bind(this);
|
|
110
|
-
this.onKeyDown = this.onKeyDown.bind(this);
|
|
111
|
-
this.onKeyUp = this.onKeyUp.bind(this);
|
|
112
|
-
this.onMouseMove = this.onMouseMove.bind(this);
|
|
113
|
-
this.onScroll = this.onScroll.bind(this);
|
|
114
|
-
this.onMouseDown = this.onMouseDown.bind(this);
|
|
115
|
-
this.onKeyboardStateChange = this.onKeyboardStateChange.bind(this);
|
|
116
|
-
this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
|
|
117
|
-
this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
|
|
118
|
-
this.performExit = this.performExit.bind(this);
|
|
119
|
-
|
|
120
|
-
this.confirmDialog.setConfirmAction(this.performExit);
|
|
121
|
-
this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
|
|
122
|
-
}
|
|
164
|
+
componentWillUnmount() {
|
|
165
|
+
window.removeEventListener("keydown", this.onKeyDownListener);
|
|
166
|
+
window.removeEventListener("keyup", this.onKeyUp);
|
|
167
|
+
document.removeEventListener("wheel", this.onScrollListener);
|
|
123
168
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
169
|
+
document.removeEventListener(
|
|
170
|
+
"cursorStateChange",
|
|
171
|
+
this.cursorVisibilityChange
|
|
172
|
+
);
|
|
128
173
|
|
|
129
|
-
|
|
130
|
-
passive: true,
|
|
131
|
-
});
|
|
174
|
+
document.removeEventListener("focusin", this.handleInputFocus);
|
|
132
175
|
|
|
133
|
-
|
|
176
|
+
document.removeEventListener("mousedown", this.onMouseDownListener);
|
|
134
177
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
this.onKeyboardStateChange,
|
|
138
|
-
false
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
document.addEventListener(
|
|
142
|
-
"cursorStateChange",
|
|
143
|
-
this.cursorVisibilityChange,
|
|
144
|
-
false
|
|
145
|
-
);
|
|
178
|
+
if (this.timeout) {
|
|
179
|
+
this.clearTimeout();
|
|
146
180
|
}
|
|
147
181
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
window.removeEventListener("keyup", this.onKeyUp);
|
|
151
|
-
document.removeEventListener("wheel", this.onScrollListener);
|
|
152
|
-
|
|
153
|
-
document.removeEventListener(
|
|
154
|
-
"cursorStateChange",
|
|
155
|
-
this.cursorVisibilityChange
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
document.removeEventListener(
|
|
159
|
-
"keyboardStateChange",
|
|
160
|
-
this.onKeyboardStateChange
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
document.removeEventListener("mousedown", this.onMouseDownListener);
|
|
182
|
+
this.isDismissing = false;
|
|
183
|
+
}
|
|
164
184
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
185
|
+
performExit() {
|
|
186
|
+
if (isSamsungPlatform()) {
|
|
187
|
+
this.onConfirmDialogClose();
|
|
188
|
+
sendQuickBrickEvent(QUICK_BRICK_EVENTS.MOVE_APP_TO_BACKGROUND);
|
|
168
189
|
}
|
|
169
190
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
191
|
+
if (isLgPlatform()) {
|
|
192
|
+
// webOS recommend to use this method when implemention a custom exit
|
|
193
|
+
globalAny.close();
|
|
194
|
+
}
|
|
175
195
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
globalAny.close();
|
|
179
|
-
}
|
|
196
|
+
if (isVizioPlatform()) {
|
|
197
|
+
window?.VIZIO?.exitApplication();
|
|
180
198
|
}
|
|
199
|
+
}
|
|
181
200
|
|
|
182
|
-
|
|
183
|
-
|
|
201
|
+
handleWebOsBack() {
|
|
202
|
+
const systemBack = globalAny?.webOS?.platformBack;
|
|
184
203
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
204
|
+
if (systemBack) {
|
|
205
|
+
systemBack();
|
|
206
|
+
} else {
|
|
207
|
+
/**
|
|
208
|
+
* In case webOS failed to show the exit pop-up, we show a regular promtp as fallback
|
|
209
|
+
*/
|
|
210
|
+
showConfirmationDialog({
|
|
211
|
+
title: "",
|
|
212
|
+
message: alertConfirmationMesage,
|
|
213
|
+
confirmCompletion: this.performExit,
|
|
214
|
+
});
|
|
197
215
|
}
|
|
216
|
+
}
|
|
198
217
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
} else if (Platform.OS === ("lg_tv" as QuickBrickPlatforms)) {
|
|
222
|
-
this.handleWebOsBack();
|
|
218
|
+
/**
|
|
219
|
+
* This methods sends the app to background in whatever way is appropriate for each platform
|
|
220
|
+
* In the case of Tizen it shows a custom dialog on confirm it exits the app
|
|
221
|
+
* WebOS behavior depends on the SDK version, WebOS 4 would pull up the launcher menu
|
|
222
|
+
* following versions would show a native exit prompt
|
|
223
|
+
*/
|
|
224
|
+
platformBack() {
|
|
225
|
+
try {
|
|
226
|
+
// TODO: temporary hack until this code is refactored
|
|
227
|
+
if (isSamsungPlatform() || isVizioPlatform()) {
|
|
228
|
+
const { isDialogVisible } = confirmationDialogStore.getState();
|
|
229
|
+
|
|
230
|
+
if (isDialogVisible) {
|
|
231
|
+
this.onConfirmDialogClose();
|
|
232
|
+
} else {
|
|
233
|
+
showConfirmationDialog({
|
|
234
|
+
title: "",
|
|
235
|
+
message: alertConfirmationMesage,
|
|
236
|
+
confirmCompletion: this.performExit,
|
|
237
|
+
cancelCompletion: this.onConfirmDialogClose,
|
|
238
|
+
});
|
|
223
239
|
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
console.warn("Failed to execute platformBack", e);
|
|
240
|
+
} else if (isLgPlatform()) {
|
|
241
|
+
this.handleWebOsBack();
|
|
227
242
|
}
|
|
243
|
+
} catch (e) {
|
|
244
|
+
// eslint-disable-next-line no-console
|
|
245
|
+
console.warn("Failed to execute platformBack", e);
|
|
228
246
|
}
|
|
247
|
+
}
|
|
229
248
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
249
|
+
cursorVisibilityChange(event) {
|
|
250
|
+
const visible = event.detail.visibility;
|
|
251
|
+
const { setDisplayState, displayState } = this.props;
|
|
233
252
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
253
|
+
if (visible && displayState === DISPLAY_STATES.PLAYER) {
|
|
254
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
255
|
+
this.resetHudTimeout();
|
|
238
256
|
}
|
|
257
|
+
}
|
|
239
258
|
|
|
240
|
-
|
|
241
|
-
|
|
259
|
+
onMouseMove() {
|
|
260
|
+
const { setDisplayState, displayState } = this.props;
|
|
242
261
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
262
|
+
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
263
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
264
|
+
this.resetHudTimeout();
|
|
247
265
|
}
|
|
266
|
+
}
|
|
248
267
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
268
|
+
isHomeScreen() {
|
|
269
|
+
const { navigator } = this.props;
|
|
270
|
+
const { rivers } = this.props;
|
|
252
271
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
272
|
+
const homeId = R.compose(
|
|
273
|
+
R.prop("id"),
|
|
274
|
+
R.find(R.prop("home")),
|
|
275
|
+
R.values
|
|
276
|
+
)(rivers);
|
|
258
277
|
|
|
259
|
-
|
|
278
|
+
const homePath = `/river/${homeId}`;
|
|
260
279
|
|
|
261
|
-
|
|
262
|
-
|
|
280
|
+
return homePath === navigator.currentRoute;
|
|
281
|
+
}
|
|
263
282
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
283
|
+
goToHome() {
|
|
284
|
+
const { navigator } = this.props;
|
|
285
|
+
const { rivers } = this.props;
|
|
286
|
+
const homeRiver = R.find(R.propEq("home", true), R.values(rivers));
|
|
268
287
|
|
|
269
|
-
|
|
270
|
-
|
|
288
|
+
navigator.replace(homeRiver);
|
|
289
|
+
}
|
|
271
290
|
|
|
272
|
-
|
|
273
|
-
|
|
291
|
+
resetHudTimeout() {
|
|
292
|
+
const { resetHudTimer = noop } = this.props;
|
|
274
293
|
|
|
275
|
-
|
|
276
|
-
|
|
294
|
+
resetHudTimer?.();
|
|
295
|
+
}
|
|
277
296
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
297
|
+
clearTimeout() {
|
|
298
|
+
if (this.timeout) {
|
|
299
|
+
clearTimeout(this.timeout);
|
|
300
|
+
this.timeout = null;
|
|
283
301
|
}
|
|
302
|
+
}
|
|
284
303
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
304
|
+
clearLongPressTimeout() {
|
|
305
|
+
if (this.longKeyPressTimeout) {
|
|
306
|
+
clearTimeout(this.longKeyPressTimeout);
|
|
307
|
+
this.longKeyPressTimeout = null;
|
|
290
308
|
}
|
|
309
|
+
}
|
|
291
310
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
311
|
+
/**
|
|
312
|
+
* If the keySupportsLongPress this method is called on longpress of key
|
|
313
|
+
* Register your longpress handlers here, and make sure to add it to list of supported keys
|
|
314
|
+
*/
|
|
315
|
+
onLongPress(event) {
|
|
316
|
+
this.longPressActive = true;
|
|
317
|
+
// Legacy way of determining whether controls are being displayed
|
|
318
|
+
// Or if the player is in a playback state.
|
|
319
|
+
const { displayState } = this.props;
|
|
320
|
+
const playerState = displayState === DISPLAY_STATES.PLAYER;
|
|
321
|
+
const hudState = displayState === DISPLAY_STATES.HUD;
|
|
322
|
+
const playbackState = playerState || hudState;
|
|
323
|
+
|
|
324
|
+
switch (event.code) {
|
|
325
|
+
case KEYS.Back.code:
|
|
326
|
+
// If you longpress the back button we probably want to exit
|
|
327
|
+
this.platformBack();
|
|
309
328
|
|
|
310
|
-
|
|
329
|
+
break;
|
|
311
330
|
|
|
312
|
-
|
|
313
|
-
|
|
331
|
+
case KEYS.Enter.code:
|
|
332
|
+
focusManager.longPress();
|
|
314
333
|
|
|
315
|
-
|
|
334
|
+
break;
|
|
316
335
|
|
|
317
|
-
|
|
318
|
-
|
|
336
|
+
case KEYS.Forward.code:
|
|
337
|
+
playbackState && this.props.seekMethods.onForwardLongPress();
|
|
319
338
|
|
|
320
|
-
|
|
339
|
+
break;
|
|
321
340
|
|
|
322
|
-
|
|
323
|
-
|
|
341
|
+
case KEYS.Rewind.code:
|
|
342
|
+
playbackState && this.props.seekMethods.onRewindLongPress();
|
|
324
343
|
|
|
325
|
-
|
|
344
|
+
break;
|
|
326
345
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
346
|
+
default:
|
|
347
|
+
break;
|
|
330
348
|
}
|
|
349
|
+
}
|
|
331
350
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
351
|
+
/**
|
|
352
|
+
* If the keySupportsLongPress this method is called on keyup of a longpress key
|
|
353
|
+
* If you need to handle the release or keyup of a longpress key register the handler here
|
|
354
|
+
*/
|
|
355
|
+
onLongPressRelease(event) {
|
|
356
|
+
this.longPressActive = false;
|
|
357
|
+
this.resetHudTimeout();
|
|
339
358
|
|
|
340
|
-
|
|
359
|
+
focusManager.pressOut();
|
|
341
360
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
361
|
+
switch (event.code) {
|
|
362
|
+
case KEYS.Forward.code:
|
|
363
|
+
this.props.seekMethods.onForwardPressOut();
|
|
345
364
|
|
|
346
|
-
|
|
365
|
+
break;
|
|
347
366
|
|
|
348
|
-
|
|
349
|
-
|
|
367
|
+
case KEYS.Rewind.code:
|
|
368
|
+
this.props.seekMethods.onForwardPressOut();
|
|
350
369
|
|
|
351
|
-
|
|
370
|
+
break;
|
|
352
371
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
372
|
+
default:
|
|
373
|
+
break;
|
|
356
374
|
}
|
|
375
|
+
}
|
|
357
376
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
this.sequenceTimeout = setTimeout(() => {
|
|
372
|
-
// User needs to complete sequence before SEQUENCE_ENTRY_TIME
|
|
373
|
-
// or we set userSequence, and prev sequenceTimeout to empty values
|
|
374
|
-
this.sequenceTimeout = null;
|
|
375
|
-
this.userSequence = [];
|
|
376
|
-
}, SEQUENCE_ENTRY_TIME);
|
|
377
|
+
/**
|
|
378
|
+
* Resets the sequence of keys we captured.
|
|
379
|
+
* Clear ensures that we don't interpret regular interactions
|
|
380
|
+
* as a sequence used to unlock certain features
|
|
381
|
+
*/
|
|
382
|
+
resetSequenceTimeout() {
|
|
383
|
+
const SEQUENCE_ENTRY_TIME = 1900;
|
|
384
|
+
|
|
385
|
+
if (this.sequenceTimeout) {
|
|
386
|
+
// Start timer over
|
|
387
|
+
clearTimeout(this.sequenceTimeout);
|
|
377
388
|
}
|
|
378
389
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
390
|
+
this.sequenceTimeout = setTimeout(() => {
|
|
391
|
+
// User needs to complete sequence before SEQUENCE_ENTRY_TIME
|
|
392
|
+
// or we set userSequence, and prev sequenceTimeout to empty values
|
|
393
|
+
this.sequenceTimeout = null;
|
|
394
|
+
this.userSequence = [];
|
|
395
|
+
}, SEQUENCE_ENTRY_TIME);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* If a certain sequence of keys are pressed we enable special menus or settings
|
|
400
|
+
* Each supported sequence can be stored as a constant
|
|
401
|
+
*/
|
|
402
|
+
checkSequence(key) {
|
|
403
|
+
const SINK_SEQUENCE = [
|
|
404
|
+
KEYS.ArrowUp.keyCode,
|
|
405
|
+
KEYS.ArrowUp.keyCode,
|
|
406
|
+
KEYS.ArrowDown.keyCode,
|
|
407
|
+
KEYS.ArrowDown.keyCode,
|
|
408
|
+
KEYS.ArrowLeft.keyCode,
|
|
409
|
+
KEYS.ArrowRight.keyCode,
|
|
410
|
+
KEYS.ArrowLeft.keyCode,
|
|
411
|
+
KEYS.ArrowRight.keyCode,
|
|
412
|
+
];
|
|
413
|
+
|
|
414
|
+
this.resetSequenceTimeout();
|
|
415
|
+
this.userSequence.push(key);
|
|
416
|
+
|
|
417
|
+
// Remember [1,2,3] !== [1,2,3] in js, so string comparison is better
|
|
418
|
+
const shouldAddSink =
|
|
419
|
+
this.userSequence.toString() === SINK_SEQUENCE.toString();
|
|
420
|
+
|
|
421
|
+
if (shouldAddSink) {
|
|
422
|
+
this.props.xray.addRemoteSink({});
|
|
405
423
|
}
|
|
424
|
+
}
|
|
406
425
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
KEYS.Back,
|
|
415
|
-
KEYS.Enter,
|
|
416
|
-
KEYS.Rewind,
|
|
417
|
-
KEYS.Forward,
|
|
418
|
-
];
|
|
426
|
+
/**
|
|
427
|
+
* Determines whether the key supports or handles longpress
|
|
428
|
+
* At the moment the only keys that support are the ones defined in
|
|
429
|
+
* supportedEvents array. This logic just prevents us from registering timeouts for every key
|
|
430
|
+
*/
|
|
431
|
+
keySupportsLongPress(event): boolean {
|
|
432
|
+
const supportedEvents = [KEYS.Back, KEYS.Enter, KEYS.Rewind, KEYS.Forward];
|
|
419
433
|
|
|
420
|
-
|
|
434
|
+
const eventMatcher = R.compose(R.prop("matches"), keyCode)(event);
|
|
421
435
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
436
|
+
const supportsLongPress = R.compose(
|
|
437
|
+
R.any(R.equals(true)),
|
|
438
|
+
R.map(eventMatcher)
|
|
439
|
+
)(supportedEvents);
|
|
426
440
|
|
|
427
|
-
|
|
428
|
-
|
|
441
|
+
return supportsLongPress;
|
|
442
|
+
}
|
|
429
443
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
444
|
+
onKeyUp(event: KeyboardEvent) {
|
|
445
|
+
// If this is a supported longpress key we need to clear the timeout and handle release of key
|
|
446
|
+
// This logic is handled by onLongPressRelease
|
|
447
|
+
if (this.keySupportsLongPress(event)) {
|
|
448
|
+
if (this.longPressActive) {
|
|
449
|
+
this.onLongPressRelease(event);
|
|
450
|
+
} else {
|
|
451
|
+
this.clearLongPressTimeout();
|
|
439
452
|
}
|
|
440
453
|
}
|
|
454
|
+
}
|
|
441
455
|
|
|
442
|
-
|
|
443
|
-
|
|
456
|
+
onKeyDown(event) {
|
|
457
|
+
const { displayState, setDisplayState, navigator } = this.props;
|
|
458
|
+
const { isKeyboardVisible } = this.state;
|
|
444
459
|
|
|
445
|
-
|
|
460
|
+
const { isDialogVisible } = confirmationDialogStore.getState();
|
|
446
461
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
462
|
+
// If this is a supported longpress key we need to set the timeout and handle the longpress
|
|
463
|
+
if (this.keySupportsLongPress(event)) {
|
|
464
|
+
this.longKeyPressTimeout = setTimeout(() => {
|
|
465
|
+
this.onLongPress(event);
|
|
466
|
+
}, LONG_KEY_PRESS_TIMEOUT);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (isKeyboardVisible && shouldUseOnScreenKeyboard()) {
|
|
470
|
+
if (keyCode(event).matchesAny("Escape", "Back")) {
|
|
471
|
+
event.preventDefault();
|
|
472
|
+
event.stopPropagation();
|
|
473
|
+
this.handleKeyboardDismiss();
|
|
474
|
+
|
|
475
|
+
return;
|
|
452
476
|
}
|
|
477
|
+
}
|
|
453
478
|
|
|
479
|
+
/**
|
|
480
|
+
When the player is displayed, we listen to Native Play / Pause / Stop
|
|
481
|
+
buttons. Any other key press will display the transport controls
|
|
482
|
+
*/
|
|
483
|
+
if (
|
|
484
|
+
displayState === DISPLAY_STATES.PLAYER ||
|
|
485
|
+
displayState === DISPLAY_STATES.HUD
|
|
486
|
+
) {
|
|
454
487
|
/**
|
|
455
|
-
|
|
456
|
-
buttons. Any other key press will display the transport controls
|
|
488
|
+
registering native keys for playback
|
|
457
489
|
*/
|
|
458
|
-
if (
|
|
459
|
-
|
|
460
|
-
displayState === DISPLAY_STATES.HUD
|
|
461
|
-
) {
|
|
462
|
-
/**
|
|
463
|
-
registering native keys for playback
|
|
464
|
-
*/
|
|
465
|
-
if (keyCode(event).matches(KEYS.TogglePlayPause)) {
|
|
466
|
-
const { playing } = playerManager.getState() || {};
|
|
467
|
-
|
|
468
|
-
if (!playing) {
|
|
469
|
-
return playerManager.togglePlayPause();
|
|
470
|
-
}
|
|
471
|
-
}
|
|
490
|
+
if (keyCode(event).matches(KEYS.TogglePlayPause)) {
|
|
491
|
+
const { playing } = playerManager.getState() || {};
|
|
472
492
|
|
|
473
|
-
if (
|
|
474
|
-
return playerManager.
|
|
493
|
+
if (!playing) {
|
|
494
|
+
return playerManager.togglePlayPause();
|
|
475
495
|
}
|
|
496
|
+
}
|
|
476
497
|
|
|
477
|
-
|
|
478
|
-
|
|
498
|
+
if (keyCode(event).matches(KEYS.Play)) {
|
|
499
|
+
return playerManager.play();
|
|
500
|
+
}
|
|
479
501
|
|
|
480
|
-
|
|
481
|
-
|
|
502
|
+
if (keyCode(event).matches(KEYS.Pause)) {
|
|
503
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
482
504
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
navigator.goBack();
|
|
505
|
+
return playerManager.pause();
|
|
506
|
+
}
|
|
486
507
|
|
|
487
|
-
|
|
488
|
-
|
|
508
|
+
if (keyCode(event).matches(KEYS.Stop)) {
|
|
509
|
+
setDisplayState(DISPLAY_STATES.DEFAULT);
|
|
510
|
+
navigator.goBack();
|
|
489
511
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
this.props.seekMethods.onForwardPress();
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
493
514
|
|
|
494
|
-
|
|
495
|
-
|
|
515
|
+
if (keyCode(event).matches(KEYS.Forward)) {
|
|
516
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
517
|
+
this.props.seekMethods.onForwardPress();
|
|
496
518
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
this.props.seekMethods.onRewindPress();
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
500
521
|
|
|
501
|
-
|
|
502
|
-
|
|
522
|
+
if (keyCode(event).matches(KEYS.Rewind)) {
|
|
523
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
524
|
+
this.props.seekMethods.onRewindPress();
|
|
525
|
+
|
|
526
|
+
return;
|
|
503
527
|
}
|
|
528
|
+
}
|
|
504
529
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
530
|
+
/**
|
|
531
|
+
When pressing backspace or the Native "Back" button:
|
|
532
|
+
if on the transport controls: we show the player
|
|
533
|
+
if on the player : we show the UI
|
|
534
|
+
if on the UI : we exit the app
|
|
535
|
+
*/
|
|
511
536
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
537
|
+
if (
|
|
538
|
+
keyCode(event).matchesAny(
|
|
539
|
+
KEYS.Back,
|
|
540
|
+
KEYS.Escape,
|
|
541
|
+
KEYS.EscapeDevice,
|
|
542
|
+
KEYS.Backspace
|
|
543
|
+
)
|
|
544
|
+
) {
|
|
545
|
+
switch (displayState) {
|
|
546
|
+
case DISPLAY_STATES.DEFAULT:
|
|
547
|
+
case DISPLAY_STATES.PLAYER:
|
|
548
|
+
if (isDialogVisible) {
|
|
549
|
+
this.onConfirmDialogClose();
|
|
550
|
+
} else if (navigator.canGoBack()) {
|
|
551
|
+
navigator.goBack();
|
|
552
|
+
} else if (this.isHomeScreen()) {
|
|
553
|
+
this.platformBack();
|
|
554
|
+
} else if (navigator.currentRoute.includes("hook")) {
|
|
555
|
+
// If code reaches this block navigator cant go back, it is not home,
|
|
556
|
+
// and this is a login plugin that was pushed on top of the home
|
|
557
|
+
// Treat it like a home screen and run platformBack()
|
|
558
|
+
const entryData = navigator?.data?.entry;
|
|
559
|
+
const isHookInHomescreen = entryData?.payload?.home;
|
|
560
|
+
|
|
561
|
+
const isHookFlowBlocker =
|
|
562
|
+
entryData?.hookPlugin?.module?.isFlowBlocker();
|
|
563
|
+
|
|
564
|
+
if (isHookInHomescreen && isHookFlowBlocker) {
|
|
528
565
|
this.platformBack();
|
|
529
|
-
} else if (navigator.currentRoute.includes("hook")) {
|
|
530
|
-
// If code reaches this block navigator cant go back, it is not home,
|
|
531
|
-
// and this is a login plugin that was pushed on top of the home
|
|
532
|
-
// Treat it like a home screen and run platformBack()
|
|
533
|
-
const entryData = navigator?.data?.entry;
|
|
534
|
-
const isHookInHomescreen = entryData?.payload?.home;
|
|
535
|
-
|
|
536
|
-
const isHookFlowBlocker =
|
|
537
|
-
entryData?.hookPlugin?.module?.isFlowBlocker();
|
|
538
|
-
|
|
539
|
-
if (isHookInHomescreen && isHookFlowBlocker) {
|
|
540
|
-
this.platformBack();
|
|
541
|
-
} else {
|
|
542
|
-
navigator.goBack(false, true);
|
|
543
|
-
}
|
|
544
566
|
} else {
|
|
545
|
-
|
|
567
|
+
navigator.goBack(false, true);
|
|
546
568
|
}
|
|
569
|
+
} else {
|
|
570
|
+
this.goToHome();
|
|
571
|
+
}
|
|
547
572
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}
|
|
573
|
+
break;
|
|
574
|
+
case DISPLAY_STATES.HUD:
|
|
575
|
+
// IF transport controls are open, close them instead of closing player
|
|
576
|
+
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
577
|
+
break;
|
|
578
|
+
default:
|
|
579
|
+
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
580
|
+
break;
|
|
557
581
|
}
|
|
582
|
+
}
|
|
558
583
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
return true;
|
|
584
|
+
if (keyCode(event).matches(KEYS.Enter)) {
|
|
585
|
+
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
586
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
587
|
+
} else {
|
|
588
|
+
focusManager.press();
|
|
567
589
|
}
|
|
568
590
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
this.performExit();
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
572
593
|
|
|
573
|
-
|
|
574
|
-
|
|
594
|
+
if (keyCode(event).matches(KEYS.Exit)) {
|
|
595
|
+
if (isSamsungPlatform() || shouldUseOnScreenKeyboard()) {
|
|
596
|
+
this.performExit();
|
|
575
597
|
|
|
576
|
-
|
|
598
|
+
return;
|
|
577
599
|
}
|
|
578
600
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
!this.state.isKeyboardVisible
|
|
582
|
-
) {
|
|
583
|
-
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
584
|
-
setDisplayState(DISPLAY_STATES.HUD);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
this.checkSequence(event.keyCode);
|
|
588
|
-
|
|
589
|
-
const direction = keyCode(event).direction();
|
|
590
|
-
|
|
591
|
-
if (!isDialogVisible || !["up", "down"].includes(direction.value)) {
|
|
592
|
-
focusManager.moveFocus(direction);
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
if (
|
|
596
|
-
displayState === DISPLAY_STATES.PLAYER ||
|
|
597
|
-
displayState === DISPLAY_STATES.HUD
|
|
598
|
-
) {
|
|
599
|
-
this.resetHudTimeout();
|
|
600
|
-
}
|
|
601
|
+
this.platformBack();
|
|
602
|
+
}
|
|
601
603
|
|
|
602
|
-
|
|
604
|
+
if (
|
|
605
|
+
keyCode(event).matchesAny(...ARROW_KEYS) &&
|
|
606
|
+
!this.state.isKeyboardVisible
|
|
607
|
+
) {
|
|
608
|
+
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
609
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
603
610
|
}
|
|
604
|
-
}
|
|
605
611
|
|
|
606
|
-
|
|
607
|
-
const { displayState } = this.props;
|
|
612
|
+
this.checkSequence(event.keyCode);
|
|
608
613
|
|
|
609
|
-
const
|
|
614
|
+
const direction = keyCode(event).direction();
|
|
610
615
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
isVertical: true,
|
|
615
|
-
value: "",
|
|
616
|
-
};
|
|
616
|
+
if (!isDialogVisible || !["up", "down"].includes(direction.value)) {
|
|
617
|
+
focusManager.moveFocus(direction);
|
|
618
|
+
}
|
|
617
619
|
|
|
618
|
-
if (
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
DIRECTION.value =
|
|
623
|
-
Platform.OS === ("lg_tv" as QuickBrickPlatforms) ? "up" : "down";
|
|
620
|
+
if (!isDialogVisible) {
|
|
621
|
+
// run focus recovery on user interaction attempt
|
|
622
|
+
// probably we failed to set initial focus for some reason
|
|
623
|
+
focusManager.recoverFocus();
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
if (
|
|
@@ -628,46 +628,152 @@ export function withInteractionManager(Component: React.FC) {
|
|
|
628
628
|
displayState === DISPLAY_STATES.HUD
|
|
629
629
|
) {
|
|
630
630
|
this.resetHudTimeout();
|
|
631
|
-
} else {
|
|
632
|
-
focusManager.moveFocus(DIRECTION);
|
|
633
631
|
}
|
|
632
|
+
|
|
633
|
+
return true;
|
|
634
634
|
}
|
|
635
|
+
}
|
|
635
636
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
const { displayState } = this.props;
|
|
637
|
+
onScroll(event) {
|
|
638
|
+
const { displayState } = this.props;
|
|
639
639
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
640
|
+
const deltaY = event?.deltaY;
|
|
641
|
+
|
|
642
|
+
const DIRECTION = {
|
|
643
|
+
axis: "y",
|
|
644
|
+
isHorizontal: false,
|
|
645
|
+
isVertical: true,
|
|
646
|
+
value: "",
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
if (deltaY > 0) {
|
|
650
|
+
DIRECTION.value = isLgPlatform() ? "down" : "up";
|
|
651
|
+
} else if (deltaY < 0) {
|
|
652
|
+
DIRECTION.value = isLgPlatform() ? "up" : "down";
|
|
647
653
|
}
|
|
648
654
|
|
|
649
|
-
|
|
650
|
-
|
|
655
|
+
if (
|
|
656
|
+
displayState === DISPLAY_STATES.PLAYER ||
|
|
657
|
+
displayState === DISPLAY_STATES.HUD
|
|
658
|
+
) {
|
|
659
|
+
this.resetHudTimeout();
|
|
660
|
+
} else {
|
|
661
|
+
focusManager.moveFocus(DIRECTION);
|
|
651
662
|
}
|
|
663
|
+
}
|
|
652
664
|
|
|
653
|
-
|
|
654
|
-
|
|
665
|
+
onMouseDown(event) {
|
|
666
|
+
const { button } = event;
|
|
667
|
+
const { displayState } = this.props;
|
|
668
|
+
|
|
669
|
+
if (
|
|
670
|
+
button === 1 && // number 1 represents press on the scroll wheel
|
|
671
|
+
(displayState === DISPLAY_STATES.PLAYER ||
|
|
672
|
+
displayState === DISPLAY_STATES.HUD)
|
|
673
|
+
) {
|
|
674
|
+
this.resetHudTimeout();
|
|
655
675
|
}
|
|
676
|
+
}
|
|
656
677
|
|
|
657
|
-
|
|
658
|
-
|
|
678
|
+
onKeyboardStateChange(event) {
|
|
679
|
+
this.setState({ isKeyboardVisible: event.visibility });
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
onConfirmDialogOpen() {
|
|
683
|
+
this.confirmDialog.showDialog();
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
onConfirmDialogClose() {
|
|
687
|
+
this.confirmDialog.hideDialog();
|
|
688
|
+
|
|
689
|
+
// restore initial focus after closing dialog
|
|
690
|
+
focusManager.setInitialFocus();
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
handleInputFocus = (event: FocusEvent) => {
|
|
694
|
+
if (!shouldUseOnScreenKeyboard()) return;
|
|
695
|
+
const target = event.target as HTMLElement;
|
|
696
|
+
|
|
697
|
+
if (this.isDismissing) {
|
|
698
|
+
return;
|
|
659
699
|
}
|
|
660
700
|
|
|
661
|
-
|
|
662
|
-
|
|
701
|
+
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
|
|
702
|
+
this.setState({
|
|
703
|
+
isKeyboardVisible: true,
|
|
704
|
+
keyboardInput: (target as HTMLInputElement).value || "",
|
|
705
|
+
});
|
|
663
706
|
}
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
handleInputBlur(event: FocusEvent) {
|
|
710
|
+
if (!shouldUseOnScreenKeyboard()) return;
|
|
711
|
+
|
|
712
|
+
const target = event.target as HTMLElement;
|
|
713
|
+
|
|
714
|
+
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
|
|
715
|
+
const relatedTarget = event.relatedTarget as HTMLElement;
|
|
716
|
+
|
|
717
|
+
if (
|
|
718
|
+
!relatedTarget ||
|
|
719
|
+
(relatedTarget.tagName !== "INPUT" &&
|
|
720
|
+
relatedTarget.tagName !== "TEXTAREA")
|
|
721
|
+
) {
|
|
722
|
+
this.setState({ isKeyboardVisible: false });
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
handleKeyboardDismiss = () => {
|
|
728
|
+
this.isDismissing = true;
|
|
729
|
+
|
|
730
|
+
this.setState(
|
|
731
|
+
{
|
|
732
|
+
isKeyboardVisible: false,
|
|
733
|
+
keyboardInput: "",
|
|
734
|
+
},
|
|
735
|
+
() => {
|
|
736
|
+
this.isDismissing = false;
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
handleKeyboardInput(value: string) {
|
|
742
|
+
this.setState({ keyboardInput: value });
|
|
664
743
|
}
|
|
665
744
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
745
|
+
render() {
|
|
746
|
+
return (
|
|
747
|
+
(shouldUseOnScreenKeyboard() && this.state.isKeyboardVisible && (
|
|
748
|
+
<OnScreenKeyboard
|
|
749
|
+
initialValue={this.state.keyboardInput}
|
|
750
|
+
onInput={this.handleKeyboardInput}
|
|
751
|
+
onDismiss={this.handleKeyboardDismiss}
|
|
752
|
+
/>
|
|
753
|
+
)) ||
|
|
754
|
+
null
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const IM = R.compose(
|
|
760
|
+
withNavigator,
|
|
761
|
+
withUseSeek,
|
|
762
|
+
withXray,
|
|
763
|
+
PlayerContentContext.withConsumer,
|
|
764
|
+
DisplayStateContext.withConsumer
|
|
765
|
+
)(InteractionManager);
|
|
766
|
+
|
|
767
|
+
export function withInteractionManager(Component: React.FC) {
|
|
768
|
+
// Wrapper was created to avoid re-renders of the Component when InteractionManager context changes
|
|
769
|
+
const InteractionManagerWrapper = (props: Props) => {
|
|
770
|
+
return (
|
|
771
|
+
<>
|
|
772
|
+
<Component {...props} />
|
|
773
|
+
<IM {...props} />
|
|
774
|
+
</>
|
|
775
|
+
);
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
return InteractionManagerWrapper;
|
|
673
779
|
}
|
|
@@ -42,6 +42,36 @@ export const isSamsungPlatform = () => {
|
|
|
42
42
|
);
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Checks if we are on the Vizio platform by using the userAgent string
|
|
47
|
+
*
|
|
48
|
+
* Use this method when you need to identify the platform on runtime
|
|
49
|
+
* before the VIZIO Companion Library has loaded
|
|
50
|
+
*/
|
|
51
|
+
export const isVizioPlatform = () => {
|
|
52
|
+
const userAgent = getUserAgent();
|
|
53
|
+
|
|
54
|
+
const isVizioAgent =
|
|
55
|
+
userAgent.includes(PLATFORMS.vizio) ||
|
|
56
|
+
userAgent.includes(PLATFORMS.smartcast) ||
|
|
57
|
+
userAgent.includes(PLATFORMS.conjure);
|
|
58
|
+
|
|
59
|
+
return isVizioAgent;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Checks if we are on the Vizio platform by checking for the global VIZIO object
|
|
64
|
+
* and the VIZIO Companion Library. This method does not use the userAgent string,
|
|
65
|
+
* because it mainly checks whether we have access to apis, which may not be available yet
|
|
66
|
+
*/
|
|
67
|
+
export const hasVizioAPIs = () => {
|
|
68
|
+
const hasAPIs =
|
|
69
|
+
typeof window.VIZIO !== "undefined" &&
|
|
70
|
+
window?.applicaster?.vizioLibraryDidLoad;
|
|
71
|
+
|
|
72
|
+
return hasAPIs;
|
|
73
|
+
};
|
|
74
|
+
|
|
45
75
|
/**
|
|
46
76
|
* platformSelect can't be used, because Platform.OS is overriden
|
|
47
77
|
* by overloadReactNativePlatform and don't support 'web' value
|
|
@@ -253,6 +283,24 @@ export const getDeviceData = async () => {
|
|
|
253
283
|
...tizenConnectionInfo,
|
|
254
284
|
device_type: getDeviceType(),
|
|
255
285
|
};
|
|
286
|
+
} else if (isVizioPlatform()) {
|
|
287
|
+
deviceData = {
|
|
288
|
+
...deviceData,
|
|
289
|
+
platform: "vizio",
|
|
290
|
+
deviceMake: "Vizio",
|
|
291
|
+
deviceType: "tv",
|
|
292
|
+
userAgent: getUserAgent(),
|
|
293
|
+
deviceWidth: window.innerWidth,
|
|
294
|
+
deviceHeight: window.innerHeight,
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
if (hasVizioAPIs()) {
|
|
298
|
+
window.VIZIO.getFirmwareVersion(function (firmwareVersion) {
|
|
299
|
+
deviceData.osVersion = firmwareVersion;
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
deviceData.deviceModel = window.VIZIO.deviceModel;
|
|
303
|
+
}
|
|
256
304
|
}
|
|
257
305
|
|
|
258
306
|
return deviceData;
|
package/main.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-dom-app",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.7990242848",
|
|
4
4
|
"description": "Zapp App Component for Applicaster's Quick Brick React Native App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://github.com/applicaster/zapp-react-dom-app#readme",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@applicaster/zapp-react-dom-ui-components": "12.0.0-alpha.
|
|
26
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.
|
|
27
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.
|
|
28
|
-
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.
|
|
29
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
25
|
+
"@applicaster/zapp-react-dom-ui-components": "12.0.0-alpha.7990242848",
|
|
26
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.7990242848",
|
|
27
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.7990242848",
|
|
28
|
+
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.7990242848",
|
|
29
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.7990242848",
|
|
30
30
|
"abortcontroller-polyfill": "^1.7.5",
|
|
31
31
|
"history": "^4.7.2",
|
|
32
32
|
"react-router-dom": "^5.1.2",
|