kasy-cli 1.24.0 → 1.26.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 +53 -3
- package/lib/utils/flutter-install.js +26 -1
- package/lib/utils/i18n/messages-en.js +3 -0
- package/lib/utils/i18n/messages-es.js +3 -0
- package/lib/utils/i18n/messages-pt.js +3 -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_card.dart +4 -0
- 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_sidebar.dart +6 -0
- package/templates/firebase/lib/components/kasy_tabs.dart +76 -65
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +103 -3
- package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +45 -2
- package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +37 -1
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +9 -4
- package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +1 -0
- package/templates/firebase/lib/features/authentication/ui/signin_page.dart +10 -5
- package/templates/firebase/lib/features/authentication/ui/signup_page.dart +1 -0
- 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/settings_page.dart +17 -1
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +37 -23
- package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +63 -48
- package/templates/firebase/lib/features/settings/ui/widgets/admin_card.dart +14 -6
- package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +2 -0
- 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(),
|
|
@@ -12,6 +12,7 @@ import 'package:kasy_kit/core/security/biometric_ui_bundle.dart';
|
|
|
12
12
|
import 'package:kasy_kit/core/states/logout_action.dart';
|
|
13
13
|
import 'package:kasy_kit/core/states/user_state_notifier.dart';
|
|
14
14
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
15
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
15
16
|
import 'package:kasy_kit/core/widgets/kasy_hover.dart';
|
|
16
17
|
import 'package:kasy_kit/features/settings/ui/components/avatar_component.dart';
|
|
17
18
|
import 'package:kasy_kit/features/settings/ui/components/delete_user_component.dart';
|
|
@@ -329,7 +330,18 @@ class ProfileTile extends StatelessWidget {
|
|
|
329
330
|
child: ClipRRect(
|
|
330
331
|
borderRadius: KasyRadius.smBorderRadius,
|
|
331
332
|
child: onTap != null
|
|
332
|
-
?
|
|
333
|
+
? KasyFocusRing(
|
|
334
|
+
onActivate: onTap,
|
|
335
|
+
borderRadius: KasyRadius.smBorderRadius,
|
|
336
|
+
gapColor: context.colors.surface,
|
|
337
|
+
// The InkWell keeps its tap ripple but yields focus to the ring,
|
|
338
|
+
// so the keyboard outline matches every other Kasy control.
|
|
339
|
+
child: InkWell(
|
|
340
|
+
canRequestFocus: false,
|
|
341
|
+
onTap: onTap,
|
|
342
|
+
child: content,
|
|
343
|
+
),
|
|
344
|
+
)
|
|
333
345
|
: content,
|
|
334
346
|
),
|
|
335
347
|
);
|
|
@@ -547,6 +559,8 @@ class _NavTile extends StatelessWidget {
|
|
|
547
559
|
borderRadius: KasyRadius.smBorderRadius,
|
|
548
560
|
hoverColor: c.surfaceNeutralSoft,
|
|
549
561
|
pressColor: c.onSurface,
|
|
562
|
+
focusable: true,
|
|
563
|
+
focusGapColor: c.surface,
|
|
550
564
|
onTap: onTap,
|
|
551
565
|
child: Container(
|
|
552
566
|
padding: const EdgeInsets.symmetric(
|
|
@@ -770,6 +784,8 @@ class _LogoutRow extends StatelessWidget {
|
|
|
770
784
|
return KasyHover(
|
|
771
785
|
borderRadius: KasyRadius.smBorderRadius,
|
|
772
786
|
pressColor: context.colors.error,
|
|
787
|
+
focusable: true,
|
|
788
|
+
focusGapColor: context.colors.surface,
|
|
773
789
|
onTap: onTap,
|
|
774
790
|
child: Padding(
|
|
775
791
|
padding: const EdgeInsets.symmetric(vertical: KasySpacing.sm),
|
|
@@ -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
|
);
|
|
@@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
5
5
|
import 'package:kasy_kit/core/home_widgets/home_widget_mywidget_service.dart';
|
|
6
6
|
import 'package:kasy_kit/core/shared_preferences/shared_preferences.dart';
|
|
7
7
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
8
|
+
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
8
9
|
import 'package:kasy_kit/features/settings/ui/widgets/settings_tile.dart';
|
|
9
10
|
import 'package:kasy_kit/i18n/app_locale_display.dart';
|
|
10
11
|
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
@@ -17,31 +18,40 @@ class LanguageSwitcher extends ConsumerWidget {
|
|
|
17
18
|
@override
|
|
18
19
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
19
20
|
final AppLocale current = TranslationProvider.of(context).locale;
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
return KasyFocusRing(
|
|
22
|
+
onActivate: () => _showLanguagePicker(context, ref, current),
|
|
23
|
+
borderRadius: KasyRadius.smBorderRadius,
|
|
24
|
+
child: InkWell(
|
|
25
|
+
canRequestFocus: false,
|
|
26
|
+
onTap: () => _showLanguagePicker(context, ref, current),
|
|
27
|
+
child: Padding(
|
|
28
|
+
padding: const EdgeInsets.symmetric(vertical: KasySpacing.sm),
|
|
29
|
+
child: Row(
|
|
30
|
+
children: <Widget>[
|
|
31
|
+
Icon(
|
|
32
|
+
KasyIcons.language,
|
|
33
|
+
size: 21,
|
|
34
|
+
color: context.colors.onSurface,
|
|
35
|
+
),
|
|
36
|
+
const SizedBox(width: KasySpacing.sm),
|
|
37
|
+
Expanded(
|
|
38
|
+
child: Text(
|
|
39
|
+
context.t.settings.language_title,
|
|
40
|
+
style: context.textTheme.titleMedium?.copyWith(
|
|
41
|
+
color: context.colors.onSurface,
|
|
42
|
+
),
|
|
33
43
|
),
|
|
34
44
|
),
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
Text(
|
|
46
|
+
current.nativeName,
|
|
47
|
+
style: context.textTheme.bodyMedium?.copyWith(
|
|
48
|
+
color: context.colors.muted,
|
|
49
|
+
),
|
|
40
50
|
),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
const SizedBox(width: KasySpacing.xs),
|
|
52
|
+
const SettingsListChevron(),
|
|
53
|
+
],
|
|
54
|
+
),
|
|
45
55
|
),
|
|
46
56
|
),
|
|
47
57
|
);
|
|
@@ -147,36 +157,41 @@ class _LocaleOptionTile extends StatelessWidget {
|
|
|
147
157
|
final Color primary = context.colors.primary;
|
|
148
158
|
final Color fg = isSelected ? primary : context.colors.onSurface;
|
|
149
159
|
|
|
150
|
-
return
|
|
151
|
-
|
|
160
|
+
return KasyFocusRing(
|
|
161
|
+
onActivate: onTap,
|
|
152
162
|
borderRadius: BorderRadius.circular(KasyRadius.sm),
|
|
153
|
-
child:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
child: InkWell(
|
|
164
|
+
canRequestFocus: false,
|
|
165
|
+
onTap: onTap,
|
|
166
|
+
borderRadius: BorderRadius.circular(KasyRadius.sm),
|
|
167
|
+
child: Padding(
|
|
168
|
+
padding: const EdgeInsets.symmetric(
|
|
169
|
+
horizontal: KasySpacing.xs,
|
|
170
|
+
vertical: KasySpacing.smd,
|
|
171
|
+
),
|
|
172
|
+
child: Row(
|
|
173
|
+
children: <Widget>[
|
|
174
|
+
Expanded(
|
|
175
|
+
child: Text(
|
|
176
|
+
locale.nativeName,
|
|
177
|
+
style: context.textTheme.bodyLarge?.copyWith(
|
|
178
|
+
color: fg,
|
|
179
|
+
fontWeight:
|
|
180
|
+
isSelected ? FontWeight.w600 : FontWeight.w400,
|
|
181
|
+
),
|
|
167
182
|
),
|
|
168
183
|
),
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
184
|
+
if (isSelected)
|
|
185
|
+
Container(
|
|
186
|
+
width: 10,
|
|
187
|
+
height: 10,
|
|
188
|
+
decoration: BoxDecoration(
|
|
189
|
+
color: primary,
|
|
190
|
+
shape: BoxShape.circle,
|
|
191
|
+
),
|
|
177
192
|
),
|
|
178
|
-
|
|
179
|
-
|
|
193
|
+
],
|
|
194
|
+
),
|
|
180
195
|
),
|
|
181
196
|
),
|
|
182
197
|
);
|
|
@@ -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
|
}
|
|
@@ -157,6 +157,8 @@ class SettingsTile extends StatelessWidget {
|
|
|
157
157
|
onTap: onTap,
|
|
158
158
|
hoverEnabled: false,
|
|
159
159
|
pressEnabled: false,
|
|
160
|
+
focusable: true,
|
|
161
|
+
borderRadius: KasyRadius.smBorderRadius,
|
|
160
162
|
semanticLabel: title,
|
|
161
163
|
padding: const EdgeInsets.symmetric(vertical: KasySpacing.sm),
|
|
162
164
|
child: Row(
|
|
@@ -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
|
),
|