flu-cli-core 1.0.5 → 1.1.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.
Files changed (117) hide show
  1. package/README.md +9 -0
  2. package/dist/chunk-BGYZU6TU.js +466 -0
  3. package/dist/chunk-QGM4M3NI.js +37 -0
  4. package/dist/factory-LM2CTHPW.js +7 -0
  5. package/dist/factory-P6ABQFH3.js +7 -0
  6. package/dist/index.cjs +17765 -3244
  7. package/dist/index.d.cts +783 -99
  8. package/dist/index.d.ts +783 -99
  9. package/dist/index.js +17322 -2942
  10. package/dist/upgrade_snippets-BJ6CQY5Q.js +9 -0
  11. package/package.json +3 -3
  12. package/templates/README.md +12 -0
  13. package/templates/core_files/auth/auth_middleware.dart.template +33 -0
  14. package/templates/core_files/auth/auth_service.dart.template +22 -0
  15. package/templates/core_files/auth/auth_viewmodel_mixin.dart.template +9 -0
  16. package/templates/core_files/auth/index.dart.template +4 -0
  17. package/templates/core_files/base/base_service.dart.template +12 -0
  18. package/templates/core_files/base/index.dart.template +3 -0
  19. package/templates/core_files/config/agreement_document_page.dart.template +220 -0
  20. package/templates/core_files/config/app_agreement.dart.template +297 -0
  21. package/templates/core_files/config/app_config.dart.template +81 -22
  22. package/templates/core_files/config/app_env.dart.template +107 -0
  23. package/templates/core_files/config/app_initializer.dart.template +16 -23
  24. package/templates/core_files/config/index.dart.template +4 -1
  25. package/templates/core_files/config/privacy_dialog.dart.template +158 -0
  26. package/templates/core_files/index.dart.template +3 -0
  27. package/templates/core_files/mixins/page/keep_alive_mixin.dart.template +6 -0
  28. package/templates/core_files/mixins/page/scroll_controller_mixin.dart.template +7 -0
  29. package/templates/core_files/mixins/service/request_guard_mixin.dart.template +18 -0
  30. package/templates/core_files/mixins/viewmodel/debounce_mixin.dart.template +18 -0
  31. package/templates/core_files/network/app_http.dart.template +19 -4
  32. package/templates/core_files/network/index.dart.template +4 -0
  33. package/templates/core_files/network/interceptors/global_params_interceptor.dart.template +77 -0
  34. package/templates/core_files/network/interceptors/index.dart.template +3 -0
  35. package/templates/core_files/network/network_monitor.dart.template +18 -0
  36. package/templates/core_files/network/response_adapter.dart.template +8 -19
  37. package/templates/core_files/router/app_routes.dart.template +3 -6
  38. package/templates/core_files/storage/storage_keys.dart.template +6 -0
  39. package/templates/core_files/theme/app_color_config.dart.template +32 -0
  40. package/templates/core_files/theme/app_text_size_config.dart.template +22 -0
  41. package/templates/core_files/theme/app_text_style_config.dart.template +139 -0
  42. package/templates/core_files/theme/app_theme.dart.template +72 -12
  43. package/templates/core_files/theme/index.dart.template +3 -0
  44. package/templates/core_files/utils/loading_util.dart.template +1 -1
  45. package/templates/examples/eg_list_page.dart.template +1 -2
  46. package/templates/examples/eg_service.dart.template +27 -4
  47. package/templates/examples/home_feed_service.dart.template +37 -0
  48. package/templates/helper_examples/image_picker_example_page.dart.template +289 -0
  49. package/templates/helper_examples/index.dart.template +4 -0
  50. package/templates/helper_examples/payment_shell_example_page.dart.template +67 -0
  51. package/templates/helper_examples/permission_example_page.dart.template +365 -0
  52. package/templates/helper_examples/webview_example_page.dart.template +44 -0
  53. package/templates/helpers/image_picker/README.md.template +30 -0
  54. package/templates/helpers/image_picker/index.dart.template +73 -0
  55. package/templates/helpers/payment/README.md.template +29 -0
  56. package/templates/helpers/payment/index.dart.template +66 -0
  57. package/templates/helpers/permission/README.md.template +30 -0
  58. package/templates/helpers/permission/index.dart.template +67 -0
  59. package/templates/helpers/webview/README.md.template +29 -0
  60. package/templates/helpers/webview/index.dart.template +88 -0
  61. package/templates/starter_project/.env.dev.template +14 -0
  62. package/templates/starter_project/.env.prod.example.template +14 -0
  63. package/templates/starter_project/.env.staging.template +14 -0
  64. package/templates/starter_project/.vscode/launch.json.template +54 -0
  65. package/templates/starter_project/DEVELOPER_GUIDE.md.template +150 -0
  66. package/templates/starter_project/README.md.template +99 -0
  67. package/templates/starter_project/analysis_options.yaml.template +28 -0
  68. package/templates/starter_project/lib/app.dart.template +22 -0
  69. package/templates/starter_project/lib/main.dart.template +34 -0
  70. package/templates/starter_project/lib/pages/splash_page.dart.template +154 -0
  71. package/templates/template_clean/lib/features/home/data/datasources/index.dart +1 -0
  72. package/templates/template_clean/lib/features/home/data/models/index.dart +1 -0
  73. package/templates/template_clean/lib/features/home/domain/index.dart +1 -0
  74. package/templates/template_clean/lib/features/home/presentation/pages/home_page.dart +290 -0
  75. package/templates/template_clean/lib/features/home/presentation/pages/index.dart +2 -0
  76. package/templates/template_clean/lib/features/home/presentation/pages/splash_page.dart +154 -0
  77. package/templates/template_clean/lib/features/home/presentation/viewmodels/home_viewmodel.dart +17 -0
  78. package/templates/template_clean/lib/features/index.dart +2 -0
  79. package/templates/template_clean/lib/features/user/data/datasources/home_feed_service.dart +37 -0
  80. package/templates/template_clean/lib/features/user/data/datasources/index.dart +4 -0
  81. package/templates/template_clean/lib/features/user/data/models/index.dart +3 -0
  82. package/templates/template_clean/lib/features/user/data/models/user.dart +15 -0
  83. package/templates/template_clean/lib/features/user/domain/index.dart +1 -0
  84. package/templates/template_clean/lib/features/user/presentation/pages/index.dart +1 -0
  85. package/templates/template_clean/lib/features/user/presentation/pages/user_list_page.dart +27 -0
  86. package/templates/template_clean/lib/features/user/presentation/viewmodels/user_list_viewmodel.dart +88 -0
  87. package/templates/template_clean/lib/features/user/presentation/widgets/user_item_card.dart +24 -0
  88. package/templates/template_clean/lib/shared/extensions/index.dart +1 -0
  89. package/templates/template_clean/lib/shared/widgets/index.dart +1 -0
  90. package/templates/template_lite/lib/models/index.dart +1 -0
  91. package/templates/template_lite/lib/pages/home_page.dart +290 -0
  92. package/templates/template_lite/lib/pages/index.dart +3 -0
  93. package/templates/template_lite/lib/pages/splash_page.dart +154 -0
  94. package/templates/template_lite/lib/pages/user_list_page.dart +29 -0
  95. package/templates/template_lite/lib/services/home_feed_service.dart +37 -0
  96. package/templates/template_lite/lib/services/index.dart +5 -0
  97. package/templates/template_lite/lib/utils/index.dart +1 -0
  98. package/templates/template_lite/lib/viewmodels/home_viewmodel.dart +34 -0
  99. package/templates/template_lite/lib/viewmodels/index.dart +2 -0
  100. package/templates/template_lite/lib/viewmodels/user_list_viewmodel.dart +103 -0
  101. package/templates/template_lite/lib/widgets/index.dart +1 -0
  102. package/templates/template_lite/lib/widgets/user_item_widget.dart +57 -0
  103. package/templates/template_modular/lib/features/home/index.dart +2 -0
  104. package/templates/template_modular/lib/features/home/models/index.dart +1 -0
  105. package/templates/template_modular/lib/features/home/pages/home_page.dart +290 -0
  106. package/templates/template_modular/lib/features/home/pages/index.dart +2 -0
  107. package/templates/template_modular/lib/features/home/pages/splash_page.dart +154 -0
  108. package/templates/template_modular/lib/features/home/services/index.dart +1 -0
  109. package/templates/template_modular/lib/features/home/viewmodels/home_viewmodel.dart +17 -0
  110. package/templates/template_modular/lib/features/index.dart +2 -0
  111. package/templates/template_modular/lib/features/user/index.dart +6 -0
  112. package/templates/template_modular/lib/features/user/pages/user_list_page.dart +26 -0
  113. package/templates/template_modular/lib/features/user/services/home_feed_service.dart +37 -0
  114. package/templates/template_modular/lib/features/user/viewmodels/user_list_viewmodel.dart +103 -0
  115. package/templates/template_modular/lib/features/user/widgets/user_item_widget.dart +24 -0
  116. package/templates/template_modular/lib/shared/utils/index.dart +1 -0
  117. package/templates/template_modular/lib/shared/widgets/index.dart +1 -0
