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