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