kasy-cli 1.32.0 → 1.34.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 (60) hide show
  1. package/bin/kasy.js +42 -0
  2. package/lib/commands/apple-web.js +222 -0
  3. package/lib/commands/configure.js +3 -91
  4. package/lib/commands/doctor.js +20 -0
  5. package/lib/commands/facebook.js +189 -0
  6. package/lib/commands/new.js +50 -2
  7. package/lib/scaffold/CHANGELOG.json +18 -0
  8. package/lib/scaffold/backends/firebase/setup-from-scratch.js +164 -0
  9. package/lib/scaffold/backends/supabase/deploy.js +92 -0
  10. package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +10 -0
  11. package/lib/scaffold/shared/generator-utils.js +18 -6
  12. package/lib/utils/apple-web.js +147 -0
  13. package/lib/utils/facebook.js +162 -0
  14. package/lib/utils/i18n/messages-en.js +62 -0
  15. package/lib/utils/i18n/messages-es.js +62 -0
  16. package/lib/utils/i18n/messages-pt.js +62 -0
  17. package/package.json +2 -2
  18. package/templates/firebase/AGENTS.md +87 -0
  19. package/templates/firebase/CLAUDE.md +16 -0
  20. package/templates/firebase/DESIGN_SYSTEM.md +234 -0
  21. package/templates/firebase/docs/auth-setup.en.md +2 -2
  22. package/templates/firebase/docs/auth-setup.es.md +2 -2
  23. package/templates/firebase/docs/auth-setup.pt.md +2 -2
  24. package/templates/firebase/lib/components/components.dart +1 -0
  25. package/templates/firebase/lib/components/kasy_app_bar.dart +4 -1
  26. package/templates/firebase/lib/components/kasy_screen.dart +114 -0
  27. package/templates/firebase/lib/components/kasy_toast.dart +39 -70
  28. package/templates/firebase/lib/core/chrome/chrome_visibility.dart +22 -0
  29. package/templates/firebase/lib/core/config/features.dart +5 -0
  30. package/templates/firebase/lib/core/rating/widgets/review_popup.dart +46 -124
  31. package/templates/firebase/lib/core/widgets/update_bottom_sheet.dart +29 -126
  32. package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +11 -7
  33. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_chat_composer.dart +21 -0
  34. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +1 -1
  35. package/templates/firebase/lib/features/authentication/api/authentication_api.dart +61 -0
  36. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +21 -15
  37. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +20 -14
  38. package/templates/firebase/lib/features/feedbacks/ui/widgets/feature_card.dart +1 -2
  39. package/templates/firebase/lib/features/home/home_components_page.dart +7 -1
  40. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +32 -0
  41. package/templates/firebase/lib/features/local_reminders/ui/reminder_page.dart +165 -209
  42. package/templates/firebase/lib/features/notifications/ui/components/notification_settings_sheet.dart +2 -2
  43. package/templates/firebase/lib/features/notifications/ui/components/notification_tile.dart +21 -8
  44. package/templates/firebase/lib/features/notifications/ui/components/push_notification_switcher.dart +2 -2
  45. package/templates/firebase/lib/features/notifications/ui/notifications_page.dart +3 -6
  46. package/templates/firebase/lib/features/notifications/ui/widgets/notification_tile.dart +77 -126
  47. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +3 -4
  48. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +2 -4
  49. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +2 -1
  50. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +17 -8
  51. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +2 -2
  52. package/templates/firebase/lib/i18n/en.i18n.json +5 -4
  53. package/templates/firebase/lib/i18n/es.i18n.json +5 -4
  54. package/templates/firebase/lib/i18n/pt.i18n.json +5 -4
  55. package/templates/firebase/lib/router.dart +2 -0
  56. package/templates/firebase/pubspec.yaml +1 -1
  57. package/templates/firebase/tool/design_check.dart +152 -0
  58. package/templates/firebase/assets/images/review.png +0 -0
  59. package/templates/firebase/assets/images/update.png +0 -0
  60. package/templates/firebase/lib/features/notifications/ui/components/notifications_header.dart +0 -32
