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
@@ -0,0 +1,639 @@
1
+ import 'package:flutter/material.dart';
2
+ import 'package:kasy_kit/core/theme/theme.dart';
3
+ import 'package:kasy_kit/i18n/translations.g.dart';
4
+
5
+ /// Live, in‑Flutter mockups of the kit's modules used as onboarding heroes.
6
+ ///
7
+ /// They are purely presentational (no interaction) and built entirely from
8
+ /// theme tokens, so they adapt to light/dark and to the brand color. Each one
9
+ /// is a tiny, faithful preview of a real module the kit ships with.
10
+
11
+ // ─────────────────────────────────────────────────────────────────────────
12
+ // Shared building blocks
13
+ // ─────────────────────────────────────────────────────────────────────────
14
+
15
+ /// A soft brand glow behind a floating card, framed in a clean stage.
16
+ class _MockStage extends StatelessWidget {
17
+ const _MockStage({required this.child, this.maxWidth = 300});
18
+
19
+ final Widget child;
20
+ final double maxWidth;
21
+
22
+ @override
23
+ Widget build(BuildContext context) {
24
+ final primary = context.colors.primary;
25
+ return Center(
26
+ child: ConstrainedBox(
27
+ constraints: BoxConstraints(maxWidth: maxWidth),
28
+ child: Stack(
29
+ alignment: Alignment.center,
30
+ clipBehavior: Clip.none,
31
+ children: [
32
+ // Radial brand glow centered behind the card.
33
+ Positioned.fill(
34
+ child: Center(
35
+ child: Container(
36
+ width: maxWidth * 0.9,
37
+ height: maxWidth * 0.9,
38
+ decoration: BoxDecoration(
39
+ shape: BoxShape.circle,
40
+ gradient: RadialGradient(
41
+ colors: [
42
+ primary.withValues(alpha: context.isDark ? 0.22 : 0.16),
43
+ primary.withValues(alpha: 0),
44
+ ],
45
+ ),
46
+ ),
47
+ ),
48
+ ),
49
+ ),
50
+ child,
51
+ ],
52
+ ),
53
+ ),
54
+ );
55
+ }
56
+ }
57
+
58
+ /// A floating surface card with hairline border + soft elevation.
59
+ class _Card extends StatelessWidget {
60
+ const _Card({
61
+ required this.child,
62
+ this.padding = const EdgeInsets.all(KasySpacing.md),
63
+ });
64
+
65
+ final Widget child;
66
+ final EdgeInsets padding;
67
+
68
+ @override
69
+ Widget build(BuildContext context) {
70
+ final colors = context.colors;
71
+ return Container(
72
+ padding: padding,
73
+ decoration: BoxDecoration(
74
+ color: colors.surface,
75
+ borderRadius: KasyRadius.xlBorderRadius,
76
+ border: Border.all(
77
+ // Hairline: a faint light edge in dark mode, a faint dark edge in light.
78
+ color: context.isDark
79
+ ? Colors.white.withValues(alpha: 0.06)
80
+ : Colors.black.withValues(alpha: 0.06),
81
+ ),
82
+ boxShadow: [
83
+ // Always a dark shadow (never tinted by onBackground, which flips to
84
+ // near‑white in dark mode and produced a strange halo).
85
+ BoxShadow(
86
+ color: Colors.black.withValues(
87
+ alpha: context.isDark ? 0.30 : 0.10,
88
+ ),
89
+ blurRadius: 24,
90
+ offset: const Offset(0, 12),
91
+ ),
92
+ ],
93
+ ),
94
+ child: child,
95
+ );
96
+ }
97
+ }
98
+
99
+ /// Brand‑colored rounded icon badge.
100
+ class _IconBadge extends StatelessWidget {
101
+ const _IconBadge(this.icon, {this.size = 40, this.glyph = 20});
102
+
103
+ final IconData icon;
104
+ final double size;
105
+ final double glyph;
106
+
107
+ @override
108
+ Widget build(BuildContext context) {
109
+ final colors = context.colors;
110
+ return Container(
111
+ width: size,
112
+ height: size,
113
+ decoration: BoxDecoration(
114
+ gradient: LinearGradient(
115
+ begin: Alignment.topLeft,
116
+ end: Alignment.bottomRight,
117
+ colors: [
118
+ colors.primary,
119
+ Color.lerp(colors.primary, Colors.black, 0.18)!,
120
+ ],
121
+ ),
122
+ borderRadius: BorderRadius.circular(size * 0.3),
123
+ ),
124
+ child: Icon(icon, color: colors.onPrimary, size: glyph),
125
+ );
126
+ }
127
+ }
128
+
129
+ /// Skeleton line used to suggest text without spelling it out.
130
+ class _Bar extends StatelessWidget {
131
+ const _Bar({required this.width, this.height = 8, this.strong = false});
132
+
133
+ final double width;
134
+ final double height;
135
+ final bool strong;
136
+
137
+ @override
138
+ Widget build(BuildContext context) {
139
+ final colors = context.colors;
140
+ return Container(
141
+ width: width,
142
+ height: height,
143
+ decoration: BoxDecoration(
144
+ color: colors.onSurface.withValues(alpha: strong ? 0.55 : 0.14),
145
+ borderRadius: KasyRadius.fullBorderRadius,
146
+ ),
147
+ );
148
+ }
149
+ }
150
+
151
+ /// Faux primary pill (looks like [KasyButton] without being interactive).
152
+ class _PillButton extends StatelessWidget {
153
+ const _PillButton(this.label, {this.filled = true});
154
+
155
+ final String label;
156
+ final bool filled;
157
+
158
+ @override
159
+ Widget build(BuildContext context) {
160
+ final colors = context.colors;
161
+ return Container(
162
+ height: 38,
163
+ alignment: Alignment.center,
164
+ padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
165
+ decoration: BoxDecoration(
166
+ color: filled ? colors.primary : Colors.transparent,
167
+ borderRadius: KasyRadius.mdBorderRadius,
168
+ border: filled
169
+ ? null
170
+ : Border.all(color: colors.outlineButton),
171
+ ),
172
+ child: Text(
173
+ label,
174
+ maxLines: 1,
175
+ overflow: TextOverflow.ellipsis,
176
+ textAlign: TextAlign.center,
177
+ style: context.textTheme.labelLarge?.copyWith(
178
+ color: filled ? colors.onPrimary : colors.onSurface,
179
+ fontWeight: FontWeight.w700,
180
+ ),
181
+ ),
182
+ );
183
+ }
184
+ }
185
+
186
+ // ─────────────────────────────────────────────────────────────────────────
187
+ // Paywall / subscriptions
188
+ // ─────────────────────────────────────────────────────────────────────────
189
+
190
+ class PaywallMockup extends StatelessWidget {
191
+ const PaywallMockup({super.key});
192
+
193
+ @override
194
+ Widget build(BuildContext context) {
195
+ final colors = context.colors;
196
+ final t = Translations.of(context).onboarding.mockups.paywall;
197
+ return _MockStage(
198
+ maxWidth: 320,
199
+ child: _Card(
200
+ padding: const EdgeInsets.all(KasySpacing.lg),
201
+ child: Column(
202
+ mainAxisSize: MainAxisSize.min,
203
+ crossAxisAlignment: CrossAxisAlignment.stretch,
204
+ children: [
205
+ Row(
206
+ children: [
207
+ const _IconBadge(KasyIcons.star),
208
+ const SizedBox(width: KasySpacing.smd),
209
+ Column(
210
+ crossAxisAlignment: CrossAxisAlignment.start,
211
+ children: [
212
+ Text(
213
+ t.title,
214
+ style: context.textTheme.titleMedium?.copyWith(
215
+ color: colors.onSurface,
216
+ fontWeight: FontWeight.w800,
217
+ ),
218
+ ),
219
+ const SizedBox(height: 4),
220
+ const _Bar(width: 96),
221
+ ],
222
+ ),
223
+ ],
224
+ ),
225
+ const SizedBox(height: KasySpacing.lg),
226
+ _PlanRow(
227
+ title: t.annual,
228
+ price: t.price_year,
229
+ badge: t.save_badge,
230
+ selected: true,
231
+ ),
232
+ const SizedBox(height: KasySpacing.sm),
233
+ _PlanRow(title: t.monthly, price: t.price_month),
234
+ const SizedBox(height: KasySpacing.lg),
235
+ _PillButton(t.cta),
236
+ ],
237
+ ),
238
+ ),
239
+ );
240
+ }
241
+ }
242
+
243
+ class _PlanRow extends StatelessWidget {
244
+ const _PlanRow({
245
+ required this.title,
246
+ required this.price,
247
+ this.badge,
248
+ this.selected = false,
249
+ });
250
+
251
+ final String title;
252
+ final String price;
253
+ final String? badge;
254
+ final bool selected;
255
+
256
+ @override
257
+ Widget build(BuildContext context) {
258
+ final colors = context.colors;
259
+ return Container(
260
+ padding: const EdgeInsets.symmetric(
261
+ horizontal: KasySpacing.smd,
262
+ vertical: KasySpacing.smd,
263
+ ),
264
+ decoration: BoxDecoration(
265
+ color: selected ? colors.surfacePrimarySoft : colors.surfaceNeutralSoft,
266
+ borderRadius: KasyRadius.lgBorderRadius,
267
+ border: Border.all(
268
+ color: selected ? colors.primary : Colors.transparent,
269
+ width: 1.5,
270
+ ),
271
+ ),
272
+ child: Row(
273
+ children: [
274
+ Container(
275
+ width: 18,
276
+ height: 18,
277
+ decoration: BoxDecoration(
278
+ shape: BoxShape.circle,
279
+ color: selected ? colors.primary : Colors.transparent,
280
+ border: Border.all(
281
+ color: selected ? colors.primary : colors.outlineButton,
282
+ width: 2,
283
+ ),
284
+ ),
285
+ child: selected
286
+ ? Icon(KasyIcons.check, size: 12, color: colors.onPrimary)
287
+ : null,
288
+ ),
289
+ const SizedBox(width: KasySpacing.smd),
290
+ Expanded(
291
+ child: Text(
292
+ title,
293
+ maxLines: 1,
294
+ overflow: TextOverflow.ellipsis,
295
+ style: context.textTheme.titleSmall?.copyWith(
296
+ color: colors.onSurface,
297
+ fontWeight: FontWeight.w700,
298
+ ),
299
+ ),
300
+ ),
301
+ const SizedBox(width: KasySpacing.sm),
302
+ if (badge != null) ...[
303
+ Container(
304
+ padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
305
+ decoration: BoxDecoration(
306
+ color: colors.primary,
307
+ borderRadius: KasyRadius.fullBorderRadius,
308
+ ),
309
+ child: Text(
310
+ badge!,
311
+ style: context.textTheme.labelSmall?.copyWith(
312
+ color: colors.onPrimary,
313
+ fontWeight: FontWeight.w800,
314
+ letterSpacing: 0.4,
315
+ ),
316
+ ),
317
+ ),
318
+ const SizedBox(width: KasySpacing.sm),
319
+ ],
320
+ Text(
321
+ price,
322
+ style: context.textTheme.bodySmall?.copyWith(
323
+ color: colors.muted,
324
+ fontWeight: FontWeight.w600,
325
+ ),
326
+ ),
327
+ ],
328
+ ),
329
+ );
330
+ }
331
+ }
332
+
333
+ // ─────────────────────────────────────────────────────────────────────────
334
+ // Authentication
335
+ // ─────────────────────────────────────────────────────────────────────────
336
+
337
+ class AuthMockup extends StatelessWidget {
338
+ const AuthMockup({super.key});
339
+
340
+ @override
341
+ Widget build(BuildContext context) {
342
+ final colors = context.colors;
343
+ final t = Translations.of(context).onboarding.mockups.auth;
344
+ return _MockStage(
345
+ child: _Card(
346
+ padding: const EdgeInsets.all(KasySpacing.lg),
347
+ child: Column(
348
+ mainAxisSize: MainAxisSize.min,
349
+ crossAxisAlignment: CrossAxisAlignment.stretch,
350
+ children: [
351
+ Text(
352
+ t.welcome,
353
+ style: context.textTheme.titleMedium?.copyWith(
354
+ color: colors.onSurface,
355
+ fontWeight: FontWeight.w800,
356
+ ),
357
+ ),
358
+ const SizedBox(height: KasySpacing.md),
359
+ _FakeField(icon: KasyIcons.person, hint: t.email_hint),
360
+ const SizedBox(height: KasySpacing.sm),
361
+ const _FakeField(
362
+ icon: KasyIcons.security,
363
+ hint: '••••••••',
364
+ obscured: true,
365
+ ),
366
+ const SizedBox(height: KasySpacing.md),
367
+ _PillButton(t.sign_in),
368
+ const SizedBox(height: KasySpacing.md),
369
+ Row(
370
+ children: [
371
+ const Expanded(child: _Bar(width: double.infinity, height: 1)),
372
+ Padding(
373
+ padding:
374
+ const EdgeInsets.symmetric(horizontal: KasySpacing.sm),
375
+ child: Text(
376
+ t.divider,
377
+ style: context.textTheme.labelSmall?.copyWith(
378
+ color: colors.muted,
379
+ ),
380
+ ),
381
+ ),
382
+ const Expanded(child: _Bar(width: double.infinity, height: 1)),
383
+ ],
384
+ ),
385
+ const SizedBox(height: KasySpacing.md),
386
+ const Row(
387
+ children: [
388
+ Expanded(child: _SocialChip(KasyIcons.language)),
389
+ SizedBox(width: KasySpacing.sm),
390
+ Expanded(child: _SocialChip(KasyIcons.favorite)),
391
+ ],
392
+ ),
393
+ ],
394
+ ),
395
+ ),
396
+ );
397
+ }
398
+ }
399
+
400
+ class _FakeField extends StatelessWidget {
401
+ const _FakeField({
402
+ required this.icon,
403
+ required this.hint,
404
+ this.obscured = false,
405
+ });
406
+
407
+ final IconData icon;
408
+ final String hint;
409
+ final bool obscured;
410
+
411
+ @override
412
+ Widget build(BuildContext context) {
413
+ final colors = context.colors;
414
+ return Container(
415
+ height: 44,
416
+ padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
417
+ decoration: BoxDecoration(
418
+ color: colors.surfaceNeutralSoft,
419
+ borderRadius: KasyRadius.mdBorderRadius,
420
+ border: Border.all(color: colors.outline),
421
+ ),
422
+ child: Row(
423
+ children: [
424
+ Icon(icon, size: 16, color: colors.muted),
425
+ const SizedBox(width: KasySpacing.sm),
426
+ Text(
427
+ hint,
428
+ style: context.textTheme.bodyMedium?.copyWith(
429
+ color: colors.muted,
430
+ letterSpacing: obscured ? 2 : 0.1,
431
+ ),
432
+ ),
433
+ ],
434
+ ),
435
+ );
436
+ }
437
+ }
438
+
439
+ class _SocialChip extends StatelessWidget {
440
+ const _SocialChip(this.icon);
441
+
442
+ final IconData icon;
443
+
444
+ @override
445
+ Widget build(BuildContext context) {
446
+ final colors = context.colors;
447
+ return Container(
448
+ height: 40,
449
+ alignment: Alignment.center,
450
+ decoration: BoxDecoration(
451
+ color: colors.surfaceNeutralSoft,
452
+ borderRadius: KasyRadius.mdBorderRadius,
453
+ border: Border.all(color: colors.outline),
454
+ ),
455
+ child: Icon(icon, size: 18, color: colors.onSurface),
456
+ );
457
+ }
458
+ }
459
+
460
+ // ─────────────────────────────────────────────────────────────────────────
461
+ // Notifications (push toast stack)
462
+ // ─────────────────────────────────────────────────────────────────────────
463
+
464
+ class NotificationsMockup extends StatelessWidget {
465
+ const NotificationsMockup({super.key});
466
+
467
+ @override
468
+ Widget build(BuildContext context) {
469
+ final colors = context.colors;
470
+ final t = Translations.of(context).onboarding.mockups.notification;
471
+ return _MockStage(
472
+ child: Column(
473
+ mainAxisSize: MainAxisSize.min,
474
+ children: [
475
+ // Faded card behind for depth.
476
+ Transform.translate(
477
+ offset: const Offset(0, 14),
478
+ child: Transform.scale(
479
+ scale: 0.92,
480
+ child: const Opacity(
481
+ opacity: 0.5,
482
+ child: _Card(
483
+ child: SizedBox(
484
+ height: 40,
485
+ width: double.infinity,
486
+ child: Row(
487
+ children: [
488
+ _Bar(width: 32, height: 32),
489
+ SizedBox(width: KasySpacing.smd),
490
+ Column(
491
+ mainAxisAlignment: MainAxisAlignment.center,
492
+ crossAxisAlignment: CrossAxisAlignment.start,
493
+ children: [
494
+ _Bar(width: 120, strong: true),
495
+ SizedBox(height: 6),
496
+ _Bar(width: 80),
497
+ ],
498
+ ),
499
+ ],
500
+ ),
501
+ ),
502
+ ),
503
+ ),
504
+ ),
505
+ ),
506
+ _Card(
507
+ child: Row(
508
+ children: [
509
+ const _IconBadge(KasyIcons.notificationActive, glyph: 18),
510
+ const SizedBox(width: KasySpacing.smd),
511
+ Expanded(
512
+ child: Column(
513
+ crossAxisAlignment: CrossAxisAlignment.start,
514
+ children: [
515
+ Row(
516
+ children: [
517
+ Flexible(
518
+ child: Text(
519
+ t.title,
520
+ maxLines: 1,
521
+ overflow: TextOverflow.ellipsis,
522
+ style: context.textTheme.titleSmall?.copyWith(
523
+ color: colors.onSurface,
524
+ fontWeight: FontWeight.w800,
525
+ ),
526
+ ),
527
+ ),
528
+ const Spacer(),
529
+ Text(
530
+ t.time,
531
+ style: context.textTheme.labelSmall?.copyWith(
532
+ color: colors.muted,
533
+ ),
534
+ ),
535
+ ],
536
+ ),
537
+ const SizedBox(height: 6),
538
+ const _Bar(width: 160),
539
+ const SizedBox(height: 6),
540
+ const _Bar(width: 110),
541
+ ],
542
+ ),
543
+ ),
544
+ ],
545
+ ),
546
+ ),
547
+ ],
548
+ ),
549
+ );
550
+ }
551
+ }
552
+
553
+ // ─────────────────────────────────────────────────────────────────────────
554
+ // Permission dialogs (iOS‑style alert) — push & tracking
555
+ // ─────────────────────────────────────────────────────────────────────────
556
+
557
+ class PushPermissionMockup extends StatelessWidget {
558
+ const PushPermissionMockup({super.key});
559
+
560
+ @override
561
+ Widget build(BuildContext context) {
562
+ final t = Translations.of(context).onboarding.mockups.push_permission;
563
+ return _PermissionDialogMockup(
564
+ icon: KasyIcons.notificationActive,
565
+ title: t.title,
566
+ primaryLabel: t.allow,
567
+ secondaryLabel: t.deny,
568
+ );
569
+ }
570
+ }
571
+
572
+ class TrackingPermissionMockup extends StatelessWidget {
573
+ const TrackingPermissionMockup({super.key});
574
+
575
+ @override
576
+ Widget build(BuildContext context) {
577
+ final t = Translations.of(context).onboarding.mockups.tracking_permission;
578
+ return _PermissionDialogMockup(
579
+ icon: KasyIcons.privacy,
580
+ title: t.title,
581
+ primaryLabel: t.allow,
582
+ secondaryLabel: t.deny,
583
+ );
584
+ }
585
+ }
586
+
587
+ class _PermissionDialogMockup extends StatelessWidget {
588
+ const _PermissionDialogMockup({
589
+ required this.icon,
590
+ required this.title,
591
+ required this.primaryLabel,
592
+ required this.secondaryLabel,
593
+ });
594
+
595
+ final IconData icon;
596
+ final String title;
597
+ final String primaryLabel;
598
+ final String secondaryLabel;
599
+
600
+ @override
601
+ Widget build(BuildContext context) {
602
+ final colors = context.colors;
603
+ return _MockStage(
604
+ maxWidth: 272,
605
+ child: _Card(
606
+ padding: const EdgeInsets.fromLTRB(
607
+ KasySpacing.lg,
608
+ KasySpacing.lg,
609
+ KasySpacing.lg,
610
+ KasySpacing.md,
611
+ ),
612
+ child: Column(
613
+ mainAxisSize: MainAxisSize.min,
614
+ crossAxisAlignment: CrossAxisAlignment.stretch,
615
+ children: [
616
+ Center(child: _IconBadge(icon, size: 52, glyph: 26)),
617
+ const SizedBox(height: KasySpacing.md),
618
+ Text(
619
+ title,
620
+ textAlign: TextAlign.center,
621
+ style: context.textTheme.titleMedium?.copyWith(
622
+ color: colors.onSurface,
623
+ fontWeight: FontWeight.w800,
624
+ ),
625
+ ),
626
+ const SizedBox(height: KasySpacing.sm),
627
+ const Center(child: _Bar(width: 180)),
628
+ const SizedBox(height: 6),
629
+ const Center(child: _Bar(width: 130)),
630
+ const SizedBox(height: KasySpacing.lg),
631
+ _PillButton(primaryLabel),
632
+ const SizedBox(height: KasySpacing.sm),
633
+ _PillButton(secondaryLabel, filled: false),
634
+ ],
635
+ ),
636
+ ),
637
+ );
638
+ }
639
+ }