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