@appiq/flutter-workflow 1.0.0 → 1.2.0
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/CHANGELOG.md +92 -0
- package/CONTRIBUTING.md +298 -0
- package/agents/claude/cubit-agent.md +63 -0
- package/agents/claude/data-agent.md +83 -0
- package/agents/claude/domain-agent.md +76 -0
- package/agents/claude/orchestrator.md +41 -0
- package/agents/claude/po-agent.md +42 -0
- package/agents/claude/security-agent.md +91 -0
- package/agents/claude/test-agent.md +114 -0
- package/agents/claude/ui-agent.md +56 -0
- package/agents/ui-agent.md +231 -67
- package/bin/cli.js +7 -2
- package/package.json +3 -2
- package/templates/platform-adaptive-widget-template.dart +407 -0
- package/templates/pretty-ui-examples.md +597 -0
@@ -0,0 +1,407 @@
|
|
1
|
+
import 'package:flutter/cupertino.dart';
|
2
|
+
import 'package:flutter/material.dart';
|
3
|
+
import 'package:flutter/foundation.dart';
|
4
|
+
|
5
|
+
/// Platform-adaptive widget template for creating native-feeling components
|
6
|
+
///
|
7
|
+
/// This template demonstrates how to create widgets that automatically
|
8
|
+
/// adapt to iOS (Cupertino) and Android (Material) design languages
|
9
|
+
///
|
10
|
+
/// Usage Example:
|
11
|
+
/// ```dart
|
12
|
+
/// AdaptiveButton(
|
13
|
+
/// onPressed: () => print('Pressed'),
|
14
|
+
/// child: Text('Click me'),
|
15
|
+
/// )
|
16
|
+
/// ```
|
17
|
+
class AdaptiveButton extends StatelessWidget {
|
18
|
+
const AdaptiveButton({
|
19
|
+
super.key,
|
20
|
+
required this.onPressed,
|
21
|
+
required this.child,
|
22
|
+
this.variant = AdaptiveButtonVariant.primary,
|
23
|
+
});
|
24
|
+
|
25
|
+
final VoidCallback? onPressed;
|
26
|
+
final Widget child;
|
27
|
+
final AdaptiveButtonVariant variant;
|
28
|
+
|
29
|
+
@override
|
30
|
+
Widget build(BuildContext context) {
|
31
|
+
switch (Theme.of(context).platform) {
|
32
|
+
case TargetPlatform.iOS:
|
33
|
+
case TargetPlatform.macOS:
|
34
|
+
return _buildCupertinoButton(context);
|
35
|
+
case TargetPlatform.android:
|
36
|
+
case TargetPlatform.fuchsia:
|
37
|
+
case TargetPlatform.linux:
|
38
|
+
case TargetPlatform.windows:
|
39
|
+
default:
|
40
|
+
return _buildMaterialButton(context);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
Widget _buildCupertinoButton(BuildContext context) {
|
45
|
+
switch (variant) {
|
46
|
+
case AdaptiveButtonVariant.primary:
|
47
|
+
return CupertinoButton.filled(
|
48
|
+
onPressed: onPressed,
|
49
|
+
child: child,
|
50
|
+
);
|
51
|
+
case AdaptiveButtonVariant.secondary:
|
52
|
+
return CupertinoButton(
|
53
|
+
onPressed: onPressed,
|
54
|
+
child: child,
|
55
|
+
);
|
56
|
+
case AdaptiveButtonVariant.destructive:
|
57
|
+
return CupertinoButton.filled(
|
58
|
+
onPressed: onPressed,
|
59
|
+
child: child,
|
60
|
+
);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
Widget _buildMaterialButton(BuildContext context) {
|
65
|
+
switch (variant) {
|
66
|
+
case AdaptiveButtonVariant.primary:
|
67
|
+
return FilledButton(
|
68
|
+
onPressed: onPressed,
|
69
|
+
child: child,
|
70
|
+
);
|
71
|
+
case AdaptiveButtonVariant.secondary:
|
72
|
+
return OutlinedButton(
|
73
|
+
onPressed: onPressed,
|
74
|
+
child: child,
|
75
|
+
);
|
76
|
+
case AdaptiveButtonVariant.destructive:
|
77
|
+
return FilledButton(
|
78
|
+
onPressed: onPressed,
|
79
|
+
style: FilledButton.styleFrom(
|
80
|
+
backgroundColor: Theme.of(context).colorScheme.error,
|
81
|
+
foregroundColor: Theme.of(context).colorScheme.onError,
|
82
|
+
),
|
83
|
+
child: child,
|
84
|
+
);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
enum AdaptiveButtonVariant {
|
90
|
+
primary,
|
91
|
+
secondary,
|
92
|
+
destructive,
|
93
|
+
}
|
94
|
+
|
95
|
+
/// Platform-adaptive navigation bar
|
96
|
+
class AdaptiveNavigationBar extends StatelessWidget implements PreferredSizeWidget {
|
97
|
+
const AdaptiveNavigationBar({
|
98
|
+
super.key,
|
99
|
+
this.title,
|
100
|
+
this.leading,
|
101
|
+
this.actions,
|
102
|
+
this.backgroundColor,
|
103
|
+
});
|
104
|
+
|
105
|
+
final Widget? title;
|
106
|
+
final Widget? leading;
|
107
|
+
final List<Widget>? actions;
|
108
|
+
final Color? backgroundColor;
|
109
|
+
|
110
|
+
@override
|
111
|
+
Widget build(BuildContext context) {
|
112
|
+
switch (Theme.of(context).platform) {
|
113
|
+
case TargetPlatform.iOS:
|
114
|
+
case TargetPlatform.macOS:
|
115
|
+
return CupertinoNavigationBar(
|
116
|
+
middle: title,
|
117
|
+
leading: leading,
|
118
|
+
trailing: actions?.isNotEmpty == true
|
119
|
+
? Row(
|
120
|
+
mainAxisSize: MainAxisSize.min,
|
121
|
+
children: actions!,
|
122
|
+
)
|
123
|
+
: null,
|
124
|
+
backgroundColor: backgroundColor,
|
125
|
+
);
|
126
|
+
case TargetPlatform.android:
|
127
|
+
case TargetPlatform.fuchsia:
|
128
|
+
case TargetPlatform.linux:
|
129
|
+
case TargetPlatform.windows:
|
130
|
+
default:
|
131
|
+
return AppBar(
|
132
|
+
title: title,
|
133
|
+
leading: leading,
|
134
|
+
actions: actions,
|
135
|
+
backgroundColor: backgroundColor,
|
136
|
+
);
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
@override
|
141
|
+
Size get preferredSize {
|
142
|
+
switch (defaultTargetPlatform) {
|
143
|
+
case TargetPlatform.iOS:
|
144
|
+
case TargetPlatform.macOS:
|
145
|
+
return const Size.fromHeight(44.0);
|
146
|
+
case TargetPlatform.android:
|
147
|
+
case TargetPlatform.fuchsia:
|
148
|
+
case TargetPlatform.linux:
|
149
|
+
case TargetPlatform.windows:
|
150
|
+
default:
|
151
|
+
return const Size.fromHeight(56.0);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
/// Platform-adaptive loading indicator
|
157
|
+
class AdaptiveLoadingIndicator extends StatelessWidget {
|
158
|
+
const AdaptiveLoadingIndicator({
|
159
|
+
super.key,
|
160
|
+
this.size,
|
161
|
+
this.color,
|
162
|
+
});
|
163
|
+
|
164
|
+
final double? size;
|
165
|
+
final Color? color;
|
166
|
+
|
167
|
+
@override
|
168
|
+
Widget build(BuildContext context) {
|
169
|
+
switch (Theme.of(context).platform) {
|
170
|
+
case TargetPlatform.iOS:
|
171
|
+
case TargetPlatform.macOS:
|
172
|
+
return CupertinoActivityIndicator(
|
173
|
+
radius: size != null ? size! / 2 : 10.0,
|
174
|
+
color: color,
|
175
|
+
);
|
176
|
+
case TargetPlatform.android:
|
177
|
+
case TargetPlatform.fuchsia:
|
178
|
+
case TargetPlatform.linux:
|
179
|
+
case TargetPlatform.windows:
|
180
|
+
default:
|
181
|
+
return CircularProgressIndicator(
|
182
|
+
strokeWidth: 2.0,
|
183
|
+
color: color,
|
184
|
+
);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
/// Platform-adaptive switch
|
190
|
+
class AdaptiveSwitch extends StatelessWidget {
|
191
|
+
const AdaptiveSwitch({
|
192
|
+
super.key,
|
193
|
+
required this.value,
|
194
|
+
required this.onChanged,
|
195
|
+
this.activeColor,
|
196
|
+
});
|
197
|
+
|
198
|
+
final bool value;
|
199
|
+
final ValueChanged<bool>? onChanged;
|
200
|
+
final Color? activeColor;
|
201
|
+
|
202
|
+
@override
|
203
|
+
Widget build(BuildContext context) {
|
204
|
+
switch (Theme.of(context).platform) {
|
205
|
+
case TargetPlatform.iOS:
|
206
|
+
case TargetPlatform.macOS:
|
207
|
+
return CupertinoSwitch(
|
208
|
+
value: value,
|
209
|
+
onChanged: onChanged,
|
210
|
+
activeColor: activeColor,
|
211
|
+
);
|
212
|
+
case TargetPlatform.android:
|
213
|
+
case TargetPlatform.fuchsia:
|
214
|
+
case TargetPlatform.linux:
|
215
|
+
case TargetPlatform.windows:
|
216
|
+
default:
|
217
|
+
return Switch(
|
218
|
+
value: value,
|
219
|
+
onChanged: onChanged,
|
220
|
+
activeColor: activeColor,
|
221
|
+
);
|
222
|
+
}
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
/// Platform-adaptive dialog
|
227
|
+
class AdaptiveDialog {
|
228
|
+
static Future<T?> show<T>({
|
229
|
+
required BuildContext context,
|
230
|
+
required String title,
|
231
|
+
required String content,
|
232
|
+
String? cancelText,
|
233
|
+
String? confirmText,
|
234
|
+
VoidCallback? onCancel,
|
235
|
+
VoidCallback? onConfirm,
|
236
|
+
}) {
|
237
|
+
switch (Theme.of(context).platform) {
|
238
|
+
case TargetPlatform.iOS:
|
239
|
+
case TargetPlatform.macOS:
|
240
|
+
return showCupertinoDialog<T>(
|
241
|
+
context: context,
|
242
|
+
builder: (context) => CupertinoAlertDialog(
|
243
|
+
title: Text(title),
|
244
|
+
content: Text(content),
|
245
|
+
actions: [
|
246
|
+
if (cancelText != null)
|
247
|
+
CupertinoDialogAction(
|
248
|
+
onPressed: () {
|
249
|
+
Navigator.of(context).pop();
|
250
|
+
onCancel?.call();
|
251
|
+
},
|
252
|
+
child: Text(cancelText),
|
253
|
+
),
|
254
|
+
if (confirmText != null)
|
255
|
+
CupertinoDialogAction(
|
256
|
+
isDestructiveAction: true,
|
257
|
+
onPressed: () {
|
258
|
+
Navigator.of(context).pop();
|
259
|
+
onConfirm?.call();
|
260
|
+
},
|
261
|
+
child: Text(confirmText),
|
262
|
+
),
|
263
|
+
],
|
264
|
+
),
|
265
|
+
);
|
266
|
+
case TargetPlatform.android:
|
267
|
+
case TargetPlatform.fuchsia:
|
268
|
+
case TargetPlatform.linux:
|
269
|
+
case TargetPlatform.windows:
|
270
|
+
default:
|
271
|
+
return showDialog<T>(
|
272
|
+
context: context,
|
273
|
+
builder: (context) => AlertDialog(
|
274
|
+
title: Text(title),
|
275
|
+
content: Text(content),
|
276
|
+
actions: [
|
277
|
+
if (cancelText != null)
|
278
|
+
TextButton(
|
279
|
+
onPressed: () {
|
280
|
+
Navigator.of(context).pop();
|
281
|
+
onCancel?.call();
|
282
|
+
},
|
283
|
+
child: Text(cancelText),
|
284
|
+
),
|
285
|
+
if (confirmText != null)
|
286
|
+
FilledButton(
|
287
|
+
onPressed: () {
|
288
|
+
Navigator.of(context).pop();
|
289
|
+
onConfirm?.call();
|
290
|
+
},
|
291
|
+
child: Text(confirmText),
|
292
|
+
),
|
293
|
+
],
|
294
|
+
),
|
295
|
+
);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
300
|
+
/// Pretty UI Card with modern design
|
301
|
+
class PrettyCard extends StatelessWidget {
|
302
|
+
const PrettyCard({
|
303
|
+
super.key,
|
304
|
+
required this.child,
|
305
|
+
this.padding,
|
306
|
+
this.margin,
|
307
|
+
this.borderRadius,
|
308
|
+
this.elevation,
|
309
|
+
this.shadowColor,
|
310
|
+
this.backgroundColor,
|
311
|
+
this.onTap,
|
312
|
+
});
|
313
|
+
|
314
|
+
final Widget child;
|
315
|
+
final EdgeInsetsGeometry? padding;
|
316
|
+
final EdgeInsetsGeometry? margin;
|
317
|
+
final BorderRadius? borderRadius;
|
318
|
+
final double? elevation;
|
319
|
+
final Color? shadowColor;
|
320
|
+
final Color? backgroundColor;
|
321
|
+
final VoidCallback? onTap;
|
322
|
+
|
323
|
+
@override
|
324
|
+
Widget build(BuildContext context) {
|
325
|
+
final theme = Theme.of(context);
|
326
|
+
final defaultBorderRadius = BorderRadius.circular(16.0);
|
327
|
+
|
328
|
+
return Container(
|
329
|
+
margin: margin ?? const EdgeInsets.all(8.0),
|
330
|
+
child: Material(
|
331
|
+
color: backgroundColor ?? theme.colorScheme.surface,
|
332
|
+
borderRadius: borderRadius ?? defaultBorderRadius,
|
333
|
+
elevation: elevation ?? 2.0,
|
334
|
+
shadowColor: shadowColor ?? theme.shadowColor.withOpacity(0.1),
|
335
|
+
child: InkWell(
|
336
|
+
onTap: onTap,
|
337
|
+
borderRadius: borderRadius ?? defaultBorderRadius,
|
338
|
+
child: Padding(
|
339
|
+
padding: padding ?? const EdgeInsets.all(16.0),
|
340
|
+
child: child,
|
341
|
+
),
|
342
|
+
),
|
343
|
+
),
|
344
|
+
);
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
/// Modern gradient button with pretty UI design
|
349
|
+
class PrettyGradientButton extends StatelessWidget {
|
350
|
+
const PrettyGradientButton({
|
351
|
+
super.key,
|
352
|
+
required this.onPressed,
|
353
|
+
required this.child,
|
354
|
+
this.gradient,
|
355
|
+
this.borderRadius,
|
356
|
+
this.elevation,
|
357
|
+
this.padding,
|
358
|
+
});
|
359
|
+
|
360
|
+
final VoidCallback? onPressed;
|
361
|
+
final Widget child;
|
362
|
+
final Gradient? gradient;
|
363
|
+
final BorderRadius? borderRadius;
|
364
|
+
final double? elevation;
|
365
|
+
final EdgeInsetsGeometry? padding;
|
366
|
+
|
367
|
+
@override
|
368
|
+
Widget build(BuildContext context) {
|
369
|
+
final theme = Theme.of(context);
|
370
|
+
final defaultGradient = LinearGradient(
|
371
|
+
colors: [
|
372
|
+
theme.colorScheme.primary,
|
373
|
+
theme.colorScheme.primary.withOpacity(0.8),
|
374
|
+
],
|
375
|
+
begin: Alignment.topLeft,
|
376
|
+
end: Alignment.bottomRight,
|
377
|
+
);
|
378
|
+
|
379
|
+
return Container(
|
380
|
+
decoration: BoxDecoration(
|
381
|
+
gradient: gradient ?? defaultGradient,
|
382
|
+
borderRadius: borderRadius ?? BorderRadius.circular(12.0),
|
383
|
+
boxShadow: [
|
384
|
+
BoxShadow(
|
385
|
+
color: theme.colorScheme.primary.withOpacity(0.3),
|
386
|
+
blurRadius: elevation ?? 8.0,
|
387
|
+
offset: const Offset(0, 4),
|
388
|
+
),
|
389
|
+
],
|
390
|
+
),
|
391
|
+
child: Material(
|
392
|
+
color: Colors.transparent,
|
393
|
+
child: InkWell(
|
394
|
+
onTap: onPressed,
|
395
|
+
borderRadius: borderRadius ?? BorderRadius.circular(12.0),
|
396
|
+
child: Padding(
|
397
|
+
padding: padding ?? const EdgeInsets.symmetric(
|
398
|
+
horizontal: 24.0,
|
399
|
+
vertical: 12.0,
|
400
|
+
),
|
401
|
+
child: child,
|
402
|
+
),
|
403
|
+
),
|
404
|
+
),
|
405
|
+
);
|
406
|
+
}
|
407
|
+
}
|