kasy-cli 1.21.9 → 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.
- package/lib/commands/add.js +93 -80
- package/lib/commands/configure.js +100 -32
- package/lib/commands/doctor.js +28 -2
- package/lib/commands/new.js +80 -37
- package/lib/commands/notifications.js +1 -1
- package/lib/commands/remove.js +43 -15
- package/lib/commands/run.js +2 -2
- package/lib/commands/update.js +2 -2
- package/lib/scaffold/CHANGELOG.json +14 -0
- package/lib/scaffold/backends/api/generator.js +14 -14
- package/lib/scaffold/backends/api/patch/README.md +83 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +5 -0
- package/lib/scaffold/backends/api/patch/lib/{environnements.dart → environments.dart} +3 -11
- package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_api.dart +108 -0
- package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +51 -0
- 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
- package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +71 -38
- package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +2 -2
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +54 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +16 -16
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +100 -0
- package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
- package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +60 -0
- package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/lib/scaffold/backends/api/pubspec.yaml.tpl +4 -5
- package/lib/scaffold/backends/firebase/deploy.js +87 -13
- package/lib/scaffold/backends/firebase/generator.js +5 -5
- package/lib/scaffold/backends/firebase/tokens.js +4 -4
- package/lib/scaffold/backends/supabase/deploy.js +63 -11
- package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
- package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
- package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
- package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
- package/lib/scaffold/backends/supabase/generator.js +17 -17
- package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
- package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
- package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
- 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
- package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
- package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
- package/lib/scaffold/backends/supabase/tokens.js +3 -3
- package/lib/scaffold/catalog.js +9 -11
- package/lib/scaffold/generate.js +45 -31
- package/lib/scaffold/shared/generator-utils.js +188 -81
- package/lib/scaffold/shared/sort-imports.js +191 -0
- package/lib/scaffold/shared/template-strings.js +3 -3
- package/lib/utils/checks.js +2 -2
- package/lib/utils/i18n/messages-en.js +50 -35
- package/lib/utils/i18n/messages-es.js +50 -35
- package/lib/utils/i18n/messages-pt.js +52 -37
- package/lib/utils/updates.js +15 -15
- package/package.json +1 -1
- package/templates/firebase/.env.example +2 -2
- package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
- package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
- package/templates/firebase/assets/images/logo_wordmark_dark.png +0 -0
- package/templates/firebase/assets/images/logo_wordmark_light.png +0 -0
- package/templates/firebase/docs/revenuecat-setup.es.md +1 -1
- package/templates/firebase/docs/revenuecat-setup.pt.md +1 -1
- package/templates/firebase/firestore.rules +24 -5
- package/templates/firebase/functions/package-lock.json +22 -1
- package/templates/firebase/functions/package.json +2 -1
- package/templates/firebase/functions/src/admin/functions.ts +113 -0
- package/templates/firebase/functions/src/{llm_chat → ai_chat}/index.ts +16 -16
- package/templates/firebase/functions/src/index.ts +8 -2
- package/templates/firebase/functions/src/notifications/device_triggers.ts +2 -2
- package/templates/firebase/functions/src/notifications/triggers.ts +3 -3
- package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +2 -0
- package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +222 -0
- package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +2 -2
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
- package/templates/firebase/lib/components/components.dart +4 -1
- package/templates/firebase/lib/components/kasy_app_bar.dart +22 -7
- package/templates/firebase/lib/components/kasy_avatar.dart +7 -6
- package/templates/firebase/lib/components/kasy_button.dart +23 -99
- package/templates/firebase/lib/components/kasy_dialog.dart +11 -11
- package/templates/firebase/lib/components/kasy_image_viewer.dart +84 -0
- package/templates/firebase/lib/components/{kasy_sidebar_pro.dart → kasy_sidebar.dart} +692 -425
- package/templates/firebase/lib/components/kasy_status_tag.dart +91 -0
- package/templates/firebase/lib/components/kasy_text_area.dart +1 -3
- package/templates/firebase/lib/components/kasy_text_field.dart +5 -6
- package/templates/firebase/lib/components/kasy_text_field_otp.dart +1 -3
- package/templates/firebase/lib/components/kasy_toast.dart +2 -2
- package/templates/firebase/lib/components/kasy_web_header.dart +209 -0
- package/templates/firebase/lib/core/ads/ads_provider.dart +1 -1
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +57 -4
- package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +19 -91
- package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +196 -96
- package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +41 -0
- package/templates/firebase/lib/core/config/app_env.dart +5 -11
- package/templates/firebase/lib/core/config/features.dart +5 -4
- package/templates/firebase/lib/core/data/api/analytics_api.dart +1 -1
- package/templates/firebase/lib/core/data/api/http_client.dart +1 -1
- package/templates/firebase/lib/core/data/entities/user_entity.dart +3 -0
- package/templates/firebase/lib/core/data/models/entitlement.dart +35 -0
- package/templates/firebase/lib/core/data/models/subscription.dart +13 -186
- package/templates/firebase/lib/core/data/models/user.dart +11 -0
- package/templates/firebase/lib/core/data/repositories/user_repository.dart +1 -1
- package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +1 -1
- package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +1 -1
- package/templates/firebase/lib/core/icons/kasy_icons.dart +31 -1
- package/templates/firebase/lib/core/rating/api/rating_api.dart +2 -2
- package/templates/firebase/lib/core/states/logout_action.dart +25 -0
- package/templates/firebase/lib/core/states/user_state_notifier.dart +3 -3
- package/templates/firebase/lib/core/theme/colors.dart +488 -188
- package/templates/firebase/lib/core/theme/radius.dart +22 -11
- package/templates/firebase/lib/core/theme/shadows.dart +66 -0
- package/templates/firebase/lib/core/theme/texts.dart +75 -41
- package/templates/firebase/lib/core/theme/universal_theme.dart +9 -4
- package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +5 -4
- package/templates/firebase/lib/core/web_viewport_scale.dart +52 -0
- package/templates/firebase/lib/core/widgets/kasy_brand_badge.dart +118 -0
- package/templates/firebase/lib/core/widgets/kasy_brand_logo.dart +40 -0
- package/templates/firebase/lib/core/widgets/kasy_focus_ring.dart +125 -0
- package/templates/firebase/lib/core/widgets/kasy_hover.dart +33 -13
- package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +18 -13
- package/templates/firebase/lib/{environnements.dart → environments.dart} +3 -14
- package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +159 -0
- package/templates/firebase/lib/features/ai_chat/api/ai_chat_api.dart +107 -0
- package/templates/firebase/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +64 -0
- package/templates/firebase/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
- package/templates/firebase/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +73 -38
- package/templates/firebase/lib/features/ai_chat/providers/ai_conversations_notifier.dart +103 -0
- package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_avatars.dart → ai_chat/ui/widgets/ai_chat_avatars.dart} +13 -13
- package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_composer.dart → ai_chat/ui/widgets/ai_chat_composer.dart} +10 -10
- package/templates/firebase/lib/features/{llm_chat/llm_chat_page.dart → ai_chat/ui/widgets/ai_chat_conversation_view.dart} +80 -67
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +285 -0
- package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +163 -0
- package/templates/firebase/lib/features/authentication/api/authentication_api.dart +52 -13
- package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher.dart +12 -0
- package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher_web.dart +35 -0
- package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +108 -68
- package/templates/firebase/lib/features/authentication/ui/signin_page.dart +38 -51
- package/templates/firebase/lib/features/authentication/ui/signup_page.dart +38 -51
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +118 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +61 -44
- package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +32 -0
- package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +5 -5
- package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +2 -2
- package/templates/firebase/lib/features/home/design_system_page.dart +808 -170
- package/templates/firebase/lib/features/home/home_components_page.dart +6 -3
- package/templates/firebase/lib/features/home/home_components_preview_page.dart +6 -6
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +325 -186
- package/templates/firebase/lib/features/home/home_feed.dart +289 -0
- package/templates/firebase/lib/features/home/home_image_grid.dart +355 -0
- package/templates/firebase/lib/features/home/home_page.dart +11 -250
- package/templates/firebase/lib/features/{local_reminder → local_reminders}/providers/reminder_notifier.dart +1 -1
- package/templates/firebase/lib/features/{local_reminder → local_reminders}/ui/reminder_page.dart +2 -2
- package/templates/firebase/lib/features/notifications/shared/att_permission.dart +1 -1
- package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +25 -61
- package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +117 -0
- package/templates/firebase/lib/features/onboarding/models/user_info.dart +16 -16
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +7 -9
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +71 -48
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +3 -2
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +5 -5
- package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +4 -4
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +4 -2
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +39 -121
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +105 -70
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +639 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +62 -50
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_step_header.dart +75 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +16 -5
- package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +26 -22
- package/templates/firebase/lib/features/settings/settings_page.dart +601 -90
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +1193 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +1 -1
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +2 -3
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +86 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +1215 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +236 -0
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +3 -3
- package/templates/firebase/lib/features/settings/ui/widgets/kasy_user_avatar.dart +77 -0
- package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +1 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +17 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/inapp_subscription_api.dart +67 -46
- package/templates/firebase/lib/features/subscriptions/api/revenuecat_product.dart +189 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +55 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +82 -0
- package/templates/firebase/lib/features/subscriptions/api/stripe_product.dart +178 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
- package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api.dart +53 -0
- package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api_provider.dart +21 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/providers/premium_page_provider.dart +9 -6
- package/templates/firebase/lib/features/{subscription → subscriptions}/repositories/subscription_repository.dart +26 -30
- package/{lib/scaffold/backends/supabase/patch/lib/features/subscription → templates/firebase/lib/features/subscriptions}/shared/maybeshow_premium.dart +0 -2
- package/templates/firebase/lib/features/subscriptions/shared/subscription_management.dart +45 -0
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/active_premium_content.dart +28 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_minimal.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_row.dart +8 -8
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_with_switch.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_content.dart +7 -7
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_page_factory.dart +5 -5
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/premium_page.dart +5 -5
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/comparison_table.dart +1 -1
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/paywall_empty_state.dart +4 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_bottom_menu.dart +3 -4
- package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_col.dart +1 -1
- package/templates/firebase/lib/i18n/en.i18n.json +171 -46
- package/templates/firebase/lib/i18n/es.i18n.json +175 -50
- package/templates/firebase/lib/i18n/pt.i18n.json +166 -41
- package/templates/firebase/lib/main.dart +6 -3
- package/templates/firebase/lib/router.dart +15 -23
- package/templates/firebase/pubspec.yaml +4 -5
- package/templates/firebase/test/core/data/repositories/user_repository_test.dart +3 -3
- package/templates/firebase/test/core/states/user_state_notifier_test.dart +4 -4
- package/templates/firebase/test/core/widgets/focus_ring_shape_test.dart +55 -0
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_inapp_subscription_api.dart +11 -4
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_revenuecat_product.dart +1 -0
- package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_subscription_api.dart +2 -2
- package/templates/firebase/test/features/{subscription → subscriptions}/subscription_page_test.dart +4 -4
- package/templates/firebase/test/test_utils.dart +6 -6
- package/templates/firebase/web/index.html +5 -2
- package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -58
- package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -86
- package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +0 -22
- package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -47
- package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/img2.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/img3.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/notifications.png +0 -0
- package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
- package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +0 -2021
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +0 -35
- package/templates/firebase/lib/features/home/home_features_page.dart +0 -207
- package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +0 -50
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +0 -316
- package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +0 -85
- /package/templates/firebase/lib/features/{local_reminder → local_reminders}/repositories/reminder_preferences.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/providers/models/premium_state.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/feature_line.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background_gradient.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_banner.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_card.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_close_button.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_feature.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_row.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/trial_switcher.dart +0 -0
- /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/unsubscribe_feedback_popup.dart +0 -0
|
@@ -1,36 +1,46 @@
|
|
|
1
1
|
import 'package:bart/bart.dart' as bart;
|
|
2
2
|
import 'package:bart/bart/bart_model.dart';
|
|
3
3
|
import 'package:bart/bart/router_delegate.dart';
|
|
4
|
-
import 'package:bart/bart/widgets/bottom_bar/styles/bottom_bar_cupertino.dart';
|
|
5
4
|
import 'package:bart/bart/widgets/bottom_bar/styles/bottom_bar_custom.dart';
|
|
6
|
-
import 'package:bart/bart/widgets/bottom_bar/styles/bottom_bar_material.dart';
|
|
7
|
-
import 'package:flutter/foundation.dart';
|
|
8
5
|
import 'package:flutter/material.dart';
|
|
9
6
|
import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
|
|
10
7
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
11
8
|
|
|
12
|
-
///
|
|
13
|
-
const double
|
|
9
|
+
/// Side breathing room so the floating bar never touches the screen edges.
|
|
10
|
+
const double _kFloatingSideMargin = 16;
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
const double
|
|
12
|
+
/// Gap above the bar (separates it from the page content).
|
|
13
|
+
const double _kFloatingTopGap = 6;
|
|
17
14
|
|
|
18
|
-
///
|
|
19
|
-
///
|
|
20
|
-
/// inset
|
|
15
|
+
/// Minimum gap under the bar when the device has no bottom safe-area inset
|
|
16
|
+
/// (Android with gesture nav / no system bar). On notched devices the real
|
|
17
|
+
/// inset is used instead so the home indicator stays clear.
|
|
18
|
+
const double _kFloatingMinBottomGap = 16;
|
|
19
|
+
|
|
20
|
+
/// Corner radius of the floating pill (HeroUI `rounded-3xl`).
|
|
21
|
+
const double _kFloatingRadius = KasyRadius.rounded3xl;
|
|
22
|
+
|
|
23
|
+
/// Bar (pill) inner height — the row of tab items.
|
|
24
|
+
const double _kBarHeight = 72;
|
|
25
|
+
|
|
26
|
+
/// Tab icon size.
|
|
27
|
+
const double _kNavIconSize = 24;
|
|
28
|
+
|
|
29
|
+
/// Gap between a tab's icon and its label.
|
|
30
|
+
const double _kNavLabelGap = 3;
|
|
31
|
+
|
|
32
|
+
/// Selection color-fade timing (muted ↔ primary highlight).
|
|
33
|
+
const Duration _kSelectDuration = Duration(milliseconds: 200);
|
|
34
|
+
const Curve _kSelectCurve = Curves.easeOut;
|
|
35
|
+
|
|
36
|
+
/// [BartScaffold] requires a [bart.BartBottomBar]. This factory draws a single,
|
|
37
|
+
/// custom navigation bar (same look on iOS and Android) wrapped in a floating,
|
|
38
|
+
/// fully rounded surface that hovers above the screen edges with a safe-area
|
|
39
|
+
/// aware gap underneath (iPhone home indicator / Android nav). Each tab is an
|
|
40
|
+
/// icon over its label; the selected one is highlighted in the primary color.
|
|
21
41
|
final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
|
|
22
42
|
const KasyPaddedSurfaceBottomBarFactory();
|
|
23
43
|
|
|
24
|
-
bool _useCupertino(BuildContext context) {
|
|
25
|
-
if (kIsWeb) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
return switch (defaultTargetPlatform) {
|
|
29
|
-
TargetPlatform.iOS => true,
|
|
30
|
-
_ => false,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
44
|
@override
|
|
35
45
|
Widget create({
|
|
36
46
|
required BuildContext context,
|
|
@@ -45,11 +55,7 @@ final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
|
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
Widget _build(BuildContext context) {
|
|
48
|
-
final KasyColors colors = context.colors;
|
|
49
58
|
final MenuRouter menuRouter = MenuRouter.of(context);
|
|
50
|
-
final BorderSide topEdge = BorderSide(
|
|
51
|
-
color: colors.outline.withValues(alpha: 0.35),
|
|
52
|
-
);
|
|
53
59
|
void handleTap(int index) {
|
|
54
60
|
if (menuRouter.indexNotifier.value == index &&
|
|
55
61
|
menuRouter.routingTypeNotifier.value ==
|
|
@@ -64,82 +70,176 @@ final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
|
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
73
|
+
final Widget barCore = SizedBox(
|
|
74
|
+
height: _kBarHeight,
|
|
75
|
+
child: ValueListenableBuilder<int>(
|
|
76
|
+
valueListenable: menuRouter.indexNotifier,
|
|
77
|
+
builder: (context, currentIndex, _) {
|
|
78
|
+
// [currentIndex] / [handleTap] address the full route list, so map each
|
|
79
|
+
// tab back to its full-list index (robust to any non-tab route).
|
|
80
|
+
final List<BartMenuRoute> allRoutes = menuRouter.routesBuilder();
|
|
81
|
+
final List<BartMenuRoute> navRoutes = allRoutes
|
|
82
|
+
.where((r) => r.type == BartMenuRouteType.bottomNavigation)
|
|
83
|
+
.toList();
|
|
84
|
+
return Row(
|
|
85
|
+
children: [
|
|
86
|
+
for (final route in navRoutes)
|
|
87
|
+
Expanded(
|
|
88
|
+
child: _KasyNavItem(
|
|
89
|
+
route: route,
|
|
90
|
+
selected: allRoutes.indexOf(route) == currentIndex,
|
|
91
|
+
onTap: () => handleTap(allRoutes.indexOf(route)),
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
],
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return _floating(context, barCore);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// Wraps [barCore] in a floating, fully rounded surface with side margins and
|
|
104
|
+
/// a safe-area-aware bottom gap, over a fade that lets scrolling content melt
|
|
105
|
+
/// into the page background before it reaches the bar.
|
|
106
|
+
Widget _floating(BuildContext context, Widget barCore) {
|
|
107
|
+
final KasyColors colors = context.colors;
|
|
108
|
+
// Real bottom safe area (home indicator / system nav). [viewPaddingOf] keeps
|
|
109
|
+
// reporting it even though we strip it from the inner bar below.
|
|
110
|
+
final double safeBottom = MediaQuery.viewPaddingOf(context).bottom;
|
|
111
|
+
final double bottomGap =
|
|
112
|
+
safeBottom > 0 ? safeBottom : _kFloatingMinBottomGap;
|
|
113
|
+
const BorderRadius radius = BorderRadius.all(
|
|
114
|
+
Radius.circular(_kFloatingRadius),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
final Widget pill = Container(
|
|
118
|
+
decoration: BoxDecoration(
|
|
119
|
+
color: colors.surface,
|
|
120
|
+
borderRadius: radius,
|
|
121
|
+
// Single, very light shadow — just enough to lift the pill off the canvas.
|
|
122
|
+
boxShadow: [
|
|
123
|
+
KasyShadows.component(
|
|
124
|
+
context,
|
|
125
|
+
blurRadius: 12,
|
|
126
|
+
spreadRadius: -7,
|
|
127
|
+
offset: const Offset(0, 3),
|
|
89
128
|
),
|
|
90
129
|
],
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
130
|
+
),
|
|
131
|
+
// Border drawn on top of the child so the clip never eats the hairline.
|
|
132
|
+
foregroundDecoration: BoxDecoration(
|
|
133
|
+
borderRadius: radius,
|
|
134
|
+
border: Border.all(
|
|
135
|
+
color: colors.outline.withValues(alpha: 0.35),
|
|
136
|
+
),
|
|
137
|
+
),
|
|
138
|
+
child: ClipRRect(
|
|
139
|
+
borderRadius: radius,
|
|
140
|
+
child: barCore,
|
|
141
|
+
),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Low bottom-up fade in the page background color: opaque at the very bottom
|
|
145
|
+
// (hides content scrolling under the bar), fully transparent again around the
|
|
146
|
+
// pill's mid-height so it stays a discreet wash low on the bar rather than a
|
|
147
|
+
// tall veil. Follows light/dark via the background token; same RGB at both
|
|
148
|
+
// ends so there is no grey halo.
|
|
149
|
+
final Widget fade = IgnorePointer(
|
|
150
|
+
child: DecoratedBox(
|
|
151
|
+
decoration: BoxDecoration(
|
|
152
|
+
gradient: LinearGradient(
|
|
153
|
+
begin: Alignment.bottomCenter,
|
|
154
|
+
end: Alignment.topCenter,
|
|
155
|
+
colors: [
|
|
156
|
+
colors.background,
|
|
157
|
+
colors.background,
|
|
158
|
+
colors.background.withValues(alpha: 0),
|
|
159
|
+
],
|
|
160
|
+
stops: const [0.0, 0.33, 0.66],
|
|
103
161
|
),
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return IconThemeData(
|
|
118
|
-
color: selected ? colors.primary : colors.muted,
|
|
119
|
-
);
|
|
120
|
-
}),
|
|
121
|
-
labelTextStyle: WidgetStateProperty.resolveWith((states) {
|
|
122
|
-
final selected = states.contains(WidgetState.selected);
|
|
123
|
-
final base = Theme.of(context).textTheme.labelMedium ??
|
|
124
|
-
const TextStyle();
|
|
125
|
-
return base.copyWith(
|
|
126
|
-
color: selected ? colors.primary : colors.muted,
|
|
127
|
-
);
|
|
128
|
-
}),
|
|
129
|
-
),
|
|
130
|
-
),
|
|
131
|
-
child: BartMaterial3BottomBar(
|
|
132
|
-
routes: menuRouter.routesBuilder(),
|
|
133
|
-
theme: Material3BottomBarTheme(
|
|
134
|
-
bgColor: Colors.transparent,
|
|
135
|
-
elevation: 0,
|
|
136
|
-
height: _kBottomBarHeightMaterial3 - kasyBottomBarTopPadding,
|
|
137
|
-
),
|
|
138
|
-
currentIndexNotifier: menuRouter.indexNotifier,
|
|
139
|
-
onTap: handleTap,
|
|
140
|
-
),
|
|
162
|
+
),
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
return Stack(
|
|
167
|
+
children: [
|
|
168
|
+
Positioned.fill(child: fade),
|
|
169
|
+
Padding(
|
|
170
|
+
padding: EdgeInsets.only(
|
|
171
|
+
left: _kFloatingSideMargin,
|
|
172
|
+
right: _kFloatingSideMargin,
|
|
173
|
+
top: _kFloatingTopGap,
|
|
174
|
+
bottom: bottomGap,
|
|
141
175
|
),
|
|
142
|
-
|
|
176
|
+
child: pill,
|
|
177
|
+
),
|
|
178
|
+
],
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/// A single bottom-bar tab: icon over its label. Selected is highlighted in the
|
|
184
|
+
/// primary color (icon + label); unselected is muted. Selection fades the color.
|
|
185
|
+
class _KasyNavItem extends StatelessWidget {
|
|
186
|
+
final BartMenuRoute route;
|
|
187
|
+
final bool selected;
|
|
188
|
+
final VoidCallback onTap;
|
|
189
|
+
|
|
190
|
+
const _KasyNavItem({
|
|
191
|
+
required this.route,
|
|
192
|
+
required this.selected,
|
|
193
|
+
required this.onTap,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
Widget _icon(BuildContext context, Color color) {
|
|
197
|
+
final Widget raw = route.iconBuilder != null
|
|
198
|
+
? route.iconBuilder!(context, selected)
|
|
199
|
+
: Icon(route.icon);
|
|
200
|
+
return IconTheme.merge(
|
|
201
|
+
data: IconThemeData(color: color, size: _kNavIconSize),
|
|
202
|
+
child: raw,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@override
|
|
207
|
+
Widget build(BuildContext context) {
|
|
208
|
+
final KasyColors colors = context.colors;
|
|
209
|
+
final TextStyle labelBase =
|
|
210
|
+
context.textTheme.labelMedium ?? const TextStyle();
|
|
211
|
+
final String label = route.label ?? '';
|
|
212
|
+
|
|
213
|
+
return Semantics(
|
|
214
|
+
button: true,
|
|
215
|
+
selected: selected,
|
|
216
|
+
label: label,
|
|
217
|
+
child: GestureDetector(
|
|
218
|
+
behavior: HitTestBehavior.opaque,
|
|
219
|
+
onTap: onTap,
|
|
220
|
+
child: Center(
|
|
221
|
+
child: TweenAnimationBuilder<double>(
|
|
222
|
+
tween: Tween<double>(end: selected ? 1.0 : 0.0),
|
|
223
|
+
duration: _kSelectDuration,
|
|
224
|
+
curve: _kSelectCurve,
|
|
225
|
+
builder: (context, t, _) {
|
|
226
|
+
final Color color = Color.lerp(colors.muted, colors.primary, t)!;
|
|
227
|
+
return Column(
|
|
228
|
+
mainAxisSize: MainAxisSize.min,
|
|
229
|
+
children: [
|
|
230
|
+
_icon(context, color),
|
|
231
|
+
const SizedBox(height: _kNavLabelGap),
|
|
232
|
+
Text(
|
|
233
|
+
label,
|
|
234
|
+
maxLines: 1,
|
|
235
|
+
overflow: TextOverflow.ellipsis,
|
|
236
|
+
style: labelBase.copyWith(color: color),
|
|
237
|
+
),
|
|
238
|
+
],
|
|
239
|
+
);
|
|
240
|
+
},
|
|
241
|
+
),
|
|
242
|
+
),
|
|
143
243
|
),
|
|
144
244
|
);
|
|
145
245
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import 'package:flutter/material.dart';
|
|
2
|
+
import 'package:kasy_kit/components/kasy_web_header.dart';
|
|
3
|
+
import 'package:kasy_kit/core/theme/theme.dart';
|
|
4
|
+
import 'package:kasy_kit/core/widgets/responsive_layout.dart';
|
|
5
|
+
|
|
6
|
+
/// On desktop (≥ [DeviceType.large]) this puts the [KasyWebHeader] at the top of
|
|
7
|
+
/// the content area, above the routed page. On phone/tablet it is transparent
|
|
8
|
+
/// (returns the page untouched) — there the page keeps its own [KasyAppBar].
|
|
9
|
+
///
|
|
10
|
+
/// Wrap each routed page with this in the bottom router so the header is present
|
|
11
|
+
/// across navigation without touching individual pages.
|
|
12
|
+
class WebContentWrapper extends StatelessWidget {
|
|
13
|
+
final Widget child;
|
|
14
|
+
|
|
15
|
+
const WebContentWrapper({super.key, required this.child});
|
|
16
|
+
|
|
17
|
+
@override
|
|
18
|
+
Widget build(BuildContext context) {
|
|
19
|
+
final bool isDesktop =
|
|
20
|
+
MediaQuery.sizeOf(context).width >= DeviceType.large.breakpoint;
|
|
21
|
+
if (!isDesktop) return child;
|
|
22
|
+
|
|
23
|
+
return ColoredBox(
|
|
24
|
+
color: context.colors.background,
|
|
25
|
+
child: Column(
|
|
26
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
27
|
+
children: [
|
|
28
|
+
// The sidebar carries the user profile here, so the header drops its
|
|
29
|
+
// avatar (showAvatar: false) to avoid duplicating the account chip.
|
|
30
|
+
KasyWebHeader(
|
|
31
|
+
onToggleTheme: () => ThemeProvider.of(context).toggle(),
|
|
32
|
+
onNotifications: () {},
|
|
33
|
+
onCreate: () {},
|
|
34
|
+
showAvatar: false,
|
|
35
|
+
),
|
|
36
|
+
Expanded(child: child),
|
|
37
|
+
],
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -16,9 +16,6 @@ const String _kRcAndroidApiKeyFromDefine = String.fromEnvironment(
|
|
|
16
16
|
const String _kRcIosApiKeyFromDefine = String.fromEnvironment(
|
|
17
17
|
'RC_IOS_API_KEY',
|
|
18
18
|
);
|
|
19
|
-
const String _kRcWebApiKeyFromDefine = String.fromEnvironment(
|
|
20
|
-
'RC_WEB_API_KEY',
|
|
21
|
-
);
|
|
22
19
|
const String _kMixpanelTokenFromDefine = String.fromEnvironment(
|
|
23
20
|
'MIXPANEL_TOKEN',
|
|
24
21
|
);
|
|
@@ -28,8 +25,8 @@ const String _kSentryDsnFromDefine = String.fromEnvironment(
|
|
|
28
25
|
const String _kAppStoreIdFromDefine = String.fromEnvironment(
|
|
29
26
|
'APP_STORE_ID',
|
|
30
27
|
);
|
|
31
|
-
const String
|
|
32
|
-
'
|
|
28
|
+
const String _kAiChatEndpointFromDefine = String.fromEnvironment(
|
|
29
|
+
'AI_CHAT_ENDPOINT',
|
|
33
30
|
);
|
|
34
31
|
|
|
35
32
|
// ignore: avoid_classes_with_only_static_members
|
|
@@ -68,9 +65,6 @@ class AppEnv {
|
|
|
68
65
|
static String get rcIosApiKey =>
|
|
69
66
|
_resolve(key: 'RC_IOS_API_KEY', dartDefineValue: _kRcIosApiKeyFromDefine);
|
|
70
67
|
|
|
71
|
-
static String get rcWebApiKey =>
|
|
72
|
-
_resolve(key: 'RC_WEB_API_KEY', dartDefineValue: _kRcWebApiKeyFromDefine);
|
|
73
|
-
|
|
74
68
|
static String get mixpanelToken => _resolve(
|
|
75
69
|
key: 'MIXPANEL_TOKEN',
|
|
76
70
|
dartDefineValue: _kMixpanelTokenFromDefine,
|
|
@@ -82,9 +76,9 @@ class AppEnv {
|
|
|
82
76
|
static String get appStoreId =>
|
|
83
77
|
_resolve(key: 'APP_STORE_ID', dartDefineValue: _kAppStoreIdFromDefine);
|
|
84
78
|
|
|
85
|
-
static String get
|
|
86
|
-
key: '
|
|
87
|
-
dartDefineValue:
|
|
79
|
+
static String get aiChatEndpoint => _resolve(
|
|
80
|
+
key: 'AI_CHAT_ENDPOINT',
|
|
81
|
+
dartDefineValue: _kAiChatEndpointFromDefine,
|
|
88
82
|
);
|
|
89
83
|
|
|
90
84
|
static String _resolve({
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
/// When false, the router skips that feature's routes and the guard ignores it.
|
|
3
3
|
// ignore_for_file: avoid_redundant_argument_values
|
|
4
4
|
const bool withOnboarding = true;
|
|
5
|
-
const bool
|
|
5
|
+
const bool withAiChat = true;
|
|
6
6
|
const bool withFeedback = true;
|
|
7
7
|
const bool withRevenuecat = true;
|
|
8
|
-
const bool
|
|
8
|
+
const bool withLocalReminders = true;
|
|
9
9
|
/// When true, the app includes web support:
|
|
10
10
|
/// - anonymous sign-up is disabled on web (user is redirected to /signin)
|
|
11
11
|
/// - onboarding is skipped on web
|
|
12
12
|
/// - home widgets and background fetch are no-ops on web
|
|
13
13
|
const bool withWeb = true;
|
|
14
|
-
/// When true,
|
|
15
|
-
|
|
14
|
+
/// When true, the Stripe web-subscription module is included (web checkout +
|
|
15
|
+
/// customer portal). Independent from RevenueCat (which stays mobile-only).
|
|
16
|
+
const bool withStripe = true;
|
|
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|
|
2
2
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
3
|
import 'package:kasy_kit/core/data/models/user.dart';
|
|
4
4
|
import 'package:kasy_kit/core/initializer/onstart_service.dart';
|
|
5
|
-
import 'package:kasy_kit/
|
|
5
|
+
import 'package:kasy_kit/environments.dart';
|
|
6
6
|
import 'package:mixpanel_flutter/mixpanel_flutter.dart';
|
|
7
7
|
|
|
8
8
|
final analyticsApiProvider = Provider<AnalyticsApi>(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'package:dio/dio.dart';
|
|
2
2
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
|
-
import 'package:kasy_kit/
|
|
3
|
+
import 'package:kasy_kit/environments.dart';
|
|
4
4
|
|
|
5
5
|
final httpClientProvider = Provider<HttpClient>((ref) {
|
|
6
6
|
return HttpClient.fromEnv();
|
|
@@ -24,6 +24,9 @@ sealed class UserEntity with _$UserEntity {
|
|
|
24
24
|
String? avatarPath,
|
|
25
25
|
bool? onboarded,
|
|
26
26
|
String? locale,
|
|
27
|
+
// User role for access control. Null/absent = normal user. Set to "admin"
|
|
28
|
+
// manually in the Firebase/Supabase console to unlock server-side admin data.
|
|
29
|
+
String? role,
|
|
27
30
|
}) = UserEntityData;
|
|
28
31
|
|
|
29
32
|
const UserEntity._();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/// Provider-agnostic subscription entitlement (an access right granted to the
|
|
2
|
+
/// user by an active subscription).
|
|
3
|
+
///
|
|
4
|
+
/// This decouples the subscription core from any specific payment SDK:
|
|
5
|
+
/// RevenueCat's `EntitlementInfo` (mobile) and a Stripe subscription (web) both
|
|
6
|
+
/// map to this kit-owned type. That way a web-only app using the Stripe module
|
|
7
|
+
/// compiles and runs without the `purchases_flutter` package.
|
|
8
|
+
class Entitlement {
|
|
9
|
+
/// Entitlement identifier (e.g. `premium`).
|
|
10
|
+
final String identifier;
|
|
11
|
+
|
|
12
|
+
/// Whether the entitlement is currently active.
|
|
13
|
+
final bool isActive;
|
|
14
|
+
|
|
15
|
+
/// Whether the subscription is currently in a free-trial period.
|
|
16
|
+
final bool isInTrial;
|
|
17
|
+
|
|
18
|
+
/// Whether the subscription is set to auto-renew.
|
|
19
|
+
final bool willRenew;
|
|
20
|
+
|
|
21
|
+
/// Store product id backing this entitlement, when known.
|
|
22
|
+
final String? productId;
|
|
23
|
+
|
|
24
|
+
/// When the entitlement expires, when known.
|
|
25
|
+
final DateTime? expirationDate;
|
|
26
|
+
|
|
27
|
+
const Entitlement({
|
|
28
|
+
required this.identifier,
|
|
29
|
+
this.isActive = true,
|
|
30
|
+
this.isInTrial = false,
|
|
31
|
+
this.willRenew = false,
|
|
32
|
+
this.productId,
|
|
33
|
+
this.expirationDate,
|
|
34
|
+
});
|
|
35
|
+
}
|