refactor: create separate BLoCs for each screen with comprehensive tests

- Created 8 separate BLoCs (Home, Library, BookDetails, AddBook, Scanner, Categories, Wishlist, Settings)
- Each BLoC has its own event, state, and bloc files
- Added 70 comprehensive tests covering all BLoC functionality
- All tests passing (70/70)
- Fixed linting issues and updated deprecated APIs
- Improved code organization and maintainability
This commit is contained in:
Yuriy Panov
2026-02-04 14:40:00 +06:00
parent 3004f712f3
commit 310463e89a
177 changed files with 9718 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../models/models.dart';
import 'book_details_event.dart';
import 'book_details_state.dart';
class BookDetailsBloc extends Bloc<BookDetailsEvent, BookDetailsState> {
BookDetailsBloc() : super(BookDetailsState.initial()) {
on<LoadBookDetails>(_onLoadBookDetails);
on<ToggleFavorite>(_onToggleFavorite);
on<UpdateProgress>(_onUpdateProgress);
on<UpdateStatus>(_onUpdateStatus);
on<DeleteBook>(_onDeleteBook);
}
void _onLoadBookDetails(LoadBookDetails event, Emitter<BookDetailsState> emit) {
emit(state.copyWith(
book: event.book,
isLoading: false,
));
}
void _onToggleFavorite(ToggleFavorite event, Emitter<BookDetailsState> emit) {
if (state.book == null) return;
final updatedBook = state.book!.copyWith(
isFavorite: !state.book!.isFavorite,
);
emit(state.copyWith(
book: updatedBook,
));
}
void _onUpdateProgress(UpdateProgress event, Emitter<BookDetailsState> emit) {
if (state.book == null) return;
final updatedBook = state.book!.copyWith(
progress: event.progress,
status: event.progress >= 100 ? BookStatus.done : BookStatus.reading,
);
emit(state.copyWith(
book: updatedBook,
));
}
void _onUpdateStatus(UpdateStatus event, Emitter<BookDetailsState> emit) {
if (state.book == null) return;
final updatedBook = state.book!.copyWith(
status: event.status,
);
emit(state.copyWith(
book: updatedBook,
));
}
void _onDeleteBook(DeleteBook event, Emitter<BookDetailsState> emit) {
emit(state.copyWith(
isDeleted: true,
));
}
}

View File

@@ -0,0 +1,28 @@
import '../../models/models.dart';
abstract class BookDetailsEvent {
const BookDetailsEvent();
}
class LoadBookDetails extends BookDetailsEvent {
final Book book;
const LoadBookDetails(this.book);
}
class ToggleFavorite extends BookDetailsEvent {
const ToggleFavorite();
}
class UpdateProgress extends BookDetailsEvent {
final int progress;
const UpdateProgress(this.progress);
}
class UpdateStatus extends BookDetailsEvent {
final BookStatus status;
const UpdateStatus(this.status);
}
class DeleteBook extends BookDetailsEvent {
const DeleteBook();
}

View File

@@ -0,0 +1,44 @@
import 'package:equatable/equatable.dart';
import '../../models/models.dart';
class BookDetailsState extends Equatable {
final Book? book;
final bool isLoading;
final bool isDeleted;
final String? errorMessage;
const BookDetailsState({
this.book,
this.isLoading = false,
this.isDeleted = false,
this.errorMessage,
});
factory BookDetailsState.initial() {
return const BookDetailsState(
isLoading: true,
);
}
BookDetailsState copyWith({
Book? book,
bool? isLoading,
bool? isDeleted,
String? errorMessage,
}) {
return BookDetailsState(
book: book ?? this.book,
isLoading: isLoading ?? this.isLoading,
isDeleted: isDeleted ?? this.isDeleted,
errorMessage: errorMessage ?? this.errorMessage,
);
}
@override
List<Object?> get props => [
book,
isLoading,
isDeleted,
errorMessage,
];
}