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