kasy-cli 1.21.9 → 1.23.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 (269) hide show
  1. package/lib/commands/add.js +93 -80
  2. package/lib/commands/configure.js +100 -32
  3. package/lib/commands/doctor.js +28 -2
  4. package/lib/commands/new.js +80 -37
  5. package/lib/commands/notifications.js +1 -1
  6. package/lib/commands/remove.js +43 -15
  7. package/lib/commands/run.js +2 -2
  8. package/lib/commands/update.js +2 -2
  9. package/lib/scaffold/CHANGELOG.json +14 -0
  10. package/lib/scaffold/backends/api/generator.js +14 -14
  11. package/lib/scaffold/backends/api/patch/README.md +83 -0
  12. package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
  13. package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +5 -0
  14. package/lib/scaffold/backends/api/patch/lib/{environnements.dart → environments.dart} +3 -11
  15. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_api.dart +108 -0
  16. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +51 -0
  17. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +5 -5
  18. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +71 -38
  19. package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +2 -2
  20. package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +54 -0
  21. package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +16 -16
  22. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  23. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  24. package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +100 -0
  25. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  26. package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +60 -0
  27. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  28. package/lib/scaffold/backends/api/pubspec.yaml.tpl +4 -5
  29. package/lib/scaffold/backends/firebase/deploy.js +87 -13
  30. package/lib/scaffold/backends/firebase/generator.js +5 -5
  31. package/lib/scaffold/backends/firebase/tokens.js +4 -4
  32. package/lib/scaffold/backends/supabase/deploy.js +63 -11
  33. package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
  34. package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
  35. package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
  36. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
  37. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
  38. package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
  39. package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
  40. package/lib/scaffold/backends/supabase/generator.js +17 -17
  41. package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
  42. package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
  43. package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
  44. package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
  45. package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
  46. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
  47. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
  48. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  49. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
  50. package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
  51. package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
  52. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
  53. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  54. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  55. package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
  56. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  57. package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
  58. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  59. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
  60. package/lib/scaffold/backends/supabase/tokens.js +3 -3
  61. package/lib/scaffold/catalog.js +9 -11
  62. package/lib/scaffold/generate.js +45 -31
  63. package/lib/scaffold/shared/generator-utils.js +188 -81
  64. package/lib/scaffold/shared/sort-imports.js +191 -0
  65. package/lib/scaffold/shared/template-strings.js +3 -3
  66. package/lib/utils/checks.js +22 -6
  67. package/lib/utils/env-tools.js +7 -0
  68. package/lib/utils/flutter-install.js +114 -0
  69. package/lib/utils/i18n/messages-en.js +52 -35
  70. package/lib/utils/i18n/messages-es.js +52 -35
  71. package/lib/utils/i18n/messages-pt.js +54 -37
  72. package/lib/utils/updates.js +15 -15
  73. package/package.json +1 -1
  74. package/templates/firebase/.env.example +2 -2
  75. package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
  76. package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
  77. package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
  78. package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
  79. package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
  80. package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
  81. package/templates/firebase/assets/images/logo_wordmark_dark.png +0 -0
  82. package/templates/firebase/assets/images/logo_wordmark_light.png +0 -0
  83. package/templates/firebase/docs/revenuecat-setup.es.md +1 -1
  84. package/templates/firebase/docs/revenuecat-setup.pt.md +1 -1
  85. package/templates/firebase/firestore.rules +24 -5
  86. package/templates/firebase/functions/package-lock.json +22 -1
  87. package/templates/firebase/functions/package.json +2 -1
  88. package/templates/firebase/functions/src/admin/functions.ts +113 -0
  89. package/templates/firebase/functions/src/{llm_chat → ai_chat}/index.ts +16 -16
  90. package/templates/firebase/functions/src/index.ts +8 -2
  91. package/templates/firebase/functions/src/notifications/device_triggers.ts +2 -2
  92. package/templates/firebase/functions/src/notifications/triggers.ts +3 -3
  93. package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +2 -0
  94. package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +222 -0
  95. package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +2 -2
  96. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
  97. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
  98. package/templates/firebase/lib/components/components.dart +4 -1
  99. package/templates/firebase/lib/components/kasy_app_bar.dart +22 -7
  100. package/templates/firebase/lib/components/kasy_avatar.dart +7 -6
  101. package/templates/firebase/lib/components/kasy_button.dart +23 -99
  102. package/templates/firebase/lib/components/kasy_dialog.dart +11 -11
  103. package/templates/firebase/lib/components/kasy_image_viewer.dart +84 -0
  104. package/templates/firebase/lib/components/{kasy_sidebar_pro.dart → kasy_sidebar.dart} +702 -425
  105. package/templates/firebase/lib/components/kasy_status_tag.dart +91 -0
  106. package/templates/firebase/lib/components/kasy_text_area.dart +1 -3
  107. package/templates/firebase/lib/components/kasy_text_field.dart +5 -6
  108. package/templates/firebase/lib/components/kasy_text_field_otp.dart +1 -3
  109. package/templates/firebase/lib/components/kasy_toast.dart +2 -2
  110. package/templates/firebase/lib/components/kasy_web_header.dart +209 -0
  111. package/templates/firebase/lib/core/ads/ads_provider.dart +1 -1
  112. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +136 -23
  113. package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +19 -91
  114. package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +196 -96
  115. package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +54 -0
  116. package/templates/firebase/lib/core/config/app_env.dart +5 -11
  117. package/templates/firebase/lib/core/config/features.dart +5 -4
  118. package/templates/firebase/lib/core/data/api/analytics_api.dart +1 -1
  119. package/templates/firebase/lib/core/data/api/http_client.dart +1 -1
  120. package/templates/firebase/lib/core/data/entities/user_entity.dart +3 -0
  121. package/templates/firebase/lib/core/data/models/entitlement.dart +35 -0
  122. package/templates/firebase/lib/core/data/models/subscription.dart +13 -186
  123. package/templates/firebase/lib/core/data/models/user.dart +11 -0
  124. package/templates/firebase/lib/core/data/repositories/user_repository.dart +1 -1
  125. package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +1 -1
  126. package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +1 -1
  127. package/templates/firebase/lib/core/icons/kasy_icons.dart +31 -1
  128. package/templates/firebase/lib/core/rating/api/rating_api.dart +2 -2
  129. package/templates/firebase/lib/core/states/logout_action.dart +25 -0
  130. package/templates/firebase/lib/core/states/user_state_notifier.dart +3 -3
  131. package/templates/firebase/lib/core/theme/colors.dart +488 -188
  132. package/templates/firebase/lib/core/theme/radius.dart +22 -11
  133. package/templates/firebase/lib/core/theme/shadows.dart +66 -0
  134. package/templates/firebase/lib/core/theme/texts.dart +75 -41
  135. package/templates/firebase/lib/core/theme/universal_theme.dart +9 -4
  136. package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +5 -4
  137. package/templates/firebase/lib/core/web_viewport_scale.dart +52 -0
  138. package/templates/firebase/lib/core/widgets/kasy_brand_badge.dart +118 -0
  139. package/templates/firebase/lib/core/widgets/kasy_brand_logo.dart +40 -0
  140. package/templates/firebase/lib/core/widgets/kasy_focus_ring.dart +125 -0
  141. package/templates/firebase/lib/core/widgets/kasy_hover.dart +53 -14
  142. package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +18 -13
  143. package/templates/firebase/lib/{environnements.dart → environments.dart} +3 -14
  144. package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +159 -0
  145. package/templates/firebase/lib/features/ai_chat/api/ai_chat_api.dart +107 -0
  146. package/templates/firebase/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +64 -0
  147. package/templates/firebase/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  148. package/templates/firebase/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +73 -38
  149. package/templates/firebase/lib/features/ai_chat/providers/ai_conversations_notifier.dart +103 -0
  150. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_avatars.dart → ai_chat/ui/widgets/ai_chat_avatars.dart} +13 -13
  151. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_composer.dart → ai_chat/ui/widgets/ai_chat_composer.dart} +10 -10
  152. package/templates/firebase/lib/features/{llm_chat/llm_chat_page.dart → ai_chat/ui/widgets/ai_chat_conversation_view.dart} +80 -67
  153. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +285 -0
  154. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +163 -0
  155. package/templates/firebase/lib/features/authentication/api/authentication_api.dart +52 -13
  156. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher.dart +12 -0
  157. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher_web.dart +35 -0
  158. package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +108 -68
  159. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +38 -51
  160. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +38 -51
  161. package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +128 -0
  162. package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +61 -44
  163. package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +32 -0
  164. package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +5 -5
  165. package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +2 -2
  166. package/templates/firebase/lib/features/home/design_system_page.dart +808 -170
  167. package/templates/firebase/lib/features/home/home_components_page.dart +6 -3
  168. package/templates/firebase/lib/features/home/home_components_preview_page.dart +6 -6
  169. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +325 -186
  170. package/templates/firebase/lib/features/home/home_feed.dart +289 -0
  171. package/templates/firebase/lib/features/home/home_image_grid.dart +355 -0
  172. package/templates/firebase/lib/features/home/home_page.dart +11 -250
  173. package/templates/firebase/lib/features/{local_reminder → local_reminders}/providers/reminder_notifier.dart +1 -1
  174. package/templates/firebase/lib/features/{local_reminder → local_reminders}/ui/reminder_page.dart +2 -2
  175. package/templates/firebase/lib/features/notifications/shared/att_permission.dart +1 -1
  176. package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +25 -61
  177. package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +117 -0
  178. package/templates/firebase/lib/features/onboarding/models/user_info.dart +16 -16
  179. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  180. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +7 -9
  181. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +71 -48
  182. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +3 -2
  183. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +5 -5
  184. package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +4 -4
  185. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +4 -2
  186. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +39 -121
  187. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +105 -70
  188. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +639 -0
  189. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +62 -50
  190. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  191. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_step_header.dart +75 -0
  192. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +16 -5
  193. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +26 -22
  194. package/templates/firebase/lib/features/settings/settings_page.dart +601 -90
  195. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +1193 -0
  196. package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +1 -1
  197. package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +2 -3
  198. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +86 -0
  199. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +1215 -0
  200. package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +236 -0
  201. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +3 -3
  202. package/templates/firebase/lib/features/settings/ui/widgets/kasy_user_avatar.dart +77 -0
  203. package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +1 -0
  204. package/templates/firebase/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +17 -0
  205. package/templates/firebase/lib/features/{subscription → subscriptions}/api/inapp_subscription_api.dart +67 -46
  206. package/templates/firebase/lib/features/subscriptions/api/revenuecat_product.dart +189 -0
  207. package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +55 -0
  208. package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +82 -0
  209. package/templates/firebase/lib/features/subscriptions/api/stripe_product.dart +178 -0
  210. package/templates/firebase/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  211. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api.dart +53 -0
  212. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api_provider.dart +21 -0
  213. package/templates/firebase/lib/features/{subscription → subscriptions}/providers/premium_page_provider.dart +9 -6
  214. package/templates/firebase/lib/features/{subscription → subscriptions}/repositories/subscription_repository.dart +26 -30
  215. package/{lib/scaffold/backends/supabase/patch/lib/features/subscription → templates/firebase/lib/features/subscriptions}/shared/maybeshow_premium.dart +0 -2
  216. package/templates/firebase/lib/features/subscriptions/shared/subscription_management.dart +45 -0
  217. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/active_premium_content.dart +28 -4
  218. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_minimal.dart +7 -7
  219. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_row.dart +8 -8
  220. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_with_switch.dart +7 -7
  221. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_content.dart +7 -7
  222. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_page_factory.dart +5 -5
  223. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/premium_page.dart +5 -5
  224. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/comparison_table.dart +1 -1
  225. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/paywall_empty_state.dart +4 -4
  226. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_bottom_menu.dart +3 -4
  227. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_col.dart +1 -1
  228. package/templates/firebase/lib/i18n/en.i18n.json +171 -46
  229. package/templates/firebase/lib/i18n/es.i18n.json +175 -50
  230. package/templates/firebase/lib/i18n/pt.i18n.json +166 -41
  231. package/templates/firebase/lib/main.dart +6 -3
  232. package/templates/firebase/lib/router.dart +15 -23
  233. package/templates/firebase/pubspec.yaml +5 -6
  234. package/templates/firebase/test/core/data/repositories/user_repository_test.dart +3 -3
  235. package/templates/firebase/test/core/states/user_state_notifier_test.dart +4 -4
  236. package/templates/firebase/test/core/widgets/focus_ring_shape_test.dart +55 -0
  237. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_inapp_subscription_api.dart +11 -4
  238. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_revenuecat_product.dart +1 -0
  239. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_subscription_api.dart +2 -2
  240. package/templates/firebase/test/features/{subscription → subscriptions}/subscription_page_test.dart +4 -4
  241. package/templates/firebase/test/test_utils.dart +6 -6
  242. package/templates/firebase/web/index.html +5 -2
  243. package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -58
  244. package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -86
  245. package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +0 -22
  246. package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -47
  247. package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
  248. package/templates/firebase/assets/images/onboarding/img2.jpg +0 -0
  249. package/templates/firebase/assets/images/onboarding/img3.jpg +0 -0
  250. package/templates/firebase/assets/images/onboarding/notifications.png +0 -0
  251. package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
  252. package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +0 -2021
  253. package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +0 -35
  254. package/templates/firebase/lib/features/home/home_features_page.dart +0 -207
  255. package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +0 -50
  256. package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +0 -316
  257. package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +0 -85
  258. /package/templates/firebase/lib/features/{local_reminder → local_reminders}/repositories/reminder_preferences.dart +0 -0
  259. /package/templates/firebase/lib/features/{subscription → subscriptions}/providers/models/premium_state.dart +0 -0
  260. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/feature_line.dart +0 -0
  261. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background.dart +0 -0
  262. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background_gradient.dart +0 -0
  263. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_banner.dart +0 -0
  264. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_card.dart +0 -0
  265. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_close_button.dart +0 -0
  266. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_feature.dart +0 -0
  267. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_row.dart +0 -0
  268. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/trial_switcher.dart +0 -0
  269. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/unsubscribe_feedback_popup.dart +0 -0
