runWizard method
Runs the interactive CLI wizard and returns a completed ProjectConfig.
Implementation
Future<ProjectConfig> runWizard(
{String? initialProjectName, String? initialOrg}) async {
_logger.info('');
final floLogo = r'''
______ __ ______ ______ __ __
/\ ___\ /\ \ /\ __ \ /\ ___\ /\ \ /\ \
\ \ __\ \ \ \____ \ \ \/\ \ \ \ \____ \ \ \____ \ \ \
\ \_\ \ \_____\ \ \_____\ \ \_____\ \ \_____\ \ \_\
\/_/ \/_____/ \/_____/ \/_____/ \/_____/ \/_/
''';
_logger.info(floLogo);
_logger.info('✨ \x1B[1mWelcome to the Flo CLI Project Generator\x1B[0m ✨');
_logger.info('-----------------------------------------');
final projectName = initialProjectName ??
_logger.prompt('Project Name', defaultValue: 'my_app');
final org = initialOrg ??
_logger.prompt('Organization', defaultValue: 'com.example');
final allPlatforms = ['android', 'ios', 'web', 'macos', 'windows', 'linux'];
final platforms = _logger.chooseAny<String>(
'Platforms',
choices: allPlatforms,
defaultValues: ['android', 'ios'],
);
final architecture = _logger.chooseOne<String>(
'Architecture',
choices: ['Clean Architecture', 'MVVM', 'MVC'],
defaultValue: 'Clean Architecture',
);
final stateManagement = _logger.chooseOne<String>(
'State Management',
choices: ['Bloc', 'Riverpod', 'Provider', 'None'],
defaultValue: 'Bloc',
);
// Build context-aware dependency list
final smKey = stateManagement.toLowerCase();
final packageGroup = PackageRegistry.flutterPackages[smKey] ??
PackageRegistry.flutterPackages['bloc']!;
final recommendedDeps = <String>{};
// Always include state management, serialization, and dev dependencies as defaults
recommendedDeps.addAll(packageGroup['state_management'] ?? []);
recommendedDeps.addAll(packageGroup['serialization'] ?? []);
recommendedDeps.addAll(packageGroup['dev_dependencies'] ?? []);
// Determine which categories have recommended dependencies
final categories = packageGroup.keys.toList();
final defaultCategories = <String>[];
for (var category in categories) {
final packagesInCategory = packageGroup[category]!;
if (packagesInCategory.any((p) => recommendedDeps.contains(p))) {
defaultCategories.add(category);
}
}
_logger.info('');
_logger.info('Dependency configuration is segregated into categories.');
final selectedCategories = _logger.chooseAny<String>(
'Select Categories to configure',
choices: categories,
defaultValues: defaultCategories,
display: (category) => category.replaceAll('_', ' ').toUpperCase(),
);
final selectedDependencies = <String>[];
for (final category in selectedCategories) {
final packages = packageGroup[category]!;
final defaultPackages =
packages.where((p) => recommendedDeps.contains(p)).toList();
final formattedCategory = category.replaceAll('_', ' ').toUpperCase();
final categorySelection = _logger.chooseAny<String>(
'Select $formattedCategory packages',
choices: packages,
defaultValues: defaultPackages,
);
selectedDependencies.addAll(categorySelection);
}
final gitInit =
_logger.confirm('Initialize Git repository?', defaultValue: true);
final generateReadme =
_logger.confirm('Generate README.md?', defaultValue: true);
_logger.info('-----------------------------------------');
_logger.success('Configuration complete!');
_logger.info('');
return ProjectConfig(
projectName: projectName,
org: org,
platforms: platforms,
architecture: architecture,
stateManagement: stateManagement,
gitInit: gitInit,
generateReadme: generateReadme,
dependencies: selectedDependencies,
);
}