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