kasy-cli 1.13.0 → 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 +122 -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 +3 -4
- package/lib/commands/update.js +1 -1
- 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/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/pubspec.yaml.tpl +11 -1
- 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 +335 -0
- package/lib/utils/mobile-identity.js +35 -0
- package/lib/utils/ui.js +114 -0
- package/package.json +1 -2
- 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/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/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/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/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/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/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 +4 -1
- package/templates/firebase/lib/i18n/es.i18n.json +4 -1
- package/templates/firebase/lib/i18n/pt.i18n.json +4 -1
- package/templates/firebase/pubspec.yaml +6 -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 +3 -0
- package/templates/firebase/web/manifest.json +3 -3
- 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/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
|
@@ -443,6 +443,7 @@
|
|
|
443
443
|
"group_yesterday": "Ayer",
|
|
444
444
|
"group_older": "Más antiguas",
|
|
445
445
|
"empty_cta": "Activar notificaciones",
|
|
446
|
+
"empty_cta_open_settings": "Abrir ajustes",
|
|
446
447
|
"delete_all": "Eliminar todo",
|
|
447
448
|
"delete_all_confirm_title": "¿Eliminar todas las notificaciones?",
|
|
448
449
|
"delete_all_confirm_message": "Esto eliminará todas las notificaciones de tu cuenta. Esta acción no se puede deshacer.",
|
|
@@ -527,8 +528,10 @@
|
|
|
527
528
|
"greeting_evening": "Buenas noches",
|
|
528
529
|
"title_with_name": "¡Hola, $name!",
|
|
529
530
|
"title_default": "¡Hola!",
|
|
531
|
+
"title_logged_out": "Te esperamos de vuelta",
|
|
530
532
|
"plan_free": "Plan gratuito",
|
|
531
|
-
"plan_pro": "PRO"
|
|
533
|
+
"plan_pro": "PRO",
|
|
534
|
+
"quote": "Siempre parece imposible hasta que se hace."
|
|
532
535
|
}
|
|
533
536
|
}
|
|
534
537
|
|
|
@@ -443,6 +443,7 @@
|
|
|
443
443
|
"group_yesterday": "Ontem",
|
|
444
444
|
"group_older": "Mais antigas",
|
|
445
445
|
"empty_cta": "Ativar notificações",
|
|
446
|
+
"empty_cta_open_settings": "Abrir configurações",
|
|
446
447
|
"delete_all": "Excluir tudo",
|
|
447
448
|
"delete_all_confirm_title": "Excluir todas as notificações?",
|
|
448
449
|
"delete_all_confirm_message": "Isso vai remover todas as notificações da sua conta. Essa ação não pode ser desfeita.",
|
|
@@ -527,8 +528,10 @@
|
|
|
527
528
|
"greeting_evening": "Boa noite",
|
|
528
529
|
"title_with_name": "Olá, $name!",
|
|
529
530
|
"title_default": "Olá!",
|
|
531
|
+
"title_logged_out": "Aguardamos seu retorno",
|
|
530
532
|
"plan_free": "Plano grátis",
|
|
531
|
-
"plan_pro": "PRO"
|
|
533
|
+
"plan_pro": "PRO",
|
|
534
|
+
"quote": "Sempre parece impossível, até que seja feito."
|
|
532
535
|
}
|
|
533
536
|
}
|
|
534
537
|
|
|
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
|
16
16
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
17
17
|
# In Windows, build-name is used as the major, minor, and patch parts
|
|
18
18
|
# of the product and file versions while build-number is used as the build suffix.
|
|
19
|
-
version: 1.0.0+
|
|
19
|
+
version: 1.0.0+31
|
|
20
20
|
|
|
21
21
|
environment:
|
|
22
22
|
sdk: ^3.11.0
|
|
@@ -130,6 +130,11 @@ flutter_launcher_icons:
|
|
|
130
130
|
android: ic_launcher
|
|
131
131
|
ios: true
|
|
132
132
|
remove_alpha_ios: true
|
|
133
|
+
web:
|
|
134
|
+
generate: true
|
|
135
|
+
image_path: assets/images/favicon.png
|
|
136
|
+
background_color: "#01171f"
|
|
137
|
+
theme_color: "#01171f"
|
|
133
138
|
flutter_native_splash:
|
|
134
139
|
color: "#FFFFFF"
|
|
135
140
|
color_dark: "#000000"
|
|
@@ -15,6 +15,15 @@ class FakeDeviceApi implements DeviceApi {
|
|
|
15
15
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
@override
|
|
19
|
+
Future<void> touch(String userId, String installationId) async {}
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
Future<void> cleanupStaleDevices(
|
|
23
|
+
String userId,
|
|
24
|
+
String currentInstallationId,
|
|
25
|
+
) async {}
|
|
26
|
+
|
|
18
27
|
@override
|
|
19
28
|
Future<DeviceEntity> get() {
|
|
20
29
|
return Future.value(
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
|
|
35
|
+
|
|
36
|
+
|
|
35
37
|
<style id="splash-screen-style">
|
|
36
38
|
html {
|
|
37
39
|
height: 100%
|
|
@@ -111,6 +113,7 @@
|
|
|
111
113
|
<img class="center" aria-hidden="true" src="splash/img/light-1x.png" alt="">
|
|
112
114
|
</picture>
|
|
113
115
|
|
|
116
|
+
|
|
114
117
|
<script src="flutter_bootstrap.js" async=""></script>
|
|
115
118
|
<script src="./local_notifications.js"></script>
|
|
116
119
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"short_name": "kasy",
|
|
4
4
|
"start_url": ".",
|
|
5
5
|
"display": "standalone",
|
|
6
|
-
"background_color": "#
|
|
7
|
-
"theme_color": "#
|
|
6
|
+
"background_color": "#01171f",
|
|
7
|
+
"theme_color": "#01171f",
|
|
8
8
|
"description": "A new Flutter project.",
|
|
9
9
|
"orientation": "portrait-primary",
|
|
10
10
|
"prefer_related_applications": false,
|
|
@@ -32,4 +32,4 @@
|
|
|
32
32
|
"purpose": "maskable"
|
|
33
33
|
}
|
|
34
34
|
]
|
|
35
|
-
}
|
|
35
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import 'package:flutter/foundation.dart';
|
|
2
|
-
import 'package:flutter/material.dart';
|
|
3
|
-
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
4
|
-
import 'package:kasy_kit/components/kasy_button.dart';
|
|
5
|
-
import 'package:kasy_kit/components/kasy_dialog.dart';
|
|
6
|
-
import 'package:kasy_kit/core/data/models/user.dart';
|
|
7
|
-
import 'package:kasy_kit/core/icons/kasy_icons.dart';
|
|
8
|
-
import 'package:kasy_kit/core/security/biometric_preference_notifier.dart';
|
|
9
|
-
import 'package:kasy_kit/core/security/biometric_service.dart';
|
|
10
|
-
import 'package:kasy_kit/core/security/biometric_ui_bundle.dart';
|
|
11
|
-
import 'package:kasy_kit/core/shared_preferences/shared_preferences.dart';
|
|
12
|
-
import 'package:kasy_kit/core/states/components/maybeshow_component.dart';
|
|
13
|
-
import 'package:kasy_kit/core/states/models/event_model.dart';
|
|
14
|
-
import 'package:kasy_kit/core/states/user_state_notifier.dart';
|
|
15
|
-
|
|
16
|
-
class MaybeAskBiometricSetup extends MaybeShowWithRef {
|
|
17
|
-
@override
|
|
18
|
-
Future<bool> handle(WidgetRef ref, AppEvent event) async {
|
|
19
|
-
if (event is! OnAppStartEvent) return false;
|
|
20
|
-
if (kIsWeb) return false;
|
|
21
|
-
|
|
22
|
-
final prefs = ref.read(sharedPreferencesProvider);
|
|
23
|
-
if (prefs.getBiometricPromptShown()) return false;
|
|
24
|
-
if (prefs.getBiometricEnabled()) return false;
|
|
25
|
-
|
|
26
|
-
final user = ref.read(userStateNotifierProvider).user;
|
|
27
|
-
if (user is! AuthenticatedUserData) return false;
|
|
28
|
-
|
|
29
|
-
final service = ref.read(biometricServiceProvider);
|
|
30
|
-
if (!await service.isAvailable()) return false;
|
|
31
|
-
|
|
32
|
-
await Future.delayed(const Duration(milliseconds: 800));
|
|
33
|
-
if (!ref.context.mounted) return false;
|
|
34
|
-
|
|
35
|
-
final platform = Theme.of(ref.context).platform;
|
|
36
|
-
final slot = await ref.read(biometricCopySlotFamily(platform).future);
|
|
37
|
-
if (!ref.context.mounted) return false;
|
|
38
|
-
final bundle = BioBundle.fromSlot(ref.context, slot);
|
|
39
|
-
|
|
40
|
-
// ignore: use_build_context_synchronously
|
|
41
|
-
await _showPrompt(ref.context, ref, bundle);
|
|
42
|
-
await prefs.setBiometricPromptShown(true);
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
Future<void> _showPrompt(
|
|
47
|
-
BuildContext context,
|
|
48
|
-
WidgetRef ref,
|
|
49
|
-
BioBundle bundle,
|
|
50
|
-
) async {
|
|
51
|
-
await showKasyBlurDialog<void>(
|
|
52
|
-
context: context,
|
|
53
|
-
barrierDismissible: false,
|
|
54
|
-
builder: (dialogContext) => KasyDialog(
|
|
55
|
-
leadingIcon: KasyIcons.fingerprint,
|
|
56
|
-
iconTone: KasyDialogIconTone.info,
|
|
57
|
-
title: bundle.promptTitle,
|
|
58
|
-
message: bundle.promptMessage,
|
|
59
|
-
showCloseButton: false,
|
|
60
|
-
actionsAxis: Axis.horizontal,
|
|
61
|
-
actions: [
|
|
62
|
-
KasyButton(
|
|
63
|
-
label: bundle.notNowLabel,
|
|
64
|
-
variant: KasyButtonVariant.outline,
|
|
65
|
-
expand: true,
|
|
66
|
-
onPressed: () => Navigator.of(dialogContext).pop(),
|
|
67
|
-
),
|
|
68
|
-
KasyButton(
|
|
69
|
-
label: bundle.enableLabel,
|
|
70
|
-
expand: true,
|
|
71
|
-
onPressed: () async {
|
|
72
|
-
Navigator.of(dialogContext).pop();
|
|
73
|
-
final service = ref.read(biometricServiceProvider);
|
|
74
|
-
final authenticated = await service.authenticate(
|
|
75
|
-
localizedReason: bundle.enableReason,
|
|
76
|
-
);
|
|
77
|
-
if (authenticated) {
|
|
78
|
-
await ref
|
|
79
|
-
.read(biometricPreferenceProvider.notifier)
|
|
80
|
-
.setEnabled(true);
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
),
|
|
84
|
-
],
|
|
85
|
-
),
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import 'package:flutter/foundation.dart';
|
|
2
|
-
import 'package:flutter/material.dart';
|
|
3
|
-
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
4
|
-
import 'package:kasy_kit/components/components.dart';
|
|
5
|
-
import 'package:kasy_kit/core/icons/kasy_icons.dart';
|
|
6
|
-
import 'package:kasy_kit/core/states/components/maybeshow_component.dart';
|
|
7
|
-
import 'package:kasy_kit/core/states/models/event_model.dart';
|
|
8
|
-
import 'package:kasy_kit/features/notifications/api/local_notifier.dart';
|
|
9
|
-
import 'package:kasy_kit/features/notifications/repositories/notifications_repository.dart';
|
|
10
|
-
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
11
|
-
import 'package:logger/logger.dart';
|
|
12
|
-
import 'package:permission_handler/permission_handler.dart';
|
|
13
|
-
import 'package:sentry_flutter/sentry_flutter.dart';
|
|
14
|
-
|
|
15
|
-
/// This widget is used to show the notification permission dialog
|
|
16
|
-
/// if user didn't grant permission, we will show the dialog again
|
|
17
|
-
/// if user granted permission, we will not show the dialog again
|
|
18
|
-
/// customize the trigger condition to your needs
|
|
19
|
-
class MaybeShowNotificationPermission extends MaybeShowWithContext {
|
|
20
|
-
@override
|
|
21
|
-
Future<bool> handle(BuildContext context, AppEvent? event) async {
|
|
22
|
-
if (event == null) return false;
|
|
23
|
-
return switch (event) {
|
|
24
|
-
OnAppStartEvent() => showNotificationPermissionSheetIfNeeded(context),
|
|
25
|
-
_ => false,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
Future<bool> showNotificationPermissionSheetIfNeeded(
|
|
31
|
-
BuildContext context, {
|
|
32
|
-
bool force = false,
|
|
33
|
-
}) async {
|
|
34
|
-
if (kIsWeb) return false;
|
|
35
|
-
Logger().d("🔔 [MaybeShowNotificationPermission] checking permission status");
|
|
36
|
-
final permissionStatus = await Permission.notification.status;
|
|
37
|
-
if (permissionStatus.isGranted && !force) {
|
|
38
|
-
debugPrint('🔔 [MaybeShowNotificationPermission] permission is granted ✅');
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
if (context.mounted) {
|
|
42
|
-
await showKasyBlurDialog<void>(
|
|
43
|
-
context: context,
|
|
44
|
-
builder: (dialogContext) => const _NotificationPermissionDialog(),
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
class _NotificationPermissionDialog extends ConsumerWidget {
|
|
51
|
-
const _NotificationPermissionDialog();
|
|
52
|
-
|
|
53
|
-
@override
|
|
54
|
-
Widget build(BuildContext context, WidgetRef ref) {
|
|
55
|
-
final translations = Translations.of(
|
|
56
|
-
context,
|
|
57
|
-
).request_notification_permission;
|
|
58
|
-
final notificationSettings = ref.read(notificationsSettingsProvider);
|
|
59
|
-
final notificationRepository = ref.read(notificationRepositoryProvider);
|
|
60
|
-
|
|
61
|
-
return KasyDialog(
|
|
62
|
-
leadingIcon: KasyIcons.notificationAdd,
|
|
63
|
-
iconTone: KasyDialogIconTone.info,
|
|
64
|
-
title: translations.title,
|
|
65
|
-
message: translations.description,
|
|
66
|
-
showCloseButton: false,
|
|
67
|
-
actions: [
|
|
68
|
-
KasyButton(
|
|
69
|
-
label: translations.continue_button,
|
|
70
|
-
expand: true,
|
|
71
|
-
onPressed: () => _requestNotificationPermission(
|
|
72
|
-
context,
|
|
73
|
-
notificationSettings,
|
|
74
|
-
notificationRepository,
|
|
75
|
-
),
|
|
76
|
-
),
|
|
77
|
-
],
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
Future<void> _requestNotificationPermission(
|
|
82
|
-
BuildContext context,
|
|
83
|
-
NotificationSettings notificationSettings,
|
|
84
|
-
NotificationsRepository notificationRepository,
|
|
85
|
-
) async {
|
|
86
|
-
try {
|
|
87
|
-
final permissionStatus = await Permission.notification.status;
|
|
88
|
-
|
|
89
|
-
if (permissionStatus.isPermanentlyDenied) {
|
|
90
|
-
if (!context.mounted) return;
|
|
91
|
-
await _showPermissionDeniedDialog(context);
|
|
92
|
-
if (!context.mounted) return;
|
|
93
|
-
Navigator.of(context).pop();
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (permissionStatus.isDenied) {
|
|
98
|
-
final granted = await notificationSettings.askPermission();
|
|
99
|
-
if (!context.mounted) return;
|
|
100
|
-
Navigator.of(context).pop();
|
|
101
|
-
if (granted) {
|
|
102
|
-
notificationRepository.init();
|
|
103
|
-
} else {
|
|
104
|
-
await _showPermissionDeniedDialog(context);
|
|
105
|
-
}
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
final notificationsEnabled =
|
|
110
|
-
await notificationSettings.areNotificationsEnabled();
|
|
111
|
-
if (!context.mounted) return;
|
|
112
|
-
if (notificationsEnabled) {
|
|
113
|
-
await notificationRepository.init();
|
|
114
|
-
if (!context.mounted) return;
|
|
115
|
-
Navigator.of(context).pop();
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
await _showPermissionDeniedDialog(context);
|
|
119
|
-
if (!context.mounted) return;
|
|
120
|
-
Navigator.of(context).pop();
|
|
121
|
-
} catch (e, stackTrace) {
|
|
122
|
-
if (!context.mounted) return;
|
|
123
|
-
debugPrint('🔔 [NotificationPermissionDialog] error: $e');
|
|
124
|
-
Sentry.captureException(e, stackTrace: stackTrace);
|
|
125
|
-
Navigator.of(context).pop();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
Future<void> _showPermissionDeniedDialog(BuildContext context) {
|
|
130
|
-
final t = Translations.of(context).notification_permission_denied;
|
|
131
|
-
return showKasyConfirmDialog(
|
|
132
|
-
context,
|
|
133
|
-
title: t.title,
|
|
134
|
-
message: t.description,
|
|
135
|
-
cancelLabel: t.cancel_button,
|
|
136
|
-
confirmLabel: t.open_settings_button,
|
|
137
|
-
onCancel: () => Navigator.of(context).pop(),
|
|
138
|
-
onConfirm: () {
|
|
139
|
-
Navigator.of(context).pop();
|
|
140
|
-
openAppSettings();
|
|
141
|
-
},
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
}
|