@robotical/webapp-types 3.18.2 → 3.18.4
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/dist-types/src/application/ApplicationManager/ApplicationManager.d.ts +4 -1
- package/dist-types/src/application/ApplicationManager/ApplicationManager.js +42 -13
- package/dist-types/src/application/RAFTs/RAFT.d.ts +1 -0
- package/dist-types/src/application/RAFTs/RAFT.js +9 -5
- package/dist-types/src/application/communicators/SelfdestructiveMessagePromise.d.ts +2 -3
- package/dist-types/src/application/communicators/SelfdestructiveMessagePromise.js +10 -10
- package/dist-types/src/application/communicators/WrapperCommunicator.d.ts +0 -1
- package/dist-types/src/application/communicators/WrapperCommunicator.js +6 -2
- package/dist-types/src/components/disposables/SwitchableCameraScanner/camera-stream-lifecycle-guard.d.ts +11 -0
- package/dist-types/src/components/disposables/SwitchableCameraScanner/camera-stream-lifecycle-guard.js +202 -0
- package/dist-types/src/components/disposables/SwitchableCameraScanner/index.js +17 -2
- package/dist-types/src/components/modals/LEDLightsOrQRVerificationModal/index.js +5 -1
- package/dist-types/src/components/modals/VerificationModal/index.js +15 -2
- package/dist-types/src/components/modals/VerificationModalPhoneApp/index.js +21 -4
- package/dist-types/src/store/SelectedRaftContext.d.ts +1 -0
- package/dist-types/src/store/SelectedRaftContext.js +16 -12
- package/dist-types/src/wrapper-app/WrapperAppManager.js +12 -5
- package/dist-types/src/wrapper-app/connectors/Connector.d.ts +12 -0
- package/dist-types/src/wrapper-app/connectors/Connector.js +29 -3
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ import AnalyticsFacade from "@robotical/appv2-analytics-gatherer";
|
|
|
14
14
|
import { CarouselNavigatorManager } from "../../utils/CarouselNavigatorManager";
|
|
15
15
|
import { CustomBluetoothItem, UserDeviceInfo } from "../../types/userDeviceInfo";
|
|
16
16
|
import { UserRoleContextTypes } from "../../store/user-role-context";
|
|
17
|
+
type ConnectResultDisposition = "commit" | "release" | "ignore";
|
|
17
18
|
export default class ApplicationManager {
|
|
18
19
|
selectedLocale: string;
|
|
19
20
|
AnalyticsFacade: typeof AnalyticsFacade;
|
|
@@ -97,6 +98,7 @@ export default class ApplicationManager {
|
|
|
97
98
|
private _clearConnectPromise;
|
|
98
99
|
private _dismissConnectAttempt;
|
|
99
100
|
private _isConnectAttemptActive;
|
|
101
|
+
private _getConnectResultDisposition;
|
|
100
102
|
private _createConnectingModal;
|
|
101
103
|
private _connectGeneric;
|
|
102
104
|
/**
|
|
@@ -108,7 +110,7 @@ export default class ApplicationManager {
|
|
|
108
110
|
* Selects a RAFT in Phone's verification modal
|
|
109
111
|
*/
|
|
110
112
|
selectRaft(ricToConnectTo: FOUND_RAFT_ON_DISCOVERY_RESPONSE['foundRIC'], method: RaftConnectionMethod): Promise<RAFT | null>;
|
|
111
|
-
connectToRIC(method: RaftConnectionMethod, uuids: string[], withoutVerification?: boolean): Promise<RAFT | null>;
|
|
113
|
+
connectToRIC(method: RaftConnectionMethod, uuids: string[], withoutVerification?: boolean, getResultDisposition?: () => ConnectResultDisposition): Promise<RAFT | null>;
|
|
112
114
|
/**
|
|
113
115
|
* Warranty Service bluetooth scan for device
|
|
114
116
|
* It scans for a device and gets the device object
|
|
@@ -187,3 +189,4 @@ export default class ApplicationManager {
|
|
|
187
189
|
injectJS(jsCode: string): Promise<unknown>;
|
|
188
190
|
getTheCurrentlySelectedDeviceOrFirstOfItsKind(deviceType: RaftTypeE): RAFT | undefined;
|
|
189
191
|
}
|
|
192
|
+
export {};
|
|
@@ -546,6 +546,16 @@ var ApplicationManager = /** @class */ (function () {
|
|
|
546
546
|
ApplicationManager.prototype._isConnectAttemptActive = function (connectAttemptId) {
|
|
547
547
|
return this._activeConnectAttemptId === connectAttemptId;
|
|
548
548
|
};
|
|
549
|
+
ApplicationManager.prototype._getConnectResultDisposition = function (connectAttemptId) {
|
|
550
|
+
if (this._isConnectAttemptActive(connectAttemptId)) {
|
|
551
|
+
return "commit";
|
|
552
|
+
}
|
|
553
|
+
// A newer app attempt shares WrapperAppManager's in-flight Bluetooth
|
|
554
|
+
// result. Let that current consumer commit it instead of tearing down the
|
|
555
|
+
// transport underneath it. With no replacement consumer, Dismiss means
|
|
556
|
+
// the late success must be fully released.
|
|
557
|
+
return this._activeConnectAttemptId === null ? "release" : "ignore";
|
|
558
|
+
};
|
|
549
559
|
ApplicationManager.prototype._createConnectingModal = function (connectAttemptId) {
|
|
550
560
|
var _this = this;
|
|
551
561
|
return createElement(ConnectingLoadingSpinnerModal, {
|
|
@@ -633,7 +643,7 @@ var ApplicationManager = /** @class */ (function () {
|
|
|
633
643
|
_a.label = 11;
|
|
634
644
|
case 11:
|
|
635
645
|
_a.trys.push([11, 16, , 17]);
|
|
636
|
-
return [4 /*yield*/, window.applicationManager.connectToRIC(RaftConnectionMethod.WEB_BLE, uuids, isQRVerification)];
|
|
646
|
+
return [4 /*yield*/, window.applicationManager.connectToRIC(RaftConnectionMethod.WEB_BLE, uuids, isQRVerification, function () { return _this._getConnectResultDisposition(connectAttemptId); })];
|
|
637
647
|
case 12:
|
|
638
648
|
newRaft = _a.sent();
|
|
639
649
|
if (!this._isConnectAttemptActive(connectAttemptId)) {
|
|
@@ -767,21 +777,31 @@ var ApplicationManager = /** @class */ (function () {
|
|
|
767
777
|
});
|
|
768
778
|
});
|
|
769
779
|
};
|
|
770
|
-
ApplicationManager.prototype.connectToRIC = function (method, uuids, withoutVerification) {
|
|
780
|
+
ApplicationManager.prototype.connectToRIC = function (method, uuids, withoutVerification, getResultDisposition) {
|
|
771
781
|
var _a, _b, _c, _d;
|
|
782
|
+
if (getResultDisposition === void 0) { getResultDisposition = function () { return "commit"; }; }
|
|
772
783
|
return __awaiter(this, void 0, void 0, function () {
|
|
773
|
-
var wasConnectedObj, raftId, raftType, raft;
|
|
784
|
+
var wasConnectedObj, raftId, raftType, resultDisposition, raft;
|
|
774
785
|
return __generator(this, function (_e) {
|
|
775
786
|
switch (_e.label) {
|
|
776
787
|
case 0: return [4 /*yield*/, RAFT.connect(method, uuids)];
|
|
777
788
|
case 1:
|
|
778
789
|
wasConnectedObj = _e.sent();
|
|
779
|
-
if (!wasConnectedObj.success) return [3 /*break*/,
|
|
790
|
+
if (!wasConnectedObj.success) return [3 /*break*/, 7];
|
|
780
791
|
raftId = (_a = wasConnectedObj.data) === null || _a === void 0 ? void 0 : _a.raftId;
|
|
781
792
|
raftType = (_b = wasConnectedObj.data) === null || _b === void 0 ? void 0 : _b.raftType;
|
|
782
793
|
if (!raftId || !raftType) {
|
|
783
794
|
throw new Error("RAFT ID or RAFT Type is missing: ".concat(raftId, " ").concat(raftType));
|
|
784
795
|
}
|
|
796
|
+
resultDisposition = getResultDisposition();
|
|
797
|
+
if (!(resultDisposition !== "commit")) return [3 /*break*/, 4];
|
|
798
|
+
if (!(resultDisposition === "release")) return [3 /*break*/, 3];
|
|
799
|
+
return [4 /*yield*/, window.wrapperCommunicator.sendMessageAndWait(AppSentMessage.RAFT_DISCONNECT, { raftId: raftId })];
|
|
800
|
+
case 2:
|
|
801
|
+
_e.sent();
|
|
802
|
+
_e.label = 3;
|
|
803
|
+
case 3: return [2 /*return*/, null];
|
|
804
|
+
case 4:
|
|
785
805
|
raft = void 0;
|
|
786
806
|
switch (raftType) {
|
|
787
807
|
case RaftTypeE.MARTY:
|
|
@@ -799,23 +819,23 @@ var ApplicationManager = /** @class */ (function () {
|
|
|
799
819
|
}
|
|
800
820
|
// get missed Connect event
|
|
801
821
|
publishMissedConnectionEvent(raftId);
|
|
802
|
-
if (!!((_d = wasConnectedObj.data) === null || _d === void 0 ? void 0 : _d.systemInfo)) return [3 /*break*/,
|
|
822
|
+
if (!!((_d = wasConnectedObj.data) === null || _d === void 0 ? void 0 : _d.systemInfo)) return [3 /*break*/, 6];
|
|
803
823
|
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 200); })];
|
|
804
|
-
case
|
|
824
|
+
case 5:
|
|
805
825
|
_e.sent();
|
|
806
|
-
_e.label =
|
|
807
|
-
case
|
|
826
|
+
_e.label = 6;
|
|
827
|
+
case 6:
|
|
808
828
|
// start LED verification process
|
|
809
829
|
if (!withoutVerification) {
|
|
810
830
|
modalState.setModal(createElement(VerificationModal, { connectedRAFT_: raft }), i18n.t("connection.looking_for_raft", { raftType: raft.type }), false);
|
|
811
831
|
}
|
|
812
832
|
return [2 /*return*/, raft];
|
|
813
|
-
case
|
|
833
|
+
case 7:
|
|
814
834
|
if (wasConnectedObj.reason === 'unplugged') {
|
|
815
835
|
modalState.setModal(createElement(InUnpluggedModalContent), i18n.t("calibration_screen.colour_calibration.unplugged_modal_title"));
|
|
816
836
|
}
|
|
817
|
-
_e.label =
|
|
818
|
-
case
|
|
837
|
+
_e.label = 8;
|
|
838
|
+
case 8: return [2 /*return*/, null];
|
|
819
839
|
}
|
|
820
840
|
});
|
|
821
841
|
});
|
|
@@ -1113,12 +1133,21 @@ var ApplicationManager = /** @class */ (function () {
|
|
|
1113
1133
|
}
|
|
1114
1134
|
};
|
|
1115
1135
|
ApplicationManager.prototype.receivedRICEvent = function (raftId, eventType, eventEnum, eventName, eventData) {
|
|
1116
|
-
var _a;
|
|
1117
1136
|
if (raftId === "scanner") {
|
|
1118
1137
|
this.publish(eventType, eventEnum, eventName, eventData);
|
|
1119
1138
|
}
|
|
1120
1139
|
else {
|
|
1121
|
-
|
|
1140
|
+
var raft = this.connectedRafts[raftId];
|
|
1141
|
+
if (!raft) {
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
var isTerminalDisconnectEvent = eventType === "conn" && (eventEnum === RaftConnEvent.CONN_REJECTED ||
|
|
1145
|
+
eventEnum === RaftConnEvent.CONN_DISCONNECTED);
|
|
1146
|
+
if (this._disconnectPromises.has(raft) && !isTerminalDisconnectEvent) {
|
|
1147
|
+
Logger.info(SHOW_LOGS, TAG, "Ignoring ".concat(eventName, " after disconnect started for ").concat(raftId));
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
raft.receivedRICEvent(eventType, eventEnum, eventName, eventData);
|
|
1122
1151
|
}
|
|
1123
1152
|
};
|
|
1124
1153
|
//======================//
|
|
@@ -18,6 +18,7 @@ export default class RAFT implements RICInterface {
|
|
|
18
18
|
systemInfo: RaftSystemInfo | null;
|
|
19
19
|
raftStateInfo: RICStateInfo | SimplifiedCogStateInfo | null;
|
|
20
20
|
isVerified: boolean;
|
|
21
|
+
private _verificationDecision;
|
|
21
22
|
hasVerifiedConnection(): boolean;
|
|
22
23
|
/**
|
|
23
24
|
* Method to get ledLcdColours, to be implemented in child classes.
|
|
@@ -58,6 +58,7 @@ var RAFT = /** @class */ (function () {
|
|
|
58
58
|
// RAFT State Info
|
|
59
59
|
this.raftStateInfo = null;
|
|
60
60
|
this.isVerified = false;
|
|
61
|
+
this._verificationDecision = null;
|
|
61
62
|
}
|
|
62
63
|
RAFT.prototype.hasVerifiedConnection = function () {
|
|
63
64
|
return this.isVerified;
|
|
@@ -145,6 +146,7 @@ var RAFT = /** @class */ (function () {
|
|
|
145
146
|
RAFT.prototype.verifyRaftPhoneApp = function (discoveredDevice) {
|
|
146
147
|
return __awaiter(this, void 0, void 0, function () {
|
|
147
148
|
return __generator(this, function (_a) {
|
|
149
|
+
this._verificationDecision = null;
|
|
148
150
|
return [2 /*return*/, window.wrapperCommunicator.sendMessageAndWait(AppSentMessage.RAFT_VERIFY_PHONE, { ledLcdColours: this.ledLcdColours, discoveredDevice: discoveredDevice, raftId: this.id })];
|
|
149
151
|
});
|
|
150
152
|
});
|
|
@@ -155,6 +157,7 @@ var RAFT = /** @class */ (function () {
|
|
|
155
157
|
RAFT.prototype.verifyRaft = function () {
|
|
156
158
|
return __awaiter(this, void 0, void 0, function () {
|
|
157
159
|
return __generator(this, function (_a) {
|
|
160
|
+
this._verificationDecision = null;
|
|
158
161
|
return [2 /*return*/, window.wrapperCommunicator.sendMessageAndWait(AppSentMessage.RAFT_VERIFY, { ledLcdColours: this.ledLcdColours, raftId: this.id })];
|
|
159
162
|
});
|
|
160
163
|
});
|
|
@@ -163,11 +166,12 @@ var RAFT = /** @class */ (function () {
|
|
|
163
166
|
* Stops the verification process
|
|
164
167
|
*/
|
|
165
168
|
RAFT.prototype.stopVerifyingRaft = function (isCorrectRIC) {
|
|
166
|
-
|
|
167
|
-
return
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
169
|
+
if (this._verificationDecision) {
|
|
170
|
+
return this._verificationDecision.promise;
|
|
171
|
+
}
|
|
172
|
+
var promise = window.wrapperCommunicator.sendMessageAndWait(AppSentMessage.RAFT_STOP_VERIFY, { isCorrectRIC: isCorrectRIC, raftId: this.id });
|
|
173
|
+
this._verificationDecision = { isCorrectRIC: isCorrectRIC, promise: promise };
|
|
174
|
+
return promise;
|
|
171
175
|
};
|
|
172
176
|
/**
|
|
173
177
|
* Receiveds events from the RICConnector
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
export default class SelfdestructiveMessagePromise {
|
|
3
3
|
resolve: (value?: any) => void;
|
|
4
4
|
reject: (reason?: any) => void;
|
|
5
|
-
timeout
|
|
6
|
-
TIMEOUT_PERIOD: number;
|
|
5
|
+
timeout?: NodeJS.Timeout;
|
|
7
6
|
constructor(resolve: (value?: any) => void, reject: (reason?: any) => void, id: string, messagePromises: {
|
|
8
7
|
[key: string]: SelfdestructiveMessagePromise | undefined;
|
|
9
|
-
});
|
|
8
|
+
}, timeoutPeriod?: number | null);
|
|
10
9
|
}
|
|
@@ -2,29 +2,29 @@ import Logger from "../../services/logger/Logger";
|
|
|
2
2
|
var SHOW_LOGS = true;
|
|
3
3
|
var TAG = "SelfdestructiveMessagePromise";
|
|
4
4
|
var SelfdestructiveMessagePromise = /** @class */ (function () {
|
|
5
|
-
function SelfdestructiveMessagePromise(resolve, reject, id, messagePromises) {
|
|
5
|
+
function SelfdestructiveMessagePromise(resolve, reject, id, messagePromises, timeoutPeriod) {
|
|
6
|
+
if (timeoutPeriod === void 0) { timeoutPeriod = 30000; }
|
|
6
7
|
var _this = this;
|
|
7
8
|
this.resolve = function () { };
|
|
8
9
|
this.reject = function () { };
|
|
9
|
-
this.TIMEOUT_PERIOD = 30000;
|
|
10
10
|
this.resolve = function (value) {
|
|
11
11
|
resolve(value);
|
|
12
|
-
|
|
12
|
+
if (_this.timeout)
|
|
13
|
+
clearTimeout(_this.timeout);
|
|
13
14
|
delete messagePromises[id];
|
|
14
15
|
};
|
|
15
16
|
this.reject = function (reason) {
|
|
16
17
|
resolve(reason); // on purpose resolving instead of rejecting
|
|
17
|
-
|
|
18
|
+
if (_this.timeout)
|
|
19
|
+
clearTimeout(_this.timeout);
|
|
18
20
|
delete messagePromises[id];
|
|
19
21
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
if (timeoutPeriod !== null) {
|
|
23
|
+
this.timeout = setTimeout(function () {
|
|
22
24
|
Logger.warn(SHOW_LOGS, TAG, "Timeout for message promise with id: ".concat(id));
|
|
23
25
|
_this.reject({ error: "Timeout" });
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
clearTimeout(_this.timeout);
|
|
27
|
-
}, this.TIMEOUT_PERIOD);
|
|
26
|
+
}, timeoutPeriod);
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
29
|
return SelfdestructiveMessagePromise;
|
|
30
30
|
}());
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { AppSentMessage, IWrapperSentMessage, WRAPPER_RESPONSE_BASE } from "../../types/communication-between-apps/wrapper-communication";
|
|
2
2
|
export declare class WrapperCommunicator {
|
|
3
3
|
private messagePromises;
|
|
4
|
-
constructor();
|
|
5
4
|
/**
|
|
6
5
|
* Receives a message from the wrapper app
|
|
7
6
|
*/
|
|
@@ -35,7 +35,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
import Logger from "../../services/logger/Logger";
|
|
38
|
-
import { WrapperSentMessage } from "../../types/communication-between-apps/wrapper-communication";
|
|
38
|
+
import { AppSentMessage, WrapperSentMessage } from "../../types/communication-between-apps/wrapper-communication";
|
|
39
39
|
import randomHashGenerator from "../../utils/helpers/randomHashGenerator";
|
|
40
40
|
import isPhoneApp from "../../utils/phone-app-communication/is-phone-app";
|
|
41
41
|
import SelfdestructiveMessagePromise from "./SelfdestructiveMessagePromise";
|
|
@@ -59,7 +59,11 @@ var WrapperCommunicator = /** @class */ (function () {
|
|
|
59
59
|
var _this = this;
|
|
60
60
|
var messagePromiseId = randomHashGenerator();
|
|
61
61
|
var promise = new Promise(function (resolve, reject) {
|
|
62
|
-
_this.messagePromises[messagePromiseId] = new SelfdestructiveMessagePromise(resolve, reject, messagePromiseId, _this.messagePromises
|
|
62
|
+
_this.messagePromises[messagePromiseId] = new SelfdestructiveMessagePromise(resolve, reject, messagePromiseId, _this.messagePromises,
|
|
63
|
+
// Choosing a physical Bluetooth device is user-mediated and has no
|
|
64
|
+
// application-safe deadline. The connecting modal owns cancellation;
|
|
65
|
+
// timing this bridge request out would orphan a later chooser result.
|
|
66
|
+
message === AppSentMessage.RAFT_CONNECT ? null : undefined);
|
|
63
67
|
});
|
|
64
68
|
var messageObject = {
|
|
65
69
|
message: message,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type CameraStreamLifecycleLease = {
|
|
2
|
+
owner?: symbol;
|
|
3
|
+
release: () => void;
|
|
4
|
+
};
|
|
5
|
+
export declare const addCameraStreamLifecycleOwner: (constraints: MediaTrackConstraints | undefined, owner: symbol) => MediaTrackConstraints;
|
|
6
|
+
/**
|
|
7
|
+
* Keeps each camera request owned by the QR scanner that initiated it.
|
|
8
|
+
* getUserMedia cannot be aborted, so a stream that resolves after its scanner
|
|
9
|
+
* unmounts is stopped before the dependency's fixed startup delay can retain it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const acquireCameraStreamLifecycleGuard: () => CameraStreamLifecycleLease;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var CAMERA_STREAM_OWNER = Symbol("qr-camera-stream-owner");
|
|
13
|
+
var activeGuard;
|
|
14
|
+
var stopStreamOnce = function (stream) {
|
|
15
|
+
stream.getTracks().forEach(function (track) {
|
|
16
|
+
if (track.readyState === "ended") {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
var originalStop = track.stop.bind(track);
|
|
20
|
+
var stopped = false;
|
|
21
|
+
var stopOnce = function () {
|
|
22
|
+
if (stopped || track.readyState === "ended") {
|
|
23
|
+
stopped = true;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
stopped = true;
|
|
27
|
+
originalStop();
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
Object.defineProperty(track, "stop", {
|
|
31
|
+
configurable: true,
|
|
32
|
+
writable: true,
|
|
33
|
+
value: stopOnce,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (_a) {
|
|
37
|
+
// Native MediaStreamTrack objects are normally extensible. If a WebView
|
|
38
|
+
// makes one read-only, stopping it is still more important than deduping
|
|
39
|
+
// a later, harmless stop call from the scanner dependency.
|
|
40
|
+
}
|
|
41
|
+
stopOnce();
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var getOwnedRequest = function (constraints) {
|
|
45
|
+
var videoConstraints = constraints === null || constraints === void 0 ? void 0 : constraints.video;
|
|
46
|
+
if (!videoConstraints || typeof videoConstraints !== "object") {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
var owner = videoConstraints[CAMERA_STREAM_OWNER];
|
|
50
|
+
if (!owner) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
var nativeVideoConstraints = __assign({}, videoConstraints);
|
|
54
|
+
Reflect.deleteProperty(nativeVideoConstraints, CAMERA_STREAM_OWNER);
|
|
55
|
+
return {
|
|
56
|
+
owner: owner,
|
|
57
|
+
constraints: __assign(__assign({}, constraints), { video: nativeVideoConstraints }),
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
var installGuard = function (mediaDevices) {
|
|
61
|
+
var _a, _b, _c;
|
|
62
|
+
var originalGetUserMedia = mediaDevices.getUserMedia;
|
|
63
|
+
if (typeof originalGetUserMedia !== "function") {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
var state = {
|
|
67
|
+
mediaDevices: mediaDevices,
|
|
68
|
+
originalDescriptor: Object.getOwnPropertyDescriptor(mediaDevices, "getUserMedia"),
|
|
69
|
+
originalGetUserMedia: originalGetUserMedia,
|
|
70
|
+
guardedGetUserMedia: undefined,
|
|
71
|
+
owners: new Set(),
|
|
72
|
+
requests: new Set(),
|
|
73
|
+
};
|
|
74
|
+
state.guardedGetUserMedia = function (constraints) {
|
|
75
|
+
var ownedRequest = getOwnedRequest(constraints);
|
|
76
|
+
if (!ownedRequest) {
|
|
77
|
+
return state.originalGetUserMedia.call(state.mediaDevices, constraints);
|
|
78
|
+
}
|
|
79
|
+
var request = {
|
|
80
|
+
owner: ownedRequest.owner,
|
|
81
|
+
cancelled: false,
|
|
82
|
+
};
|
|
83
|
+
state.requests.add(request);
|
|
84
|
+
var cameraRequest;
|
|
85
|
+
try {
|
|
86
|
+
cameraRequest = state.originalGetUserMedia.call(state.mediaDevices, ownedRequest.constraints);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
state.requests.delete(request);
|
|
90
|
+
return Promise.reject(error);
|
|
91
|
+
}
|
|
92
|
+
return cameraRequest.then(function (stream) {
|
|
93
|
+
request.stream = stream;
|
|
94
|
+
if (request.cancelled || !state.owners.has(request.owner)) {
|
|
95
|
+
stopStreamOnce(stream);
|
|
96
|
+
state.requests.delete(request);
|
|
97
|
+
}
|
|
98
|
+
// Resolve the now-ended stream instead of rejecting. The scanner is
|
|
99
|
+
// already unmounted, and this lets its queued cleanup settle without
|
|
100
|
+
// reporting an expected AbortError to the React Native native logger.
|
|
101
|
+
return stream;
|
|
102
|
+
}, function (error) {
|
|
103
|
+
state.requests.delete(request);
|
|
104
|
+
throw error;
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
var installed = false;
|
|
108
|
+
try {
|
|
109
|
+
installed =
|
|
110
|
+
Reflect.set(mediaDevices, "getUserMedia", state.guardedGetUserMedia) &&
|
|
111
|
+
mediaDevices.getUserMedia === state.guardedGetUserMedia;
|
|
112
|
+
}
|
|
113
|
+
catch (_d) {
|
|
114
|
+
installed = false;
|
|
115
|
+
}
|
|
116
|
+
if (!installed && ((_a = state.originalDescriptor) === null || _a === void 0 ? void 0 : _a.configurable) !== false) {
|
|
117
|
+
try {
|
|
118
|
+
Object.defineProperty(mediaDevices, "getUserMedia", {
|
|
119
|
+
configurable: true,
|
|
120
|
+
enumerable: (_c = (_b = state.originalDescriptor) === null || _b === void 0 ? void 0 : _b.enumerable) !== null && _c !== void 0 ? _c : false,
|
|
121
|
+
writable: true,
|
|
122
|
+
value: state.guardedGetUserMedia,
|
|
123
|
+
});
|
|
124
|
+
installed = mediaDevices.getUserMedia === state.guardedGetUserMedia;
|
|
125
|
+
}
|
|
126
|
+
catch (_e) {
|
|
127
|
+
installed = false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return installed ? state : null;
|
|
131
|
+
};
|
|
132
|
+
var restoreGetUserMedia = function (state) {
|
|
133
|
+
if (state.mediaDevices.getUserMedia !== state.guardedGetUserMedia) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
if (state.originalDescriptor) {
|
|
138
|
+
Object.defineProperty(state.mediaDevices, "getUserMedia", state.originalDescriptor);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
Reflect.deleteProperty(state.mediaDevices, "getUserMedia");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (_a) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
return state.mediaDevices.getUserMedia !== state.guardedGetUserMedia;
|
|
148
|
+
};
|
|
149
|
+
export var addCameraStreamLifecycleOwner = function (constraints, owner) {
|
|
150
|
+
var _a;
|
|
151
|
+
return (__assign(__assign({}, constraints), (_a = {}, _a[CAMERA_STREAM_OWNER] = owner, _a)));
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Keeps each camera request owned by the QR scanner that initiated it.
|
|
155
|
+
* getUserMedia cannot be aborted, so a stream that resolves after its scanner
|
|
156
|
+
* unmounts is stopped before the dependency's fixed startup delay can retain it.
|
|
157
|
+
*/
|
|
158
|
+
export var acquireCameraStreamLifecycleGuard = function () {
|
|
159
|
+
var mediaDevices = typeof navigator === "undefined" ? undefined : navigator.mediaDevices;
|
|
160
|
+
if (!mediaDevices || typeof mediaDevices.getUserMedia !== "function") {
|
|
161
|
+
return { release: function () { return undefined; } };
|
|
162
|
+
}
|
|
163
|
+
var state = activeGuard;
|
|
164
|
+
if (!state ||
|
|
165
|
+
state.mediaDevices !== mediaDevices ||
|
|
166
|
+
mediaDevices.getUserMedia !== state.guardedGetUserMedia) {
|
|
167
|
+
state = installGuard(mediaDevices) || undefined;
|
|
168
|
+
if (!state) {
|
|
169
|
+
return { release: function () { return undefined; } };
|
|
170
|
+
}
|
|
171
|
+
activeGuard = state;
|
|
172
|
+
}
|
|
173
|
+
var acquiredState = state;
|
|
174
|
+
var owner = Symbol("qr-camera-owner");
|
|
175
|
+
acquiredState.owners.add(owner);
|
|
176
|
+
var released = false;
|
|
177
|
+
return {
|
|
178
|
+
owner: owner,
|
|
179
|
+
release: function () {
|
|
180
|
+
if (released) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
released = true;
|
|
184
|
+
acquiredState.owners.delete(owner);
|
|
185
|
+
acquiredState.requests.forEach(function (request) {
|
|
186
|
+
if (request.owner !== owner) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
request.cancelled = true;
|
|
190
|
+
if (request.stream) {
|
|
191
|
+
stopStreamOnce(request.stream);
|
|
192
|
+
acquiredState.requests.delete(request);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
if (acquiredState.owners.size === 0 &&
|
|
196
|
+
restoreGetUserMedia(acquiredState) &&
|
|
197
|
+
activeGuard === acquiredState) {
|
|
198
|
+
activeGuard = undefined;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
};
|
|
@@ -21,12 +21,27 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
21
21
|
return t;
|
|
22
22
|
};
|
|
23
23
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
24
|
-
import { useMemo, useState } from "react";
|
|
24
|
+
import { useEffect, useMemo, useState } from "react";
|
|
25
25
|
import { useTranslation } from "react-i18next";
|
|
26
26
|
import { MdCameraswitch } from "react-icons/md";
|
|
27
27
|
import { Scanner } from "@yudiel/react-qr-scanner";
|
|
28
28
|
import isPhoneApp from "../../../utils/phone-app-communication/is-phone-app";
|
|
29
|
+
import { acquireCameraStreamLifecycleGuard, addCameraStreamLifecycleOwner, } from "./camera-stream-lifecycle-guard";
|
|
29
30
|
import styles from "./styles.module.css";
|
|
31
|
+
function LifecycleGuardedScanner(props) {
|
|
32
|
+
var _a = useState(null), cameraLease = _a[0], setCameraLease = _a[1];
|
|
33
|
+
useEffect(function () {
|
|
34
|
+
var lease = acquireCameraStreamLifecycleGuard();
|
|
35
|
+
setCameraLease(lease);
|
|
36
|
+
return lease.release;
|
|
37
|
+
}, []);
|
|
38
|
+
var guardedConstraints = useMemo(function () {
|
|
39
|
+
return (cameraLease === null || cameraLease === void 0 ? void 0 : cameraLease.owner)
|
|
40
|
+
? addCameraStreamLifecycleOwner(props.constraints, cameraLease.owner)
|
|
41
|
+
: props.constraints;
|
|
42
|
+
}, [cameraLease, props.constraints]);
|
|
43
|
+
return cameraLease ? (_jsx(Scanner, __assign({}, props, { constraints: guardedConstraints }))) : null;
|
|
44
|
+
}
|
|
30
45
|
export default function SwitchableCameraScanner(_a) {
|
|
31
46
|
var constraints = _a.constraints, scannerProps = __rest(_a, ["constraints"]);
|
|
32
47
|
var t = useTranslation().t;
|
|
@@ -39,7 +54,7 @@ export default function SwitchableCameraScanner(_a) {
|
|
|
39
54
|
var cameraSwitchLabel = switchToFrontCamera
|
|
40
55
|
? t("connection.switch_to_front_camera")
|
|
41
56
|
: t("connection.switch_to_rear_camera");
|
|
42
|
-
return (_jsxs("div", __assign({ className: styles.container }, { children: [_jsx(
|
|
57
|
+
return (_jsxs("div", __assign({ className: styles.container }, { children: [_jsx(LifecycleGuardedScanner, __assign({}, scannerProps, { constraints: cameraConstraints })), isPhoneApp() && (_jsx("button", __assign({ type: "button", className: styles.cameraSwitchButton, "aria-label": cameraSwitchLabel, title: cameraSwitchLabel, onClick: function () {
|
|
43
58
|
return setFacingMode(function (currentFacingMode) {
|
|
44
59
|
return currentFacingMode === "environment" ? "user" : "environment";
|
|
45
60
|
});
|
|
@@ -110,7 +110,11 @@ export default function LEDLightsOrQRVerificationModal(_a) {
|
|
|
110
110
|
return [2 /*return*/];
|
|
111
111
|
});
|
|
112
112
|
}); };
|
|
113
|
-
return (_jsxs("div", __assign({ className: styles.container }, { children: [_jsxs("div", __assign({ className: styles.robotContext }, { children: [_jsx("p", __assign({ className: styles.robotContextEyebrow }, { children: t("connection.connecting_to", "Connecting to") })), _jsx("h3", __assign({ className: styles.robotContextTitle }, { children: targetRaftType })), allowSwitchToMarty && (_jsx("button", __assign({ type: "button", className: styles.switchRobotButton, onClick: function () {
|
|
113
|
+
return (_jsxs("div", __assign({ className: styles.container }, { children: [_jsxs("div", __assign({ className: styles.robotContext }, { children: [_jsx("p", __assign({ className: styles.robotContextEyebrow }, { children: t("connection.connecting_to", "Connecting to") })), _jsx("h3", __assign({ className: styles.robotContextTitle }, { children: targetRaftType })), allowSwitchToMarty && (_jsx("button", __assign({ type: "button", className: styles.switchRobotButton, onClick: function () {
|
|
114
|
+
return modalState.closeModalWithoutAnimation({
|
|
115
|
+
action: "switch-to-marty",
|
|
116
|
+
});
|
|
117
|
+
} }, { children: t("connection.connect_marty_instead", "Connect Marty instead") })))] })), _jsxs("div", __assign({ className: styles.bluetoothNotice }, { children: [_jsx(BluetoothSVG, { className: styles.bluetoothIcon, fill: MAIN_BLUE, "aria-hidden": "true", focusable: "false" }), _jsx("span", __assign({ className: styles.bluetoothText }, { children: t("configuration_screen.bluetooth") }))] })), _jsxs("div", { children: [_jsx("p", __assign({ className: styles.robotContextSubtitle }, { children: t("connection.cog_verification_prompt", "Choose how you want to verify your Cog connection.") })), !isButtonToConnectVisible ? _jsx("div", __assign({ className: styles.cards }, { children: options.map(function (_a) {
|
|
114
118
|
var id = _a.id, title = _a.title, subtitle = _a.subtitle, icon = _a.icon;
|
|
115
119
|
return (_jsxs("button", __assign({ type: "button", className: qrSelected && id === 'qr' ? [styles.card, styles.qrselected].join(" ") : styles.card, onClick: function () { return handleSelect(id); }, "aria-label": title, "aria-pressed": id === "qr" ? qrSelected : false }, { children: [_jsx("div", __assign({ className: styles.icon }, { children: icon })), _jsx("h3", __assign({ className: styles.title }, { children: title })), _jsx("p", __assign({ className: styles.subtitle }, { children: subtitle }))] }), id));
|
|
116
120
|
}) })) :
|
|
@@ -46,7 +46,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
48
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
49
|
-
import { useEffect, useState } from "react";
|
|
49
|
+
import { useEffect, useRef, useState } from "react";
|
|
50
50
|
import "./styles.css";
|
|
51
51
|
import { ReactComponent as BluetoothSVG } from "../../../assets/configuration/bluetooth.svg";
|
|
52
52
|
import { MAIN_BLUE } from "../../../styles/colors";
|
|
@@ -62,7 +62,16 @@ function VerificationModal(_a) {
|
|
|
62
62
|
var _b = useState([]), randomColours = _b[0], setRandomColours = _b[1];
|
|
63
63
|
// const [connectedRaft, setConnectedRaft] = useState<RAFT | undefined>(connectedRAFT_);
|
|
64
64
|
var _c = useState(-200), RSSI = _c[0], setRSSI = _c[1];
|
|
65
|
+
var _d = useState(false), isActionPending = _d[0], setIsActionPending = _d[1];
|
|
66
|
+
var actionStartedRef = useRef(false);
|
|
65
67
|
var t = useTranslation().t;
|
|
68
|
+
var claimVerificationAction = function () {
|
|
69
|
+
if (actionStartedRef.current)
|
|
70
|
+
return false;
|
|
71
|
+
actionStartedRef.current = true;
|
|
72
|
+
setIsActionPending(true);
|
|
73
|
+
return true;
|
|
74
|
+
};
|
|
66
75
|
useEffect(function () {
|
|
67
76
|
/* Subscribe to the connectedRaft's SIGNAL strength */
|
|
68
77
|
if (!connectedRAFT_)
|
|
@@ -76,6 +85,8 @@ function VerificationModal(_a) {
|
|
|
76
85
|
return __generator(this, function (_a) {
|
|
77
86
|
switch (_a.label) {
|
|
78
87
|
case 0:
|
|
88
|
+
if (!claimVerificationAction())
|
|
89
|
+
return [2 /*return*/];
|
|
79
90
|
// close modal, stop verification process, disconnect, scan again
|
|
80
91
|
modalState.closeModal();
|
|
81
92
|
if (!connectedRAFT_)
|
|
@@ -91,6 +102,8 @@ function VerificationModal(_a) {
|
|
|
91
102
|
return __generator(this, function (_a) {
|
|
92
103
|
switch (_a.label) {
|
|
93
104
|
case 0:
|
|
105
|
+
if (!claimVerificationAction())
|
|
106
|
+
return [2 /*return*/];
|
|
94
107
|
modalState.closeModal();
|
|
95
108
|
return [4 /*yield*/, (connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.stopVerifyingRaft(true))];
|
|
96
109
|
case 1:
|
|
@@ -113,7 +126,7 @@ function VerificationModal(_a) {
|
|
|
113
126
|
/* Verify the connectedRaft once it's connected */
|
|
114
127
|
connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.verifyRaft();
|
|
115
128
|
}, [connectedRAFT_]);
|
|
116
|
-
var contentJSX = _jsxs("div", __assign({ className: "verification-modal-container" }, { children: [_jsxs("div", __assign({ className: "verification-modal-martys-container" }, { children: [_jsxs("div", __assign({ className: "verification-modal-marty-name-row-container" }, { children: [_jsx("p", __assign({ className: "verification-modal-marty-name" }, { children: connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.getFriendlyName() })), _jsx("div", __assign({ className: "verification-modal-marty-signal-container" }, { children: _jsx(RICSignal, { signalStrength: RSSI }) })), _jsx(BluetoothSVG, { fill: MAIN_BLUE })] })), _jsx("p", __assign({ className: "verification-modal-martys-back-hint" }, { children: t("verification_modal_phone.look_on_back", { raftType: connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.type }) })), _jsxs("div", __assign({ className: "verification-modal-led-row-container" }, { children: [_jsx(LEDs, { coloursArr: randomColours, connectedRaft: connectedRAFT_ }), _jsx(SimpleButton, { onClick: onCancel, title: t("verification_modal_phone.no"), borderColour: "red", colour: "white", textColour: "red" }), _jsx(SimpleButton, { onClick: onYes, title: t("connection.yes") })] }))] })), _jsxs("div", __assign({ className: "verification-modal-bottom-btns-container" }, { children: [_jsx("div", { className: "dummy-gap" }), _jsx(SimpleButton, { onClick: onCancel, title: t("connection.cancel") })] }))] }));
|
|
129
|
+
var contentJSX = _jsxs("div", __assign({ className: "verification-modal-container" }, { children: [_jsxs("div", __assign({ className: "verification-modal-martys-container" }, { children: [_jsxs("div", __assign({ className: "verification-modal-marty-name-row-container" }, { children: [_jsx("p", __assign({ className: "verification-modal-marty-name" }, { children: connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.getFriendlyName() })), _jsx("div", __assign({ className: "verification-modal-marty-signal-container" }, { children: _jsx(RICSignal, { signalStrength: RSSI }) })), _jsx(BluetoothSVG, { fill: MAIN_BLUE })] })), _jsx("p", __assign({ className: "verification-modal-martys-back-hint" }, { children: t("verification_modal_phone.look_on_back", { raftType: connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.type }) })), _jsxs("div", __assign({ className: "verification-modal-led-row-container" }, { children: [_jsx(LEDs, { coloursArr: randomColours, connectedRaft: connectedRAFT_ }), _jsx(SimpleButton, { onClick: onCancel, title: t("verification_modal_phone.no"), disabled: isActionPending, borderColour: "red", colour: "white", textColour: "red" }), _jsx(SimpleButton, { onClick: onYes, title: t("connection.yes"), disabled: isActionPending })] }))] })), _jsxs("div", __assign({ className: "verification-modal-bottom-btns-container" }, { children: [_jsx("div", { className: "dummy-gap" }), _jsx(SimpleButton, { onClick: onCancel, title: t("connection.cancel"), disabled: isActionPending })] }))] }));
|
|
117
130
|
return contentJSX;
|
|
118
131
|
}
|
|
119
132
|
export default VerificationModal;
|
|
@@ -55,7 +55,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
55
55
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
56
|
};
|
|
57
57
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
58
|
-
import { Fragment, useEffect, useState } from "react";
|
|
58
|
+
import { Fragment, useEffect, useRef, useState } from "react";
|
|
59
59
|
import "./styles.css";
|
|
60
60
|
import { ReactComponent as BluetoothSVG } from "../../../assets/configuration/bluetooth.svg";
|
|
61
61
|
import { ReactComponent as RefreshSVG } from "../../../assets/refresh.svg";
|
|
@@ -81,6 +81,15 @@ function VerificationModalPhoneApp(_a) {
|
|
|
81
81
|
var _e = useState(false), isLoading = _e[0], setIsLoading = _e[1];
|
|
82
82
|
var _f = useState(isPhoneApp()), isScanning = _f[0], setIsScanning = _f[1];
|
|
83
83
|
var _g = useState(), connectedRaft = _g[0], setConnectedRaft = _g[1];
|
|
84
|
+
var _h = useState(false), isActionPending = _h[0], setIsActionPending = _h[1];
|
|
85
|
+
var actionStartedRef = useRef(false);
|
|
86
|
+
var claimVerificationAction = function () {
|
|
87
|
+
if (actionStartedRef.current)
|
|
88
|
+
return false;
|
|
89
|
+
actionStartedRef.current = true;
|
|
90
|
+
setIsActionPending(true);
|
|
91
|
+
return true;
|
|
92
|
+
};
|
|
84
93
|
useEffect(function () {
|
|
85
94
|
raftDiscoveryFinishedSubscriptionHelper().subscribe(function () { return setIsScanning(false); });
|
|
86
95
|
raftDiscoveryStartedSubscriptionHelper().subscribe(function () { return setIsScanning(true); });
|
|
@@ -108,6 +117,8 @@ function VerificationModalPhoneApp(_a) {
|
|
|
108
117
|
return __generator(this, function (_a) {
|
|
109
118
|
switch (_a.label) {
|
|
110
119
|
case 0:
|
|
120
|
+
if (!claimVerificationAction())
|
|
121
|
+
return [2 /*return*/];
|
|
111
122
|
if (!connectedRaft) return [3 /*break*/, 2];
|
|
112
123
|
return [4 /*yield*/, window.applicationManager.stopVerifyingRaft(connectedRaft.id, false)];
|
|
113
124
|
case 1:
|
|
@@ -128,6 +139,8 @@ function VerificationModalPhoneApp(_a) {
|
|
|
128
139
|
return __generator(this, function (_a) {
|
|
129
140
|
switch (_a.label) {
|
|
130
141
|
case 0:
|
|
142
|
+
if (!claimVerificationAction())
|
|
143
|
+
return [2 /*return*/];
|
|
131
144
|
modalState.closeModalWithoutAnimation();
|
|
132
145
|
if (!connectedRaft) return [3 /*break*/, 2];
|
|
133
146
|
return [4 /*yield*/, window.applicationManager.stopVerifyingRaft(connectedRaft.id, false)];
|
|
@@ -150,6 +163,8 @@ function VerificationModalPhoneApp(_a) {
|
|
|
150
163
|
return __generator(this, function (_a) {
|
|
151
164
|
switch (_a.label) {
|
|
152
165
|
case 0:
|
|
166
|
+
if (!claimVerificationAction())
|
|
167
|
+
return [2 /*return*/];
|
|
153
168
|
modalState.closeModal();
|
|
154
169
|
return [4 /*yield*/, (connectedRaft === null || connectedRaft === void 0 ? void 0 : connectedRaft.stopVerifyingRaft(true))];
|
|
155
170
|
case 1:
|
|
@@ -174,6 +189,8 @@ function VerificationModalPhoneApp(_a) {
|
|
|
174
189
|
return __generator(this, function (_a) {
|
|
175
190
|
switch (_a.label) {
|
|
176
191
|
case 0:
|
|
192
|
+
if (actionStartedRef.current)
|
|
193
|
+
return [2 /*return*/];
|
|
177
194
|
setIsLoading(true);
|
|
178
195
|
if (!connectedRaft) return [3 /*break*/, 2];
|
|
179
196
|
return [4 /*yield*/, window.applicationManager.stopVerifyingRaft(connectedRaft.id, false)];
|
|
@@ -200,12 +217,12 @@ function VerificationModalPhoneApp(_a) {
|
|
|
200
217
|
}); };
|
|
201
218
|
var contentJSX = null;
|
|
202
219
|
if (foundRICsState.length === 0) {
|
|
203
|
-
contentJSX = _jsxs("div", __assign({ className: "verification-modal-container" }, { children: [!isScanning && _jsx("p", __assign({ style: { alignSelf: 'center' } }, { children: t("verification_modal_phone.no_robots_found", "No devices found") })), _jsx("div", __assign({ className: "verification-modal-martys-container" }, { children: isScanning && _jsxs("div", __assign({ style: { margin: "auto", width: "50px", height: "50px" } }, { children: [" ", _jsx(LoadingSpinner, {}), " "] })) })), _jsxs("div", __assign({ className: "verification-modal-bottom-btns-container" }, { children: [_jsx(SVGImageButton, { onClick: onScanAgain, title: t("verification_modal_phone.scan_again", "SCAN AGAIN"), SVGImage: RefreshSVG, backgroundColour: MAIN_BLUE, titleColour: WHITE, SVGColour: WHITE }), _jsx("div", { className: "dummy-gap" }), _jsx(SimpleButton, { onClick: onCancel, title: t("verification_modal_phone.cancel", "CANCEL") })] }))] }));
|
|
220
|
+
contentJSX = _jsxs("div", __assign({ className: "verification-modal-container" }, { children: [!isScanning && _jsx("p", __assign({ style: { alignSelf: 'center' } }, { children: t("verification_modal_phone.no_robots_found", "No devices found") })), _jsx("div", __assign({ className: "verification-modal-martys-container" }, { children: isScanning && _jsxs("div", __assign({ style: { margin: "auto", width: "50px", height: "50px" } }, { children: [" ", _jsx(LoadingSpinner, {}), " "] })) })), _jsxs("div", __assign({ className: "verification-modal-bottom-btns-container" }, { children: [_jsx(SVGImageButton, { onClick: onScanAgain, title: t("verification_modal_phone.scan_again", "SCAN AGAIN"), SVGImage: RefreshSVG, backgroundColour: MAIN_BLUE, titleColour: WHITE, SVGColour: WHITE, disabled: isScanning || isActionPending }), _jsx("div", { className: "dummy-gap" }), _jsx(SimpleButton, { onClick: onCancel, title: t("verification_modal_phone.cancel", "CANCEL"), disabled: isActionPending })] }))] }));
|
|
204
221
|
}
|
|
205
222
|
else {
|
|
206
223
|
contentJSX = _jsxs("div", __assign({ className: "verification-modal-container" }, { children: [_jsxs("div", __assign({ className: "verification-modal-martys-container" }, { children: [isScanning && _jsxs("div", __assign({ style: { margin: "auto", width: "50px", height: "50px" } }, { children: [" ", _jsx(LoadingSpinner, {}), " "] })), foundRICsState.map(function (raftObj, raftIdx) {
|
|
207
|
-
return _jsxs(Fragment, { children: [_jsxs("button", __assign({ type: "button", className: "verification-modal-marty-name-row-container", onClick: function () { return onSelectRaft(raftIdx); }, "aria-label": "".concat(t("verification_modal_phone.select_robot", "Select device"), " ").concat(raftObj._localName) }, { children: [_jsx("p", __assign({ className: "verification-modal-marty-name" }, { children: raftObj._localName })), _jsx("div", __assign({ className: "verification-modal-marty-signal-container" }, { children: _jsx(RICSignal, { signalStrength: raftObj._rssi }) })), _jsx(BluetoothSVG, { fill: MAIN_BLUE, "aria-hidden": "true" })] })), selectedRICIdx === raftIdx && _jsxs("div", { children: [_jsx("p", __assign({ className: "verification-modal-martys-back-hint" }, { children: isLoading ? t("verification_modal_phone.loading", "Loading...") : t("verification_modal_phone.look_on_back", { raftType: connectedRaft === null || connectedRaft === void 0 ? void 0 : connectedRaft.type }) })), _jsxs("div", __assign({ className: "verification-modal-led-row-container" }, { children: [_jsx(LEDs, { coloursArr: randomColours, connectedRaft: connectedRaft }), !isLoading && _jsx(SimpleButton, { onClick: onCancel, title: t("verification_modal_phone.no", "No"), borderColour: "red", colour: "white", textColour: "red" }), !isLoading && _jsx(SimpleButton, { onClick: onYes, title: t("connection.yes") })] }))] })] }, raftIdx);
|
|
208
|
-
})] })), _jsxs("div", __assign({ className: "verification-modal-bottom-btns-container" }, { children: [_jsx(SVGImageButton, { onClick: onScanAgain, title: t("connection.scan_again"), SVGImage: RefreshSVG, backgroundColour: MAIN_BLUE, titleColour: WHITE, SVGColour: WHITE, disabled: isScanning }), _jsx("div", { className: "dummy-gap" }), _jsx(SimpleButton, { onClick: onCancel, title: t("connection.cancel") })] }))] }));
|
|
224
|
+
return _jsxs(Fragment, { children: [_jsxs("button", __assign({ type: "button", className: "verification-modal-marty-name-row-container", onClick: function () { return onSelectRaft(raftIdx); }, "aria-label": "".concat(t("verification_modal_phone.select_robot", "Select device"), " ").concat(raftObj._localName), disabled: isActionPending || isLoading }, { children: [_jsx("p", __assign({ className: "verification-modal-marty-name" }, { children: raftObj._localName })), _jsx("div", __assign({ className: "verification-modal-marty-signal-container" }, { children: _jsx(RICSignal, { signalStrength: raftObj._rssi }) })), _jsx(BluetoothSVG, { fill: MAIN_BLUE, "aria-hidden": "true" })] })), selectedRICIdx === raftIdx && _jsxs("div", { children: [_jsx("p", __assign({ className: "verification-modal-martys-back-hint" }, { children: isLoading ? t("verification_modal_phone.loading", "Loading...") : t("verification_modal_phone.look_on_back", { raftType: connectedRaft === null || connectedRaft === void 0 ? void 0 : connectedRaft.type }) })), _jsxs("div", __assign({ className: "verification-modal-led-row-container" }, { children: [_jsx(LEDs, { coloursArr: randomColours, connectedRaft: connectedRaft }), !isLoading && _jsx(SimpleButton, { onClick: onCancel, title: t("verification_modal_phone.no", "No"), disabled: isActionPending, borderColour: "red", colour: "white", textColour: "red" }), !isLoading && _jsx(SimpleButton, { onClick: onYes, title: t("connection.yes"), disabled: isActionPending })] }))] })] }, raftIdx);
|
|
225
|
+
})] })), _jsxs("div", __assign({ className: "verification-modal-bottom-btns-container" }, { children: [_jsx(SVGImageButton, { onClick: onScanAgain, title: t("connection.scan_again"), SVGImage: RefreshSVG, backgroundColour: MAIN_BLUE, titleColour: WHITE, SVGColour: WHITE, disabled: isScanning || isActionPending }), _jsx("div", { className: "dummy-gap" }), _jsx(SimpleButton, { onClick: onCancel, title: t("connection.cancel"), disabled: isActionPending })] }))] }));
|
|
209
226
|
}
|
|
210
227
|
return contentJSX;
|
|
211
228
|
}
|
|
@@ -8,6 +8,7 @@ export type ConnectedRaftItem = {
|
|
|
8
8
|
type: RaftTypeE;
|
|
9
9
|
isSelected: boolean;
|
|
10
10
|
};
|
|
11
|
+
export declare const removeConnectedRaftFromList: (connectedRafts: ConnectedRaftItem[], connectedRaftId: string) => ConnectedRaftItem[];
|
|
11
12
|
export declare const ConnectedRaftContentProvider: ({ children }: {
|
|
12
13
|
children: React.ReactNode;
|
|
13
14
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -25,6 +25,18 @@ export var NewRobotIdE;
|
|
|
25
25
|
(function (NewRobotIdE) {
|
|
26
26
|
NewRobotIdE["NEW"] = "=+__new__+=";
|
|
27
27
|
})(NewRobotIdE || (NewRobotIdE = {}));
|
|
28
|
+
export var removeConnectedRaftFromList = function (connectedRafts, connectedRaftId) {
|
|
29
|
+
var removedRaftWasSelected = connectedRafts.some(function (connectedRaft) {
|
|
30
|
+
return connectedRaft.id === connectedRaftId && connectedRaft.isSelected;
|
|
31
|
+
});
|
|
32
|
+
var remainingRafts = connectedRafts.filter(function (connectedRaft) { return connectedRaft.id !== connectedRaftId; });
|
|
33
|
+
if (!removedRaftWasSelected) {
|
|
34
|
+
return remainingRafts;
|
|
35
|
+
}
|
|
36
|
+
var fallbackRaft = remainingRafts.find(function (connectedRaft) { return connectedRaft.id !== NewRobotIdE.NEW; }) ||
|
|
37
|
+
remainingRafts[0];
|
|
38
|
+
return remainingRafts.map(function (connectedRaft) { return (__assign(__assign({}, connectedRaft), { isSelected: connectedRaft.id === (fallbackRaft === null || fallbackRaft === void 0 ? void 0 : fallbackRaft.id) })); });
|
|
39
|
+
};
|
|
28
40
|
var ConnectedRaftContext = createContext({
|
|
29
41
|
nameUpdatedState: 0,
|
|
30
42
|
connectedRafts: [],
|
|
@@ -59,17 +71,9 @@ export var ConnectedRaftContentProvider = function (_a) {
|
|
|
59
71
|
setConnectedRafts(function (prev) { return __spreadArray(__spreadArray([], prev, true), [connectedRaft], false); });
|
|
60
72
|
};
|
|
61
73
|
var removeConnectedRaft = function (connectedRaftId) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
setConnectedRafts(function (prev) { return prev
|
|
66
|
-
.filter(function (connectedRaft) { return connectedRaft.id !== connectedRaftId; })
|
|
67
|
-
.map(function (connectedRaft, index) { return (__assign(__assign({}, connectedRaft), { isSelected: index === 1 })); }); });
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
// otherwise just filter out the raft
|
|
71
|
-
setConnectedRafts(function (prev) { return prev.filter(function (connectedRaft) { return connectedRaft.id !== connectedRaftId; }); });
|
|
72
|
-
}
|
|
74
|
+
setConnectedRafts(function (prev) {
|
|
75
|
+
return removeConnectedRaftFromList(prev, connectedRaftId);
|
|
76
|
+
});
|
|
73
77
|
};
|
|
74
78
|
var setSelectedRaft = function (connectedRaftId) {
|
|
75
79
|
// deselect the previously selected raft
|
|
@@ -95,7 +99,7 @@ export var ConnectedRaftContentProvider = function (_a) {
|
|
|
95
99
|
}
|
|
96
100
|
tryAttach();
|
|
97
101
|
return function () { handle && clearTimeout(handle); };
|
|
98
|
-
}, [addConnectedRaft, removeConnectedRaft, setSelectedRaft, nameUpdated]);
|
|
102
|
+
}, [addConnectedRaft, removeConnectedRaft, getSelectedRaft, setSelectedRaft, nameUpdated]);
|
|
99
103
|
return (_jsx(ConnectedRaftContext.Provider, __assign({ value: { connectedRafts: connectedRafts, addConnectedRaft: addConnectedRaft, removeConnectedRaft: removeConnectedRaft, setSelectedRaft: setSelectedRaft, getSelectedRaft: getSelectedRaft, nameUpdated: nameUpdated, nameUpdatedState: nameUpdatedState } }, { children: children })));
|
|
100
104
|
};
|
|
101
105
|
export var useConnectedRafts = function () { return useContext(ConnectedRaftContext); };
|
|
@@ -273,9 +273,10 @@ var WrapperAppManager = /** @class */ (function () {
|
|
|
273
273
|
* Re-triggers the connect event which was missed due to the connection logic
|
|
274
274
|
*/
|
|
275
275
|
WrapperAppManager.prototype.getMissedConnEvent = function (raftId) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
276
|
+
var connector = this.connectors[raftId];
|
|
277
|
+
if (connector === null || connector === void 0 ? void 0 : connector.shouldHandleEvent("conn", RaftConnEvent.CONN_CONNECTED)) {
|
|
278
|
+
connector.eventHandler("conn", RaftConnEvent.CONN_CONNECTED, "connect", {});
|
|
279
|
+
connector.publish("conn", RaftConnEvent.CONN_CONNECTED, "connect", {});
|
|
279
280
|
}
|
|
280
281
|
};
|
|
281
282
|
/**
|
|
@@ -283,6 +284,7 @@ var WrapperAppManager = /** @class */ (function () {
|
|
|
283
284
|
*/
|
|
284
285
|
WrapperAppManager.prototype.confirmVerifiedRaft = function (raftId) {
|
|
285
286
|
return __awaiter(this, void 0, void 0, function () {
|
|
287
|
+
var connector;
|
|
286
288
|
return __generator(this, function (_a) {
|
|
287
289
|
switch (_a.label) {
|
|
288
290
|
case 0:
|
|
@@ -290,10 +292,14 @@ var WrapperAppManager = /** @class */ (function () {
|
|
|
290
292
|
Logger.warn(SHOW_LOGS, TAG, "confirmVerifiedRaft: No connector found for raftId: ".concat(raftId));
|
|
291
293
|
return [2 /*return*/, false];
|
|
292
294
|
}
|
|
293
|
-
|
|
295
|
+
connector = this.connectors[raftId];
|
|
296
|
+
if (!connector.shouldHandleEvent("conn", RaftConnEvent.CONN_VERIFIED_CORRECT)) {
|
|
297
|
+
return [2 /*return*/, false];
|
|
298
|
+
}
|
|
299
|
+
return [4 /*yield*/, connector.eventHandler("conn", RaftConnEvent.CONN_VERIFIED_CORRECT, "VERIFIED_CORRECT", {})];
|
|
294
300
|
case 1:
|
|
295
301
|
_a.sent();
|
|
296
|
-
|
|
302
|
+
connector.publish("conn", RaftConnEvent.CONN_VERIFIED_CORRECT, "VERIFIED_CORRECT", {});
|
|
297
303
|
return [2 /*return*/, true];
|
|
298
304
|
}
|
|
299
305
|
});
|
|
@@ -378,6 +384,7 @@ var WrapperAppManager = /** @class */ (function () {
|
|
|
378
384
|
if ((inFlightDisconnect === null || inFlightDisconnect === void 0 ? void 0 : inFlightDisconnect.connector) === connector) {
|
|
379
385
|
return inFlightDisconnect.promise;
|
|
380
386
|
}
|
|
387
|
+
connector.beginDisconnect();
|
|
381
388
|
var operation = Promise.resolve().then(function () { return connector.disconnect(); });
|
|
382
389
|
var disconnectPromise;
|
|
383
390
|
disconnectPromise = operation.finally(function () {
|
|
@@ -12,6 +12,7 @@ declare class Connector implements ConnectorInterface {
|
|
|
12
12
|
[key: string]: Array<RaftObserver>;
|
|
13
13
|
};
|
|
14
14
|
private _onDisconnected?;
|
|
15
|
+
private _disconnectStarted;
|
|
15
16
|
connManager: ConnManager;
|
|
16
17
|
constructor(id: string, connManager: ConnManager);
|
|
17
18
|
/**
|
|
@@ -38,6 +39,17 @@ declare class Connector implements ConnectorInterface {
|
|
|
38
39
|
* Disconnect from a RAFT
|
|
39
40
|
*/
|
|
40
41
|
disconnect(): Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Marks this connector as teardown-owned before asynchronous disconnect work
|
|
44
|
+
* can yield. Late nonterminal callbacks must not revive application state or
|
|
45
|
+
* install listeners while the connector is going away.
|
|
46
|
+
*/
|
|
47
|
+
beginDisconnect(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Rejection and disconnection are terminal lifecycle notifications and must
|
|
50
|
+
* still propagate while teardown is pending. All other late events are stale.
|
|
51
|
+
*/
|
|
52
|
+
shouldHandleEvent(eventType: string, eventEnum: RaftConnEvent | RaftUpdateEvent | RaftPublishEvent): boolean;
|
|
41
53
|
/**
|
|
42
54
|
* Register the manager-owned cleanup callback for a terminal disconnect event.
|
|
43
55
|
*/
|
|
@@ -60,11 +60,16 @@ var Connector = /** @class */ (function () {
|
|
|
60
60
|
// RAFT
|
|
61
61
|
// Observers
|
|
62
62
|
this._observers = {};
|
|
63
|
+
this._disconnectStarted = false;
|
|
63
64
|
this.connManager = connManager;
|
|
64
65
|
// Set the listener function
|
|
65
66
|
// Subscribe to connManager events
|
|
66
67
|
this.connManager.setConnectionEventListener(function (eventType, eventEnum, eventName, eventData) {
|
|
67
68
|
var _a;
|
|
69
|
+
if (!_this.shouldHandleEvent(eventType, eventEnum)) {
|
|
70
|
+
Logger.info(SHOW_LOGS, TAG, "Ignoring ".concat(eventName, " after disconnect started for ").concat(_this.id));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
68
73
|
if (eventType === "pub") {
|
|
69
74
|
// if it's a pub event, we are publishing it from _pubEventHandler method (in child classes)
|
|
70
75
|
}
|
|
@@ -151,9 +156,10 @@ var Connector = /** @class */ (function () {
|
|
|
151
156
|
return __awaiter(this, void 0, void 0, function () {
|
|
152
157
|
return __generator(this, function (_a) {
|
|
153
158
|
switch (_a.label) {
|
|
154
|
-
case 0:
|
|
155
|
-
|
|
156
|
-
|
|
159
|
+
case 0:
|
|
160
|
+
this.beginDisconnect();
|
|
161
|
+
// this.sendRestMessage('blerestart');
|
|
162
|
+
return [4 /*yield*/, this.connManager.disconnect()];
|
|
157
163
|
case 1:
|
|
158
164
|
// this.sendRestMessage('blerestart');
|
|
159
165
|
_a.sent();
|
|
@@ -162,6 +168,25 @@ var Connector = /** @class */ (function () {
|
|
|
162
168
|
});
|
|
163
169
|
});
|
|
164
170
|
};
|
|
171
|
+
/**
|
|
172
|
+
* Marks this connector as teardown-owned before asynchronous disconnect work
|
|
173
|
+
* can yield. Late nonterminal callbacks must not revive application state or
|
|
174
|
+
* install listeners while the connector is going away.
|
|
175
|
+
*/
|
|
176
|
+
Connector.prototype.beginDisconnect = function () {
|
|
177
|
+
this._disconnectStarted = true;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Rejection and disconnection are terminal lifecycle notifications and must
|
|
181
|
+
* still propagate while teardown is pending. All other late events are stale.
|
|
182
|
+
*/
|
|
183
|
+
Connector.prototype.shouldHandleEvent = function (eventType, eventEnum) {
|
|
184
|
+
if (!this._disconnectStarted) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
return eventType === "conn" && (eventEnum === RaftConnEvent.CONN_REJECTED ||
|
|
188
|
+
eventEnum === RaftConnEvent.CONN_DISCONNECTED);
|
|
189
|
+
};
|
|
165
190
|
/**
|
|
166
191
|
* Register the manager-owned cleanup callback for a terminal disconnect event.
|
|
167
192
|
*/
|
|
@@ -175,6 +200,7 @@ var Connector = /** @class */ (function () {
|
|
|
175
200
|
* RoboticalJS package while the new ConnManager API is being released.
|
|
176
201
|
*/
|
|
177
202
|
Connector.prototype.disconnectForPageUnload = function () {
|
|
203
|
+
this.beginDisconnect();
|
|
178
204
|
var connManagerWithPageUnload = this.connManager;
|
|
179
205
|
if (typeof connManagerWithPageUnload.disconnectForPageUnload === "function") {
|
|
180
206
|
connManagerWithPageUnload.disconnectForPageUnload();
|