kasy-cli 1.20.0 → 1.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +11 -3
  2. package/lib/commands/new.js +78 -37
  3. package/lib/commands/run.js +7 -0
  4. package/lib/scaffold/backends/api/patch/lib/core/data/api/meta_ads_api.dart +1 -1
  5. package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
  6. package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +1 -1
  7. package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +4 -5
  8. package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +1 -1
  9. package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_vote_api.dart +1 -1
  10. package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +1 -1
  11. package/lib/scaffold/backends/api/patch/lib/features/llm_chat/providers/llm_chat_notifier.dart +317 -0
  12. package/lib/scaffold/backends/api/patch/lib/features/notifications/api/device_api.dart +40 -1
  13. package/lib/scaffold/backends/api/patch/lib/features/notifications/api/entities/notifications_entity.dart +2 -0
  14. package/lib/scaffold/backends/api/patch/lib/features/onboarding/api/entities/user_info_entity.dart +1 -1
  15. package/lib/scaffold/backends/api/patch/lib/features/subscription/api/entities/subscription_entity.dart +1 -1
  16. package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -2
  17. package/lib/scaffold/backends/api/pubspec.yaml.tpl +2 -0
  18. package/lib/scaffold/backends/firebase/enable-auth-via-cli.js +11 -8
  19. package/lib/scaffold/backends/supabase/deploy.js +56 -3
  20. package/lib/scaffold/backends/supabase/patch/lib/core/data/api/storage_api.dart +5 -11
  21. package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +2 -2
  22. package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/device_api.dart +31 -1
  23. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/api/entities/user_info_entity.dart +1 -1
  24. package/lib/scaffold/backends/supabase/patch/lib/features/subscription/api/entities/subscription_entity.dart +1 -1
  25. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +2 -0
  26. package/lib/scaffold/catalog.js +2 -2
  27. package/lib/scaffold/generate.js +19 -3
  28. package/lib/scaffold/shared/generator-utils.js +265 -55
  29. package/lib/scaffold/shared/post-build.js +11 -0
  30. package/lib/utils/i18n/messages-en.js +5 -1
  31. package/lib/utils/i18n/messages-es.js +5 -1
  32. package/lib/utils/i18n/messages-pt.js +5 -1
  33. package/package.json +1 -1
  34. package/templates/firebase/lib/components/kasy_sidebar_pro.dart +3 -1
  35. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +38 -128
  36. package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +6 -125
  37. package/templates/firebase/lib/core/states/user_state_notifier.dart +8 -10
  38. package/templates/firebase/lib/features/home/home_components_page.dart +8 -14
  39. package/templates/firebase/lib/features/home/home_page.dart +7 -8
  40. package/templates/firebase/lib/router.dart +60 -0
  41. package/templates/firebase/test/core/bottom_menu/detail_route_menu_test.dart +57 -0
  42. package/lib/scaffold/backends/api/patch/lib/core/rating/widgets/review_popup.dart +0 -211
  43. package/lib/scaffold/backends/api/patch/lib/features/notifications/providers/models/notification.dart +0 -185
  44. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +0 -73
  45. package/lib/scaffold/backends/api/patch/lib/main.dart +0 -275
  46. package/lib/scaffold/backends/api/patch/lib/router.dart +0 -133
  47. package/lib/scaffold/backends/supabase/patch/lib/core/rating/widgets/review_popup.dart +0 -211
  48. package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/ui/component/add_feature_form.dart +0 -199
  49. package/lib/scaffold/backends/supabase/patch/lib/features/notifications/providers/models/notification.dart +0 -174
  50. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +0 -73
  51. package/lib/scaffold/backends/supabase/patch/lib/main.dart +0 -307
  52. package/lib/scaffold/backends/supabase/patch/lib/router.dart +0 -133
