kasy-cli 1.38.0 → 1.39.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.
Files changed (102) hide show
  1. package/lib/scaffold/CHANGELOG.json +14 -0
  2. package/lib/scaffold/backends/api/patch/README.md +15 -0
  3. package/lib/scaffold/backends/api/patch/lib/features/notifications/api/device_api.dart +11 -6
  4. package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +9 -1
  5. package/lib/scaffold/backends/api/pubspec.yaml.tpl +1 -0
  6. package/lib/scaffold/backends/patch-base-hashes.json +6 -6
  7. package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +3 -1
  8. package/lib/scaffold/backends/supabase/edge-functions/send-push-notification/index.ts +3 -0
  9. package/lib/scaffold/backends/supabase/migrations/20240101000012_welcome_decouple_from_push.sql +62 -0
  10. package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/device_api.dart +11 -6
  11. package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +7 -0
  12. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +1 -0
  13. package/lib/scaffold/shared/generator-utils.js +12 -6
  14. package/package.json +1 -1
  15. package/templates/firebase/.firebase/hosting.YnVpbGQvd2Vi.cache +23 -23
  16. package/templates/firebase/DESIGN_SYSTEM.md +22 -8
  17. package/templates/firebase/assets/icons/apple_black.svg +3 -0
  18. package/templates/firebase/assets/icons/apple_white.svg +4 -0
  19. package/templates/firebase/assets/icons/facebook.svg +49 -0
  20. package/templates/firebase/assets/icons/google.svg +1 -0
  21. package/templates/firebase/functions/src/admin/functions.ts +2 -0
  22. package/templates/firebase/functions/src/authentication/functions.ts +13 -7
  23. package/templates/firebase/functions/src/notifications/triggers.ts +6 -2
  24. package/templates/firebase/lib/components/components.dart +1 -1
  25. package/templates/firebase/lib/components/kasy_app_bar.dart +314 -14
  26. package/templates/firebase/lib/components/kasy_card.dart +4 -0
  27. package/templates/firebase/lib/components/kasy_drop_down.dart +584 -0
  28. package/templates/firebase/lib/components/kasy_sidebar.dart +18 -6
  29. package/templates/firebase/lib/components/kasy_tabs.dart +31 -10
  30. package/templates/firebase/lib/components/kasy_text_field.dart +29 -7
  31. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +27 -18
  32. package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +12 -10
  33. package/templates/firebase/lib/core/chrome/app_bar_config.dart +214 -0
  34. package/templates/firebase/lib/core/chrome/app_bar_scope.dart +102 -0
  35. package/templates/firebase/lib/core/data/api/user_api.dart +11 -0
  36. package/templates/firebase/lib/core/dev_inspector/dev_inspector_service.dart +55 -15
  37. package/templates/firebase/lib/core/rating/widgets/review_popup.dart +18 -35
  38. package/templates/firebase/lib/core/shared_preferences/shared_preferences.dart +11 -0
  39. package/templates/firebase/lib/core/states/logout_action.dart +11 -1
  40. package/templates/firebase/lib/core/states/user_state_notifier.dart +28 -1
  41. package/templates/firebase/lib/core/theme/texts.dart +21 -6
  42. package/templates/firebase/lib/core/theme/type_scale.dart +34 -15
  43. package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +51 -19
  44. package/templates/firebase/lib/core/web_viewport_scale.dart +64 -35
  45. package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +14 -3
  46. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_chat_composer.dart +1 -1
  47. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_chat_conversation_view.dart +52 -35
  48. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +1 -1
  49. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +18 -8
  50. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +11 -61
  51. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +11 -61
  52. package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +7 -5
  53. package/templates/firebase/lib/features/authentication/ui/widgets/social_auth_tile.dart +83 -0
  54. package/templates/firebase/lib/features/feedbacks/ui/widgets/feature_card.dart +4 -4
  55. package/templates/firebase/lib/features/home/home_components_page.dart +253 -125
  56. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +231 -57
  57. package/templates/firebase/lib/features/home/home_feed.dart +2 -2
  58. package/templates/firebase/lib/features/home/home_image_grid.dart +3 -3
  59. package/templates/firebase/lib/features/local_reminders/providers/reminder_notifier.dart +8 -1
  60. package/templates/firebase/lib/features/local_reminders/ui/reminder_page.dart +111 -57
  61. package/templates/firebase/lib/features/notifications/api/device_api.dart +11 -3
  62. package/templates/firebase/lib/features/notifications/ui/notifications_page.dart +16 -4
  63. package/templates/firebase/lib/features/notifications/ui/widgets/empty_notifications.dart +7 -56
  64. package/templates/firebase/lib/features/notifications/ui/widgets/notification_tile.dart +5 -5
  65. package/templates/firebase/lib/features/notifications/ui/widgets/push_permission_banner.dart +163 -0
  66. package/templates/firebase/lib/features/notifications/ui/widgets/web_notifications_bell.dart +2 -2
  67. package/templates/firebase/lib/features/onboarding/providers/onboarding_model.dart +9 -0
  68. package/templates/firebase/lib/features/onboarding/providers/onboarding_provider.dart +28 -0
  69. package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +51 -12
  70. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +90 -32
  71. package/templates/firebase/lib/features/settings/settings_page.dart +53 -32
  72. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +895 -111
  73. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +7 -0
  74. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +445 -233
  75. package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +171 -41
  76. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +1 -1
  77. package/templates/firebase/lib/features/settings/ui/components/delete_user_component.dart +9 -1
  78. package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +48 -47
  79. package/templates/firebase/lib/features/settings/ui/widgets/settings_bottom_sheet_option_tile.dart +21 -18
  80. package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +25 -10
  81. package/templates/firebase/lib/i18n/en.i18n.json +749 -712
  82. package/templates/firebase/lib/i18n/es.i18n.json +749 -712
  83. package/templates/firebase/lib/i18n/pt.i18n.json +749 -712
  84. package/templates/firebase/lib/main.dart +20 -7
  85. package/templates/firebase/lib/router.dart +32 -26
  86. package/templates/firebase/pubspec.yaml +2 -1
  87. package/templates/firebase/test/admin_shell_chrome_test.dart +11 -5
  88. package/templates/firebase/test/components/kasy_text_field_height_test.dart +77 -0
  89. package/templates/firebase/test/core/web_viewport_scale_test.dart +23 -16
  90. package/templates/firebase/tool/design_check.dart +9 -0
  91. package/templates/firebase/assets/icons/apple.png +0 -0
  92. package/templates/firebase/assets/icons/facebook.png +0 -0
  93. package/templates/firebase/assets/icons/google.png +0 -0
  94. package/templates/firebase/assets/icons/google_play_games.png +0 -0
  95. package/templates/firebase/lib/components/kasy_web_header.dart +0 -218
  96. package/templates/firebase/lib/core/chrome/web_header_scope.dart +0 -20
  97. package/templates/firebase/lib/features/authentication/ui/components/apple_signin.dart +0 -19
  98. package/templates/firebase/lib/features/authentication/ui/components/google_signin.dart +0 -32
  99. package/templates/firebase/lib/features/authentication/ui/widgets/round_signin.dart +0 -73
  100. package/templates/firebase/lib/features/feedbacks/ui/widgets/add_feature_button.dart +0 -66
  101. package/templates/firebase/lib/features/notifications/ui/components/notification_settings_sheet.dart +0 -179
  102. package/templates/firebase/lib/features/notifications/ui/components/push_notification_switcher.dart +0 -106
