kasy-cli 1.21.8 → 1.22.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 +86 -38
  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/enable-auth-via-cli.js +14 -6
  31. package/lib/scaffold/backends/firebase/generator.js +5 -5
  32. package/lib/scaffold/backends/firebase/setup-from-scratch.js +69 -45
  33. package/lib/scaffold/backends/firebase/tokens.js +4 -4
  34. package/lib/scaffold/backends/supabase/deploy.js +63 -11
  35. package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
  36. package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
  37. package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
  38. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
  39. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
  40. package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
  41. package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
  42. package/lib/scaffold/backends/supabase/generator.js +17 -17
  43. package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
  44. package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
  45. package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
  46. package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
  47. package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
  48. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
  49. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
  50. 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
  51. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
  52. package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
  53. package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
  54. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
  55. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  56. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  57. package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
  58. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  59. package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
  60. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  61. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
  62. package/lib/scaffold/backends/supabase/tokens.js +3 -3
  63. package/lib/scaffold/catalog.js +9 -11
  64. package/lib/scaffold/generate.js +45 -31
  65. package/lib/scaffold/shared/generator-utils.js +188 -81
  66. package/lib/scaffold/shared/sort-imports.js +191 -0
  67. package/lib/scaffold/shared/template-strings.js +3 -3
  68. package/lib/utils/checks.js +2 -2
  69. package/lib/utils/i18n/messages-en.js +50 -35
  70. package/lib/utils/i18n/messages-es.js +50 -35
  71. package/lib/utils/i18n/messages-pt.js +52 -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} +692 -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 +57 -4
  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 +41 -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 +33 -13
  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 +118 -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 +4 -5
  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,36 +1,46 @@
1
1
  import 'package:bart/bart.dart' as bart;
2
2
  import 'package:bart/bart/bart_model.dart';
3
3
  import 'package:bart/bart/router_delegate.dart';
4
- import 'package:bart/bart/widgets/bottom_bar/styles/bottom_bar_cupertino.dart';
5
4
  import 'package:bart/bart/widgets/bottom_bar/styles/bottom_bar_custom.dart';
6
- import 'package:bart/bart/widgets/bottom_bar/styles/bottom_bar_material.dart';
7
- import 'package:flutter/foundation.dart';
8
5
  import 'package:flutter/material.dart';
9
6
  import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
10
7
  import 'package:kasy_kit/core/theme/theme.dart';
11
8
 
12
- /// Breathing room under the top hairline so icons/labels are not glued to it.
13
- const double kasyBottomBarTopPadding = 6;
9
+ /// Side breathing room so the floating bar never touches the screen edges.
10
+ const double _kFloatingSideMargin = 16;
14
11
 
15
- const double _kBottomBarHeightMaterial3 = 88;
16
- const double _kBottomBarHeightCupertino = 56;
12
+ /// Gap above the bar (separates it from the page content).
13
+ const double _kFloatingTopGap = 6;
17
14
 
18
- /// [BartScaffold] requires a [bart.BartBottomBar]. This factory draws the same
19
- /// Material / Cupertino bars as [bart.BartBottomBar.adaptive], with extra top
20
- /// inset inside the chrome (not only a taller bar).
15
+ /// Minimum gap under the bar when the device has no bottom safe-area inset
16
+ /// (Android with gesture nav / no system bar). On notched devices the real
17
+ /// inset is used instead so the home indicator stays clear.
18
+ const double _kFloatingMinBottomGap = 16;
19
+
20
+ /// Corner radius of the floating pill (HeroUI `rounded-3xl`).
21
+ const double _kFloatingRadius = KasyRadius.rounded3xl;
22
+
23
+ /// Bar (pill) inner height — the row of tab items.
24
+ const double _kBarHeight = 72;
25
+
26
+ /// Tab icon size.
27
+ const double _kNavIconSize = 24;
28
+
29
+ /// Gap between a tab's icon and its label.
30
+ const double _kNavLabelGap = 3;
31
+
32
+ /// Selection color-fade timing (muted ↔ primary highlight).
33
+ const Duration _kSelectDuration = Duration(milliseconds: 200);
34
+ const Curve _kSelectCurve = Curves.easeOut;
35
+
36
+ /// [BartScaffold] requires a [bart.BartBottomBar]. This factory draws a single,
37
+ /// custom navigation bar (same look on iOS and Android) wrapped in a floating,
38
+ /// fully rounded surface that hovers above the screen edges with a safe-area
39
+ /// aware gap underneath (iPhone home indicator / Android nav). Each tab is an
40
+ /// icon over its label; the selected one is highlighted in the primary color.
21
41
  final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
