@robotical/webapp-types 3.18.13 → 3.19.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/dist-types/src/application/ApplicationManager/ApplicationManager.d.ts +21 -10
- package/dist-types/src/application/ApplicationManager/ApplicationManager.js +297 -83
- package/dist-types/src/application/RAFTs/Cog/Cog.d.ts +2 -0
- package/dist-types/src/application/RAFTs/Cog/Cog.js +3 -0
- package/dist-types/src/application/RAFTs/Marty/Marty.js +7 -3
- package/dist-types/src/application/RAFTs/Marty/MartyWifiManager.d.ts +6 -18
- package/dist-types/src/application/RAFTs/Marty/MartyWifiManager.js +25 -274
- package/dist-types/src/application/RAFTs/RAFT.d.ts +8 -2
- package/dist-types/src/application/RAFTs/RAFT.js +23 -4
- package/dist-types/src/application/RAFTs/RaftWifiManager.d.ts +24 -0
- package/dist-types/src/application/RAFTs/RaftWifiManager.js +329 -0
- package/dist-types/src/application/communicators/WrapperCommunicator.js +7 -3
- package/dist-types/src/components/modals/VerificationModal/index.js +4 -1
- package/dist-types/src/components/modals/WifiConnectionModal/index.d.ts +6 -0
- package/dist-types/src/components/modals/WifiConnectionModal/index.js +41 -0
- package/dist-types/src/i18n.js +43 -3
- package/dist-types/src/store/ConnectionMethodPreference.d.ts +7 -0
- package/dist-types/src/store/ConnectionMethodPreference.js +44 -0
- package/dist-types/src/store/SelectedRaftContext.d.ts +3 -1
- package/dist-types/src/store/SelectedRaftContext.js +1 -1
- package/dist-types/src/types/raft.d.ts +23 -0
- package/dist-types/src/utils/helpers/wifi-configuration-subtitle-gen.d.ts +2 -1
- package/dist-types/src/utils/helpers/wifi-configuration-subtitle-gen.js +26 -22
- package/dist-types/src/utils/wifi-connection.d.ts +18 -0
- package/dist-types/src/utils/wifi-connection.js +97 -0
- package/dist-types/src/wrapper-app/WrapperAppManager.d.ts +3 -2
- package/dist-types/src/wrapper-app/WrapperAppManager.js +149 -45
- package/dist-types/src/wrapper-app/communicators/WebAppCommunicator.js +1 -1
- package/dist-types/src/wrapper-app/connectors/ConnectorFactory.d.ts +1 -0
- package/dist-types/src/wrapper-app/connectors/ConnectorFactory.js +15 -11
- package/package.json +1 -1
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { RaftWifiConnState, RaftWifiConnStatus, } from "@robdobsn/raftjs";
|
|
38
|
+
import Logger from "../../services/logger/Logger";
|
|
39
|
+
var SHOW_LOGS = true;
|
|
40
|
+
var TAG = "RaftWifiManager";
|
|
41
|
+
var flagIsSet = function (value) {
|
|
42
|
+
return value === true ||
|
|
43
|
+
value === 1 ||
|
|
44
|
+
value === "1" ||
|
|
45
|
+
(typeof value === "string" && value.toLowerCase() === "true");
|
|
46
|
+
};
|
|
47
|
+
var responseSucceeded = function (response) {
|
|
48
|
+
return !!response &&
|
|
49
|
+
typeof response === "object" &&
|
|
50
|
+
"rslt" in response &&
|
|
51
|
+
String(response.rslt).toLowerCase() === "ok";
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Wi-Fi provisioning is implemented by the common RAFT NetMan endpoints, so
|
|
55
|
+
* it is shared by Marty and Cog. The manager deliberately owns no transport:
|
|
56
|
+
* commands continue over the RAFT's current BLE or WebSocket connection.
|
|
57
|
+
*/
|
|
58
|
+
var RaftWifiManager = /** @class */ (function () {
|
|
59
|
+
function RaftWifiManager(raft, _defaultWiFiHostname) {
|
|
60
|
+
if (_defaultWiFiHostname === void 0) { _defaultWiFiHostname = "Raft"; }
|
|
61
|
+
this.raft = raft;
|
|
62
|
+
this._defaultWiFiHostname = _defaultWiFiHostname;
|
|
63
|
+
this._wifiConnStatus = new RaftWifiConnStatus();
|
|
64
|
+
this._maxSecsToWaitForWiFiConn = 20;
|
|
65
|
+
this._wifiScanDuration = 10000;
|
|
66
|
+
}
|
|
67
|
+
RaftWifiManager.prototype._getHostnameFromFriendlyName = function () {
|
|
68
|
+
var friendlyName = this.raft.getFriendlyName();
|
|
69
|
+
if (!friendlyName) {
|
|
70
|
+
return this._defaultWiFiHostname;
|
|
71
|
+
}
|
|
72
|
+
return friendlyName.replace(/ /g, "-").replace(/\W+/g, "") ||
|
|
73
|
+
this._defaultWiFiHostname;
|
|
74
|
+
};
|
|
75
|
+
RaftWifiManager.prototype.wifiConnect = function (ssid, password) {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
77
|
+
var credentialsCommand, response, error_1, timeoutCount;
|
|
78
|
+
return __generator(this, function (_a) {
|
|
79
|
+
switch (_a.label) {
|
|
80
|
+
case 0:
|
|
81
|
+
Logger.info(SHOW_LOGS, TAG, "Connecting ".concat(this.raft.type, " to Wi-Fi network ").concat(ssid));
|
|
82
|
+
_a.label = 1;
|
|
83
|
+
case 1:
|
|
84
|
+
_a.trys.push([1, 3, , 4]);
|
|
85
|
+
credentialsCommand = [
|
|
86
|
+
"w",
|
|
87
|
+
encodeURIComponent(ssid),
|
|
88
|
+
encodeURIComponent(password),
|
|
89
|
+
encodeURIComponent(this._getHostnameFromFriendlyName()),
|
|
90
|
+
].join("/");
|
|
91
|
+
return [4 /*yield*/, this.raft.sendRestMessage(credentialsCommand)];
|
|
92
|
+
case 2:
|
|
93
|
+
response = _a.sent();
|
|
94
|
+
if (!responseSucceeded(response)) {
|
|
95
|
+
Logger.warn(SHOW_LOGS, TAG, "NetMan rejected Wi-Fi credentials for ".concat(ssid));
|
|
96
|
+
return [2 /*return*/, false];
|
|
97
|
+
}
|
|
98
|
+
return [3 /*break*/, 4];
|
|
99
|
+
case 3:
|
|
100
|
+
error_1 = _a.sent();
|
|
101
|
+
Logger.warn(SHOW_LOGS, TAG, "Failed to send Wi-Fi credentials: ".concat(error_1));
|
|
102
|
+
return [2 /*return*/, false];
|
|
103
|
+
case 4:
|
|
104
|
+
timeoutCount = 0;
|
|
105
|
+
_a.label = 5;
|
|
106
|
+
case 5:
|
|
107
|
+
if (!(timeoutCount < this._maxSecsToWaitForWiFiConn)) return [3 /*break*/, 9];
|
|
108
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 1000); })];
|
|
109
|
+
case 6:
|
|
110
|
+
_a.sent();
|
|
111
|
+
return [4 /*yield*/, this.getWiFiConnStatus()];
|
|
112
|
+
case 7:
|
|
113
|
+
_a.sent();
|
|
114
|
+
if (this._wifiConnStatus.connState ===
|
|
115
|
+
RaftWifiConnState.WIFI_CONN_CONNECTED) {
|
|
116
|
+
return [2 /*return*/, true];
|
|
117
|
+
}
|
|
118
|
+
_a.label = 8;
|
|
119
|
+
case 8:
|
|
120
|
+
timeoutCount++;
|
|
121
|
+
return [3 /*break*/, 5];
|
|
122
|
+
case 9: return [2 /*return*/, false];
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
RaftWifiManager.prototype.wifiDisconnect = function () {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
129
|
+
var response, error_2;
|
|
130
|
+
return __generator(this, function (_a) {
|
|
131
|
+
switch (_a.label) {
|
|
132
|
+
case 0:
|
|
133
|
+
_a.trys.push([0, 5, , 6]);
|
|
134
|
+
return [4 /*yield*/, this.raft.sendRestMessage("wc/norestart")];
|
|
135
|
+
case 1:
|
|
136
|
+
response = _a.sent();
|
|
137
|
+
if (!!responseSucceeded(response)) return [3 /*break*/, 3];
|
|
138
|
+
return [4 /*yield*/, this.raft.sendRestMessage("wc")];
|
|
139
|
+
case 2:
|
|
140
|
+
// Older Marty firmware only implements the original command,
|
|
141
|
+
// which restarts its network manager after clearing credentials.
|
|
142
|
+
response = _a.sent();
|
|
143
|
+
if (!responseSucceeded(response)) {
|
|
144
|
+
return [2 /*return*/, false];
|
|
145
|
+
}
|
|
146
|
+
_a.label = 3;
|
|
147
|
+
case 3: return [4 /*yield*/, this.getWiFiConnStatus()];
|
|
148
|
+
case 4:
|
|
149
|
+
_a.sent();
|
|
150
|
+
return [2 /*return*/, true];
|
|
151
|
+
case 5:
|
|
152
|
+
error_2 = _a.sent();
|
|
153
|
+
Logger.warn(SHOW_LOGS, TAG, "Failed to clear Wi-Fi credentials: ".concat(error_2));
|
|
154
|
+
return [2 /*return*/, false];
|
|
155
|
+
case 6: return [2 /*return*/];
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
RaftWifiManager.prototype.getWiFiConnStatus = function () {
|
|
161
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
162
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
163
|
+
var status_1, station, isConnected, isPaused, error_3;
|
|
164
|
+
return __generator(this, function (_j) {
|
|
165
|
+
switch (_j.label) {
|
|
166
|
+
case 0:
|
|
167
|
+
_j.trys.push([0, 2, , 3]);
|
|
168
|
+
return [4 /*yield*/, this.raft.sendRestMessage("sysmodinfo/NetMan")];
|
|
169
|
+
case 1:
|
|
170
|
+
status_1 = _j.sent();
|
|
171
|
+
if (String(status_1 === null || status_1 === void 0 ? void 0 : status_1.rslt).toLowerCase() !== "ok") {
|
|
172
|
+
throw new Error("NetMan is unavailable");
|
|
173
|
+
}
|
|
174
|
+
station = status_1.wifiSTA;
|
|
175
|
+
isConnected = station
|
|
176
|
+
? flagIsSet(station.conn)
|
|
177
|
+
: flagIsSet(status_1.isConn);
|
|
178
|
+
isPaused = station
|
|
179
|
+
? flagIsSet(station.paused)
|
|
180
|
+
: flagIsSet(status_1.isPaused);
|
|
181
|
+
this._wifiConnStatus.connState = isConnected
|
|
182
|
+
? RaftWifiConnState.WIFI_CONN_CONNECTED
|
|
183
|
+
: RaftWifiConnState.WIFI_CONN_NONE;
|
|
184
|
+
this._wifiConnStatus.isPaused = isPaused;
|
|
185
|
+
this._wifiConnStatus.ipAddress = (_b = (_a = station === null || station === void 0 ? void 0 : station.IP) !== null && _a !== void 0 ? _a : status_1.IP) !== null && _b !== void 0 ? _b : "";
|
|
186
|
+
this._wifiConnStatus.hostname = (_d = (_c = status_1.hostname) !== null && _c !== void 0 ? _c : status_1.Hostname) !== null && _d !== void 0 ? _d : "";
|
|
187
|
+
this._wifiConnStatus.ssid = (_f = (_e = station === null || station === void 0 ? void 0 : station.SSID) !== null && _e !== void 0 ? _e : status_1.SSID) !== null && _f !== void 0 ? _f : "";
|
|
188
|
+
this._wifiConnStatus.bssid = (_h = (_g = station === null || station === void 0 ? void 0 : station.MAC) !== null && _g !== void 0 ? _g : status_1.WiFiMAC) !== null && _h !== void 0 ? _h : "";
|
|
189
|
+
this._wifiConnStatus.validMs = Date.now();
|
|
190
|
+
return [2 /*return*/, isConnected || isPaused];
|
|
191
|
+
case 2:
|
|
192
|
+
error_3 = _j.sent();
|
|
193
|
+
Logger.info(SHOW_LOGS, TAG, "Wi-Fi status is unavailable: ".concat(error_3));
|
|
194
|
+
this._wifiConnStatus = new RaftWifiConnStatus();
|
|
195
|
+
return [2 /*return*/, null];
|
|
196
|
+
case 3: return [2 /*return*/];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
RaftWifiManager.prototype.pauseWifiConnection = function (pause) {
|
|
202
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
203
|
+
var response, statusResult, error_4;
|
|
204
|
+
return __generator(this, function (_a) {
|
|
205
|
+
switch (_a.label) {
|
|
206
|
+
case 0:
|
|
207
|
+
_a.trys.push([0, 4, , 5]);
|
|
208
|
+
return [4 /*yield*/, this.raft.sendRestMessage(pause ? "wifipause/pause" : "wifipause/resume", undefined, { waitForResponse: false })];
|
|
209
|
+
case 1:
|
|
210
|
+
response = _a.sent();
|
|
211
|
+
if (!responseSucceeded(response)) {
|
|
212
|
+
return [2 /*return*/, false];
|
|
213
|
+
}
|
|
214
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 250); })];
|
|
215
|
+
case 2:
|
|
216
|
+
_a.sent();
|
|
217
|
+
return [4 /*yield*/, this.getWiFiConnStatus()];
|
|
218
|
+
case 3:
|
|
219
|
+
statusResult = _a.sent();
|
|
220
|
+
return [2 /*return*/, statusResult !== null &&
|
|
221
|
+
this._wifiConnStatus.isPaused === pause];
|
|
222
|
+
case 4:
|
|
223
|
+
error_4 = _a.sent();
|
|
224
|
+
Logger.warn(SHOW_LOGS, TAG, "Failed to ".concat(pause ? "pause" : "resume", " Wi-Fi: ").concat(error_4));
|
|
225
|
+
return [2 /*return*/, false];
|
|
226
|
+
case 5: return [2 /*return*/];
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
};
|
|
231
|
+
RaftWifiManager.prototype._wifiScanResults = function () {
|
|
232
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
233
|
+
var response, error_5;
|
|
234
|
+
return __generator(this, function (_a) {
|
|
235
|
+
switch (_a.label) {
|
|
236
|
+
case 0:
|
|
237
|
+
_a.trys.push([0, 2, , 3]);
|
|
238
|
+
return [4 /*yield*/, this.raft.sendRestMessage("wifiscan/results")];
|
|
239
|
+
case 1:
|
|
240
|
+
response = _a.sent();
|
|
241
|
+
return [2 /*return*/, response];
|
|
242
|
+
case 2:
|
|
243
|
+
error_5 = _a.sent();
|
|
244
|
+
Logger.warn(SHOW_LOGS, TAG, "Failed to get Wi-Fi scan results: ".concat(error_5));
|
|
245
|
+
return [2 /*return*/, false];
|
|
246
|
+
case 3: return [2 /*return*/];
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
};
|
|
251
|
+
RaftWifiManager.prototype._wifiScanStart = function () {
|
|
252
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
253
|
+
var response, error_6;
|
|
254
|
+
return __generator(this, function (_a) {
|
|
255
|
+
switch (_a.label) {
|
|
256
|
+
case 0:
|
|
257
|
+
_a.trys.push([0, 2, , 3]);
|
|
258
|
+
return [4 /*yield*/, this.raft.sendRestMessage("wifiscan/start")];
|
|
259
|
+
case 1:
|
|
260
|
+
response = _a.sent();
|
|
261
|
+
return [2 /*return*/, responseSucceeded(response)];
|
|
262
|
+
case 2:
|
|
263
|
+
error_6 = _a.sent();
|
|
264
|
+
Logger.warn(SHOW_LOGS, TAG, "Failed to start Wi-Fi scan: ".concat(error_6));
|
|
265
|
+
return [2 /*return*/, false];
|
|
266
|
+
case 3: return [2 /*return*/];
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
};
|
|
271
|
+
RaftWifiManager.prototype.getCachedWifiStatus = function () {
|
|
272
|
+
return this._wifiConnStatus;
|
|
273
|
+
};
|
|
274
|
+
RaftWifiManager.prototype.getWifiScanResults = function () {
|
|
275
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
276
|
+
var statusResult, wasPaused, _a, results;
|
|
277
|
+
var _this = this;
|
|
278
|
+
return __generator(this, function (_b) {
|
|
279
|
+
switch (_b.label) {
|
|
280
|
+
case 0: return [4 /*yield*/, this.getWiFiConnStatus()];
|
|
281
|
+
case 1:
|
|
282
|
+
statusResult = _b.sent();
|
|
283
|
+
if (statusResult === null) {
|
|
284
|
+
return [2 /*return*/, false];
|
|
285
|
+
}
|
|
286
|
+
wasPaused = this._wifiConnStatus.isPaused;
|
|
287
|
+
_b.label = 2;
|
|
288
|
+
case 2:
|
|
289
|
+
_b.trys.push([2, , 8, 11]);
|
|
290
|
+
_a = wasPaused;
|
|
291
|
+
if (!_a) return [3 /*break*/, 4];
|
|
292
|
+
return [4 /*yield*/, this.pauseWifiConnection(false)];
|
|
293
|
+
case 3:
|
|
294
|
+
_a = !(_b.sent());
|
|
295
|
+
_b.label = 4;
|
|
296
|
+
case 4:
|
|
297
|
+
if (_a) {
|
|
298
|
+
return [2 /*return*/, false];
|
|
299
|
+
}
|
|
300
|
+
return [4 /*yield*/, this._wifiScanStart()];
|
|
301
|
+
case 5:
|
|
302
|
+
if (!(_b.sent())) {
|
|
303
|
+
return [2 /*return*/, false];
|
|
304
|
+
}
|
|
305
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, _this._wifiScanDuration); })];
|
|
306
|
+
case 6:
|
|
307
|
+
_b.sent();
|
|
308
|
+
return [4 /*yield*/, this._wifiScanResults()];
|
|
309
|
+
case 7:
|
|
310
|
+
results = _b.sent();
|
|
311
|
+
if (results && "wifi" in results) {
|
|
312
|
+
return [2 /*return*/, results];
|
|
313
|
+
}
|
|
314
|
+
return [2 /*return*/, false];
|
|
315
|
+
case 8:
|
|
316
|
+
if (!wasPaused) return [3 /*break*/, 10];
|
|
317
|
+
return [4 /*yield*/, this.pauseWifiConnection(true)];
|
|
318
|
+
case 9:
|
|
319
|
+
_b.sent();
|
|
320
|
+
_b.label = 10;
|
|
321
|
+
case 10: return [7 /*endfinally*/];
|
|
322
|
+
case 11: return [2 /*return*/];
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
return RaftWifiManager;
|
|
328
|
+
}());
|
|
329
|
+
export { RaftWifiManager };
|
|
@@ -39,6 +39,7 @@ import { AppSentMessage, WrapperSentMessage } from "../../types/communication-be
|
|
|
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";
|
|
42
|
+
import { RaftConnectionMethod } from "../../types/raft";
|
|
42
43
|
var SHOW_LOGS = true;
|
|
43
44
|
var TAG = "WrapperAppCommunicator";
|
|
44
45
|
var WrapperCommunicator = /** @class */ (function () {
|
|
@@ -61,9 +62,12 @@ var WrapperCommunicator = /** @class */ (function () {
|
|
|
61
62
|
var promise = new Promise(function (resolve, reject) {
|
|
62
63
|
_this.messagePromises[messagePromiseId] = new SelfdestructiveMessagePromise(resolve, reject, messagePromiseId, _this.messagePromises,
|
|
63
64
|
// Choosing a physical Bluetooth device is user-mediated and has no
|
|
64
|
-
// application-safe deadline.
|
|
65
|
-
//
|
|
66
|
-
message === AppSentMessage.RAFT_CONNECT
|
|
65
|
+
// application-safe deadline. A direct WebSocket connection is not, so
|
|
66
|
+
// retain the normal bridge timeout if a native wrapper fails to reply.
|
|
67
|
+
message === AppSentMessage.RAFT_CONNECT &&
|
|
68
|
+
(data === null || data === void 0 ? void 0 : data.method) !== RaftConnectionMethod.WEB_SOCKET
|
|
69
|
+
? null
|
|
70
|
+
: undefined);
|
|
67
71
|
});
|
|
68
72
|
var messageObject = {
|
|
69
73
|
message: message,
|
|
@@ -56,6 +56,8 @@ import SimpleButton from "../../disposables/buttons/SimpleButton";
|
|
|
56
56
|
import LEDs from "../../oneoffs/LEDs";
|
|
57
57
|
import { raftConnectingSubscriptionHelper } from "../../../application/RAFTs/raft-subscription-helpers";
|
|
58
58
|
import { useTranslation } from "react-i18next";
|
|
59
|
+
import { FaWifi } from "react-icons/fa";
|
|
60
|
+
import { RaftConnectionMethod } from "../../../types/raft";
|
|
59
61
|
function VerificationModal(_a) {
|
|
60
62
|
var _this = this;
|
|
61
63
|
var connectedRAFT_ = _a.connectedRAFT_;
|
|
@@ -65,6 +67,7 @@ function VerificationModal(_a) {
|
|
|
65
67
|
var _d = useState(false), isActionPending = _d[0], setIsActionPending = _d[1];
|
|
66
68
|
var actionStartedRef = useRef(false);
|
|
67
69
|
var t = useTranslation().t;
|
|
70
|
+
var isWifiConnection = (connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.connectionMethod) === RaftConnectionMethod.WEB_SOCKET;
|
|
68
71
|
var claimVerificationAction = function () {
|
|
69
72
|
if (actionStartedRef.current)
|
|
70
73
|
return false;
|
|
@@ -126,7 +129,7 @@ function VerificationModal(_a) {
|
|
|
126
129
|
/* Verify the connectedRaft once it's connected */
|
|
127
130
|
connectedRAFT_ === null || connectedRAFT_ === void 0 ? void 0 : connectedRAFT_.verifyRaft();
|
|
128
131
|
}, [connectedRAFT_]);
|
|
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 })] }))] }));
|
|
132
|
+
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 }) })), isWifiConnection ? (_jsx(FaWifi, { className: "verification-modal-transport-icon", color: MAIN_BLUE, "aria-label": String(t("connection.wifi_title", "Wi-Fi")) })) : (_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 })] }))] }));
|
|
130
133
|
return contentJSX;
|
|
131
134
|
}
|
|
132
135
|
export default VerificationModal;
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { useState } from "react";
|
|
14
|
+
import { useTranslation } from "react-i18next";
|
|
15
|
+
import modalState from "../../../state-observables/modal/ModalState";
|
|
16
|
+
import { RaftTypeE } from "../../../types/raft";
|
|
17
|
+
import { normalizeWifiLocator } from "../../../utils/wifi-connection";
|
|
18
|
+
import styles from "./styles.module.css";
|
|
19
|
+
var MARTY_WIFI_GUIDE_URL = "https://userguides.robotical.io/martyv2/userguides/marty/wifi?s[]=wifi";
|
|
20
|
+
export default function WifiConnectionModal(_a) {
|
|
21
|
+
var raftType = _a.raftType;
|
|
22
|
+
var t = useTranslation().t;
|
|
23
|
+
var _b = useState(""), endpoint = _b[0], setEndpoint = _b[1];
|
|
24
|
+
var _c = useState(""), error = _c[0], setError = _c[1];
|
|
25
|
+
var submit = function (event) {
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
try {
|
|
28
|
+
var locator = normalizeWifiLocator(endpoint, raftType);
|
|
29
|
+
modalState.closeModalWithoutAnimation(locator);
|
|
30
|
+
}
|
|
31
|
+
catch (normalizationError) {
|
|
32
|
+
setError(normalizationError instanceof Error
|
|
33
|
+
? normalizationError.message
|
|
34
|
+
: String(t("connection.wifi_invalid_endpoint", "Enter a valid IP address or hostname.")));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return (_jsxs("form", __assign({ className: styles.container, onSubmit: submit }, { children: [_jsx("p", __assign({ className: styles.description }, { children: t("connection.wifi_endpoint_prompt", "Enter the IP address or hostname shown in your device's Wi-Fi settings.") })), raftType === RaftTypeE.MARTY && (_jsxs("p", __assign({ className: styles.guide }, { children: [t("connection.wifi_marty_guide_prompt", "Need help connecting Marty to Wi-Fi?"), " ", _jsx("a", __assign({ className: styles.guideLink, href: MARTY_WIFI_GUIDE_URL, target: "_blank", rel: "noopener noreferrer" }, { children: t("connection.wifi_marty_guide_link", "View the step-by-step guide.") }))] }))), _jsx("label", __assign({ className: styles.label, htmlFor: "wifi-robot-endpoint" }, { children: t("connection.wifi_endpoint_label", "IP address or hostname") })), _jsx("input", { id: "wifi-robot-endpoint", className: styles.input, type: "text", value: endpoint, onChange: function (event) {
|
|
38
|
+
setEndpoint(event.target.value);
|
|
39
|
+
setError("");
|
|
40
|
+
}, autoCapitalize: "none", autoCorrect: "off", spellCheck: false, inputMode: "url", placeholder: String(t("connection.wifi_endpoint_placeholder", "192.168.1.42 or marty.local")), autoFocus: true }), error && (_jsx("p", __assign({ className: styles.error, role: "alert" }, { children: error }))), _jsxs("div", __assign({ className: styles.actions }, { children: [_jsx("button", __assign({ type: "button", className: styles.cancelButton, onClick: function () { return modalState.closeModalWithoutAnimation(false); } }, { children: t("connection.cancel") })), _jsx("button", __assign({ type: "submit", className: styles.connectButton }, { children: t("connection.wifi_connect", "Connect over Wi-Fi") }))] }))] })));
|
|
41
|
+
}
|
package/dist-types/src/i18n.js
CHANGED
|
@@ -244,13 +244,22 @@ var resources = {
|
|
|
244
244
|
"choose_robot_cta": "Choose device to connect",
|
|
245
245
|
"choose_robot_prompt": "Choose the device you want to connect.",
|
|
246
246
|
"choose_robot_title": "Choose a Device",
|
|
247
|
+
"choose_transport_prompt": "Choose how you want to connect to your device.",
|
|
248
|
+
"choose_transport_title": "Choose a Connection",
|
|
249
|
+
"bluetooth_title": "Bluetooth",
|
|
250
|
+
"bluetooth_subtitle": "Choose a nearby device using Bluetooth.",
|
|
247
251
|
"cog_verification_prompt": "Choose how you want to verify your Cog connection.",
|
|
252
|
+
"cog_bluetooth_only": "Cog always connects using Bluetooth.",
|
|
253
|
+
"cog_wifi_unsupported": "Cog does not support Wi-Fi. Connect using Bluetooth instead.",
|
|
248
254
|
"connect_another_robot": "Connect another device",
|
|
249
255
|
"connect_cog": "Connect Cog",
|
|
250
|
-
"connect_cog_subtitle": "
|
|
256
|
+
"connect_cog_subtitle": "Connect using Bluetooth.",
|
|
257
|
+
"connect_device": "Connect a device",
|
|
258
|
+
"connect_device_using_method": "Connect a device using {{method}}",
|
|
251
259
|
"connect_marty": "Connect Marty",
|
|
252
260
|
"connect_marty_instead": "Connect Marty instead",
|
|
253
|
-
"connect_marty_subtitle": "Connect using Bluetooth.",
|
|
261
|
+
"connect_marty_subtitle": "Connect using Bluetooth or Wi-Fi.",
|
|
262
|
+
"connect_using_method": "Connect using {{method}}.",
|
|
254
263
|
"connecting_to": "Connecting to",
|
|
255
264
|
"connecting_loading": "This shouldn't take long!",
|
|
256
265
|
"connecting_msg": "Connecting...",
|
|
@@ -266,6 +275,22 @@ var resources = {
|
|
|
266
275
|
"switch_to_front_camera": "Switch to front camera",
|
|
267
276
|
"switch_to_rear_camera": "Switch to rear camera",
|
|
268
277
|
"verification_method": "Verification Method",
|
|
278
|
+
"wait_for_disconnect": "Please wait for the current device disconnect to finish.",
|
|
279
|
+
"wifi_connect": "Connect over Wi-Fi",
|
|
280
|
+
"wifi_connect_failed": "Couldn't connect over Wi-Fi. Check the address, local-network permission, and that the device is online.",
|
|
281
|
+
"wifi_already_connected": "This Wi-Fi device is already connected or connecting.",
|
|
282
|
+
"wifi_connection_title": "Connect over Wi-Fi",
|
|
283
|
+
"wifi_endpoint_label": "IP address or hostname",
|
|
284
|
+
"wifi_endpoint_placeholder": "192.168.1.42 or marty.local",
|
|
285
|
+
"wifi_endpoint_prompt": "Enter the IP address or hostname shown in your device's Wi-Fi settings.",
|
|
286
|
+
"wifi_invalid_endpoint": "Enter a valid IP address or hostname.",
|
|
287
|
+
"wifi_marty_guide_link": "View the step-by-step guide.",
|
|
288
|
+
"wifi_marty_guide_prompt": "Need help connecting Marty to Wi-Fi?",
|
|
289
|
+
"wifi_robot_type_required": "Choose Marty or Cog before connecting over Wi-Fi.",
|
|
290
|
+
"wifi_subtitle": "Connect to a device on the same local network.",
|
|
291
|
+
"wifi_title": "Wi-Fi",
|
|
292
|
+
"wifi_wrong_robot_type": "The address belongs to a {{actualType}}, not a {{expectedType}}.",
|
|
293
|
+
"wifi_wrong_robot_type_generic": "The address belongs to a different kind of device.",
|
|
269
294
|
"yes": "Yes"
|
|
270
295
|
},
|
|
271
296
|
"detailed_feedback_modal": {
|
|
@@ -342,11 +367,26 @@ var resources = {
|
|
|
342
367
|
"games": "Cog Games",
|
|
343
368
|
"sensors": "Sensor Dashboard"
|
|
344
369
|
},
|
|
370
|
+
"layout": {
|
|
371
|
+
"app_settings": "App settings",
|
|
372
|
+
"content_visibility": "Visible content",
|
|
373
|
+
"language_selector": "App language",
|
|
374
|
+
"marty_connection_method": "Marty connection method",
|
|
375
|
+
"primary_navigation": "Primary navigation",
|
|
376
|
+
"skip_to_main_content": "Skip to main content"
|
|
377
|
+
},
|
|
345
378
|
"nav": {
|
|
346
379
|
"activities": "Activities",
|
|
380
|
+
"choose_robot_settings_prompt": "Choose a connected robot to configure.",
|
|
381
|
+
"choose_robot_settings_title": "Choose Robot Settings",
|
|
382
|
+
"currently_selected_robot": "Currently selected",
|
|
347
383
|
"games": "Cog Games",
|
|
348
384
|
"home": "Home",
|
|
349
|
-
"
|
|
385
|
+
"open_robot_settings_for": "Open robot settings for {{name}}",
|
|
386
|
+
"robot_settings_unavailable": "Connect a device to access robot settings",
|
|
387
|
+
"robot_settings": "Robot settings",
|
|
388
|
+
"robot_type_cog": "Cog",
|
|
389
|
+
"robot_type_marty": "Marty"
|
|
350
390
|
},
|
|
351
391
|
"report_issue": {
|
|
352
392
|
"app_issue_desc": "Report an application issue.",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare enum ConnectionMethodPreference {
|
|
2
|
+
BLUETOOTH = "bluetooth",
|
|
3
|
+
WIFI = "wifi"
|
|
4
|
+
}
|
|
5
|
+
export declare const getConnectionMethodPreference: () => ConnectionMethodPreference;
|
|
6
|
+
export declare const setConnectionMethodPreference: (method: ConnectionMethodPreference) => void;
|
|
7
|
+
export declare const useConnectionMethodPreference: () => readonly [ConnectionMethodPreference, (nextMethod: ConnectionMethodPreference) => void];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
export var ConnectionMethodPreference;
|
|
3
|
+
(function (ConnectionMethodPreference) {
|
|
4
|
+
ConnectionMethodPreference["BLUETOOTH"] = "bluetooth";
|
|
5
|
+
ConnectionMethodPreference["WIFI"] = "wifi";
|
|
6
|
+
})(ConnectionMethodPreference || (ConnectionMethodPreference = {}));
|
|
7
|
+
var STORAGE_KEY = "connection.preferredMethod";
|
|
8
|
+
var CHANGE_EVENT = "robotical:connection-method-change";
|
|
9
|
+
export var getConnectionMethodPreference = function () {
|
|
10
|
+
try {
|
|
11
|
+
return window.localStorage.getItem(STORAGE_KEY) === ConnectionMethodPreference.WIFI
|
|
12
|
+
? ConnectionMethodPreference.WIFI
|
|
13
|
+
: ConnectionMethodPreference.BLUETOOTH;
|
|
14
|
+
}
|
|
15
|
+
catch (_a) {
|
|
16
|
+
return ConnectionMethodPreference.BLUETOOTH;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export var setConnectionMethodPreference = function (method) {
|
|
20
|
+
try {
|
|
21
|
+
window.localStorage.setItem(STORAGE_KEY, method);
|
|
22
|
+
}
|
|
23
|
+
catch (_a) {
|
|
24
|
+
// Keep the current in-memory component state when storage is unavailable.
|
|
25
|
+
}
|
|
26
|
+
window.dispatchEvent(new CustomEvent(CHANGE_EVENT, { detail: method }));
|
|
27
|
+
};
|
|
28
|
+
export var useConnectionMethodPreference = function () {
|
|
29
|
+
var _a = useState(getConnectionMethodPreference), method = _a[0], setMethodState = _a[1];
|
|
30
|
+
useEffect(function () {
|
|
31
|
+
var syncMethod = function () { return setMethodState(getConnectionMethodPreference()); };
|
|
32
|
+
window.addEventListener(CHANGE_EVENT, syncMethod);
|
|
33
|
+
window.addEventListener("storage", syncMethod);
|
|
34
|
+
return function () {
|
|
35
|
+
window.removeEventListener(CHANGE_EVENT, syncMethod);
|
|
36
|
+
window.removeEventListener("storage", syncMethod);
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
var setMethod = useCallback(function (nextMethod) {
|
|
40
|
+
setMethodState(nextMethod);
|
|
41
|
+
setConnectionMethodPreference(nextMethod);
|
|
42
|
+
}, []);
|
|
43
|
+
return [method, setMethod];
|
|
44
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RaftTypeE } from '../types/raft';
|
|
1
|
+
import { RaftConnectionMethod, RaftTypeE } from '../types/raft';
|
|
2
2
|
export declare enum NewRobotIdE {
|
|
3
3
|
NEW = "=+__new__+="
|
|
4
4
|
}
|
|
@@ -7,6 +7,8 @@ export type ConnectedRaftItem = {
|
|
|
7
7
|
name: string;
|
|
8
8
|
type: RaftTypeE;
|
|
9
9
|
isSelected: boolean;
|
|
10
|
+
connectionMethod?: RaftConnectionMethod | null;
|
|
11
|
+
connectionLocator?: string;
|
|
10
12
|
};
|
|
11
13
|
export declare const removeConnectedRaftFromList: (connectedRafts: ConnectedRaftItem[], connectedRaftId: string) => ConnectedRaftItem[];
|
|
12
14
|
export declare const ConnectedRaftContentProvider: ({ children }: {
|
|
@@ -61,7 +61,7 @@ export var ConnectedRaftContentProvider = function (_a) {
|
|
|
61
61
|
// if the new raft is already in the list, do not add it again, just select it
|
|
62
62
|
var existingRaft = connectedRafts.find(function (connectedRaft_) { return connectedRaft_.id === connectedRaft.id; });
|
|
63
63
|
if (existingRaft) {
|
|
64
|
-
setConnectedRafts(function (prev) { return prev.map(function (connectedRaft_) { return (__assign(__assign({}, connectedRaft_), { isSelected: connectedRaft_.id === connectedRaft.id })); }); });
|
|
64
|
+
setConnectedRafts(function (prev) { return prev.map(function (connectedRaft_) { return (__assign(__assign(__assign({}, connectedRaft_), (connectedRaft_.id === connectedRaft.id ? connectedRaft : {})), { isSelected: connectedRaft_.id === connectedRaft.id })); }); });
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
67
|
// if the newly added raft is selected, deselect the previously selected raft
|
|
@@ -4,6 +4,29 @@ export declare enum RaftConnectionMethod {
|
|
|
4
4
|
WEB_BLE = "WebBLE",
|
|
5
5
|
PHONE_BLE = "PhoneBLE"
|
|
6
6
|
}
|
|
7
|
+
export type ConnectableRaftType = RaftTypeE.MARTY | RaftTypeE.COG;
|
|
8
|
+
/**
|
|
9
|
+
* Optional connection controls for host integrations such as MartyBlocks and
|
|
10
|
+
* Blocks Jr. Omitting `method` uses Marty's connection method selected in App
|
|
11
|
+
* Settings for Marty, while Cog always defaults to Bluetooth.
|
|
12
|
+
*/
|
|
13
|
+
export type RaftConnectOptions = {
|
|
14
|
+
method?: RaftConnectionMethod;
|
|
15
|
+
locator?: string;
|
|
16
|
+
expectedRaftType?: ConnectableRaftType;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Shared browser/native bridge contract for a direct RAFT connection.
|
|
20
|
+
*
|
|
21
|
+
* WebSocket locators are complete ws:// or wss:// URLs. Bluetooth connections
|
|
22
|
+
* use an empty locator because their platform chooser/discovery owns selection.
|
|
23
|
+
*/
|
|
24
|
+
export type RaftConnectRequest = {
|
|
25
|
+
method: RaftConnectionMethod;
|
|
26
|
+
locator: string;
|
|
27
|
+
uuids: string[];
|
|
28
|
+
expectedRaftType?: ConnectableRaftType;
|
|
29
|
+
};
|
|
7
30
|
export type ConnectionAttemptResults = {
|
|
8
31
|
success: boolean;
|
|
9
32
|
reason: 'failed' | 'unplugged' | 'success' | 'no_sys_info' | 'invalid_raft_type';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import RAFT from "../../application/RAFTs/RAFT";
|
|
2
2
|
import { RaftWifiConnStatus } from "@robdobsn/raftjs";
|
|
3
3
|
export declare const FW_VERSION_RSSI_WIFI = "1.2.0";
|
|
4
|
-
export
|
|
4
|
+
export type WifiCapability = "checking" | "supported" | "unsupported";
|
|
5
|
+
export default function wifiConfigSub(raft: RAFT | undefined, cachedStatus: RaftWifiConnStatus | undefined, capability?: WifiCapability): string;
|