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
@@ -29,9 +29,17 @@ import 'package:flutter/foundation.dart' show kIsWeb;
29
29
  import 'package:flutter/material.dart';
30
30
  import 'package:flutter/services.dart' show SystemUiOverlayStyle;
31
31
  import 'package:kasy_kit/core/theme/theme.dart';
32
+ import 'package:kasy_kit/core/widgets/responsive_layout.dart';
32
33
 
33
34
  /// Inner toolbar band height (orbit hit targets, title baseline).
34
35
  const double kasyAppBarToolbarRowHeight = 44;
36
+
37
+ /// Effective toolbar band height. [KasyAppBar] serves phone and tablet only — on
38
+ /// desktop the richer web header takes over — so the band keeps a single
39
+ /// compact height across every viewport where the app bar appears.
40
+ double kasyAppBarToolbarRowHeightOf(BuildContext context) =>
41
+ kasyAppBarToolbarRowHeight;
42
+
35
43
  const double kasyAppBarTitleFontScale = 0.92;
36
44
 
37
45
  /// Tight vertical padding inside the frost, above/below [kasyAppBarToolbarRowHeight].
@@ -48,9 +56,13 @@ enum KasyAppBarScrollTreatment { overlay, intrinsicScroll }
48
56
 
49
57
  /// Vertical inset for scroll/viewport when using [KasyAppBarScrollTreatment.overlay].
50
58
  double kasyAppBarBodyTopOverlap(BuildContext context) {
59
+ // On desktop the app bar hides (the web header owns the top chrome).
60
+ if (MediaQuery.sizeOf(context).width >= DeviceType.large.breakpoint) {
61
+ return 0;
62
+ }
51
63
  return MediaQuery.paddingOf(context).top +
52
64
  kasyAppBarChromePaddingTop +
53
- kasyAppBarToolbarRowHeight +
65
+ kasyAppBarToolbarRowHeightOf(context) +
54
66
  kasyAppBarChromePaddingBottom;
55
67
  }
56
68
 
@@ -112,13 +124,11 @@ class KasyFrostedChromeBackground extends StatelessWidget {
112
124
  });
113
125
 
114
126
  /// Translucent tint so blurred content shows through; tuned per brightness.
127
+ /// Derived from the global `surface` token so the bar lifts off the canvas
128
+ /// and follows light/dark automatically.
115
129
  Color _tint(BuildContext context) {
116
130
  final bool dark = Theme.of(context).brightness == Brightness.dark;
117
- if (dark) {
118
- return const Color(0xFF161618).withValues(alpha: 0.88);
119
- }
120
- // White (surface) instead of background grey so the bar lifts off the canvas.
121
- return const Color(0xFFFFFFFF).withValues(alpha: 0.82);
131
+ return context.colors.surface.withValues(alpha: dark ? 0.88 : 0.82);
122
132
  }
123
133
 
124
134
  @override
