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