@applicaster/zapp-react-dom-app 12.0.0-rc.11 → 12.0.0-rc.110
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 +572 -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,562 @@ type Props = {
|
|
|
56
67
|
};
|
|
57
68
|
};
|
|
58
69
|
|
|
59
|
-
type State = { isKeyboardVisible: boolean };
|
|
70
|
+
type State = { isKeyboardVisible: boolean; keyboardInput: string };
|
|
60
71
|
|
|
61
72
|
type KeyCode = { code: string; keyCode: number | string };
|
|
62
73
|
|
|
63
74
|
export const alertConfirmationMesage =
|
|
64
75
|
"Are you sure you want to exit application?";
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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;
|
|
82
|
+
|
|
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;
|
|
90
|
+
|
|
91
|
+
constructor(props) {
|
|
92
|
+
super(props);
|
|
93
|
+
|
|
94
|
+
this.onKeyDownListener = this.onKeyDown.bind(this);
|
|
95
|
+
|
|
96
|
+
this.state = {
|
|
97
|
+
isKeyboardVisible: false,
|
|
98
|
+
keyboardInput: "",
|
|
99
|
+
};
|
|
100
|
+
|
|
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
|
+
}
|
|
72
139
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
userSequence: number[] = [];
|
|
78
|
-
confirmDialog: any;
|
|
140
|
+
componentDidMount() {
|
|
141
|
+
window.addEventListener("keydown", this.onKeyDownListener);
|
|
142
|
+
window.addEventListener("keyup", this.onKeyUp);
|
|
143
|
+
window.addEventListener("mousemove", this.onMouseMoveListener);
|
|
79
144
|
|
|
80
|
-
|
|
81
|
-
|
|
145
|
+
document.addEventListener("wheel", this.onScrollListener, {
|
|
146
|
+
passive: true,
|
|
147
|
+
});
|
|
82
148
|
|
|
83
|
-
|
|
149
|
+
document.addEventListener("mousedown", this.onMouseDownListener);
|
|
84
150
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
151
|
+
document.addEventListener(
|
|
152
|
+
"keyboardStateChange",
|
|
153
|
+
this.onKeyboardStateChange,
|
|
154
|
+
false
|
|
155
|
+
);
|
|
88
156
|
|
|
89
|
-
|
|
90
|
-
fn: this.onMouseMove,
|
|
91
|
-
context: this,
|
|
92
|
-
});
|
|
157
|
+
document.addEventListener("focusin", this.handleInputFocus);
|
|
93
158
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.onMouseDownListener = debounce({
|
|
101
|
-
fn: this.onMouseDown,
|
|
102
|
-
context: this,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
this.longKeyPressTimeout = null;
|
|
106
|
-
this.longPressActive = false;
|
|
107
|
-
this.confirmDialog = confirmationDialogStore.getState();
|
|
108
|
-
this.resetHudTimeout = this.resetHudTimeout.bind(this);
|
|
109
|
-
this.cursorVisibilityChange = this.cursorVisibilityChange.bind(this);
|
|
110
|
-
this.onKeyDown = this.onKeyDown.bind(this);
|
|
111
|
-
this.onKeyUp = this.onKeyUp.bind(this);
|
|
112
|
-
this.onMouseMove = this.onMouseMove.bind(this);
|
|
113
|
-
this.onScroll = this.onScroll.bind(this);
|
|
114
|
-
this.onMouseDown = this.onMouseDown.bind(this);
|
|
115
|
-
this.onKeyboardStateChange = this.onKeyboardStateChange.bind(this);
|
|
116
|
-
this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
|
|
117
|
-
this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
|
|
118
|
-
this.performExit = this.performExit.bind(this);
|
|
119
|
-
|
|
120
|
-
this.confirmDialog.setConfirmAction(this.performExit);
|
|
121
|
-
this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
|
|
122
|
-
}
|
|
159
|
+
document.addEventListener(
|
|
160
|
+
"cursorStateChange",
|
|
161
|
+
this.cursorVisibilityChange,
|
|
162
|
+
false
|
|
163
|
+
);
|
|
164
|
+
}
|
|
123
165
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
166
|
+
componentWillUnmount() {
|
|
167
|
+
window.removeEventListener("keydown", this.onKeyDownListener);
|
|
168
|
+
window.removeEventListener("keyup", this.onKeyUp);
|
|
169
|
+
document.removeEventListener("wheel", this.onScrollListener);
|
|
128
170
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
171
|
+
document.removeEventListener(
|
|
172
|
+
"cursorStateChange",
|
|
173
|
+
this.cursorVisibilityChange
|
|
174
|
+
);
|
|
132
175
|
|
|
133
|
-
|
|
176
|
+
document.removeEventListener("focusin", this.handleInputFocus);
|
|
134
177
|
|
|
135
|
-
|
|
136
|
-
"keyboardStateChange",
|
|
137
|
-
this.onKeyboardStateChange,
|
|
138
|
-
false
|
|
139
|
-
);
|
|
178
|
+
document.removeEventListener("mousedown", this.onMouseDownListener);
|
|
140
179
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.cursorVisibilityChange,
|
|
144
|
-
false
|
|
145
|
-
);
|
|
180
|
+
if (this.timeout) {
|
|
181
|
+
this.clearTimeout();
|
|
146
182
|
}
|
|
147
183
|
|
|
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);
|
|
184
|
+
this.isDismissing = false;
|
|
185
|
+
}
|
|
164
186
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
187
|
+
performExit() {
|
|
188
|
+
if (isSamsungPlatform()) {
|
|
189
|
+
this.onConfirmDialogClose();
|
|
190
|
+
sendQuickBrickEvent(QUICK_BRICK_EVENTS.MOVE_APP_TO_BACKGROUND);
|
|
168
191
|
}
|
|
169
192
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
193
|
+
if (isLgPlatform()) {
|
|
194
|
+
// webOS recommend to use this method when implemention a custom exit
|
|
195
|
+
globalAny.close();
|
|
196
|
+
}
|
|
175
197
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
globalAny.close();
|
|
179
|
-
}
|
|
198
|
+
if (isVizioPlatform()) {
|
|
199
|
+
window?.VIZIO?.exitApplication();
|
|
180
200
|
}
|
|
201
|
+
}
|
|
181
202
|
|
|
182
|
-
|
|
183
|
-
|
|
203
|
+
handleWebOsBack() {
|
|
204
|
+
const systemBack = globalAny?.webOS?.platformBack;
|
|
184
205
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
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
|
+
});
|
|
197
217
|
}
|
|
218
|
+
}
|
|
198
219
|
|
|
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();
|
|
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
|
+
});
|
|
223
241
|
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
console.warn("Failed to execute platformBack", e);
|
|
242
|
+
} else if (isLgPlatform()) {
|
|
243
|
+
this.handleWebOsBack();
|
|
227
244
|
}
|
|
245
|
+
} catch (e) {
|
|
246
|
+
// eslint-disable-next-line no-console
|
|
247
|
+
console.warn("Failed to execute platformBack", e);
|
|
228
248
|
}
|
|
249
|
+
}
|
|
229
250
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
251
|
+
cursorVisibilityChange(event) {
|
|
252
|
+
const visible = event.detail.visibility;
|
|
253
|
+
const { setDisplayState, displayState } = this.props;
|
|
233
254
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
255
|
+
if (visible && displayState === DISPLAY_STATES.PLAYER) {
|
|
256
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
257
|
+
this.resetHudTimeout();
|
|
238
258
|
}
|
|
259
|
+
}
|
|
239
260
|
|
|
240
|
-
|
|
241
|
-
|
|
261
|
+
onMouseMove() {
|
|
262
|
+
const { setDisplayState, displayState } = this.props;
|
|
242
263
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
264
|
+
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
265
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
266
|
+
this.resetHudTimeout();
|
|
247
267
|
}
|
|
268
|
+
}
|
|
248
269
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
270
|
+
isHomeScreen() {
|
|
271
|
+
const { navigator } = this.props;
|
|
272
|
+
const { rivers } = this.props;
|
|
252
273
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
274
|
+
const homeId = R.compose(
|
|
275
|
+
R.prop("id"),
|
|
276
|
+
R.find(R.prop("home")),
|
|
277
|
+
R.values
|
|
278
|
+
)(rivers);
|
|
258
279
|
|
|
259
|
-
|
|
280
|
+
const homePath = `/river/${homeId}`;
|
|
260
281
|
|
|
261
|
-
|
|
262
|
-
|
|
282
|
+
return homePath === navigator.currentRoute;
|
|
283
|
+
}
|
|
263
284
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
285
|
+
goToHome() {
|
|
286
|
+
const { navigator } = this.props;
|
|
287
|
+
const { rivers } = this.props;
|
|
288
|
+
const homeRiver = R.find(R.propEq("home", true), R.values(rivers));
|
|
268
289
|
|
|
269
|
-
|
|
270
|
-
|
|
290
|
+
navigator.replace(homeRiver);
|
|
291
|
+
}
|
|
271
292
|
|
|
272
|
-
|
|
273
|
-
|
|
293
|
+
resetHudTimeout() {
|
|
294
|
+
const { resetHudTimer = noop } = this.props;
|
|
274
295
|
|
|
275
|
-
|
|
276
|
-
|
|
296
|
+
resetHudTimer?.();
|
|
297
|
+
}
|
|
277
298
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
299
|
+
clearTimeout() {
|
|
300
|
+
if (this.timeout) {
|
|
301
|
+
clearTimeout(this.timeout);
|
|
302
|
+
this.timeout = null;
|
|
283
303
|
}
|
|
304
|
+
}
|
|
284
305
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
306
|
+
clearLongPressTimeout() {
|
|
307
|
+
if (this.longKeyPressTimeout) {
|
|
308
|
+
clearTimeout(this.longKeyPressTimeout);
|
|
309
|
+
this.longKeyPressTimeout = null;
|
|
290
310
|
}
|
|
311
|
+
}
|
|
291
312
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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();
|
|
309
330
|
|
|
310
|
-
|
|
331
|
+
break;
|
|
311
332
|
|
|
312
|
-
|
|
313
|
-
|
|
333
|
+
case KEYS.Enter.code:
|
|
334
|
+
focusManager.longPress();
|
|
314
335
|
|
|
315
|
-
|
|
336
|
+
break;
|
|
316
337
|
|
|
317
|
-
|
|
318
|
-
|
|
338
|
+
case KEYS.Forward.code:
|
|
339
|
+
playbackState && this.props.seekMethods.onForwardLongPress();
|
|
319
340
|
|
|
320
|
-
|
|
341
|
+
break;
|
|
321
342
|
|
|
322
|
-
|
|
323
|
-
|
|
343
|
+
case KEYS.Rewind.code:
|
|
344
|
+
playbackState && this.props.seekMethods.onRewindLongPress();
|
|
324
345
|
|
|
325
|
-
|
|
346
|
+
break;
|
|
326
347
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
348
|
+
default:
|
|
349
|
+
break;
|
|
330
350
|
}
|
|
351
|
+
}
|
|
331
352
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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();
|
|
339
360
|
|
|
340
|
-
|
|
361
|
+
focusManager.pressOut();
|
|
341
362
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
363
|
+
switch (event.code) {
|
|
364
|
+
case KEYS.Forward.code:
|
|
365
|
+
this.props.seekMethods.onForwardPressOut();
|
|
345
366
|
|
|
346
|
-
|
|
367
|
+
break;
|
|
347
368
|
|
|
348
|
-
|
|
349
|
-
|
|
369
|
+
case KEYS.Rewind.code:
|
|
370
|
+
this.props.seekMethods.onForwardPressOut();
|
|
350
371
|
|
|
351
|
-
|
|
372
|
+
break;
|
|
352
373
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
374
|
+
default:
|
|
375
|
+
break;
|
|
356
376
|
}
|
|
377
|
+
}
|
|
357
378
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
this.sequenceTimeout = setTimeout(() => {
|
|
372
|
-
// User needs to complete sequence before SEQUENCE_ENTRY_TIME
|
|
373
|
-
// or we set userSequence, and prev sequenceTimeout to empty values
|
|
374
|
-
this.sequenceTimeout = null;
|
|
375
|
-
this.userSequence = [];
|
|
376
|
-
}, SEQUENCE_ENTRY_TIME);
|
|
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);
|
|
377
390
|
}
|
|
378
391
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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
|
+
}
|
|
399
|
+
|
|
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({});
|
|
405
425
|
}
|
|
426
|
+
}
|
|
406
427
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
KEYS.Back,
|
|
415
|
-
KEYS.Enter,
|
|
416
|
-
KEYS.Rewind,
|
|
417
|
-
KEYS.Forward,
|
|
418
|
-
];
|
|
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];
|
|
419
435
|
|
|
420
|
-
|
|
436
|
+
const eventMatcher = R.compose(R.prop("matches"), keyCode)(event);
|
|
421
437
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
438
|
+
const supportsLongPress = R.compose(
|
|
439
|
+
R.any(R.equals(true)),
|
|
440
|
+
R.map(eventMatcher)
|
|
441
|
+
)(supportedEvents);
|
|
426
442
|
|
|
427
|
-
|
|
428
|
-
|
|
443
|
+
return supportsLongPress;
|
|
444
|
+
}
|
|
429
445
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
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();
|
|
439
454
|
}
|
|
440
455
|
}
|
|
456
|
+
}
|
|
441
457
|
|
|
442
|
-
|
|
443
|
-
|
|
458
|
+
onKeyDown(event) {
|
|
459
|
+
const { displayState, setDisplayState, navigator } = this.props;
|
|
460
|
+
const { isKeyboardVisible } = this.state;
|
|
461
|
+
|
|
462
|
+
const { isDialogVisible } = confirmationDialogStore.getState();
|
|
463
|
+
|
|
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
|
+
}
|
|
444
470
|
|
|
445
|
-
|
|
471
|
+
if (isKeyboardVisible && shouldUseOnScreenKeyboard()) {
|
|
472
|
+
if (keyCode(event).matchesAny("Escape", "Back")) {
|
|
473
|
+
event.preventDefault();
|
|
474
|
+
event.stopPropagation();
|
|
475
|
+
this.handleKeyboardDismiss();
|
|
446
476
|
|
|
447
|
-
|
|
448
|
-
if (this.keySupportsLongPress(event)) {
|
|
449
|
-
this.longKeyPressTimeout = setTimeout(() => {
|
|
450
|
-
this.onLongPress(event);
|
|
451
|
-
}, LONG_KEY_PRESS_TIMEOUT);
|
|
477
|
+
return;
|
|
452
478
|
}
|
|
479
|
+
}
|
|
453
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
|
+
) {
|
|
454
489
|
/**
|
|
455
|
-
|
|
456
|
-
buttons. Any other key press will display the transport controls
|
|
490
|
+
registering native keys for playback
|
|
457
491
|
*/
|
|
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
|
-
}
|
|
492
|
+
if (keyCode(event).matches(KEYS.TogglePlayPause)) {
|
|
493
|
+
const { playing } = playerManager.getState() || {};
|
|
472
494
|
|
|
473
|
-
if (
|
|
474
|
-
return playerManager.
|
|
495
|
+
if (!playing) {
|
|
496
|
+
return playerManager.togglePlayPause();
|
|
475
497
|
}
|
|
498
|
+
}
|
|
476
499
|
|
|
477
|
-
|
|
478
|
-
|
|
500
|
+
if (keyCode(event).matches(KEYS.Play)) {
|
|
501
|
+
return playerManager.play();
|
|
502
|
+
}
|
|
479
503
|
|
|
480
|
-
|
|
481
|
-
|
|
504
|
+
if (keyCode(event).matches(KEYS.Pause)) {
|
|
505
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
482
506
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
navigator.goBack();
|
|
507
|
+
return playerManager.pause();
|
|
508
|
+
}
|
|
486
509
|
|
|
487
|
-
|
|
488
|
-
|
|
510
|
+
if (keyCode(event).matches(KEYS.Stop)) {
|
|
511
|
+
setDisplayState(DISPLAY_STATES.DEFAULT);
|
|
512
|
+
navigator.goBack();
|
|
489
513
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
this.props.seekMethods.onForwardPress();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
493
516
|
|
|
494
|
-
|
|
495
|
-
|
|
517
|
+
if (keyCode(event).matches(KEYS.Forward)) {
|
|
518
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
519
|
+
this.props.seekMethods.onForwardPress();
|
|
496
520
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
this.props.seekMethods.onRewindPress();
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
500
523
|
|
|
501
|
-
|
|
502
|
-
|
|
524
|
+
if (keyCode(event).matches(KEYS.Rewind)) {
|
|
525
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
526
|
+
this.props.seekMethods.onRewindPress();
|
|
527
|
+
|
|
528
|
+
return;
|
|
503
529
|
}
|
|
530
|
+
}
|
|
504
531
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
+
*/
|
|
511
538
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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) {
|
|
528
567
|
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
568
|
} else {
|
|
545
|
-
|
|
569
|
+
navigator.goBack(false, true);
|
|
546
570
|
}
|
|
571
|
+
} else {
|
|
572
|
+
this.goToHome();
|
|
573
|
+
}
|
|
547
574
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}
|
|
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;
|
|
557
583
|
}
|
|
584
|
+
}
|
|
558
585
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
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();
|
|
567
591
|
}
|
|
568
592
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
this.performExit();
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
572
595
|
|
|
573
|
-
|
|
574
|
-
|
|
596
|
+
if (keyCode(event).matches(KEYS.Exit)) {
|
|
597
|
+
if (isSamsungPlatform() || shouldUseOnScreenKeyboard()) {
|
|
598
|
+
this.performExit();
|
|
575
599
|
|
|
576
|
-
|
|
600
|
+
return;
|
|
577
601
|
}
|
|
578
602
|
|
|
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
|
-
}
|
|
603
|
+
this.platformBack();
|
|
604
|
+
}
|
|
601
605
|
|
|
602
|
-
|
|
606
|
+
if (
|
|
607
|
+
keyCode(event).matchesAny(...ARROW_KEYS) &&
|
|
608
|
+
!this.state.isKeyboardVisible
|
|
609
|
+
) {
|
|
610
|
+
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
611
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
603
612
|
}
|
|
604
|
-
}
|
|
605
613
|
|
|
606
|
-
|
|
607
|
-
const { displayState } = this.props;
|
|
614
|
+
this.checkSequence(event.keyCode);
|
|
608
615
|
|
|
609
|
-
const
|
|
616
|
+
const direction = keyCode(event).direction();
|
|
610
617
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
isVertical: true,
|
|
615
|
-
value: "",
|
|
616
|
-
};
|
|
618
|
+
if (!isDialogVisible || !["up", "down"].includes(direction.value)) {
|
|
619
|
+
focusManager.moveFocus(direction);
|
|
620
|
+
}
|
|
617
621
|
|
|
618
|
-
if (
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
DIRECTION.value =
|
|
623
|
-
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();
|
|
624
626
|
}
|
|
625
627
|
|
|
626
628
|
if (
|
|
@@ -628,46 +630,139 @@ export function withInteractionManager(Component: React.FC) {
|
|
|
628
630
|
displayState === DISPLAY_STATES.HUD
|
|
629
631
|
) {
|
|
630
632
|
this.resetHudTimeout();
|
|
631
|
-
} else {
|
|
632
|
-
focusManager.moveFocus(DIRECTION);
|
|
633
633
|
}
|
|
634
|
+
|
|
635
|
+
return true;
|
|
634
636
|
}
|
|
637
|
+
}
|
|
635
638
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
const { displayState } = this.props;
|
|
639
|
+
onScroll(event) {
|
|
640
|
+
const { displayState } = this.props;
|
|
639
641
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
642
|
+
const deltaY = event?.deltaY;
|
|
643
|
+
|
|
644
|
+
const DIRECTION = {
|
|
645
|
+
axis: "y",
|
|
646
|
+
isHorizontal: false,
|
|
647
|
+
isVertical: true,
|
|
648
|
+
value: "",
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
if (deltaY > 0) {
|
|
652
|
+
DIRECTION.value = isLgPlatform() ? "down" : "up";
|
|
653
|
+
} else if (deltaY < 0) {
|
|
654
|
+
DIRECTION.value = isLgPlatform() ? "up" : "down";
|
|
647
655
|
}
|
|
648
656
|
|
|
649
|
-
|
|
650
|
-
|
|
657
|
+
if (
|
|
658
|
+
displayState === DISPLAY_STATES.PLAYER ||
|
|
659
|
+
displayState === DISPLAY_STATES.HUD
|
|
660
|
+
) {
|
|
661
|
+
this.resetHudTimeout();
|
|
662
|
+
} else {
|
|
663
|
+
focusManager.moveFocus(DIRECTION);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
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();
|
|
651
677
|
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
onKeyboardStateChange(event) {
|
|
681
|
+
this.setState({ isKeyboardVisible: event.visibility });
|
|
682
|
+
}
|
|
652
683
|
|
|
653
|
-
|
|
654
|
-
|
|
684
|
+
onConfirmDialogOpen() {
|
|
685
|
+
this.confirmDialog.showDialog();
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
onConfirmDialogClose() {
|
|
689
|
+
this.confirmDialog.hideDialog();
|
|
690
|
+
|
|
691
|
+
// restore initial focus after closing dialog
|
|
692
|
+
focusManager.setInitialFocus();
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
handleInputFocus = (event: FocusEvent) => {
|
|
696
|
+
if (!shouldUseOnScreenKeyboard()) return;
|
|
697
|
+
const target = event.target as HTMLElement;
|
|
698
|
+
|
|
699
|
+
if (this.isDismissing) {
|
|
700
|
+
return;
|
|
655
701
|
}
|
|
656
702
|
|
|
657
|
-
|
|
658
|
-
this.
|
|
703
|
+
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
|
|
704
|
+
this.setState({
|
|
705
|
+
isKeyboardVisible: true,
|
|
706
|
+
keyboardInput: (target as HTMLInputElement).value || "",
|
|
707
|
+
});
|
|
659
708
|
}
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
handleInputBlur(event: FocusEvent) {
|
|
712
|
+
if (!shouldUseOnScreenKeyboard()) return;
|
|
713
|
+
|
|
714
|
+
const target = event.target as HTMLElement;
|
|
660
715
|
|
|
661
|
-
|
|
662
|
-
|
|
716
|
+
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
|
|
717
|
+
const relatedTarget = event.relatedTarget as HTMLElement;
|
|
718
|
+
|
|
719
|
+
if (
|
|
720
|
+
!relatedTarget ||
|
|
721
|
+
(relatedTarget.tagName !== "INPUT" &&
|
|
722
|
+
relatedTarget.tagName !== "TEXTAREA")
|
|
723
|
+
) {
|
|
724
|
+
this.setState({ isKeyboardVisible: false });
|
|
725
|
+
}
|
|
663
726
|
}
|
|
664
727
|
}
|
|
665
728
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
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
|
+
}
|
|
673
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);
|