kasy-cli 1.25.0 → 1.27.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/lib/commands/new.js +63 -3
- package/lib/utils/i18n/messages-en.js +4 -0
- package/lib/utils/i18n/messages-es.js +4 -0
- package/lib/utils/i18n/messages-pt.js +4 -0
- package/package.json +1 -1
- package/templates/firebase/lib/components/kasy_app_bar.dart +12 -6
- package/templates/firebase/lib/components/kasy_avatar.dart +17 -10
- package/templates/firebase/lib/components/kasy_checkbox.dart +24 -15
- package/templates/firebase/lib/components/kasy_date_picker.dart +27 -20
- package/templates/firebase/lib/components/kasy_otp_verification_bottom_sheet.dart +19 -14
- package/templates/firebase/lib/components/kasy_tabs.dart +75 -65
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +98 -2
- package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +45 -2
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +9 -4
- package/templates/firebase/lib/features/feedbacks/ui/widgets/add_feature_button.dart +1 -0
- package/templates/firebase/lib/features/feedbacks/ui/widgets/feature_card.dart +2 -0
- package/templates/firebase/lib/features/home/home_feed.dart +21 -5
- package/templates/firebase/lib/features/home/home_image_grid.dart +83 -58
- package/templates/firebase/lib/features/local_reminders/ui/reminder_page.dart +124 -101
- package/templates/firebase/lib/features/notifications/ui/components/notification_tile.dart +1 -0
- package/templates/firebase/lib/features/notifications/ui/widgets/notification_tile.dart +85 -85
- package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +67 -62
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +37 -23
- package/templates/firebase/lib/features/settings/ui/widgets/admin_card.dart +14 -6
- package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_banner.dart +9 -3
- package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_close_button.dart +24 -16
- package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_col.dart +29 -22
- package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_row.dart +19 -12
- package/templates/firebase/lib/i18n/en.i18n.json +2 -1
- package/templates/firebase/lib/i18n/es.i18n.json +2 -1
- package/templates/firebase/lib/i18n/pt.i18n.json +2 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import 'package:flutter/material.dart';
|
|
2
2
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
3
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
3
4
|
|
|
4
5
|
typedef OnSelectRow = void Function(int index, bool selected);
|
|
5
6
|
|
|
@@ -51,38 +52,50 @@ class _OnboardingSelectableRowGroupState
|
|
|
51
52
|
return ListView.separated(
|
|
52
53
|
physics: widget.physics,
|
|
53
54
|
shrinkWrap: true,
|
|
54
|
-
separatorBuilder: (context, index) =>
|
|
55
|
+
separatorBuilder: (context, index) =>
|
|
56
|
+
const SizedBox(height: KasySpacing.sm),
|
|
55
57
|
itemCount: widget.options.length,
|
|
56
58
|
itemBuilder: (context, index) {
|
|
57
|
-
final hasOnSelectInfo =
|
|
59
|
+
final hasOnSelectInfo =
|
|
60
|
+
widget.onSelectInfoWidget != null &&
|
|
58
61
|
widget.onSelectInfoWidget!.length > index &&
|
|
59
62
|
widget.onSelectInfoWidget![index] != null;
|
|
63
|
+
void selectRow() {
|
|
64
|
+
if (_selectedIndex == index) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
setState(() {
|
|
68
|
+
_selectedIndex = index;
|
|
69
|
+
});
|
|
70
|
+
widget.onSelect?.call(index, true);
|
|
71
|
+
}
|
|
72
|
+
|
|
60
73
|
return Column(
|
|
61
74
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
62
75
|
children: [
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
KasyFocusRing(
|
|
77
|
+
onActivate: selectRow,
|
|
65
78
|
borderRadius: KasyRadius.lgBorderRadius,
|
|
66
|
-
child:
|
|
79
|
+
child: Material(
|
|
80
|
+
color: Colors.transparent,
|
|
67
81
|
borderRadius: KasyRadius.lgBorderRadius,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
child: switch (hasOnSelectInfo && _selectedIndex == index) {
|
|
78
|
-
false => widget.options[index],
|
|
79
|
-
true => widget.options[index],
|
|
80
|
-
},
|
|
82
|
+
child: InkWell(
|
|
83
|
+
canRequestFocus: false,
|
|
84
|
+
borderRadius: KasyRadius.lgBorderRadius,
|
|
85
|
+
onTap: selectRow,
|
|
86
|
+
child: switch (hasOnSelectInfo && _selectedIndex == index) {
|
|
87
|
+
false => widget.options[index],
|
|
88
|
+
true => widget.options[index],
|
|
89
|
+
},
|
|
90
|
+
),
|
|
81
91
|
),
|
|
82
92
|
),
|
|
83
93
|
if (hasOnSelectInfo && _selectedIndex == index)
|
|
84
94
|
Padding(
|
|
85
|
-
padding: const EdgeInsets.only(
|
|
95
|
+
padding: const EdgeInsets.only(
|
|
96
|
+
top: KasySpacing.sm,
|
|
97
|
+
bottom: KasySpacing.md,
|
|
98
|
+
),
|
|
86
99
|
child: widget.onSelectInfoWidget![index],
|
|
87
100
|
),
|
|
88
101
|
],
|
|
@@ -126,26 +139,33 @@ class _OnboardingMultiSelectableRowGroupState
|
|
|
126
139
|
runSpacing: KasySpacing.sm,
|
|
127
140
|
children: widget.options.map((option) {
|
|
128
141
|
final index = widget.options.indexOf(option);
|
|
129
|
-
|
|
130
|
-
|
|
142
|
+
void toggleSelection() {
|
|
143
|
+
if (_selectedIndex.contains(index)) {
|
|
144
|
+
_selectedIndex.remove(index);
|
|
145
|
+
widget.onSelect?.call(index, false);
|
|
146
|
+
} else {
|
|
147
|
+
_selectedIndex.add(index);
|
|
148
|
+
widget.onSelect?.call(index, true);
|
|
149
|
+
}
|
|
150
|
+
setState(() {});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return KasyFocusRing(
|
|
154
|
+
onActivate: toggleSelection,
|
|
131
155
|
borderRadius: KasyRadius.mdBorderRadius,
|
|
132
|
-
child:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
title: option.title,
|
|
146
|
-
subtitle: option.subtitle,
|
|
147
|
-
selected: _selectedIndex.contains(index),
|
|
148
|
-
emoj: option.emoj,
|
|
156
|
+
child: Material(
|
|
157
|
+
color: Colors.transparent,
|
|
158
|
+
borderRadius: KasyRadius.mdBorderRadius,
|
|
159
|
+
child: InkWell(
|
|
160
|
+
canRequestFocus: false,
|
|
161
|
+
splashColor: context.colors.primary.withValues(alpha: .1),
|
|
162
|
+
onTap: toggleSelection,
|
|
163
|
+
child: SelectableRowTile(
|
|
164
|
+
title: option.title,
|
|
165
|
+
subtitle: option.subtitle,
|
|
166
|
+
selected: _selectedIndex.contains(index),
|
|
167
|
+
emoj: option.emoj,
|
|
168
|
+
),
|
|
149
169
|
),
|
|
150
170
|
),
|
|
151
171
|
);
|
|
@@ -205,15 +225,11 @@ class _SelectableRowTileState extends State<SelectableRowTile>
|
|
|
205
225
|
_opacityAnimation = Tween(
|
|
206
226
|
begin: 0.0,
|
|
207
227
|
end: 1.0,
|
|
208
|
-
).animate(
|
|
209
|
-
CurvedAnimation(parent: _controller, curve: Curves.ease),
|
|
210
|
-
);
|
|
228
|
+
).animate(CurvedAnimation(parent: _controller, curve: Curves.ease));
|
|
211
229
|
_iconSizeAnimation = Tween(
|
|
212
230
|
begin: 0.0,
|
|
213
231
|
end: 1.0,
|
|
214
|
-
).animate(
|
|
215
|
-
CurvedAnimation(parent: _controller, curve: Curves.elasticOut),
|
|
216
|
-
);
|
|
232
|
+
).animate(CurvedAnimation(parent: _controller, curve: Curves.elasticOut));
|
|
217
233
|
if (widget.selected) {
|
|
218
234
|
_controller.forward();
|
|
219
235
|
}
|
|
@@ -267,9 +283,7 @@ class _SelectableRowTileState extends State<SelectableRowTile>
|
|
|
267
283
|
padding: const EdgeInsets.only(right: KasySpacing.md),
|
|
268
284
|
child: Text(
|
|
269
285
|
widget.emoj!,
|
|
270
|
-
style: context.textTheme.titleMedium?.copyWith(
|
|
271
|
-
fontSize: 28,
|
|
272
|
-
),
|
|
286
|
+
style: context.textTheme.titleMedium?.copyWith(fontSize: 28),
|
|
273
287
|
),
|
|
274
288
|
),
|
|
275
289
|
),
|
|
@@ -282,8 +296,9 @@ class _SelectableRowTileState extends State<SelectableRowTile>
|
|
|
282
296
|
widget.title!,
|
|
283
297
|
style: context.textTheme.bodyLarge?.copyWith(
|
|
284
298
|
color: colors.onSurface,
|
|
285
|
-
fontWeight:
|
|
286
|
-
|
|
299
|
+
fontWeight: widget.selected
|
|
300
|
+
? FontWeight.w700
|
|
301
|
+
: FontWeight.w600,
|
|
287
302
|
),
|
|
288
303
|
),
|
|
289
304
|
if (widget.subtitle != null)
|
|
@@ -301,10 +316,7 @@ class _SelectableRowTileState extends State<SelectableRowTile>
|
|
|
301
316
|
),
|
|
302
317
|
const SizedBox(width: KasySpacing.sm),
|
|
303
318
|
if (!widget.selected)
|
|
304
|
-
Flexible(
|
|
305
|
-
flex: 0,
|
|
306
|
-
child: RoundRadioBox.unselected(context),
|
|
307
|
-
),
|
|
319
|
+
Flexible(flex: 0, child: RoundRadioBox.unselected(context)),
|
|
308
320
|
if (widget.selected)
|
|
309
321
|
Flexible(
|
|
310
322
|
flex: 0,
|
|
@@ -371,10 +383,7 @@ class RoundRadioBox extends StatelessWidget {
|
|
|
371
383
|
decoration: BoxDecoration(
|
|
372
384
|
color: bgColor,
|
|
373
385
|
shape: BoxShape.circle,
|
|
374
|
-
border: Border.all(
|
|
375
|
-
color: borderColor,
|
|
376
|
-
width: 2,
|
|
377
|
-
),
|
|
386
|
+
border: Border.all(color: borderColor, width: 2),
|
|
378
387
|
),
|
|
379
388
|
child: Center(
|
|
380
389
|
child: icon != null
|
|
@@ -382,11 +391,7 @@ class RoundRadioBox extends StatelessWidget {
|
|
|
382
391
|
opacity: iconOpacity,
|
|
383
392
|
child: Transform.scale(
|
|
384
393
|
scale: iconSize,
|
|
385
|
-
child: Icon(
|
|
386
|
-
icon,
|
|
387
|
-
color: context.colors.onPrimary,
|
|
388
|
-
size: 15,
|
|
389
|
-
),
|
|
394
|
+
child: Icon(icon, color: context.colors.onPrimary, size: 15),
|
|
390
395
|
),
|
|
391
396
|
)
|
|
392
397
|
: const SizedBox.shrink(),
|
|
@@ -11,6 +11,7 @@ import 'package:kasy_kit/core/data/repositories/user_repository.dart';
|
|
|
11
11
|
import 'package:kasy_kit/core/states/models/user_state.dart';
|
|
12
12
|
import 'package:kasy_kit/core/states/user_state_notifier.dart';
|
|
13
13
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
14
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
14
15
|
import 'package:kasy_kit/features/settings/ui/widgets/avatar_utils.dart';
|
|
15
16
|
import 'package:kasy_kit/features/settings/ui/widgets/round_progress.dart';
|
|
16
17
|
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
@@ -57,12 +58,18 @@ class _EditableUserAvatarState extends ConsumerState<EditableUserAvatar> {
|
|
|
57
58
|
final displayAvatarPath = _optimisticAvatarUrl ?? avatarPath;
|
|
58
59
|
final double d = widget.diameter ?? KasyAvatarSize.medium.diameter;
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
final VoidCallback? onTapAvatar = userId != null && !_isUploading
|
|
62
|
+
? () => _onTapAvatar(context, userState, avatarPath)
|
|
63
|
+
: null;
|
|
64
|
+
|
|
65
|
+
return KasyFocusRing(
|
|
66
|
+
enabled: onTapAvatar != null,
|
|
67
|
+
onActivate: onTapAvatar,
|
|
68
|
+
borderRadius: BorderRadius.circular(999),
|
|
69
|
+
child: GestureDetector(
|
|
70
|
+
behavior: HitTestBehavior.opaque,
|
|
71
|
+
onTap: onTapAvatar,
|
|
72
|
+
child: Padding(
|
|
66
73
|
padding: const EdgeInsets.all(6),
|
|
67
74
|
child: Stack(
|
|
68
75
|
clipBehavior: Clip.none,
|
|
@@ -103,6 +110,7 @@ class _EditableUserAvatarState extends ConsumerState<EditableUserAvatar> {
|
|
|
103
110
|
),
|
|
104
111
|
],
|
|
105
112
|
),
|
|
113
|
+
),
|
|
106
114
|
),
|
|
107
115
|
);
|
|
108
116
|
}
|
|
@@ -313,24 +321,30 @@ class _BottomSheetTile extends StatelessWidget {
|
|
|
313
321
|
@override
|
|
314
322
|
Widget build(BuildContext context) {
|
|
315
323
|
final Color fg = color ?? context.colors.onSurface;
|
|
316
|
-
return
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
child:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
324
|
+
return KasyFocusRing(
|
|
325
|
+
onActivate: onTap,
|
|
326
|
+
borderRadius: BorderRadius.circular(KasyRadius.sm),
|
|
327
|
+
gapColor: context.colors.surface,
|
|
328
|
+
child: InkWell(
|
|
329
|
+
canRequestFocus: false,
|
|
330
|
+
onTap: onTap,
|
|
331
|
+
child: Padding(
|
|
332
|
+
padding: const EdgeInsets.symmetric(
|
|
333
|
+
horizontal: KasySpacing.md,
|
|
334
|
+
vertical: KasySpacing.smd,
|
|
335
|
+
),
|
|
336
|
+
child: Row(
|
|
337
|
+
children: [
|
|
338
|
+
if (icon != null) ...[
|
|
339
|
+
Icon(icon, size: 22, color: fg),
|
|
340
|
+
const SizedBox(width: KasySpacing.sm),
|
|
341
|
+
],
|
|
342
|
+
Text(
|
|
343
|
+
label,
|
|
344
|
+
style: context.textTheme.bodyLarge?.copyWith(color: fg),
|
|
345
|
+
),
|
|
328
346
|
],
|
|
329
|
-
|
|
330
|
-
label,
|
|
331
|
-
style: context.textTheme.bodyLarge?.copyWith(color: fg),
|
|
332
|
-
),
|
|
333
|
-
],
|
|
347
|
+
),
|
|
334
348
|
),
|
|
335
349
|
),
|
|
336
350
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'package:flutter/material.dart';
|
|
2
2
|
import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
|
|
3
3
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
4
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
4
5
|
|
|
5
6
|
/// Here is just a simple content card
|
|
6
7
|
class AdminPanelCard extends StatelessWidget {
|
|
@@ -21,12 +22,18 @@ class AdminPanelCard extends StatelessWidget {
|
|
|
21
22
|
|
|
22
23
|
@override
|
|
23
24
|
Widget build(BuildContext context) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
void handleActivate() {
|
|
26
|
+
KasyHaptics.medium(context);
|
|
27
|
+
onTap.call();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return KasyFocusRing(
|
|
31
|
+
onActivate: handleActivate,
|
|
32
|
+
borderRadius: BorderRadius.circular(KasyRadius.sm),
|
|
33
|
+
child: InkWell(
|
|
34
|
+
canRequestFocus: false,
|
|
35
|
+
onTap: handleActivate,
|
|
36
|
+
child: Card(
|
|
30
37
|
color: backgroundColor ?? context.colors.primary.withValues(alpha: .15),
|
|
31
38
|
margin: EdgeInsets.zero,
|
|
32
39
|
elevation: 0,
|
|
@@ -53,6 +60,7 @@ class AdminPanelCard extends StatelessWidget {
|
|
|
53
60
|
],
|
|
54
61
|
),
|
|
55
62
|
),
|
|
63
|
+
),
|
|
56
64
|
),
|
|
57
65
|
);
|
|
58
66
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'package:flutter/material.dart';
|
|
2
2
|
import 'package:google_fonts/google_fonts.dart';
|
|
3
3
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
4
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
4
5
|
|
|
5
6
|
typedef PremiumWideBannerOnTap = void Function();
|
|
6
7
|
|
|
@@ -32,9 +33,13 @@ class PremiumWideBanner extends StatelessWidget {
|
|
|
32
33
|
color: bgColor,
|
|
33
34
|
// border: Border.all(color: borderColor),
|
|
34
35
|
),
|
|
35
|
-
child:
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
child: KasyFocusRing(
|
|
37
|
+
onActivate: () => onTap(),
|
|
38
|
+
borderRadius: BorderRadius.zero,
|
|
39
|
+
child: InkWell(
|
|
40
|
+
canRequestFocus: false,
|
|
41
|
+
onTap: () => onTap(),
|
|
42
|
+
child: Row(
|
|
38
43
|
children: [
|
|
39
44
|
Image.asset(
|
|
40
45
|
imagePath,
|
|
@@ -72,6 +77,7 @@ class PremiumWideBanner extends StatelessWidget {
|
|
|
72
77
|
const SizedBox(width: KasySpacing.lg),
|
|
73
78
|
],
|
|
74
79
|
),
|
|
80
|
+
),
|
|
75
81
|
),
|
|
76
82
|
),
|
|
77
83
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'package:flutter/material.dart';
|
|
2
2
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
3
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
4
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
4
5
|
|
|
5
6
|
class AppCloseButtonComponent extends ConsumerWidget {
|
|
6
7
|
final ValueNotifier<bool> showCloseBtn;
|
|
@@ -34,24 +35,31 @@ class AppCloseButton extends StatelessWidget {
|
|
|
34
35
|
|
|
35
36
|
@override
|
|
36
37
|
Widget build(BuildContext context) {
|
|
38
|
+
final VoidCallback? onClose = onTap;
|
|
37
39
|
return Material(
|
|
38
40
|
color: Colors.transparent,
|
|
39
|
-
child:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
child:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
color: context.colors.
|
|
54
|
-
|
|
41
|
+
child: KasyFocusRing(
|
|
42
|
+
enabled: onClose != null,
|
|
43
|
+
onActivate: onClose,
|
|
44
|
+
borderRadius: BorderRadius.circular(999),
|
|
45
|
+
child: InkWell(
|
|
46
|
+
canRequestFocus: false,
|
|
47
|
+
onTapUp: (_) {
|
|
48
|
+
onClose?.call();
|
|
49
|
+
},
|
|
50
|
+
child: Ink(
|
|
51
|
+
width: 32,
|
|
52
|
+
height: 32,
|
|
53
|
+
decoration: BoxDecoration(
|
|
54
|
+
shape: BoxShape.circle,
|
|
55
|
+
color: context.colors.onBackground.withValues(alpha: 0.6),
|
|
56
|
+
),
|
|
57
|
+
child: Center(
|
|
58
|
+
child: Icon(
|
|
59
|
+
KasyIcons.close,
|
|
60
|
+
color: context.colors.background,
|
|
61
|
+
size: 21,
|
|
62
|
+
),
|
|
55
63
|
),
|
|
56
64
|
),
|
|
57
65
|
),
|
|
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|
|
4
4
|
import 'package:flutter_animate/flutter_animate.dart';
|
|
5
5
|
import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
|
|
6
6
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
7
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
7
8
|
import 'package:kasy_kit/features/subscriptions/ui/widgets/selectable_row.dart';
|
|
8
9
|
|
|
9
10
|
|
|
@@ -43,6 +44,17 @@ class _SelectableColGroupState<T> extends State<SelectableColGroup<T>> {
|
|
|
43
44
|
|
|
44
45
|
OnSelectItem<T> get onSelectItem => widget.onSelectItem;
|
|
45
46
|
|
|
47
|
+
void _selectIndex(int i) {
|
|
48
|
+
setState(() {
|
|
49
|
+
if (selectedIndex == i) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
KasyHaptics.heavy(context);
|
|
53
|
+
selectedIndex = i;
|
|
54
|
+
onSelectItem(widget.items[i].data);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
@override
|
|
47
59
|
Widget build(BuildContext context) {
|
|
48
60
|
return IntrinsicHeight(
|
|
@@ -53,29 +65,24 @@ class _SelectableColGroupState<T> extends State<SelectableColGroup<T>> {
|
|
|
53
65
|
children: [
|
|
54
66
|
for (var i = 0; i < widget.items.length; i++)
|
|
55
67
|
Expanded(
|
|
56
|
-
child:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
child: KasyFocusRing(
|
|
69
|
+
onActivate: () => _selectIndex(i),
|
|
70
|
+
borderRadius: KasyRadius.lgBorderRadius,
|
|
71
|
+
child: GestureDetector(
|
|
72
|
+
onTap: () => _selectIndex(i),
|
|
73
|
+
child: Animate(
|
|
74
|
+
effects: [
|
|
75
|
+
FadeEffect(
|
|
76
|
+
delay: Duration(milliseconds: 100 + 100 * i),
|
|
77
|
+
duration: const Duration(milliseconds: 500),
|
|
78
|
+
),
|
|
79
|
+
],
|
|
80
|
+
child: SelectableCol.fromOption(
|
|
81
|
+
key: ValueKey('item_$i'),
|
|
82
|
+
widget.items[i],
|
|
83
|
+
selected: selectedIndex == i,
|
|
84
|
+
brightness: widget.brightness,
|
|
72
85
|
),
|
|
73
|
-
],
|
|
74
|
-
child: SelectableCol.fromOption(
|
|
75
|
-
key: ValueKey('item_$i'),
|
|
76
|
-
widget.items[i],
|
|
77
|
-
selected: selectedIndex == i,
|
|
78
|
-
brightness: widget.brightness,
|
|
79
86
|
),
|
|
80
87
|
),
|
|
81
88
|
),
|
|
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|
|
2
2
|
import 'package:flutter_animate/flutter_animate.dart';
|
|
3
3
|
import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
|
|
4
4
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
5
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
5
6
|
|
|
6
7
|
typedef OnSelectItem<T> = void Function(T data);
|
|
7
8
|
|
|
@@ -34,23 +35,28 @@ class _SelectableRowGroupState<T> extends State<SelectableRowGroup<T>> {
|
|
|
34
35
|
|
|
35
36
|
OnSelectItem<T> get onSelectItem => widget.onSelectItem;
|
|
36
37
|
|
|
38
|
+
void _selectIndex(int i) {
|
|
39
|
+
setState(() {
|
|
40
|
+
if (selectedIndex == i) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
KasyHaptics.heavy(context);
|
|
44
|
+
selectedIndex = i;
|
|
45
|
+
onSelectItem(widget.items[i].data);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
37
49
|
@override
|
|
38
50
|
Widget build(BuildContext context) {
|
|
39
51
|
return Column(
|
|
40
52
|
children: [
|
|
41
53
|
for (var i = 0; i < widget.items.length; i++)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
KasyHaptics.heavy(context);
|
|
49
|
-
selectedIndex = i;
|
|
50
|
-
onSelectItem(widget.items[i].data);
|
|
51
|
-
});
|
|
52
|
-
},
|
|
53
|
-
child: Padding(
|
|
54
|
+
KasyFocusRing(
|
|
55
|
+
onActivate: () => _selectIndex(i),
|
|
56
|
+
borderRadius: KasyRadius.mdBorderRadius,
|
|
57
|
+
child: GestureDetector(
|
|
58
|
+
onTap: () => _selectIndex(i),
|
|
59
|
+
child: Padding(
|
|
54
60
|
padding: EdgeInsets.only(
|
|
55
61
|
bottom: i == widget.items.length - 1 ? 0 : KasySpacing.sm,
|
|
56
62
|
),
|
|
@@ -69,6 +75,7 @@ class _SelectableRowGroupState<T> extends State<SelectableRowGroup<T>> {
|
|
|
69
75
|
),
|
|
70
76
|
),
|
|
71
77
|
),
|
|
78
|
+
),
|
|
72
79
|
),
|
|
73
80
|
],
|
|
74
81
|
);
|