From 8d38171089c1a4f4d67473811af415f2885fe6d7 Mon Sep 17 00:00:00 2001 From: GermanPerelmuter Date: Fri, 4 Apr 2025 11:08:34 +0200 Subject: [PATCH 1/4] Implement addon selection --- bin/dev_pilot.dart | 32 ++++++++++++++++++++++++ lib/src/constants/app_constants.dart | 7 +++++- lib/src/enums/addon.dart | 18 ++++++++++++++ lib/src/services/script_service.dart | 37 ++++++++++++++-------------- 4 files changed, 74 insertions(+), 20 deletions(-) create mode 100644 lib/src/enums/addon.dart diff --git a/bin/dev_pilot.dart b/bin/dev_pilot.dart index 986efd1..40b0289 100755 --- a/bin/dev_pilot.dart +++ b/bin/dev_pilot.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:dcli/dcli.dart' as dcli; import 'package:dev_pilot/src/constants/app_constants.dart'; +import 'package:dev_pilot/src/enums/addon.dart'; import 'package:dev_pilot/src/services/converter_service.dart'; import 'package:dev_pilot/src/services/directory_service.dart'; import 'package:dev_pilot/src/services/file_service.dart'; @@ -33,6 +34,7 @@ void main(List arguments) async { List featureModules = []; List flavors = []; bool isPackagesNeeded = false; + List addons = []; final List packageModules = []; final Map> packages = >{}; @@ -161,6 +163,22 @@ void main(List arguments) async { } } + final String doIncludeAddonsAnswer = logger.chooseOne( + AppConstants.kWillYouUseAddons, + choices: [ + AppConstants.kYes, + AppConstants.kNo, + ], + ); + + if (doIncludeAddonsAnswer == AppConstants.kYes) { + addons = logger.chooseAny( + AppConstants.kSpecifyAddons, + choices: Addon.values, + display: (Addon addon) => addon.displayName, + ); + } + //Create project with a given name final ProcessResult result = Process.runSync( AppConstants.kFlutter, @@ -349,6 +367,20 @@ void main(List arguments) async { destinationPath: '$path/$projectName/.gitignore', ); + //Include specified addons + final String rootProjectPath = '$path/$projectName'; + final String rootProjectAbsolutePath = Directory(rootProjectPath).absolute.path; + final List rootProjectPathArgs = [rootProjectAbsolutePath]; + + for (final Addon addon in addons) { + final String workingDirectory = '$templatesPath/${AppConstants.kAddons}/${addon.remoteName}'; + await ScriptService.runScript( + AppConstants.kAddonScriptName, + workingDirectory, + rootProjectPathArgs, + ); + } + //Delete templates directory await DirectoryService.deleteDirectory( path: templatesPath, diff --git a/lib/src/constants/app_constants.dart b/lib/src/constants/app_constants.dart index 3b5a4c7..ef9c5a1 100644 --- a/lib/src/constants/app_constants.dart +++ b/lib/src/constants/app_constants.dart @@ -25,6 +25,9 @@ class AppConstants { 'Please enter the flavors separated by commas (dev, stage, prod etc...): '; static const String kInvalidFlavours = 'Invalid input. Please enter only full strings separated by commas : '; + static const String kWillYouUseAddons = + 'Do you want to include any addons (network provider, shared prefs setup, etc.) to this project?'; + static const String kSpecifyAddons = 'Please specify addons you would like to include'; static String kAddPackages(String modulesString) { return 'Do you want to add any packages to any of the following modules (core, core_ui, data, domain, navigation, features ${modulesString.isEmpty ? '' : [ @@ -67,6 +70,8 @@ class AppConstants { static const String kFeature = 'feature'; static const String kNavigation = 'navigation'; static const String kApp = 'app'; + static const String kFiles = 'files'; + static const String kAddons = 'addons'; static const String kFlutter = 'flutter'; static const String kCreate = 'create'; @@ -74,10 +79,10 @@ class AppConstants { static const String kOrg = '--org'; static const String kComExample = 'com.example'; static const String kProjectName = '--project-name'; + static const String kAddonScriptName = 'script.sh'; static String kCurrentPath = Directory.current.path; static String kTemplates = '$kCurrentPath/lib/src/templates'; - static const String kFiles = 'files'; static const String kGlobalErrorHandler = 'error_handler'; static const String kFeaturePlug = 'name: plug'; diff --git a/lib/src/enums/addon.dart b/lib/src/enums/addon.dart new file mode 100644 index 0000000..37582f0 --- /dev/null +++ b/lib/src/enums/addon.dart @@ -0,0 +1,18 @@ +enum Addon { + internetObserver( + remoteName: 'connection_observer', + displayName: 'Internet observer', + ), + apiProvider( + remoteName: 'api_provider', + displayName: 'HTTP provider', + ); + + final String remoteName; + final String displayName; + + const Addon({ + required this.remoteName, + required this.displayName, + }); +} diff --git a/lib/src/services/script_service.dart b/lib/src/services/script_service.dart index 5bd7bd7..a6e0852 100644 --- a/lib/src/services/script_service.dart +++ b/lib/src/services/script_service.dart @@ -19,11 +19,9 @@ class ScriptService { runInShell: true, ); if (cleanProcess.exitCode != 0) { - stdout.writeln(red( - '❌ Error running flutter clean for $modulePath: ${cleanProcess.stderr}')); + stdout.writeln(red('❌ Error running flutter clean for $modulePath: ${cleanProcess.stderr}')); } else { - stdout - .writeln(green('✅ Successfully ran flutter clean for $modulePath')); + stdout.writeln(green('✅ Successfully ran flutter clean for $modulePath')); } } @@ -41,11 +39,10 @@ class ScriptService { runInShell: true, ); if (pubGetProcess.exitCode != 0) { - stdout.writeln(red( - '❌ Error running flutter pub get for $modulePath : ${pubGetProcess.stderr}')); - } else { stdout.writeln( - green('✅ Successfully ran flutter pub get for $modulePath')); + red('❌ Error running flutter pub get for $modulePath : ${pubGetProcess.stderr}')); + } else { + stdout.writeln(green('✅ Successfully ran flutter pub get for $modulePath')); } } @@ -87,11 +84,18 @@ class ScriptService { /// /// If the command is successful, a success message is printed to the console. /// If the command fails, an error message is printed to the console. - static Future runScript(String scriptName, String directoryPath) async { + static Future runScript( + String scriptName, + String directoryPath, [ + List? parameters, + ]) async { final String scriptPath = '$directoryPath/$scriptName'; final ProcessResult process = await Process.run( 'sh', - [scriptPath], + [ + scriptPath, + if (parameters != null) ...parameters, + ], workingDirectory: directoryPath, runInShell: true, ); @@ -130,16 +134,14 @@ class ScriptService { /// [maxVersion] A string that represents the maximum version of Dart allowed. /// return A Future that is true if the installed version of Dart /// is within the allowed range and false otherwise. - static Future isDartVersionInRange( - String minVersion, String maxVersion) async { + static Future isDartVersionInRange(String minVersion, String maxVersion) async { final ProcessResult processResult = await Process.run( 'dart', ['--version'], runInShell: true, ); final String versionOutput = processResult.stdout.toString().trim(); - final RegExpMatch? versionMatch = - RegExp(r'version: ([\d\.]+)').firstMatch(versionOutput); + final RegExpMatch? versionMatch = RegExp(r'version: ([\d\.]+)').firstMatch(versionOutput); if (versionMatch != null) { final String? sdkVersion = versionMatch.group(1); if (sdkVersion != null) { @@ -149,11 +151,8 @@ class ScriptService { convertToThousands(int.tryParse(minVersion.replaceAll('.', ''))); final int? numericMaxVersion = convertToThousands(int.tryParse(maxVersion.replaceAll('.', ''))); - if (numericSdkVersion != null && - numericMinVersion != null && - numericMaxVersion != null) { - if (numericSdkVersion >= numericMinVersion && - numericSdkVersion <= numericMaxVersion) { + if (numericSdkVersion != null && numericMinVersion != null && numericMaxVersion != null) { + if (numericSdkVersion >= numericMinVersion && numericSdkVersion <= numericMaxVersion) { return true; } } From 22148567ed6a1dbc2add46451de99f74f815abde Mon Sep 17 00:00:00 2001 From: GermanPerelmuter Date: Tue, 8 Apr 2025 14:05:10 +0200 Subject: [PATCH 2/4] Minor code adjustments --- lib/src/constants/app_constants.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/constants/app_constants.dart b/lib/src/constants/app_constants.dart index ef9c5a1..095b608 100644 --- a/lib/src/constants/app_constants.dart +++ b/lib/src/constants/app_constants.dart @@ -146,7 +146,7 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); - _setupDI(Flavor.dev); + await _setupDI(Flavor.dev); runApp(const App()); } @@ -188,9 +188,9 @@ import 'error_handler/provider/app_error_handler_provider.dart'; Future _setupDI(Flavor flavor) async { appLocator.pushNewScope( scopeName: unauthScope, - init: (_) { + init: (_) async { AppDI.initDependencies(appLocator, flavor); - DataDI.initDependencies(appLocator); + await DataDI.initDependencies(appLocator); DomainDI.initDependencies(appLocator); NavigationDI.initDependencies(appLocator); }, From dd32cbc574d0e7513bd24238f81c7a3008adc08d Mon Sep 17 00:00:00 2001 From: GermanPerelmuter Date: Fri, 18 Apr 2025 11:04:57 +0200 Subject: [PATCH 3/4] Make websocket provider optional --- lib/src/enums/addon.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/enums/addon.dart b/lib/src/enums/addon.dart index 37582f0..bad1dd4 100644 --- a/lib/src/enums/addon.dart +++ b/lib/src/enums/addon.dart @@ -6,6 +6,10 @@ enum Addon { apiProvider( remoteName: 'api_provider', displayName: 'HTTP provider', + ), + websocketProvider( + remoteName: 'websocket_provider', + displayName: 'Websocket provider', ); final String remoteName; From 971b25f31d9198a9afb32f6e625625070c272a3d Mon Sep 17 00:00:00 2001 From: GermanPerelmuter Date: Fri, 18 Apr 2025 14:00:53 +0200 Subject: [PATCH 4/4] Add support for drift database --- lib/src/enums/addon.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/enums/addon.dart b/lib/src/enums/addon.dart index bad1dd4..638e4cc 100644 --- a/lib/src/enums/addon.dart +++ b/lib/src/enums/addon.dart @@ -10,6 +10,10 @@ enum Addon { websocketProvider( remoteName: 'websocket_provider', displayName: 'Websocket provider', + ), + driftDatabase( + remoteName: 'drift_database', + displayName: 'Drift database', ); final String remoteName;