kasy-cli 1.2.1
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/README.md +56 -0
- package/bin/kasy.js +529 -0
- package/docs/cli-reference.md +251 -0
- package/lib/commands/add.js +777 -0
- package/lib/commands/check.js +240 -0
- package/lib/commands/codemagic.js +161 -0
- package/lib/commands/deploy.js +257 -0
- package/lib/commands/docs.js +47 -0
- package/lib/commands/doctor.js +227 -0
- package/lib/commands/features.js +36 -0
- package/lib/commands/ios.js +206 -0
- package/lib/commands/new.js +1870 -0
- package/lib/commands/notifications.js +207 -0
- package/lib/commands/remove.js +466 -0
- package/lib/commands/run.js +75 -0
- package/lib/commands/update.js +382 -0
- package/lib/commands/validate.js +131 -0
- package/lib/scaffold/CHANGELOG.json +6 -0
- package/lib/scaffold/backends/api/.flutter-plugins-dependencies +1 -0
- package/lib/scaffold/backends/api/analysis_options.yaml +5 -0
- package/lib/scaffold/backends/api/generator.js +76 -0
- package/lib/scaffold/backends/api/patch/README.md +85 -0
- package/lib/scaffold/backends/api/patch/android/app/src/main/AndroidManifest.xml +87 -0
- package/lib/scaffold/backends/api/patch/ios/Runner/AppDelegate.swift +61 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/meta_ads_api.dart +80 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +117 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/user_api.dart +148 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/entities/json_converters.dart +35 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +48 -0
- package/lib/scaffold/backends/api/patch/lib/core/rating/widgets/review_popup.dart +211 -0
- package/lib/scaffold/backends/api/patch/lib/environnements.dart +151 -0
- package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +303 -0
- package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api_interface.dart +80 -0
- package/lib/scaffold/backends/api/patch/lib/features/authentication/repositories/authentication_repository.dart +406 -0
- package/lib/scaffold/backends/api/patch/lib/features/camera/xfile_extension.dart +6 -0
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/entities/feature_request_entity.dart +24 -0
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/entities/feature_vote_entity.dart +21 -0
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +52 -0
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_vote_api.dart +60 -0
- package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +58 -0
- package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_message_entity.dart +29 -0
- package/lib/scaffold/backends/api/patch/lib/features/notifications/api/device_api.dart +398 -0
- package/lib/scaffold/backends/api/patch/lib/features/notifications/api/entities/device_entity.dart +39 -0
- package/lib/scaffold/backends/api/patch/lib/features/notifications/api/entities/notifications_entity.dart +23 -0
- package/lib/scaffold/backends/api/patch/lib/features/notifications/api/notifications_api.dart +333 -0
- package/lib/scaffold/backends/api/patch/lib/features/notifications/providers/models/notification.dart +185 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/api/entities/user_info_entity.dart +26 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/api/user_infos_api.dart +107 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +94 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/repositories/user_infos_repository.dart +29 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/animations/movefade_anim.dart +34 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +66 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +73 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +173 -0
- package/lib/scaffold/backends/api/patch/lib/features/settings/ui/widgets/avatar_utils.dart +33 -0
- package/lib/scaffold/backends/api/patch/lib/features/subscription/api/entities/subscription_entity.dart +34 -0
- package/lib/scaffold/backends/api/patch/lib/features/subscription/api/subscription_api.dart +49 -0
- package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +88 -0
- package/lib/scaffold/backends/api/patch/lib/main.dart +256 -0
- package/lib/scaffold/backends/api/patch/lib/router.dart +133 -0
- package/lib/scaffold/backends/api/pubspec.yaml.tpl +108 -0
- package/lib/scaffold/backends/firebase/deploy.js +1006 -0
- package/lib/scaffold/backends/firebase/generator.js +24 -0
- package/lib/scaffold/backends/firebase/setup-from-scratch.js +1008 -0
- package/lib/scaffold/backends/firebase/tokens.js +113 -0
- package/lib/scaffold/backends/supabase/.flutter-plugins-dependencies +1 -0
- package/lib/scaffold/backends/supabase/analysis_options.yaml +5 -0
- package/lib/scaffold/backends/supabase/config.toml +34 -0
- package/lib/scaffold/backends/supabase/deploy.js +485 -0
- package/lib/scaffold/backends/supabase/edge-functions/delete-user-account/README.md +15 -0
- package/lib/scaffold/backends/supabase/edge-functions/delete-user-account/index.ts +97 -0
- package/lib/scaffold/backends/supabase/edge-functions/llm-chat/index.ts +156 -0
- package/lib/scaffold/backends/supabase/edge-functions/meta-track-event/index.ts +292 -0
- package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/README.md +30 -0
- package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +488 -0
- package/lib/scaffold/backends/supabase/edge-functions/send-push-notification/README.md +35 -0
- package/lib/scaffold/backends/supabase/edge-functions/send-push-notification/index.ts +314 -0
- package/lib/scaffold/backends/supabase/generator.js +108 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000001_initial_schema.sql +149 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000002_storage_bucket.sql +40 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000005_vote_triggers.sql +34 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000006_notification_webhook.sql +36 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000007_welcome_notification.sql +64 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000008_user_feature_requests.sql +2 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +22 -0
- package/lib/scaffold/backends/supabase/migrations/20240101000010_notification_image.sql +2 -0
- package/lib/scaffold/backends/supabase/patch/README.md +121 -0
- package/lib/scaffold/backends/supabase/patch/android/app/src/main/AndroidManifest.xml +87 -0
- package/lib/scaffold/backends/supabase/patch/ios/Runner/AppDelegate.swift +61 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/api/meta_ads_api.dart +75 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/api/storage_api.dart +83 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/api/user_api.dart +143 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/json_converters.dart +35 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +48 -0
- package/lib/scaffold/backends/supabase/patch/lib/core/rating/widgets/review_popup.dart +211 -0
- package/lib/scaffold/backends/supabase/patch/lib/environnements.dart +149 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +546 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/authentication/repositories/authentication_repository.dart +410 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/camera/xfile_extension.dart +6 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/entities/feature_request_entity.dart +25 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/entities/feature_vote_entity.dart +21 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +59 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_vote_api.dart +85 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/ui/component/add_feature_form.dart +199 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +47 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_message_entity.dart +30 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/providers/llm_chat_notifier.dart +266 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/device_api.dart +410 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/entities/device_entity.dart +51 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/entities/notifications_entity.dart +26 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/notifications_api.dart +317 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/providers/models/notification.dart +174 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/api/entities/user_info_entity.dart +26 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/api/user_infos_api.dart +90 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +94 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/repositories/user_infos_repository.dart +29 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/animations/movefade_anim.dart +34 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +66 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +73 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +173 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/widgets/avatar_utils.dart +35 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/subscription/api/entities/subscription_entity.dart +35 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/subscription/api/subscription_api.dart +44 -0
- package/lib/scaffold/backends/supabase/patch/lib/features/subscription/shared/maybeshow_premium.dart +85 -0
- package/lib/scaffold/backends/supabase/patch/lib/google_auth_options.dart +23 -0
- package/lib/scaffold/backends/supabase/patch/lib/main.dart +288 -0
- package/lib/scaffold/backends/supabase/patch/lib/router.dart +133 -0
- package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +110 -0
- package/lib/scaffold/backends/supabase/tokens.js +9 -0
- package/lib/scaffold/catalog.js +177 -0
- package/lib/scaffold/engine.js +230 -0
- package/lib/scaffold/features/README.md +152 -0
- package/lib/scaffold/features/analytics/lib/core/data/api/analytics_api.dart +124 -0
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/BUG.es.md +35 -0
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/BUG.md +35 -0
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/BUG.pt.md +35 -0
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/feature_request.es.md +12 -0
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/feature_request.md +12 -0
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/feature_request.pt.md +12 -0
- package/lib/scaffold/features/ci/.github/PULL_REQUEST_TEMPLATE.es.md +17 -0
- package/lib/scaffold/features/ci/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- package/lib/scaffold/features/ci/.github/PULL_REQUEST_TEMPLATE.pt.md +17 -0
- package/lib/scaffold/features/ci/.github/dependabot.yml +16 -0
- package/lib/scaffold/features/ci/.github/workflows/app.yml +20 -0
- package/lib/scaffold/features/ci/.gitlab/templates/deploy.yaml +14 -0
- package/lib/scaffold/features/ci/.gitlab/templates/dropbox.yaml +19 -0
- package/lib/scaffold/features/ci/.gitlab/templates/flutter.yaml +163 -0
- package/lib/scaffold/features/ci/.gitlab/templates/mailgun.yaml +28 -0
- package/lib/scaffold/features/ci/.gitlab-ci.yml +37 -0
- package/lib/scaffold/features/ci/codemagic.yaml +157 -0
- package/lib/scaffold/features/facebook/lib/core/data/api/tracking_api.dart +111 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/entities/feature_request_entity.dart +27 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/entities/feature_vote_entity.dart +27 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/feature_request_api.dart +50 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/feature_vote_api.dart +79 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/models/feature_requests.dart +48 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/models/feedback_state.dart +42 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/providers/feedback_page_notifier.dart +147 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/repositories/feature_request_repository.dart +95 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/component/add_feature_form.dart +199 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/feedback_page.dart +175 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/widgets/add_feature_button.dart +76 -0
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/widgets/feature_card.dart +279 -0
- package/lib/scaffold/features/ios-release/.kasy/apple.env.example +8 -0
- package/lib/scaffold/features/ios-release/.kasy/codemagic.env.example +7 -0
- package/lib/scaffold/features/ios-release/docs/codemagic-release.en.md +50 -0
- package/lib/scaffold/features/ios-release/docs/codemagic-release.es.md +50 -0
- package/lib/scaffold/features/ios-release/docs/codemagic-release.pt.md +50 -0
- package/lib/scaffold/features/ios-release/docs/ios-release.en.md +41 -0
- package/lib/scaffold/features/ios-release/docs/ios-release.es.md +41 -0
- package/lib/scaffold/features/ios-release/docs/ios-release.pt.md +41 -0
- package/lib/scaffold/features/ios-release/scripts/bump-ios-version.js +38 -0
- package/lib/scaffold/features/ios-release/scripts/release-ios.sh +137 -0
- package/lib/scaffold/features/llm_chat/lib/features/llm_chat/llm_chat_page.dart +301 -0
- package/lib/scaffold/features/local_notifications/lib/features/local_reminder/providers/reminder_notifier.dart +81 -0
- package/lib/scaffold/features/local_notifications/lib/features/local_reminder/repositories/reminder_preferences.dart +76 -0
- package/lib/scaffold/features/local_notifications/lib/features/local_reminder/ui/reminder_page.dart +282 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/api/entities/user_info_entity.dart +24 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/api/user_infos_api.dart +71 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/models/user_info.dart +92 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/providers/onboarding_model.dart +15 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/providers/onboarding_provider.dart +78 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/repositories/user_infos_repository.dart +29 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/animations/page_transitions.dart +30 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_att_setup.dart +66 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_features.dart +72 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_loader.dart +92 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +73 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_questions.dart +89 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/onboarding_page.dart +94 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_background.dart +80 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_feature.dart +139 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +110 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_progress.dart +84 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +173 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_reassurance.dart +45 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +77 -0
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +392 -0
- package/lib/scaffold/features/revenuecat/lib/core/data/api/tracking_api.dart +116 -0
- package/lib/scaffold/features/revenuecat/lib/core/data/models/subscription.dart +322 -0
- package/lib/scaffold/features/revenuecat/lib/core/home_widgets/home_widget_background_task.dart +41 -0
- package/lib/scaffold/features/revenuecat/lib/core/states/user_state_notifier.dart +305 -0
- package/lib/scaffold/features/widget/lib/core/home_widgets/home_widget_background_task.dart +41 -0
- package/lib/scaffold/features/widget/lib/core/home_widgets/home_widget_mywidget_service.dart +57 -0
- package/lib/scaffold/features/widget/lib/core/home_widgets/home_widget_service.dart +54 -0
- package/lib/scaffold/features/widget/lib/features/settings/ui/components/admin/admin_home_widgets.dart +32 -0
- package/lib/scaffold/generate.js +370 -0
- package/lib/scaffold/patch.js +395 -0
- package/lib/scaffold/shared/backend-config.js +74 -0
- package/lib/scaffold/shared/fcm-service-account.js +126 -0
- package/lib/scaffold/shared/generator-utils.js +1664 -0
- package/lib/scaffold/shared/post-build.js +809 -0
- package/lib/scaffold/shared/template-strings.js +112 -0
- package/lib/utils/apple-release.js +273 -0
- package/lib/utils/checks.js +319 -0
- package/lib/utils/codemagic-release.js +127 -0
- package/lib/utils/fs.js +122 -0
- package/lib/utils/i18n.js +2123 -0
- package/lib/utils/license-gate.js +72 -0
- package/lib/utils/license.js +64 -0
- package/lib/utils/prompts.js +213 -0
- package/lib/utils/updates.js +97 -0
- package/package.json +55 -0
- package/templates/firebase/.env.example +24 -0
- package/templates/firebase/.firebaserc +5 -0
- package/templates/firebase/.kasy/apple.env.example +8 -0
- package/templates/firebase/.kasy/codemagic.env.example +7 -0
- package/templates/firebase/.metadata +30 -0
- package/templates/firebase/.windsurfrules +95 -0
- package/templates/firebase/Makefile +30 -0
- package/templates/firebase/README.en.md +180 -0
- package/templates/firebase/README.es.md +180 -0
- package/templates/firebase/README.md +180 -0
- package/templates/firebase/analysis_options.yaml +37 -0
- package/templates/firebase/android/app/build.gradle.kts +80 -0
- package/templates/firebase/android/app/src/debug/AndroidManifest.xml +7 -0
- package/templates/firebase/android/app/src/main/AndroidManifest.xml +93 -0
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MainActivity.kt +36 -0
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MyWidget.kt +50 -0
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MyWidgetReceiver.kt +7 -0
- package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable/launch_background.xml +9 -0
- package/templates/firebase/android/app/src/main/res/drawable-hdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-mdpi/splash.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/drawable-v21/launch_background.xml +9 -0
- package/templates/firebase/android/app/src/main/res/drawable-xhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xxxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/templates/firebase/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/templates/firebase/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/templates/firebase/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/templates/firebase/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/templates/firebase/android/app/src/main/res/values/strings.xml +6 -0
- package/templates/firebase/android/app/src/main/res/values/styles.xml +22 -0
- package/templates/firebase/android/app/src/main/res/values-night/styles.xml +22 -0
- package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +20 -0
- package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +20 -0
- package/templates/firebase/android/app/src/main/res/xml/locales_config.xml +7 -0
- package/templates/firebase/android/app/src/main/res/xml/mywidget_info.xml +11 -0
- package/templates/firebase/android/app/src/profile/AndroidManifest.xml +7 -0
- package/templates/firebase/android/build.gradle.kts +28 -0
- package/templates/firebase/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/templates/firebase/android/gradle.properties +2 -0
- package/templates/firebase/android/settings.gradle.kts +29 -0
- package/templates/firebase/assets/icons/apple.png +0 -0
- package/templates/firebase/assets/icons/facebook.png +0 -0
- package/templates/firebase/assets/icons/google.png +0 -0
- package/templates/firebase/assets/icons/google_play_games.png +0 -0
- package/templates/firebase/assets/images/app_icon.png +0 -0
- package/templates/firebase/assets/images/empty_notifications.jpg +0 -0
- package/templates/firebase/assets/images/icon.png +0 -0
- package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/img1.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/onboarding.png +0 -0
- package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
- package/templates/firebase/assets/images/premium-bg.jpg +0 -0
- package/templates/firebase/assets/images/premium-switch-header.png +0 -0
- package/templates/firebase/assets/images/review.png +0 -0
- package/templates/firebase/assets/images/splashscreen.png +0 -0
- package/templates/firebase/assets/images/update.png +0 -0
- package/templates/firebase/build.yaml +13 -0
- package/templates/firebase/devtools_options.yaml +3 -0
- package/templates/firebase/docs/auth-setup.en.md +145 -0
- package/templates/firebase/docs/auth-setup.es.md +145 -0
- package/templates/firebase/docs/auth-setup.pt.md +145 -0
- package/templates/firebase/docs/codemagic-release.en.md +50 -0
- package/templates/firebase/docs/codemagic-release.es.md +50 -0
- package/templates/firebase/docs/codemagic-release.pt.md +50 -0
- package/templates/firebase/docs/ios-release.en.md +41 -0
- package/templates/firebase/docs/ios-release.es.md +41 -0
- package/templates/firebase/docs/ios-release.pt.md +54 -0
- package/templates/firebase/docs/navigation-transitions.md +80 -0
- package/templates/firebase/docs/revenuecat-setup.es.md +341 -0
- package/templates/firebase/docs/revenuecat-setup.pt.md +341 -0
- package/templates/firebase/firebase.json +1 -0
- package/templates/firebase/firestore.indexes.json +25 -0
- package/templates/firebase/firestore.rules +51 -0
- package/templates/firebase/functions/.eslintrc.js +45 -0
- package/templates/firebase/functions/jest.config.js +16 -0
- package/templates/firebase/functions/package-lock.json +6876 -0
- package/templates/firebase/functions/package.json +33 -0
- package/templates/firebase/functions/src/authentication/functions.ts +30 -0
- package/templates/firebase/functions/src/authentication/triggers.ts +103 -0
- package/templates/firebase/functions/src/core/api/meta_ads_api.ts +390 -0
- package/templates/firebase/functions/src/core/data/entities/entity_utils.ts +87 -0
- package/templates/firebase/functions/src/core/data/entities/notification_entity.ts +74 -0
- package/templates/firebase/functions/src/core/data/entities/page.ts +4 -0
- package/templates/firebase/functions/src/core/data/entities/subscription_entity.ts +76 -0
- package/templates/firebase/functions/src/core/data/entities/user_device_entity.ts +64 -0
- package/templates/firebase/functions/src/core/data/entities/user_entity.ts +43 -0
- package/templates/firebase/functions/src/core/data/repositories/repositories.ts +16 -0
- package/templates/firebase/functions/src/core/data/repositories/subscription_repository.ts +42 -0
- package/templates/firebase/functions/src/core/data/repositories/user_device_repository.ts +31 -0
- package/templates/firebase/functions/src/core/data/repositories/user_notifications_repository.ts +58 -0
- package/templates/firebase/functions/src/core/data/repositories/user_repository.ts +84 -0
- package/templates/firebase/functions/src/core/logger/logger.ts +13 -0
- package/templates/firebase/functions/src/core/storage/storage_manager.ts +52 -0
- package/templates/firebase/functions/src/core/utils/async_utils.ts +5 -0
- package/templates/firebase/functions/src/feature_requests/triggers.ts +3 -0
- package/templates/firebase/functions/src/index.ts +24 -0
- package/templates/firebase/functions/src/llm_chat/index.ts +181 -0
- package/templates/firebase/functions/src/notifications/admin_functions.ts +91 -0
- package/templates/firebase/functions/src/notifications/models/notification.ts +61 -0
- package/templates/firebase/functions/src/notifications/notifications_api.ts +147 -0
- package/templates/firebase/functions/src/notifications/triggers.ts +102 -0
- package/templates/firebase/functions/src/subscriptions/models/revenuecat_events.ts +162 -0
- package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +18 -0
- package/templates/firebase/functions/src/subscriptions/models/subscriptions.ts +173 -0
- package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +135 -0
- package/templates/firebase/functions/src/subscriptions/triggers.ts +35 -0
- package/templates/firebase/functions/src/test/core/data/entities/entity_utils.spec.ts +44 -0
- package/templates/firebase/functions/tsconfig.dev.json +5 -0
- package/templates/firebase/functions/tsconfig.json +18 -0
- package/templates/firebase/home_widget_config.json +30 -0
- package/templates/firebase/ios/Flutter/AppFrameworkInfo.plist +24 -0
- package/templates/firebase/ios/Flutter/Debug.xcconfig +2 -0
- package/templates/firebase/ios/Flutter/Profile.xcconfig +2 -0
- package/templates/firebase/ios/Flutter/Release.xcconfig +2 -0
- package/templates/firebase/ios/HomeWidgetExtension/HomeWidgetBundle.swift +13 -0
- package/templates/firebase/ios/HomeWidgetExtension/Info.plist +29 -0
- package/templates/firebase/ios/HomeWidgetExtension/MyWidget.swift +86 -0
- package/templates/firebase/ios/HomeWidgetExtension.entitlements +10 -0
- package/templates/firebase/ios/NotificationService/Info.plist +31 -0
- package/templates/firebase/ios/NotificationService/NotificationService.swift +76 -0
- package/templates/firebase/ios/Podfile +111 -0
- package/templates/firebase/ios/Runner/AppDelegate.swift +75 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +1 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json +21 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +23 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +5 -0
- package/templates/firebase/ios/Runner/Base.lproj/LaunchScreen.storyboard +44 -0
- package/templates/firebase/ios/Runner/Base.lproj/Main.storyboard +26 -0
- package/templates/firebase/ios/Runner/Info.plist +132 -0
- package/templates/firebase/ios/Runner/Runner-Bridging-Header.h +1 -0
- package/templates/firebase/ios/Runner/Runner.entitlements +14 -0
- package/templates/firebase/ios/Runner/es.lproj/InfoPlist.strings +10 -0
- package/templates/firebase/ios/Runner/pt-BR.lproj/InfoPlist.strings +10 -0
- package/templates/firebase/ios/Runner/pt.lproj/InfoPlist.strings +10 -0
- package/templates/firebase/ios/Runner.xcodeproj/project.pbxproj +1108 -0
- package/templates/firebase/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/templates/firebase/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/templates/firebase/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- package/templates/firebase/ios/Runner.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme +58 -0
- package/templates/firebase/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +101 -0
- package/templates/firebase/ios/Runner.xcworkspace/contents.xcworkspacedata +10 -0
- package/templates/firebase/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/templates/firebase/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- package/templates/firebase/ios/RunnerTests/RunnerTests.swift +12 -0
- package/templates/firebase/lib/components/components.dart +27 -0
- package/templates/firebase/lib/components/kasy_accordion.dart +384 -0
- package/templates/firebase/lib/components/kasy_alert.dart +266 -0
- package/templates/firebase/lib/components/kasy_app_bar.dart +536 -0
- package/templates/firebase/lib/components/kasy_avatar.dart +549 -0
- package/templates/firebase/lib/components/kasy_avatar_presets.dart +104 -0
- package/templates/firebase/lib/components/kasy_badge.dart +278 -0
- package/templates/firebase/lib/components/kasy_bottom_sheet.dart +338 -0
- package/templates/firebase/lib/components/kasy_button.dart +926 -0
- package/templates/firebase/lib/components/kasy_card.dart +128 -0
- package/templates/firebase/lib/components/kasy_checkbox.dart +429 -0
- package/templates/firebase/lib/components/kasy_chip.dart +83 -0
- package/templates/firebase/lib/components/kasy_dialog.dart +789 -0
- package/templates/firebase/lib/components/kasy_otp_verification_bottom_sheet.dart +233 -0
- package/templates/firebase/lib/components/kasy_skeleton.dart +225 -0
- package/templates/firebase/lib/components/kasy_text_area.dart +392 -0
- package/templates/firebase/lib/components/kasy_text_field.dart +591 -0
- package/templates/firebase/lib/components/kasy_text_field_otp.dart +532 -0
- package/templates/firebase/lib/components/kasy_toast.dart +803 -0
- package/templates/firebase/lib/core/ads/ads_provider.dart +136 -0
- package/templates/firebase/lib/core/ads/ads_state.dart +15 -0
- package/templates/firebase/lib/core/animations/bottomfade_anim.dart +37 -0
- package/templates/firebase/lib/core/animations/movefade_anim.dart +34 -0
- package/templates/firebase/lib/core/animations/slideright_anim.dart +38 -0
- package/templates/firebase/lib/core/bottom_menu/bart_inner_paths.dart +5 -0
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +127 -0
- package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +281 -0
- package/templates/firebase/lib/core/bottom_menu/kasy_bart_navigation.dart +22 -0
- package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +127 -0
- package/templates/firebase/lib/core/bottom_menu/notification_bottom_item.dart +48 -0
- package/templates/firebase/lib/core/config/app_env.dart +100 -0
- package/templates/firebase/lib/core/config/features.dart +15 -0
- package/templates/firebase/lib/core/data/api/analytics_api.dart +124 -0
- package/templates/firebase/lib/core/data/api/base_api_exceptions.dart +28 -0
- package/templates/firebase/lib/core/data/api/firestore_retry.dart +29 -0
- package/templates/firebase/lib/core/data/api/http_client.dart +38 -0
- package/templates/firebase/lib/core/data/api/image.dart +52 -0
- package/templates/firebase/lib/core/data/api/remote_config_api.dart +170 -0
- package/templates/firebase/lib/core/data/api/storage_api.dart +115 -0
- package/templates/firebase/lib/core/data/api/tracking_api.dart +119 -0
- package/templates/firebase/lib/core/data/api/user_api.dart +115 -0
- package/templates/firebase/lib/core/data/entities/json_converters.dart +39 -0
- package/templates/firebase/lib/core/data/entities/upload_result.dart +48 -0
- package/templates/firebase/lib/core/data/entities/user_entity.dart +54 -0
- package/templates/firebase/lib/core/data/models/pageable.dart +12 -0
- package/templates/firebase/lib/core/data/models/subscription.dart +322 -0
- package/templates/firebase/lib/core/data/models/user.dart +107 -0
- package/templates/firebase/lib/core/data/repositories/user_repository.dart +130 -0
- package/templates/firebase/lib/core/dev_inspector/dev_inspector.dart +464 -0
- package/templates/firebase/lib/core/dev_inspector/dev_inspector_highlight.dart +88 -0
- package/templates/firebase/lib/core/dev_inspector/dev_inspector_info.dart +70 -0
- package/templates/firebase/lib/core/dev_inspector/dev_inspector_panel.dart +204 -0
- package/templates/firebase/lib/core/dev_inspector/dev_inspector_service.dart +321 -0
- package/templates/firebase/lib/core/extensions/date.ext.dart +32 -0
- package/templates/firebase/lib/core/guards/authenticated_guard.dart +37 -0
- package/templates/firebase/lib/core/guards/guard.dart +68 -0
- package/templates/firebase/lib/core/guards/user_info_guard.dart +55 -0
- package/templates/firebase/lib/core/haptics/haptic_feedback_notifier.dart +19 -0
- package/templates/firebase/lib/core/haptics/kasy_haptics.dart +27 -0
- package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +41 -0
- package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +57 -0
- package/templates/firebase/lib/core/home_widgets/home_widget_service.dart +54 -0
- package/templates/firebase/lib/core/icons/kasy_icons.dart +86 -0
- package/templates/firebase/lib/core/initializer/models/run_state.dart +14 -0
- package/templates/firebase/lib/core/initializer/onstart_service.dart +38 -0
- package/templates/firebase/lib/core/initializer/onstart_widget.dart +83 -0
- package/templates/firebase/lib/core/initializer/pending_notification_handler.dart +48 -0
- package/templates/firebase/lib/core/keyboard_fix/keyboard_flicker_fix.dart +164 -0
- package/templates/firebase/lib/core/navigation/kasy_fade_page_transitions_builder.dart +34 -0
- package/templates/firebase/lib/core/navigation/kasy_material_page_route.dart +41 -0
- package/templates/firebase/lib/core/navigation/kasy_navigation_config.dart +29 -0
- package/templates/firebase/lib/core/navigation/kasy_page_transition.dart +40 -0
- package/templates/firebase/lib/core/navigation/kasy_route_transition.dart +68 -0
- package/templates/firebase/lib/core/navigation/kasy_transition_kind.dart +17 -0
- package/templates/firebase/lib/core/navigation/navigation.dart +6 -0
- package/templates/firebase/lib/core/rating/api/rating_api.dart +99 -0
- package/templates/firebase/lib/core/rating/models/rating.dart +52 -0
- package/templates/firebase/lib/core/rating/models/review.dart +70 -0
- package/templates/firebase/lib/core/rating/providers/rating_repository.dart +75 -0
- package/templates/firebase/lib/core/rating/widgets/rate_banner.dart +190 -0
- package/templates/firebase/lib/core/rating/widgets/rate_popup.dart +54 -0
- package/templates/firebase/lib/core/rating/widgets/review_popup.dart +175 -0
- package/templates/firebase/lib/core/security/biometric_copy_slot.dart +20 -0
- package/templates/firebase/lib/core/security/biometric_guard.dart +114 -0
- package/templates/firebase/lib/core/security/biometric_preference_notifier.dart +17 -0
- package/templates/firebase/lib/core/security/biometric_service.dart +79 -0
- package/templates/firebase/lib/core/security/biometric_ui_bundle.dart +136 -0
- package/templates/firebase/lib/core/security/secured_storage.dart +46 -0
- package/templates/firebase/lib/core/shared_preferences/shared_preferences.dart +70 -0
- package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +2021 -0
- package/templates/firebase/lib/core/states/components/maybe_ask_biometric_setup.dart +88 -0
- package/templates/firebase/lib/core/states/components/maybe_ask_rating.dart +49 -0
- package/templates/firebase/lib/core/states/components/maybe_show_update_bottom_sheet.dart +86 -0
- package/templates/firebase/lib/core/states/components/maybeshow_component.dart +110 -0
- package/templates/firebase/lib/core/states/events_dispatcher.dart +103 -0
- package/templates/firebase/lib/core/states/models/event_model.dart +118 -0
- package/templates/firebase/lib/core/states/models/user_state.dart +22 -0
- package/templates/firebase/lib/core/states/notifications_dispatcher.dart +81 -0
- package/templates/firebase/lib/core/states/translations.dart +11 -0
- package/templates/firebase/lib/core/states/user_state_notifier.dart +321 -0
- package/templates/firebase/lib/core/theme/colors.dart +262 -0
- package/templates/firebase/lib/core/theme/extensions/theme_extension.dart +48 -0
- package/templates/firebase/lib/core/theme/providers/kasy_theme.dart +76 -0
- package/templates/firebase/lib/core/theme/providers/theme_provider.dart +212 -0
- package/templates/firebase/lib/core/theme/radius.dart +33 -0
- package/templates/firebase/lib/core/theme/shadows.dart +64 -0
- package/templates/firebase/lib/core/theme/spacing.dart +44 -0
- package/templates/firebase/lib/core/theme/texts.dart +176 -0
- package/templates/firebase/lib/core/theme/theme.dart +24 -0
- package/templates/firebase/lib/core/theme/theme_data/theme_data.dart +32 -0
- package/templates/firebase/lib/core/theme/theme_data/theme_data_factory.dart +15 -0
- package/templates/firebase/lib/core/theme/universal_theme.dart +210 -0
- package/templates/firebase/lib/core/toast/toast_service.dart +55 -0
- package/templates/firebase/lib/core/ui/app_dialog.dart +26 -0
- package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +1126 -0
- package/templates/firebase/lib/core/widgets/debouncer.dart +31 -0
- package/templates/firebase/lib/core/widgets/kasy_hover.dart +166 -0
- package/templates/firebase/lib/core/widgets/kasy_pressable.dart +2 -0
- package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +161 -0
- package/templates/firebase/lib/core/widgets/kasy_scroll_behavior.dart +17 -0
- package/templates/firebase/lib/core/widgets/keyboard_visibility.dart +75 -0
- package/templates/firebase/lib/core/widgets/page_background.dart +71 -0
- package/templates/firebase/lib/core/widgets/page_not_found.dart +15 -0
- package/templates/firebase/lib/core/widgets/responsive_layout.dart +215 -0
- package/templates/firebase/lib/core/widgets/update_bottom_sheet.dart +192 -0
- package/templates/firebase/lib/environnements.dart +160 -0
- package/templates/firebase/lib/features/authentication/api/authentication_api.dart +528 -0
- package/templates/firebase/lib/features/authentication/api/authentication_api_interface.dart +84 -0
- package/templates/firebase/lib/features/authentication/providers/models/email.dart +36 -0
- package/templates/firebase/lib/features/authentication/providers/models/password.dart +37 -0
- package/templates/firebase/lib/features/authentication/providers/models/phone_signin_state.dart +21 -0
- package/templates/firebase/lib/features/authentication/providers/models/recover_state.dart +21 -0
- package/templates/firebase/lib/features/authentication/providers/models/signin_state.dart +20 -0
- package/templates/firebase/lib/features/authentication/providers/models/signup_state.dart +20 -0
- package/templates/firebase/lib/features/authentication/providers/phone_auth_notifier.dart +132 -0
- package/templates/firebase/lib/features/authentication/providers/recover_provider.dart +51 -0
- package/templates/firebase/lib/features/authentication/providers/signin_state_provider.dart +166 -0
- package/templates/firebase/lib/features/authentication/providers/signup_state_provider.dart +67 -0
- package/templates/firebase/lib/features/authentication/repositories/authentication_repository.dart +399 -0
- package/templates/firebase/lib/features/authentication/repositories/exceptions/authentication_exceptions.dart +85 -0
- package/templates/firebase/lib/features/authentication/ui/components/apple_signin.dart +19 -0
- package/templates/firebase/lib/features/authentication/ui/components/facebook_signin.dart +19 -0
- package/templates/firebase/lib/features/authentication/ui/components/google_signin.dart +32 -0
- package/templates/firebase/lib/features/authentication/ui/components/otp_verification.dart +100 -0
- package/templates/firebase/lib/features/authentication/ui/components/phone_input.dart +109 -0
- package/templates/firebase/lib/features/authentication/ui/phone_auth_page.dart +60 -0
- package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +101 -0
- package/templates/firebase/lib/features/authentication/ui/signin_page.dart +321 -0
- package/templates/firebase/lib/features/authentication/ui/signup_page.dart +310 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +35 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/auth_page_back_button.dart +149 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/otp_input.dart +194 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +62 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/round_signin.dart +73 -0
- package/templates/firebase/lib/features/authentication/ui/widgets/social_separator.dart +26 -0
- package/templates/firebase/lib/features/dev/keyboard_test_page.dart +93 -0
- package/templates/firebase/lib/features/feedbacks/api/entities/feature_request_entity.dart +27 -0
- package/templates/firebase/lib/features/feedbacks/api/entities/feature_vote_entity.dart +27 -0
- package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +51 -0
- package/templates/firebase/lib/features/feedbacks/api/feature_vote_api.dart +79 -0
- package/templates/firebase/lib/features/feedbacks/models/feature_requests.dart +48 -0
- package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +43 -0
- package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +147 -0
- package/templates/firebase/lib/features/feedbacks/repositories/feature_request_repository.dart +92 -0
- package/templates/firebase/lib/features/feedbacks/ui/component/add_feature_form.dart +112 -0
- package/templates/firebase/lib/features/feedbacks/ui/feedback_page.dart +184 -0
- package/templates/firebase/lib/features/feedbacks/ui/widgets/add_feature_button.dart +66 -0
- package/templates/firebase/lib/features/feedbacks/ui/widgets/feature_card.dart +266 -0
- package/templates/firebase/lib/features/home/design_system_page.dart +552 -0
- package/templates/firebase/lib/features/home/home_components_page.dart +314 -0
- package/templates/firebase/lib/features/home/home_components_preview_page.dart +791 -0
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +7712 -0
- package/templates/firebase/lib/features/home/home_features_page.dart +207 -0
- package/templates/firebase/lib/features/home/home_page.dart +348 -0
- package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +50 -0
- package/templates/firebase/lib/features/llm_chat/api/llm_chat_message_entity.dart +35 -0
- package/templates/firebase/lib/features/llm_chat/llm_chat_page.dart +352 -0
- package/templates/firebase/lib/features/llm_chat/providers/llm_chat_notifier.dart +315 -0
- package/templates/firebase/lib/features/llm_chat/ui/widgets/llm_chat_avatars.dart +148 -0
- package/templates/firebase/lib/features/llm_chat/ui/widgets/llm_chat_composer.dart +124 -0
- package/templates/firebase/lib/features/local_reminder/providers/reminder_notifier.dart +81 -0
- package/templates/firebase/lib/features/local_reminder/repositories/reminder_preferences.dart +76 -0
- package/templates/firebase/lib/features/local_reminder/ui/reminder_page.dart +288 -0
- package/templates/firebase/lib/features/notifications/api/device_api.dart +433 -0
- package/templates/firebase/lib/features/notifications/api/entities/device_entity.dart +62 -0
- package/templates/firebase/lib/features/notifications/api/entities/notifications_entity.dart +35 -0
- package/templates/firebase/lib/features/notifications/api/local_notifier.dart +409 -0
- package/templates/firebase/lib/features/notifications/api/notifications_api.dart +319 -0
- package/templates/firebase/lib/features/notifications/providers/models/device.dart +27 -0
- package/templates/firebase/lib/features/notifications/providers/models/notification.dart +196 -0
- package/templates/firebase/lib/features/notifications/providers/models/notification_list.dart +38 -0
- package/templates/firebase/lib/features/notifications/providers/notifications_provider.dart +120 -0
- package/templates/firebase/lib/features/notifications/repositories/background_notification_handler.dart +13 -0
- package/templates/firebase/lib/features/notifications/repositories/device_repository.dart +137 -0
- package/templates/firebase/lib/features/notifications/repositories/notifications_repository.dart +214 -0
- package/templates/firebase/lib/features/notifications/shared/att_permission.dart +75 -0
- package/templates/firebase/lib/features/notifications/shared/notification_permission_bottom_sheet.dart +144 -0
- package/templates/firebase/lib/features/notifications/ui/components/notification_settings_sheet.dart +169 -0
- package/templates/firebase/lib/features/notifications/ui/components/notification_tile.dart +46 -0
- package/templates/firebase/lib/features/notifications/ui/components/notifications_header.dart +32 -0
- package/templates/firebase/lib/features/notifications/ui/components/push_notification_switcher.dart +106 -0
- package/templates/firebase/lib/features/notifications/ui/notifications_page.dart +202 -0
- package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +84 -0
- package/templates/firebase/lib/features/notifications/ui/widgets/empty_notifications.dart +73 -0
- package/templates/firebase/lib/features/notifications/ui/widgets/notification_tile.dart +362 -0
- package/templates/firebase/lib/features/onboarding/api/entities/user_info_entity.dart +24 -0
- package/templates/firebase/lib/features/onboarding/api/user_infos_api.dart +71 -0
- package/templates/firebase/lib/features/onboarding/models/user_info.dart +92 -0
- package/templates/firebase/lib/features/onboarding/providers/onboarding_model.dart +15 -0
- package/templates/firebase/lib/features/onboarding/providers/onboarding_provider.dart +78 -0
- package/templates/firebase/lib/features/onboarding/repositories/user_infos_repository.dart +29 -0
- package/templates/firebase/lib/features/onboarding/ui/animations/page_transitions.dart +33 -0
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +66 -0
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +76 -0
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +92 -0
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +76 -0
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +89 -0
- package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +108 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +80 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +145 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +125 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +84 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +173 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_reassurance.dart +44 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +77 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +392 -0
- package/templates/firebase/lib/features/settings/settings_page.dart +460 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +301 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_home_widgets.dart +38 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +53 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +22 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +366 -0
- package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notifier.dart +40 -0
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +430 -0
- package/templates/firebase/lib/features/settings/ui/components/delete_user_component.dart +28 -0
- package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +163 -0
- package/templates/firebase/lib/features/settings/ui/widgets/admin_card.dart +59 -0
- package/templates/firebase/lib/features/settings/ui/widgets/avatar_utils.dart +51 -0
- package/templates/firebase/lib/features/settings/ui/widgets/round_progress.dart +151 -0
- package/templates/firebase/lib/features/settings/ui/widgets/settings_bottom_sheet_option_tile.dart +52 -0
- package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +163 -0
- package/templates/firebase/lib/features/subscription/api/entities/subscription_entity.dart +40 -0
- package/templates/firebase/lib/features/subscription/api/inapp_subscription_api.dart +389 -0
- package/templates/firebase/lib/features/subscription/api/subscription_api.dart +39 -0
- package/templates/firebase/lib/features/subscription/providers/models/premium_state.dart +35 -0
- package/templates/firebase/lib/features/subscription/providers/premium_page_provider.dart +259 -0
- package/templates/firebase/lib/features/subscription/repositories/subscription_repository.dart +177 -0
- package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +85 -0
- package/templates/firebase/lib/features/subscription/ui/component/active_premium_content.dart +171 -0
- package/templates/firebase/lib/features/subscription/ui/component/paywall_minimal.dart +146 -0
- package/templates/firebase/lib/features/subscription/ui/component/paywall_row.dart +332 -0
- package/templates/firebase/lib/features/subscription/ui/component/paywall_with_switch.dart +207 -0
- package/templates/firebase/lib/features/subscription/ui/component/premium_content.dart +157 -0
- package/templates/firebase/lib/features/subscription/ui/component/premium_page_factory.dart +161 -0
- package/templates/firebase/lib/features/subscription/ui/premium_page.dart +139 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/comparison_table.dart +346 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/feature_line.dart +131 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/paywall_empty_state.dart +68 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/premium_background.dart +63 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/premium_background_gradient.dart +53 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/premium_banner.dart +80 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/premium_bottom_menu.dart +102 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/premium_card.dart +26 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/premium_close_button.dart +61 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/premium_feature.dart +39 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/selectable_col.dart +377 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/selectable_row.dart +436 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/trial_switcher.dart +85 -0
- package/templates/firebase/lib/features/subscription/ui/widgets/unsubscribe_feedback_popup.dart +123 -0
- package/templates/firebase/lib/firebase_options.dart +75 -0
- package/templates/firebase/lib/google_auth_options.dart +10 -0
- package/templates/firebase/lib/i18n/app_locale_display.dart +17 -0
- package/templates/firebase/lib/i18n/en.i18n.json +514 -0
- package/templates/firebase/lib/i18n/es.i18n.json +514 -0
- package/templates/firebase/lib/i18n/pt.i18n.json +514 -0
- package/templates/firebase/lib/i18n/widgets/locale_code_badge.dart +47 -0
- package/templates/firebase/lib/main.dart +263 -0
- package/templates/firebase/lib/router.dart +226 -0
- package/templates/firebase/login-redesign-preview.png +0 -0
- package/templates/firebase/pubspec.yaml +177 -0
- package/templates/firebase/scripts/bump-ios-version.js +38 -0
- package/templates/firebase/scripts/release-ios.sh +137 -0
- package/templates/firebase/slang.yaml +7 -0
- package/templates/firebase/storage.rules +12 -0
- package/templates/firebase/test/core/data/api/analytics_api_fake.dart +25 -0
- package/templates/firebase/test/core/data/api/fake_remote_config_api.dart +45 -0
- package/templates/firebase/test/core/data/api/storage_api_fake.dart +28 -0
- package/templates/firebase/test/core/data/models/subscription_test.dart +42 -0
- package/templates/firebase/test/core/data/repositories/user_repository_test.dart +56 -0
- package/templates/firebase/test/core/guards/guard_test.dart +78 -0
- package/templates/firebase/test/core/navigation/kasy_page_transition_test.dart +30 -0
- package/templates/firebase/test/core/onstart_service_test.dart +18 -0
- package/templates/firebase/test/core/rating/rating_api_fake.dart +58 -0
- package/templates/firebase/test/core/rating/rating_banner_test.dart +117 -0
- package/templates/firebase/test/core/rating/rating_test.dart +60 -0
- package/templates/firebase/test/core/security/secured_storage_fake.dart +33 -0
- package/templates/firebase/test/core/states/event_dispatcher_test.dart +269 -0
- package/templates/firebase/test/core/states/user_state_notifier_test.dart +244 -0
- package/templates/firebase/test/core/widgets/responsive_layout_test.dart +50 -0
- package/templates/firebase/test/device_test_utils.dart +98 -0
- package/templates/firebase/test/features/authentication/data/api/auth_api_fake.dart +169 -0
- package/templates/firebase/test/features/authentication/data/api/user_api_fake.dart +86 -0
- package/templates/firebase/test/features/authentication/lost_password_page_test.dart +59 -0
- package/templates/firebase/test/features/authentication/repositories/authentication_repository_test.dart +88 -0
- package/templates/firebase/test/features/authentication/signin_page_test.dart +133 -0
- package/templates/firebase/test/features/authentication/signup_page_test.dart +136 -0
- package/templates/firebase/test/features/notifications/data/device_api_fake.dart +66 -0
- package/templates/firebase/test/features/notifications/data/fake_facebook_api.dart +40 -0
- package/templates/firebase/test/features/notifications/data/local_notifier_fake.dart +59 -0
- package/templates/firebase/test/features/notifications/data/notifications_api_fake.dart +120 -0
- package/templates/firebase/test/features/notifications/data/notifications_settings_fake.dart +34 -0
- package/templates/firebase/test/features/notifications/providers/device_repository_test.dart +68 -0
- package/templates/firebase/test/features/notifications/providers/notifications_repository_test.dart +74 -0
- package/templates/firebase/test/features/notifications/ui/notifications_page_test.dart +69 -0
- package/templates/firebase/test/features/subscription/api/fake_inapp_subscription_api.dart +85 -0
- package/templates/firebase/test/features/subscription/api/fake_revenuecat_product.dart +186 -0
- package/templates/firebase/test/features/subscription/api/fake_subscription_api.dart +11 -0
- package/templates/firebase/test/features/subscription/subscription_page_test.dart +119 -0
- package/templates/firebase/test/firebase_test_utils.dart +25 -0
- package/templates/firebase/test/test_utils.dart +272 -0
- package/templates/firebase/web/favicon.png +0 -0
- package/templates/firebase/web/firebase-messaging-sw.js +27 -0
- package/templates/firebase/web/icons/Icon-192.png +0 -0
- package/templates/firebase/web/icons/Icon-512.png +0 -0
- package/templates/firebase/web/icons/Icon-maskable-192.png +0 -0
- package/templates/firebase/web/icons/Icon-maskable-512.png +0 -0
- package/templates/firebase/web/index.html +110 -0
- package/templates/firebase/web/local_notifications.js +31 -0
- package/templates/firebase/web/manifest.json +35 -0
- package/templates/firebase/web/splash/img/dark-1x.png +0 -0
- package/templates/firebase/web/splash/img/dark-2x.png +0 -0
- package/templates/firebase/web/splash/img/dark-3x.png +0 -0
- package/templates/firebase/web/splash/img/dark-4x.png +0 -0
- package/templates/firebase/web/splash/img/light-1x.png +0 -0
- package/templates/firebase/web/splash/img/light-2x.png +0 -0
- package/templates/firebase/web/splash/img/light-3x.png +0 -0
- package/templates/firebase/web/splash/img/light-4x.png +0 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import 'package:flutter/material.dart';
|
|
2
|
+
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
3
|
+
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
4
|
+
import 'package:kasy_kit/features/subscription/api/entities/subscription_entity.dart';
|
|
5
|
+
import 'package:purchases_flutter/purchases_flutter.dart';
|
|
6
|
+
|
|
7
|
+
part 'subscription.freezed.dart';
|
|
8
|
+
|
|
9
|
+
abstract class SubscriptionProduct {
|
|
10
|
+
/// Unique identifier of the product in the store
|
|
11
|
+
String get skuId;
|
|
12
|
+
|
|
13
|
+
/// Unique identifier
|
|
14
|
+
String get id;
|
|
15
|
+
|
|
16
|
+
/// Description of the subscription from your app
|
|
17
|
+
String get description;
|
|
18
|
+
|
|
19
|
+
/// Label of the subscription from the package in revenue cat
|
|
20
|
+
String get label;
|
|
21
|
+
|
|
22
|
+
/// Price of the subscription
|
|
23
|
+
double get price;
|
|
24
|
+
|
|
25
|
+
/// Duration of the subscription
|
|
26
|
+
Duration get duration;
|
|
27
|
+
|
|
28
|
+
/// Promotion of the subscription (configure it in the revenue cat offering json)
|
|
29
|
+
String? get promotion;
|
|
30
|
+
|
|
31
|
+
/// Formatted price with duration from the user locale
|
|
32
|
+
String formattedPrice(BuildContext context);
|
|
33
|
+
|
|
34
|
+
/// Duration type of the subscription (week, month, year, ...)
|
|
35
|
+
DurationType get durationType;
|
|
36
|
+
|
|
37
|
+
/// Title of the offer
|
|
38
|
+
String? get title;
|
|
39
|
+
|
|
40
|
+
/// Trial days of the offer
|
|
41
|
+
int? get trialDays;
|
|
42
|
+
|
|
43
|
+
/// Features textes of the offer
|
|
44
|
+
List<String>? get features;
|
|
45
|
+
|
|
46
|
+
/// Price of the subscription in string
|
|
47
|
+
String get priceString;
|
|
48
|
+
|
|
49
|
+
String get currency;
|
|
50
|
+
|
|
51
|
+
/// Shows the price per month (only if the duration is not monthly)
|
|
52
|
+
String pricePerMonth(BuildContext context);
|
|
53
|
+
|
|
54
|
+
/// Shows the price per year (only if the duration is not yearly)
|
|
55
|
+
String? pricePerYear(BuildContext context);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class RevenueCatProduct implements SubscriptionProduct {
|
|
59
|
+
final Offering revenueCatOffer;
|
|
60
|
+
final Package revenueCatPackage;
|
|
61
|
+
|
|
62
|
+
RevenueCatProduct({
|
|
63
|
+
required this.revenueCatOffer,
|
|
64
|
+
required this.revenueCatPackage,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
@override
|
|
68
|
+
String get skuId => revenueCatPackage.identifier;
|
|
69
|
+
|
|
70
|
+
@override
|
|
71
|
+
String get id => revenueCatOffer.identifier;
|
|
72
|
+
|
|
73
|
+
@override
|
|
74
|
+
String get description => revenueCatOffer.serverDescription;
|
|
75
|
+
|
|
76
|
+
@override
|
|
77
|
+
String get label =>
|
|
78
|
+
revenueCatPackage.presentedOfferingContext.offeringIdentifier;
|
|
79
|
+
|
|
80
|
+
@override
|
|
81
|
+
double get price => revenueCatPackage.storeProduct.price;
|
|
82
|
+
|
|
83
|
+
@override
|
|
84
|
+
String get currency => revenueCatPackage.storeProduct.currencyCode;
|
|
85
|
+
|
|
86
|
+
@override
|
|
87
|
+
int? get trialDays {
|
|
88
|
+
final introductory = revenueCatPackage.storeProduct.introductoryPrice;
|
|
89
|
+
if (introductory == null) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (introductory.price == 0) {
|
|
93
|
+
final unit = introductory.periodUnit;
|
|
94
|
+
switch (unit) {
|
|
95
|
+
case PeriodUnit.day:
|
|
96
|
+
return introductory.periodNumberOfUnits;
|
|
97
|
+
case PeriodUnit.week:
|
|
98
|
+
return introductory.periodNumberOfUnits * 7;
|
|
99
|
+
case PeriodUnit.month:
|
|
100
|
+
return introductory.periodNumberOfUnits * 30;
|
|
101
|
+
case PeriodUnit.year:
|
|
102
|
+
return introductory.periodNumberOfUnits * 365;
|
|
103
|
+
default:
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@override
|
|
111
|
+
String? get promotion {
|
|
112
|
+
if (revenueCatOffer.metadata["promotions"] == null) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
final data =
|
|
116
|
+
revenueCatOffer.metadata["promotions"]! as Map<Object?, Object?>;
|
|
117
|
+
final locale = LocaleSettings.currentLocale.languageCode;
|
|
118
|
+
final id = skuId;
|
|
119
|
+
if (data.containsKey(id)) {
|
|
120
|
+
final promotion = data[id]! as Map<Object?, Object?>;
|
|
121
|
+
return promotion[locale]! as String;
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@override
|
|
127
|
+
String? get title {
|
|
128
|
+
return revenueCatPackage.storeProduct.title;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@override
|
|
132
|
+
List<String>? get features {
|
|
133
|
+
final locale = LocaleSettings.currentLocale.languageCode;
|
|
134
|
+
if (revenueCatOffer.metadata[locale] == null) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
final data = revenueCatOffer.metadata[locale]! as Map<Object?, Object?>;
|
|
138
|
+
final featuerObj = data["features"]! as List<Object?>;
|
|
139
|
+
return featuerObj.map((e) => e! as String).toList();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@override
|
|
143
|
+
String get priceString {
|
|
144
|
+
return revenueCatPackage.storeProduct.priceString;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@override
|
|
148
|
+
Duration get duration =>
|
|
149
|
+
switch (revenueCatPackage.storeProduct.subscriptionPeriod) {
|
|
150
|
+
'P1W' => const Duration(days: 7),
|
|
151
|
+
'P1M' => const Duration(days: 30),
|
|
152
|
+
'P3M' => const Duration(days: 90),
|
|
153
|
+
'P6M' => const Duration(days: 180),
|
|
154
|
+
'P1Y' => const Duration(days: 365),
|
|
155
|
+
_ => Duration.zero,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
@override
|
|
159
|
+
DurationType get durationType {
|
|
160
|
+
final durationCpy = duration;
|
|
161
|
+
if (durationCpy.inDays == 7) {
|
|
162
|
+
return DurationType.week;
|
|
163
|
+
} else if (durationCpy.inDays == 30) {
|
|
164
|
+
return DurationType.month;
|
|
165
|
+
} else if (durationCpy.inDays == 90) {
|
|
166
|
+
return DurationType.threeMonth;
|
|
167
|
+
} else if (durationCpy.inDays == 180) {
|
|
168
|
+
return DurationType.sixMonth;
|
|
169
|
+
} else if (durationCpy.inDays == 365) {
|
|
170
|
+
return DurationType.year;
|
|
171
|
+
}
|
|
172
|
+
return DurationType.lifetime;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@override
|
|
176
|
+
String formattedPrice(BuildContext context) {
|
|
177
|
+
final translatedDuration = switch (durationType) {
|
|
178
|
+
DurationType.week => Translations.of(context).premium.duration_weekly,
|
|
179
|
+
DurationType.year => Translations.of(context).premium.duration_annual,
|
|
180
|
+
DurationType.month => Translations.of(context).premium.duration_monthly,
|
|
181
|
+
DurationType.lifetime => Translations.of(
|
|
182
|
+
context,
|
|
183
|
+
).premium.duration_lifetime,
|
|
184
|
+
_ => "",
|
|
185
|
+
};
|
|
186
|
+
return "${revenueCatPackage.storeProduct.priceString} $translatedDuration";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@override
|
|
190
|
+
String pricePerMonth(BuildContext context) {
|
|
191
|
+
final translatedDuration = Translations.of(
|
|
192
|
+
context,
|
|
193
|
+
).premium.duration_monthly;
|
|
194
|
+
if (durationType == DurationType.lifetime) {
|
|
195
|
+
return revenueCatPackage.storeProduct.priceString;
|
|
196
|
+
}
|
|
197
|
+
final pricePerMonth = switch (durationType) {
|
|
198
|
+
DurationType.year => price / 12,
|
|
199
|
+
DurationType.threeMonth => price / 3,
|
|
200
|
+
DurationType.sixMonth => price / 6,
|
|
201
|
+
DurationType.week => (price * 4) / 12,
|
|
202
|
+
_ => 1,
|
|
203
|
+
};
|
|
204
|
+
final pricePerMonthString = pricePerMonth.toStringAsFixed(2);
|
|
205
|
+
final money = revenueCatPackage.storeProduct.currencyCode;
|
|
206
|
+
if (money == "USD") {
|
|
207
|
+
return "\$$pricePerMonthString/$translatedDuration";
|
|
208
|
+
} else if (money == "EUR") {
|
|
209
|
+
return "$pricePerMonthString/$translatedDuration";
|
|
210
|
+
}
|
|
211
|
+
return "$pricePerMonthString $money/$translatedDuration";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@override
|
|
215
|
+
String? pricePerYear(BuildContext context) {
|
|
216
|
+
final translatedDuration = Translations.of(context).premium.duration_annual;
|
|
217
|
+
if (durationType == DurationType.lifetime) {
|
|
218
|
+
return revenueCatPackage.storeProduct.priceString;
|
|
219
|
+
}
|
|
220
|
+
final pricePerMonth = switch (durationType) {
|
|
221
|
+
DurationType.year => price,
|
|
222
|
+
DurationType.threeMonth => price * 4,
|
|
223
|
+
DurationType.sixMonth => price * 2,
|
|
224
|
+
DurationType.week => (price * 4) * 12,
|
|
225
|
+
_ => 1,
|
|
226
|
+
};
|
|
227
|
+
final pricePerMonthString = pricePerMonth.toStringAsFixed(2);
|
|
228
|
+
final money = revenueCatPackage.storeProduct.currencyCode;
|
|
229
|
+
if (money == "USD") {
|
|
230
|
+
return "\$$pricePerMonthString/$translatedDuration";
|
|
231
|
+
} else if (money == "EUR") {
|
|
232
|
+
return "$pricePerMonthString/$translatedDuration";
|
|
233
|
+
}
|
|
234
|
+
return "$pricePerMonthString $money/$translatedDuration";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
enum DurationType { week, month, threeMonth, sixMonth, year, lifetime }
|
|
239
|
+
|
|
240
|
+
@freezed
|
|
241
|
+
sealed class Subscription with _$Subscription {
|
|
242
|
+
const factory Subscription.active({
|
|
243
|
+
SubscriptionProduct? activeOffer,
|
|
244
|
+
List<EntitlementInfo>? entitlements,
|
|
245
|
+
}) = SubscriptionStateData;
|
|
246
|
+
|
|
247
|
+
const factory Subscription.inactive({
|
|
248
|
+
required int hoursBetweenTwoRequests,
|
|
249
|
+
DateTime? lastAskingDate,
|
|
250
|
+
}) = SubscriptionInactiveStateData;
|
|
251
|
+
|
|
252
|
+
const factory Subscription.loading() = SubscriptionStateLoading;
|
|
253
|
+
|
|
254
|
+
const Subscription._();
|
|
255
|
+
|
|
256
|
+
factory Subscription.fromEntity(
|
|
257
|
+
SubscriptionEntity? entity,
|
|
258
|
+
DateTime? lastAskingDate, {
|
|
259
|
+
int hoursBetweenTwoRequests = 24,
|
|
260
|
+
}) {
|
|
261
|
+
if (entity == null ||
|
|
262
|
+
(entity.periodEndDate != null &&
|
|
263
|
+
entity.periodEndDate!.isBefore(DateTime.now()))) {
|
|
264
|
+
return Subscription.inactive(
|
|
265
|
+
hoursBetweenTwoRequests: hoursBetweenTwoRequests,
|
|
266
|
+
lastAskingDate: lastAskingDate,
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
return const Subscription.active();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
bool get canPurchase => switch (this) {
|
|
273
|
+
SubscriptionStateData() => false,
|
|
274
|
+
SubscriptionInactiveStateData() => true,
|
|
275
|
+
SubscriptionStateLoading() => false,
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
bool get isActive => switch (this) {
|
|
279
|
+
SubscriptionStateData() => true,
|
|
280
|
+
SubscriptionInactiveStateData() => false,
|
|
281
|
+
SubscriptionStateLoading() => false,
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
bool get isInTrial => switch (this) {
|
|
285
|
+
SubscriptionStateData(:final entitlements) =>
|
|
286
|
+
entitlements?.firstOrNull?.periodType == PeriodType.trial,
|
|
287
|
+
SubscriptionInactiveStateData() => false,
|
|
288
|
+
SubscriptionStateLoading() => false,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
bool get hasRenewal => switch (this) {
|
|
292
|
+
SubscriptionStateData(:final entitlements) =>
|
|
293
|
+
entitlements?.firstOrNull?.willRenew == true,
|
|
294
|
+
SubscriptionInactiveStateData() => false,
|
|
295
|
+
SubscriptionStateLoading() => false,
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
bool get isLifetime => switch (this) {
|
|
299
|
+
SubscriptionStateData(:final activeOffer) =>
|
|
300
|
+
activeOffer?.durationType == DurationType.lifetime,
|
|
301
|
+
SubscriptionInactiveStateData() => false,
|
|
302
|
+
SubscriptionStateLoading() => false,
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
bool get shouldAskForSubscription {
|
|
306
|
+
final now = DateTime.now();
|
|
307
|
+
final (lastAskingDate, hoursBetweenTwoRequests) = switch (this) {
|
|
308
|
+
SubscriptionStateData() => (null, null),
|
|
309
|
+
SubscriptionInactiveStateData(
|
|
310
|
+
:final lastAskingDate,
|
|
311
|
+
:final hoursBetweenTwoRequests,
|
|
312
|
+
) =>
|
|
313
|
+
(lastAskingDate, hoursBetweenTwoRequests),
|
|
314
|
+
SubscriptionStateLoading() => (null, null),
|
|
315
|
+
};
|
|
316
|
+
if (lastAskingDate == null) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
final diff = now.difference(lastAskingDate);
|
|
320
|
+
return diff.inHours >= hoursBetweenTwoRequests!;
|
|
321
|
+
}
|
|
322
|
+
}
|
package/lib/scaffold/features/revenuecat/lib/core/home_widgets/home_widget_background_task.dart
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
2
|
+
import 'package:logger/logger.dart';
|
|
3
|
+
import 'package:kasy_kit/core/home_widgets/home_widget_mywidget_service.dart';
|
|
4
|
+
import 'package:kasy_kit/core/shared_preferences/shared_preferences.dart';
|
|
5
|
+
import 'package:kasy_kit/core/states/user_state_notifier.dart';
|
|
6
|
+
import 'package:kasy_kit/features/authentication/api/authentication_api.dart';
|
|
7
|
+
import 'package:kasy_kit/features/subscription/repositories/subscription_repository.dart';
|
|
8
|
+
|
|
9
|
+
/// Generated by Kasy CLI
|
|
10
|
+
/// ----
|
|
11
|
+
/// Background task callback for workmanager
|
|
12
|
+
/// This allows updating home widgets even when the app is in the background
|
|
13
|
+
@pragma('vm:entry-point')
|
|
14
|
+
Future<void> homeWidgetCallbackDispatcher() async {
|
|
15
|
+
try {
|
|
16
|
+
Logger().i('🔄 Home Widget background task triggered');
|
|
17
|
+
final globalContainer = ProviderContainer();
|
|
18
|
+
final sharedPreferences = globalContainer.read(sharedPreferencesProvider);
|
|
19
|
+
await sharedPreferences.init();
|
|
20
|
+
await globalContainer.read(authenticationApiProvider).init();
|
|
21
|
+
await globalContainer.read(subscriptionRepositoryProvider).init();
|
|
22
|
+
await globalContainer.read(userStateNotifierProvider.notifier).init();
|
|
23
|
+
|
|
24
|
+
/// If you want to restric the background task to only run when the user is subscribed,
|
|
25
|
+
/// you can use the subscription variable here.
|
|
26
|
+
// final subscription = globalContainer
|
|
27
|
+
// .read(userStateNotifierProvider)
|
|
28
|
+
// .subscription;
|
|
29
|
+
|
|
30
|
+
final myWidgetWidget = globalContainer.read(
|
|
31
|
+
myWidgetHomeWidgetProvider.notifier,
|
|
32
|
+
);
|
|
33
|
+
await myWidgetWidget.update();
|
|
34
|
+
|
|
35
|
+
globalContainer.dispose();
|
|
36
|
+
return;
|
|
37
|
+
} catch (e) {
|
|
38
|
+
Logger().e('Error in background task: $e');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import 'package:flutter/foundation.dart';
|
|
2
|
+
import 'package:logger/logger.dart';
|
|
3
|
+
import 'package:kasy_kit/core/config/features.dart';
|
|
4
|
+
import 'package:kasy_kit/core/data/models/subscription.dart';
|
|
5
|
+
import 'package:kasy_kit/core/data/models/user.dart';
|
|
6
|
+
import 'package:kasy_kit/core/data/repositories/user_repository.dart';
|
|
7
|
+
import 'package:kasy_kit/core/initializer/onstart_service.dart';
|
|
8
|
+
import 'package:kasy_kit/core/states/models/user_state.dart';
|
|
9
|
+
import 'package:kasy_kit/environnements.dart';
|
|
10
|
+
import 'package:kasy_kit/features/authentication/repositories/authentication_repository.dart';
|
|
11
|
+
import 'package:kasy_kit/features/notifications/providers/models/device.dart';
|
|
12
|
+
import 'package:kasy_kit/features/notifications/repositories/device_repository.dart';
|
|
13
|
+
import 'package:purchases_flutter/models/entitlement_info_wrapper.dart';
|
|
14
|
+
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
15
|
+
|
|
16
|
+
part 'user_state_notifier.g.dart';
|
|
17
|
+
|
|
18
|
+
/// Use this provider to access the user state (legacy name)
|
|
19
|
+
final userStateNotifierProvider = userStateProvider;
|
|
20
|
+
|
|
21
|
+
/// This enum is used to parameter the list of the authentication mode
|
|
22
|
+
///
|
|
23
|
+
/// Most of apps try to not force user to create an account to access the app
|
|
24
|
+
/// But you may want to force the user to be authenticated to access the app
|
|
25
|
+
enum AuthenticationMode {
|
|
26
|
+
/// By default the user will be authenticated anonymously
|
|
27
|
+
/// This means that the user can access your app without login
|
|
28
|
+
/// He will be able to link his account later to an email or social login
|
|
29
|
+
anonymous,
|
|
30
|
+
|
|
31
|
+
/// The user requires to be authenticated to access the app
|
|
32
|
+
/// By default the user won't have any identity
|
|
33
|
+
authRequired,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// This class is responsible for managing the state of the user over the app.
|
|
37
|
+
/// It will be used to know if the user is connected or not and to get the user
|
|
38
|
+
@Riverpod(keepAlive: true)
|
|
39
|
+
class UserStateNotifier extends _$UserStateNotifier implements OnStartService {
|
|
40
|
+
Logger get _logger => Logger();
|
|
41
|
+
|
|
42
|
+
AuthenticationRepository get _authenticationRepository =>
|
|
43
|
+
ref.read(authRepositoryProvider);
|
|
44
|
+
|
|
45
|
+
DeviceRepository get _deviceRepository => ref.read(deviceRepositoryProvider);
|
|
46
|
+
|
|
47
|
+
UserRepository get _userRepository => ref.read(userRepositoryProvider);
|
|
48
|
+
|
|
49
|
+
/// The authentication mode of the app.
|
|
50
|
+
/// On web (when withWeb is true), always require explicit auth —
|
|
51
|
+
/// anonymous accounts are not used on web.
|
|
52
|
+
/// see [AuthenticationMode]
|
|
53
|
+
AuthenticationMode get mode {
|
|
54
|
+
if (kIsWeb && withWeb) return AuthenticationMode.authRequired;
|
|
55
|
+
return ref.read(environmentProvider).authenticationMode;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@override
|
|
59
|
+
UserState build() {
|
|
60
|
+
return const UserState(user: User.loading());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@override
|
|
64
|
+
Future<void> init() async {
|
|
65
|
+
try {
|
|
66
|
+
await _loadState();
|
|
67
|
+
} catch (e, stacktrace) {
|
|
68
|
+
_logger.e(e, stackTrace: stacktrace);
|
|
69
|
+
if(kDebugMode) {
|
|
70
|
+
// we automatically logout the user if an error occurs in debug mode
|
|
71
|
+
// customize this behavior to fit your needs
|
|
72
|
+
_authenticationRepository.logout();
|
|
73
|
+
}
|
|
74
|
+
rethrow;
|
|
75
|
+
}
|
|
76
|
+
assert(state.user is! LoadingUserData, 'UserStateNotifier is not ready');
|
|
77
|
+
await _initDeviceRegistration();
|
|
78
|
+
_deviceRepository.onTokenUpdate(_onUpdateToken);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// This function is called when the user click on the signin button
|
|
82
|
+
/// It will load the user state and register the device to the notification service
|
|
83
|
+
/// It will also load the subscription state
|
|
84
|
+
Future<void> onSignin() async {
|
|
85
|
+
state = const UserState(
|
|
86
|
+
user: User.loading(),
|
|
87
|
+
);
|
|
88
|
+
await _loadState();
|
|
89
|
+
await _initDeviceRegistration();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// Set the user as onboarded in the database
|
|
93
|
+
/// This function is called when the user has completed the onboarding
|
|
94
|
+
Future<void> onOnboarded() async {
|
|
95
|
+
if (state.user.idOrNull == null) {
|
|
96
|
+
// Guest with no account: persist onboarding in local state only.
|
|
97
|
+
// No Firestore document exists yet — no write needed.
|
|
98
|
+
state = state.copyWith(user: const User.anonymous(onboarded: true));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
final newUser = await _userRepository.setOnboarded(state.user);
|
|
102
|
+
state = state.copyWith(user: newUser);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// This function is called when the user click on the logout button
|
|
106
|
+
/// It will unregister the device from the notification service
|
|
107
|
+
/// and logout the user
|
|
108
|
+
Future<void> onLogout() async {
|
|
109
|
+
final userId = state.user.idOrThrow;
|
|
110
|
+
_deviceRepository.removeTokenUpdateListener();
|
|
111
|
+
await _deviceRepository.unregister(userId);
|
|
112
|
+
await _authenticationRepository.logout();
|
|
113
|
+
state = const UserState(
|
|
114
|
+
user: User.anonymous(),
|
|
115
|
+
);
|
|
116
|
+
if (mode == AuthenticationMode.anonymous) {
|
|
117
|
+
await _loadAnonymousState();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/// Refresh the user
|
|
122
|
+
Future<void> onUpdateAvatar() async {
|
|
123
|
+
await refresh();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// Refresh the user
|
|
127
|
+
Future<void> refresh() async {
|
|
128
|
+
final id = state.user.idOrNull;
|
|
129
|
+
if (id == null) return; // Guest: no Firestore document, nothing to refresh
|
|
130
|
+
final user = await _userRepository.get(id);
|
|
131
|
+
state = state.copyWith(user: user ?? const User.anonymous());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// This function is called after a user successfuly purchased a subscription
|
|
135
|
+
/// It will refresh the subscription state without waiting for the webhook
|
|
136
|
+
/// (which can take some time and could show a wrong state to the user)
|
|
137
|
+
/// On next app start, the subscription will be refreshed from the webhook result
|
|
138
|
+
Future<void> refreshSubscription({
|
|
139
|
+
SubscriptionProduct? product,
|
|
140
|
+
List<EntitlementInfo>? entitlements,
|
|
141
|
+
}) async {
|
|
142
|
+
if (product != null) {
|
|
143
|
+
final newUser = switch (state.user) {
|
|
144
|
+
final AuthenticatedUserData user => user.copyWith(
|
|
145
|
+
subscription: Subscription.active(
|
|
146
|
+
activeOffer: product,
|
|
147
|
+
entitlements: entitlements,
|
|
148
|
+
),
|
|
149
|
+
),
|
|
150
|
+
final AnonymousUserData user => user.copyWith(
|
|
151
|
+
subscription: Subscription.active(
|
|
152
|
+
activeOffer: product,
|
|
153
|
+
entitlements: entitlements,
|
|
154
|
+
),
|
|
155
|
+
),
|
|
156
|
+
final LoadingUserData _ => throw 'User is not connected',
|
|
157
|
+
};
|
|
158
|
+
state = state.copyWith(user: newUser);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
await Future.delayed(const Duration(seconds: 2));
|
|
162
|
+
await _loadState();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// Apple store and Google play stores requires you to be able to delete a user account on demand
|
|
166
|
+
/// Here is the function to do it.
|
|
167
|
+
/// It will delete the user account and logout the user
|
|
168
|
+
Future<void> deleteAccount() async {
|
|
169
|
+
try {
|
|
170
|
+
final userId = state.user.idOrThrow;
|
|
171
|
+
_deviceRepository.removeTokenUpdateListener();
|
|
172
|
+
await _deviceRepository.unregister(userId);
|
|
173
|
+
await _userRepository.delete();
|
|
174
|
+
await _authenticationRepository.logout();
|
|
175
|
+
} catch (e) {
|
|
176
|
+
_logger.e(e);
|
|
177
|
+
}
|
|
178
|
+
state = const UserState(
|
|
179
|
+
user: User.anonymous(),
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
if (mode == AuthenticationMode.anonymous) {
|
|
183
|
+
await _loadAnonymousState();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// -------------------------------
|
|
188
|
+
// PRIVATES
|
|
189
|
+
// -------------------------------
|
|
190
|
+
|
|
191
|
+
/// load anonymous state for the user
|
|
192
|
+
Future<void> _loadAnonymousState() async {
|
|
193
|
+
await _authenticationRepository.signupAnonymously();
|
|
194
|
+
await Future.delayed(const Duration(seconds: 1));
|
|
195
|
+
final credentials = await _authenticationRepository.get();
|
|
196
|
+
var user = await _userRepository.get(credentials!.id);
|
|
197
|
+
// We retry to get the user 3 times (sometimes the user creation trigger is not fast enough)
|
|
198
|
+
var retry = 0;
|
|
199
|
+
while (user == null && retry < 3) {
|
|
200
|
+
await Future.delayed(const Duration(seconds: 1));
|
|
201
|
+
user = await _userRepository.get(credentials.id);
|
|
202
|
+
retry++;
|
|
203
|
+
}
|
|
204
|
+
if (user == null) {
|
|
205
|
+
// Backend not deployed yet: the Cloud Function onUserRegistration has not
|
|
206
|
+
// created the Firestore document. Log the issue for the developer and fall
|
|
207
|
+
// back to a local anonymous state so the app still opens.
|
|
208
|
+
_logger.e(
|
|
209
|
+
'⚠️ User profile not found in database.\n'
|
|
210
|
+
' The backend may not be deployed yet.\n'
|
|
211
|
+
' Run: kasy deploy\n'
|
|
212
|
+
' Then restart the app.',
|
|
213
|
+
);
|
|
214
|
+
state = state.copyWith(user: User.anonymous(id: credentials.id));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
state = state.copyWith(user: user);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/// Load the state of the user
|
|
221
|
+
Future<void> _loadState() async {
|
|
222
|
+
final credentials = await _authenticationRepository.get();
|
|
223
|
+
|
|
224
|
+
if (credentials == null && mode == AuthenticationMode.anonymous) {
|
|
225
|
+
_logger.i('Anonymous user mode activated, signup anonymously');
|
|
226
|
+
await _loadAnonymousState();
|
|
227
|
+
} else if (credentials == null && mode == AuthenticationMode.authRequired) {
|
|
228
|
+
_logger.i('Authentification required, user is not connected');
|
|
229
|
+
state = state.copyWith(user: const User.anonymous());
|
|
230
|
+
} else if (credentials != null) {
|
|
231
|
+
_logger.i('User is connected with id ${credentials.id}');
|
|
232
|
+
var user = await _userRepository.get(credentials.id);
|
|
233
|
+
// Retry a few times: the Cloud Function onUserRegistration may not have
|
|
234
|
+
// finished creating the Firestore document yet (race condition on first login).
|
|
235
|
+
var retry = 0;
|
|
236
|
+
while (user == null && retry < 3) {
|
|
237
|
+
await Future.delayed(const Duration(seconds: 1));
|
|
238
|
+
user = await _userRepository.get(credentials.id);
|
|
239
|
+
retry++;
|
|
240
|
+
}
|
|
241
|
+
if (user == null) {
|
|
242
|
+
// User document not found after login. Possible causes:
|
|
243
|
+
// - Firebase: onUserRegistration Cloud Function not deployed or failed
|
|
244
|
+
// - Supabase: handle_new_user trigger not run yet (race) or failed
|
|
245
|
+
// - User was deleted but session was still cached
|
|
246
|
+
// Logout to clear invalid session, then create new anonymous user if applicable.
|
|
247
|
+
_logger.e(
|
|
248
|
+
'⚠️ User profile not found in database after sign-in.\n'
|
|
249
|
+
' Logging out and creating new anonymous user.',
|
|
250
|
+
);
|
|
251
|
+
await _authenticationRepository.logout();
|
|
252
|
+
state = state.copyWith(user: const User.anonymous());
|
|
253
|
+
if (mode == AuthenticationMode.anonymous) {
|
|
254
|
+
await _loadAnonymousState();
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// If the Firestore document is anonymous (no email) but Firebase Auth
|
|
259
|
+
// already has an email (happens after linkWithProvider — Google, email, etc.),
|
|
260
|
+
// sync the email and name so the user is properly recognised as authenticated.
|
|
261
|
+
if (user is AnonymousUserData) {
|
|
262
|
+
final authEmail = await _authenticationRepository.getCurrentUserEmail();
|
|
263
|
+
if (authEmail != null && authEmail.isNotEmpty) {
|
|
264
|
+
final authName = await _authenticationRepository.getCurrentUserDisplayName();
|
|
265
|
+
await _userRepository.updateEmailAndName(
|
|
266
|
+
userId: credentials.id,
|
|
267
|
+
email: authEmail,
|
|
268
|
+
name: authName,
|
|
269
|
+
);
|
|
270
|
+
final syncedUser = await _userRepository.get(credentials.id);
|
|
271
|
+
state = state.copyWith(user: syncedUser ?? user);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
state = state.copyWith(user: user);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/// If user has an ID we will register his device to send notifications from
|
|
280
|
+
/// the server to the device (only if user has accepted them)
|
|
281
|
+
/// Maybe save your device in UserState if you need it in your app
|
|
282
|
+
Future<void> _initDeviceRegistration() async {
|
|
283
|
+
if (kIsWeb) return;
|
|
284
|
+
final userId = state.user.idOrNull;
|
|
285
|
+
if (userId == null) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
final _ = await _deviceRepository.register(userId);
|
|
290
|
+
} catch (err, stacktrace) {
|
|
291
|
+
_logger.e(err, stackTrace: stacktrace);
|
|
292
|
+
_logger.e('''
|
|
293
|
+
❌ Your device seems not to be registered.
|
|
294
|
+
Check that you correctly setup a device registration API
|
|
295
|
+
see: `lib/features/notifications/api/device_api.dart`
|
|
296
|
+
''');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/// This function is called when the device token is updated
|
|
301
|
+
/// It will update the token in the database
|
|
302
|
+
Future<void> _onUpdateToken(Device device) async {
|
|
303
|
+
await _deviceRepository.updateToken(device.token);
|
|
304
|
+
}
|
|
305
|
+
}
|