From 2f978730957b35dee39cd96d5088157bb6396583 Mon Sep 17 00:00:00 2001 From: Yuriy Panov Date: Wed, 4 Feb 2026 15:28:59 +0600 Subject: [PATCH] Fix import paths and test issues - Fixed test file import paths to point to correct Bloc file locations - Fixed Bloc file import paths for models (../../../models/models.dart) - Added explicit type annotations to resolve null safety warnings - Fixed null safety issues in wishlist_bloc_test.dart - All 70 tests now passing --- .../add_book}/add_book_screen.dart | 6 +- .../add_book/bloc}/add_book_bloc.dart | 2 +- .../add_book/bloc}/add_book_event.dart | 0 .../add_book/bloc}/add_book_state.dart | 2 +- .../book_details/bloc}/book_details_bloc.dart | 2 +- .../bloc}/book_details_event.dart | 2 +- .../bloc}/book_details_state.dart | 2 +- .../book_details}/book_details_screen.dart | 6 +- .../categories/bloc}/categories_bloc.dart | 2 +- .../categories/bloc}/categories_event.dart | 2 +- .../categories/bloc}/categories_state.dart | 2 +- .../categories}/categories_screen.dart | 2 +- .../home/bloc}/home_bloc.dart | 2 +- .../home/bloc}/home_event.dart | 2 +- .../home/bloc}/home_state.dart | 2 +- .../home}/home_screen.dart | 22 +- .../library/bloc}/library_bloc.dart | 6 +- .../library/bloc}/library_event.dart | 2 +- .../library/bloc}/library_state.dart | 2 +- .../library}/library_screen.dart | 8 +- .../scanner/bloc}/scanner_bloc.dart | 0 .../scanner/bloc}/scanner_event.dart | 0 .../scanner/bloc}/scanner_state.dart | 0 .../scanner}/scanner_screen.dart | 6 +- .../settings/bloc}/settings_bloc.dart | 0 .../settings/bloc}/settings_event.dart | 0 .../settings/bloc}/settings_state.dart | 0 .../settings}/settings_screen.dart | 0 .../wishlist/bloc}/wishlist_bloc.dart | 2 +- .../wishlist/bloc}/wishlist_event.dart | 0 .../wishlist/bloc}/wishlist_state.dart | 2 +- .../wishlist}/wishlist_screen.dart | 0 bookshelf_flutter/lib/main.dart | 2 +- bookshelf_flutter/lib/models/app_screen.dart | 10 + bookshelf_flutter/lib/models/book.dart | 127 ++++++++++++ bookshelf_flutter/lib/models/book_status.dart | 20 ++ bookshelf_flutter/lib/models/category.dart | 27 +++ bookshelf_flutter/lib/models/models.dart | 190 +----------------- .../bloc/add_book/add_book_bloc_test.dart | 6 +- .../book_details/book_details_bloc_test.dart | 6 +- .../bloc/categories/categories_bloc_test.dart | 6 +- .../test/bloc/home/home_bloc_test.dart | 6 +- .../test/bloc/library/library_bloc_test.dart | 8 +- .../test/bloc/scanner/scanner_bloc_test.dart | 6 +- .../bloc/settings/settings_bloc_test.dart | 6 +- .../bloc/wishlist/wishlist_bloc_test.dart | 24 ++- 46 files changed, 270 insertions(+), 260 deletions(-) rename bookshelf_flutter/lib/{screens => features/add_book}/add_book_screen.dart (99%) rename bookshelf_flutter/lib/{bloc/add_book => features/add_book/bloc}/add_book_bloc.dart (98%) rename bookshelf_flutter/lib/{bloc/add_book => features/add_book/bloc}/add_book_event.dart (100%) rename bookshelf_flutter/lib/{bloc/add_book => features/add_book/bloc}/add_book_state.dart (98%) rename bookshelf_flutter/lib/{bloc/book_details => features/book_details/bloc}/book_details_bloc.dart (97%) rename bookshelf_flutter/lib/{bloc/book_details => features/book_details/bloc}/book_details_event.dart (93%) rename bookshelf_flutter/lib/{bloc/book_details => features/book_details/bloc}/book_details_state.dart (95%) rename bookshelf_flutter/lib/{screens => features/book_details}/book_details_screen.dart (98%) rename bookshelf_flutter/lib/{bloc/categories => features/categories/bloc}/categories_bloc.dart (98%) rename bookshelf_flutter/lib/{bloc/categories => features/categories/bloc}/categories_event.dart (90%) rename bookshelf_flutter/lib/{bloc/categories => features/categories/bloc}/categories_state.dart (97%) rename bookshelf_flutter/lib/{screens => features/categories}/categories_screen.dart (99%) rename bookshelf_flutter/lib/{bloc/home => features/home/bloc}/home_bloc.dart (94%) rename bookshelf_flutter/lib/{bloc/home => features/home/bloc}/home_event.dart (85%) rename bookshelf_flutter/lib/{bloc/home => features/home/bloc}/home_state.dart (95%) rename bookshelf_flutter/lib/{screens => features/home}/home_screen.dart (78%) rename bookshelf_flutter/lib/{bloc/library => features/library/bloc}/library_bloc.dart (96%) rename bookshelf_flutter/lib/{bloc/library => features/library/bloc}/library_event.dart (92%) rename bookshelf_flutter/lib/{bloc/library => features/library/bloc}/library_state.dart (97%) rename bookshelf_flutter/lib/{screens => features/library}/library_screen.dart (98%) rename bookshelf_flutter/lib/{bloc/scanner => features/scanner/bloc}/scanner_bloc.dart (100%) rename bookshelf_flutter/lib/{bloc/scanner => features/scanner/bloc}/scanner_event.dart (100%) rename bookshelf_flutter/lib/{bloc/scanner => features/scanner/bloc}/scanner_state.dart (100%) rename bookshelf_flutter/lib/{screens => features/scanner}/scanner_screen.dart (98%) rename bookshelf_flutter/lib/{bloc/settings => features/settings/bloc}/settings_bloc.dart (100%) rename bookshelf_flutter/lib/{bloc/settings => features/settings/bloc}/settings_event.dart (100%) rename bookshelf_flutter/lib/{bloc/settings => features/settings/bloc}/settings_state.dart (100%) rename bookshelf_flutter/lib/{screens => features/settings}/settings_screen.dart (100%) rename bookshelf_flutter/lib/{bloc/wishlist => features/wishlist/bloc}/wishlist_bloc.dart (98%) rename bookshelf_flutter/lib/{bloc/wishlist => features/wishlist/bloc}/wishlist_event.dart (100%) rename bookshelf_flutter/lib/{bloc/wishlist => features/wishlist/bloc}/wishlist_state.dart (96%) rename bookshelf_flutter/lib/{screens => features/wishlist}/wishlist_screen.dart (100%) create mode 100644 bookshelf_flutter/lib/models/app_screen.dart create mode 100644 bookshelf_flutter/lib/models/book.dart create mode 100644 bookshelf_flutter/lib/models/book_status.dart create mode 100644 bookshelf_flutter/lib/models/category.dart diff --git a/bookshelf_flutter/lib/screens/add_book_screen.dart b/bookshelf_flutter/lib/features/add_book/add_book_screen.dart similarity index 99% rename from bookshelf_flutter/lib/screens/add_book_screen.dart rename to bookshelf_flutter/lib/features/add_book/add_book_screen.dart index 06515c3..d857a1c 100644 --- a/bookshelf_flutter/lib/screens/add_book_screen.dart +++ b/bookshelf_flutter/lib/features/add_book/add_book_screen.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:image_picker/image_picker.dart'; import 'package:cached_network_image/cached_network_image.dart'; -import '../bloc/app_bloc.dart'; -import '../bloc/app_event.dart'; -import '../models/models.dart'; +import '../../bloc/app_bloc.dart'; +import '../../bloc/app_event.dart'; +import '../../../models/models.dart'; class AddBookScreen extends StatefulWidget { final dynamic initialData; diff --git a/bookshelf_flutter/lib/bloc/add_book/add_book_bloc.dart b/bookshelf_flutter/lib/features/add_book/bloc/add_book_bloc.dart similarity index 98% rename from bookshelf_flutter/lib/bloc/add_book/add_book_bloc.dart rename to bookshelf_flutter/lib/features/add_book/bloc/add_book_bloc.dart index c954d58..e30c2f1 100644 --- a/bookshelf_flutter/lib/bloc/add_book/add_book_bloc.dart +++ b/bookshelf_flutter/lib/features/add_book/bloc/add_book_bloc.dart @@ -1,5 +1,5 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; import 'add_book_event.dart'; import 'add_book_state.dart'; diff --git a/bookshelf_flutter/lib/bloc/add_book/add_book_event.dart b/bookshelf_flutter/lib/features/add_book/bloc/add_book_event.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/add_book/add_book_event.dart rename to bookshelf_flutter/lib/features/add_book/bloc/add_book_event.dart diff --git a/bookshelf_flutter/lib/bloc/add_book/add_book_state.dart b/bookshelf_flutter/lib/features/add_book/bloc/add_book_state.dart similarity index 98% rename from bookshelf_flutter/lib/bloc/add_book/add_book_state.dart rename to bookshelf_flutter/lib/features/add_book/bloc/add_book_state.dart index 46fa7ea..09126ea 100644 --- a/bookshelf_flutter/lib/bloc/add_book/add_book_state.dart +++ b/bookshelf_flutter/lib/features/add_book/bloc/add_book_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; class AddBookState extends Equatable { final String title; diff --git a/bookshelf_flutter/lib/bloc/book_details/book_details_bloc.dart b/bookshelf_flutter/lib/features/book_details/bloc/book_details_bloc.dart similarity index 97% rename from bookshelf_flutter/lib/bloc/book_details/book_details_bloc.dart rename to bookshelf_flutter/lib/features/book_details/bloc/book_details_bloc.dart index 0f61a55..b26a3b3 100644 --- a/bookshelf_flutter/lib/bloc/book_details/book_details_bloc.dart +++ b/bookshelf_flutter/lib/features/book_details/bloc/book_details_bloc.dart @@ -1,5 +1,5 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; import 'book_details_event.dart'; import 'book_details_state.dart'; diff --git a/bookshelf_flutter/lib/bloc/book_details/book_details_event.dart b/bookshelf_flutter/lib/features/book_details/bloc/book_details_event.dart similarity index 93% rename from bookshelf_flutter/lib/bloc/book_details/book_details_event.dart rename to bookshelf_flutter/lib/features/book_details/bloc/book_details_event.dart index 17cf261..842a667 100644 --- a/bookshelf_flutter/lib/bloc/book_details/book_details_event.dart +++ b/bookshelf_flutter/lib/features/book_details/bloc/book_details_event.dart @@ -1,4 +1,4 @@ -import '../../models/models.dart'; +import '../../../models/models.dart'; abstract class BookDetailsEvent { const BookDetailsEvent(); diff --git a/bookshelf_flutter/lib/bloc/book_details/book_details_state.dart b/bookshelf_flutter/lib/features/book_details/bloc/book_details_state.dart similarity index 95% rename from bookshelf_flutter/lib/bloc/book_details/book_details_state.dart rename to bookshelf_flutter/lib/features/book_details/bloc/book_details_state.dart index 2965522..ca90431 100644 --- a/bookshelf_flutter/lib/bloc/book_details/book_details_state.dart +++ b/bookshelf_flutter/lib/features/book_details/bloc/book_details_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; class BookDetailsState extends Equatable { final Book? book; diff --git a/bookshelf_flutter/lib/screens/book_details_screen.dart b/bookshelf_flutter/lib/features/book_details/book_details_screen.dart similarity index 98% rename from bookshelf_flutter/lib/screens/book_details_screen.dart rename to bookshelf_flutter/lib/features/book_details/book_details_screen.dart index 9713446..d49e42b 100644 --- a/bookshelf_flutter/lib/screens/book_details_screen.dart +++ b/bookshelf_flutter/lib/features/book_details/book_details_screen.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:cached_network_image/cached_network_image.dart'; -import '../bloc/app_bloc.dart'; -import '../bloc/app_event.dart'; -import '../models/models.dart'; +import '../../bloc/app_bloc.dart'; +import '../../bloc/app_event.dart'; +import '../../../models/models.dart'; class BookDetailsScreen extends StatelessWidget { final Book book; diff --git a/bookshelf_flutter/lib/bloc/categories/categories_bloc.dart b/bookshelf_flutter/lib/features/categories/bloc/categories_bloc.dart similarity index 98% rename from bookshelf_flutter/lib/bloc/categories/categories_bloc.dart rename to bookshelf_flutter/lib/features/categories/bloc/categories_bloc.dart index a41f72b..cd103bf 100644 --- a/bookshelf_flutter/lib/bloc/categories/categories_bloc.dart +++ b/bookshelf_flutter/lib/features/categories/bloc/categories_bloc.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; import 'categories_event.dart'; import 'categories_state.dart'; diff --git a/bookshelf_flutter/lib/bloc/categories/categories_event.dart b/bookshelf_flutter/lib/features/categories/bloc/categories_event.dart similarity index 90% rename from bookshelf_flutter/lib/bloc/categories/categories_event.dart rename to bookshelf_flutter/lib/features/categories/bloc/categories_event.dart index 907a199..7483ee4 100644 --- a/bookshelf_flutter/lib/bloc/categories/categories_event.dart +++ b/bookshelf_flutter/lib/features/categories/bloc/categories_event.dart @@ -1,4 +1,4 @@ -import '../../models/models.dart'; +import '../../../models/models.dart'; abstract class CategoriesEvent { const CategoriesEvent(); diff --git a/bookshelf_flutter/lib/bloc/categories/categories_state.dart b/bookshelf_flutter/lib/features/categories/bloc/categories_state.dart similarity index 97% rename from bookshelf_flutter/lib/bloc/categories/categories_state.dart rename to bookshelf_flutter/lib/features/categories/bloc/categories_state.dart index 32fa2a2..1b8850a 100644 --- a/bookshelf_flutter/lib/bloc/categories/categories_state.dart +++ b/bookshelf_flutter/lib/features/categories/bloc/categories_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; class CategoriesState extends Equatable { final List categories; diff --git a/bookshelf_flutter/lib/screens/categories_screen.dart b/bookshelf_flutter/lib/features/categories/categories_screen.dart similarity index 99% rename from bookshelf_flutter/lib/screens/categories_screen.dart rename to bookshelf_flutter/lib/features/categories/categories_screen.dart index 3dbd17e..3bf89be 100644 --- a/bookshelf_flutter/lib/screens/categories_screen.dart +++ b/bookshelf_flutter/lib/features/categories/categories_screen.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import '../models/models.dart'; +import '../../../models/models.dart'; class CategoriesScreen extends StatelessWidget { const CategoriesScreen({super.key}); diff --git a/bookshelf_flutter/lib/bloc/home/home_bloc.dart b/bookshelf_flutter/lib/features/home/bloc/home_bloc.dart similarity index 94% rename from bookshelf_flutter/lib/bloc/home/home_bloc.dart rename to bookshelf_flutter/lib/features/home/bloc/home_bloc.dart index 7a4c99b..3337aee 100644 --- a/bookshelf_flutter/lib/bloc/home/home_bloc.dart +++ b/bookshelf_flutter/lib/features/home/bloc/home_bloc.dart @@ -1,5 +1,5 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; import 'home_event.dart'; import 'home_state.dart'; diff --git a/bookshelf_flutter/lib/bloc/home/home_event.dart b/bookshelf_flutter/lib/features/home/bloc/home_event.dart similarity index 85% rename from bookshelf_flutter/lib/bloc/home/home_event.dart rename to bookshelf_flutter/lib/features/home/bloc/home_event.dart index 05d1ac1..35ee602 100644 --- a/bookshelf_flutter/lib/bloc/home/home_event.dart +++ b/bookshelf_flutter/lib/features/home/bloc/home_event.dart @@ -1,4 +1,4 @@ -import '../../models/models.dart'; +import '../../../models/models.dart'; abstract class HomeEvent { const HomeEvent(); diff --git a/bookshelf_flutter/lib/bloc/home/home_state.dart b/bookshelf_flutter/lib/features/home/bloc/home_state.dart similarity index 95% rename from bookshelf_flutter/lib/bloc/home/home_state.dart rename to bookshelf_flutter/lib/features/home/bloc/home_state.dart index c850175..809fd04 100644 --- a/bookshelf_flutter/lib/bloc/home/home_state.dart +++ b/bookshelf_flutter/lib/features/home/bloc/home_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; class HomeState extends Equatable { final AppScreen currentScreen; diff --git a/bookshelf_flutter/lib/screens/home_screen.dart b/bookshelf_flutter/lib/features/home/home_screen.dart similarity index 78% rename from bookshelf_flutter/lib/screens/home_screen.dart rename to bookshelf_flutter/lib/features/home/home_screen.dart index 25bfaf7..709493d 100644 --- a/bookshelf_flutter/lib/screens/home_screen.dart +++ b/bookshelf_flutter/lib/features/home/home_screen.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import '../bloc/app_bloc.dart'; -import '../bloc/app_state.dart'; -import '../models/models.dart'; -import 'library_screen.dart'; -import 'categories_screen.dart'; -import 'book_details_screen.dart'; -import 'add_book_screen.dart'; -import 'scanner_screen.dart'; -import 'wishlist_screen.dart'; -import 'settings_screen.dart'; -import '../widgets/bottom_nav.dart'; +import '../../bloc/app_bloc.dart'; +import '../../bloc/app_state.dart'; +import '../../../models/models.dart'; +import '../library/library_screen.dart'; +import '../categories/categories_screen.dart'; +import '../book_details/book_details_screen.dart'; +import '../add_book/add_book_screen.dart'; +import '../scanner/scanner_screen.dart'; +import '../wishlist/wishlist_screen.dart'; +import '../settings/settings_screen.dart'; +import '../../widgets/bottom_nav.dart'; class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); diff --git a/bookshelf_flutter/lib/bloc/library/library_bloc.dart b/bookshelf_flutter/lib/features/library/bloc/library_bloc.dart similarity index 96% rename from bookshelf_flutter/lib/bloc/library/library_bloc.dart rename to bookshelf_flutter/lib/features/library/bloc/library_bloc.dart index 5070355..aac225c 100644 --- a/bookshelf_flutter/lib/bloc/library/library_bloc.dart +++ b/bookshelf_flutter/lib/features/library/bloc/library_bloc.dart @@ -1,5 +1,5 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; import 'library_event.dart'; import 'library_state.dart'; @@ -87,7 +87,7 @@ class LibraryBloc extends Bloc { void _onSearchBooks(SearchBooks event, Emitter emit) { final query = event.query.toLowerCase(); - final filtered = state.books.where((book) { + final filtered = state.books.where((Book book) { return book.title.toLowerCase().contains(query) || book.author.toLowerCase().contains(query) || book.genre.toLowerCase().contains(query); @@ -104,7 +104,7 @@ class LibraryBloc extends Bloc { } void _onFilterByStatus(FilterByStatus event, Emitter emit) { - final filtered = state.books.where((book) { + final filtered = state.books.where((Book book) { return book.status == event.status; }).toList(); diff --git a/bookshelf_flutter/lib/bloc/library/library_event.dart b/bookshelf_flutter/lib/features/library/bloc/library_event.dart similarity index 92% rename from bookshelf_flutter/lib/bloc/library/library_event.dart rename to bookshelf_flutter/lib/features/library/bloc/library_event.dart index 49dfaa4..4b2ad8f 100644 --- a/bookshelf_flutter/lib/bloc/library/library_event.dart +++ b/bookshelf_flutter/lib/features/library/bloc/library_event.dart @@ -1,4 +1,4 @@ -import '../../models/models.dart'; +import '../../../models/models.dart'; abstract class LibraryEvent { const LibraryEvent(); diff --git a/bookshelf_flutter/lib/bloc/library/library_state.dart b/bookshelf_flutter/lib/features/library/bloc/library_state.dart similarity index 97% rename from bookshelf_flutter/lib/bloc/library/library_state.dart rename to bookshelf_flutter/lib/features/library/bloc/library_state.dart index 177293a..0d9636f 100644 --- a/bookshelf_flutter/lib/bloc/library/library_state.dart +++ b/bookshelf_flutter/lib/features/library/bloc/library_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; class LibraryState extends Equatable { final List books; diff --git a/bookshelf_flutter/lib/screens/library_screen.dart b/bookshelf_flutter/lib/features/library/library_screen.dart similarity index 98% rename from bookshelf_flutter/lib/screens/library_screen.dart rename to bookshelf_flutter/lib/features/library/library_screen.dart index 065d97c..c45b4db 100644 --- a/bookshelf_flutter/lib/screens/library_screen.dart +++ b/bookshelf_flutter/lib/features/library/library_screen.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:cached_network_image/cached_network_image.dart'; -import '../bloc/app_bloc.dart'; -import '../bloc/app_event.dart'; -import '../bloc/app_state.dart'; -import '../models/models.dart'; +import '../../bloc/app_bloc.dart'; +import '../../bloc/app_event.dart'; +import '../../bloc/app_state.dart'; +import '../../../models/models.dart'; class LibraryScreen extends StatefulWidget { const LibraryScreen({super.key}); diff --git a/bookshelf_flutter/lib/bloc/scanner/scanner_bloc.dart b/bookshelf_flutter/lib/features/scanner/bloc/scanner_bloc.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/scanner/scanner_bloc.dart rename to bookshelf_flutter/lib/features/scanner/bloc/scanner_bloc.dart diff --git a/bookshelf_flutter/lib/bloc/scanner/scanner_event.dart b/bookshelf_flutter/lib/features/scanner/bloc/scanner_event.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/scanner/scanner_event.dart rename to bookshelf_flutter/lib/features/scanner/bloc/scanner_event.dart diff --git a/bookshelf_flutter/lib/bloc/scanner/scanner_state.dart b/bookshelf_flutter/lib/features/scanner/bloc/scanner_state.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/scanner/scanner_state.dart rename to bookshelf_flutter/lib/features/scanner/bloc/scanner_state.dart diff --git a/bookshelf_flutter/lib/screens/scanner_screen.dart b/bookshelf_flutter/lib/features/scanner/scanner_screen.dart similarity index 98% rename from bookshelf_flutter/lib/screens/scanner_screen.dart rename to bookshelf_flutter/lib/features/scanner/scanner_screen.dart index 3b1ab37..fce86a3 100644 --- a/bookshelf_flutter/lib/screens/scanner_screen.dart +++ b/bookshelf_flutter/lib/features/scanner/scanner_screen.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import '../bloc/app_bloc.dart'; -import '../bloc/app_event.dart'; -import '../models/models.dart'; +import '../../bloc/app_bloc.dart'; +import '../../bloc/app_event.dart'; +import '../../../models/models.dart'; class ScannerScreen extends StatelessWidget { const ScannerScreen({super.key}); diff --git a/bookshelf_flutter/lib/bloc/settings/settings_bloc.dart b/bookshelf_flutter/lib/features/settings/bloc/settings_bloc.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/settings/settings_bloc.dart rename to bookshelf_flutter/lib/features/settings/bloc/settings_bloc.dart diff --git a/bookshelf_flutter/lib/bloc/settings/settings_event.dart b/bookshelf_flutter/lib/features/settings/bloc/settings_event.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/settings/settings_event.dart rename to bookshelf_flutter/lib/features/settings/bloc/settings_event.dart diff --git a/bookshelf_flutter/lib/bloc/settings/settings_state.dart b/bookshelf_flutter/lib/features/settings/bloc/settings_state.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/settings/settings_state.dart rename to bookshelf_flutter/lib/features/settings/bloc/settings_state.dart diff --git a/bookshelf_flutter/lib/screens/settings_screen.dart b/bookshelf_flutter/lib/features/settings/settings_screen.dart similarity index 100% rename from bookshelf_flutter/lib/screens/settings_screen.dart rename to bookshelf_flutter/lib/features/settings/settings_screen.dart diff --git a/bookshelf_flutter/lib/bloc/wishlist/wishlist_bloc.dart b/bookshelf_flutter/lib/features/wishlist/bloc/wishlist_bloc.dart similarity index 98% rename from bookshelf_flutter/lib/bloc/wishlist/wishlist_bloc.dart rename to bookshelf_flutter/lib/features/wishlist/bloc/wishlist_bloc.dart index 68dfa81..cc95fdc 100644 --- a/bookshelf_flutter/lib/bloc/wishlist/wishlist_bloc.dart +++ b/bookshelf_flutter/lib/features/wishlist/bloc/wishlist_bloc.dart @@ -1,5 +1,5 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; import 'wishlist_event.dart'; import 'wishlist_state.dart'; diff --git a/bookshelf_flutter/lib/bloc/wishlist/wishlist_event.dart b/bookshelf_flutter/lib/features/wishlist/bloc/wishlist_event.dart similarity index 100% rename from bookshelf_flutter/lib/bloc/wishlist/wishlist_event.dart rename to bookshelf_flutter/lib/features/wishlist/bloc/wishlist_event.dart diff --git a/bookshelf_flutter/lib/bloc/wishlist/wishlist_state.dart b/bookshelf_flutter/lib/features/wishlist/bloc/wishlist_state.dart similarity index 96% rename from bookshelf_flutter/lib/bloc/wishlist/wishlist_state.dart rename to bookshelf_flutter/lib/features/wishlist/bloc/wishlist_state.dart index bc22258..7180686 100644 --- a/bookshelf_flutter/lib/bloc/wishlist/wishlist_state.dart +++ b/bookshelf_flutter/lib/features/wishlist/bloc/wishlist_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import '../../models/models.dart'; +import '../../../models/models.dart'; class WishlistState extends Equatable { final List books; diff --git a/bookshelf_flutter/lib/screens/wishlist_screen.dart b/bookshelf_flutter/lib/features/wishlist/wishlist_screen.dart similarity index 100% rename from bookshelf_flutter/lib/screens/wishlist_screen.dart rename to bookshelf_flutter/lib/features/wishlist/wishlist_screen.dart diff --git a/bookshelf_flutter/lib/main.dart b/bookshelf_flutter/lib/main.dart index f9af1ab..5a781e2 100644 --- a/bookshelf_flutter/lib/main.dart +++ b/bookshelf_flutter/lib/main.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'bloc/app_bloc.dart'; -import 'screens/home_screen.dart'; +import 'features/home/home_screen.dart'; void main() { runApp(const BookshelfApp()); diff --git a/bookshelf_flutter/lib/models/app_screen.dart b/bookshelf_flutter/lib/models/app_screen.dart new file mode 100644 index 0000000..f3f6121 --- /dev/null +++ b/bookshelf_flutter/lib/models/app_screen.dart @@ -0,0 +1,10 @@ +// App screen enum +enum AppScreen { + library, + categories, + wishlist, + settings, + details, + addBook, + scanner, +} \ No newline at end of file diff --git a/bookshelf_flutter/lib/models/book.dart b/bookshelf_flutter/lib/models/book.dart new file mode 100644 index 0000000..c85c202 --- /dev/null +++ b/bookshelf_flutter/lib/models/book.dart @@ -0,0 +1,127 @@ +import 'book_status.dart'; + +// Book record - using Dart records as data classes +typedef Book = ({ + String id, + String title, + String author, + String genre, + String annotation, + String? coverUrl, + int? pages, + String? language, + int? publishedYear, + double? rating, + BookStatus status, + int? progress, + bool isFavorite, +}); + +// Helper function to create a Book record +Book createBook({ + required String id, + required String title, + required String author, + required String genre, + required String annotation, + String? coverUrl, + int? pages, + String? language, + int? publishedYear, + double? rating, + required BookStatus status, + int? progress, + required bool isFavorite, +}) { + return ( + id: id, + title: title, + author: author, + genre: genre, + annotation: annotation, + coverUrl: coverUrl, + pages: pages, + language: language, + publishedYear: publishedYear, + rating: rating, + status: status, + progress: progress, + isFavorite: isFavorite, + ); +} + +// Extension to create Book from partial data +extension BookExtension on Book { + Book copyWith({ + String? id, + String? title, + String? author, + String? genre, + String? annotation, + String? coverUrl, + int? pages, + String? language, + int? publishedYear, + double? rating, + BookStatus? status, + int? progress, + bool? isFavorite, + }) { + return createBook( + id: id ?? this.id, + title: title ?? this.title, + author: author ?? this.author, + genre: genre ?? this.genre, + annotation: annotation ?? this.annotation, + coverUrl: coverUrl ?? this.coverUrl, + pages: pages ?? this.pages, + language: language ?? this.language, + publishedYear: publishedYear ?? this.publishedYear, + rating: rating ?? this.rating, + status: status ?? this.status, + progress: progress ?? this.progress, + isFavorite: isFavorite ?? this.isFavorite, + ); + } + + // Convert to JSON for storage/transport + Map toJson() { + return { + 'id': id, + 'title': title, + 'author': author, + 'genre': genre, + 'annotation': annotation, + 'coverUrl': coverUrl, + 'pages': pages, + 'language': language, + 'publishedYear': publishedYear, + 'rating': rating, + 'status': status.name, + 'progress': progress, + 'isFavorite': isFavorite, + }; + } + + // Create Book from JSON + static Book fromJson(Map json) { + return ( + id: json['id'] as String, + title: json['title'] as String, + author: json['author'] as String, + genre: json['genre'] as String, + annotation: json['annotation'] as String, + coverUrl: json['coverUrl'] as String?, + pages: json['pages'] as int?, + language: json['language'] as String?, + publishedYear: json['publishedYear'] as int?, + rating: (json['rating'] as num?)?.toDouble(), + status: BookStatus.values.firstWhere( + (e) => e.name == json['status'], + orElse: () => BookStatus.wantToRead, + ), + progress: json['progress'] as int?, + isFavorite: json['isFavorite'] as bool? ?? false, + ); + } +} \ No newline at end of file diff --git a/bookshelf_flutter/lib/models/book_status.dart b/bookshelf_flutter/lib/models/book_status.dart new file mode 100644 index 0000000..f89b4e7 --- /dev/null +++ b/bookshelf_flutter/lib/models/book_status.dart @@ -0,0 +1,20 @@ +// Book status enum +enum BookStatus { + reading, + done, + wantToRead, +} + +// Extension for BookStatus to get display name +extension BookStatusExtension on BookStatus { + String get displayName { + switch (this) { + case BookStatus.reading: + return 'Reading Now'; + case BookStatus.done: + return 'Completed'; + case BookStatus.wantToRead: + return 'Wishlist'; + } + } +} \ No newline at end of file diff --git a/bookshelf_flutter/lib/models/category.dart b/bookshelf_flutter/lib/models/category.dart new file mode 100644 index 0000000..989d1ad --- /dev/null +++ b/bookshelf_flutter/lib/models/category.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +// Category record - using Dart records as data classes +typedef Category = ({ + String id, + String name, + int count, + IconData icon, + String colorClass, +}); + +// Helper function to create a Category record +Category createCategory({ + required String id, + required String name, + required int count, + required IconData icon, + required String colorClass, +}) { + return ( + id: id, + name: name, + count: count, + icon: icon, + colorClass: colorClass, + ); +} \ No newline at end of file diff --git a/bookshelf_flutter/lib/models/models.dart b/bookshelf_flutter/lib/models/models.dart index 5c2fabe..d40b204 100644 --- a/bookshelf_flutter/lib/models/models.dart +++ b/bookshelf_flutter/lib/models/models.dart @@ -1,185 +1,5 @@ -import 'package:flutter/material.dart'; - -// App screen enum -enum AppScreen { - library, - categories, - wishlist, - settings, - details, - addBook, - scanner, -} - -// Book status enum -enum BookStatus { - reading, - done, - wantToRead, -} - -// Extension for BookStatus to get display name -extension BookStatusExtension on BookStatus { - String get displayName { - switch (this) { - case BookStatus.reading: - return 'Reading Now'; - case BookStatus.done: - return 'Completed'; - case BookStatus.wantToRead: - return 'Wishlist'; - } - } -} - -// Category record - using Dart records as data classes -typedef Category = ({ - String id, - String name, - int count, - IconData icon, - String colorClass, -}); - -// Book record - using Dart records as data classes -typedef Book = ({ - String id, - String title, - String author, - String genre, - String annotation, - String? coverUrl, - int? pages, - String? language, - int? publishedYear, - double? rating, - BookStatus status, - int? progress, - bool isFavorite, -}); - -// Helper function to create a Category record -Category createCategory({ - required String id, - required String name, - required int count, - required IconData icon, - required String colorClass, -}) { - return ( - id: id, - name: name, - count: count, - icon: icon, - colorClass: colorClass, - ); -} - -// Helper function to create a Book record -Book createBook({ - required String id, - required String title, - required String author, - required String genre, - required String annotation, - String? coverUrl, - int? pages, - String? language, - int? publishedYear, - double? rating, - required BookStatus status, - int? progress, - required bool isFavorite, -}) { - return ( - id: id, - title: title, - author: author, - genre: genre, - annotation: annotation, - coverUrl: coverUrl, - pages: pages, - language: language, - publishedYear: publishedYear, - rating: rating, - status: status, - progress: progress, - isFavorite: isFavorite, - ); -} - -// Extension to create Book from partial data -extension BookExtension on Book { - Book copyWith({ - String? id, - String? title, - String? author, - String? genre, - String? annotation, - String? coverUrl, - int? pages, - String? language, - int? publishedYear, - double? rating, - BookStatus? status, - int? progress, - bool? isFavorite, - }) { - return createBook( - id: id ?? this.id, - title: title ?? this.title, - author: author ?? this.author, - genre: genre ?? this.genre, - annotation: annotation ?? this.annotation, - coverUrl: coverUrl ?? this.coverUrl, - pages: pages ?? this.pages, - language: language ?? this.language, - publishedYear: publishedYear ?? this.publishedYear, - rating: rating ?? this.rating, - status: status ?? this.status, - progress: progress ?? this.progress, - isFavorite: isFavorite ?? this.isFavorite, - ); - } - - // Convert to JSON for storage/transport - Map toJson() { - return { - 'id': id, - 'title': title, - 'author': author, - 'genre': genre, - 'annotation': annotation, - 'coverUrl': coverUrl, - 'pages': pages, - 'language': language, - 'publishedYear': publishedYear, - 'rating': rating, - 'status': status.name, - 'progress': progress, - 'isFavorite': isFavorite, - }; - } - - // Create Book from JSON - static Book fromJson(Map json) { - return ( - id: json['id'] as String, - title: json['title'] as String, - author: json['author'] as String, - genre: json['genre'] as String, - annotation: json['annotation'] as String, - coverUrl: json['coverUrl'] as String?, - pages: json['pages'] as int?, - language: json['language'] as String?, - publishedYear: json['publishedYear'] as int?, - rating: (json['rating'] as num?)?.toDouble(), - status: BookStatus.values.firstWhere( - (e) => e.name == json['status'], - orElse: () => BookStatus.wantToRead, - ), - progress: json['progress'] as int?, - isFavorite: json['isFavorite'] as bool? ?? false, - ); - } -} \ No newline at end of file +// Barrel export for all models +export 'app_screen.dart'; +export 'book_status.dart'; +export 'category.dart'; +export 'book.dart'; \ No newline at end of file diff --git a/bookshelf_flutter/test/bloc/add_book/add_book_bloc_test.dart b/bookshelf_flutter/test/bloc/add_book/add_book_bloc_test.dart index a02c089..6a6e5e1 100644 --- a/bookshelf_flutter/test/bloc/add_book/add_book_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/add_book/add_book_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/add_book/add_book_bloc.dart'; -import 'package:bookshelf_flutter/bloc/add_book/add_book_event.dart'; -import 'package:bookshelf_flutter/bloc/add_book/add_book_state.dart'; +import 'package:bookshelf_flutter/features/add_book/bloc/add_book_bloc.dart'; +import 'package:bookshelf_flutter/features/add_book/bloc/add_book_event.dart'; +import 'package:bookshelf_flutter/features/add_book/bloc/add_book_state.dart'; import 'package:bookshelf_flutter/models/models.dart'; void main() { diff --git a/bookshelf_flutter/test/bloc/book_details/book_details_bloc_test.dart b/bookshelf_flutter/test/bloc/book_details/book_details_bloc_test.dart index e7214b1..d846cf0 100644 --- a/bookshelf_flutter/test/bloc/book_details/book_details_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/book_details/book_details_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/book_details/book_details_bloc.dart'; -import 'package:bookshelf_flutter/bloc/book_details/book_details_event.dart'; -import 'package:bookshelf_flutter/bloc/book_details/book_details_state.dart'; +import 'package:bookshelf_flutter/features/book_details/bloc/book_details_bloc.dart'; +import 'package:bookshelf_flutter/features/book_details/bloc/book_details_event.dart'; +import 'package:bookshelf_flutter/features/book_details/bloc/book_details_state.dart'; import 'package:bookshelf_flutter/models/models.dart'; void main() { diff --git a/bookshelf_flutter/test/bloc/categories/categories_bloc_test.dart b/bookshelf_flutter/test/bloc/categories/categories_bloc_test.dart index d23100d..8ea2b13 100644 --- a/bookshelf_flutter/test/bloc/categories/categories_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/categories/categories_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/categories/categories_bloc.dart'; -import 'package:bookshelf_flutter/bloc/categories/categories_event.dart'; -import 'package:bookshelf_flutter/bloc/categories/categories_state.dart'; +import 'package:bookshelf_flutter/features/categories/bloc/categories_bloc.dart'; +import 'package:bookshelf_flutter/features/categories/bloc/categories_event.dart'; +import 'package:bookshelf_flutter/features/categories/bloc/categories_state.dart'; void main() { group('CategoriesBloc', () { diff --git a/bookshelf_flutter/test/bloc/home/home_bloc_test.dart b/bookshelf_flutter/test/bloc/home/home_bloc_test.dart index 7c6299a..e395a5c 100644 --- a/bookshelf_flutter/test/bloc/home/home_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/home/home_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/home/home_bloc.dart'; -import 'package:bookshelf_flutter/bloc/home/home_event.dart'; -import 'package:bookshelf_flutter/bloc/home/home_state.dart'; +import 'package:bookshelf_flutter/features/home/bloc/home_bloc.dart'; +import 'package:bookshelf_flutter/features/home/bloc/home_event.dart'; +import 'package:bookshelf_flutter/features/home/bloc/home_state.dart'; import 'package:bookshelf_flutter/models/models.dart'; void main() { diff --git a/bookshelf_flutter/test/bloc/library/library_bloc_test.dart b/bookshelf_flutter/test/bloc/library/library_bloc_test.dart index 3fc6b1a..1195a71 100644 --- a/bookshelf_flutter/test/bloc/library/library_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/library/library_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/library/library_bloc.dart'; -import 'package:bookshelf_flutter/bloc/library/library_event.dart'; -import 'package:bookshelf_flutter/bloc/library/library_state.dart'; +import 'package:bookshelf_flutter/features/library/bloc/library_bloc.dart'; +import 'package:bookshelf_flutter/features/library/bloc/library_event.dart'; +import 'package:bookshelf_flutter/features/library/bloc/library_state.dart'; import 'package:bookshelf_flutter/models/models.dart'; void main() { @@ -100,7 +100,7 @@ void main() { libraryBloc.add(const FilterByStatus(BookStatus.reading)); await Future.delayed(Duration.zero); - expect(libraryBloc.state.filteredBooks.every((book) => book.status == BookStatus.reading), true); + expect(libraryBloc.state.filteredBooks.every((Book book) => book.status == BookStatus.reading), true); expect(libraryBloc.state.statusFilter, BookStatus.reading); }); }); diff --git a/bookshelf_flutter/test/bloc/scanner/scanner_bloc_test.dart b/bookshelf_flutter/test/bloc/scanner/scanner_bloc_test.dart index 3b49853..9d2f6f7 100644 --- a/bookshelf_flutter/test/bloc/scanner/scanner_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/scanner/scanner_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/scanner/scanner_bloc.dart'; -import 'package:bookshelf_flutter/bloc/scanner/scanner_event.dart'; -import 'package:bookshelf_flutter/bloc/scanner/scanner_state.dart'; +import 'package:bookshelf_flutter/features/scanner/bloc/scanner_bloc.dart'; +import 'package:bookshelf_flutter/features/scanner/bloc/scanner_event.dart'; +import 'package:bookshelf_flutter/features/scanner/bloc/scanner_state.dart'; void main() { group('ScannerBloc', () { diff --git a/bookshelf_flutter/test/bloc/settings/settings_bloc_test.dart b/bookshelf_flutter/test/bloc/settings/settings_bloc_test.dart index 44880ed..20093c7 100644 --- a/bookshelf_flutter/test/bloc/settings/settings_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/settings/settings_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/settings/settings_bloc.dart'; -import 'package:bookshelf_flutter/bloc/settings/settings_event.dart'; -import 'package:bookshelf_flutter/bloc/settings/settings_state.dart'; +import 'package:bookshelf_flutter/features/settings/bloc/settings_bloc.dart'; +import 'package:bookshelf_flutter/features/settings/bloc/settings_event.dart'; +import 'package:bookshelf_flutter/features/settings/bloc/settings_state.dart'; void main() { group('SettingsBloc', () { diff --git a/bookshelf_flutter/test/bloc/wishlist/wishlist_bloc_test.dart b/bookshelf_flutter/test/bloc/wishlist/wishlist_bloc_test.dart index 9744b85..8d7c309 100644 --- a/bookshelf_flutter/test/bloc/wishlist/wishlist_bloc_test.dart +++ b/bookshelf_flutter/test/bloc/wishlist/wishlist_bloc_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:bookshelf_flutter/bloc/wishlist/wishlist_bloc.dart'; -import 'package:bookshelf_flutter/bloc/wishlist/wishlist_event.dart'; -import 'package:bookshelf_flutter/bloc/wishlist/wishlist_state.dart'; +import 'package:bookshelf_flutter/features/wishlist/bloc/wishlist_bloc.dart'; +import 'package:bookshelf_flutter/features/wishlist/bloc/wishlist_event.dart'; +import 'package:bookshelf_flutter/features/wishlist/bloc/wishlist_state.dart'; import 'package:bookshelf_flutter/models/models.dart'; void main() { @@ -37,16 +37,19 @@ void main() { wishlistBloc.add(const LoadWishlist()); await Future.delayed(Duration.zero); - final bookId = wishlistBloc.state.books.first.id; + expect(wishlistBloc.state.books.isNotEmpty, true, reason: 'No books loaded'); + final book = wishlistBloc.state.books.first; + final bookId = book.id; + wishlistBloc.add(RemoveFromWishlist(bookId)); await Future.delayed(Duration.zero); expect( - wishlistBloc.state.books.any((book) => book.id == bookId), + wishlistBloc.state.books.any((b) => b.id == bookId), false, ); expect( - wishlistBloc.state.filteredBooks.any((book) => book.id == bookId), + wishlistBloc.state.filteredBooks.any((b) => b.id == bookId), false, ); }); @@ -91,12 +94,15 @@ void main() { wishlistBloc.add(const LoadWishlist()); await Future.delayed(Duration.zero); - final bookId = wishlistBloc.state.books.first.id; + expect(wishlistBloc.state.books.isNotEmpty, true, reason: 'No books loaded'); + final book = wishlistBloc.state.books.first; + final bookId = book.id; + wishlistBloc.add(MoveToLibrary(bookId)); await Future.delayed(Duration.zero); - final book = wishlistBloc.state.books.firstWhere((b) => b.id == bookId); - expect(book.status, BookStatus.reading); + final foundBook = wishlistBloc.state.books.firstWhere((b) => b.id == bookId); + expect(foundBook.status, BookStatus.reading); expect(wishlistBloc.state.movedBookId, bookId); }); });