@@ -227,11 +237,16 @@ class KasyAppBar extends StatelessWidget {
227
237
 
228
238
  @override
229
239
  Widget build(BuildContext context) {
240
+ // On desktop the web header owns the top chrome, so the page app bar hides.
241
+ if (MediaQuery.sizeOf(context).width >= DeviceType.large.breakpoint) {
242
+ return const SizedBox.shrink();
243
+ }
230
244
  final Color orbFg = context.colors.onSurface;
231
245
  final Color orbFill = kasyChromeOrbFillColor(context);
232
246
  final VoidCallback handleBack = onBack ?? () => Navigator.maybePop(context);
233
247
 
234
- final double rowHeight = toolbarHeight ?? kasyAppBarToolbarRowHeight;
248
+ final double rowHeight =
249
+ toolbarHeight ?? kasyAppBarToolbarRowHeightOf(context);
235
250
  final Widget leading = switch (style) {
236
251
  KasyAppBarStyle.rootTab => SizedBox(
237
252
  width: 44,
@@ -153,9 +153,9 @@ class KasyAvatar extends StatelessWidget {
153
153
  width: _d,
154
154
  height: _d,
155
155
  fit: BoxFit.cover,
156
- // Evita o blur de decodificação progressiva de JPEG:
157
- // enquanto a imagem carrega, mostra o fallback; quando o primeiro
158
- // frame está pronto, faz crossfade suave.
156
+ // Avoids the blur from progressive JPEG decoding:
157
+ // while the image loads, show the fallback; when the first
158
+ // frame is ready, do a smooth crossfade.
159
159
  frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
160
160
  if (wasSynchronouslyLoaded) return child;
161
161
  return SizedBox(
@@ -301,7 +301,7 @@ class KasyAvatar extends StatelessWidget {
301
301
  width: badge,
302
302
  height: badge,
303
303
  decoration: BoxDecoration(
304
- color: const Color(0xFF81C784),
304
+ color: context.colors.success,
305
305
  shape: BoxShape.circle,
306
306
  border: Border.all(color: context.colors.surface, width: 2),
307
307
  ),
@@ -451,8 +451,9 @@ _KasyAvatarColors _colorsForTone(
451
451
  final KasyColors k = context.colors;
452
452
  final bool dark = context.isDark;
453
453
 
454
- // Accent color per tone (Figma: accent=#0485F7, success=#17C964,
455
- // warning=#F5A524, danger=#FF383C, neutral uses neutral fg).
454
+ // Accent color per tone, from the global theme tokens: the "blue" tone maps
455
+ // to the primary accent, success/warning/danger to their semantic tokens,
456
+ // neutral to the foreground.
456
457
  Color accentColor() => switch (tone) {
457
458
  KasyAvatarTone.blue => k.primary,
458
459
  KasyAvatarTone.neutral => k.grey3,
@@ -1,7 +1,7 @@
1
1
  import 'package:flutter/foundation.dart' show kIsWeb;
2
2
  import 'package:flutter/material.dart';
3
- import 'package:flutter/services.dart';
4
3
  import 'package:kasy_kit/core/theme/theme.dart';
4
+ import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
5
5
  import 'package:kasy_kit/core/widgets/kasy_hover.dart';
6
6
  import 'package:kasy_kit/core/widgets/kasy_pressable_depth.dart';
7
7
 
@@ -496,8 +496,8 @@ class _KasyButtonShell extends StatelessWidget {
496
496
 
497
497
  Widget _wrapFocus(Widget child, BorderRadius borderRadius) {
498
498
  if (!enabled || onPressed == null) return child;
499
- return _KeyboardFocus(
500
- onActivate: onPressed!,
499
+ return KasyFocusRing(
500
+ onActivate: onPressed,
501
501
  borderRadius: borderRadius,
502
502
  child: child,
503
503
  );
@@ -625,30 +625,28 @@ class _KasyButtonShell extends StatelessWidget {
625
625
 
626
626
  if (pressEffect == KasyButtonPressEffect.both) {
627
627
  final bool isDark = Theme.of(context).brightness == Brightness.dark;
628
- return _wrapFocus(
629
- KasyPressableDepth(
630
- semanticLabel: _accessibilityLabel,
631
- onPressed: onPressed!,
632
- clipBorderRadius: resolvedRadius,
633
- hapticFeedbackEnabled: hapticFeedbackEnabled,
634
- pressOverlayColor: palette.foreground.withValues(
635
- alpha: isDark ? 0.04 : 0.10,
636
- ),
637
- child: painted,
638
- ),
639
- resolvedRadius,
640
- );
641
- }
642
-
643
- return _wrapFocus(
644
- KasyPressableDepth(
628
+ return KasyPressableDepth(
645
629
  semanticLabel: _accessibilityLabel,
646
630
  onPressed: onPressed!,
647
631
  clipBorderRadius: resolvedRadius,
648
632
  hapticFeedbackEnabled: hapticFeedbackEnabled,
649
- child: painted,
650
- ),
651
- resolvedRadius,
633
+ pressOverlayColor: palette.foreground.withValues(
634
+ alpha: isDark ? 0.04 : 0.10,
635
+ ),
636
+ // Wrap the focus ring around the painted visual, not the pressable: the
637
+ // pressable enforces a 44px min tap target and stretches to its parent,
638
+ // so ringing it would draw an oversized oval around a small round orb.
639
+ child: _wrapFocus(painted, resolvedRadius),
640
+ );
641
+ }
642
+
643
+ return KasyPressableDepth(
644
+ semanticLabel: _accessibilityLabel,
645
+ onPressed: onPressed!,
646
+ clipBorderRadius: resolvedRadius,
647
+ hapticFeedbackEnabled: hapticFeedbackEnabled,
648
+ // Ring hugs the visual, not the (larger) tap target. See note above.
649
+ child: _wrapFocus(painted, resolvedRadius),
652
650
  );
653
651
  }
654
652
 
@@ -840,10 +838,10 @@ class _KasyButtonMetrics {
840
838
  final EdgeInsets horizontalPadding;
841
839
  final double labelFontSize;
842
840
 
843
- /// Ícone ao lado do rótulo (botões com texto).
841
+ /// Icon next to the label (buttons with text).
844
842
  final double iconSize;
845
843
 
846
- /// Tamanho do glifo dentro do botão apenas-ícone (pode diferir de [iconSize]).
844
+ /// Glyph size inside the icon-only button (may differ from [iconSize]).
847
845
  final double iconOnlyGlyphSize;
848
846
  final double loadingSpinnerExtent;
849
847
 
@@ -858,77 +856,3 @@ class _KasyButtonMetrics {
858
856
  });
859
857
  }
860
858
 
861
- /// Makes a button keyboard-navigable (Tab) and activates it on Enter/Space.
862
- /// Shows a focus ring when focused. Inert on touch-only platforms.
863
- class _KeyboardFocus extends StatefulWidget {
864
- final VoidCallback onActivate;
865
- final Widget child;
866
- final BorderRadius borderRadius;
867
-
868
- const _KeyboardFocus({
869
- required this.onActivate,
870
- required this.child,
871
- required this.borderRadius,
872
- });
873
-
874
- @override
875
- State<_KeyboardFocus> createState() => _KeyboardFocusState();
876
- }
877
-
878
- class _KeyboardFocusState extends State<_KeyboardFocus> {
879
- late final FocusNode _node;
880
- bool _focused = false;
881
-
882
- @override
883
- void initState() {
884
- super.initState();
885
- _node = FocusNode();
886
- _node.addListener(_onFocusChange);
887
- }
888
-
889
- @override
890
- void dispose() {
891
- _node.removeListener(_onFocusChange);
892
- _node.dispose();
893
- super.dispose();
894
- }
895
-
896
- void _onFocusChange() {
897
- if (mounted) setState(() => _focused = _node.hasFocus);
898
- }
899
-
900
- KeyEventResult _onKeyEvent(FocusNode node, KeyEvent event) {
901
- if (event is KeyDownEvent &&
902
- (event.logicalKey == LogicalKeyboardKey.enter ||
903
- event.logicalKey == LogicalKeyboardKey.space ||
904
- event.logicalKey == LogicalKeyboardKey.numpadEnter)) {
905
- widget.onActivate();
906
- return KeyEventResult.handled;
907
- }
908
- return KeyEventResult.ignored;
909
- }
910
-
911
- @override
912
- Widget build(BuildContext context) {
913
- final Color focusColor = Theme.of(context).colorScheme.primary;
914
- return Focus(
915
- focusNode: _node,
916
- onKeyEvent: _onKeyEvent,
917
- child: AnimatedContainer(
918
- duration: const Duration(milliseconds: 120),
919
- decoration: _focused
920
- ? BoxDecoration(
921
- borderRadius: widget.borderRadius,
922
- boxShadow: [
923
- BoxShadow(
924
- color: focusColor.withValues(alpha: 0.5),
925
- spreadRadius: 2,
926
- ),
927
- ],
928
- )
929
- : const BoxDecoration(),
930
- child: widget.child,
931
- ),
932
- );
933
- }
934
- }
@@ -494,7 +494,10 @@ class _DialogIconPalette {
494
494
  /// Two-button confirm/cancel dialog built on [KasyDialog].
495
495
  ///
496
496
  /// Feature code supplies copy and callbacks; layout stays in the design system.
497
- /// Destructive flows use [showKasyBlurDialog] with a danger icon by default.
497
+ /// Every confirm dialog is presented over the same blurred, dimmed backdrop
498
+ /// ([showKasyBlurDialog]) so the experience is identical project-wide — the
499
+ /// [destructive] flag only switches the accent to danger (red button + trash
500
+ /// icon), not whether there's a blur.
498
501
  Future<void> showKasyConfirmDialog(
499
502
  BuildContext context, {
500
503
  required String title,
@@ -506,15 +509,12 @@ Future<void> showKasyConfirmDialog(
506
509
  bool destructive = false,
507
510
  bool barrierDismissible = false,
508
511
  IconData? leadingIcon,
509
- KasyDialogIconTone iconTone = KasyDialogIconTone.warning,
512
+ // Defaults to [info] (primary tone) so the icon bubble matches the primary
513
+ // confirm button — same harmony destructive flows get (danger icon + danger
514
+ // button). Override per call when a different accent is needed.
515
+ KasyDialogIconTone iconTone = KasyDialogIconTone.info,
510
516
  }) {
511
- final Future<void> Function({
512
- required BuildContext context,
513
- required Widget Function(BuildContext dialogContext) builder,
514
- bool barrierDismissible,
515
- }) presentDialog = destructive ? showKasyBlurDialog<void> : showKasyDialog<void>;
516
-
517
- return presentDialog(
517
+ return showKasyBlurDialog<void>(
518
518
  context: context,
519
519
  barrierDismissible: barrierDismissible,
520
520
  builder: (dialogCtx) => KasyDialog(
@@ -665,7 +665,7 @@ class _BlurDialogScaffoldState extends State<_BlurDialogScaffold> {
665
665
  @override
666
666
  void didChangeDependencies() {
667
667
  super.didChangeDependencies();
668
- // Rastreia teclado subindo congela quando fecha.
668
+ // Tracks the keyboard rising; freezes when it closes.
669
669
  if (!_isClosing) {
670
670
  _bottomInset = MediaQuery.viewInsetsOf(context).bottom;
671
671
  }
@@ -731,7 +731,7 @@ class _BlurDialogScaffoldState extends State<_BlurDialogScaffold> {
731
731
  curve: Curves.easeOutQuart,
732
732
  reverseCurve: Curves.easeIn,
733
733
  );
734
- // Backdrop desaparece rapidamente na saída
734
+ // Backdrop disappears quickly on exit
735
735
  final backdropCurved = CurvedAnimation(
736
736
  parent: widget.animation,
737
737
  curve: Curves.linear,
@@ -0,0 +1,84 @@
1
+ import 'dart:ui';
2
+
3
+ import 'package:flutter/material.dart';
4
+ import 'package:kasy_kit/core/theme/theme.dart';
5
+
6
+ /// Full-screen image lightbox: a single image floating over a dimmed, blurred
7
+ /// backdrop — no card, no chrome. Tapping anywhere outside the image (or
8
+ /// pressing back) dismisses it. Pinch / double-tap to zoom while open.
9
+ ///
10
+ /// Pass a [heroTag] (e.g. the photo id) matching a [Hero] around the source
11
+ /// thumbnail to get a smooth shared-element zoom into and out of the viewer.
12
+ Future<void> showKasyImageViewer(
13
+ BuildContext context, {
14
+ required String imageUrl,
15
+ Object? heroTag,
16
+ }) {
17
+ return Navigator.of(context, rootNavigator: true).push<void>(
18
+ PageRouteBuilder<void>(
19
+ opaque: false,
20
+ barrierColor: Colors.transparent,
21
+ transitionDuration: const Duration(milliseconds: 280),
22
+ reverseTransitionDuration: const Duration(milliseconds: 220),
23
+ pageBuilder: (_, _, _) =>
24
+ _ImageViewer(imageUrl: imageUrl, heroTag: heroTag),
25
+ transitionsBuilder: (_, animation, _, child) {
26
+ // The image itself rides the Hero flight; only the backdrop fades.
27
+ return FadeTransition(opacity: animation, child: child);
28
+ },
29
+ ),
30
+ );
31
+ }
32
+
33
+ class _ImageViewer extends StatelessWidget {
34
+ const _ImageViewer({required this.imageUrl, this.heroTag});
35
+
36
+ final String imageUrl;
37
+ final Object? heroTag;
38
+
39
+ @override
40
+ Widget build(BuildContext context) {
41
+ final bool dark = context.isDark;
42
+
43
+ Widget image = Image.network(imageUrl, fit: BoxFit.contain);
44
+ if (heroTag != null) {
45
+ image = Hero(tag: heroTag!, child: image);
46
+ }
47
+
48
+ return Scaffold(
49
+ backgroundColor: Colors.transparent,
50
+ body: Stack(
51
+ fit: StackFit.expand,
52
+ children: <Widget>[
53
+ // Dimmed + blurred backdrop. Tapping it closes the viewer.
54
+ GestureDetector(
55
+ behavior: HitTestBehavior.opaque,
56
+ onTap: () => Navigator.of(context).maybePop(),
57
+ child: BackdropFilter(
58
+ filter: ImageFilter.blur(sigmaX: 18, sigmaY: 18),
59
+ child: ColoredBox(
60
+ color: Colors.black.withValues(alpha: dark ? 0.74 : 0.62),
61
+ child: const SizedBox.expand(),
62
+ ),
63
+ ),
64
+ ),
65
+
66
+ // The single image, centered. A transparent tap target around it
67
+ // (via the padding) still falls through to the backdrop's onTap.
68
+ SafeArea(
69
+ child: Padding(
70
+ padding: const EdgeInsets.all(KasySpacing.lg),
71
+ child: Center(
72
+ child: InteractiveViewer(
73
+ minScale: 1.0,
74
+ maxScale: 4.0,
75
+ child: image,
76
+ ),
77
+ ),
78
+ ),
79
+ ),
80
+ ],
81
+ ),
82
+ );
83
+ }
84
+ }