neoagent 2.4.1-beta.29 → 2.4.1-beta.31
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/onboarding_intro.mp4 +0 -0
- package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +391 -382
- package/flutter_app/lib/features/onboarding/onboarding_companion_step.dart +78 -56
- package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +18 -16
- package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +18 -17
- package/flutter_app/lib/features/onboarding/onboarding_shell.dart +2 -1
- package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +16 -13
- package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +15 -11
- package/flutter_app/lib/main_account_settings.dart +1 -1
- package/flutter_app/lib/main_admin.dart +1 -1
- package/flutter_app/lib/main_app_shell.dart +190 -191
- package/flutter_app/lib/main_chat.dart +385 -229
- package/flutter_app/lib/main_devices.dart +1 -1
- package/flutter_app/lib/main_launcher.dart +1 -1
- package/flutter_app/lib/main_operations.dart +3 -3
- package/flutter_app/lib/main_shared.dart +339 -342
- package/flutter_app/lib/main_spacing.dart +4 -4
- package/flutter_app/lib/main_theme.dart +20 -14
- package/flutter_app/lib/src/theme/palette.dart +76 -34
- package/flutter_app/pubspec.lock +2 -2
- package/flutter_app/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +60569 -60356
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import 'dart:ui' show ImageFilter;
|
|
2
|
-
|
|
3
1
|
import 'package:flutter/material.dart';
|
|
4
|
-
|
|
2
|
+
import 'package:google_fonts/google_fonts.dart';
|
|
3
|
+
|
|
4
|
+
import '../../src/theme/palette.dart';
|
|
5
|
+
|
|
6
|
+
/// Shared chrome for the onboarding flow.
|
|
7
|
+
///
|
|
8
|
+
/// On wide viewports this renders the "Control Surface" two-pane onboarding:
|
|
9
|
+
/// a brand / narrative pane on the left (logo, step counter, eyebrow, title,
|
|
10
|
+
/// supporting copy and progress rail) over the olive [bgPrimary] surface, and
|
|
11
|
+
/// an interaction pane on the right (the step's content + nav) over the deeper
|
|
12
|
+
/// [bgSecondary]. It is fully theme-aware — light or dark follows the system
|
|
13
|
+
/// brightness via [paletteOf].
|
|
5
14
|
class OnboardingScaffold extends StatelessWidget {
|
|
6
15
|
const OnboardingScaffold({
|
|
7
16
|
super.key,
|
|
@@ -28,59 +37,297 @@ class OnboardingScaffold extends StatelessWidget {
|
|
|
28
37
|
|
|
29
38
|
@override
|
|
30
39
|
Widget build(BuildContext context) {
|
|
31
|
-
final
|
|
32
|
-
final
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
final p = paletteOf(context);
|
|
41
|
+
final wide = MediaQuery.sizeOf(context).width >= 900;
|
|
42
|
+
|
|
43
|
+
if (!wide) {
|
|
44
|
+
return ColoredBox(
|
|
45
|
+
color: p.bgPrimary,
|
|
46
|
+
child: SafeArea(child: _CompactBody(scaffold: this)),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return ColoredBox(
|
|
51
|
+
color: p.bgPrimary,
|
|
52
|
+
child: SafeArea(
|
|
53
|
+
child: Row(
|
|
54
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
55
|
+
children: <Widget>[
|
|
56
|
+
Expanded(flex: 43, child: _NarrativePane(scaffold: this)),
|
|
57
|
+
Expanded(flex: 57, child: _InteractionPane(scaffold: this)),
|
|
58
|
+
],
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class _NarrativePane extends StatelessWidget {
|
|
66
|
+
const _NarrativePane({required this.scaffold});
|
|
67
|
+
|
|
68
|
+
final OnboardingScaffold scaffold;
|
|
69
|
+
|
|
70
|
+
@override
|
|
71
|
+
Widget build(BuildContext context) {
|
|
72
|
+
final p = paletteOf(context);
|
|
73
|
+
return DecoratedBox(
|
|
74
|
+
decoration: BoxDecoration(color: p.bgPrimary),
|
|
75
|
+
child: Stack(
|
|
76
|
+
children: <Widget>[
|
|
77
|
+
// Sage glow, top-left — the brand "agent OS" atmosphere.
|
|
78
|
+
Positioned.fill(
|
|
79
|
+
child: DecoratedBox(
|
|
80
|
+
decoration: BoxDecoration(
|
|
81
|
+
gradient: RadialGradient(
|
|
82
|
+
center: const Alignment(-0.8, -0.9),
|
|
83
|
+
radius: 1.2,
|
|
84
|
+
colors: <Color>[
|
|
85
|
+
p.accentAlt.withValues(alpha: 0.20),
|
|
86
|
+
p.accentAlt.withValues(alpha: 0),
|
|
87
|
+
],
|
|
88
|
+
),
|
|
89
|
+
),
|
|
43
90
|
),
|
|
91
|
+
),
|
|
92
|
+
Padding(
|
|
93
|
+
padding: const EdgeInsets.fromLTRB(52, 44, 44, 44),
|
|
44
94
|
child: Column(
|
|
95
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
45
96
|
children: <Widget>[
|
|
46
|
-
|
|
47
|
-
const SizedBox(height: 18),
|
|
97
|
+
_Brand(step: scaffold.step, totalSteps: scaffold.totalSteps),
|
|
48
98
|
Expanded(
|
|
49
|
-
child:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
99
|
+
child: Center(
|
|
100
|
+
child: SingleChildScrollView(
|
|
101
|
+
child: Column(
|
|
102
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
103
|
+
mainAxisSize: MainAxisSize.min,
|
|
104
|
+
children: <Widget>[
|
|
105
|
+
const SizedBox(height: 24),
|
|
106
|
+
OnboardingEyebrow(scaffold.eyebrow),
|
|
107
|
+
const SizedBox(height: 18),
|
|
108
|
+
Text(
|
|
109
|
+
scaffold.title,
|
|
110
|
+
style: GoogleFonts.geist(
|
|
111
|
+
color: p.textPrimary,
|
|
112
|
+
fontSize: 42,
|
|
113
|
+
height: 1.04,
|
|
114
|
+
fontWeight: FontWeight.w800,
|
|
115
|
+
letterSpacing: -1.2,
|
|
116
|
+
),
|
|
60
117
|
),
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
118
|
+
const SizedBox(height: 18),
|
|
119
|
+
ConstrainedBox(
|
|
120
|
+
constraints: const BoxConstraints(maxWidth: 460),
|
|
121
|
+
child: Text(
|
|
122
|
+
scaffold.description,
|
|
123
|
+
style: GoogleFonts.geist(
|
|
124
|
+
color: p.textSecondary,
|
|
125
|
+
fontSize: 16,
|
|
126
|
+
height: 1.6,
|
|
127
|
+
),
|
|
128
|
+
),
|
|
72
129
|
),
|
|
73
|
-
|
|
130
|
+
if (scaffold.sidePanel != null) ...<Widget>[
|
|
131
|
+
const SizedBox(height: 28),
|
|
132
|
+
scaffold.sidePanel!,
|
|
133
|
+
],
|
|
134
|
+
const SizedBox(height: 24),
|
|
135
|
+
],
|
|
136
|
+
),
|
|
137
|
+
),
|
|
138
|
+
),
|
|
139
|
+
),
|
|
140
|
+
_ProgressRail(
|
|
141
|
+
step: scaffold.step,
|
|
142
|
+
totalSteps: scaffold.totalSteps,
|
|
74
143
|
),
|
|
75
144
|
],
|
|
76
145
|
),
|
|
77
146
|
),
|
|
147
|
+
],
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
class _InteractionPane extends StatelessWidget {
|
|
154
|
+
const _InteractionPane({required this.scaffold});
|
|
155
|
+
|
|
156
|
+
final OnboardingScaffold scaffold;
|
|
157
|
+
|
|
158
|
+
@override
|
|
159
|
+
Widget build(BuildContext context) {
|
|
160
|
+
final p = paletteOf(context);
|
|
161
|
+
return DecoratedBox(
|
|
162
|
+
decoration: BoxDecoration(
|
|
163
|
+
color: p.bgSecondary,
|
|
164
|
+
border: Border(left: BorderSide(color: p.border)),
|
|
165
|
+
),
|
|
166
|
+
child: Padding(
|
|
167
|
+
padding: EdgeInsets.all(scaffold.dense ? 36 : 44),
|
|
168
|
+
child: Column(
|
|
169
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
170
|
+
children: <Widget>[
|
|
171
|
+
Expanded(child: scaffold.child),
|
|
172
|
+
const SizedBox(height: 26),
|
|
173
|
+
scaffold.footer,
|
|
174
|
+
],
|
|
175
|
+
),
|
|
176
|
+
),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
class _CompactBody extends StatelessWidget {
|
|
182
|
+
const _CompactBody({required this.scaffold});
|
|
183
|
+
|
|
184
|
+
final OnboardingScaffold scaffold;
|
|
185
|
+
|
|
186
|
+
@override
|
|
187
|
+
Widget build(BuildContext context) {
|
|
188
|
+
final p = paletteOf(context);
|
|
189
|
+
return Padding(
|
|
190
|
+
padding: const EdgeInsets.fromLTRB(22, 18, 22, 22),
|
|
191
|
+
child: Column(
|
|
192
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
193
|
+
children: <Widget>[
|
|
194
|
+
_Brand(step: scaffold.step, totalSteps: scaffold.totalSteps),
|
|
195
|
+
const SizedBox(height: 16),
|
|
196
|
+
_ProgressRail(step: scaffold.step, totalSteps: scaffold.totalSteps),
|
|
197
|
+
const SizedBox(height: 24),
|
|
198
|
+
OnboardingEyebrow(scaffold.eyebrow),
|
|
199
|
+
const SizedBox(height: 12),
|
|
200
|
+
Text(
|
|
201
|
+
scaffold.title,
|
|
202
|
+
style: GoogleFonts.geist(
|
|
203
|
+
color: p.textPrimary,
|
|
204
|
+
fontSize: 28,
|
|
205
|
+
height: 1.06,
|
|
206
|
+
fontWeight: FontWeight.w800,
|
|
207
|
+
letterSpacing: -0.8,
|
|
208
|
+
),
|
|
209
|
+
),
|
|
210
|
+
const SizedBox(height: 10),
|
|
211
|
+
Text(
|
|
212
|
+
scaffold.description,
|
|
213
|
+
style: GoogleFonts.geist(
|
|
214
|
+
color: p.textSecondary,
|
|
215
|
+
fontSize: 14.5,
|
|
216
|
+
height: 1.55,
|
|
217
|
+
),
|
|
218
|
+
),
|
|
219
|
+
if (scaffold.sidePanel != null) ...<Widget>[
|
|
220
|
+
const SizedBox(height: 18),
|
|
221
|
+
scaffold.sidePanel!,
|
|
222
|
+
],
|
|
223
|
+
const SizedBox(height: 22),
|
|
224
|
+
Expanded(child: scaffold.child),
|
|
225
|
+
const SizedBox(height: 18),
|
|
226
|
+
scaffold.footer,
|
|
227
|
+
],
|
|
228
|
+
),
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
class _Brand extends StatelessWidget {
|
|
234
|
+
const _Brand({required this.step, required this.totalSteps});
|
|
235
|
+
|
|
236
|
+
final int step;
|
|
237
|
+
final int totalSteps;
|
|
238
|
+
|
|
239
|
+
@override
|
|
240
|
+
Widget build(BuildContext context) {
|
|
241
|
+
final p = paletteOf(context);
|
|
242
|
+
final dark = MediaQuery.platformBrightnessOf(context) == Brightness.dark;
|
|
243
|
+
return Row(
|
|
244
|
+
mainAxisSize: MainAxisSize.min,
|
|
245
|
+
children: <Widget>[
|
|
246
|
+
Container(
|
|
247
|
+
width: 36,
|
|
248
|
+
height: 36,
|
|
249
|
+
decoration: BoxDecoration(
|
|
250
|
+
borderRadius: BorderRadius.circular(10),
|
|
251
|
+
boxShadow: <BoxShadow>[
|
|
252
|
+
BoxShadow(
|
|
253
|
+
color: p.accent.withValues(alpha: 0.16),
|
|
254
|
+
blurRadius: 14,
|
|
255
|
+
),
|
|
256
|
+
],
|
|
257
|
+
),
|
|
258
|
+
child: ClipRRect(
|
|
259
|
+
borderRadius: BorderRadius.circular(10),
|
|
260
|
+
child: Image.asset(
|
|
261
|
+
dark
|
|
262
|
+
? 'assets/branding/app_icon_1024.png'
|
|
263
|
+
: 'assets/branding/app_icon_light_1024.png',
|
|
264
|
+
width: 36,
|
|
265
|
+
height: 36,
|
|
266
|
+
filterQuality: FilterQuality.high,
|
|
267
|
+
),
|
|
268
|
+
),
|
|
269
|
+
),
|
|
270
|
+
const SizedBox(width: 12),
|
|
271
|
+
Column(
|
|
272
|
+
mainAxisSize: MainAxisSize.min,
|
|
273
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
274
|
+
children: <Widget>[
|
|
275
|
+
Text(
|
|
276
|
+
'NeoAgent',
|
|
277
|
+
style: GoogleFonts.geist(
|
|
278
|
+
color: p.textPrimary,
|
|
279
|
+
fontSize: 17,
|
|
280
|
+
fontWeight: FontWeight.w700,
|
|
281
|
+
letterSpacing: -0.3,
|
|
282
|
+
),
|
|
283
|
+
),
|
|
284
|
+
const SizedBox(height: 2),
|
|
285
|
+
Text(
|
|
286
|
+
'STEP ${step + 1} OF $totalSteps',
|
|
287
|
+
style: GoogleFonts.geistMono(
|
|
288
|
+
color: p.textMuted,
|
|
289
|
+
fontSize: 10.5,
|
|
290
|
+
fontWeight: FontWeight.w600,
|
|
291
|
+
letterSpacing: 1.6,
|
|
292
|
+
),
|
|
293
|
+
),
|
|
294
|
+
],
|
|
78
295
|
),
|
|
79
296
|
],
|
|
80
297
|
);
|
|
81
298
|
}
|
|
82
299
|
}
|
|
83
300
|
|
|
301
|
+
class _ProgressRail extends StatelessWidget {
|
|
302
|
+
const _ProgressRail({required this.step, required this.totalSteps});
|
|
303
|
+
|
|
304
|
+
final int step;
|
|
305
|
+
final int totalSteps;
|
|
306
|
+
|
|
307
|
+
@override
|
|
308
|
+
Widget build(BuildContext context) {
|
|
309
|
+
final p = paletteOf(context);
|
|
310
|
+
return Row(
|
|
311
|
+
mainAxisSize: MainAxisSize.min,
|
|
312
|
+
children: List<Widget>.generate(totalSteps, (index) {
|
|
313
|
+
final active = index == step;
|
|
314
|
+
final done = index < step;
|
|
315
|
+
return AnimatedContainer(
|
|
316
|
+
duration: const Duration(milliseconds: 320),
|
|
317
|
+
curve: Curves.easeOutCubic,
|
|
318
|
+
margin: const EdgeInsets.only(right: 8),
|
|
319
|
+
width: active ? 30 : 16,
|
|
320
|
+
height: 5,
|
|
321
|
+
decoration: BoxDecoration(
|
|
322
|
+
color: active || done ? p.accent : p.borderLight,
|
|
323
|
+
borderRadius: BorderRadius.circular(999),
|
|
324
|
+
),
|
|
325
|
+
);
|
|
326
|
+
}),
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
84
331
|
class OnboardingPanel extends StatelessWidget {
|
|
85
332
|
const OnboardingPanel({
|
|
86
333
|
super.key,
|
|
@@ -93,7 +340,16 @@ class OnboardingPanel extends StatelessWidget {
|
|
|
93
340
|
|
|
94
341
|
@override
|
|
95
342
|
Widget build(BuildContext context) {
|
|
96
|
-
|
|
343
|
+
final p = paletteOf(context);
|
|
344
|
+
return Container(
|
|
345
|
+
padding: padding,
|
|
346
|
+
decoration: BoxDecoration(
|
|
347
|
+
color: p.bgCard,
|
|
348
|
+
borderRadius: BorderRadius.circular(20),
|
|
349
|
+
border: Border.all(color: p.border),
|
|
350
|
+
),
|
|
351
|
+
child: child,
|
|
352
|
+
);
|
|
97
353
|
}
|
|
98
354
|
}
|
|
99
355
|
|
|
@@ -115,33 +371,31 @@ class OnboardingOptionCard extends StatelessWidget {
|
|
|
115
371
|
|
|
116
372
|
@override
|
|
117
373
|
Widget build(BuildContext context) {
|
|
118
|
-
final
|
|
374
|
+
final p = paletteOf(context);
|
|
375
|
+
final highlight = accent ?? p.accent;
|
|
376
|
+
final radius = compact ? 16.0 : 20.0;
|
|
119
377
|
return Material(
|
|
120
378
|
color: Colors.transparent,
|
|
121
379
|
child: InkWell(
|
|
122
380
|
onTap: onTap,
|
|
123
|
-
borderRadius: BorderRadius.circular(
|
|
381
|
+
borderRadius: BorderRadius.circular(radius),
|
|
124
382
|
child: AnimatedContainer(
|
|
125
|
-
duration: const Duration(milliseconds:
|
|
383
|
+
duration: const Duration(milliseconds: 200),
|
|
126
384
|
curve: Curves.easeOutCubic,
|
|
127
|
-
padding: EdgeInsets.all(compact ? 16 :
|
|
385
|
+
padding: EdgeInsets.all(compact ? 16 : 18),
|
|
128
386
|
decoration: BoxDecoration(
|
|
129
|
-
color: selected
|
|
130
|
-
|
|
131
|
-
: Colors.white.withValues(alpha: 0.055),
|
|
132
|
-
borderRadius: BorderRadius.circular(compact ? 22 : 28),
|
|
387
|
+
color: selected ? highlight.withValues(alpha: 0.08) : p.bgCard,
|
|
388
|
+
borderRadius: BorderRadius.circular(radius),
|
|
133
389
|
border: Border.all(
|
|
134
|
-
color: selected
|
|
135
|
-
|
|
136
|
-
: Colors.white.withValues(alpha: 0.1),
|
|
137
|
-
width: selected ? 1.8 : 1,
|
|
390
|
+
color: selected ? highlight : p.borderLight,
|
|
391
|
+
width: selected ? 1.6 : 1,
|
|
138
392
|
),
|
|
139
393
|
boxShadow: selected
|
|
140
394
|
? <BoxShadow>[
|
|
141
395
|
BoxShadow(
|
|
142
|
-
color: highlight.withValues(alpha: 0.
|
|
143
|
-
blurRadius:
|
|
144
|
-
|
|
396
|
+
color: highlight.withValues(alpha: 0.22),
|
|
397
|
+
blurRadius: 0,
|
|
398
|
+
spreadRadius: 3,
|
|
145
399
|
),
|
|
146
400
|
]
|
|
147
401
|
: const <BoxShadow>[],
|
|
@@ -167,14 +421,19 @@ class OnboardingGhostButton extends StatelessWidget {
|
|
|
167
421
|
|
|
168
422
|
@override
|
|
169
423
|
Widget build(BuildContext context) {
|
|
424
|
+
final p = paletteOf(context);
|
|
170
425
|
return TextButton.icon(
|
|
171
426
|
onPressed: onPressed,
|
|
172
427
|
style: TextButton.styleFrom(
|
|
173
|
-
foregroundColor:
|
|
174
|
-
padding: const EdgeInsets.symmetric(horizontal:
|
|
175
|
-
textStyle:
|
|
428
|
+
foregroundColor: p.textSecondary,
|
|
429
|
+
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
|
430
|
+
textStyle: GoogleFonts.geist(fontSize: 14, fontWeight: FontWeight.w600),
|
|
431
|
+
shape: RoundedRectangleBorder(
|
|
432
|
+
borderRadius: BorderRadius.circular(12),
|
|
433
|
+
side: BorderSide(color: p.border),
|
|
434
|
+
),
|
|
176
435
|
),
|
|
177
|
-
icon: icon == null ? const SizedBox.shrink() : Icon(icon, size:
|
|
436
|
+
icon: icon == null ? const SizedBox.shrink() : Icon(icon, size: 17),
|
|
178
437
|
label: Text(label),
|
|
179
438
|
);
|
|
180
439
|
}
|
|
@@ -194,31 +453,58 @@ class OnboardingPrimaryButton extends StatelessWidget {
|
|
|
194
453
|
|
|
195
454
|
@override
|
|
196
455
|
Widget build(BuildContext context) {
|
|
197
|
-
final
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
456
|
+
final p = paletteOf(context);
|
|
457
|
+
final enabled = onPressed != null;
|
|
458
|
+
final gold = p.accent;
|
|
459
|
+
return Opacity(
|
|
460
|
+
opacity: enabled ? 1 : 0.5,
|
|
461
|
+
child: DecoratedBox(
|
|
462
|
+
decoration: BoxDecoration(
|
|
463
|
+
gradient: LinearGradient(
|
|
464
|
+
begin: Alignment.topLeft,
|
|
465
|
+
end: Alignment.bottomRight,
|
|
466
|
+
colors: <Color>[
|
|
467
|
+
Color.lerp(gold, Colors.white, 0.16)!,
|
|
468
|
+
gold,
|
|
469
|
+
],
|
|
206
470
|
),
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
471
|
+
borderRadius: BorderRadius.circular(14),
|
|
472
|
+
boxShadow: <BoxShadow>[
|
|
473
|
+
BoxShadow(
|
|
474
|
+
color: gold.withValues(alpha: 0.34),
|
|
475
|
+
blurRadius: 22,
|
|
476
|
+
offset: const Offset(0, 10),
|
|
477
|
+
),
|
|
478
|
+
],
|
|
479
|
+
),
|
|
480
|
+
child: Material(
|
|
481
|
+
color: Colors.transparent,
|
|
482
|
+
child: InkWell(
|
|
483
|
+
onTap: onPressed,
|
|
484
|
+
borderRadius: BorderRadius.circular(14),
|
|
485
|
+
child: Padding(
|
|
486
|
+
padding: const EdgeInsets.symmetric(horizontal: 26, vertical: 17),
|
|
487
|
+
child: Row(
|
|
488
|
+
mainAxisSize: MainAxisSize.min,
|
|
489
|
+
children: <Widget>[
|
|
490
|
+
Text(
|
|
491
|
+
label,
|
|
492
|
+
style: GoogleFonts.geist(
|
|
493
|
+
color: Colors.white,
|
|
494
|
+
fontSize: 15,
|
|
495
|
+
fontWeight: FontWeight.w700,
|
|
496
|
+
letterSpacing: -0.1,
|
|
497
|
+
),
|
|
498
|
+
),
|
|
499
|
+
if (icon != null) ...<Widget>[
|
|
500
|
+
const SizedBox(width: 9),
|
|
501
|
+
Icon(icon, size: 18, color: Colors.white),
|
|
502
|
+
],
|
|
503
|
+
],
|
|
504
|
+
),
|
|
505
|
+
),
|
|
217
506
|
),
|
|
218
|
-
textStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w700),
|
|
219
507
|
),
|
|
220
|
-
icon: icon == null ? const SizedBox.shrink() : Icon(icon, size: 18),
|
|
221
|
-
label: Text(label),
|
|
222
508
|
),
|
|
223
509
|
);
|
|
224
510
|
}
|
|
@@ -236,12 +522,13 @@ class OnboardingMetricPill extends StatelessWidget {
|
|
|
236
522
|
|
|
237
523
|
@override
|
|
238
524
|
Widget build(BuildContext context) {
|
|
525
|
+
final p = paletteOf(context);
|
|
239
526
|
return Container(
|
|
240
527
|
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
|
241
528
|
decoration: BoxDecoration(
|
|
242
|
-
color:
|
|
243
|
-
borderRadius: BorderRadius.circular(
|
|
244
|
-
border: Border.all(color:
|
|
529
|
+
color: p.bgCard,
|
|
530
|
+
borderRadius: BorderRadius.circular(14),
|
|
531
|
+
border: Border.all(color: p.border),
|
|
245
532
|
),
|
|
246
533
|
child: Column(
|
|
247
534
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
@@ -249,18 +536,18 @@ class OnboardingMetricPill extends StatelessWidget {
|
|
|
249
536
|
children: <Widget>[
|
|
250
537
|
Text(
|
|
251
538
|
label.toUpperCase(),
|
|
252
|
-
style:
|
|
253
|
-
color:
|
|
254
|
-
fontSize:
|
|
255
|
-
fontWeight: FontWeight.
|
|
256
|
-
letterSpacing:
|
|
539
|
+
style: GoogleFonts.geistMono(
|
|
540
|
+
color: p.textMuted,
|
|
541
|
+
fontSize: 10.5,
|
|
542
|
+
fontWeight: FontWeight.w600,
|
|
543
|
+
letterSpacing: 1.4,
|
|
257
544
|
),
|
|
258
545
|
),
|
|
259
546
|
const SizedBox(height: 6),
|
|
260
547
|
Text(
|
|
261
548
|
value,
|
|
262
|
-
style:
|
|
263
|
-
color:
|
|
549
|
+
style: GoogleFonts.geist(
|
|
550
|
+
color: p.textPrimary,
|
|
264
551
|
fontSize: 15,
|
|
265
552
|
fontWeight: FontWeight.w700,
|
|
266
553
|
),
|
|
@@ -271,300 +558,22 @@ class OnboardingMetricPill extends StatelessWidget {
|
|
|
271
558
|
}
|
|
272
559
|
}
|
|
273
560
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
final int step;
|
|
278
|
-
final int totalSteps;
|
|
279
|
-
|
|
280
|
-
@override
|
|
281
|
-
Widget build(BuildContext context) {
|
|
282
|
-
final progress = totalSteps <= 1 ? 1.0 : (step + 1) / totalSteps;
|
|
283
|
-
return Row(
|
|
284
|
-
children: <Widget>[
|
|
285
|
-
Container(
|
|
286
|
-
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
|
287
|
-
decoration: BoxDecoration(
|
|
288
|
-
color: Colors.white.withValues(alpha: 0.06),
|
|
289
|
-
borderRadius: BorderRadius.circular(999),
|
|
290
|
-
border: Border.all(color: Colors.white.withValues(alpha: 0.08)),
|
|
291
|
-
),
|
|
292
|
-
child: Row(
|
|
293
|
-
mainAxisSize: MainAxisSize.min,
|
|
294
|
-
children: <Widget>[
|
|
295
|
-
Container(
|
|
296
|
-
width: 10,
|
|
297
|
-
height: 10,
|
|
298
|
-
decoration: BoxDecoration(
|
|
299
|
-
color: Theme.of(context).colorScheme.primary,
|
|
300
|
-
shape: BoxShape.circle,
|
|
301
|
-
),
|
|
302
|
-
),
|
|
303
|
-
const SizedBox(width: 10),
|
|
304
|
-
const Text(
|
|
305
|
-
'NeoAgent Setup',
|
|
306
|
-
style: TextStyle(
|
|
307
|
-
color: Colors.white,
|
|
308
|
-
fontSize: 14,
|
|
309
|
-
fontWeight: FontWeight.w700,
|
|
310
|
-
),
|
|
311
|
-
),
|
|
312
|
-
],
|
|
313
|
-
),
|
|
314
|
-
),
|
|
315
|
-
const SizedBox(width: 16),
|
|
316
|
-
Expanded(
|
|
317
|
-
child: ClipRRect(
|
|
318
|
-
borderRadius: BorderRadius.circular(999),
|
|
319
|
-
child: TweenAnimationBuilder<double>(
|
|
320
|
-
tween: Tween<double>(begin: 0, end: progress),
|
|
321
|
-
duration: const Duration(milliseconds: 700),
|
|
322
|
-
curve: Curves.easeOutCubic,
|
|
323
|
-
builder: (context, animatedValue, _) {
|
|
324
|
-
return LinearProgressIndicator(
|
|
325
|
-
value: animatedValue,
|
|
326
|
-
minHeight: 8,
|
|
327
|
-
backgroundColor: Colors.white.withValues(alpha: 0.08),
|
|
328
|
-
valueColor: AlwaysStoppedAnimation<Color>(
|
|
329
|
-
Theme.of(context).colorScheme.primary,
|
|
330
|
-
),
|
|
331
|
-
);
|
|
332
|
-
},
|
|
333
|
-
),
|
|
334
|
-
),
|
|
335
|
-
),
|
|
336
|
-
const SizedBox(width: 16),
|
|
337
|
-
Text(
|
|
338
|
-
'${step + 1} / $totalSteps',
|
|
339
|
-
style: TextStyle(
|
|
340
|
-
color: Colors.white.withValues(alpha: 0.7),
|
|
341
|
-
fontSize: 13,
|
|
342
|
-
fontWeight: FontWeight.w700,
|
|
343
|
-
),
|
|
344
|
-
),
|
|
345
|
-
],
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
class _OnboardingContentColumn extends StatelessWidget {
|
|
351
|
-
const _OnboardingContentColumn({
|
|
352
|
-
required this.eyebrow,
|
|
353
|
-
required this.title,
|
|
354
|
-
required this.description,
|
|
355
|
-
required this.child,
|
|
356
|
-
required this.footer,
|
|
357
|
-
required this.sidePanel,
|
|
358
|
-
required this.compact,
|
|
359
|
-
});
|
|
561
|
+
/// Mono gold-ink eyebrow label, matching the design's `.eyebrow` treatment.
|
|
562
|
+
class OnboardingEyebrow extends StatelessWidget {
|
|
563
|
+
const OnboardingEyebrow(this.text, {super.key});
|
|
360
564
|
|
|
361
|
-
final String
|
|
362
|
-
final String title;
|
|
363
|
-
final String description;
|
|
364
|
-
final Widget child;
|
|
365
|
-
final Widget footer;
|
|
366
|
-
final Widget? sidePanel;
|
|
367
|
-
final bool compact;
|
|
565
|
+
final String text;
|
|
368
566
|
|
|
369
567
|
@override
|
|
370
568
|
Widget build(BuildContext context) {
|
|
371
|
-
final
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
).colorScheme.primary.withValues(alpha: 0.92),
|
|
380
|
-
fontSize: 12,
|
|
381
|
-
fontWeight: FontWeight.w800,
|
|
382
|
-
letterSpacing: 1.1,
|
|
383
|
-
),
|
|
384
|
-
),
|
|
385
|
-
const SizedBox(height: 14),
|
|
386
|
-
Text(
|
|
387
|
-
title,
|
|
388
|
-
style: TextStyle(
|
|
389
|
-
color: Colors.white,
|
|
390
|
-
fontSize: compact ? 40 : 56,
|
|
391
|
-
height: compact ? 1.04 : 1.0,
|
|
392
|
-
fontWeight: FontWeight.w800,
|
|
393
|
-
letterSpacing: compact ? -1.6 : -2.3,
|
|
394
|
-
),
|
|
395
|
-
),
|
|
396
|
-
const SizedBox(height: 18),
|
|
397
|
-
ConstrainedBox(
|
|
398
|
-
constraints: const BoxConstraints(maxWidth: 680),
|
|
399
|
-
child: Text(
|
|
400
|
-
description,
|
|
401
|
-
style: TextStyle(
|
|
402
|
-
color: Colors.white.withValues(alpha: 0.74),
|
|
403
|
-
fontSize: compact ? 17 : 19,
|
|
404
|
-
height: 1.55,
|
|
405
|
-
fontWeight: FontWeight.w500,
|
|
406
|
-
),
|
|
407
|
-
),
|
|
408
|
-
),
|
|
409
|
-
],
|
|
410
|
-
);
|
|
411
|
-
|
|
412
|
-
if (compact) {
|
|
413
|
-
return Column(
|
|
414
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
415
|
-
children: <Widget>[
|
|
416
|
-
intro,
|
|
417
|
-
const SizedBox(height: 26),
|
|
418
|
-
if (sidePanel != null) ...<Widget>[
|
|
419
|
-
sidePanel!,
|
|
420
|
-
const SizedBox(height: 18),
|
|
421
|
-
],
|
|
422
|
-
Expanded(child: child),
|
|
423
|
-
const SizedBox(height: 20),
|
|
424
|
-
footer,
|
|
425
|
-
],
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
return Column(
|
|
430
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
431
|
-
children: <Widget>[
|
|
432
|
-
Row(
|
|
433
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
434
|
-
children: <Widget>[
|
|
435
|
-
Expanded(flex: 12, child: intro),
|
|
436
|
-
if (sidePanel != null) ...<Widget>[
|
|
437
|
-
const SizedBox(width: 28),
|
|
438
|
-
Expanded(flex: 7, child: sidePanel!),
|
|
439
|
-
],
|
|
440
|
-
],
|
|
441
|
-
),
|
|
442
|
-
const SizedBox(height: 28),
|
|
443
|
-
Expanded(child: child),
|
|
444
|
-
const SizedBox(height: 22),
|
|
445
|
-
footer,
|
|
446
|
-
],
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
class _OnboardingPanel extends StatelessWidget {
|
|
452
|
-
const _OnboardingPanel({required this.child, required this.padding});
|
|
453
|
-
|
|
454
|
-
final Widget child;
|
|
455
|
-
final EdgeInsetsGeometry padding;
|
|
456
|
-
|
|
457
|
-
@override
|
|
458
|
-
Widget build(BuildContext context) {
|
|
459
|
-
return ClipRRect(
|
|
460
|
-
borderRadius: BorderRadius.circular(36),
|
|
461
|
-
child: BackdropFilter(
|
|
462
|
-
filter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
|
|
463
|
-
child: Container(
|
|
464
|
-
padding: padding,
|
|
465
|
-
decoration: BoxDecoration(
|
|
466
|
-
gradient: LinearGradient(
|
|
467
|
-
colors: <Color>[
|
|
468
|
-
Colors.white.withValues(alpha: 0.16),
|
|
469
|
-
Colors.white.withValues(alpha: 0.08),
|
|
470
|
-
const Color(0xFF111317).withValues(alpha: 0.72),
|
|
471
|
-
],
|
|
472
|
-
begin: Alignment.topLeft,
|
|
473
|
-
end: Alignment.bottomRight,
|
|
474
|
-
),
|
|
475
|
-
borderRadius: BorderRadius.circular(36),
|
|
476
|
-
border: Border.all(color: Colors.white.withValues(alpha: 0.14)),
|
|
477
|
-
boxShadow: <BoxShadow>[
|
|
478
|
-
BoxShadow(
|
|
479
|
-
color: Colors.black.withValues(alpha: 0.34),
|
|
480
|
-
blurRadius: 46,
|
|
481
|
-
offset: const Offset(0, 24),
|
|
482
|
-
),
|
|
483
|
-
],
|
|
484
|
-
),
|
|
485
|
-
child: child,
|
|
486
|
-
),
|
|
487
|
-
),
|
|
488
|
-
);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
class _OnboardingBackdrop extends StatelessWidget {
|
|
493
|
-
const _OnboardingBackdrop();
|
|
494
|
-
|
|
495
|
-
@override
|
|
496
|
-
Widget build(BuildContext context) {
|
|
497
|
-
final accent = Theme.of(context).colorScheme.primary;
|
|
498
|
-
return DecoratedBox(
|
|
499
|
-
decoration: const BoxDecoration(
|
|
500
|
-
gradient: RadialGradient(
|
|
501
|
-
center: Alignment(-0.8, -0.95),
|
|
502
|
-
radius: 1.8,
|
|
503
|
-
colors: <Color>[
|
|
504
|
-
Color(0xFF20242C),
|
|
505
|
-
Color(0xFF0C0F13),
|
|
506
|
-
Color(0xFF040506),
|
|
507
|
-
],
|
|
508
|
-
),
|
|
509
|
-
),
|
|
510
|
-
child: Stack(
|
|
511
|
-
children: <Widget>[
|
|
512
|
-
Positioned(
|
|
513
|
-
top: -120,
|
|
514
|
-
left: -80,
|
|
515
|
-
child: _GlowOrb(size: 340, color: accent.withValues(alpha: 0.24)),
|
|
516
|
-
),
|
|
517
|
-
const Positioned(
|
|
518
|
-
top: 120,
|
|
519
|
-
right: -60,
|
|
520
|
-
child: _GlowOrb(size: 300, color: Color(0x226EDBFF)),
|
|
521
|
-
),
|
|
522
|
-
const Positioned(
|
|
523
|
-
bottom: -120,
|
|
524
|
-
left: 160,
|
|
525
|
-
child: _GlowOrb(size: 420, color: Color(0x18D7B27C)),
|
|
526
|
-
),
|
|
527
|
-
Positioned.fill(
|
|
528
|
-
child: IgnorePointer(
|
|
529
|
-
child: DecoratedBox(
|
|
530
|
-
decoration: BoxDecoration(
|
|
531
|
-
gradient: LinearGradient(
|
|
532
|
-
colors: <Color>[
|
|
533
|
-
Colors.white.withValues(alpha: 0.04),
|
|
534
|
-
Colors.transparent,
|
|
535
|
-
Colors.black.withValues(alpha: 0.26),
|
|
536
|
-
],
|
|
537
|
-
begin: Alignment.topCenter,
|
|
538
|
-
end: Alignment.bottomCenter,
|
|
539
|
-
),
|
|
540
|
-
),
|
|
541
|
-
),
|
|
542
|
-
),
|
|
543
|
-
),
|
|
544
|
-
],
|
|
545
|
-
),
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
class _GlowOrb extends StatelessWidget {
|
|
551
|
-
const _GlowOrb({required this.size, required this.color});
|
|
552
|
-
|
|
553
|
-
final double size;
|
|
554
|
-
final Color color;
|
|
555
|
-
|
|
556
|
-
@override
|
|
557
|
-
Widget build(BuildContext context) {
|
|
558
|
-
return IgnorePointer(
|
|
559
|
-
child: Container(
|
|
560
|
-
width: size,
|
|
561
|
-
height: size,
|
|
562
|
-
decoration: BoxDecoration(
|
|
563
|
-
shape: BoxShape.circle,
|
|
564
|
-
boxShadow: <BoxShadow>[
|
|
565
|
-
BoxShadow(color: color, blurRadius: 160, spreadRadius: 28),
|
|
566
|
-
],
|
|
567
|
-
),
|
|
569
|
+
final p = paletteOf(context);
|
|
570
|
+
return Text(
|
|
571
|
+
text.toUpperCase(),
|
|
572
|
+
style: GoogleFonts.geistMono(
|
|
573
|
+
color: p.accentHover,
|
|
574
|
+
fontSize: 11.5,
|
|
575
|
+
fontWeight: FontWeight.w600,
|
|
576
|
+
letterSpacing: 1.8,
|
|
568
577
|
),
|
|
569
578
|
);
|
|
570
579
|
}
|