kasy-cli 1.19.3 → 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.
- package/README.md +11 -3
- package/bin/kasy.js +1 -0
- package/lib/commands/new.js +87 -37
- package/lib/commands/run.js +14 -0
- package/lib/scaffold/backends/api/patch/lib/core/data/api/meta_ads_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +4 -5
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_vote_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/features/llm_chat/providers/llm_chat_notifier.dart +317 -0
- package/lib/scaffold/backends/api/patch/lib/features/notifications/api/device_api.dart +40 -1
- package/lib/scaffold/backends/api/patch/lib/features/notifications/api/entities/notifications_entity.dart +2 -0
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/api/entities/user_info_entity.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/features/subscription/api/entities/subscription_entity.dart +1 -1
- package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -2
- package/lib/scaffold/backends/api/pubspec.yaml.tpl +2 -0
- package/lib/scaffold/backends/firebase/enable-auth-via-cli.js +11 -8
- package/lib/scaffold/backends/firebase/setup-from-scratch.js +91 -2
- package/lib/scaffold/backends/supabase/deploy.js +56 -3
- package/lib/scaffold/backends/supabase/patch/lib/core/data/api/storage_api.dart +5 -11
- package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +2 -2
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/device_api.dart +31 -1
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/api/entities/user_info_entity.dart +1 -1
- package/lib/scaffold/backends/supabase/patch/lib/features/subscription/api/entities/subscription_entity.dart +1 -1
- package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +2 -0
- package/lib/scaffold/catalog.js +2 -2
- package/lib/scaffold/engine.js +5 -0
- package/lib/scaffold/generate.js +23 -3
- package/lib/scaffold/shared/generator-utils.js +303 -56
- package/lib/scaffold/shared/post-build.js +11 -0
- package/lib/utils/i18n/messages-en.js +6 -1
- package/lib/utils/i18n/messages-es.js +6 -1
- package/lib/utils/i18n/messages-pt.js +6 -1
- package/package.json +1 -1
- package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
- package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
- package/templates/firebase/lib/components/kasy_date_picker.dart +14 -8
- package/templates/firebase/lib/components/kasy_sidebar_pro.dart +1150 -0
- package/templates/firebase/lib/components/kasy_tabs.dart +156 -43
- package/templates/firebase/lib/components/kasy_text_field.dart +37 -34
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +13 -82
- package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +6 -102
- package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +8 -1
- package/templates/firebase/lib/core/dev_inspector/dev_inspector.dart +433 -243
- package/templates/firebase/lib/core/dev_inspector/dev_inspector_service.dart +198 -83
- package/templates/firebase/lib/core/icons/kasy_icons.dart +1 -0
- package/templates/firebase/lib/core/states/user_state_notifier.dart +8 -10
- package/templates/firebase/lib/core/theme/colors.dart +6 -2
- package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +119 -19
- package/templates/firebase/lib/core/widgets/kasy_hover.dart +68 -27
- package/templates/firebase/lib/features/home/home_components_page.dart +11 -14
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +121 -66
- package/templates/firebase/lib/features/home/home_page.dart +7 -8
- package/templates/firebase/lib/features/settings/settings_page.dart +27 -146
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +16 -3
- package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +22 -5
- package/templates/firebase/lib/i18n/en.i18n.json +3 -1
- package/templates/firebase/lib/i18n/es.i18n.json +3 -1
- package/templates/firebase/lib/i18n/pt.i18n.json +3 -1
- package/templates/firebase/lib/router.dart +60 -0
- package/templates/firebase/pubspec.yaml +6 -4
- package/templates/firebase/test/core/bottom_menu/detail_route_menu_test.dart +57 -0
- package/templates/firebase/web/index.html +7 -17
- package/lib/scaffold/backends/api/patch/lib/core/rating/widgets/review_popup.dart +0 -211
- package/lib/scaffold/backends/api/patch/lib/features/notifications/providers/models/notification.dart +0 -185
- package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +0 -73
- package/lib/scaffold/backends/api/patch/lib/main.dart +0 -275
- package/lib/scaffold/backends/api/patch/lib/router.dart +0 -133
- package/lib/scaffold/backends/supabase/patch/lib/core/rating/widgets/review_popup.dart +0 -211
- package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/ui/component/add_feature_form.dart +0 -199
- package/lib/scaffold/backends/supabase/patch/lib/features/notifications/providers/models/notification.dart +0 -174
- package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +0 -73
- package/lib/scaffold/backends/supabase/patch/lib/main.dart +0 -307
- package/lib/scaffold/backends/supabase/patch/lib/router.dart +0 -133
- package/templates/firebase/lib/firebase_options.dart +0 -75
|
@@ -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
|
-
}
|