kasy-cli 1.12.1 → 1.14.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/bin/kasy.js +143 -7
- package/lib/commands/add.js +2 -2
- package/lib/commands/codemagic.js +11 -4
- package/lib/commands/deploy.js +3 -3
- package/lib/commands/favicon.js +115 -0
- package/lib/commands/icon.js +143 -0
- package/lib/commands/ios.js +20 -5
- package/lib/commands/new.js +8 -20
- package/lib/commands/remove.js +1 -1
- package/lib/commands/reset.js +287 -0
- package/lib/commands/run.js +24 -17
- package/lib/commands/splash.js +219 -0
- package/lib/commands/update.js +1 -1
- package/lib/scaffold/CHANGELOG.json +9 -0
- package/lib/scaffold/backends/api/patch/README.md +1 -1
- package/lib/scaffold/backends/api/patch/android/app/src/main/AndroidManifest.xml +1 -1
- package/lib/scaffold/backends/api/patch/lib/features/notifications/api/device_api.dart +53 -0
- package/lib/scaffold/backends/api/patch/lib/main.dart +29 -10
- package/lib/scaffold/backends/api/pubspec.yaml.tpl +11 -1
- package/lib/scaffold/backends/firebase/tokens.js +2 -2
- package/lib/scaffold/backends/supabase/edge-functions/send-push-notification/index.ts +8 -2
- package/lib/scaffold/backends/supabase/migrations/20240101000011_dedupe_device_tokens.sql +34 -0
- package/lib/scaffold/backends/supabase/patch/README.md +1 -1
- package/lib/scaffold/backends/supabase/patch/android/app/src/main/AndroidManifest.xml +1 -1
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/device_api.dart +43 -0
- package/lib/scaffold/backends/supabase/patch/lib/main.dart +29 -10
- package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +11 -1
- package/lib/scaffold/features/README.md +15 -139
- package/lib/scaffold/shared/generator-utils.js +16 -15
- package/lib/utils/apple-release.js +85 -16
- package/lib/utils/checks.js +4 -105
- package/lib/utils/flutter-run.js +173 -0
- package/lib/utils/i18n.js +413 -0
- package/lib/utils/mobile-identity.js +35 -0
- package/lib/utils/ui.js +114 -0
- package/package.json +2 -3
- package/templates/firebase/README.en.md +1 -1
- package/templates/firebase/README.es.md +1 -1
- package/templates/firebase/README.md +1 -1
- package/templates/firebase/android/app/build.gradle.kts +10 -1
- package/templates/firebase/android/app/src/main/AndroidManifest.xml +1 -1
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MainActivity.kt +25 -1
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MyWidget.kt +160 -11
- package/templates/firebase/android/app/src/main/res/drawable/widget_add_button.xml +15 -0
- package/templates/firebase/android/app/src/main/res/drawable/widget_gradient_bg.xml +9 -0
- package/templates/firebase/android/app/src/main/res/drawable/widget_gradient_inner.xml +12 -0
- package/templates/firebase/android/app/src/main/res/drawable/widget_plan_pill_bg.xml +5 -0
- package/templates/firebase/android/app/src/main/res/drawable/widget_preview_image.xml +17 -0
- package/templates/firebase/android/app/src/main/res/drawable/widget_pro_pill_bg.xml +5 -0
- package/templates/firebase/android/app/src/main/res/drawable-hdpi/android12splash.png +0 -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/android12splash.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-night/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night/launch_background.xml +9 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-hdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-hdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-mdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-mdpi/splash.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-night-v21/launch_background.xml +9 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-xxxhdpi/splash.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-xhdpi/android12splash.png +0 -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/android12splash.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/android12splash.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/layout/widget_loading.xml +8 -0
- package/templates/firebase/android/app/src/main/res/layout/widget_preview.xml +46 -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-night-v31/styles.xml +2 -1
- package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -0
- package/templates/firebase/android/app/src/main/res/xml/mywidget_info.xml +9 -3
- package/templates/firebase/assets/images/favicon.png +0 -0
- package/templates/firebase/assets/images/icon.png +0 -0
- package/templates/firebase/assets/images/splash_logo_dark.png +0 -0
- package/templates/firebase/assets/images/splash_logo_light.png +0 -0
- package/templates/firebase/firestore.indexes.json +10 -0
- package/templates/firebase/functions/src/core/data/entities/user_device_entity.ts +3 -0
- package/templates/firebase/functions/src/core/data/repositories/user_device_repository.ts +17 -1
- package/templates/firebase/functions/src/index.ts +1 -0
- package/templates/firebase/functions/src/notifications/device_triggers.ts +58 -0
- package/templates/firebase/ios/HomeWidgetExtension/MyWidget.swift +116 -33
- package/templates/firebase/ios/Runner/AppDelegate.swift +17 -1
- 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 +9 -8
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +33 -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/LaunchImageDark.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png +0 -0
- package/templates/firebase/ios/Runner/Base.lproj/LaunchScreen.storyboard +1 -1
- package/templates/firebase/ios/Runner/Info.plist +2 -2
- package/templates/firebase/ios/Runner/es.lproj/InfoPlist.strings +1 -1
- package/templates/firebase/ios/Runner/pt-BR.lproj/InfoPlist.strings +1 -1
- package/templates/firebase/ios/Runner/pt.lproj/InfoPlist.strings +1 -1
- package/templates/firebase/lib/components/kasy_button.dart +8 -0
- package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +18 -0
- package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +67 -19
- package/templates/firebase/lib/core/home_widgets/home_widget_service.dart +22 -8
- package/templates/firebase/lib/core/shared_preferences/shared_preferences.dart +16 -4
- package/templates/firebase/lib/core/states/components/maybeshow_component.dart +4 -8
- package/templates/firebase/lib/core/states/user_state_notifier.dart +13 -1
- package/templates/firebase/lib/core/theme/providers/theme_provider.dart +48 -24
- package/templates/firebase/lib/features/home/home_page.dart +0 -6
- package/templates/firebase/lib/features/notifications/api/device_api.dart +57 -0
- package/templates/firebase/lib/features/notifications/providers/models/notification.dart +11 -1
- package/templates/firebase/lib/features/notifications/repositories/device_repository.dart +9 -0
- package/templates/firebase/lib/features/notifications/repositories/notifications_repository.dart +1 -4
- package/templates/firebase/lib/features/notifications/shared/att_permission.dart +28 -8
- package/templates/firebase/lib/features/notifications/ui/notifications_page.dart +16 -1
- package/templates/firebase/lib/features/notifications/ui/widgets/empty_notifications.dart +44 -11
- package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +4 -0
- package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +1 -0
- package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +13 -0
- package/templates/firebase/lib/features/settings/settings_page.dart +158 -18
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +31 -29
- package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +21 -5
- package/templates/firebase/lib/i18n/en.i18n.json +10 -3
- package/templates/firebase/lib/i18n/es.i18n.json +10 -3
- package/templates/firebase/lib/i18n/pt.i18n.json +10 -3
- package/templates/firebase/lib/main.dart +29 -10
- package/templates/firebase/pubspec.yaml +10 -6
- package/templates/firebase/test/core/data/repositories/user_repository_test.dart +1 -1
- package/templates/firebase/test/features/notifications/data/device_api_fake.dart +9 -0
- package/templates/firebase/web/favicon.png +0 -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 +50 -39
- package/templates/firebase/web/manifest.json +3 -3
- 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
- package/lib/scaffold/features/analytics/lib/core/data/api/analytics_api.dart +0 -124
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/BUG.es.md +0 -35
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/BUG.md +0 -35
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/BUG.pt.md +0 -35
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/feature_request.es.md +0 -12
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/feature_request.md +0 -12
- package/lib/scaffold/features/ci/.github/ISSUE_TEMPLATE/feature_request.pt.md +0 -12
- package/lib/scaffold/features/ci/.github/PULL_REQUEST_TEMPLATE.es.md +0 -17
- package/lib/scaffold/features/ci/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- package/lib/scaffold/features/ci/.github/PULL_REQUEST_TEMPLATE.pt.md +0 -17
- package/lib/scaffold/features/ci/.github/dependabot.yml +0 -16
- package/lib/scaffold/features/ci/.github/workflows/app.yml +0 -20
- package/lib/scaffold/features/ci/.gitlab/templates/deploy.yaml +0 -14
- package/lib/scaffold/features/ci/.gitlab/templates/dropbox.yaml +0 -19
- package/lib/scaffold/features/ci/.gitlab/templates/flutter.yaml +0 -163
- package/lib/scaffold/features/ci/.gitlab/templates/mailgun.yaml +0 -28
- package/lib/scaffold/features/ci/.gitlab-ci.yml +0 -37
- package/lib/scaffold/features/ci/codemagic.yaml +0 -157
- package/lib/scaffold/features/facebook/lib/core/data/api/tracking_api.dart +0 -111
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/entities/feature_request_entity.dart +0 -27
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/entities/feature_vote_entity.dart +0 -27
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/feature_request_api.dart +0 -50
- package/lib/scaffold/features/feedback/lib/features/feedbacks/api/feature_vote_api.dart +0 -79
- package/lib/scaffold/features/feedback/lib/features/feedbacks/models/feature_requests.dart +0 -48
- package/lib/scaffold/features/feedback/lib/features/feedbacks/models/feedback_state.dart +0 -42
- package/lib/scaffold/features/feedback/lib/features/feedbacks/providers/feedback_page_notifier.dart +0 -147
- package/lib/scaffold/features/feedback/lib/features/feedbacks/repositories/feature_request_repository.dart +0 -95
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/component/add_feature_form.dart +0 -199
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/feedback_page.dart +0 -175
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/widgets/add_feature_button.dart +0 -76
- package/lib/scaffold/features/feedback/lib/features/feedbacks/ui/widgets/feature_card.dart +0 -279
- package/lib/scaffold/features/ios-release/.kasy/apple.env.example +0 -8
- package/lib/scaffold/features/ios-release/.kasy/codemagic.env.example +0 -7
- package/lib/scaffold/features/ios-release/docs/codemagic-release.en.md +0 -50
- package/lib/scaffold/features/ios-release/docs/codemagic-release.es.md +0 -50
- package/lib/scaffold/features/ios-release/docs/codemagic-release.pt.md +0 -50
- package/lib/scaffold/features/ios-release/docs/ios-release.en.md +0 -41
- package/lib/scaffold/features/ios-release/docs/ios-release.es.md +0 -41
- package/lib/scaffold/features/ios-release/docs/ios-release.pt.md +0 -41
- package/lib/scaffold/features/ios-release/scripts/bump-ios-version.js +0 -38
- package/lib/scaffold/features/ios-release/scripts/release-ios.sh +0 -137
- package/lib/scaffold/features/llm_chat/lib/features/llm_chat/llm_chat_page.dart +0 -301
- package/lib/scaffold/features/local_notifications/lib/features/local_reminder/providers/reminder_notifier.dart +0 -81
- package/lib/scaffold/features/local_notifications/lib/features/local_reminder/repositories/reminder_preferences.dart +0 -76
- package/lib/scaffold/features/local_notifications/lib/features/local_reminder/ui/reminder_page.dart +0 -282
- package/lib/scaffold/features/onboarding/lib/features/onboarding/api/entities/user_info_entity.dart +0 -24
- package/lib/scaffold/features/onboarding/lib/features/onboarding/api/user_infos_api.dart +0 -71
- package/lib/scaffold/features/onboarding/lib/features/onboarding/models/user_info.dart +0 -92
- package/lib/scaffold/features/onboarding/lib/features/onboarding/providers/onboarding_model.dart +0 -15
- package/lib/scaffold/features/onboarding/lib/features/onboarding/providers/onboarding_provider.dart +0 -78
- package/lib/scaffold/features/onboarding/lib/features/onboarding/repositories/user_infos_repository.dart +0 -29
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/animations/page_transitions.dart +0 -30
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_att_setup.dart +0 -66
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_features.dart +0 -72
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_loader.dart +0 -92
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +0 -73
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/components/onboarding_questions.dart +0 -89
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/onboarding_page.dart +0 -94
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_background.dart +0 -80
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_feature.dart +0 -139
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +0 -110
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_progress.dart +0 -84
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +0 -173
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_reassurance.dart +0 -45
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +0 -77
- package/lib/scaffold/features/onboarding/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +0 -392
- package/lib/scaffold/features/revenuecat/lib/core/data/api/tracking_api.dart +0 -116
- package/lib/scaffold/features/revenuecat/lib/core/data/models/subscription.dart +0 -322
- package/lib/scaffold/features/revenuecat/lib/core/home_widgets/home_widget_background_task.dart +0 -41
- package/lib/scaffold/features/revenuecat/lib/core/states/user_state_notifier.dart +0 -305
- package/templates/firebase/assets/images/app_icon.png +0 -0
- package/templates/firebase/assets/images/onboarding/img1.jpg +0 -0
- package/templates/firebase/assets/images/onboarding/onboarding.png +0 -0
- package/templates/firebase/assets/images/splashscreen.png +0 -0
- package/templates/firebase/lib/core/states/components/maybe_ask_biometric_setup.dart +0 -88
- package/templates/firebase/lib/features/notifications/shared/notification_permission_bottom_sheet.dart +0 -144
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Publish to iOS (App Store)
|
|
2
|
-
|
|
3
|
-
## Prerequisites
|
|
4
|
-
|
|
5
|
-
- Paid [Apple Developer](https://developer.apple.com) account
|
|
6
|
-
- App created in [App Store Connect](https://appstoreconnect.apple.com) with the same **Bundle ID** as your project
|
|
7
|
-
- Mac with Xcode and Flutter installed
|
|
8
|
-
|
|
9
|
-
## One-time setup
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
kasy ios configure
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Opens Apple links, collects the API key (`.p8`), and writes `.kasy/apple.env` (gitignored).
|
|
16
|
-
|
|
17
|
-
## Ship a new build
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
kasy ios release
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Bumps the build number in `pubspec.yaml`, builds the IPA, and uploads to App Store Connect (no Transporter).
|
|
24
|
-
|
|
25
|
-
Shortcut: `make release-ios`
|
|
26
|
-
|
|
27
|
-
### Options
|
|
28
|
-
|
|
29
|
-
- `kasy ios build` — IPA only, no upload
|
|
30
|
-
- `kasy ios release --no-bump` — skip build number bump
|
|
31
|
-
- `kasy ios release --version-name 1.0.1` — change marketing version
|
|
32
|
-
|
|
33
|
-
## No Mac?
|
|
34
|
-
|
|
35
|
-
Use cloud builds: [codemagic-release.md](./codemagic-release.md) and `kasy codemagic configure` / `kasy codemagic release`.
|
|
36
|
-
|
|
37
|
-
## Check environment
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
kasy doctor
|
|
41
|
-
```
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Publicar en iOS (App Store)
|
|
2
|
-
|
|
3
|
-
## Requisitos
|
|
4
|
-
|
|
5
|
-
- Cuenta de pago [Apple Developer](https://developer.apple.com)
|
|
6
|
-
- App creada en [App Store Connect](https://appstoreconnect.apple.com) con el mismo **Bundle ID** del proyecto
|
|
7
|
-
- Mac con Xcode y Flutter instalados
|
|
8
|
-
|
|
9
|
-
## Configuración única
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
kasy ios configure
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Abre los enlaces de Apple, pide la clave API (`.p8`) y guarda `.kasy/apple.env` (no se sube a Git).
|
|
16
|
-
|
|
17
|
-
## Enviar nueva versión
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
kasy ios release
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Incrementa el build en `pubspec.yaml`, genera el IPA y lo sube a App Store Connect (sin Transporter).
|
|
24
|
-
|
|
25
|
-
Atajo: `make release-ios`
|
|
26
|
-
|
|
27
|
-
### Opciones
|
|
28
|
-
|
|
29
|
-
- `kasy ios build` — solo IPA, sin subir
|
|
30
|
-
- `kasy ios release --no-bump` — no incrementar build
|
|
31
|
-
- `kasy ios release --version-name 1.0.1` — cambiar versión visible
|
|
32
|
-
|
|
33
|
-
## ¿Sin Mac?
|
|
34
|
-
|
|
35
|
-
Build en la nube: [codemagic-release.md](./codemagic-release.md) y `kasy codemagic configure` / `kasy codemagic release`.
|
|
36
|
-
|
|
37
|
-
## Verificar entorno
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
kasy doctor
|
|
41
|
-
```
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Publicar no iOS (App Store)
|
|
2
|
-
|
|
3
|
-
## Pré-requisitos
|
|
4
|
-
|
|
5
|
-
- Conta [Apple Developer](https://developer.apple.com) (paga)
|
|
6
|
-
- App criado no [App Store Connect](https://appstoreconnect.apple.com) com o mesmo **Bundle ID** do projeto
|
|
7
|
-
- Mac com Xcode e Flutter instalados
|
|
8
|
-
|
|
9
|
-
## Configuração única
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
kasy ios configure
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
O comando abre os links da Apple, pede a chave API (`.p8`) e grava `.kasy/apple.env` (não vai para o Git).
|
|
16
|
-
|
|
17
|
-
## Enviar nova versão
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
kasy ios release
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Isso incrementa o build no `pubspec.yaml`, gera o IPA e envia para a App Store Connect (sem Transporter).
|
|
24
|
-
|
|
25
|
-
Atalho: `make release-ios`
|
|
26
|
-
|
|
27
|
-
### Opções
|
|
28
|
-
|
|
29
|
-
- `kasy ios build` — só gera o IPA, sem enviar
|
|
30
|
-
- `kasy ios release --no-bump` — não incrementa o build
|
|
31
|
-
- `kasy ios release --version-name 1.0.1` — altera a versão visível
|
|
32
|
-
|
|
33
|
-
## Sem Mac?
|
|
34
|
-
|
|
35
|
-
Use build na nuvem: [codemagic-release.md](./codemagic-release.md) e `kasy codemagic configure` / `kasy codemagic release`.
|
|
36
|
-
|
|
37
|
-
## Verificar ambiente
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
kasy doctor
|
|
41
|
-
```
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const fs = require('node:fs');
|
|
5
|
-
const path = require('node:path');
|
|
6
|
-
|
|
7
|
-
const root = path.resolve(__dirname, '..');
|
|
8
|
-
const pubspecPath = path.join(root, 'pubspec.yaml');
|
|
9
|
-
|
|
10
|
-
function parseArgs() {
|
|
11
|
-
const args = process.argv.slice(2);
|
|
12
|
-
let versionName = null;
|
|
13
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
14
|
-
if (args[i] === '--version-name' && args[i + 1]) {
|
|
15
|
-
versionName = args[i + 1];
|
|
16
|
-
i += 1;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return { versionName };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function bumpPubspecVersion(content, versionNameOverride) {
|
|
23
|
-
const match = content.match(/^version:\s*(\d+\.\d+\.\d+)\+(\d+)\s*$/m);
|
|
24
|
-
if (!match) {
|
|
25
|
-
throw new Error('Invalid version line in pubspec.yaml (expected format: 1.0.0+1)');
|
|
26
|
-
}
|
|
27
|
-
const name = versionNameOverride || match[1];
|
|
28
|
-
const build = parseInt(match[2], 10) + 1;
|
|
29
|
-
const next = `version: ${name}+${build}`;
|
|
30
|
-
const updated = content.replace(/^version:\s*.*/m, next);
|
|
31
|
-
return { updated, label: `${name}+${build}` };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const { versionName } = parseArgs();
|
|
35
|
-
const content = fs.readFileSync(pubspecPath, 'utf8');
|
|
36
|
-
const { updated, label } = bumpPubspecVersion(content, versionName);
|
|
37
|
-
fs.writeFileSync(pubspecPath, updated);
|
|
38
|
-
console.log(label);
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Build and upload iOS IPA to App Store Connect.
|
|
3
|
-
# Prefer: kasy ios release (configure first with kasy ios configure)
|
|
4
|
-
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
8
|
-
cd "$ROOT"
|
|
9
|
-
|
|
10
|
-
APPLE_ENV="${ROOT}/.kasy/apple.env"
|
|
11
|
-
UPLOAD=1
|
|
12
|
-
BUMP=1
|
|
13
|
-
VERSION_NAME=""
|
|
14
|
-
|
|
15
|
-
while [[ $# -gt 0 ]]; do
|
|
16
|
-
case "$1" in
|
|
17
|
-
--no-upload) UPLOAD=0; shift ;;
|
|
18
|
-
--no-bump) BUMP=0; shift ;;
|
|
19
|
-
--version-name)
|
|
20
|
-
VERSION_NAME="${2:-}"
|
|
21
|
-
shift 2
|
|
22
|
-
;;
|
|
23
|
-
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
24
|
-
esac
|
|
25
|
-
done
|
|
26
|
-
|
|
27
|
-
if [[ ! -f pubspec.yaml ]]; then
|
|
28
|
-
echo "pubspec.yaml not found. Run from the Flutter project root." >&2
|
|
29
|
-
exit 1
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
check_google_ios_url_scheme() {
|
|
33
|
-
local google_plist="${ROOT}/ios/Runner/GoogleService-Info.plist"
|
|
34
|
-
local info_plist="${ROOT}/ios/Runner/Info.plist"
|
|
35
|
-
|
|
36
|
-
[[ -f "$google_plist" ]] || return 0
|
|
37
|
-
|
|
38
|
-
if [[ ! -f "$info_plist" ]]; then
|
|
39
|
-
echo "ios/Runner/Info.plist not found." >&2
|
|
40
|
-
exit 1
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
local reversed_client_id
|
|
44
|
-
reversed_client_id="$(/usr/libexec/PlistBuddy -c "Print :REVERSED_CLIENT_ID" "$google_plist" 2>/dev/null || true)"
|
|
45
|
-
if [[ -z "$reversed_client_id" ]]; then
|
|
46
|
-
echo "REVERSED_CLIENT_ID not found in ios/Runner/GoogleService-Info.plist." >&2
|
|
47
|
-
echo "Run flutterfire configure before building iOS." >&2
|
|
48
|
-
exit 1
|
|
49
|
-
fi
|
|
50
|
-
|
|
51
|
-
if ! /usr/libexec/PlistBuddy -c "Print :CFBundleURLTypes" "$info_plist" 2>/dev/null | grep -Fq "$reversed_client_id"; then
|
|
52
|
-
echo "Google Sign-In iOS URL scheme mismatch." >&2
|
|
53
|
-
echo "Expected CFBundleURLSchemes to include: $reversed_client_id" >&2
|
|
54
|
-
echo "Run: kasy ios clean, then rebuild. If it still fails, re-run flutterfire configure/project setup." >&2
|
|
55
|
-
exit 1
|
|
56
|
-
fi
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
check_google_ios_url_scheme
|
|
60
|
-
|
|
61
|
-
if [[ "$BUMP" -eq 1 ]]; then
|
|
62
|
-
BUMP_SCRIPT="${ROOT}/scripts/bump-ios-version.js"
|
|
63
|
-
if [[ -f "$BUMP_SCRIPT" ]]; then
|
|
64
|
-
if [[ -n "$VERSION_NAME" ]]; then
|
|
65
|
-
node "$BUMP_SCRIPT" --version-name "$VERSION_NAME"
|
|
66
|
-
else
|
|
67
|
-
node "$BUMP_SCRIPT"
|
|
68
|
-
fi
|
|
69
|
-
else
|
|
70
|
-
echo "bump-ios-version.js not found" >&2
|
|
71
|
-
exit 1
|
|
72
|
-
fi
|
|
73
|
-
fi
|
|
74
|
-
|
|
75
|
-
load_dart_defines() {
|
|
76
|
-
DEFINES_ARGS=()
|
|
77
|
-
if [[ -f .dart_defines ]]; then
|
|
78
|
-
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
79
|
-
[[ -z "$line" || "$line" =~ ^# ]] && continue
|
|
80
|
-
DEFINES_ARGS+=("$line")
|
|
81
|
-
done < .dart_defines
|
|
82
|
-
fi
|
|
83
|
-
# Projects generated by Kasy may inline DEFINES in the Makefile instead of .dart_defines
|
|
84
|
-
if [[ ${#DEFINES_ARGS[@]} -eq 0 && -f Makefile ]]; then
|
|
85
|
-
local block
|
|
86
|
-
block="$(awk '/^DEFINES :=/{flag=1;next} flag && /^[^[:space:]#]/{exit} flag{print}' Makefile)"
|
|
87
|
-
while IFS= read -r line || [[ -n "$block" ]]; do
|
|
88
|
-
line="${line%%\\}" # trim trailing backslash from Makefile continuation
|
|
89
|
-
line="$(echo "$line" | xargs)"
|
|
90
|
-
[[ -z "$line" || "$line" =~ ^# ]] && continue
|
|
91
|
-
DEFINES_ARGS+=("$line")
|
|
92
|
-
done <<< "$block"
|
|
93
|
-
fi
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
load_dart_defines
|
|
97
|
-
|
|
98
|
-
echo "Building IPA..."
|
|
99
|
-
if [[ ${#DEFINES_ARGS[@]} -gt 0 ]]; then
|
|
100
|
-
flutter build ipa --release "${DEFINES_ARGS[@]}"
|
|
101
|
-
else
|
|
102
|
-
flutter build ipa --release
|
|
103
|
-
fi
|
|
104
|
-
|
|
105
|
-
if [[ "$UPLOAD" -eq 0 ]]; then
|
|
106
|
-
echo "IPA built at build/ios/ipa/"
|
|
107
|
-
exit 0
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
if [[ ! -f "$APPLE_ENV" ]]; then
|
|
111
|
-
echo "Missing $APPLE_ENV — run: kasy ios configure" >&2
|
|
112
|
-
exit 1
|
|
113
|
-
fi
|
|
114
|
-
|
|
115
|
-
# shellcheck disable=SC1090
|
|
116
|
-
source "$APPLE_ENV"
|
|
117
|
-
|
|
118
|
-
if [[ -z "${APP_STORE_API_KEY:-}" || -z "${APP_STORE_ISSUER_ID:-}" ]]; then
|
|
119
|
-
echo "APP_STORE_API_KEY and APP_STORE_ISSUER_ID required in .kasy/apple.env" >&2
|
|
120
|
-
exit 1
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
shopt -s nullglob
|
|
124
|
-
IPA=(build/ios/ipa/*.ipa)
|
|
125
|
-
shopt -u nullglob
|
|
126
|
-
|
|
127
|
-
if [[ ${#IPA[@]} -eq 0 || ! -f "${IPA[0]}" ]]; then
|
|
128
|
-
echo "IPA not found in build/ios/ipa/" >&2
|
|
129
|
-
exit 1
|
|
130
|
-
fi
|
|
131
|
-
|
|
132
|
-
echo "Uploading to App Store Connect..."
|
|
133
|
-
xcrun altool --upload-app --type ios -f "${IPA[0]}" \
|
|
134
|
-
--apiKey "$APP_STORE_API_KEY" \
|
|
135
|
-
--apiIssuer "$APP_STORE_ISSUER_ID"
|
|
136
|
-
|
|
137
|
-
echo "Upload complete."
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import 'package:flutter/material.dart';
|
|
2
|
-
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
|
-
import 'package:kasy_kit/components/components.dart';
|
|
4
|
-
import 'package:kasy_kit/core/theme/theme.dart';
|
|
5
|
-
import 'package:kasy_kit/core/widgets/kasy_app_bar.dart';
|
|
6
|
-
import 'package:kasy_kit/core/widgets/kasy_scroll_behavior.dart';
|
|
7
|
-
import 'package:kasy_kit/features/llm_chat/providers/llm_chat_notifier.dart';
|
|
8
|
-
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
9
|
-
|
|
10
|
-
class LlmChatPage extends ConsumerStatefulWidget {
|
|
11
|
-
const LlmChatPage({super.key});
|
|
12
|
-
|
|
13
|
-
@override
|
|
14
|
-
ConsumerState<LlmChatPage> createState() => _LlmChatPageState();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
class _LlmChatPageState extends ConsumerState<LlmChatPage> {
|
|
18
|
-
final TextEditingController _controller = TextEditingController();
|
|
19
|
-
final ScrollController _scrollController = ScrollController();
|
|
20
|
-
|
|
21
|
-
@override
|
|
22
|
-
void initState() {
|
|
23
|
-
super.initState();
|
|
24
|
-
// Scroll to bottom once the history finishes loading.
|
|
25
|
-
WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
void _sendMessage() {
|
|
29
|
-
final prompt = _controller.text.trim();
|
|
30
|
-
if (prompt.isEmpty) return;
|
|
31
|
-
_controller.clear();
|
|
32
|
-
ref.read(llmChatNotifierProvider.notifier).sendMessage(prompt);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
void _scrollToBottom() {
|
|
36
|
-
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
37
|
-
if (!_scrollController.hasClients) return;
|
|
38
|
-
_scrollController.animateTo(
|
|
39
|
-
_scrollController.position.maxScrollExtent,
|
|
40
|
-
duration: const Duration(milliseconds: 250),
|
|
41
|
-
curve: Curves.easeOut,
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@override
|
|
47
|
-
void dispose() {
|
|
48
|
-
_controller.dispose();
|
|
49
|
-
_scrollController.dispose();
|
|
50
|
-
super.dispose();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@override
|
|
54
|
-
Widget build(BuildContext context) {
|
|
55
|
-
// Scroll to bottom whenever the message list changes.
|
|
56
|
-
ref.listen(llmChatNotifierProvider, (_, _) => _scrollToBottom());
|
|
57
|
-
|
|
58
|
-
final chatAsync = ref.watch(llmChatNotifierProvider);
|
|
59
|
-
|
|
60
|
-
return Scaffold(
|
|
61
|
-
backgroundColor: context.colors.background,
|
|
62
|
-
body: Column(
|
|
63
|
-
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
64
|
-
children: [
|
|
65
|
-
KasyAppBar(
|
|
66
|
-
title: t.llm_chat.title,
|
|
67
|
-
),
|
|
68
|
-
Expanded(
|
|
69
|
-
child: chatAsync.when(
|
|
70
|
-
loading: () => const Center(child: CircularProgressIndicator()),
|
|
71
|
-
error: (_, _) =>
|
|
72
|
-
Center(child: Text(t.llm_chat.error_network)),
|
|
73
|
-
data: (chatState) => _buildBody(context, chatState),
|
|
74
|
-
),
|
|
75
|
-
),
|
|
76
|
-
],
|
|
77
|
-
),
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
Widget _buildBody(BuildContext context, LlmChatState chatState) {
|
|
82
|
-
final messages = chatState.messages;
|
|
83
|
-
final isReplying = chatState.isReplying;
|
|
84
|
-
|
|
85
|
-
// Show the typing indicator only while waiting for the first SSE chunk.
|
|
86
|
-
// Once streaming starts the partial assistant bubble is already in [messages].
|
|
87
|
-
final showTypingIndicator = isReplying && !chatState.streamingStarted;
|
|
88
|
-
|
|
89
|
-
return Column(
|
|
90
|
-
children: [
|
|
91
|
-
Expanded(
|
|
92
|
-
child: messages.isEmpty && !isReplying
|
|
93
|
-
? Center(
|
|
94
|
-
child: Text(
|
|
95
|
-
t.llm_chat.empty_state,
|
|
96
|
-
style: context.textTheme.bodyLarge?.copyWith(
|
|
97
|
-
color: context.colors.muted,
|
|
98
|
-
),
|
|
99
|
-
),
|
|
100
|
-
)
|
|
101
|
-
: ScrollConfiguration(
|
|
102
|
-
behavior: const KasyKitScrollBehavior(),
|
|
103
|
-
child: ListView.builder(
|
|
104
|
-
controller: _scrollController,
|
|
105
|
-
padding: const EdgeInsets.fromLTRB(
|
|
106
|
-
KasySpacing.pageHorizontalGutter,
|
|
107
|
-
KasySpacing.md,
|
|
108
|
-
KasySpacing.pageHorizontalGutter,
|
|
109
|
-
KasySpacing.md,
|
|
110
|
-
),
|
|
111
|
-
// +1 for the typing indicator shown before the first SSE chunk
|
|
112
|
-
itemCount: messages.length + (showTypingIndicator ? 1 : 0),
|
|
113
|
-
itemBuilder: (context, index) {
|
|
114
|
-
if (showTypingIndicator && index == messages.length) {
|
|
115
|
-
return const Align(
|
|
116
|
-
alignment: Alignment.centerLeft,
|
|
117
|
-
child: _TypingIndicator(),
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
final message = messages[index];
|
|
121
|
-
return _ChatBubble(
|
|
122
|
-
message: message,
|
|
123
|
-
isUser: message.role == 'user',
|
|
124
|
-
);
|
|
125
|
-
},
|
|
126
|
-
),
|
|
127
|
-
),
|
|
128
|
-
),
|
|
129
|
-
SafeArea(
|
|
130
|
-
top: false,
|
|
131
|
-
child: Padding(
|
|
132
|
-
padding: const EdgeInsets.fromLTRB(
|
|
133
|
-
KasySpacing.pageHorizontalGutter,
|
|
134
|
-
KasySpacing.sm,
|
|
135
|
-
KasySpacing.pageHorizontalGutter,
|
|
136
|
-
KasySpacing.md,
|
|
137
|
-
),
|
|
138
|
-
child: Row(
|
|
139
|
-
crossAxisAlignment: CrossAxisAlignment.end,
|
|
140
|
-
children: [
|
|
141
|
-
Expanded(
|
|
142
|
-
child: KasyTextField(
|
|
143
|
-
controller: _controller,
|
|
144
|
-
maxLines: 4,
|
|
145
|
-
textInputAction: TextInputAction.send,
|
|
146
|
-
onSubmitted: (_) => _sendMessage(),
|
|
147
|
-
hint: t.llm_chat.hint,
|
|
148
|
-
),
|
|
149
|
-
),
|
|
150
|
-
const SizedBox(width: KasySpacing.smd),
|
|
151
|
-
SizedBox(
|
|
152
|
-
height: 48,
|
|
153
|
-
width: 48,
|
|
154
|
-
child: ElevatedButton(
|
|
155
|
-
style: ElevatedButton.styleFrom(
|
|
156
|
-
padding: EdgeInsets.zero,
|
|
157
|
-
shape: RoundedRectangleBorder(
|
|
158
|
-
borderRadius: KasyRadius.smBorderRadius,
|
|
159
|
-
),
|
|
160
|
-
),
|
|
161
|
-
onPressed: isReplying ? null : _sendMessage,
|
|
162
|
-
child: isReplying
|
|
163
|
-
? SizedBox(
|
|
164
|
-
width: 18,
|
|
165
|
-
height: 18,
|
|
166
|
-
child: CircularProgressIndicator(
|
|
167
|
-
strokeWidth: 2,
|
|
168
|
-
color: context.colors.muted,
|
|
169
|
-
),
|
|
170
|
-
)
|
|
171
|
-
: const Icon(KasyIcons.send, size: 20),
|
|
172
|
-
),
|
|
173
|
-
),
|
|
174
|
-
],
|
|
175
|
-
),
|
|
176
|
-
),
|
|
177
|
-
),
|
|
178
|
-
],
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
class _ChatBubble extends StatelessWidget {
|
|
184
|
-
const _ChatBubble({required this.message, required this.isUser});
|
|
185
|
-
|
|
186
|
-
final ChatMessage message;
|
|
187
|
-
final bool isUser;
|
|
188
|
-
|
|
189
|
-
@override
|
|
190
|
-
Widget build(BuildContext context) {
|
|
191
|
-
return Align(
|
|
192
|
-
alignment: isUser ? Alignment.centerRight : Alignment.centerLeft,
|
|
193
|
-
child: Container(
|
|
194
|
-
margin: EdgeInsets.only(
|
|
195
|
-
bottom: KasySpacing.sm,
|
|
196
|
-
left: isUser ? 48 : 0,
|
|
197
|
-
right: isUser ? 0 : 48,
|
|
198
|
-
),
|
|
199
|
-
padding: const EdgeInsets.symmetric(
|
|
200
|
-
horizontal: KasySpacing.smd,
|
|
201
|
-
vertical: KasySpacing.sm,
|
|
202
|
-
),
|
|
203
|
-
decoration: BoxDecoration(
|
|
204
|
-
color: isUser
|
|
205
|
-
? context.colors.primary
|
|
206
|
-
: context.colors.onBackground.withValues(alpha: 0.06),
|
|
207
|
-
borderRadius: BorderRadius.only(
|
|
208
|
-
topLeft: const Radius.circular(16),
|
|
209
|
-
topRight: const Radius.circular(16),
|
|
210
|
-
bottomLeft:
|
|
211
|
-
isUser ? const Radius.circular(16) : const Radius.circular(4),
|
|
212
|
-
bottomRight:
|
|
213
|
-
isUser ? const Radius.circular(4) : const Radius.circular(16),
|
|
214
|
-
),
|
|
215
|
-
),
|
|
216
|
-
child: Text(
|
|
217
|
-
message.content,
|
|
218
|
-
style: context.textTheme.bodyMedium?.copyWith(
|
|
219
|
-
color:
|
|
220
|
-
isUser ? context.colors.onPrimary : context.colors.onBackground,
|
|
221
|
-
),
|
|
222
|
-
),
|
|
223
|
-
),
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/// Animated three-dot indicator shown while the assistant is generating a reply.
|
|
229
|
-
class _TypingIndicator extends StatefulWidget {
|
|
230
|
-
const _TypingIndicator();
|
|
231
|
-
|
|
232
|
-
@override
|
|
233
|
-
State<_TypingIndicator> createState() => _TypingIndicatorState();
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
class _TypingIndicatorState extends State<_TypingIndicator>
|
|
237
|
-
with SingleTickerProviderStateMixin {
|
|
238
|
-
late final AnimationController _controller;
|
|
239
|
-
|
|
240
|
-
@override
|
|
241
|
-
void initState() {
|
|
242
|
-
super.initState();
|
|
243
|
-
_controller = AnimationController(
|
|
244
|
-
vsync: this,
|
|
245
|
-
duration: const Duration(milliseconds: 900),
|
|
246
|
-
)..repeat();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
@override
|
|
250
|
-
void dispose() {
|
|
251
|
-
_controller.dispose();
|
|
252
|
-
super.dispose();
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
@override
|
|
256
|
-
Widget build(BuildContext context) {
|
|
257
|
-
return Container(
|
|
258
|
-
margin: const EdgeInsets.only(bottom: KasySpacing.sm),
|
|
259
|
-
padding: const EdgeInsets.symmetric(
|
|
260
|
-
horizontal: KasySpacing.smd,
|
|
261
|
-
vertical: KasySpacing.sm,
|
|
262
|
-
),
|
|
263
|
-
decoration: BoxDecoration(
|
|
264
|
-
color: context.colors.onBackground.withValues(alpha: 0.06),
|
|
265
|
-
borderRadius: const BorderRadius.only(
|
|
266
|
-
topLeft: Radius.circular(16),
|
|
267
|
-
topRight: Radius.circular(16),
|
|
268
|
-
bottomLeft: Radius.circular(4),
|
|
269
|
-
bottomRight: Radius.circular(16),
|
|
270
|
-
),
|
|
271
|
-
),
|
|
272
|
-
child: Row(
|
|
273
|
-
mainAxisSize: MainAxisSize.min,
|
|
274
|
-
spacing: 4,
|
|
275
|
-
children: List.generate(3, (i) {
|
|
276
|
-
return AnimatedBuilder(
|
|
277
|
-
animation: _controller,
|
|
278
|
-
builder: (context, _) {
|
|
279
|
-
// Each dot bounces at a slightly different phase.
|
|
280
|
-
final double phase =
|
|
281
|
-
(_controller.value - i * 0.2).clamp(0.0, 1.0);
|
|
282
|
-
final double scale = 1.0 +
|
|
283
|
-
0.4 * (phase < 0.5 ? phase * 2 : (1.0 - phase) * 2);
|
|
284
|
-
return Transform.scale(
|
|
285
|
-
scale: scale,
|
|
286
|
-
child: Container(
|
|
287
|
-
width: 6,
|
|
288
|
-
height: 6,
|
|
289
|
-
decoration: BoxDecoration(
|
|
290
|
-
shape: BoxShape.circle,
|
|
291
|
-
color: context.colors.muted,
|
|
292
|
-
),
|
|
293
|
-
),
|
|
294
|
-
);
|
|
295
|
-
},
|
|
296
|
-
);
|
|
297
|
-
}),
|
|
298
|
-
),
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import 'package:kasy_kit/core/states/translations.dart';
|
|
2
|
-
import 'package:kasy_kit/features/local_reminder/repositories/reminder_preferences.dart';
|
|
3
|
-
import 'package:kasy_kit/features/notifications/api/local_notifier.dart';
|
|
4
|
-
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
5
|
-
|
|
6
|
-
part 'reminder_notifier.g.dart';
|
|
7
|
-
|
|
8
|
-
const _kReminderId = 42;
|
|
9
|
-
|
|
10
|
-
@Riverpod(keepAlive: true)
|
|
11
|
-
class ReminderNotifier extends _$ReminderNotifier {
|
|
12
|
-
@override
|
|
13
|
-
Future<ReminderState> build() {
|
|
14
|
-
return ReminderPreferences.load();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
Future<void> setEnabled(bool value) async {
|
|
18
|
-
final current = state.requireValue;
|
|
19
|
-
await _applyAndSave(current.copyWith(enabled: value));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
Future<void> setType(ReminderType type) async {
|
|
23
|
-
final current = state.requireValue;
|
|
24
|
-
await _applyAndSave(current.copyWith(type: type));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
Future<void> setTime(int hour, int minute) async {
|
|
28
|
-
final current = state.requireValue;
|
|
29
|
-
await _applyAndSave(current.copyWith(hour: hour, minute: minute));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
Future<void> setDayOfWeek(int day) async {
|
|
33
|
-
final current = state.requireValue;
|
|
34
|
-
await _applyAndSave(current.copyWith(dayOfWeek: day));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
Future<void> setDate(DateTime date) async {
|
|
38
|
-
final current = state.requireValue;
|
|
39
|
-
await _applyAndSave(current.copyWith(date: date));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
Future<void> _applyAndSave(ReminderState next) async {
|
|
43
|
-
state = AsyncData(next);
|
|
44
|
-
final notifier = ref.read(localNotifierProvider);
|
|
45
|
-
await notifier.cancel(_kReminderId);
|
|
46
|
-
|
|
47
|
-
if (next.enabled) {
|
|
48
|
-
final tr = ref.read(translationsProvider).dailyReminder;
|
|
49
|
-
switch (next.type) {
|
|
50
|
-
case ReminderType.daily:
|
|
51
|
-
await notifier.scheduleDailyAt(
|
|
52
|
-
notificationId: _kReminderId,
|
|
53
|
-
title: tr.title,
|
|
54
|
-
body: tr.body,
|
|
55
|
-
hour: next.hour,
|
|
56
|
-
minute: next.minute,
|
|
57
|
-
);
|
|
58
|
-
case ReminderType.weekly:
|
|
59
|
-
await notifier.scheduleWeekly(
|
|
60
|
-
notificationId: _kReminderId,
|
|
61
|
-
title: tr.title,
|
|
62
|
-
body: tr.body,
|
|
63
|
-
dayOfWeekIndex: next.dayOfWeek,
|
|
64
|
-
hour: next.hour,
|
|
65
|
-
minute: next.minute,
|
|
66
|
-
);
|
|
67
|
-
case ReminderType.specificDate:
|
|
68
|
-
if (next.date != null) {
|
|
69
|
-
await notifier.scheduleAt(
|
|
70
|
-
notificationId: _kReminderId,
|
|
71
|
-
title: tr.title,
|
|
72
|
-
body: tr.body,
|
|
73
|
-
date: next.date!,
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
await ReminderPreferences.save(next);
|
|
80
|
-
}
|
|
81
|
-
}
|