22
42
  const KasyPaddedSurfaceBottomBarFactory();
23
43
 
24
- bool _useCupertino(BuildContext context) {
25
- if (kIsWeb) {
26
- return false;
27
- }
28
- return switch (defaultTargetPlatform) {
29
- TargetPlatform.iOS => true,
30
- _ => false,
31
- };
32
- }
33
-
34
44
  @override
35
45
  Widget create({
36
46
  required BuildContext context,
@@ -45,11 +55,7 @@ final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
45
55
  }
46
56
 
47
57
  Widget _build(BuildContext context) {
48
- final KasyColors colors = context.colors;
49
58
  final MenuRouter menuRouter = MenuRouter.of(context);
50
- final BorderSide topEdge = BorderSide(
51
- color: colors.outline.withValues(alpha: 0.35),
52
- );
53
59
  void handleTap(int index) {
54
60
  if (menuRouter.indexNotifier.value == index &&
55
61
  menuRouter.routingTypeNotifier.value ==
@@ -64,82 +70,176 @@ final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
64
70
  }
65
71
  }
66
72
 
67
- if (_useCupertino(context)) {
68
- return Column(
69
- mainAxisSize: MainAxisSize.min,
70
- children: [
71
- DecoratedBox(
72
- decoration: BoxDecoration(
73
- color: colors.surface,
74
- border: Border(top: topEdge),
75
- ),
76
- child: const SizedBox(
77
- height: kasyBottomBarTopPadding,
78
- width: double.infinity,
79
- ),
80
- ),
81
- BartCupertinoBottomBar(
82
- routes: menuRouter.routesBuilder(),
83
- theme: CupertinoBottomBarTheme(
84
- bgColor: colors.surface,
85
- height: _kBottomBarHeightCupertino - kasyBottomBarTopPadding,
86
- ),
87
- currentIndexNotifier: menuRouter.indexNotifier,
88
- onTap: handleTap,
73
+ final Widget barCore = SizedBox(
74
+ height: _kBarHeight,
75
+ child: ValueListenableBuilder<int>(
76
+ valueListenable: menuRouter.indexNotifier,
77
+ builder: (context, currentIndex, _) {
78
+ // [currentIndex] / [handleTap] address the full route list, so map each
79
+ // tab back to its full-list index (robust to any non-tab route).
80
+ final List<BartMenuRoute> allRoutes = menuRouter.routesBuilder();
81
+ final List<BartMenuRoute> navRoutes = allRoutes
82
+ .where((r) => r.type == BartMenuRouteType.bottomNavigation)
83
+ .toList();
84
+ return Row(
85
+ children: [
86
+ for (final route in navRoutes)
87
+ Expanded(
88
+ child: _KasyNavItem(
89
+ route: route,
90
+ selected: allRoutes.indexOf(route) == currentIndex,
91
+ onTap: () => handleTap(allRoutes.indexOf(route)),
92
+ ),
93
+ ),
94
+ ],
95
+ );
96
+ },
97
+ ),
98
+ );
99
+
100
+ return _floating(context, barCore);
101
+ }
102
+
103
+ /// Wraps [barCore] in a floating, fully rounded surface with side margins and
104
+ /// a safe-area-aware bottom gap, over a fade that lets scrolling content melt
105
+ /// into the page background before it reaches the bar.
106
+ Widget _floating(BuildContext context, Widget barCore) {
107
+ final KasyColors colors = context.colors;
108
+ // Real bottom safe area (home indicator / system nav). [viewPaddingOf] keeps
109
+ // reporting it even though we strip it from the inner bar below.
110
+ final double safeBottom = MediaQuery.viewPaddingOf(context).bottom;
111
+ final double bottomGap =
112
+ safeBottom > 0 ? safeBottom : _kFloatingMinBottomGap;
113
+ const BorderRadius radius = BorderRadius.all(
114
+ Radius.circular(_kFloatingRadius),
115
+ );
116
+
117
+ final Widget pill = Container(
118
+ decoration: BoxDecoration(
119
+ color: colors.surface,
120
+ borderRadius: radius,
121
+ // Single, very light shadow — just enough to lift the pill off the canvas.
122
+ boxShadow: [
123
+ KasyShadows.component(
124
+ context,
125
+ blurRadius: 12,
126
+ spreadRadius: -7,
127
+ offset: const Offset(0, 3),
89
128
  ),
90
129
  ],
91
- );
92
- }
93
- return Material(
94
- color: colors.surface,
95
- elevation: 2,
96
- shadowColor: Colors.black.withValues(alpha: 0.12),
97
- child: Column(
98
- mainAxisSize: MainAxisSize.min,
99
- children: [
100
- const SizedBox(
101
- height: kasyBottomBarTopPadding,
102
- width: double.infinity,
130
+ ),
131
+ // Border drawn on top of the child so the clip never eats the hairline.
132
+ foregroundDecoration: BoxDecoration(
133
+ borderRadius: radius,
134
+ border: Border.all(
135
+ color: colors.outline.withValues(alpha: 0.35),
136
+ ),
137
+ ),
138
+ child: ClipRRect(
139
+ borderRadius: radius,
140
+ child: barCore,
141
+ ),
142
+ );
143
+
144
+ // Low bottom-up fade in the page background color: opaque at the very bottom
145
+ // (hides content scrolling under the bar), fully transparent again around the
146
+ // pill's mid-height so it stays a discreet wash low on the bar rather than a
147
+ // tall veil. Follows light/dark via the background token; same RGB at both
148
+ // ends so there is no grey halo.
149
+ final Widget fade = IgnorePointer(
150
+ child: DecoratedBox(
151
+ decoration: BoxDecoration(
152
+ gradient: LinearGradient(
153
+ begin: Alignment.bottomCenter,
154
+ end: Alignment.topCenter,
155
+ colors: [
156
+ colors.background,
157
+ colors.background,
158
+ colors.background.withValues(alpha: 0),
159
+ ],
160
+ stops: const [0.0, 0.33, 0.66],
103
161
  ),
104
- Theme(
105
- data: Theme.of(context).copyWith(
106
- splashFactory: NoSplash.splashFactory,
107
- splashColor: Colors.transparent,
108
- highlightColor: Colors.transparent,
109
- navigationBarTheme: NavigationBarTheme.of(context).copyWith(
110
- backgroundColor: Colors.transparent,
111
- elevation: 0,
112
- shadowColor: Colors.transparent,
113
- surfaceTintColor: Colors.transparent,
114
- indicatorColor: Colors.transparent,
115
- iconTheme: WidgetStateProperty.resolveWith((states) {
116
- final selected = states.contains(WidgetState.selected);
117
- return IconThemeData(
118
- color: selected ? colors.primary : colors.muted,
119
- );
120
- }),
121
- labelTextStyle: WidgetStateProperty.resolveWith((states) {
122
- final selected = states.contains(WidgetState.selected);
123
- final base = Theme.of(context).textTheme.labelMedium ??
124
- const TextStyle();
125
- return base.copyWith(
126
- color: selected ? colors.primary : colors.muted,
127
- );
128
- }),
129
- ),
130
- ),
131
- child: BartMaterial3BottomBar(
132
- routes: menuRouter.routesBuilder(),
133
- theme: Material3BottomBarTheme(
134
- bgColor: Colors.transparent,
135
- elevation: 0,
136
- height: _kBottomBarHeightMaterial3 - kasyBottomBarTopPadding,
137
- ),
138
- currentIndexNotifier: menuRouter.indexNotifier,
139
- onTap: handleTap,
140
- ),
162
+ ),
163
+ ),
164
+ );
165
+
166
+ return Stack(
167
+ children: [
168
+ Positioned.fill(child: fade),
169
+ Padding(
170
+ padding: EdgeInsets.only(
171
+ left: _kFloatingSideMargin,
172
+ right: _kFloatingSideMargin,
173
+ top: _kFloatingTopGap,
174
+ bottom: bottomGap,
141
175
  ),
142
- ],
176
+ child: pill,
177
+ ),
178
+ ],
179
+ );
180
+ }
181
+ }
182
+
183
+ /// A single bottom-bar tab: icon over its label. Selected is highlighted in the
184
+ /// primary color (icon + label); unselected is muted. Selection fades the color.
185
+ class _KasyNavItem extends StatelessWidget {
186
+ final BartMenuRoute route;
187
+ final bool selected;
188
+ final VoidCallback onTap;
189
+
190
+ const _KasyNavItem({
191
+ required this.route,
192
+ required this.selected,
193
+ required this.onTap,
194
+ });
195
+
196
+ Widget _icon(BuildContext context, Color color) {
197
+ final Widget raw = route.iconBuilder != null
198
+ ? route.iconBuilder!(context, selected)
199
+ : Icon(route.icon);
200
+ return IconTheme.merge(
201
+ data: IconThemeData(color: color, size: _kNavIconSize),
202
+ child: raw,
203
+ );
204
+ }
205
+
206
+ @override
207
+ Widget build(BuildContext context) {
208
+ final KasyColors colors = context.colors;
209
+ final TextStyle labelBase =
210
+ context.textTheme.labelMedium ?? const TextStyle();
211
+ final String label = route.label ?? '';
212
+
213
+ return Semantics(
214
+ button: true,
215
+ selected: selected,
216
+ label: label,
217
+ child: GestureDetector(
218
+ behavior: HitTestBehavior.opaque,
219
+ onTap: onTap,
220
+ child: Center(
221
+ child: TweenAnimationBuilder<double>(
222
+ tween: Tween<double>(end: selected ? 1.0 : 0.0),
223
+ duration: _kSelectDuration,
224
+ curve: _kSelectCurve,
225
+ builder: (context, t, _) {
226
+ final Color color = Color.lerp(colors.muted, colors.primary, t)!;
227
+ return Column(
228
+ mainAxisSize: MainAxisSize.min,
229
+ children: [
230
+ _icon(context, color),
231
+ const SizedBox(height: _kNavLabelGap),
232
+ Text(
233
+ label,
234
+ maxLines: 1,
235
+ overflow: TextOverflow.ellipsis,
236
+ style: labelBase.copyWith(color: color),
237
+ ),
238
+ ],
239
+ );
240
+ },
241
+ ),
242
+ ),
143
243
  ),
144
244
  );
145
245
  }
@@ -0,0 +1,41 @@
1
+ import 'package:flutter/material.dart';
2
+ import 'package:kasy_kit/components/kasy_web_header.dart';
3
+ import 'package:kasy_kit/core/theme/theme.dart';
4
+ import 'package:kasy_kit/core/widgets/responsive_layout.dart';
5
+
6
+ /// On desktop (≥ [DeviceType.large]) this puts the [KasyWebHeader] at the top of
7
+ /// the content area, above the routed page. On phone/tablet it is transparent
8
+ /// (returns the page untouched) — there the page keeps its own [KasyAppBar].
9
+ ///
10
+ /// Wrap each routed page with this in the bottom router so the header is present
11
+ /// across navigation without touching individual pages.
12
+ class WebContentWrapper extends StatelessWidget {
13
+ final Widget child;
14
+
15
+ const WebContentWrapper({super.key, required this.child});
16
+
17
+ @override
18
+ Widget build(BuildContext context) {
19
+ final bool isDesktop =
20
+ MediaQuery.sizeOf(context).width >= DeviceType.large.breakpoint;
21
+ if (!isDesktop) return child;
22
+
23
+ return ColoredBox(
24
+ color: context.colors.background,
25
+ child: Column(
26
+ crossAxisAlignment: CrossAxisAlignment.stretch,
27
+ children: [
28
+ // The sidebar carries the user profile here, so the header drops its
29
+ // avatar (showAvatar: false) to avoid duplicating the account chip.
30
+ KasyWebHeader(
31
+ onToggleTheme: () => ThemeProvider.of(context).toggle(),
32
+ onNotifications: () {},
33
+ onCreate: () {},
34
+ showAvatar: false,
35
+ ),
36
+ Expanded(child: child),
37
+ ],
38
+ ),
39
+ );
40
+ }
41
+ }
@@ -16,9 +16,6 @@ const String _kRcAndroidApiKeyFromDefine = String.fromEnvironment(
16
16
  const String _kRcIosApiKeyFromDefine = String.fromEnvironment(
17
17
  'RC_IOS_API_KEY',
18
18
  );
19
- const String _kRcWebApiKeyFromDefine = String.fromEnvironment(
20
- 'RC_WEB_API_KEY',
21
- );
22
19
  const String _kMixpanelTokenFromDefine = String.fromEnvironment(
23
20
  'MIXPANEL_TOKEN',
24
21
  );
@@ -28,8 +25,8 @@ const String _kSentryDsnFromDefine = String.fromEnvironment(
28
25
  const String _kAppStoreIdFromDefine = String.fromEnvironment(
29
26
  'APP_STORE_ID',
30
27
  );
31
- const String _kLlmChatEndpointFromDefine = String.fromEnvironment(
32
- 'LLM_CHAT_ENDPOINT',
28
+ const String _kAiChatEndpointFromDefine = String.fromEnvironment(
29
+ 'AI_CHAT_ENDPOINT',
33
30
  );
34
31
 
35
32
  // ignore: avoid_classes_with_only_static_members
@@ -68,9 +65,6 @@ class AppEnv {
68
65
  static String get rcIosApiKey =>
69
66
  _resolve(key: 'RC_IOS_API_KEY', dartDefineValue: _kRcIosApiKeyFromDefine);
70
67
 
71
- static String get rcWebApiKey =>
72
- _resolve(key: 'RC_WEB_API_KEY', dartDefineValue: _kRcWebApiKeyFromDefine);
73
-
74
68
  static String get mixpanelToken => _resolve(
75
69
  key: 'MIXPANEL_TOKEN',
76
70
  dartDefineValue: _kMixpanelTokenFromDefine,
@@ -82,9 +76,9 @@ class AppEnv {
82
76
  static String get appStoreId =>
83
77
  _resolve(key: 'APP_STORE_ID', dartDefineValue: _kAppStoreIdFromDefine);
84
78
 
85
- static String get llmChatEndpoint => _resolve(
86
- key: 'LLM_CHAT_ENDPOINT',
87
- dartDefineValue: _kLlmChatEndpointFromDefine,
79
+ static String get aiChatEndpoint => _resolve(
80
+ key: 'AI_CHAT_ENDPOINT',
81
+ dartDefineValue: _kAiChatEndpointFromDefine,
88
82
  );
89
83
 
90
84
  static String _resolve({
@@ -2,14 +2,15 @@
2
2
  /// When false, the router skips that feature's routes and the guard ignores it.
3
3
  // ignore_for_file: avoid_redundant_argument_values
4
4
  const bool withOnboarding = true;
5
- const bool withLlmChat = true;
5
+ const bool withAiChat = true;
6
6
  const bool withFeedback = true;
7
7
  const bool withRevenuecat = true;
8
- const bool withLocalNotifications = true;
8
+ const bool withLocalReminders = true;
9
9
  /// When true, the app includes web support:
10
10
  /// - anonymous sign-up is disabled on web (user is redirected to /signin)
11
11
  /// - onboarding is skipped on web
12
12
  /// - home widgets and background fetch are no-ops on web
13
13
  const bool withWeb = true;
14
- /// When true, RevenueCat Web Billing is enabled for subscriptions on web.
15
- const bool revenuecatWeb = true;
14
+ /// When true, the Stripe web-subscription module is included (web checkout +
15
+ /// customer portal). Independent from RevenueCat (which stays mobile-only).
16
+ const bool withStripe = true;
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
2
2
  import 'package:flutter_riverpod/flutter_riverpod.dart';
3
3
  import 'package:kasy_kit/core/data/models/user.dart';
4
4
  import 'package:kasy_kit/core/initializer/onstart_service.dart';
5
- import 'package:kasy_kit/environnements.dart';
5
+ import 'package:kasy_kit/environments.dart';
6
6
  import 'package:mixpanel_flutter/mixpanel_flutter.dart';
7
7
 
8
8
  final analyticsApiProvider = Provider<AnalyticsApi>(
@@ -1,6 +1,6 @@
1
1
  import 'package:dio/dio.dart';
2
2
  import 'package:flutter_riverpod/flutter_riverpod.dart';
3
- import 'package:kasy_kit/environnements.dart';
3
+ import 'package:kasy_kit/environments.dart';
4
4
 
5
5
  final httpClientProvider = Provider<HttpClient>((ref) {
6
6
  return HttpClient.fromEnv();
@@ -24,6 +24,9 @@ sealed class UserEntity with _$UserEntity {
24
24
  String? avatarPath,
25
25
  bool? onboarded,
26
26
  String? locale,
27
+ // User role for access control. Null/absent = normal user. Set to "admin"
28
+ // manually in the Firebase/Supabase console to unlock server-side admin data.
29
+ String? role,
27
30
  }) = UserEntityData;
28
31
 
29
32
  const UserEntity._();
@@ -0,0 +1,35 @@
1
+ /// Provider-agnostic subscription entitlement (an access right granted to the
2
+ /// user by an active subscription).
3
+ ///
4
+ /// This decouples the subscription core from any specific payment SDK:
5
+ /// RevenueCat's `EntitlementInfo` (mobile) and a Stripe subscription (web) both
6
+ /// map to this kit-owned type. That way a web-only app using the Stripe module
7
+ /// compiles and runs without the `purchases_flutter` package.
8
+ class Entitlement {
9
+ /// Entitlement identifier (e.g. `premium`).
10
+ final String identifier;
11
+
12
+ /// Whether the entitlement is currently active.
13
+ final bool isActive;
14
+
15
+ /// Whether the subscription is currently in a free-trial period.
16
+ final bool isInTrial;
17
+
18
+ /// Whether the subscription is set to auto-renew.
19
+ final bool willRenew;
20
+
21
+ /// Store product id backing this entitlement, when known.
22
+ final String? productId;
23
+
24
+ /// When the entitlement expires, when known.
25
+ final DateTime? expirationDate;
26
+
27
+ const Entitlement({
28
+ required this.identifier,
29
+ this.isActive = true,
30
+ this.isInTrial = false,
31
+ this.willRenew = false,
32
+ this.productId,
33
+ this.expirationDate,
34
+ });
35
+ }