@@ -1,275 +0,0 @@
1
- import 'package:kasy_kit/core/data/api/analytics_api.dart';
2
- import 'package:kasy_kit/core/data/api/remote_config_api.dart';
3
- import 'package:kasy_kit/core/data/api/tracking_api.dart';
4
- import 'package:kasy_kit/core/dev_inspector/dev_inspector.dart';
5
- import 'package:kasy_kit/core/initializer/onstart_widget.dart';
6
- import 'package:kasy_kit/core/web_device_preview/web_device_preview.dart';
7
- import 'package:kasy_kit/core/shared_preferences/shared_preferences.dart';
8
- import 'package:kasy_kit/core/states/user_state_notifier.dart';
9
- import 'package:kasy_kit/core/theme/colors.dart';
10
- import 'package:kasy_kit/core/theme/extensions/theme_extension.dart';
11
- import 'package:kasy_kit/core/theme/providers/theme_provider.dart';
12
- import 'package:kasy_kit/core/theme/texts.dart';
13
- import 'package:kasy_kit/core/theme/universal_theme.dart';
14
- import 'package:kasy_kit/core/config/app_env.dart';
15
- import 'package:kasy_kit/environnements.dart';
16
- import 'package:kasy_kit/firebase_options_dev.dart' as firebase_dev;
17
- import 'package:kasy_kit/i18n/translations.g.dart';
18
- import 'package:kasy_kit/features/notifications/api/local_notifier.dart';
19
- import 'package:kasy_kit/features/notifications/repositories/background_notification_handler.dart';
20
- import 'package:kasy_kit/features/notifications/repositories/notifications_repository.dart';
21
- import 'package:kasy_kit/features/subscription/repositories/subscription_repository.dart';
22
- import 'package:kasy_kit/router.dart';
23
- import 'package:device_preview/device_preview.dart';
24
- import 'package:firebase_core/firebase_core.dart';
25
- import 'package:firebase_messaging/firebase_messaging.dart';
26
- import 'package:flutter/foundation.dart';
27
- import 'package:flutter/material.dart';
28
- import 'package:flutter/services.dart';
29
- import 'package:flutter_localizations/flutter_localizations.dart';
30
- import 'package:flutter_riverpod/flutter_riverpod.dart';
31
- import 'package:logger/logger.dart';
32
- import 'package:sentry_flutter/sentry_flutter.dart';
33
- import 'package:shared_preferences/shared_preferences.dart';
34
-
35
-
36
- void main() async {
37
- WidgetsFlutterBinding.ensureInitialized();
38
- await AppEnv.load();
39
- LocaleSettings.useDeviceLocale();
40
- final env = Environment.fromEnv();
41
- final logger = Logger();
42
- logger.i('Starting app in ${env.name} mode');
43
- // I like to force portrait mode on mobile devices
44
- // What is the last time you used an app in landscape mode?
45
- SystemChrome.setPreferredOrientations([
46
- DeviceOrientation.portraitUp,
47
- DeviceOrientation.portraitDown,
48
- ]);
49
-
50
- // initialize shared preferences for theme
51
- final sharedPrefs = await SharedPreferences.getInstance();
52
-
53
- // initialize firebase app for notifications
54
- await switch(env) {
55
- DevEnvironment() => Firebase.initializeApp(
56
- options: firebase_dev.DefaultFirebaseOptions.currentPlatform,
57
- ),
58
- ProdEnvironment() => Firebase.initializeApp(
59
- // Firebase is used here only for push notifications (FCM) and Remote Config.
60
- // If you use a single Firebase project for dev and prod (most common), this is correct.
61
- // If you have a separate Firebase project for production:
62
- // 1. Run: flutterfire configure --project=YOUR_PROD_PROJECT_ID --out=lib/firebase_options_prod.dart
63
- // 2. Import it: import 'package:kasy_kit/firebase_options_prod.dart' as firebase_prod;
64
- // 3. Replace the line below with: options: firebase_prod.DefaultFirebaseOptions.currentPlatform,
65
- options: firebase_dev.DefaultFirebaseOptions.currentPlatform,
66
- ),
67
- };
68
-
69
-
70
-
71
- // MUST be registered at the top-level BEFORE runApp().
72
- FirebaseMessaging.onBackgroundMessage(onBackgroundMessage);
73
-
74
- // initialize sentry for error reporting in production only
75
- if (env is DevEnvironment) {
76
- run(sharedPrefs);
77
- } else if (env is ProdEnvironment) {
78
- SentryFlutter.init((options) {
79
- options.dsn = env.sentryDsn;
80
- // 20% of traces will be sent to Sentry server. You should start with 1 and decrease it once you have more users.
81
- options.tracesSampleRate = 0.2;
82
- options.environment = env.name;
83
- }, appRunner: () => run(sharedPrefs));
84
- }
85
-
86
-
87
- }
88
-
89
- void run(SharedPreferences prefs) => runApp(
90
- TranslationProvider(
91
- child: ProviderScope(
92
- child: MyApp(
93
- sharedPreferences: prefs,
94
- ),
95
- ),
96
- ),
97
- );
98
-
99
-
100
- // use this if you want to define different themes for different platforms
101
- // notifier: AppTheme.adaptive(
102
- // defaultTextTheme: KasyTextTheme.build(),
103
- // ios: const IosThemeFactory(),
104
- // android: const AndroidThemeFactory(),
105
- // web: const WebThemeFactory(),
106
- // lightColors: KasyColors.light(),
107
- // darkColors: KasyColors.dark(),
108
- // mode: ThemeMode.dark,
109
- // ),
110
- // See ./docs/theme.md for more details
111
- class MyApp extends ConsumerStatefulWidget {
112
- final SharedPreferences sharedPreferences;
113
-
114
- const MyApp({
115
- super.key,
116
- required this.sharedPreferences,
117
- });
118
-
119
- @override
120
- ConsumerState<MyApp> createState() => _MyAppState();
121
- }
122
-
123
- class _MyAppState extends ConsumerState<MyApp> {
124
- late final AppTheme _appTheme;
125
-
126
- @override
127
- void initState() {
128
- super.initState();
129
- _appTheme = AppTheme.uniform(
130
- sharedPreferences: widget.sharedPreferences,
131
- themeFactory: const UniversalThemeFactory(),
132
- lightColors: KasyColors.light(),
133
- darkColors: KasyColors.dark(),
134
- textTheme: KasyTextTheme.build(),
135
- defaultMode: ThemeMode.system,
136
- );
137
- }
138
-
139
- @override
140
- void dispose() {
141
- _appTheme.dispose();
142
- super.dispose();
143
- }
144
-
145
- // This widget is the root of your application.
146
- @override
147
- Widget build(BuildContext context) {
148
- ErrorWidget.builder = (FlutterErrorDetails details) {
149
- return AppErrorWidget(error: details);
150
- };
151
- final goRouter = ref.watch(goRouterProvider);
152
-
153
- return ThemeProvider(
154
- notifier: _appTheme,
155
- child: Builder(builder: (context) {
156
- return WebDevicePreview.wrap(
157
- child: DevInspector.wrap(
158
- child: MaterialApp.router(
159
- title: 'Kasy',
160
- scaffoldMessengerKey: devInspectorRootScaffoldMessengerKey,
161
- theme: ThemeProvider.of(context).light,
162
- darkTheme: ThemeProvider.of(context).dark,
163
- themeMode: ThemeProvider.of(context).mode,
164
- routerConfig: goRouter,
165
- localizationsDelegates: const [
166
- GlobalMaterialLocalizations.delegate,
167
- GlobalWidgetsLocalizations.delegate,
168
- GlobalCupertinoLocalizations.delegate,
169
- ],
170
- locale: TranslationProvider.of(context).flutterLocale,
171
- supportedLocales: AppLocaleUtils.supportedLocales,
172
- builder: (context, child) => Initializer(
173
- services: [
174
- sharedPreferencesProvider,
175
- remoteConfigApiProvider,
176
- notificationsSettingsProvider,
177
- notificationRepositoryProvider,
178
- subscriptionRepositoryProvider,
179
- userStateNotifierProvider.notifier,
180
- analyticsApiProvider,
181
- facebookEventApiProvider,
182
- ],
183
- onReady: DevicePreview.appBuilder(context, child),
184
- onError: (_, error) => InitializationErrorPage(error: error),
185
- onLoading: Scaffold(
186
- body: Center(
187
- child: CircularProgressIndicator.adaptive(
188
- valueColor:
189
- AlwaysStoppedAnimation<Color>(context.colors.primary),
190
- ),
191
- ),
192
- ),
193
- ),
194
- ),
195
- ),
196
- );
197
- }),
198
- );
199
- }
200
- }
201
-
202
- /// This is an example of a more user friendly error widget
203
- /// By default Flutter will show a red screen with the error in debug mode
204
- /// and a grey screen in release mode
205
- class AppErrorWidget extends StatelessWidget {
206
- final FlutterErrorDetails? error;
207
-
208
- const AppErrorWidget({super.key, this.error});
209
-
210
- @override
211
- Widget build(BuildContext context) {
212
- return Container(
213
- padding: const EdgeInsets.all(16),
214
- color: Colors.orangeAccent,
215
- child: Column(
216
- mainAxisAlignment: MainAxisAlignment.center,
217
- children: [
218
- const Text(
219
- 'Oups!',
220
- style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
221
- ),
222
- const SizedBox(height: 8),
223
- const Text(
224
- 'Sorry, Something went wrong',
225
- style: TextStyle(color: Colors.white),
226
- ),
227
- const SizedBox(height: 8),
228
- Text(
229
- '${error?.exception}\n',
230
- style: const TextStyle(color: Colors.white, fontSize: 10),
231
- ),
232
- ],
233
- ),
234
- );
235
- }
236
- }
237
-
238
- class InitializationErrorPage extends StatelessWidget {
239
- final String error;
240
-
241
- const InitializationErrorPage({super.key, required this.error});
242
-
243
- @override
244
- Widget build(BuildContext context) {
245
- return Scaffold(
246
- body: Padding(
247
- padding: const EdgeInsets.all(24.0),
248
- child: Column(
249
- mainAxisAlignment: MainAxisAlignment.center,
250
- crossAxisAlignment: CrossAxisAlignment.stretch,
251
- spacing: 8,
252
- children: [
253
- Text(
254
- 'Cannot start app',
255
- style: context.textTheme.titleLarge,
256
- ),
257
- Text(
258
- 'Check your internet connection and start again',
259
- style: context.textTheme.bodyLarge?.copyWith(
260
- color: context.colors.grey3,
261
- ),
262
- ),
263
- if (kDebugMode)
264
- Text(
265
- "developper mode error: $error",
266
- style: context.textTheme.bodyLarge?.copyWith(
267
- color: context.colors.error,
268
- ),
269
- ),
270
- ],
271
- ),
272
- ),
273
- );
274
- }
275
- }
@@ -1,133 +0,0 @@
1
- import 'package:flutter/material.dart';
2
- import 'package:flutter_riverpod/flutter_riverpod.dart';
3
- import 'package:go_router/go_router.dart';
4
- import 'package:kasy_kit/core/bottom_menu/bottom_menu.dart';
5
- import 'package:kasy_kit/core/config/features.dart';
6
- import 'package:kasy_kit/core/data/api/analytics_api.dart';
7
- import 'package:kasy_kit/core/guards/user_info_guard.dart';
8
- import 'package:kasy_kit/core/widgets/page_not_found.dart';
9
- import 'package:kasy_kit/features/authentication/ui/phone_auth_page.dart';
10
- import 'package:kasy_kit/features/authentication/ui/recover_password_page.dart';
11
- import 'package:kasy_kit/features/authentication/ui/signin_page.dart';
12
- import 'package:kasy_kit/features/authentication/ui/signup_page.dart';
13
- import 'package:kasy_kit/features/feedbacks/ui/component/add_feature_form.dart';
14
- import 'package:kasy_kit/features/feedbacks/ui/feedback_page.dart';
15
- import 'package:kasy_kit/features/llm_chat/llm_chat_page.dart';
16
- import 'package:kasy_kit/features/local_reminder/ui/reminder_page.dart';
17
- import 'package:kasy_kit/features/onboarding/ui/onboarding_page.dart';
18
- import 'package:kasy_kit/features/subscription/ui/premium_page.dart';
19
-
20
- final goRouterProvider = Provider<GoRouter>(
21
- (ref) => generateRouter(),
22
- );
23
-
24
- extension GoRouterRiverpod on Ref {
25
- GoRouter get goRouter => read(goRouterProvider);
26
- }
27
-
28
- final navigatorKey = GlobalKey<NavigatorState>();
29
-
30
- GoRouter generateRouter({
31
- String? initialLocation,
32
- List<GoRoute>? additionalRoutes,
33
- List<NavigatorObserver>? observers,
34
- }) {
35
- return GoRouter(
36
- initialLocation: '/',
37
- navigatorKey: navigatorKey,
38
- errorBuilder: (context, state) => const PageNotFound(),
39
- observers: [
40
- AnalyticsObserver(
41
- analyticsApi: MixpanelAnalyticsApi.instance(),
42
- ),
43
-
44
- ...?observers,
45
- ],
46
- routes: [
47
- GoRoute(
48
- name: 'home',
49
- path: '/',
50
- builder: (context, state) => const UserInfosGuard(
51
- fallbackRoute: '/onboarding',
52
- child: BottomMenu(),
53
- ),
54
- ),
55
- GoRoute(
56
- name: 'onboarding',
57
- path: '/onboarding',
58
- builder: (context, state) => const OnboardingPage(),
59
- ),
60
- GoRoute(
61
- name: 'signup',
62
- path: '/signup',
63
- builder: (context, state) => const SignupPage(),
64
- ),
65
- GoRoute(
66
- name: 'signin',
67
- path: '/signin',
68
- builder: (context, state) => const SigninPage(),
69
- ),
70
- GoRoute(
71
- name: 'signinWithPhone',
72
- path: '/signinWithPhone',
73
- builder: (context, state) => const PhoneAuthPage(),
74
- ),
75
- GoRoute(
76
- name: 'premium',
77
- path: '/premium',
78
- builder: (context, state) => const PremiumPage(),
79
- ),
80
- if (withFeedback) ...[
81
- GoRoute(
82
- name: 'feedback',
83
- path: '/feedback',
84
- builder: (context, state) => const FeedbackPage(),
85
- ),
86
- GoRoute(
87
- name: 'feedback_new',
88
- path: '/feedback/new',
89
- builder: (context, state) => const AddFeatureComponent(),
90
- ),
91
- ],
92
- if (withLlmChat)
93
- GoRoute(
94
- name: 'assistant',
95
- path: '/assistant',
96
- builder: (context, state) => const LlmChatPage(),
97
- ),
98
- if (withLocalNotifications)
99
- GoRoute(
100
- name: 'reminder',
101
- path: '/reminder',
102
- builder: (context, state) => const ReminderPage(),
103
- ),
104
- GoRoute(
105
- name: 'notifications',
106
- path: '/notifications',
107
- builder: (context, state) => const UserInfosGuard(
108
- fallbackRoute: '/onboarding',
109
- child: BottomMenu(initialRoute: 'notifications'),
110
- ),
111
- ),
112
- GoRoute(
113
- name: 'settings',
114
- path: '/settings',
115
- builder: (context, state) => const UserInfosGuard(
116
- fallbackRoute: '/onboarding',
117
- child: BottomMenu(initialRoute: 'settings'),
118
- ),
119
- ),
120
- GoRoute(
121
- name: 'recover_password',
122
- path: '/recover_password',
123
- builder: (context, state) => const RecoverPasswordPage(),
124
- ),
125
- GoRoute(
126
- name: '404',
127
- path: '/404',
128
- builder: (context, state) => const PageNotFound(),
129
- ),
130
- ],
131
- );
132
- }
133
-
@@ -1,211 +0,0 @@
1
- import 'package:flutter/material.dart';
2
- import 'package:flutter_animate/flutter_animate.dart';
3
- import 'package:flutter_riverpod/flutter_riverpod.dart';
4
- import 'package:go_router/go_router.dart';
5
- import 'package:kasy_kit/components/components.dart';
6
- import 'package:kasy_kit/core/data/api/analytics_api.dart';
7
- import 'package:kasy_kit/core/rating/providers/rating_repository.dart';
8
- import 'package:kasy_kit/core/states/user_state_notifier.dart';
9
- import 'package:kasy_kit/core/theme/theme.dart';
10
- import 'package:kasy_kit/core/widgets/responsive_layout.dart';
11
- import 'package:kasy_kit/i18n/translations.g.dart';
12
- import 'package:logger/logger.dart';
13
-
14
- Future<bool> showReviewDialog(WidgetRef ref, {bool force = false}) {
15
- if (!ref.context.mounted) {
16
- return Future.value(false);
17
- }
18
- final ratingRepository = ref.watch(ratingRepositoryProvider);
19
- final userState = ref.watch(userStateNotifierProvider);
20
- final ratingFuture = ratingRepository.getReview(userState.user);
21
-
22
- return ratingFuture.then((rating) {
23
- final shouldAsk = rating.shouldAsk();
24
- Logger().d('should Ask for review: $shouldAsk');
25
- if (!shouldAsk && !force) {
26
- return false;
27
- }
28
- if (!ref.context.mounted) {
29
- return false;
30
- }
31
- showDialog(
32
- context: ref.context,
33
- barrierDismissible: false,
34
- builder: (context) {
35
- ratingRepository.delay();
36
- return Animate(
37
- effects: const [
38
- FadeEffect(
39
- delay: Duration(milliseconds: 100),
40
- duration: Duration(milliseconds: 300),
41
- ),
42
- MoveEffect(
43
- delay: Duration(milliseconds: 100),
44
- duration: Duration(milliseconds: 450),
45
- curve: Curves.easeOut,
46
- begin: Offset(0, 50),
47
- end: Offset.zero,
48
- ),
49
- ],
50
- child: Dialog(
51
- backgroundColor: Colors.transparent,
52
- child: DeviceSizeBuilder(
53
- builder: (device) {
54
- final maxWidth = switch (device) {
55
- DeviceType.medium => MediaQuery.of(context).size.width - KasySpacing.xl,
56
- _ => 550.0,
57
- };
58
- return ConstrainedBox(
59
- constraints: BoxConstraints(maxWidth: maxWidth),
60
- child: Center(
61
- child: Container(
62
- decoration: BoxDecoration(
63
- color: context.colors.background,
64
- borderRadius: KasyRadius.lgBorderRadius,
65
- border: Border.all(
66
- color: context.colors.onBackground.withValues(
67
- alpha: .3,
68
- ),
69
- width: 2,
70
- strokeAlign: BorderSide.strokeAlignOutside,
71
- ),
72
- ),
73
- child: Column(
74
- mainAxisSize: MainAxisSize.min,
75
- crossAxisAlignment: CrossAxisAlignment.stretch,
76
- children: [
77
- Flexible(
78
- child: Stack(
79
- children: [
80
- ClipRRect(
81
- borderRadius: const BorderRadius.only(
82
- topLeft: Radius.circular(KasyRadius.lg),
83
- topRight: Radius.circular(KasyRadius.lg),
84
- ),
85
- child: Image.asset(
86
- 'assets/images/review.png',
87
- fit: BoxFit.fitWidth,
88
- width: maxWidth,
89
- ),
90
- ),
91
- Positioned(
92
- top: KasySpacing.md,
93
- left: KasySpacing.md,
94
- child: CloseIcon(
95
- onExit: () {
96
- ref
97
- .read(analyticsApiProvider)
98
- .logEvent('rating_popup_close', {});
99
- rating.delay().then((_) {
100
- if (!context.mounted) return;
101
- Navigator.of(context).pop();
102
- });
103
- },
104
- ),
105
- ),
106
- ],
107
- ),
108
- ),
109
- const SizedBox(height: KasySpacing.md),
110
- Flexible(
111
- flex: 0,
112
- child: Padding(
113
- padding: const EdgeInsets.symmetric(
114
- horizontal: KasySpacing.smd,
115
- ),
116
- child: Text(
117
- Translations.of(context).review_popup.title,
118
- textAlign: TextAlign.center,
119
- style: context.textTheme.headlineSmall,
120
- ),
121
- ),
122
- ),
123
- const SizedBox(height: KasySpacing.md),
124
- Padding(
125
- padding: const EdgeInsets.symmetric(
126
- horizontal: KasySpacing.lg,
127
- ),
128
- child: Text(
129
- Translations.of(context).review_popup.description,
130
- textAlign: TextAlign.center,
131
- style: context.textTheme.bodyMedium,
132
- ),
133
- ),
134
- const SizedBox(height: KasySpacing.lg),
135
- Padding(
136
- padding: const EdgeInsets.symmetric(
137
- horizontal: KasySpacing.md,
138
- ),
139
- child: KasyButton(
140
- label: Translations.of(context).review_popup.rate_button,
141
- expand: true,
142
- onPressed: () {
143
- ref.read(analyticsApiProvider).logEvent('rating_popup_show', {});
144
- ratingRepository
145
- .rate()
146
- .then((res) => rating.review())
147
- .then((_) {
148
- if (!context.mounted) return;
149
- Navigator.of(context).pop();
150
- });
151
- },
152
- ),
153
- ),
154
- const SizedBox(height: KasySpacing.sm),
155
- KasyButton(
156
- label: Translations.of(context).review_popup.cancel_button,
157
- variant: KasyButtonVariant.tertiary,
158
- expand: true,
159
- onPressed: () => Navigator.of(context).pop(true),
160
- ),
161
- const SizedBox(height: KasySpacing.sm),
162
- ],
163
- ),
164
- ),
165
- ),
166
- );
167
- },
168
- ),
169
- ),
170
- );
171
- },
172
- ).then((shouldOpenFeedbackPage) {
173
- if (shouldOpenFeedbackPage == true && ref.context.mounted) {
174
- ref.context.push("/feedback");
175
- }
176
- });
177
- return true;
178
- });
179
- }
180
-
181
- class CloseIcon extends StatelessWidget {
182
- final VoidCallback onExit;
183
-
184
- const CloseIcon({super.key, required this.onExit});
185
-
186
- @override
187
- Widget build(BuildContext context) {
188
- return ClipOval(
189
- child: Material(
190
- color: Colors.transparent,
191
- child: InkWell(
192
- onTap: () => onExit.call(),
193
- child: Ink(
194
- width: 32,
195
- height: 32,
196
- // padding: const EdgeInsets.all(6),
197
- decoration: BoxDecoration(
198
- color: context.colors.background,
199
- shape: BoxShape.circle,
200
- ),
201
- child: Icon(
202
- KasyIcons.close,
203
- color: context.colors.onBackground,
204
- size: 21,
205
- ),
206
- ),
207
- ),
208
- ),
209
- );
210
- }
211
- }