# Code Style and Conventions ## Linting - Uses `package:flutter_lints/flutter.yaml` - Flutter's recommended lint rules - Configuration in `analysis_options.yaml` - Run linter: `flutter analyze` - All lints must pass before committing ## Dart/Flutter Conventions ### Naming - **Classes/Enums/Typedefs**: PascalCase (e.g., `OPDSFeed`, `DatabaseHelper`) - **Variables/Functions/Parameters**: camelCase (e.g., `fetchFeed`, `serverId`) - **Private members**: Prefix with underscore (e.g., `_database`, `_authService`) - **Constants**: lowerCamelCase for const variables (e.g., `const defaultTimeout`) - **Files**: snake_case (e.g., `opds_service.dart`, `server_list_screen.dart`) ### Widget Construction - Use `const` constructors wherever possible for performance - Use `super.key` for widget keys - Mark widget fields as `final` - Prefer `StatelessWidget` over `StatefulWidget` when no state is needed - Use trailing commas for better formatting (especially in widget trees) ### State Management - Riverpod - Use **riverpod_annotation** with code generation for providers - Provider files should have corresponding `.g.dart` files - Use `@riverpod` annotation for provider functions - Run `flutter pub run build_runner build` to generate provider code - Consume providers using `ref.watch()` in widgets (via ConsumerWidget or Consumer) - Use `ref.read()` for one-time reads in callbacks ### Data Models - Freezed - All data models use **Freezed** for immutability - Include both `.freezed.dart` and `.g.dart` parts - Use `@freezed` annotation for models - Define `fromJson` factory for JSON deserialization - Private constructor pattern: `const ModelName._();` - Run `flutter pub run build_runner build` to generate model code ### Database Patterns - Singleton pattern for DatabaseHelper (`DatabaseHelper.instance`) - Table definitions as static constants in table classes - Use foreign key constraints - Repository pattern for data access - All database operations should be async ### Service Layer - Services are injectable via constructor parameters - Default implementations provided with null coalescing - Use Dio for HTTP operations with proper error handling - Parser services are separate from network services ### Code Structure - **Imports**: Organize as package imports, relative imports, then part files - **Theme**: Uses Material 3 (`useMaterial3: true`) - **Documentation**: Use `///` for public API documentation comments - **Regular comments**: Use `//` for implementation comments - **Debug output**: Use `debugPrint()` instead of `print()` ### Type Annotations - Prefer explicit types for public APIs and class fields - Type inference acceptable for local variables when obvious - Always specify return types for functions and methods ### Error Handling - Use try-catch for async operations that may fail - Provide meaningful error messages - Handle HTTP errors appropriately - Log errors with `debugPrint()` for debugging ### Authentication - Credentials stored encrypted in SQLite - Authentication handled via AuthService - Dio clients created per-server with auth configuration ### File Organization - Group related functionality in directories (screens, services, models, etc.) - Keep widget files focused on single widgets or screens - Extract reusable widgets to `lib/widgets/` - Screen-specific widgets can go in `screens//widgets/` ### Code Generation Run code generation after modifying: - Models with `@freezed` annotation - Providers with `@riverpod` annotation - Models with `@JsonSerializable` annotation Command: `flutter pub run build_runner build --delete-conflicting-outputs`