@@ -73,22 +73,10 @@ class _OnboardingSelectableRowGroupState
73
73
  return Column(
74
74
  crossAxisAlignment: CrossAxisAlignment.stretch,
75
75
  children: [
76
- KasyFocusRing(
77
- onActivate: selectRow,
76
+ _SelectableTileInk(
77
+ onTap: selectRow,
78
78
  borderRadius: KasyRadius.lgBorderRadius,
79
- child: Material(
80
- color: Colors.transparent,
81
- borderRadius: KasyRadius.lgBorderRadius,
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
- ),
91
- ),
79
+ child: widget.options[index],
92
80
  ),
93
81
  if (hasOnSelectInfo && _selectedIndex == index)
94
82
  Padding(
@@ -150,23 +138,16 @@ class _OnboardingMultiSelectableRowGroupState
150
138
  setState(() {});
151
139
  }
152
140
 
153
- return KasyFocusRing(
154
- onActivate: toggleSelection,
155
- borderRadius: KasyRadius.mdBorderRadius,
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
- ),
169
- ),
141
+ return _SelectableTileInk(
142
+ onTap: toggleSelection,
143
+ // Match the tile's own lgBorderRadius so the hover veil and focus ring
144
+ // hug its shape (the old InkWell clipped at md, a mismatch).
145
+ borderRadius: KasyRadius.lgBorderRadius,
146
+ child: SelectableRowTile(
147
+ title: option.title,
148
+ subtitle: option.subtitle,
149
+ selected: _selectedIndex.contains(index),
150
+ emoj: option.emoj,
170
151
  ),
171
152
  );
172
153
  }).toList(),
