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