@@ -9,8 +9,13 @@ import 'package:kasy_kit/features/notifications/providers/models/notification.da
9
9
  typedef OnTapNotification = void Function(app.Notification notification);
10
10
 
11
11
  /// A tile for the [NotificationsPage] widget.
12
- class NotificationTile extends StatefulWidget {
13
- final double bgOpacity;
12
+ ///
13
+ /// Renders only the row content (icon + title / body / date + unread dot). The
14
+ /// card surface (elevated [KasyCard]) and the tap/hover feedback live in
15
+ /// [NotificationTileComponent], so a notification reads exactly like a Settings
16
+ /// card. Unread vs read is signalled by the trailing dot and text strength, not
17
+ /// by a tinted background.
18
+ class NotificationTile extends StatelessWidget {
14
19
  final double titleOpacity;
15
20
  final Color titleColor;
16
21
  final Color descriptionColor;
@@ -24,7 +29,6 @@ class NotificationTile extends StatefulWidget {
24
29
 
25
30
  const NotificationTile({
26
31
  super.key,
27
- required this.bgOpacity,
28
32
  required this.titleOpacity,
29
33
  required this.icon,
30
34
  required this.date,
@@ -47,7 +51,6 @@ class NotificationTile extends StatefulWidget {
47
51
  Key? key,
48
52
  }) => NotificationTile(
49
53
  key: key,
50
- bgOpacity: .08,
51
54
  titleOpacity: 1,
52
55
  showUnreadDot: true,
53
56
  icon: imageUrl != null
@@ -72,7 +75,6 @@ class NotificationTile extends StatefulWidget {
72
75
  Key? key,
73
76
  }) => NotificationTile(
74
77
  key: key,
75
- bgOpacity: 0,
76
78
  titleOpacity: .6,
77
79
  icon: imageUrl != null
78
80
  ? TileNotificationImage(url: imageUrl)
@@ -111,124 +113,66 @@ class NotificationTile extends StatefulWidget {
111
113
  onTap: onTap,
112
114
  );
113
115
 
114
- @override
115
- State<NotificationTile> createState() => _NotificationTileState();
116
- }
117
-
118
- class _NotificationTileState extends State<NotificationTile>
119
- with SingleTickerProviderStateMixin {
120
- late final AnimationController _controller;
121
- late Animation<double> _opacityAnimation;
122
-
123
- @override
124
- void initState() {
125
- super.initState();
126
- _controller = AnimationController(
127
- duration: const Duration(milliseconds: 500),
128
- vsync: this,
129
- );
130
- _opacityAnimation = Tween(
131
- begin: 0.0,
132
- end: widget.bgOpacity,
133
- ).animate(CurvedAnimation(parent: _controller, curve: Curves.decelerate));
134
- _controller.forward();
135
- }
136
-
137
- @override
138
- void didUpdateWidget(covariant NotificationTile oldWidget) {
139
- super.didUpdateWidget(oldWidget);
140
- if (oldWidget.bgOpacity != widget.bgOpacity) {
141
- _opacityAnimation = Tween(
142
- begin: oldWidget.bgOpacity,
143
- end: widget.bgOpacity,
144
- ).animate(CurvedAnimation(parent: _controller, curve: Curves.ease));
145
- _controller.forward(from: 0);
146
- }
147
- }
148
-
149
- @override
150
- void dispose() {
151
- _controller.dispose();
152
- super.dispose();
153
- }
154
-
155
116
  @override
156
117
  Widget build(BuildContext context) {
157
- return AnimatedBuilder(
158
- animation: _controller,
159
- builder: (context, child) {
160
- return Container(
161
- decoration: BoxDecoration(
162
- color: context.colors.primary.withValues(
163
- alpha: _opacityAnimation.value,
164
- ),
165
- borderRadius: KasyRadius.smBorderRadius,
166
- ),
167
- padding: const EdgeInsets.all(KasySpacing.md),
168
- child: child,
169
- );
170
- },
171
- child: Row(
172
- crossAxisAlignment: CrossAxisAlignment.start,
173
- children: [
174
- widget.icon,
175
- const SizedBox(width: KasySpacing.smd),
176
- Expanded(
177
- child: Column(
178
- crossAxisAlignment: CrossAxisAlignment.start,
179
- children: [
180
- Flexible(
181
- flex: 0,
182
- child: Text(
183
- widget.title,
184
- style: context.textTheme.labelLarge?.copyWith(
185
- color: widget.titleColor,
186
- ),
187
- overflow: TextOverflow.clip,
188
- maxLines: 2,
189
- ),
190
- ),
191
- const SizedBox(height: KasySpacing.xs),
192
- Flexible(
193
- flex: 0,
194
- child: Text(
195
- widget.description,
196
- style: context.textTheme.bodyMedium?.copyWith(
197
- color: widget.descriptionColor,
118
+ return Row(
119
+ crossAxisAlignment: CrossAxisAlignment.start,
120
+ children: [
121
+ icon,
122
+ const SizedBox(width: KasySpacing.sm),
123
+ Expanded(
124
+ child: Column(
125
+ crossAxisAlignment: CrossAxisAlignment.start,
126
+ children: [
127
+ // Headline row: bold title on the left, timestamp (and the
128
+ // unread dot) pinned to the right — the compact, professional
129
+ // notification layout (Linear / Gmail).
130
+ Row(
131
+ children: [
132
+ Expanded(
133
+ child: Text(
134
+ title,
135
+ style: context.textTheme.titleSmall?.copyWith(
136
+ color: titleColor,
137
+ fontWeight: FontWeight.w700,
138
+ ),
139
+ overflow: TextOverflow.ellipsis,
140
+ maxLines: 1,
198
141
  ),
199
- overflow: TextOverflow.ellipsis,
200
- maxLines: 3,
201
142
  ),
202
- ),
203
- const SizedBox(height: KasySpacing.smd),
204
- Flexible(
205
- flex: 0,
206
- child: Text(
207
- Jiffy.parseFromDateTime(widget.date).fromNow(),
143
+ const SizedBox(width: KasySpacing.sm),
144
+ Text(
145
+ Jiffy.parseFromDateTime(date).fromNow(),
208
146
  style: context.textTheme.bodySmall?.copyWith(
209
- color: widget.dateColor,
147
+ color: dateColor,
210
148
  ),
211
149
  ),
150
+ if (showUnreadDot) ...[
151
+ const SizedBox(width: KasySpacing.sm),
152
+ Container(
153
+ width: 6,
154
+ height: 6,
155
+ decoration: BoxDecoration(
156
+ shape: BoxShape.circle,
157
+ color: context.colors.primary,
158
+ ),
159
+ ),
160
+ ],
161
+ ],
162
+ ),
163
+ const SizedBox(height: KasySpacing.xs),
164
+ Text(
165
+ description,
166
+ style: context.textTheme.bodyMedium?.copyWith(
167
+ color: descriptionColor,
212
168
  ),
213
- ],
214
- ),
215
- ),
216
- if (widget.showUnreadDot) ...[
217
- const SizedBox(width: KasySpacing.sm),
218
- Padding(
219
- padding: const EdgeInsets.only(top: 3),
220
- child: Container(
221
- width: 8,
222
- height: 8,
223
- decoration: BoxDecoration(
224
- shape: BoxShape.circle,
225
- color: context.colors.primary,
226
- ),
169
+ overflow: TextOverflow.ellipsis,
170
+ maxLines: 2,
227
171
  ),
228
- ),
229
- ],
230
- ],
231
- ),
172
+ ],
173
+ ),
174
+ ),
175
+ ],
232
176
  );
233
177
  }
234
178
  }
@@ -269,8 +213,8 @@ class TileNotificationImage extends StatelessWidget {
269
213
  borderRadius: BorderRadius.circular(8),
270
214
  child: Image.network(
271
215
  url,
272
- width: 48,
273
- height: 48,
216
+ width: 36,
217
+ height: 36,
274
218
  fit: BoxFit.cover,
275
219
  errorBuilder: (context, error, stack) =>
276
220
  const TileNotificationIcon(active: false),
@@ -297,8 +241,8 @@ class TileNotificationIcon extends StatelessWidget {
297
241
  ? context.colors.primary
298
242
  : context.colors.onSurface.withValues(alpha: 0.35);
299
243
  return Container(
300
- width: 40,
301
- height: 40,
244
+ width: 36,
245
+ height: 36,
302
246
  decoration: BoxDecoration(
303
247
  color: active
304
248
  ? context.colors.primary.withValues(alpha: 0.12)
@@ -307,7 +251,7 @@ class TileNotificationIcon extends StatelessWidget {
307
251
  ),
308
252
  child: Icon(
309
253
  active ? KasyIcons.notificationActive : KasyIcons.notification,
310
- size: KasyIconSize.lg,
254
+ size: KasyIconSize.sm,
311
255
  color: color,
312
256
  ),
313
257
  );
@@ -326,27 +270,34 @@ class NotificationSkeletonTile extends StatelessWidget {
326
270
  padding: EdgeInsets.only(top: KasySpacing.sm),
327
271
  child: KasySkeletonGroup(
328
272
  child: Padding(
329
- padding: EdgeInsets.all(KasySpacing.md),
273
+ padding: EdgeInsets.symmetric(
274
+ horizontal: KasySpacing.md,
275
+ vertical: KasySpacing.smd,
276
+ ),
330
277
  child: Row(
331
278
  crossAxisAlignment: CrossAxisAlignment.start,
332
279
  children: [
333
280
  KasySkeleton(
334
- width: 40,
335
- height: 40,
281
+ width: 36,
282
+ height: 36,
336
283
  borderRadius: BorderRadius.all(Radius.circular(10)),
337
284
  ),
338
- SizedBox(width: KasySpacing.smd),
285
+ SizedBox(width: KasySpacing.sm),
339
286
  Expanded(
340
287
  child: Column(
341
288
  crossAxisAlignment: CrossAxisAlignment.start,
342
289
  children: [
343
- KasySkeleton(width: 150, height: 13),
290
+ Row(
291
+ children: [
292
+ Expanded(child: KasySkeleton(width: 150, height: 13)),
293
+ SizedBox(width: KasySpacing.sm),
294
+ KasySkeleton(width: 44, height: 10),
295
+ ],
296
+ ),
344
297
  SizedBox(height: KasySpacing.sm),
345
298
  KasySkeleton(width: double.infinity, height: 11),
346
299
  SizedBox(height: KasySpacing.xs),
347
300
  KasySkeleton(width: 210, height: 11),
348
- SizedBox(height: KasySpacing.smd),
349
- KasySkeleton(width: 70, height: 10),
350
301
  ],
351
302
  ),
352
303
  ),
@@ -93,12 +93,11 @@ class OnboardingIllustrationScaffold extends StatelessWidget {
93
93
  child: Text(
94
94
  title,
95
95
  textAlign: TextAlign.start,
96
+ // Design-system page-title scale (headlineMedium = 24/w700).
97
+ // Previously bumped to 28 with custom tracking, which read as
98
+ // oversized next to the rest of the app.
96
99
  style: context.textTheme.headlineMedium?.copyWith(
97
100
  color: colors.onBackground,
98
- fontSize: 28,
99
- fontWeight: FontWeight.w700,
100
- letterSpacing: -0.3,
101
- height: 1.2,
102
101
  ),
103
102
  ),
104
103
  ),
@@ -71,12 +71,10 @@ class _OnboardingRadioQuestionState
71
71
  child: Text(
72
72
  widget.title,
73
73
  textAlign: TextAlign.start,
74
+ // Design-system page-title scale (headlineMedium = 24/w700),
75
+ // matching the illustration steps instead of a bespoke 26px size.
74
76
  style: context.textTheme.headlineMedium?.copyWith(
75
77
  color: context.colors.onBackground,
76
- fontSize: 26,
77
- fontWeight: FontWeight.w700,
78
- letterSpacing: -0.2,
79
- height: 1.2,
80
78
  ),
81
79
  ),
82
80
  ),
@@ -283,7 +283,8 @@ class _SelectableRowTileState extends State<SelectableRowTile>
283
283
  padding: const EdgeInsets.only(right: KasySpacing.md),
284
284
  child: Text(
285
285
  widget.emoj!,
286
- style: context.textTheme.titleMedium?.copyWith(fontSize: 28),
286
+ style: context.textTheme.titleMedium
287
+ ?.copyWith(fontSize: 28), // design-check: ignore — emoji glyph
287
288
  ),
288
289
  ),
289
290
  ),
@@ -1098,13 +1098,12 @@ class _ToolsTab extends ConsumerWidget {
1098
1098
  _ActionCard(
1099
1099
  icon: KasyIcons.note,
1100
1100
  title: admin.update_bottom_sheet,
1101
- onTap: () {
1102
- _backToApp(context);
1103
- showUpdateBottomSheet(
1104
- context: navigatorKey.currentContext!,
1105
- version: '0.0.0',
1106
- );
1107
- },
1101
+ // Preview the sheet over the current screen; dismissing (tap-outside /
1102
+ // Continue) just closes it and returns here, without navigating away.
1103
+ onTap: () => showUpdateBottomSheet(
1104
+ context: navigatorKey.currentContext!,
1105
+ version: '0.0.0',
1106
+ ),
1108
1107
  ),
1109
1108
  _ActionCard(
1110
1109
  icon: KasyIcons.payment,
@@ -1148,6 +1147,10 @@ class _ToolsTab extends ConsumerWidget {
1148
1147
  icon: KasyIcons.notification,
1149
1148
  title: admin.copy_fcm_token,
1150
1149
  onTap: () async {
1150
+ if (kIsWeb) {
1151
+ ref.read(toastProvider).alert(title: '', text: admin.native_only);
1152
+ return;
1153
+ }
1151
1154
  final token = await FirebaseMessaging.instance.getToken();
1152
1155
  if (token == null) {
1153
1156
  ref.read(toastProvider).alert(
@@ -1163,7 +1166,13 @@ class _ToolsTab extends ConsumerWidget {
1163
1166
  _ActionCard(
1164
1167
  icon: KasyIcons.notificationActive,
1165
1168
  title: admin.ask_notification,
1166
- onTap: () => ref.read(notificationsSettingsProvider).askPermission(),
1169
+ onTap: () {
1170
+ if (kIsWeb) {
1171
+ ref.read(toastProvider).alert(title: '', text: admin.native_only);
1172
+ return;
1173
+ }
1174
+ ref.read(notificationsSettingsProvider).askPermission();
1175
+ },
1167
1176
  ),
1168
1177
  ];
1169
1178
 
@@ -97,8 +97,8 @@ class _EditableUserAvatarState extends ConsumerState<EditableUserAvatar> {
97
97
  child: Container(
98
98
  width: 22,
99
99
  height: 22,
100
- decoration: const BoxDecoration(
101
- color: Color(0x99000000),
100
+ decoration: BoxDecoration(
101
+ color: Colors.black.withValues(alpha: 0.6),
102
102
  shape: BoxShape.circle,
103
103
  ),
104
104
  child: const Icon(
@@ -402,8 +402,8 @@
402
402
  "cancel_button": "Cancel"
403
403
  },
404
404
  "review_popup": {
405
- "title": "Your opinion matters!",
406
- "description": "Help us grow by sharing your experience with others. It only takes a few seconds and makes a huge difference to us 🙏🏻",
405
+ "title": "Your feedback matters",
406
+ "description": "If the app has been helpful, a quick review goes a long way. Got ideas to improve it? We'd love to hear them.",
407
407
  "cancel_button": "Suggest improvements",
408
408
  "rate_button": "Write a review"
409
409
  },
@@ -517,7 +517,7 @@
517
517
  "error": "Something went wrong. Please try again."
518
518
  },
519
519
  "admin": {
520
- "update_bottom_sheet": "Update bottom sheet",
520
+ "update_bottom_sheet": "Preview what's new",
521
521
  "paywalls": "Paywalls",
522
522
  "test_onboarding": "Test onboarding",
523
523
  "copy_user_id": "Copy user id",
@@ -526,12 +526,13 @@
526
526
  "fcm_token_copied": "FCM Token copied to clipboard",
527
527
  "fcm_token_unavailable": "Token unavailable (notifications disabled?)",
528
528
  "ask_notification": "Ask for notification",
529
+ "native_only": "Available only in the native app (iOS / Android)",
529
530
  "ask_review": "Ask for review",
530
531
  "home_widgets_panel": "Home Widgets panel",
531
532
  "home_widgets_title": "Home Widgets Panel",
532
533
  "inspector_fab_title": "Widget inspector",
533
534
  "inspector_fab_subtitle_prefix": "Global shortcut:",
534
- "update_mywidget_title": "📱 Update MyWidget Widget",
535
+ "update_mywidget_title": "Update MyWidget Widget",
535
536
  "update_mywidget_desc": "Call manual update for MyWidget widget",
536
537
  "paywalls_title": "Paywalls Admin Panel",
537
538
  "send_push_title": "Send notification",
@@ -402,8 +402,8 @@
402
402
  "cancel_button": "Cancelar"
403
403
  },
404
404
  "review_popup": {
405
- "title": "¡Tu opinión importa!",
406
- "description": "Ayúdanos a crecer compartiendo tu experiencia. Solo toma unos segundos y hace una gran diferencia para nosotros 🙏🏻",
405
+ "title": "Tu opinión importa",
406
+ "description": "Si la app te ha sido útil, una reseña rápida marca la diferencia. ¿Tienes ideas para mejorarla? Nos encantaría escucharlas.",
407
407
  "cancel_button": "Sugerir mejoras",
408
408
  "rate_button": "Escribir una reseña"
409
409
  },
@@ -517,7 +517,7 @@
517
517
  "error": "Algo salió mal. Por favor, inténtalo de nuevo."
518
518
  },
519
519
  "admin": {
520
- "update_bottom_sheet": "Actualizar bottom sheet",
520
+ "update_bottom_sheet": "Previsualizar novedades",
521
521
  "paywalls": "Paywalls",
522
522
  "test_onboarding": "Probar onboarding",
523
523
  "copy_user_id": "Copiar ID de usuario",
@@ -526,12 +526,13 @@
526
526
  "fcm_token_copied": "FCM Token copiado al portapapeles",
527
527
  "fcm_token_unavailable": "Token no disponible (¿notificaciones desactivadas?)",
528
528
  "ask_notification": "Pedir permiso de notificación",
529
+ "native_only": "Disponible solo en la app nativa (iOS / Android)",
529
530
  "ask_review": "Pedir evaluación",
530
531
  "home_widgets_panel": "Panel de Home Widgets",
531
532
  "home_widgets_title": "Panel de Home Widgets",
532
533
  "inspector_fab_title": "Inspector de widgets",
533
534
  "inspector_fab_subtitle_prefix": "Atajo global:",
534
- "update_mywidget_title": "📱 Actualizar Widget MyWidget",
535
+ "update_mywidget_title": "Actualizar Widget MyWidget",
535
536
  "update_mywidget_desc": "Llamar a la actualización manual para el widget MyWidget",
536
537
  "paywalls_title": "Panel de Admin de Paywalls",
537
538
  "send_push_title": "Enviar notificación",
@@ -402,8 +402,8 @@
402
402
  "cancel_button": "Cancelar"
403
403
  },
404
404
  "review_popup": {
405
- "title": "Sua opinião importa!",
406
- "description": "Ajude-nos a crescer compartilhando sua experiência. Leva apenas alguns segundos e faz uma enorme diferença para nós 🙏🏻",
405
+ "title": "Sua opinião importa",
406
+ "description": "Se o app tem te ajudado, uma avaliação rápida faz toda a diferença. Prefere sugerir melhorias? A gente quer ouvir.",
407
407
  "cancel_button": "Sugerir melhorias",
408
408
  "rate_button": "Escrever uma avaliação"
409
409
  },
@@ -517,7 +517,7 @@
517
517
  "error": "Algo deu errado. Por favor, tente novamente."
518
518
  },
519
519
  "admin": {
520
- "update_bottom_sheet": "Atualizar bottom sheet",
520
+ "update_bottom_sheet": "Pré-visualizar novidades",
521
521
  "paywalls": "Paywalls",
522
522
  "test_onboarding": "Testar onboarding",
523
523
  "copy_user_id": "Copiar ID do usuário",
@@ -526,12 +526,13 @@
526
526
  "fcm_token_copied": "FCM Token copiado para a área de transferência",
527
527
  "fcm_token_unavailable": "Token não disponível (notificações desativadas?)",
528
528
  "ask_notification": "Pedir permissão de notificação",
529
+ "native_only": "Disponível apenas no app nativo (iOS / Android)",
529
530
  "ask_review": "Pedir avaliação",
530
531
  "home_widgets_panel": "Painel de Home Widgets",
531
532
  "home_widgets_title": "Painel de Home Widgets",
532
533
  "inspector_fab_title": "Inspector de widgets",
533
534
  "inspector_fab_subtitle_prefix": "Atalho global:",
534
- "update_mywidget_title": "📱 Atualizar Widget MyWidget",
535
+ "update_mywidget_title": "Atualizar Widget MyWidget",
535
536
  "update_mywidget_desc": "Chamar atualização manual para o widget MyWidget",
536
537
  "paywalls_title": "Painel Admin de Paywalls",
537
538
  "send_push_title": "Enviar notificação",
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
3
3
  import 'package:flutter_riverpod/flutter_riverpod.dart';
4
4
  import 'package:go_router/go_router.dart';
5
5
  import 'package:kasy_kit/core/bottom_menu/bottom_menu.dart';
6
+ import 'package:kasy_kit/core/chrome/chrome_visibility.dart';
6
7
  import 'package:kasy_kit/core/config/features.dart';
7
8
  import 'package:kasy_kit/core/data/api/analytics_api.dart';
8
9
  import 'package:kasy_kit/core/guards/user_info_guard.dart';
@@ -62,6 +63,7 @@ GoRouter generateRouter({
62
63
  },
63
64
  observers: [
64
65
  AnalyticsObserver(analyticsApi: MixpanelAnalyticsApi.instance()),
66
+ KasyChromeVisibilityObserver(),
65
67
 
66
68
  ...?observers,
67
69
  ],
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
16
16
  # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
17
17
  # In Windows, build-name is used as the major, minor, and patch parts
18
18
  # of the product and file versions while build-number is used as the build suffix.
19
- version: 1.0.0+38
19
+ version: 1.0.0+39
20
20
 
21
21
  environment:
22
22
  sdk: ^3.11.0