generatePageModule function

Future<void> generatePageModule(
  1. String projectPath,
  2. String pageName, {
  3. String? jsonInput,
  4. String? basePathOverride,
  5. String? uiType,
  6. String? additionalImports,
  7. bool addApiCalling = false,
  8. bool hasBottomBar = false,
  9. bool hasDrawer = false,
  10. List<String> tabNames = const [],
  11. List<String> drawerNames = const [],
  12. bool overwritePage = false,
})

Command used to generate enterprise page modules.

Implementation

Future<void> generatePageModule(
  String projectPath,
  String pageName, {
  String? jsonInput,
  String? basePathOverride,
  String? uiType,
  String? additionalImports,
  bool addApiCalling = false,
  bool hasBottomBar = false,
  bool hasDrawer = false,
  List<String> tabNames = const [],
  List<String> drawerNames = const [],
  bool overwritePage = false,
}) async {
  final template = uiType != null ? TemplateRegistry.getTemplate(uiType) : null;
  String? autoImports;
  if (template != null) {
    await _installTemplateDependencies(projectPath, template);
    autoImports =
        _generateTemplateImports(getProjectName(projectPath), template);
  }

  final effectiveAdditionalImports =
      (additionalImports ?? "") + (autoImports ?? "");

  final state = detectStateManagement(projectPath);

  final basePath = basePathOverride ??
      p.join(
        projectPath,
        'lib',
        'presentation',
        'pages',
        pageName,
      );

  final modelDir = p.join(basePath, 'model');

  safeCreateDir(basePath);
  safeCreateDir(modelDir);

  final className = pageName[0].toUpperCase() + pageName.substring(1);
  final projectName = getProjectName(projectPath);

  if (state == 'bloc') {
    await _ensureBlocInstalled(projectPath);

    final blocDir = p.join(basePath, 'bloc');
    safeCreateDir(blocDir);

    // Bloc
    safeWriteFile(
        p.join(blocDir, '${pageName}_bloc.dart'),
        '''
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart';
${addApiCalling ? "import 'package:$projectName/core/services/api_service.dart';" : ""}
import '${pageName}_event.dart';
import '${pageName}_state.dart';

class ${className}Bloc extends Bloc<${className}Event, ${className}State> {
  ${pageName == 'dashboard' ? 'final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();' : ''}

  ${className}Bloc() : super(const ${className}State()) {

    on<${className}Started>((event, emit) async {
      emit(state.copyWith(status: ${className}Status.loading));
      try {
        await Future.delayed(const Duration(seconds: 1));
        emit(state.copyWith(status: ${className}Status.success));
      } catch (e) {
        emit(state.copyWith(
          status: ${className}Status.error,
          message: e.toString(),
        ));
      }
    });

${pageName == 'dashboard' ? '''
    on<${className}ChangeTab>((event, emit) {
      emit(state.copyWith(selectedIndex: event.index));
    });
''' : ''}

${addApiCalling ? '''
    on<${className}Submit>((event, emit) async {
      emit(state.copyWith(status: ${className}Status.loading));
      try {
        final response = await ApiService.client.post(
          "your api url",
          data: {}, // your api request
        );
        emit(state.copyWith(status: ${className}Status.success));
      } catch (e) {
        emit(state.copyWith(
          status: ${className}Status.error,
          message: e.toString(),
        ));
      }
    });
''' : ""}

${uiType == 'faq' ? '''
    on<${className}ToggleFaq>((event, emit) {
      final newIndices = List<int>.from(state.expandedIndices);
      if (newIndices.contains(event.index)) {
        newIndices.remove(event.index);
      } else {
        newIndices.add(event.index);
      }
      emit(state.copyWith(expandedIndices: newIndices));
    });
''' : ''}
  }

}
''',
        overwrite: overwritePage,
        projectPath: projectPath);

    // Event
    safeWriteFile(
        p.join(blocDir, '${pageName}_event.dart'),
        '''
abstract class ${className}Event {}

class ${className}Started extends ${className}Event {}
${addApiCalling ? "class ${className}Submit extends ${className}Event {}" : ""}
${pageName == 'dashboard' ? 'class ${className}ChangeTab extends ${className}Event { final int index; ${className}ChangeTab(this.index); }' : ''}
${uiType == 'faq' ? 'class ${className}ToggleFaq extends ${className}Event { final int index; ${className}ToggleFaq(this.index); }' : ''}
''',
        overwrite: overwritePage,
        projectPath: projectPath);

    // State
    safeWriteFile(
        p.join(blocDir, '${pageName}_state.dart'),
        '''
import 'package:equatable/equatable.dart';

enum ${className}Status {
  initial,
  loading,
  success,
  error
}

class ${className}State extends Equatable {

  final ${className}Status status;
  final String? message;
  ${pageName == 'dashboard' ? 'final int selectedIndex;' : ''}
  ${uiType == 'faq' ? 'final List<int> expandedIndices;' : ''}

  const ${className}State({
    this.status = ${className}Status.initial,
    this.message,
    ${pageName == 'dashboard' ? 'this.selectedIndex = 0,' : ''}
    ${uiType == 'faq' ? 'this.expandedIndices = const [],' : ''}
  });

  ${className}State copyWith({
    ${className}Status? status,
    String? message,
    ${pageName == 'dashboard' ? 'int? selectedIndex,' : ''}
    ${uiType == 'faq' ? 'List<int>? expandedIndices,' : ''}
  }) {
    return ${className}State(
      status: status ?? this.status,
      message: message ?? this.message,
      ${pageName == 'dashboard' ? 'selectedIndex: selectedIndex ?? this.selectedIndex,' : ''}
      ${uiType == 'faq' ? 'expandedIndices: expandedIndices ?? this.expandedIndices,' : ''}
    );
  }

  @override
  List<Object?> get props => [
        status,
        message,
        ${pageName == 'dashboard' ? 'selectedIndex,' : ''}
        ${uiType == 'faq' ? 'expandedIndices,' : ''}
      ];
}
''',
        overwrite: overwritePage,
        projectPath: projectPath);

    // Page
    final pageContent = '''
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
${effectiveAdditionalImports}
import 'bloc/${pageName}_bloc.dart';
import 'bloc/${pageName}_state.dart';
import 'bloc/${pageName}_event.dart';

class ${className}Page extends StatelessWidget {

  const ${className}Page({super.key});

  @override
  Widget build(BuildContext context) {

    return BlocProvider(
      create: (context) => ${className}Bloc()..add(${className}Started()),
      child: BlocListener<${className}Bloc, ${className}State>(
        listener: (context, state) {},
        child: BlocBuilder<${className}Bloc, ${className}State>(
        builder: (context, state) {
          final isLoading = state.status == ${className}Status.loading;
          return ${uiType != null ? _getUiBody(uiType, className, 'isLoading', projectName, addApiCalling: addApiCalling, hasBottomBar: hasBottomBar, hasDrawer: hasDrawer, tabNames: tabNames, drawerNames: drawerNames) : '''Scaffold(
            appBar: AppBar(title: const Text("${className} Page")),
            body: const Center(child: Text("${className} Page")),
          )'''};
        },
        ),
      ),
    );

  }

}
''';

    if (overwritePage) {
      forceWriteFile(p.join(basePath, '${pageName}_page.dart'), pageContent);
    } else {
      safeWriteFile(p.join(basePath, '${pageName}_page.dart'), pageContent);
    }
  } else {
    await _ensureRiverpodInstalled(projectPath);

    final providerDir = p.join(basePath, 'provider');
    safeCreateDir(providerDir);

    safeWriteFile(p.join(providerDir, '${pageName}_provider.dart'), '''
import 'package:flutter_riverpod/flutter_riverpod.dart';

final ${pageName}Provider =
NotifierProvider<${className}Controller, ${className}State>(
  ${className}Controller.new,
);

class ${className}Controller extends Notifier<${className}State> {

  @override
  ${className}State build() {
    return const ${className}State();
  }

  Future<void> load() async {

    state = state.copyWith(loading: true);

    await Future.delayed(const Duration(seconds: 1));

    state = state.copyWith(loading: false);

  }

${addApiCalling ? '''
  Future<void> submit() async {
    state = state.copyWith(loading: true);
    try {
      // final response = await ApiService.client.post("your api url", data: {});
      await Future.delayed(const Duration(seconds: 1));
      state = state.copyWith(loading: false);
    } catch (e) {
      state = state.copyWith(loading: false);
    }
  }
''' : ""}
}

class ${className}State {

  final bool loading;

  const ${className}State({
    this.loading = false,
  });

  ${className}State copyWith({
    bool? loading,
  }) {
    return ${className}State(
      loading: loading ?? this.loading,
    );
  }

}
''');

    final pageContent = '''
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
${effectiveAdditionalImports}
import 'provider/${pageName}_provider.dart';

class ${className}Page extends ConsumerWidget {

  const ${className}Page({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    final state = ref.watch(${pageName}Provider);

    return ${uiType != null ? _getUiBody(uiType, className, 'state.loading', projectName, addApiCalling: addApiCalling, hasBottomBar: hasBottomBar, hasDrawer: hasDrawer, tabNames: tabNames, drawerNames: drawerNames) : '''Scaffold(
      appBar: AppBar(
        title: const Text("${className}"),
      ),
      body: Center(
              child: ElevatedButton(
                onPressed: () {
                  ref.read(${pageName}Provider.notifier).load();
                },
                child: const Text("Load"),
              ),
            ),
    )'''};

  }

}
''';

    if (overwritePage) {
      forceWriteFile(p.join(basePath, '${pageName}_page.dart'), pageContent);
    } else {
      safeWriteFile(p.join(basePath, '${pageName}_page.dart'), pageContent);
    }
  }

  // ===================== MODEL =====================

  final modelPath = p.join(modelDir, '${pageName}_model.dart');

  if (jsonInput != null && jsonInput.isNotEmpty) {
    final modelCode = generateModelFromJson(className, jsonInput);

    /// allow overwrite (API may change)
    safeWriteFile(modelPath, modelCode,
        overwrite: true, projectPath: projectPath);

    print('🔄 ${p.basename(modelPath)} updated.');
  } else {
    safeWriteFile(modelPath, '''
class ${className}Model {

  final String? id;

  ${className}Model({
    this.id,
  });

}
''');
  }

  print(
      '✅ Enterprise page module "$pageName" generated successfully using $state.');
}