# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is a Flutter mobile application for managing a personal book library. The app features book cataloging, categorization, reading status tracking, and cover scanning capabilities (via camera + Gemini AI). **Tech Stack:** - Flutter SDK ^3.10.8 - State Management: flutter_bloc ^9.1.0 - UI: Material 3 with Google Fonts (Inter) - AI: google_generative_ai ^0.4.6 (for book cover analysis) - Camera: camera ^0.11.1 ## Development Commands ### Running the App ```bash # Run on connected device/simulator flutter run # Run on specific device flutter run -d # Run in release mode flutter run --release # List available devices flutter devices ``` ### Building ```bash # Build APK for Android flutter build apk # Build iOS flutter build ios # Build for web (not currently configured) flutter build web ``` ### Code Quality ```bash # Install/update dependencies flutter pub get # Check for outdated packages flutter pub outdated # Run static analysis flutter analyze # Format all Dart files flutter format lib/ # Run tests flutter test ``` ### Using Dart MCP Tools When the Dart MCP server is available, prefer using these tools instead of bash commands: - `mcp__dart__analyze_files` instead of `flutter analyze` - `mcp__dart__dart_format` instead of `flutter format` - `mcp__dart__run_tests` instead of `flutter test` - `mcp__dart__list_devices` to see available devices - `mcp__dart__launch_app` to run the app with DTD integration ## Architecture ### State Management (BLoC Pattern) The app uses **flutter_bloc** for state management with two main BLoCs: #### 1. BookBloc (`lib/bloc/book_bloc.dart`) Manages the book collection state and operations: - **State**: `BookState` containing `List` - **Events**: - `AddBook(book)` - Add new book to library - `UpdateBook(book)` - Update existing book - `DeleteBook(id)` - Remove book from library - `ToggleFavorite(id)` - Toggle favorite status - **Initial State**: Loads from `initialBooks` in `constants.dart` - **Note**: Currently uses in-memory storage; no persistence layer #### 2. NavigationBloc (`lib/bloc/navigation_bloc.dart`) Manages app navigation and screen state: - **State**: `NavigationState` with: - `screen` (AppScreen enum) - Current screen - `selectedBook` - Book being viewed/edited - `prefilledData` - Data for pre-populating forms - **Event**: `NavigateTo(screen, {selectedBook, prefilledData})` - **Pattern**: Declarative navigation where UI rebuilds based on state - **Important**: `prefilledData` is used when scanning covers to prefill book form, while `selectedBook` is used for editing existing books ### Data Models (`lib/models/models.dart`) Uses Dart 3 **record types** for immutability: ```dart typedef Book = ({ String id, String title, String author, String genre, String annotation, String? coverUrl, int? pages, String? language, int? publishedYear, double? rating, String status, // 'reading', 'done', 'want_to_read' double? progress, // 0-100 for reading progress bool isFavorite, }); ``` **Important**: Records are immutable. To update a book, create a new record with updated fields using record syntax: ```dart final updatedBook = ( id: book.id, title: newTitle, // ... copy all other fields ); ``` ### Navigation Flow The app uses a custom navigation system via `NavigationBloc`: 1. **Library Screen** (default) → Shows all books in grid/category view 2. **Categories Screen** → Browse books by predefined categories 3. **Book Details** → View/edit single book (triggered by tapping book card) 4. **Add/Edit Book** → Form for adding new books or editing existing 5. **Scanner Screen** → Camera interface for scanning book covers 6. **Wishlist/Settings** → Placeholder screens **Navigation Pattern:** ```dart context.read().add( NavigateTo(AppScreen.details, selectedBook: book) ); ``` The main shell (`_AppShell` in `main.dart`) rebuilds based on `NavigationState.screen`. ### Theme System (Material 3) **Critical**: This app uses a **centralized theme system**. Never hardcode colors, text styles, or spacing. **Theme Files:** - `lib/theme/app_colors.dart` - Semantic color constants (cyan-based palette) - `lib/theme/app_spacing.dart` - Spacing scale (8px base) and border radius - `lib/theme/app_theme.dart` - Material 3 ThemeData with component themes **Usage Pattern:** ```dart final colorScheme = Theme.of(context).colorScheme; final textTheme = Theme.of(context).textTheme; // Use semantic colors Container(color: colorScheme.primary) // Use text styles Text('Title', style: textTheme.displayMedium) // Use spacing constants Padding(padding: EdgeInsets.all(AppSpacing.md)) // Use shadows BoxDecoration(boxShadow: AppTheme.shadowMd) ``` **Color Scheme:** - Primary: #0891B2 (Cyan-600) - Success/CTA: #22C55E (Green-500) - Background: #ECFEFF (Cyan-50) - Surface: #FFFFFF **Typography:** Inter font family loaded via Google Fonts with weights 300-700. ### Screen Structure All main screens follow this pattern: 1. Wrap in `SafeArea` for notch/status bar handling 2. Use `BlocBuilder` to listen to relevant BLoC state 3. Access theme via `Theme.of(context)` 4. Use `AppSpacing.*` constants for all padding/margins 5. Use theme colors and text styles exclusively **Example:** ```dart class MyScreen extends StatelessWidget { @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final textTheme = Theme.of(context).textTheme; return SafeArea( child: BlocBuilder( builder: (context, state) { return Padding( padding: EdgeInsets.all(AppSpacing.lg), child: Text( 'Hello', style: textTheme.headlineMedium, ), ); }, ), ); } } ``` ### Widget Conventions **BookCard** (`lib/widgets/book_card.dart`): - Displays book cover with metadata overlay - Includes Hero animation with tag `'book-cover-${book.id}'` - Shows shimmer loading while image loads - Has hover effect on desktop/web (1.02 scale) - Displays favorite badge, status badge, or progress bar based on book state **Hero Animations:** When navigating from library to book details, book covers animate smoothly: ```dart Hero( tag: 'book-cover-${book.id}', child: Image.network(book.coverUrl), ) ``` Both `BookCard` and `BookDetailsScreen` must use matching tags. ### Gemini AI Integration The `GeminiService` (`lib/services/gemini_service.dart`) is a placeholder for future AI-powered book cover scanning: - Takes base64-encoded image from camera - Will analyze cover and extract metadata (title, author, etc.) - Returns `Book?` record with prefilled data - Currently returns `null` - implementation pending **Intended Flow:** 1. User opens Scanner Screen 2. Takes photo of book cover 3. Image sent to `GeminiService.analyzeBookCover()` 4. Extracted data passed to Add Book screen via `NavigationBloc` with `prefilledData` ## Important Patterns ### When Adding New Features 1. **New Book Fields**: Update the `Book` typedef in `models.dart` and all places that construct book records 2. **New Screens**: Add to `AppScreen` enum, handle in `_AppShell` switch statement 3. **Theme Changes**: Only modify theme files, never inline styles 4. **Navigation**: Always use `NavigationBloc`, never `Navigator.push()` ### Code Style Requirements - **Immutability**: Use records for data models, never mutable classes - **Theme Compliance**: Zero hardcoded colors/styles/spacing - **BLoC Pattern**: UI is always a pure function of state - **Const Constructors**: Use `const` for all stateless widgets and values - **Reduced Motion**: Check `MediaQuery.of(context).disableAnimations` for animations ### Testing Gotchas - Books are stored in-memory only; restarting app resets to `initialBooks` - Camera requires physical device or simulator with camera support - Gemini API requires valid API key (not implemented yet) - Hero animations require matching tags between screens ## Project-Specific Notes ### Why Records Instead of Classes? This codebase uses Dart 3 record types for immutability and simplicity. When updating books, create new records rather than mutating fields. This makes BLoC state updates predictable and prevents accidental mutations. ### Navigation Without Navigator The app doesn't use Flutter's built-in Navigator. Instead, `NavigationBloc` tracks the current screen, and `_AppShell` rebuilds the entire UI tree based on state. This gives centralized control over navigation state but means: - No native back button handling (would need to emit `NavigateTo` events) - No deep linking support (yet) - All screens must be handled in the main switch statement ### Initial Data Books are initialized from `initialBooks` constant in `lib/constants/constants.dart`. Categories are defined in the same file. To add sample data, modify these constants. ### Future Enhancements Based on the codebase structure, likely next steps: - Implement persistence (SharedPreferences, SQLite, or Firebase) - Complete Gemini AI integration for cover scanning - Add native back button handling - Implement book search/filtering - Add reading statistics/charts - Support for book series and collections