generateBlocTemplate method
Generates BLoC template with state management logic.
Creates the main BLoC class with proper event handling for both future and stream-based API methods.
Parameters:
config: API generation configuration
Implementation
String generateBlocTemplate(ApiGenerationConfig config) {
final entityClass = typeResolver.resolveEntityClass(config);
return '''${typeResolver.whenMethod(
config.method,
onStream: () => "import 'dart:async';",
onFuture: () => '',
)}
${config.returnData == 'body_bytes' ? "import 'dart:typed_data';" : ''}
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import '../../../data/models/body/${config.apiName}_body.dart';
${config.isReturnDataModel ? '''import '../../../domain/entities/${config.apiName}_entity.dart';''' : ''}
import '../../../domain/usecases/${config.apiName}_use_case.dart';
part '${config.apiName}_event.dart';
part '${config.apiName}_state.dart';
class ${config.apiClassName}Bloc extends MorphemeBloc<${config.apiClassName}Event, ${config.apiClassName}State> {
${config.apiClassName}Bloc({
required this.useCase,
}) : super(${config.apiClassName}Initial()) {
on<Fetch${config.apiClassName}>((event, emit) async {
emit(${config.apiClassName}Loading(event.body, event.headers, event.extra,),);
${typeResolver.whenMethod(
config.method,
onStream: () {
return '''final results = useCase(event.body, headers: event.headers,);
final completer = Completer();
final List<$entityClass> buffer = [];
_streamSubscription = results.listen(
(result) {
emit(
result.fold(
(failure) => ${config.apiClassName}Failed(
event.body,
event.headers,
failure,
event.extra,
),
(success) {
buffer.add(success);
return ${config.apiClassName}Stream(
event.body,
event.headers,
success,
event.extra,
);
},
),
);
},
onError: (error) {
emit(
${config.apiClassName}Failed(
event.body,
event.headers,
InternalFailure('An unexpected error occurred: \$error'),
event.extra,
),
);
completer.complete();
},
onDone: () {
emit(
${config.apiClassName}Success(
event.body,
event.headers,
buffer,
event.extra,
),
);
completer.complete();
},
);
await completer.future;
});
on<Cancel${config.apiClassName}>((event, emit) async {
_streamSubscription?.cancel();
_streamSubscription = null;
emit(${config.apiClassName}Canceled(event.extra));
});
on<Pause${config.apiClassName}>((event, emit) async {
_streamSubscription?.pause();
emit(${config.apiClassName}Paused(event.extra));
});
on<Resume${config.apiClassName}>((event, emit) async {
_streamSubscription?.resume();
emit(${config.apiClassName}Resumed(event.extra));
});''';
},
onFuture: () {
return '''_cancelableOperation = CancelableOperation.fromFuture(
useCase(
event.body,
headers: event.headers,
${typeResolver.isApplyCacheStrategy(config.method) ? 'cacheStrategy: event.cacheStrategy,' : ''}
),
);
final result = await _cancelableOperation?.valueOrCancellation();
if (result == null) {
emit(${config.apiClassName}Canceled(event.extra));
return;
}
emit(
result.fold(
(failure) => ${config.apiClassName}Failed(event.body, event.headers, failure, event.extra,),
(success) => ${config.apiClassName}Success(event.body, event.headers, success, event.extra,),
),
);
});
on<Cancel${config.apiClassName}>((event, emit) async {
_cancelableOperation?.cancel();
_cancelableOperation = null;
emit(${config.apiClassName}Canceled(event.extra));
});''';
},
)}
}
final ${config.apiClassName}UseCase useCase;
${typeResolver.whenMethod(
config.method,
onStream: () {
return '''StreamSubscription<Either<MorphemeFailure, $entityClass>>? _streamSubscription;
@override
Future<void> close() {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}''';
},
onFuture: () {
return '''CancelableOperation<Either<MorphemeFailure, $entityClass>>? _cancelableOperation;
@override
Future<void> close() {
_cancelableOperation?.cancel();
_cancelableOperation = null;
return super.close();
}''';
},
)}
}''';
}