@@ -1,10 +1,25 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:kasy_kit/core/theme/theme.dart';
3
3
 
4
+ /// Total number of progress steps shown across the onboarding flow.
5
+ ///
6
+ /// feature 1‑3 → steps 1‑3, gender → 4, age → 5, permissions → 6.
7
+ const int kOnboardingSteps = 6;
8
+
9
+ /// Segmented progress indicator (one pill per step).
10
+ ///
11
+ /// Completed steps are fully filled; the current step animates its fill from
12
+ /// left to right on mount; upcoming steps render as a faded track.
4
13
  class OnboardingProgress extends StatefulWidget {
5
- final double value;
14
+ /// 1‑based index of the current step.
15
+ final int step;
16
+ final int totalSteps;
6
17
 
7
- const OnboardingProgress({super.key, required this.value});
18
+ const OnboardingProgress({
19
+ super.key,
20
+ required this.step,
21
+ this.totalSteps = kOnboardingSteps,
22
+ });
8
23
 
9
24
  @override
10
25
  State<OnboardingProgress> createState() => _OnboardingProgressState();
@@ -12,73 +27,70 @@ class OnboardingProgress extends StatefulWidget {
12
27
 
13
28
  class _OnboardingProgressState extends State<OnboardingProgress>
14
29
  with SingleTickerProviderStateMixin {
15
- late final AnimationController animationController;
16
-
17
- late Animation<double> _progressAnimation;
30
+ late final AnimationController _controller;
31
+ late final Animation<double> _fill;
18
32
 
19
33
  @override
20
34
  void initState() {
21
35
  super.initState();
22
-
23
- animationController = AnimationController(
36
+ _controller = AnimationController(
24
37
  vsync: this,
25
- duration: const Duration(milliseconds: 1500),
38
+ duration: const Duration(milliseconds: 650),
26
39
  );
27
- _setProgressValueAndStart();
28
- }
29
-
30
- @override
31
- void didUpdateWidget(OnboardingProgress oldWidget) {
32
- super.didUpdateWidget(oldWidget);
33
- if (oldWidget.value != widget.value) {
34
- _setProgressValueAndStart();
35
- }
40
+ _fill = CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic);
41
+ _controller.forward();
36
42
  }
37
43
 
38
44
  @override
39
45
  void dispose() {
40
- animationController.dispose();
46
+ _controller.dispose();
41
47
  super.dispose();
42
48
  }
43
49
 
44
- void _setProgressValueAndStart() {
45
- var start = 0.0;
46
- if (widget.value > 0) {
47
- start = widget.value - 0.1;
48
- }
49
- _progressAnimation = Tween<double>(
50
- begin: start,
51
- end: widget.value,
52
- ).animate(
53
- CurvedAnimation(
54
- parent: animationController,
55
- curve: Curves.ease,
56
- ),
57
- );
58
- animationController.forward(from: 0);
59
- }
60
-
61
50
  @override
62
51
  Widget build(BuildContext context) {
63
- return AnimatedBuilder(
64
- animation: _progressAnimation,
65
- builder: (context, child) {
66
- return Padding(
67
- // Intentionally narrow (80px lateral) — visual design choice for progress bar
68
- padding: const EdgeInsets.fromLTRB(80, KasySpacing.md, 80, 0),
69
- child: ClipRRect(
70
- borderRadius: KasyRadius.fullBorderRadius,
71
- child: LinearProgressIndicator(
72
- value: _progressAnimation.value,
73
- minHeight: 16,
74
- valueColor: AlwaysStoppedAnimation<Color>(
75
- context.colors.primary,
52
+ final colors = context.colors;
53
+ final track = colors.primary.withValues(alpha: context.isDark ? 0.18 : 0.12);
54
+ final current = widget.step - 1; // 0‑based
55
+
56
+ return Row(
57
+ children: List.generate(widget.totalSteps, (i) {
58
+ final isLast = i == widget.totalSteps - 1;
59
+ final isCompleted = i < current;
60
+ final isCurrent = i == current;
61
+
62
+ return Expanded(
63
+ child: Padding(
64
+ padding: EdgeInsets.only(right: isLast ? 0 : KasySpacing.sm),
65
+ child: ClipRRect(
66
+ borderRadius: KasyRadius.fullBorderRadius,
67
+ child: SizedBox(
68
+ height: 6,
69
+ child: Stack(
70
+ children: [
71
+ Positioned.fill(child: ColoredBox(color: track)),
72
+ if (isCompleted)
73
+ Positioned.fill(
74
+ child: ColoredBox(color: colors.primary),
75
+ ),
76
+ if (isCurrent)
77
+ Positioned.fill(
78
+ child: AnimatedBuilder(
79
+ animation: _fill,
80
+ builder: (context, _) => FractionallySizedBox(
81
+ alignment: Alignment.centerLeft,
82
+ widthFactor: _fill.value,
83
+ child: ColoredBox(color: colors.primary),
84
+ ),
85
+ ),
86
+ ),
87
+ ],
88
+ ),
76
89
  ),
77
- backgroundColor: context.colors.primary.withValues(alpha: 0.1),
78
90
  ),
79
91
  ),
80
92
  );
81
- },
93
+ }),
82
94
  );
83
95
  }
84
96
  }
@@ -7,6 +7,7 @@ import 'package:kasy_kit/core/theme/theme.dart';
7
7
  import 'package:kasy_kit/core/widgets/responsive_layout.dart';
8
8
  import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_background.dart';
9
9
  import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_progress.dart';
10
+ import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_step_header.dart';
10
11
  import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_sticky_footer.dart';
11
12
  import 'package:kasy_kit/features/onboarding/ui/widgets/selectable_row_tile.dart';
12
13
 
@@ -18,9 +19,11 @@ typedef OnOptionIdSelected = void Function(String id);
18
19
 
19
20
  typedef OnValidate = void Function(String? key);
20
21
 
21
- /// Single choice question with radio buttons
22
+ /// Single choice question with selectable tiles, matching the clean‑premium
23
+ /// onboarding layout (shared header, left‑aligned title, sticky footer).
22
24
  class OnboardingRadioQuestion extends ConsumerStatefulWidget {
23
- final double? progress;
25
+ final int step;
26
+ final int totalSteps;
24
27
  final String title;
25
28
  final String description;
26
29
  final String btnText;
@@ -37,7 +40,8 @@ class OnboardingRadioQuestion extends ConsumerStatefulWidget {
37
40
  required this.btnText,
38
41
  required this.optionIds,
39
42
  required this.optionBuilder,
40
- this.progress,
43
+ required this.step,
44
+ this.totalSteps = kOnboardingSteps,
41
45
  this.onOptionIdSelected,
42
46
  this.onValidate,
43
47
  this.reassuranceBuilder,
@@ -54,61 +58,68 @@ class _OnboardingRadioQuestionState
54
58
 
55
59
  @override
56
60
  Widget build(BuildContext context) {
61
+ const gutter = KasySpacing.lg;
62
+
57
63
  final scrollBody = Column(
58
- crossAxisAlignment: CrossAxisAlignment.stretch,
64
+ crossAxisAlignment: CrossAxisAlignment.start,
59
65
  children: [
60
- if (widget.progress != null)
61
- OnboardingProgress(value: widget.progress!),
66
+ OnboardingStepHeader(step: widget.step, totalSteps: widget.totalSteps),
62
67
  Padding(
63
- padding: const EdgeInsets.fromLTRB(
64
- KasySpacing.md,
65
- KasySpacing.xl,
66
- KasySpacing.md,
67
- 0,
68
- ),
68
+ padding: const EdgeInsets.fromLTRB(gutter, KasySpacing.lg, gutter, 0),
69
69
  child: MoveFadeAnim(
70
- delayInMs: 100,
70
+ delayInMs: 120,
71
71
  child: Text(
72
72
  widget.title,
73
- textAlign: TextAlign.center,
74
- style: context.textTheme.headlineLarge?.copyWith(
73
+ textAlign: TextAlign.start,
74
+ style: context.textTheme.headlineMedium?.copyWith(
75
75
  color: context.colors.onBackground,
76
+ fontSize: 26,
77
+ fontWeight: FontWeight.w700,
78
+ letterSpacing: -0.2,
79
+ height: 1.2,
76
80
  ),
77
81
  ),
78
82
  ),
79
83
  ),
80
84
  Padding(
81
85
  padding: const EdgeInsets.fromLTRB(
86
+ gutter,
87
+ KasySpacing.smd,
88
+ gutter,
82
89
  KasySpacing.lg,
83
- KasySpacing.md,
84
- KasySpacing.lg,
85
- KasySpacing.xl,
86
90
  ),
87
91
  child: MoveFadeAnim(
88
92
  delayInMs: 200,
89
93
  child: Text(
90
94
  widget.description,
91
- textAlign: TextAlign.center,
95
+ textAlign: TextAlign.start,
92
96
  style: context.textTheme.bodyLarge?.copyWith(
93
- color: context.colors.onBackground.withValues(alpha: 0.6),
97
+ color: context.colors.muted,
98
+ height: 1.45,
94
99
  ),
95
100
  ),
96
101
  ),
97
102
  ),
98
103
  Padding(
99
- padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
104
+ padding: const EdgeInsets.symmetric(horizontal: gutter),
100
105
  child: OnboardingSelectableRowGroup(
101
106
  physics: const NeverScrollableScrollPhysics(),
102
- options: widget.optionIds
103
- .map(
107
+ options: widget.optionIds.map(
104
108
  (e) {
105
109
  final index = widget.optionIds.indexOf(e);
106
110
  return Animate(
107
111
  effects: [
108
112
  FadeEffect(
109
- delay: Duration(milliseconds: 300 + index * 100),
110
- duration: const Duration(milliseconds: 550),
111
- curve: Curves.easeInOut,
113
+ delay: Duration(milliseconds: 280 + index * 80),
114
+ duration: const Duration(milliseconds: 450),
115
+ curve: Curves.easeOut,
116
+ ),
117
+ MoveEffect(
118
+ delay: Duration(milliseconds: 280 + index * 80),
119
+ duration: const Duration(milliseconds: 450),
120
+ curve: Curves.easeOut,
121
+ begin: const Offset(0, 24),
122
+ end: Offset.zero,
112
123
  ),
113
124
  ],
114
125
  child: widget.optionBuilder(e, e == selectedChoiceId),
@@ -153,8 +164,7 @@ class _OnboardingRadioQuestionState
153
164
  ),
154
165
  DeviceSizeBuilder(
155
166
  builder: (device) => OnboardingStickyFooter(
156
- maxContentWidth:
157
- device == DeviceType.small ? null : 600,
167
+ maxContentWidth: device == DeviceType.small ? null : 600,
158
168
  children: [
159
169
  KasyButton(
160
170
  label: widget.btnText,
@@ -0,0 +1,75 @@
1
+ import 'package:flutter/material.dart';
2
+ import 'package:flutter_animate/flutter_animate.dart';
3
+ import 'package:kasy_kit/components/kasy_button.dart';
4
+ import 'package:kasy_kit/core/theme/theme.dart';
5
+ import 'package:kasy_kit/core/widgets/kasy_brand_logo.dart';
6
+ import 'package:kasy_kit/features/onboarding/ui/widgets/onboarding_progress.dart';
7
+
8
+ /// Shared onboarding header: segmented progress + a zero‑padded "01 / 06"
9
+ /// counter, with an optional trailing Skip action. Keeps every step pixel
10
+ /// consistent.
11
+ class OnboardingStepHeader extends StatelessWidget {
12
+ const OnboardingStepHeader({
13
+ super.key,
14
+ required this.step,
15
+ this.totalSteps = kOnboardingSteps,
16
+ this.onSkip,
17
+ this.skipLabel,
18
+ this.horizontalPadding = KasySpacing.lg,
19
+ });
20
+
21
+ final int step;
22
+ final int totalSteps;
23
+ final VoidCallback? onSkip;
24
+ final String? skipLabel;
25
+ final double horizontalPadding;
26
+
27
+ @override
28
+ Widget build(BuildContext context) {
29
+ return Padding(
30
+ padding: EdgeInsets.fromLTRB(
31
+ horizontalPadding,
32
+ KasySpacing.md,
33
+ horizontalPadding,
34
+ 0,
35
+ ),
36
+ child: Column(
37
+ crossAxisAlignment: CrossAxisAlignment.stretch,
38
+ children: [
39
+ Center(
40
+ child: const KasyBrandLogo()
41
+ .animate()
42
+ .fadeIn(
43
+ duration: const Duration(milliseconds: 420),
44
+ curve: Curves.easeOut,
45
+ ),
46
+ ),
47
+ const SizedBox(height: KasySpacing.md),
48
+ OnboardingProgress(step: step, totalSteps: totalSteps),
49
+ const SizedBox(height: KasySpacing.smd),
50
+ Row(
51
+ children: [
52
+ Text(
53
+ '${step.toString().padLeft(2, '0')} / '
54
+ '${totalSteps.toString().padLeft(2, '0')}',
55
+ style: context.textTheme.labelMedium?.copyWith(
56
+ color: context.colors.muted,
57
+ fontWeight: FontWeight.w700,
58
+ letterSpacing: 1,
59
+ ),
60
+ ),
61
+ const Spacer(),
62
+ if (onSkip != null)
63
+ KasyButton(
64
+ label: skipLabel ?? 'Skip',
65
+ variant: KasyButtonVariant.ghost,
66
+ size: KasyButtonSize.small,
67
+ onPressed: onSkip,
68
+ ),
69
+ ],
70
+ ),
71
+ ],
72
+ ),
73
+ );
74
+ }
75
+ }
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
3
3
  import 'package:kasy_kit/core/animations/movefade_anim.dart';
4
4
  import 'package:kasy_kit/core/theme/theme.dart';
5
5
 
6
- /// Rodapé fixo do onboarding: fundo até a borda inferior + animação de entrada.
6
+ /// Sticky onboarding footer: background down to the bottom edge + entrance animation.
7
7
  class OnboardingStickyFooter extends StatelessWidget {
8
8
  const OnboardingStickyFooter({
9
9
  super.key,
@@ -19,7 +19,7 @@ class OnboardingStickyFooter extends StatelessWidget {
19
19
  final int animationDelayMs;
20
20
  final double horizontalPadding;
21
21
 
22
- /// Largura máxima do conteúdo (ex.: 600 em telas médias).
22
+ /// Maximum content width (e.g. 600 on medium screens).
23
23
  final double? maxContentWidth;
24
24
 
25
25
  @override
@@ -44,11 +44,22 @@ class OnboardingStickyFooter extends StatelessWidget {
44
44
  width: double.infinity,
45
45
  decoration: BoxDecoration(
46
46
  color: context.colors.background,
47
+ border: Border(
48
+ top: BorderSide(
49
+ // Hairline separator: faint light in dark mode, faint dark in light.
50
+ color: context.isDark
51
+ ? Colors.white.withValues(alpha: 0.06)
52
+ : Colors.black.withValues(alpha: 0.06),
53
+ ),
54
+ ),
47
55
  boxShadow: [
56
+ // Dark, never tinted — avoids a white halo above the footer in dark mode.
48
57
  BoxShadow(
49
- color: context.colors.onBackground.withValues(alpha: 0.06),
50
- blurRadius: 16,
51
- offset: const Offset(0, -4),
58
+ color: Colors.black.withValues(
59
+ alpha: context.isDark ? 0.20 : 0.04,
60
+ ),
61
+ blurRadius: 20,
62
+ offset: const Offset(0, -6),
52
63
  ),
53
64
  ],
54
65
  ),
@@ -62,8 +62,9 @@ class _OnboardingSelectableRowGroupState
62
62
  children: [
63
63
  Material(
64
64
  color: Colors.transparent,
65
- borderRadius: KasyRadius.mdBorderRadius,
65
+ borderRadius: KasyRadius.lgBorderRadius,
66
66
  child: InkWell(
67
+ borderRadius: KasyRadius.lgBorderRadius,
67
68
  onTap: () {
68
69
  if (_selectedIndex == index) {
69
70
  return;
@@ -241,20 +242,22 @@ class _SelectableRowTileState extends State<SelectableRowTile>
241
242
 
242
243
  @override
243
244
  Widget build(BuildContext context) {
244
- return Ink(
245
+ final colors = context.colors;
246
+ return AnimatedContainer(
247
+ duration: const Duration(milliseconds: 180),
248
+ curve: Curves.easeOut,
245
249
  decoration: BoxDecoration(
246
250
  border: Border.all(
247
- color: widget.selected //
248
- ? context.colors.primary.withValues(alpha:.6)
249
- : context.colors.primary.withValues(alpha:.1),
250
- width: widget.selected ? 2 : 1,
251
+ color: widget.selected ? colors.primary : colors.outline,
252
+ width: widget.selected ? 1.5 : 1,
251
253
  ),
252
- borderRadius: KasyRadius.mdBorderRadius,
253
- color: widget.selected
254
- ? context.colors.primary.withValues(alpha:.3)
255
- : context.colors.surface,
254
+ borderRadius: KasyRadius.lgBorderRadius,
255
+ color: widget.selected ? colors.surfacePrimarySoft : colors.surface,
256
+ ),
257
+ padding: const EdgeInsets.symmetric(
258
+ horizontal: KasySpacing.md,
259
+ vertical: KasySpacing.md + 2,
256
260
  ),
257
- padding: const EdgeInsets.symmetric(horizontal: KasySpacing.lg, vertical: KasySpacing.md),
258
261
  child: Row(
259
262
  children: [
260
263
  if (widget.emoj != null)
@@ -278,7 +281,9 @@ class _SelectableRowTileState extends State<SelectableRowTile>
278
281
  Text(
279
282
  widget.title!,
280
283
  style: context.textTheme.bodyLarge?.copyWith(
281
- fontWeight: FontWeight.w400,
284
+ color: colors.onSurface,
285
+ fontWeight:
286
+ widget.selected ? FontWeight.w700 : FontWeight.w600,
282
287
  ),
283
288
  ),
284
289
  if (widget.subtitle != null)
@@ -342,8 +347,8 @@ class RoundRadioBox extends StatelessWidget {
342
347
  double iconSize = 1,
343
348
  }) {
344
349
  return RoundRadioBox(
345
- bgColor: context.colors.background.withValues(alpha:.3),
346
- borderColor: context.colors.onPrimary.withValues(alpha:.3),
350
+ bgColor: context.colors.primary,
351
+ borderColor: context.colors.primary,
347
352
  icon: KasyIcons.check,
348
353
  iconOpacity: iconOpacity,
349
354
  iconSize: iconSize,
@@ -353,23 +358,22 @@ class RoundRadioBox extends StatelessWidget {
353
358
  // ignore: avoid_unused_constructor_parameters
354
359
  factory RoundRadioBox.unselected(BuildContext context) {
355
360
  return RoundRadioBox(
356
- bgColor: context.colors.outline,
357
- borderColor: context.colors.surface.withValues(alpha:.1),
361
+ bgColor: Colors.transparent,
362
+ borderColor: context.colors.outlineButton,
358
363
  );
359
364
  }
360
365
 
361
366
  @override
362
367
  Widget build(BuildContext context) {
363
368
  return Container(
364
- width: 28,
365
- height: 28,
369
+ width: 24,
370
+ height: 24,
366
371
  decoration: BoxDecoration(
367
372
  color: bgColor,
368
373
  shape: BoxShape.circle,
369
374
  border: Border.all(
370
375
  color: borderColor,
371
- width: 4,
372
- strokeAlign: BorderSide.strokeAlignOutside,
376
+ width: 2,
373
377
  ),
374
378
  ),
375
379
  child: Center(
@@ -380,8 +384,8 @@ class RoundRadioBox extends StatelessWidget {
380
384
  scale: iconSize,
381
385
  child: Icon(
382
386
  icon,
383
- color: context.colors.muted,
384
- size: 21,
387
+ color: context.colors.onPrimary,
388
+ size: 15,
385
389
  ),
386
390
  ),
387
391
  )