package/README.md CHANGED
@@ -55,6 +55,15 @@ ProjectGenerator
55
55
  - **Android**: APK / AAB 自动构建
56
56
  - **iOS**: IPA 自动构建
57
57
 
58
+ ### 6. AI + SKILL(规则投影)
59
+
60
+ 通过 `.flu-cli.json`(单一事实来源)投影生成多份 AI 可读规则文件,保证 AI/CLI/VSCode 产出一致:
61
+
62
+ - `.cursor/rules/flu-project.mdc`
63
+ - `CLAUDE.md`
64
+ - `AI_RULES.md`
65
+ - `.agent/skills/<slug>/SKILL.md`
66
+
58
67
  ## 💡 架构优势
59
68
 
60
69
  - **极简核心** — `ProjectGenerator.ts` 从 1500 行精简至 100 行
@@ -0,0 +1,466 @@
1
+ // src/generators/tasks/adapters/provider_adapter.ts
2
+ var ProviderAdapter = class {
3
+ name;
4
+ constructor(name = "provider") {
5
+ this.name = name;
6
+ }
7
+ getDependencies() {
8
+ return this.name === "provider" ? ["provider: ^6.1.1"] : [];
9
+ }
10
+ getBaseViewModelTemplate(context) {
11
+ return null;
12
+ }
13
+ getBasePageParent(isListPage) {
14
+ return isListPage ? "BaseListPage" : "BasePage";
15
+ }
16
+ getBaseViewModelParent(isListPage) {
17
+ return isListPage ? "BaseListViewModel" : "BaseViewModel";
18
+ }
19
+ getImports(relativeCorePath) {
20
+ return [`import '${relativeCorePath}';`];
21
+ }
22
+ patchAppEntry(content, context) {
23
+ return content;
24
+ }
25
+ getCommonInfo() {
26
+ return ` ViewState _state = ViewState.idle;
27
+ String? _errorMessage;
28
+ bool _isRefreshing = false;
29
+
30
+ // ==================== Getters ====================
31
+ // \u5F53\u524D\u89C6\u56FE\u72B6\u6001
32
+ ViewState get state => _state;
33
+ // \u9519\u8BEF\u4FE1\u606F
34
+ String? get errorMessage => _errorMessage;
35
+ // \u662F\u5426\u6B63\u5728\u52A0\u8F7D
36
+ bool get isLoading => _state == ViewState.loading;
37
+ // \u662F\u5426\u52A0\u8F7D\u5931\u8D25
38
+ bool get isError => _state == ViewState.error;
39
+ // \u662F\u5426\u52A0\u8F7D\u6210\u529F
40
+ bool get isSuccess => _state == ViewState.success;
41
+ // \u662F\u5426\u7A7A\u95F2\u72B6\u6001
42
+ bool get isIdle => _state == ViewState.idle;
43
+ // \u662F\u5426\u6B63\u5728\u5237\u65B0
44
+ bool get isRefreshing => _isRefreshing;
45
+
46
+ // ==================== \u72B6\u6001\u8BBE\u7F6E ====================
47
+
48
+ /// \u8BBE\u7F6E\u89C6\u56FE\u72B6\u6001
49
+ void setState(ViewState state, {String? error}) {
50
+ _state = state;
51
+ _errorMessage = error;
52
+ notifyListeners();
53
+ }
54
+
55
+ /// \u8BBE\u7F6E\u5237\u65B0\u72B6\u6001
56
+ void setRefreshing(bool refreshing) {
57
+ _isRefreshing = refreshing;
58
+ notifyListeners();
59
+ }
60
+ `;
61
+ }
62
+ };
63
+
64
+ // src/generators/tasks/adapters/getx_adapter.ts
65
+ var GetXAdapter = class {
66
+ name = "getx";
67
+ getDependencies() {
68
+ return ["get: ^4.6.6"];
69
+ }
70
+ getBaseViewModelTemplate(context) {
71
+ return `import 'package:get/get.dart';
72
+
73
+ enum ViewState { idle, loading, success, error }
74
+
75
+ class BaseViewModel extends GetxController {
76
+ ViewState _state = ViewState.idle;
77
+ String? _errorMessage;
78
+ bool _isRefreshing = false;
79
+ bool _disposed = false;
80
+
81
+ // ==================== Getters ====================
82
+ ViewState get state => _state;
83
+ String? get errorMessage => _errorMessage;
84
+ bool get isLoading => _state == ViewState.loading;
85
+ bool get isError => _state == ViewState.error;
86
+ bool get isSuccess => _state == ViewState.success;
87
+ bool get isIdle => _state == ViewState.idle;
88
+ bool get isRefreshing => _isRefreshing;
89
+ // GetX \u4F7F\u7528 isClosed \u5224\u65AD\u662F\u5426\u5DF2\u91CA\u653E
90
+ bool get isDisposed => _disposed || isClosed;
91
+
92
+ // ==================== \u72B6\u6001\u8BBE\u7F6E ====================
93
+ void setState(ViewState state, {String? error}) {
94
+ if (_disposed || isClosed) return;
95
+ _state = state;
96
+ _errorMessage = error;
97
+ update(); // GetX \u4F7F\u7528 update() \u800C\u975E notifyListeners()
98
+ }
99
+
100
+ void setRefreshing(bool refreshing) {
101
+ if (_disposed || isClosed) return;
102
+ _isRefreshing = refreshing;
103
+ update();
104
+ }
105
+
106
+ /// \u901A\u77E5\u6570\u636E\u53D8\u5316(\u4EC5\u7528\u4E8E\u5C40\u90E8\u5237\u65B0)
107
+ void notifyDataChange() {
108
+ if (_disposed || isClosed) return;
109
+ update();
110
+ }
111
+
112
+ // ==================== \u751F\u547D\u5468\u671F ====================
113
+ /// \u521D\u59CB\u5316\u94A9\u5B50
114
+ @override
115
+ Future<void> onInit() async {
116
+ super.onInit();
117
+ // \u5B50\u7C7B\u53EF\u4EE5\u91CD\u5199\u6B64\u65B9\u6CD5\u8FDB\u884C\u521D\u59CB\u5316
118
+ }
119
+
120
+ /// \u5237\u65B0\u6570\u636E(\u94A9\u5B50)
121
+ Future<void> refreshData() async {
122
+ // \u5B50\u7C7B\u53EF\u4EE5\u91CD\u5199\u6B64\u65B9\u6CD5\u5B9E\u73B0\u5237\u65B0\u903B\u8F91
123
+ }
124
+
125
+ @override
126
+ void onClose() {
127
+ _disposed = true;
128
+ super.onClose();
129
+ }
130
+ }
131
+ `;
132
+ }
133
+ getBasePageParent(isListPage) {
134
+ return isListPage ? "BaseListPage" : "BasePage";
135
+ }
136
+ getBaseViewModelParent(isListPage) {
137
+ return isListPage ? "BaseListViewModel" : "BaseViewModel";
138
+ }
139
+ getImports(relativeCorePath) {
140
+ return [`import '${relativeCorePath}';`];
141
+ }
142
+ /**
143
+ * 修改 app.dart
144
+ */
145
+ patchAppEntry(content, context) {
146
+ let raw = content;
147
+ if (!raw.includes("GetMaterialApp(")) {
148
+ raw = raw.replace(/MaterialApp\s*\(/, "GetMaterialApp(");
149
+ }
150
+ if (raw.includes("GetMaterialApp(") && !raw.includes("import 'package:get/get.dart'")) {
151
+ if (raw.includes("import 'package:flutter/material.dart';")) {
152
+ raw = raw.replace(
153
+ "import 'package:flutter/material.dart';",
154
+ "import 'package:flutter/material.dart';\nimport 'package:get/get.dart';"
155
+ );
156
+ } else {
157
+ raw = `import 'package:get/get.dart';
158
+ ` + raw;
159
+ }
160
+ }
161
+ if (raw.includes("routes: AppRoutes.routes")) {
162
+ raw = raw.replace("routes: AppRoutes.routes", "getPages: AppRoutes.pages");
163
+ }
164
+ if (raw.includes("navigatorKey: NavigatorUtil.navigatorKey")) {
165
+ raw = raw.replace(/navigatorKey:\s*NavigatorUtil\.navigatorKey\s*,?/g, "");
166
+ }
167
+ if (raw.includes("scaffoldMessengerKey: NavigatorUtil.scaffoldMessengerKey")) {
168
+ raw = raw.replace(
169
+ /scaffoldMessengerKey:\s*NavigatorUtil\.scaffoldMessengerKey\s*,?\s*\n?/g,
170
+ ""
171
+ );
172
+ }
173
+ return raw;
174
+ }
175
+ /**
176
+ * 修改 app_routes.dart
177
+ */
178
+ patchRoutes(content, context) {
179
+ let raw = content;
180
+ if (raw.includes("static List<GetPage> get pages")) {
181
+ return raw;
182
+ }
183
+ if (!raw.includes("import 'package:get/get.dart'")) {
184
+ if (raw.includes("import 'package:flutter/material.dart';")) {
185
+ raw = raw.replace(
186
+ "import 'package:flutter/material.dart';",
187
+ "import 'package:get/get.dart';"
188
+ );
189
+ } else {
190
+ raw = `import 'package:get/get.dart';
191
+ ` + raw;
192
+ }
193
+ }
194
+ const startMarker = "// __ROUTE_CONFIG_START__";
195
+ const endMarker = "// __ROUTE_CONFIG_END__";
196
+ const pagesGetter = `
197
+ /// GetX \u8DEF\u7531\u6620\u5C04
198
+ /// \u5728 app.dart \u4E2D\u4F7F\u7528: GetMaterialApp(getPages: AppRoutes.pages, ...)
199
+ static List<GetPage> get pages {
200
+ return [
201
+ GetPage(name: home, page: () => const HomePage()),
202
+ // --- \u5728\u6B64\u4E0B\u65B9\u6DFB\u52A0\u60A8\u7684\u81EA\u5B9A\u4E49\u8DEF\u7531 ---
203
+ ];
204
+ }
205
+ `;
206
+ const startIndex = raw.indexOf(startMarker);
207
+ const endIndex = raw.indexOf(endMarker);
208
+ if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
209
+ const before = raw.substring(0, startIndex);
210
+ const after = raw.substring(endIndex + endMarker.length);
211
+ raw = before + pagesGetter.trim() + after;
212
+ } else {
213
+ const standardRoutesPattern = /\s*\/\/\/\s*Material\s+路由映射[\s\S]*?static\s+Map<String,\s*WidgetBuilder>\s*get\s*routes\s*\{\s*return\s*\{[\s\S]*?\}\s*;\s*\}/;
214
+ if (standardRoutesPattern.test(raw)) {
215
+ raw = raw.replace(standardRoutesPattern, pagesGetter);
216
+ } else {
217
+ const lastBraceIndex = raw.lastIndexOf("}");
218
+ if (lastBraceIndex !== -1) {
219
+ raw = raw.slice(0, lastBraceIndex) + "\n" + pagesGetter + raw.slice(lastBraceIndex);
220
+ }
221
+ }
222
+ }
223
+ return raw;
224
+ }
225
+ };
226
+
227
+ // src/generators/tasks/adapters/bloc_adapter.ts
228
+ var BlocAdapter = class {
229
+ name = "bloc";
230
+ getDependencies() {
231
+ return ["flutter_bloc: ^8.1.3"];
232
+ }
233
+ getBaseViewModelTemplate(_context) {
234
+ return `import 'package:flutter_bloc/flutter_bloc.dart';
235
+
236
+ enum ViewState { idle, loading, success, error }
237
+
238
+ class BaseViewModel extends Cubit<ViewState> {
239
+ String? _errorMessage;
240
+ bool _isRefreshing = false;
241
+ bool _disposed = false;
242
+
243
+ BaseViewModel() : super(ViewState.idle);
244
+
245
+ String? get errorMessage => _errorMessage;
246
+ bool get isLoading => state == ViewState.loading;
247
+ bool get isError => state == ViewState.error;
248
+ bool get isSuccess => state == ViewState.success;
249
+ bool get isIdle => state == ViewState.idle;
250
+ bool get isRefreshing => _isRefreshing;
251
+ bool get isDisposed => _disposed;
252
+
253
+ void setState(ViewState state, {String? error}) {
254
+ if (_disposed) return;
255
+ _errorMessage = error;
256
+ emit(state);
257
+ }
258
+
259
+ void setRefreshing(bool refreshing) {
260
+ if (_disposed) return;
261
+ _isRefreshing = refreshing;
262
+ emit(state);
263
+ }
264
+
265
+ void notifyDataChange() {
266
+ if (_disposed) return;
267
+ emit(state);
268
+ }
269
+
270
+ Future<void> onInit() async {}
271
+ Future<void> refreshData() async {}
272
+
273
+ @override
274
+ Future<void> close() {
275
+ _disposed = true;
276
+ return super.close();
277
+ }
278
+ }
279
+ `;
280
+ }
281
+ getBasePageParent(isListPage) {
282
+ return isListPage ? "BaseListPage" : "BasePage";
283
+ }
284
+ getBaseViewModelParent(isListPage) {
285
+ return isListPage ? "BaseListViewModel" : "BaseViewModel";
286
+ }
287
+ getImports(relativeCorePath) {
288
+ return [`import 'package:flutter_bloc/flutter_bloc.dart';`, `import '${relativeCorePath}';`];
289
+ }
290
+ patchAppEntry(content, _context) {
291
+ let raw = content;
292
+ if (!raw.includes("import 'package:flutter_bloc/flutter_bloc.dart'")) {
293
+ if (raw.includes("import 'package:flutter/material.dart';")) {
294
+ raw = raw.replace(
295
+ "import 'package:flutter/material.dart';",
296
+ "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';"
297
+ );
298
+ } else {
299
+ raw = `import 'package:flutter_bloc/flutter_bloc.dart';
300
+ ${raw}`;
301
+ }
302
+ }
303
+ return raw;
304
+ }
305
+ };
306
+
307
+ // src/generators/tasks/adapters/riverpod_adapter.ts
308
+ import { join } from "path";
309
+ import fsx from "fs-extra";
310
+ var RiverpodAdapter = class {
311
+ name = "riverpod";
312
+ getDependencies() {
313
+ return ["flutter_riverpod: ^2.4.9"];
314
+ }
315
+ getBasePageParent(isListPage) {
316
+ return isListPage ? "BaseListPageRiverpod" : "BasePageRiverpod";
317
+ }
318
+ getBaseViewModelParent(isListPage) {
319
+ return isListPage ? "BaseListNotifier" : "BaseNotifier";
320
+ }
321
+ getImports(relativeCorePath) {
322
+ return [
323
+ `import 'package:flutter_riverpod/flutter_riverpod.dart';`,
324
+ `import '${relativeCorePath}';`
325
+ ];
326
+ }
327
+ getBaseViewModelTemplate(context) {
328
+ return null;
329
+ }
330
+ patchAppEntry(content, context) {
331
+ let raw = content;
332
+ if (raw.includes("runApp(") && !raw.includes("ProviderScope")) {
333
+ raw = raw.replace(/runApp\((.*?)\)/, "runApp(const ProviderScope(child: $1))");
334
+ if (!raw.includes("import 'package:flutter_riverpod/flutter_riverpod.dart'")) {
335
+ raw = `import 'package:flutter_riverpod/flutter_riverpod.dart';
336
+ ` + raw;
337
+ }
338
+ }
339
+ return raw;
340
+ }
341
+ async onEnrich(context) {
342
+ const { projectPath } = context;
343
+ const baseDir = join(projectPath, "lib", "core", "base");
344
+ await fsx.ensureDir(baseDir);
345
+ await fsx.writeFile(
346
+ join(baseDir, "view_state.dart"),
347
+ "enum ViewState { idle, loading, success, error }\n"
348
+ );
349
+ await fsx.writeFile(
350
+ join(baseDir, "base_state.dart"),
351
+ `
352
+ import 'view_state.dart';
353
+
354
+ class BaseState {
355
+ final ViewState state;
356
+ final bool isRefreshing;
357
+ final String? error;
358
+
359
+ const BaseState({
360
+ this.state = ViewState.idle,
361
+ this.isRefreshing = false,
362
+ this.error,
363
+ });
364
+
365
+ BaseState copyWith({ ViewState? state, bool? isRefreshing, String? error }) {
366
+ return BaseState(
367
+ state: state ?? this.state,
368
+ isRefreshing: isRefreshing ?? this.isRefreshing,
369
+ error: error ?? this.error,
370
+ );
371
+ }
372
+
373
+ bool get isLoading => state == ViewState.loading;
374
+ bool get isSuccess => state == ViewState.success;
375
+ bool get isError => state == ViewState.error;
376
+ bool get isIdle => state == ViewState.idle;
377
+ }
378
+ `
379
+ );
380
+ await fsx.writeFile(
381
+ join(baseDir, "base_notifier.dart"),
382
+ `
383
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
384
+ import 'view_state.dart';
385
+ import 'base_state.dart';
386
+
387
+ abstract class BaseNotifier<T extends BaseState> extends Notifier<T> {
388
+ T createInitialState();
389
+ @override
390
+ T build() => createInitialState();
391
+
392
+ void setLoading() { state = (state.copyWith(state: ViewState.loading, error: null)) as T; }
393
+ void setSuccess() { state = (state.copyWith(state: ViewState.success)) as T; }
394
+ void setError(String message) { state = (state.copyWith(state: ViewState.error, error: message)) as T; }
395
+ void setRefreshing(bool refreshing) { state = (state.copyWith(isRefreshing: refreshing)) as T; }
396
+
397
+ Future<void> run(Future<void> Function() task) async {
398
+ setLoading();
399
+ try {
400
+ await task();
401
+ setSuccess();
402
+ } catch (e) {
403
+ setError(e.toString());
404
+ }
405
+ }
406
+ }
407
+ `
408
+ );
409
+ await fsx.writeFile(
410
+ join(baseDir, "base_page_riverpod.dart"),
411
+ `
412
+ import 'package:flutter/material.dart';
413
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
414
+ import 'base_state.dart';
415
+
416
+ typedef ContentBuilder<TState extends BaseState, TNotifier extends Notifier<TState>> = Widget Function(BuildContext context, TState state, TNotifier vm);
417
+
418
+ class BasePageRiverpod<TState extends BaseState, TNotifier extends Notifier<TState>> extends ConsumerWidget {
419
+ final ProviderListenable<TState> provider;
420
+ final String title;
421
+ final ContentBuilder<TState, TNotifier> builder;
422
+
423
+ const BasePageRiverpod({ super.key, required this.provider, required this.title, required this.builder });
424
+
425
+ @override
426
+ Widget build(BuildContext context, WidgetRef ref) {
427
+ final state = ref.watch(provider);
428
+ final vm = ref.read(provider as dynamic).notifier as TNotifier;
429
+ return Scaffold(
430
+ appBar: AppBar(title: Text(title)),
431
+ body: Center(
432
+ child: state.isLoading
433
+ ? const CircularProgressIndicator()
434
+ : state.isError
435
+ ? Text('Error: ' + (state.error ?? ''))
436
+ : builder(context, state, vm),
437
+ ),
438
+ );
439
+ }
440
+ }
441
+ `
442
+ );
443
+ }
444
+ };
445
+
446
+ // src/generators/tasks/adapters/factory.ts
447
+ var StateManagerAdapterFactory = class {
448
+ static getAdapter(name) {
449
+ switch (name.toLowerCase()) {
450
+ case "getx":
451
+ return new GetXAdapter();
452
+ case "bloc":
453
+ return new BlocAdapter();
454
+ case "provider":
455
+ return new ProviderAdapter("provider");
456
+ case "riverpod":
457
+ return new RiverpodAdapter();
458
+ default:
459
+ return new ProviderAdapter("default");
460
+ }
461
+ }
462
+ };
463
+
464
+ export {
465
+ StateManagerAdapterFactory
466
+ };
@@ -0,0 +1,37 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ var __commonJS = (cb, mod) => function __require2() {
14
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ export {
34
+ __require,
35
+ __commonJS,
36
+ __toESM
37
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ StateManagerAdapterFactory
3
+ } from "./chunk-BGYZU6TU.js";
4
+ import "./chunk-QGM4M3NI.js";
5
+ export {
6
+ StateManagerAdapterFactory
7
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ StateManagerAdapterFactory
3
+ } from "./chunk-ANN4MX7M.js";
4
+ import "./chunk-QGM4M3NI.js";
5
+ export {
6
+ StateManagerAdapterFactory
7
+ };