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