clean_bloc 2.0.1 clean_bloc: ^2.0.1 copied to clipboard
A Wrapper for Bloc to make it easier to use Clean Architecture. It's based on the clean_network package.
Clean Bloc #
Clean Bloc is a wrapper around the bloc package that helps implement the Clean Architecture design pattern.
Getting Started #
Installation #
Add the following to your pubspec.yaml
file:
dependencies:
clean_bloc: latest
Usage #
Paginated Clean Cubit
import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';
@injectable
class UserCubit extends PaginatedCleanCubit<UserModel> {
final UserRepository _repository;
UserCubit(this._repository) {
init();
}
@override
Pagination get initialPage =>
const Pagination.page(currentPage: 1, perPage: 6);
@override
PaginatedEitherResponse<UserModel> Function(Pagination pagination)
get remoteCall {
return (pagination) {
final params = pagination as PagePagination;
return _repository.getUsers(
page: params.currentPage,
limit: params.perPage,
);
};
}
}
Clean Cubit #
import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';
@injectable
class UserCubit extends CleanCubit<UserModel> {
final UserRepository _repository;
UserCubit(this._repository) {
init();
}
@override
EitherResponse<UserModel> Function() get remoteCall {
return () => _repository.getUser();
}
}
Create Event for Clean Bloc #
import 'package:clean_bloc/clean_bloc.dart';
class UserAddEvent extends CleanEvent {
@override
List<Object?> get props => [];
}
Clean Bloc #
import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';
@injectable
class UserBloc extends CleanBloc<UserModel> {
final UserRepository _repository;
UserBloc(this._repository) {
init();
on<UserAddEvent>(_handleAddEvent);
}
@override
EitherResponse<UserModel> Function() get remoteCall {
return () => _repository.getUser();
}
/// Handle [CleanEventInit] event
FutureOr<void> _handleAddEvent(
UserAddEvent event, Emitter<CleanState<T>> emit) async {
/// Do something
}
}
Create Event for Paginated Clean Bloc #
import 'package:clean_bloc/clean_bloc.dart';
class UserAddEvent extends PaginatedCleanEvent {
@override
List<Object?> get props => [];
}
Paginated Clean Bloc #
import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';
@injectable
class UserBloc extends PaginatedCleanBloc<UserModel> {
final UserRepository _repository;
UserBloc(this._repository) {
init();
on<UserAddEvent>(_handleAddEvent);
}
@override
Pagination get initialPage =>
const Pagination.page(currentPage: 1, perPage: 6);
@override
PaginatedEitherResponse<UserModel> Function(Pagination pagination)
get remoteCall {
return (pagination) {
final params = pagination as PagePagination;
return _repository.getUsers(
page: params.currentPage,
limit: params.perPage,
);
};
}
/// Handle [UserAddEvent] event
FutureOr<void> _handleAddEvent(
UserAddEvent event,
Emitter<PaginatedCleanState<T>> emit,
) async {
/// Do something
}
}
Use Clean Bloc #
import 'package:auto_route/auto_route.dart';
import 'package:clean_bloc/clean_bloc.dart';
import 'package:example/src/core/di/injector.dart';
import 'package:example/src/features/users/domain/models/user_model.dart';
import 'package:example/src/features/users/presentation/blocs/list/user_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@RoutePage()
class UsersPage extends StatelessWidget {
const UsersPage({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<UserCubit>(),
child: Scaffold(
appBar: AppBar(
title: const Text('Users'),
),
body: const UserList(),
),
);
}
}
class UserList extends StatelessWidget {
const UserList({super.key});
@override
Widget build(BuildContext context) {
return NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollEndNotification &&
notification.metrics.extentAfter == 0) {
context.read<UserCubit>().fetchMore();
return true;
}
return false;
},
child: PaginatedCleanBuilder<UserCubit, UserModel>(
successBuilder: (context, users, isLoadingMore) {
if (users.isEmpty) {
return const Center(
child: Text('No users found'),
);
}
return ListView.builder(
itemCount: isLoadingMore ? users.length + 1 : users.length,
itemBuilder: (context, index) {
if (index == users.length && isLoadingMore) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
}
},
);
},
),
);
}
}