@@ -338,6 +319,83 @@ class _SelectableRowTileState extends State<SelectableRowTile>
338
319
  }
339
320
  }
340
321
 
322
+ /// Adds a web hover highlight, a keyboard focus ring and a click cursor on top
323
+ /// of an opaque selectable tile — no Material ripple.
324
+ ///
325
+ /// Because the tile paints its own background, the hover veil is layered ABOVE
326
+ /// the child (clipped to [borderRadius]), the same approach the tappable
327
+ /// [KasyCard] uses; a [KasyHover]-style overlay would sit behind the opaque
328
+ /// surface and never show. The child keeps its own semantics (the option title),
329
+ /// so screen readers still announce the option, not a generic label.
330
+ class _SelectableTileInk extends StatefulWidget {
331
+ const _SelectableTileInk({
332
+ required this.onTap,
333
+ required this.borderRadius,
334
+ required this.child,
335
+ });
336
+
337
+ final VoidCallback onTap;
338
+ final BorderRadius borderRadius;
339
+ final Widget child;
340
+
341
+ @override
342
+ State<_SelectableTileInk> createState() => _SelectableTileInkState();
343
+ }
344
+
345
+ class _SelectableTileInkState extends State<_SelectableTileInk> {
346
+ bool _hovered = false;
347
+ bool _pressed = false;
348
+
349
+ @override
350
+ Widget build(BuildContext context) {
351
+ final bool dark = context.isDark;
352
+ // Subtle tint that fades in on hover (web/desktop) and deepens briefly on
353
+ // press; invisible at rest. On touch _hovered never becomes true.
354
+ final double alpha = _pressed
355
+ ? (dark ? 0.10 : 0.06)
356
+ : (_hovered ? (dark ? 0.06 : 0.04) : 0.0);
357
+
358
+ final Widget veiled = Stack(
359
+ children: <Widget>[
360
+ widget.child,
361
+ Positioned.fill(
362
+ child: IgnorePointer(
363
+ child: AnimatedContainer(
364
+ duration: const Duration(milliseconds: 120),
365
+ curve: Curves.easeOut,
366
+ decoration: BoxDecoration(
367
+ color: context.colors.onSurface.withValues(alpha: alpha),
368
+ borderRadius: widget.borderRadius,
369
+ ),
370
+ ),
371
+ ),
372
+ ),
373
+ ],
374
+ );
375
+
376
+ return KasyFocusRing(
377
+ onActivate: widget.onTap,
378
+ borderRadius: widget.borderRadius,
379
+ child: MouseRegion(
380
+ cursor: SystemMouseCursors.click,
381
+ onEnter: (_) => setState(() => _hovered = true),
382
+ onExit: (_) => setState(() {
383
+ _hovered = false;
384
+ _pressed = false;
385
+ }),
386
+ child: GestureDetector(
387
+ behavior: HitTestBehavior.opaque,
388
+ onTap: widget.onTap,
389
+ onTapDown: (_) => setState(() => _pressed = true),
390
+ onTapUp: (_) => setState(() => _pressed = false),
391
+ onTapCancel: () => setState(() => _pressed = false),
392
+ child: veiled,
393
+ ),
394
+ ),
395
+ );
396
+ }
397
+ }
398
+
341
399
  class RoundRadioBox extends StatelessWidget {
342
400
  final Color bgColor;
343
401
  final Color borderColor;
@@ -15,7 +15,6 @@ import 'package:kasy_kit/core/states/logout_action.dart';
15
15
  import 'package:kasy_kit/core/states/user_state_notifier.dart';
16
16
  import 'package:kasy_kit/core/theme/theme.dart';
17
17
  import 'package:kasy_kit/core/widgets/kasy_hover.dart';
18
- import 'package:kasy_kit/core/widgets/responsive_layout.dart';
19
18
  import 'package:kasy_kit/features/authentication/repositories/authentication_repository.dart';
20
19
  import 'package:kasy_kit/features/authentication/repositories/exceptions/authentication_exceptions.dart';
21
20
  import 'package:kasy_kit/features/settings/ui/components/avatar_component.dart';
@@ -153,6 +152,7 @@ class SettingsPage extends ConsumerWidget {
153
152
  context,
154
153
  ref,
155
154
  isAuthenticated: isAuthenticated,
155
+ hasAccount: userId != null,
156
156
  isAdmin: user.isAdmin,
157
157
  isPhone: isPhone,
158
158
  ),
@@ -182,6 +182,7 @@ class SettingsPage extends ConsumerWidget {
182
182
  BuildContext context,
183
183
  WidgetRef ref, {
184
184
  required bool isAuthenticated,
185
+ required bool hasAccount,
185
186
  required bool isAdmin,
186
187
  required bool isPhone,
187
188
  }) {
@@ -215,7 +216,7 @@ class SettingsPage extends ConsumerWidget {
215
216
  padding: const EdgeInsets.only(left: KasySpacing.xs),
216
217
  child: Text(
217
218
  t.admin_console.settings_entry.caption,
218
- style: context.textTheme.bodySmall?.copyWith(
219
+ style: context.textTheme.bodyMedium?.copyWith(
219
220
  color: context.colors.muted,
220
221
  ),
221
222
  ),
@@ -226,8 +227,13 @@ class SettingsPage extends ConsumerWidget {
226
227
  _settingsGroup([_LogoutRow(onTap: () => confirmLogout(context, ref))]),
227
228
  const SizedBox(height: KasySpacing.xl),
228
229
  ],
229
- const DeleteUserButton(),
230
- const SizedBox(height: KasySpacing.xl),
230
+ // Only offer account deletion when there's a real backend account behind
231
+ // it. A guest with no identity has nothing to delete, so the button would
232
+ // just dead-end in an error and trap them on this screen.
233
+ if (hasAccount) ...[
234
+ const DeleteUserButton(),
235
+ const SizedBox(height: KasySpacing.xl),
236
+ ],
231
237
  const _VersionLabel(),
232
238
  ];
233
239
  }
@@ -435,10 +441,9 @@ class SettingsContainer extends StatelessWidget {
435
441
  Widget build(BuildContext context) {
436
442
  return KasyCard(
437
443
  borderRadius: BorderRadius.circular(KasyRadius.lg),
438
- padding: const EdgeInsets.symmetric(
439
- horizontal: KasySpacing.md,
440
- vertical: KasySpacing.xs,
441
- ),
444
+ // No card padding: each row carries its own inset so the press/hover
445
+ // highlight spans the full card width (clipped to the rounded corners),
446
+ // instead of a pill floating inside a white margin.
442
447
  child: child,
443
448
  );
444
449
  }
@@ -460,7 +465,7 @@ class _FieldRow extends StatelessWidget {
460
465
  children: [
461
466
  Text(
462
467
  label,
463
- style: context.textTheme.titleSmall?.copyWith(
468
+ style: context.kasyTextTheme.listRowTitle.copyWith(
464
469
  color: context.colors.onSurface,
465
470
  ),
466
471
  ),
@@ -471,7 +476,7 @@ class _FieldRow extends StatelessWidget {
471
476
  textAlign: TextAlign.right,
472
477
  maxLines: 1,
473
478
  overflow: TextOverflow.ellipsis,
474
- style: context.textTheme.bodyMedium?.copyWith(
479
+ style: context.kasyTextTheme.listRowValue.copyWith(
475
480
  color: context.colors.muted,
476
481
  ),
477
482
  ),
@@ -484,18 +489,22 @@ class _FieldRow extends StatelessWidget {
484
489
  );
485
490
  if (onTap == null) {
486
491
  return Padding(
487
- padding: const EdgeInsets.symmetric(vertical: KasySpacing.sm),
492
+ padding: const EdgeInsets.symmetric(
493
+ horizontal: KasySpacing.md,
494
+ vertical: KasySpacing.smd,
495
+ ),
488
496
  child: row,
489
497
  );
490
498
  }
491
499
  return KasyHover(
492
500
  onTap: onTap!,
493
- hoverEnabled: false,
494
- pressEnabled: false,
495
501
  focusable: true,
496
- borderRadius: KasyRadius.smBorderRadius,
502
+ // Rectangular highlight (default): the card clips the rounded ends.
497
503
  semanticLabel: label,
498
- padding: const EdgeInsets.symmetric(vertical: KasySpacing.sm),
504
+ padding: const EdgeInsets.symmetric(
505
+ horizontal: KasySpacing.md,
506
+ vertical: KasySpacing.smd,
507
+ ),
499
508
  child: row,
500
509
  );
501
510
  }
@@ -512,7 +521,7 @@ class _AccountAvatarHeader extends StatelessWidget {
512
521
  return const Center(
513
522
  child: Padding(
514
523
  padding: EdgeInsets.only(top: KasySpacing.sm),
515
- child: EditableUserAvatar(diameter: 64),
524
+ child: EditableUserAvatar(diameter: 80),
516
525
  ),
517
526
  );
518
527
  }
@@ -606,9 +615,10 @@ class _SettingsDesktopViewState extends ConsumerState<_SettingsDesktopView> {
606
615
  isPhone: widget.isPhone,
607
616
  );
608
617
 
609
- const double navWidth = 248;
610
- const double gap = KasySpacing.xxl;
611
- const double groupWidth = navWidth + gap + kKasyContentMaxWidth;
618
+ const double navWidth = 220;
619
+ const double gap = KasySpacing.xl;
620
+ const double detailWidth = 560;
621
+ const double groupWidth = navWidth + gap + detailWidth;
612
622
 
613
623
  return Center(
614
624
  child: Padding(
@@ -641,7 +651,7 @@ class _SettingsDesktopViewState extends ConsumerState<_SettingsDesktopView> {
641
651
  ),
642
652
  const SizedBox(width: gap),
643
653
  if (fits)
644
- SizedBox(width: kKasyContentMaxWidth, child: pane)
654
+ SizedBox(width: detailWidth, child: pane)
645
655
  else
646
656
  Expanded(child: pane),
647
657
  ],
@@ -682,7 +692,7 @@ class _DesktopNav extends StatelessWidget {
682
692
  ),
683
693
  child: Row(
684
694
  children: [
685
- const EditableUserAvatar(diameter: 40),
695
+ const EditableUserAvatar(diameter: 64),
686
696
  const SizedBox(width: KasySpacing.sm),
687
697
  Expanded(
688
698
  child: Column(
@@ -702,7 +712,7 @@ class _DesktopNav extends StatelessWidget {
702
712
  email,
703
713
  maxLines: 1,
704
714
  overflow: TextOverflow.ellipsis,
705
- style: context.textTheme.bodySmall?.copyWith(
715
+ style: context.textTheme.bodyMedium?.copyWith(
706
716
  color: context.colors.muted,
707
717
  ),
708
718
  ),
@@ -755,7 +765,7 @@ class _NavTile extends StatelessWidget {
755
765
  child: Container(
756
766
  padding: const EdgeInsets.symmetric(
757
767
  horizontal: KasySpacing.smd,
758
- vertical: KasySpacing.smd,
768
+ vertical: KasySpacing.sm,
759
769
  ),
760
770
  decoration: BoxDecoration(
761
771
  color: selected ? c.surfaceNeutralSoft : Colors.transparent,
@@ -877,8 +887,11 @@ class _DesktopDetail extends ConsumerWidget {
877
887
  const SizedBox(height: KasySpacing.xl),
878
888
  _settingsGroup([_LogoutRow(onTap: () => confirmLogout(context, ref))]),
879
889
  ],
880
- const SizedBox(height: KasySpacing.xl),
881
- const DeleteUserButton(),
890
+ // Only when there's a real backend account to delete (see mobile layout).
891
+ if (userId != null) ...[
892
+ const SizedBox(height: KasySpacing.xl),
893
+ const DeleteUserButton(),
894
+ ],
882
895
  const SizedBox(height: KasySpacing.xl),
883
896
  const _VersionLabel(),
884
897
  ];
@@ -894,13 +907,18 @@ class _LogoutRow extends StatelessWidget {
894
907
  @override
895
908
  Widget build(BuildContext context) {
896
909
  return KasyHover(
897
- borderRadius: KasyRadius.smBorderRadius,
910
+ // Match the card radius so the full-bleed press fill hugs the rounded
911
+ // corners exactly (this row is the sole child of its card).
912
+ borderRadius: KasyRadius.lgBorderRadius,
898
913
  pressColor: context.colors.error,
899
914
  focusable: true,
900
915
  focusGapColor: context.colors.surface,
901
916
  onTap: onTap,
902
917
  child: Padding(
903
- padding: const EdgeInsets.symmetric(vertical: KasySpacing.sm),
918
+ padding: const EdgeInsets.symmetric(
919
+ horizontal: KasySpacing.md,
920
+ vertical: KasySpacing.smd,
921
+ ),
904
922
  child: Row(
905
923
  children: [
906
924
  Icon(
@@ -911,7 +929,7 @@ class _LogoutRow extends StatelessWidget {
911
929
  const SizedBox(width: KasySpacing.sm),
912
930
  Text(
913
931
  context.t.settings.logout,
914
- style: context.textTheme.titleSmall?.copyWith(
932
+ style: context.kasyTextTheme.listRowTitle.copyWith(
915
933
  color: context.colors.error,
916
934
  ),
917
935
  ),
@@ -980,12 +998,12 @@ class BiometricSwitcher extends ConsumerWidget {
980
998
  ),
981
999
  Padding(
982
1000
  padding: const EdgeInsets.only(
983
- left: KasyIconSize.rowLeading + KasySpacing.sm,
1001
+ left: KasySpacing.md + KasyIconSize.rowLeading + KasySpacing.sm,
984
1002
  bottom: KasySpacing.xs,
985
1003
  ),
986
1004
  child: Text(
987
1005
  subtitle,
988
- style: context.textTheme.bodySmall?.copyWith(
1006
+ style: context.textTheme.bodyMedium?.copyWith(
989
1007
  color: context.colors.muted,
990
1008
  ),
991
1009
  ),
@@ -1114,7 +1132,10 @@ class ThemeSwitcher extends StatelessWidget {
1114
1132
  ),
1115
1133
  ];
1116
1134
  return Padding(
1117
- padding: const EdgeInsets.symmetric(vertical: KasySpacing.sm),
1135
+ padding: const EdgeInsets.symmetric(
1136
+ horizontal: KasySpacing.md,
1137
+ vertical: KasySpacing.smd,
1138
+ ),
1118
1139
  child: Row(
1119
1140
  children: [
1120
1141
  Icon(
@@ -1126,7 +1147,7 @@ class ThemeSwitcher extends StatelessWidget {
1126
1147
  Expanded(
1127
1148
  child: Text(
1128
1149
  tr.theme_title,
1129
- style: context.textTheme.titleSmall?.copyWith(
1150
+ style: context.kasyTextTheme.listRowTitle.copyWith(
1130
1151
  color: context.colors.onSurface,
1131
1152
  ),
1132
1153
  ),