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,35 +0,0 @@
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
- /// Brand row shown at the top of login and signup screens.
6
- class AuthBrand extends StatelessWidget {
7
- const AuthBrand({super.key});
8
-
9
- static const double _iconSize = 28;
10
-
11
- @override
12
- Widget build(BuildContext context) {
13
- final TextStyle? nameStyle = context.textTheme.titleLarge;
14
- return Row(
15
- mainAxisAlignment: MainAxisAlignment.center,
16
- mainAxisSize: MainAxisSize.min,
17
- children: [
18
- Icon(
19
- KasyIcons.packageOutline,
20
- size: _iconSize,
21
- color: context.colors.onSurface,
22
- ),
23
- const SizedBox(width: KasySpacing.sm),
24
- Text(
25
- t.home.dashboard.brand,
26
- style: nameStyle?.copyWith(
27
- fontSize: (nameStyle.fontSize ?? 22) + 2,
28
- color: context.colors.onSurface,
29
- fontWeight: FontWeight.w800,
30
- ),
31
- ),
32
- ],
33
- );
34
- }
35
- }
@@ -1,207 +0,0 @@
1
- import 'package:flutter/material.dart';
2
- import 'package:flutter_riverpod/flutter_riverpod.dart';
3
- import 'package:go_router/go_router.dart';
4
- import 'package:kasy_kit/components/kasy_app_bar.dart';
5
- import 'package:kasy_kit/components/kasy_card.dart';
6
- import 'package:kasy_kit/core/config/features.dart';
7
- import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
8
- import 'package:kasy_kit/core/theme/theme.dart';
9
- import 'package:kasy_kit/core/widgets/kasy_hover.dart';
10
- import 'package:kasy_kit/core/widgets/kasy_scroll_behavior.dart';
11
- import 'package:kasy_kit/features/notifications/api/local_notifier.dart';
12
- import 'package:kasy_kit/features/notifications/providers/models/notification.dart'
13
- as kasy_kit;
14
- import 'package:kasy_kit/features/settings/ui/components/admin/admin_routes.dart';
15
- import 'package:kasy_kit/i18n/translations.g.dart';
16
-
17
- /// Feature list shown from [HomePage] (paywall, notifications, etc.).
18
- class HomeFeaturesPage extends ConsumerWidget {
19
- const HomeFeaturesPage({super.key});
20
-
21
- @override
22
- Widget build(BuildContext context, WidgetRef ref) {
23
- final rows = _visibleFeatureRows(context, ref);
24
- final Color bg = context.colors.background;
25
-
26
- return Scaffold(
27
- backgroundColor: bg,
28
- body: Column(
29
- crossAxisAlignment: CrossAxisAlignment.stretch,
30
- children: [
31
- KasyAppBar(
32
- title: t.home.features_page.title,
33
- onBack: () => Navigator.maybePop(context),
34
- ),
35
- Expanded(
36
- child: ScrollConfiguration(
37
- behavior: const KasyKitScrollBehavior(),
38
- child: SingleChildScrollView(
39
- padding: EdgeInsets.fromLTRB(
40
- KasySpacing.pageHorizontalGutter,
41
- KasySpacing.belowChromeContentGap,
42
- KasySpacing.pageHorizontalGutter,
43
- MediaQuery.paddingOf(context).bottom +
44
- KasySpacing.belowChromeContentGap,
45
- ),
46
- child: KasyCard(
47
- variant: KasyCardVariant.outlined,
48
- color: context.colors.surface,
49
- borderRadius: KasyRadius.lgBorderRadius,
50
- child: Column(
51
- children: [
52
- for (int i = 0; i < rows.length; i++) ...[
53
- KasyHover(
54
- hapticEnabled: false,
55
- onTap: () {
56
- KasyHaptics.selection(context);
57
- rows[i].onTap();
58
- },
59
- child: Padding(
60
- padding: const EdgeInsets.symmetric(
61
- horizontal: KasySpacing.smd,
62
- vertical: 14,
63
- ),
64
- child: Row(
65
- crossAxisAlignment: CrossAxisAlignment.start,
66
- children: [
67
- Padding(
68
- padding: const EdgeInsets.only(top: 2),
69
- child: Icon(
70
- rows[i].icon,
71
- size: 20,
72
- color: context.colors.onSurface
73
- .withValues(alpha: 0.45),
74
- ),
75
- ),
76
- const SizedBox(width: KasySpacing.smd),
77
- Expanded(
78
- child: Column(
79
- crossAxisAlignment:
80
- CrossAxisAlignment.start,
81
- children: [
82
- Text(
83
- rows[i].title,
84
- style: context.textTheme.bodyLarge
85
- ?.copyWith(
86
- fontWeight: FontWeight.w600,
87
- color: context.colors.onSurface,
88
- ),
89
- ),
90
- const SizedBox(height: 3),
91
- Text(
92
- rows[i].subtitle,
93
- style: context.textTheme.bodySmall
94
- ?.copyWith(
95
- color: context.colors.muted,
96
- height: 1.35,
97
- ),
98
- ),
99
- ],
100
- ),
101
- ),
102
- Padding(
103
- padding: const EdgeInsets.only(
104
- left: KasySpacing.xs,
105
- top: 3,
106
- ),
107
- child: Icon(
108
- KasyIcons.chevronRight,
109
- color: context.colors.muted,
110
- size: 18,
111
- ),
112
- ),
113
- ],
114
- ),
115
- ),
116
- ),
117
- if (i < rows.length - 1)
118
- Divider(
119
- height: 1,
120
- color: context.colors.onBackground
121
- .withValues(alpha: 0.06),
122
- ),
123
- ],
124
- ],
125
- ),
126
- ),
127
- ),
128
- ),
129
- ),
130
- ],
131
- ),
132
- );
133
- }
134
- }
135
-
136
- class _DemoFeatureRow {
137
- final IconData icon;
138
- final String title;
139
- final String subtitle;
140
- final VoidCallback onTap;
141
-
142
- const _DemoFeatureRow({
143
- required this.icon,
144
- required this.title,
145
- required this.subtitle,
146
- required this.onTap,
147
- });
148
- }
149
-
150
- List<_DemoFeatureRow> _visibleFeatureRows(BuildContext context, WidgetRef ref) {
151
- final page = t.home.features_page;
152
- return [
153
- if (withLlmChat)
154
- _DemoFeatureRow(
155
- icon: KasyIcons.assistant,
156
- title: page.assistant_title,
157
- subtitle: page.assistant_description,
158
- onTap: () => context.push('/assistant'),
159
- ),
160
- if (withFeedback)
161
- _DemoFeatureRow(
162
- icon: KasyIcons.message,
163
- title: page.feedback_title,
164
- subtitle: page.feedback_description,
165
- onTap: () => context.push('/feedback'),
166
- ),
167
- _DemoFeatureRow(
168
- icon: KasyIcons.notification,
169
- title: page.notification_title,
170
- subtitle: page.notification_description,
171
- onTap: () {
172
- final settings = ref.read(notificationsSettingsProvider);
173
- final localNotifier = ref.read(localNotifierProvider);
174
- kasy_kit.Notification.withData(
175
- id: 'fake-id',
176
- title: page.notification_demo_title,
177
- body: page.notification_demo_body,
178
- createdAt: DateTime.now(),
179
- notifier: localNotifier,
180
- notifierSettings: settings,
181
- ).show();
182
- },
183
- ),
184
- _DemoFeatureRow(
185
- icon: KasyIcons.notificationActive,
186
- title: page.send_push_title,
187
- subtitle: page.send_push_description,
188
- onTap: () => context.push(adminRouteSendPush),
189
- ),
190
- if (withRevenuecat)
191
- _DemoFeatureRow(
192
- icon: KasyIcons.payment,
193
- title: page.paywall_title,
194
- subtitle: page.paywall_description,
195
- onTap: () => context.push('/premium'),
196
- ),
197
- ];
198
- }
199
-
200
- /// Number of demo entries currently visible (matches list on this page).
201
- int homeFeaturesEntryCount() {
202
- var n = 2; // notification local + send push (always present)
203
- if (withRevenuecat) n++;
204
- if (withFeedback) n++;
205
- if (withLlmChat) n++;
206
- return n;
207
- }
@@ -1,50 +0,0 @@
1
- import 'package:cloud_firestore/cloud_firestore.dart';
2
- import 'package:flutter_riverpod/flutter_riverpod.dart';
3
- import 'package:kasy_kit/features/llm_chat/api/llm_chat_message_entity.dart';
4
- import 'package:logger/logger.dart';
5
-
6
- final llmChatApiProvider = Provider<LlmChatApi>(
7
- (ref) => LlmChatApi(client: FirebaseFirestore.instance),
8
- );
9
-
10
- class LlmChatApi {
11
- final FirebaseFirestore _client;
12
- final Logger _logger = Logger();
13
-
14
- LlmChatApi({required FirebaseFirestore client}) : _client = client;
15
-
16
- CollectionReference<Map<String, dynamic>> _messagesRef(String userId) =>
17
- _client.collection('users').doc(userId).collection('llm_messages');
18
-
19
- /// Returns all messages for a user, ordered by creation time (oldest first).
20
- Future<List<LlmChatMessageEntity>> loadMessages(String userId) async {
21
- final snapshot = await _messagesRef(userId)
22
- .orderBy('createdAt', descending: false)
23
- .get();
24
- return snapshot.docs
25
- .map((doc) => LlmChatMessageEntity.fromFirestore(doc.id, doc.data()))
26
- .toList();
27
- }
28
-
29
- /// Persists a single message to Firestore.
30
- Future<void> saveMessage(
31
- String userId,
32
- LlmChatMessageEntity message,
33
- ) async {
34
- try {
35
- await _messagesRef(userId).add(message.toFirestore());
36
- } catch (e) {
37
- _logger.e('Failed to persist LLM message: $e');
38
- }
39
- }
40
-
41
- /// Deletes all stored messages for a user (clear history).
42
- Future<void> clearHistory(String userId) async {
43
- final snapshot = await _messagesRef(userId).get();
44
- final batch = _client.batch();
45
- for (final doc in snapshot.docs) {
46
- batch.delete(doc.reference);
47
- }
48
- await batch.commit();
49
- }
50
- }
@@ -1,316 +0,0 @@
1
- import 'package:firebase_messaging/firebase_messaging.dart';
2
- import 'package:flutter/foundation.dart';
3
- import 'package:flutter/material.dart';
4
- import 'package:flutter/services.dart';
5
- import 'package:flutter_riverpod/flutter_riverpod.dart';
6
- import 'package:go_router/go_router.dart';
7
- import 'package:kasy_kit/core/dev_inspector/dev_inspector.dart';
8
- import 'package:kasy_kit/core/icons/kasy_icons.dart';
9
- import 'package:kasy_kit/core/rating/widgets/review_popup.dart';
10
- import 'package:kasy_kit/core/states/user_state_notifier.dart';
11
- import 'package:kasy_kit/core/toast/toast_service.dart';
12
- import 'package:kasy_kit/core/web_device_preview/web_device_preview.dart';
13
- import 'package:kasy_kit/core/widgets/update_bottom_sheet.dart';
14
- import 'package:kasy_kit/features/notifications/api/local_notifier.dart';
15
- import 'package:kasy_kit/features/settings/settings_page.dart';
16
- import 'package:kasy_kit/features/settings/ui/components/admin/admin_routes.dart';
17
- import 'package:kasy_kit/features/settings/ui/widgets/settings_tile.dart';
18
- import 'package:kasy_kit/i18n/translations.g.dart';
19
- import 'package:kasy_kit/router.dart';
20
- import 'package:shared_preferences/shared_preferences.dart';
21
-
22
- void showAdminBottomSheet(BuildContext context) {
23
- if (!kDebugMode) return;
24
- showModalBottomSheet<void>(
25
- context: context,
26
- useRootNavigator: true,
27
- isScrollControlled: true,
28
- enableDrag: false,
29
- backgroundColor: Colors.transparent,
30
- builder: (_) => const _AdminSheet(),
31
- );
32
- }
33
-
34
- /// Pushes an admin debug route without closing the sheet first.
35
- ///
36
- /// When the route is popped, the sheet stays open (or is re-shown if the
37
- /// platform dismissed it under the full-screen page).
38
- Future<void> pushAdminDebugRouteFromSheet(
39
- BuildContext sheetContext,
40
- String route,
41
- ) async {
42
- await sheetContext.push(route);
43
- if (!sheetContext.mounted) {
44
- final BuildContext? settings = navigatorKey.currentContext;
45
- if (settings != null && settings.mounted) {
46
- showAdminBottomSheet(settings);
47
- }
48
- }
49
- }
50
-
51
- class _AdminSheet extends ConsumerWidget {
52
- const _AdminSheet();
53
-
54
- @override
55
- Widget build(BuildContext context, WidgetRef ref) {
56
- final userState = ref.watch(userStateNotifierProvider);
57
- // Leaves status bar + AppBar visible above the sheet
58
- final double sheetHeight = MediaQuery.of(context).size.height * 0.82;
59
-
60
- return SizedBox(
61
- height: sheetHeight,
62
- child: Container(
63
- decoration: BoxDecoration(
64
- color: Theme.of(context).scaffoldBackgroundColor,
65
- borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
66
- ),
67
- child: Column(
68
- children: [
69
- _SheetHandle(onClose: () => Navigator.pop(context)),
70
- Expanded(
71
- child: ListView(
72
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
73
- children: [
74
- SettingsContainer(
75
- child: Wrap(
76
- children: [
77
- ValueListenableBuilder<bool>(
78
- valueListenable: devInspectorEnabledNotifier,
79
- builder: (context, enabled, _) {
80
- return SettingsSwitchTile(
81
- icon: KasyIcons.widgets,
82
- title: t.settings.admin.inspector_fab_title,
83
- subtitle:
84
- '${t.settings.admin.inspector_fab_subtitle_prefix} '
85
- '${devInspectorShortcutLabel()}',
86
- value: enabled,
87
- onChanged: (v) async {
88
- final p = await SharedPreferences.getInstance();
89
- await p.setBool(devInspectorEnabledPrefKey, v);
90
- devInspectorEnabledNotifier.value = v;
91
- // Turning the inspector ON closes the admin
92
- // sheet automatically — otherwise the sheet
93
- // would absorb taps and the user would be
94
- // stuck. Turning OFF leaves the sheet open.
95
- if (v && context.mounted) {
96
- Navigator.of(context).maybePop();
97
- }
98
- },
99
- );
100
- },
101
- ),
102
- if (kIsWeb) ...[
103
- const SettingsDivider(),
104
- ValueListenableBuilder<bool>(
105
- valueListenable: webDevicePreviewEnabledNotifier,
106
- builder: (context, enabled, _) {
107
- return SettingsSwitchTile(
108
- icon: KasyIcons.phoneAndroid,
109
- title: t.settings.admin.device_preview_title,
110
- subtitle:
111
- '${t.settings.admin.inspector_fab_subtitle_prefix} '
112
- '${webDevicePreviewShortcutLabel()}',
113
- value: enabled,
114
- onChanged: (v) async {
115
- final navigator = Navigator.of(
116
- context,
117
- rootNavigator: true,
118
- );
119
- final p =
120
- await SharedPreferences.getInstance();
121
- await p.setBool(
122
- webDevicePreviewEnabledPrefKey,
123
- v,
124
- );
125
- webDevicePreviewEnabledNotifier.value = v;
126
- if (v) navigator.pop();
127
- },
128
- );
129
- },
130
- ),
131
- ],
132
- const SettingsDivider(),
133
- SettingsTile(
134
- icon: KasyIcons.note,
135
- title: t.settings.admin.update_bottom_sheet,
136
- onTap: () {
137
- Navigator.pop(context);
138
- showUpdateBottomSheet(
139
- context: navigatorKey.currentContext!,
140
- version: '0.0.0',
141
- );
142
- },
143
- ),
144
- const SettingsDivider(),
145
- SettingsTile(
146
- icon: KasyIcons.payment,
147
- title: t.settings.admin.paywalls,
148
- onTap: () => pushAdminDebugRouteFromSheet(
149
- context,
150
- adminRoutePaywalls,
151
- ),
152
- ),
153
- const SettingsDivider(),
154
- SettingsTile(
155
- icon: KasyIcons.check,
156
- title: t.settings.admin.test_onboarding,
157
- onTap: () {
158
- Navigator.pop(context);
159
- ref.read(goRouterProvider).go('/onboarding');
160
- },
161
- ),
162
- const SettingsDivider(),
163
- SettingsTile(
164
- icon: KasyIcons.person,
165
- title: t.settings.admin.copy_user_id,
166
- onTap: () {
167
- Clipboard.setData(ClipboardData(
168
- text: userState.user.idOrNull ?? 'no-id (guest)',
169
- ));
170
- ref.read(toastProvider).alert(
171
- title: '',
172
- text: t.settings.admin.user_id_copied,
173
- );
174
- },
175
- ),
176
- const SettingsDivider(),
177
- SettingsTile(
178
- icon: KasyIcons.notification,
179
- title: t.settings.admin.copy_fcm_token,
180
- onTap: () async {
181
- final token =
182
- await FirebaseMessaging.instance.getToken();
183
- if (token == null) {
184
- ref.read(toastProvider).alert(
185
- title: '',
186
- text: t.settings.admin.fcm_token_unavailable,
187
- );
188
- return;
189
- }
190
- await Clipboard.setData(
191
- ClipboardData(text: token),
192
- );
193
- ref.read(toastProvider).alert(
194
- title: '',
195
- text: t.settings.admin.fcm_token_copied,
196
- );
197
- },
198
- ),
199
- const SettingsDivider(),
200
- SettingsTile(
201
- icon: KasyIcons.notificationActive,
202
- title: t.settings.admin.ask_notification,
203
- onTap: () {
204
- Navigator.pop(context);
205
- ref
206
- .read(notificationsSettingsProvider)
207
- .askPermission();
208
- },
209
- ),
210
- const SettingsDivider(),
211
- SettingsTile(
212
- icon: KasyIcons.notificationActive,
213
- title: t.settings.admin.send_push_title,
214
- onTap: () => pushAdminDebugRouteFromSheet(
215
- context,
216
- adminRouteSendPush,
217
- ),
218
- ),
219
- const SettingsDivider(),
220
- SettingsTile(
221
- icon: KasyIcons.star,
222
- title: t.settings.admin.ask_review,
223
- onTap: () =>
224
- showReviewDialog(context, ref, force: true),
225
- ),
226
- const SettingsDivider(),
227
- SettingsTile(
228
- icon: KasyIcons.message,
229
- title: t.settings.admin.home_widgets_panel,
230
- onTap: () => pushAdminDebugRouteFromSheet(
231
- context,
232
- adminRouteHomeWidgets,
233
- ),
234
- ),
235
- ],
236
- ),
237
- ),
238
- const SizedBox(height: 24),
239
- ],
240
- ),
241
- ),
242
- ],
243
- ),
244
- ),
245
- );
246
- }
247
- }
248
-
249
- class _SheetHandle extends StatelessWidget {
250
- final VoidCallback onClose;
251
-
252
- const _SheetHandle({required this.onClose});
253
-
254
- @override
255
- Widget build(BuildContext context) {
256
- return GestureDetector(
257
- // Swipe down on the handle dismisses the sheet
258
- onVerticalDragEnd: (details) {
259
- if ((details.primaryVelocity ?? 0) > 200) onClose();
260
- },
261
- behavior: HitTestBehavior.opaque,
262
- child: Column(
263
- children: [
264
- const SizedBox(height: 12),
265
- Container(
266
- width: 36,
267
- height: 4,
268
- decoration: BoxDecoration(
269
- color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.15),
270
- borderRadius: BorderRadius.circular(2),
271
- ),
272
- ),
273
- Padding(
274
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
275
- child: Row(
276
- children: [
277
- Text(
278
- 'Admin',
279
- style: Theme.of(context).textTheme.labelLarge?.copyWith(
280
- color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.4),
281
- letterSpacing: 1.1,
282
- ),
283
- ),
284
- const Spacer(),
285
- GestureDetector(
286
- onTap: onClose,
287
- behavior: HitTestBehavior.opaque,
288
- child: Padding(
289
- padding: const EdgeInsets.all(8),
290
- child: Container(
291
- width: 28,
292
- height: 28,
293
- decoration: BoxDecoration(
294
- color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.07),
295
- shape: BoxShape.circle,
296
- ),
297
- child: Icon(
298
- Icons.close,
299
- size: 15,
300
- color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.5),
301
- ),
302
- ),
303
- ),
304
- ),
305
- ],
306
- ),
307
- ),
308
- Divider(
309
- height: 1,
310
- color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.07),
311
- ),
312
- ],
313
- ),
314
- );
315
- }
316
- }
@@ -1,85 +0,0 @@
1
- // ignore_for_file: use_build_context_synchronously
2
-
3
- import 'package:flutter/foundation.dart';
4
- import 'package:flutter_riverpod/flutter_riverpod.dart';
5
- import 'package:kasy_kit/core/config/features.dart';
6
- import 'package:kasy_kit/core/data/models/user.dart';
7
- import 'package:kasy_kit/core/shared_preferences/shared_preferences.dart';
8
- import 'package:kasy_kit/core/states/components/maybeshow_component.dart';
9
- import 'package:kasy_kit/core/states/models/event_model.dart';
10
- import 'package:kasy_kit/core/states/user_state_notifier.dart';
11
- import 'package:kasy_kit/router.dart';
12
-
13
- const _lastAskKey = 'subscription_last_asking_date';
14
-
15
- const _kDaysToAsk = 2;
16
-
17
- class MaybeShowPremiumPage implements MaybeShowWithRef {
18
- @override
19
- Future<bool> handle(WidgetRef ref, AppEvent event) async {
20
- if (event is! OnAppStartEvent) {
21
- return false;
22
- }
23
- if (kIsWeb && !revenuecatWeb) return false;
24
- debugPrint("🧐 MaybeShowPremiumPage");
25
- final userState = ref.watch(userStateNotifierProvider);
26
- if (userState.subscription?.isActive == true) {
27
- return false;
28
- }
29
- final userCreationDate = switch(userState.user) {
30
- AuthenticatedUserData(:final creationDate) => creationDate,
31
- AnonymousUserData(:final creationDate) => creationDate,
32
- _ => null,
33
- };
34
-
35
- if (userCreationDate == null) {
36
- return false;
37
- }
38
-
39
- final now = DateTime.now();
40
- final prefs = ref.watch(sharedPreferencesProvider).prefs;
41
-
42
- // await prefs.remove(_lastAskKey);
43
- // await prefs.remove(_lastShowPromoKey);
44
-
45
- final lastAskingDate = prefs.getInt(_lastAskKey);
46
-
47
-
48
- /// 🧐 🧐 🧐 if we have a promo - we only show the promo once or customize it
49
- /// ----
50
- // final lastShowPromoInMS = prefs.getInt(_lastShowPromoKey);
51
- // final lastShowPromoDate = lastShowPromoInMS == null ? null : DateTime.fromMillisecondsSinceEpoch(lastShowPromoInMS);
52
- // if (now.isAfter(userCreationDate.add(const Duration(days: 3))) && lastShowPromoDate == null && ref.context.mounted) {
53
- // await prefs.setInt(_lastShowPromoKey, now.millisecondsSinceEpoch);
54
- // await prefs.setInt(_lastAskKey, DateTime.now().millisecondsSinceEpoch);
55
- // PromoBottomSheet.show(ref.context);
56
- // return true;
57
- // }
58
-
59
- if (now.isBefore(userCreationDate.add(const Duration(days: 1)))) {
60
- return false;
61
- }
62
-
63
- if (lastAskingDate == null) {
64
- await prefs.setInt(_lastAskKey, DateTime.now().millisecondsSinceEpoch);
65
- showPremiumPage(ref);
66
- return true;
67
- }
68
-
69
- final lastDate = DateTime.fromMillisecondsSinceEpoch(lastAskingDate);
70
-
71
- final difference = now.difference(lastDate);
72
-
73
- if (difference.inDays >= _kDaysToAsk) {
74
- await prefs.setInt(_lastAskKey, now.millisecondsSinceEpoch);
75
- showPremiumPage(ref);
76
- return true;
77
- }
78
-
79
- return false;
80
- }
81
-
82
- void showPremiumPage(WidgetRef ref) {
83
- ref.read(goRouterProvider).push("/premium");
84
- }
85
- }