neoagent 3.1.1-beta.5 → 3.1.1-beta.7
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/flutter_app/assets/branding/neomail_logo.svg +22 -0
- package/flutter_app/lib/main.dart +2 -0
- package/flutter_app/lib/main_integrations.dart +41 -10
- package/flutter_app/pubspec.lock +40 -0
- package/flutter_app/pubspec.yaml +2 -0
- package/package.json +1 -1
- package/server/admin/login.html +103 -8
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/AssetManifest.bin +1 -1
- package/server/public/assets/AssetManifest.bin.json +1 -1
- package/server/public/assets/NOTICES +48 -0
- package/server/public/assets/assets/branding/neomail_logo.svg +22 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +95850 -89156
- package/server/routes/admin.js +36 -6
- package/server/services/social_reach/channels/x.js +25 -7
- package/server/services/social_reach/platforms.js +1 -1
- package/server/services/social_reach/service.js +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg viewBox="0 0 100 100" width="1024" height="1024" xmlns="http://www.w3.org/2000/svg"><defs>
|
|
2
|
+
<linearGradient id="tile" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
3
|
+
<stop offset="0%" stop-color="#705331"/><stop offset="100%" stop-color="#22564c"/>
|
|
4
|
+
</linearGradient>
|
|
5
|
+
<radialGradient id="shine" cx="26%" cy="14%" r="72%">
|
|
6
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.22"/><stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>
|
|
7
|
+
</radialGradient>
|
|
8
|
+
<radialGradient id="core" cx="38%" cy="32%" r="75%">
|
|
9
|
+
<stop offset="0%" stop-color="#fffdf6"/><stop offset="48%" stop-color="#eee3cc"/><stop offset="100%" stop-color="#b5a888"/>
|
|
10
|
+
</radialGradient>
|
|
11
|
+
<radialGradient id="node" cx="36%" cy="30%" r="80%">
|
|
12
|
+
<stop offset="0%" stop-color="#f8dca8"/><stop offset="52%" stop-color="#d3a85f"/><stop offset="100%" stop-color="#9b6f2f"/>
|
|
13
|
+
</radialGradient>
|
|
14
|
+
<linearGradient id="tube" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
15
|
+
<stop offset="0%" stop-color="#fffaf0"/><stop offset="52%" stop-color="#efe7d6"/><stop offset="100%" stop-color="#cabf9f"/>
|
|
16
|
+
</linearGradient></defs>
|
|
17
|
+
<rect width="100" height="100" rx="22.5" fill="url(#tile)"/>
|
|
18
|
+
<rect width="100" height="100" rx="22.5" fill="url(#shine)"/>
|
|
19
|
+
<circle cx="50" cy="50" r="17" fill="none" stroke="url(#tube)" stroke-width="5" stroke-dasharray="78 29" stroke-linecap="round" stroke-opacity=".92"/>
|
|
20
|
+
<circle cx="50" cy="50" r="30" fill="none" stroke="url(#tube)" stroke-width="5" stroke-dasharray="150 39" stroke-linecap="round" stroke-opacity=".8"/>
|
|
21
|
+
<path d="M42 46 L50 50 L58 46 L58 56 L42 56 Z" fill="url(#core)"/>
|
|
22
|
+
<circle cx="50" cy="20" r="5.6" fill="url(#node)"/></svg>
|
|
@@ -13,6 +13,7 @@ import 'package:flutter/material.dart';
|
|
|
13
13
|
import 'package:flutter/services.dart';
|
|
14
14
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
15
15
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
|
16
|
+
import 'package:flutter_svg/flutter_svg.dart';
|
|
16
17
|
import 'package:file_picker/file_picker.dart';
|
|
17
18
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
18
19
|
import 'package:google_fonts/google_fonts.dart';
|
|
@@ -99,6 +100,7 @@ const String _desktopAssistantHotkeyLabel = 'Ctrl + Shift + Space';
|
|
|
99
100
|
const String _desktopWindowIconAsset = 'assets/branding/app_icon_256.png';
|
|
100
101
|
const String _desktopTrayTemplateIconAsset =
|
|
101
102
|
'assets/branding/tray_icon_template.png';
|
|
103
|
+
const String _neoMailLogoAsset = 'assets/branding/neomail_logo.svg';
|
|
102
104
|
const String _sessionCookiePrefsKey = 'auth.sessionCookie';
|
|
103
105
|
const String _sessionCookieBackendPrefsKey = 'auth.sessionCookieBackend';
|
|
104
106
|
const String _sessionCookieSecureStorageKey = 'auth.sessionCookie.secure';
|
|
@@ -39,14 +39,16 @@ class OfficialIntegrationsTab extends StatelessWidget {
|
|
|
39
39
|
|
|
40
40
|
@override
|
|
41
41
|
Widget build(BuildContext context) {
|
|
42
|
-
final visibleIntegrations =
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
item
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
final visibleIntegrations =
|
|
43
|
+
controller.officialIntegrations
|
|
44
|
+
.where(
|
|
45
|
+
(item) =>
|
|
46
|
+
item.env.configured ||
|
|
47
|
+
item.env.setupMode == 'user' ||
|
|
48
|
+
item.isConnected,
|
|
49
|
+
)
|
|
50
|
+
.toList()
|
|
51
|
+
..sort(_compareOfficialIntegrationItems);
|
|
50
52
|
|
|
51
53
|
if (visibleIntegrations.isEmpty) {
|
|
52
54
|
return Card(
|
|
@@ -1379,17 +1381,27 @@ class _OfficialIntegrationIcon extends StatelessWidget {
|
|
|
1379
1381
|
|
|
1380
1382
|
@override
|
|
1381
1383
|
Widget build(BuildContext context) {
|
|
1384
|
+
if (item.icon == 'neomail') {
|
|
1385
|
+
return Container(
|
|
1386
|
+
width: 44,
|
|
1387
|
+
height: 44,
|
|
1388
|
+
decoration: BoxDecoration(
|
|
1389
|
+
borderRadius: BorderRadius.circular(14),
|
|
1390
|
+
border: Border.all(color: _border),
|
|
1391
|
+
),
|
|
1392
|
+
clipBehavior: Clip.antiAlias,
|
|
1393
|
+
child: SvgPicture.asset(_neoMailLogoAsset, fit: BoxFit.cover),
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1382
1396
|
final color = switch (item.icon) {
|
|
1383
1397
|
'google' => const Color(0xFF4285F4),
|
|
1384
1398
|
'home_assistant' => const Color(0xFF41BDF5),
|
|
1385
|
-
'neomail' => const Color(0xFF0F9D8A),
|
|
1386
1399
|
'trello' => const Color(0xFF0C66E4),
|
|
1387
1400
|
_ => _accent,
|
|
1388
1401
|
};
|
|
1389
1402
|
final label = switch (item.icon) {
|
|
1390
1403
|
'google' => 'G',
|
|
1391
1404
|
'home_assistant' => 'H',
|
|
1392
|
-
'neomail' => 'N',
|
|
1393
1405
|
'trello' => 'T',
|
|
1394
1406
|
_ => item.label.isNotEmpty ? item.label[0] : '?',
|
|
1395
1407
|
};
|
|
@@ -1414,6 +1426,25 @@ class _OfficialIntegrationIcon extends StatelessWidget {
|
|
|
1414
1426
|
}
|
|
1415
1427
|
}
|
|
1416
1428
|
|
|
1429
|
+
int _compareOfficialIntegrationItems(
|
|
1430
|
+
OfficialIntegrationItem a,
|
|
1431
|
+
OfficialIntegrationItem b,
|
|
1432
|
+
) {
|
|
1433
|
+
final rankDelta = _officialIntegrationRank(a) - _officialIntegrationRank(b);
|
|
1434
|
+
if (rankDelta != 0) {
|
|
1435
|
+
return rankDelta;
|
|
1436
|
+
}
|
|
1437
|
+
return a.label.toLowerCase().compareTo(b.label.toLowerCase());
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
int _officialIntegrationRank(OfficialIntegrationItem item) {
|
|
1441
|
+
return switch (item.id) {
|
|
1442
|
+
'neomail' => 0,
|
|
1443
|
+
'google_workspace' => 1,
|
|
1444
|
+
_ => 10,
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1417
1448
|
class _IntegrationSectionTitle extends StatelessWidget {
|
|
1418
1449
|
const _IntegrationSectionTitle({required this.title});
|
|
1419
1450
|
|
package/flutter_app/pubspec.lock
CHANGED
|
@@ -372,6 +372,14 @@ packages:
|
|
|
372
372
|
url: "https://pub.dev"
|
|
373
373
|
source: hosted
|
|
374
374
|
version: "0.1.3"
|
|
375
|
+
flutter_svg:
|
|
376
|
+
dependency: "direct main"
|
|
377
|
+
description:
|
|
378
|
+
name: flutter_svg
|
|
379
|
+
sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f"
|
|
380
|
+
url: "https://pub.dev"
|
|
381
|
+
source: hosted
|
|
382
|
+
version: "2.3.0"
|
|
375
383
|
flutter_test:
|
|
376
384
|
dependency: "direct dev"
|
|
377
385
|
description: flutter
|
|
@@ -670,6 +678,14 @@ packages:
|
|
|
670
678
|
url: "https://pub.dev"
|
|
671
679
|
source: hosted
|
|
672
680
|
version: "1.9.1"
|
|
681
|
+
path_parsing:
|
|
682
|
+
dependency: transitive
|
|
683
|
+
description:
|
|
684
|
+
name: path_parsing
|
|
685
|
+
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
|
|
686
|
+
url: "https://pub.dev"
|
|
687
|
+
source: hosted
|
|
688
|
+
version: "1.1.0"
|
|
673
689
|
path_provider:
|
|
674
690
|
dependency: "direct main"
|
|
675
691
|
description:
|
|
@@ -1171,6 +1187,30 @@ packages:
|
|
|
1171
1187
|
url: "https://pub.dev"
|
|
1172
1188
|
source: hosted
|
|
1173
1189
|
version: "4.5.3"
|
|
1190
|
+
vector_graphics:
|
|
1191
|
+
dependency: transitive
|
|
1192
|
+
description:
|
|
1193
|
+
name: vector_graphics
|
|
1194
|
+
sha256: "2306c03da2ba81724afeb589c351ebbc0aa7d86005925be8f8735856dbe5e42d"
|
|
1195
|
+
url: "https://pub.dev"
|
|
1196
|
+
source: hosted
|
|
1197
|
+
version: "1.2.2"
|
|
1198
|
+
vector_graphics_codec:
|
|
1199
|
+
dependency: transitive
|
|
1200
|
+
description:
|
|
1201
|
+
name: vector_graphics_codec
|
|
1202
|
+
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
|
|
1203
|
+
url: "https://pub.dev"
|
|
1204
|
+
source: hosted
|
|
1205
|
+
version: "1.1.13"
|
|
1206
|
+
vector_graphics_compiler:
|
|
1207
|
+
dependency: transitive
|
|
1208
|
+
description:
|
|
1209
|
+
name: vector_graphics_compiler
|
|
1210
|
+
sha256: b9b3f391857781aa96acacef96066f2f49b4cd03cf9fce3ca4d8da2ef5ea129e
|
|
1211
|
+
url: "https://pub.dev"
|
|
1212
|
+
source: hosted
|
|
1213
|
+
version: "1.2.3"
|
|
1174
1214
|
vector_math:
|
|
1175
1215
|
dependency: transitive
|
|
1176
1216
|
description:
|
package/flutter_app/pubspec.yaml
CHANGED
|
@@ -40,6 +40,7 @@ dependencies:
|
|
|
40
40
|
video_player: ^2.9.2
|
|
41
41
|
flutter_animate: ^4.5.2
|
|
42
42
|
flutter_local_notifications: ^18.0.0
|
|
43
|
+
flutter_svg: ^2.3.0
|
|
43
44
|
|
|
44
45
|
dependency_overrides:
|
|
45
46
|
flutter_secure_storage_linux:
|
|
@@ -62,4 +63,5 @@ flutter:
|
|
|
62
63
|
- assets/branding/app_icon_light_1024.png
|
|
63
64
|
- assets/branding/tray_icon_template.png
|
|
64
65
|
- assets/branding/tray_icon_light_template.png
|
|
66
|
+
- assets/branding/neomail_logo.svg
|
|
65
67
|
- assets/branding/onboarding_intro.mp4
|
package/package.json
CHANGED
package/server/admin/login.html
CHANGED
|
@@ -194,6 +194,35 @@
|
|
|
194
194
|
onclick="backToCredentials()">← Back</button>
|
|
195
195
|
</div>
|
|
196
196
|
</div>
|
|
197
|
+
|
|
198
|
+
<div id="step-setup" style="display:none;">
|
|
199
|
+
<h1 class="login-heading">Set up two-factor authentication</h1>
|
|
200
|
+
<p class="login-sub">Admin access requires 2FA. Scan the QR code, enter the current authenticator code, and save the recovery codes before continuing.</p>
|
|
201
|
+
<div class="alert alert-error" id="setup-error" role="alert"></div>
|
|
202
|
+
<div style="display:flex;justify-content:center;margin-bottom:14px;">
|
|
203
|
+
<div style="background:white;padding:12px;border-radius:16px;">
|
|
204
|
+
<img id="setup-qr" alt="Admin 2FA QR code" width="200" height="200">
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
<div class="field">
|
|
208
|
+
<label for="setup-manual-key">Manual key</label>
|
|
209
|
+
<input id="setup-manual-key" type="text" readonly>
|
|
210
|
+
</div>
|
|
211
|
+
<form id="setup-form" novalidate>
|
|
212
|
+
<div class="field">
|
|
213
|
+
<label for="setup-code">Authenticator code</label>
|
|
214
|
+
<input id="setup-code" type="text" inputmode="numeric" autocomplete="one-time-code" maxlength="16" placeholder="123 456" spellcheck="false" autocorrect="off" autocapitalize="none" required>
|
|
215
|
+
</div>
|
|
216
|
+
<button type="submit" class="btn btn-primary submit-btn" id="setup-btn">Enable 2FA</button>
|
|
217
|
+
</form>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div id="step-recovery" style="display:none;">
|
|
221
|
+
<h1 class="login-heading">Save recovery codes</h1>
|
|
222
|
+
<p class="login-sub">These codes are shown once. Store them now before you continue into the admin dashboard.</p>
|
|
223
|
+
<div id="recovery-codes" style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:18px;"></div>
|
|
224
|
+
<button type="button" class="btn btn-primary submit-btn" id="recovery-btn">Continue to admin</button>
|
|
225
|
+
</div>
|
|
197
226
|
</div>
|
|
198
227
|
</div>
|
|
199
228
|
|
|
@@ -204,15 +233,48 @@
|
|
|
204
233
|
const totpForm = document.getElementById('totp-form');
|
|
205
234
|
const totpBtn = document.getElementById('totp-btn');
|
|
206
235
|
const totpError = document.getElementById('totp-error');
|
|
236
|
+
const setupForm = document.getElementById('setup-form');
|
|
237
|
+
const setupBtn = document.getElementById('setup-btn');
|
|
238
|
+
const setupError = document.getElementById('setup-error');
|
|
239
|
+
const recoveryBtn = document.getElementById('recovery-btn');
|
|
207
240
|
|
|
208
241
|
function showStep(step) {
|
|
209
|
-
document.getElementById('step-credentials').style.display = step ===
|
|
210
|
-
document.getElementById('step-totp').style.display = step ===
|
|
211
|
-
|
|
212
|
-
|
|
242
|
+
document.getElementById('step-credentials').style.display = step === 'credentials' ? '' : 'none';
|
|
243
|
+
document.getElementById('step-totp').style.display = step === 'totp' ? '' : 'none';
|
|
244
|
+
document.getElementById('step-setup').style.display = step === 'setup' ? '' : 'none';
|
|
245
|
+
document.getElementById('step-recovery').style.display = step === 'recovery' ? '' : 'none';
|
|
246
|
+
if (step === 'totp') setTimeout(() => document.getElementById('totp-code')?.focus(), 50);
|
|
247
|
+
if (step === 'setup') setTimeout(() => document.getElementById('setup-code')?.focus(), 50);
|
|
248
|
+
if (step === 'credentials') setTimeout(() => document.getElementById('username')?.focus(), 50);
|
|
213
249
|
}
|
|
214
250
|
|
|
215
|
-
function backToCredentials() { showStep(
|
|
251
|
+
function backToCredentials() { showStep('credentials'); }
|
|
252
|
+
|
|
253
|
+
function loadSetup(setup) {
|
|
254
|
+
document.getElementById('setup-qr').src = setup.qrDataUrl || '';
|
|
255
|
+
document.getElementById('setup-manual-key').value = setup.manualKey || '';
|
|
256
|
+
document.getElementById('setup-code').value = '';
|
|
257
|
+
setupError.classList.remove('visible');
|
|
258
|
+
showStep('setup');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function showRecoveryCodes(codes) {
|
|
262
|
+
const container = document.getElementById('recovery-codes');
|
|
263
|
+
container.innerHTML = '';
|
|
264
|
+
for (const code of (Array.isArray(codes) ? codes : [])) {
|
|
265
|
+
const pill = document.createElement('div');
|
|
266
|
+
pill.textContent = code;
|
|
267
|
+
pill.style.padding = '10px 12px';
|
|
268
|
+
pill.style.border = '1px solid var(--border)';
|
|
269
|
+
pill.style.borderRadius = '12px';
|
|
270
|
+
pill.style.background = 'var(--bg-secondary)';
|
|
271
|
+
pill.style.fontFamily = 'var(--font-mono)';
|
|
272
|
+
pill.style.fontSize = '12px';
|
|
273
|
+
pill.style.color = 'var(--text)';
|
|
274
|
+
container.appendChild(pill);
|
|
275
|
+
}
|
|
276
|
+
showStep('recovery');
|
|
277
|
+
}
|
|
216
278
|
|
|
217
279
|
form.addEventListener('submit', async (e) => {
|
|
218
280
|
e.preventDefault();
|
|
@@ -232,10 +294,12 @@
|
|
|
232
294
|
|
|
233
295
|
const body = await res.json().catch(() => ({}));
|
|
234
296
|
|
|
235
|
-
if (res.ok || body.requiresTwoFactor) {
|
|
236
|
-
if (body.
|
|
297
|
+
if (res.ok || body.requiresTwoFactor || body.requiresTwoFactorSetup) {
|
|
298
|
+
if (body.requiresTwoFactorSetup) {
|
|
299
|
+
loadSetup(body.setup || {});
|
|
300
|
+
} else if (body.requiresTwoFactor) {
|
|
237
301
|
// Password accepted — go to 2FA step
|
|
238
|
-
showStep(
|
|
302
|
+
showStep('totp');
|
|
239
303
|
} else {
|
|
240
304
|
window.location.replace('/admin');
|
|
241
305
|
}
|
|
@@ -253,6 +317,37 @@
|
|
|
253
317
|
}
|
|
254
318
|
});
|
|
255
319
|
|
|
320
|
+
setupForm.addEventListener('submit', async (e) => {
|
|
321
|
+
e.preventDefault();
|
|
322
|
+
setupError.classList.remove('visible');
|
|
323
|
+
setupBtn.disabled = true;
|
|
324
|
+
setupBtn.textContent = 'Enabling…';
|
|
325
|
+
try {
|
|
326
|
+
const res = await fetch('/admin/api/login/2fa/setup/enable', {
|
|
327
|
+
method: 'POST',
|
|
328
|
+
headers: { 'Content-Type': 'application/json' },
|
|
329
|
+
body: JSON.stringify({
|
|
330
|
+
code: document.getElementById('setup-code').value.trim(),
|
|
331
|
+
}),
|
|
332
|
+
});
|
|
333
|
+
const body = await res.json().catch(() => ({}));
|
|
334
|
+
if (!res.ok) {
|
|
335
|
+
throw new Error(body.error || '2FA setup failed');
|
|
336
|
+
}
|
|
337
|
+
showRecoveryCodes(body.recoveryCodes || []);
|
|
338
|
+
} catch (error) {
|
|
339
|
+
setupError.textContent = error.message || '2FA setup failed';
|
|
340
|
+
setupError.classList.add('visible');
|
|
341
|
+
} finally {
|
|
342
|
+
setupBtn.disabled = false;
|
|
343
|
+
setupBtn.textContent = 'Enable 2FA';
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
recoveryBtn.addEventListener('click', () => {
|
|
348
|
+
window.location.replace('/admin');
|
|
349
|
+
});
|
|
350
|
+
|
|
256
351
|
totpForm.addEventListener('submit', async (e) => {
|
|
257
352
|
e.preventDefault();
|
|
258
353
|
totpError.classList.remove('visible');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
66d8a64f104d72faf757b6613debe081
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"
|
|
1
|
+
"DQ4HIWFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8xMDI0LnBuZwwBDQEHBWFzc2V0ByFhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fMTAyNC5wbmcHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nDAENAQcFYXNzZXQHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwwBDQEHBWFzc2V0ByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwcnYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzEwMjQucG5nDAENAQcFYXNzZXQHJ2Fzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF8xMDI0LnBuZwcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcMAQ0BBwVhc3NldAcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nDAENAQcFYXNzZXQHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nByBhc3NldHMvYnJhbmRpbmcvbmVvbWFpbF9sb2dvLnN2ZwwBDQEHBWFzc2V0ByBhc3NldHMvYnJhbmRpbmcvbmVvbWFpbF9sb2dvLnN2ZwckYXNzZXRzL2JyYW5kaW5nL29uYm9hcmRpbmdfaW50cm8ubXA0DAENAQcFYXNzZXQHJGFzc2V0cy9icmFuZGluZy9vbmJvYXJkaW5nX2ludHJvLm1wNAcsYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl9saWdodF90ZW1wbGF0ZS5wbmcMAQ0BBwVhc3NldAcsYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl9saWdodF90ZW1wbGF0ZS5wbmcHJmFzc2V0cy9icmFuZGluZy90cmF5X2ljb25fdGVtcGxhdGUucG5nDAENAQcFYXNzZXQHJmFzc2V0cy9icmFuZGluZy90cmF5X2ljb25fdGVtcGxhdGUucG5nBzJwYWNrYWdlcy9jdXBlcnRpbm9faWNvbnMvYXNzZXRzL0N1cGVydGlub0ljb25zLnR0ZgwBDQEHBWFzc2V0BzJwYWNrYWdlcy9jdXBlcnRpbm9faWNvbnMvYXNzZXRzL0N1cGVydGlub0ljb25zLnR0Zgc3cGFja2FnZXMvcmVjb3JkX3dlYi9hc3NldHMvanMvcmVjb3JkLmZpeHdlYm1kdXJhdGlvbi5qcwwBDQEHBWFzc2V0BzdwYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQuZml4d2VibWR1cmF0aW9uLmpzBy9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwwBDQEHBWFzc2V0By9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwcWd2ViL2ljb25zL0ljb24tMTkyLnBuZwwBDQEHBWFzc2V0BxZ3ZWIvaWNvbnMvSWNvbi0xOTIucG5n"
|
|
@@ -2187,6 +2187,8 @@ url_launcher_ios
|
|
|
2187
2187
|
url_launcher_linux
|
|
2188
2188
|
url_launcher_macos
|
|
2189
2189
|
url_launcher_windows
|
|
2190
|
+
vector_graphics
|
|
2191
|
+
vector_graphics_compiler
|
|
2190
2192
|
video_player
|
|
2191
2193
|
video_player_android
|
|
2192
2194
|
video_player_avfoundation
|
|
@@ -5914,6 +5916,7 @@ shared_preferences_web
|
|
|
5914
5916
|
shared_preferences_windows
|
|
5915
5917
|
url_launcher
|
|
5916
5918
|
url_launcher_platform_interface
|
|
5919
|
+
vector_graphics_codec
|
|
5917
5920
|
video_player_web
|
|
5918
5921
|
xdg_directories
|
|
5919
5922
|
|
|
@@ -6041,6 +6044,28 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
6041
6044
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
6042
6045
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
6043
6046
|
--------------------------------------------------------------------------------
|
|
6047
|
+
flutter_svg
|
|
6048
|
+
|
|
6049
|
+
Copyright (c) 2018 Dan Field
|
|
6050
|
+
|
|
6051
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6052
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6053
|
+
in the Software without restriction, including without limitation the rights
|
|
6054
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
6055
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
6056
|
+
furnished to do so, subject to the following conditions:
|
|
6057
|
+
|
|
6058
|
+
The above copyright notice and this permission notice shall be included in all
|
|
6059
|
+
copies or substantial portions of the Software.
|
|
6060
|
+
|
|
6061
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
6062
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
6063
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
6064
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
6065
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
6066
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
6067
|
+
SOFTWARE.
|
|
6068
|
+
--------------------------------------------------------------------------------
|
|
6044
6069
|
flutter_web_bluetooth
|
|
6045
6070
|
|
|
6046
6071
|
MIT License
|
|
@@ -25427,6 +25452,29 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
25427
25452
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25428
25453
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25429
25454
|
SOFTWARE.
|
|
25455
|
+
--------------------------------------------------------------------------------
|
|
25456
|
+
path_parsing
|
|
25457
|
+
|
|
25458
|
+
Copyright (c) 2018 Dan Field
|
|
25459
|
+
|
|
25460
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25461
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
25462
|
+
in the Software without restriction, including without limitation the rights
|
|
25463
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
25464
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
25465
|
+
furnished to do so, subject to the following conditions:
|
|
25466
|
+
|
|
25467
|
+
The above copyright notice and this permission notice shall be included in all
|
|
25468
|
+
copies or substantial portions of the Software.
|
|
25469
|
+
|
|
25470
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25471
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25472
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25473
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25474
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25475
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25476
|
+
SOFTWARE.
|
|
25477
|
+
|
|
25430
25478
|
--------------------------------------------------------------------------------
|
|
25431
25479
|
perfetto
|
|
25432
25480
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg viewBox="0 0 100 100" width="1024" height="1024" xmlns="http://www.w3.org/2000/svg"><defs>
|
|
2
|
+
<linearGradient id="tile" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
3
|
+
<stop offset="0%" stop-color="#705331"/><stop offset="100%" stop-color="#22564c"/>
|
|
4
|
+
</linearGradient>
|
|
5
|
+
<radialGradient id="shine" cx="26%" cy="14%" r="72%">
|
|
6
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.22"/><stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>
|
|
7
|
+
</radialGradient>
|
|
8
|
+
<radialGradient id="core" cx="38%" cy="32%" r="75%">
|
|
9
|
+
<stop offset="0%" stop-color="#fffdf6"/><stop offset="48%" stop-color="#eee3cc"/><stop offset="100%" stop-color="#b5a888"/>
|
|
10
|
+
</radialGradient>
|
|
11
|
+
<radialGradient id="node" cx="36%" cy="30%" r="80%">
|
|
12
|
+
<stop offset="0%" stop-color="#f8dca8"/><stop offset="52%" stop-color="#d3a85f"/><stop offset="100%" stop-color="#9b6f2f"/>
|
|
13
|
+
</radialGradient>
|
|
14
|
+
<linearGradient id="tube" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
15
|
+
<stop offset="0%" stop-color="#fffaf0"/><stop offset="52%" stop-color="#efe7d6"/><stop offset="100%" stop-color="#cabf9f"/>
|
|
16
|
+
</linearGradient></defs>
|
|
17
|
+
<rect width="100" height="100" rx="22.5" fill="url(#tile)"/>
|
|
18
|
+
<rect width="100" height="100" rx="22.5" fill="url(#shine)"/>
|
|
19
|
+
<circle cx="50" cy="50" r="17" fill="none" stroke="url(#tube)" stroke-width="5" stroke-dasharray="78 29" stroke-linecap="round" stroke-opacity=".92"/>
|
|
20
|
+
<circle cx="50" cy="50" r="30" fill="none" stroke="url(#tube)" stroke-width="5" stroke-dasharray="150 39" stroke-linecap="round" stroke-opacity=".8"/>
|
|
21
|
+
<path d="M42 46 L50 50 L58 46 L58 56 L42 56 Z" fill="url(#core)"/>
|
|
22
|
+
<circle cx="50" cy="20" r="5.6" fill="url(#node)"/></svg>
|
|
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"a10d8ac38de835021c8d2f920dbf50a920ccc0
|
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "2653428156" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
|
41
41
|
}
|
|
42
42
|
});
|