Documentation Index
Fetch the complete documentation index at: https://docs.agentsoflearning.com/llms.txt
Use this file to discover all available pages before exploring further.
Code Quality Guidelines
Overview
This document outlines code quality standards and best practices for the AI-Powered Photo Journaling Flutter app.
Code Organization
Directory Structure
lib/
├── app.dart # Main app widget
├── main.dart # App entry point
├── config/ # Configuration
│ ├── constants.dart
│ ├── env.dart
│ ├── routes/
│ └── theme/
├── core/ # Core utilities
│ ├── accessibility/
│ ├── animations/
│ ├── database/
│ ├── error/
│ ├── interactions/
│ ├── services/
│ ├── utils/
│ └── widgets/
├── features/ # Feature modules
│ ├── entry/
│ ├── timeline/
│ ├── search/
│ ├── calendar/
│ ├── settings/
│ └── shared/
└── shared/ # Shared widgets
└── widgets/
Feature Module Structure
Each feature follows clean architecture:
feature_name/
├── data/
│ ├── models/ # Data models
│ └── services/ # API/database services
├── domain/
│ ├── entities/ # Business entities
│ └── repositories/ # Repository interfaces
└── presentation/
├── bloc/ # State management
├── screens/ # Screen widgets
└── widgets/ # Feature-specific widgets
Coding Standards
Dart Style Guide
Follow Effective Dart:
-
Naming:
- Classes:
PascalCase
- Functions/variables:
camelCase
- Constants:
lowerCamelCase
- Files:
snake_case.dart
-
Formatting:
- Use
dart format . before committing
- Max line length: 80 characters
- Use trailing commas for better diffs
-
Imports:
- Organize imports: dart → flutter → packages → relative
- Use relative imports for project files
- Avoid unused imports
- Use const constructors wherever possible:
// Good
const Text('Hello')
const SizedBox(height: 16)
// Bad
Text('Hello')
SizedBox(height: 16)
- Split large widgets into smaller, focused widgets:
// Good
class UserProfile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
const _ProfileHeader(),
const _ProfileStats(),
const _ProfileActions(),
],
);
}
}
class _ProfileHeader extends StatelessWidget {
const _ProfileHeader();
@override
Widget build(BuildContext context) {
// ...
}
}
- Use keys for list items:
ListView.builder(
itemBuilder: (context, index) {
return ListItem(
key: ValueKey(items[index].id),
item: items[index],
);
},
)
- Implement proper dispose:
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late ScrollController _controller;
@override
void initState() {
super.initState();
_controller = ScrollController();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListView(controller: _controller);
}
}
State Management
-
BLoC Pattern:
- Use
flutter_bloc for complex state
- Keep business logic in BLoC
- Use events for actions, states for UI updates
-
State Locality:
- Keep state as local as possible
- Avoid global state when not needed
- Use
StatefulWidget for local state
-
Immutability:
- Use immutable state classes
- Use
equatable for value equality
- Avoid mutable collections in state
Error Handling
- Use try-catch for async operations:
try {
final result = await apiCall();
return result;
} catch (error, stackTrace) {
ErrorHandler.logError(error, stackTrace: stackTrace);
rethrow;
}
- Provide user-friendly messages:
ErrorHandler.showErrorDialog(
context,
error,
userMessage: 'Failed to load entries. Please try again.',
);
- Log errors in debug mode:
if (kDebugMode) {
debugPrint('Error: $error');
}
- Const constructors: Prevent unnecessary rebuilds
- RepaintBoundary: Isolate expensive widgets
- ListView.builder: For long lists
- Lazy loading: Load data on demand
- Image caching: Use
cached_network_image
Memory Management
- Dispose controllers: Always dispose in
dispose()
- Cancel subscriptions: Cancel streams and listeners
- Weak references: Use when appropriate
- Image memory: Configure
maxCacheSize and maxCacheSizeBytes
Build Optimization
- Use profile mode for performance testing
- Enable obfuscation in release builds
- Tree-shake icons: Remove unused icons
- Split debug info: Reduce app size
Testing
Unit Tests
Test business logic and utilities:
test('should calculate total correctly', () {
final calculator = Calculator();
expect(calculator.add(2, 3), equals(5));
});
Test widget behavior:
testWidgets('should display error message', (tester) async {
await tester.pumpWidget(
ErrorDisplay(message: 'Test error'),
);
expect(find.text('Test error'), findsOneWidget);
});
Integration Tests
Test complete flows:
testWidgets('should create journal entry', (tester) async {
// Navigate to create entry
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
// Fill form
await tester.enterText(find.byKey(Key('title')), 'Test Entry');
// Submit
await tester.tap(find.text('Save'));
await tester.pumpAndSettle();
// Verify
expect(find.text('Test Entry'), findsOneWidget);
});
Documentation
- Document public APIs:
/// Creates a journal entry with the given [title] and [content].
///
/// Throws [ValidationException] if title is empty.
/// Returns the created entry's ID.
Future<String> createEntry({
required String title,
required String content,
}) async {
// Implementation
}
- Explain complex logic:
// Calculate weighted average based on emotion intensity
// Higher intensity emotions have more weight in the calculation
final weightedAverage = emotions
.map((e) => e.value * e.intensity)
.reduce((a, b) => a + b) / totalIntensity;
- Use TODO for future work:
// TODO(username): Implement offline support
// TODO: Add unit tests for edge cases
README Files
- Project root: Setup and overview
- Feature modules: Feature-specific docs
- Complex algorithms: Explanation and examples
Code Review Checklist
Before Submitting PR
Reviewing Code
Look for:
Common Anti-Patterns to Avoid
❌ Bad:
class MassiveWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
// 500 lines of nested widgets
],
);
}
}
✅ Good:
class OrganizedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
const _Header(),
const _Content(),
const _Footer(),
],
);
}
}
2. setState in Parent
❌ Bad:
setState(() {
// Rebuilds entire parent and all children
});
✅ Good:
// Use BLoC or local state in child widgets
3. Unnecessary Rebuilds
❌ Bad:
Widget build(BuildContext context) {
return Container(
child: Text('Static text'), // Rebuilds on every parent rebuild
);
}
✅ Good:
Widget build(BuildContext context) {
return Container(
child: const Text('Static text'), // Never rebuilds
);
}
4. Missing Dispose
❌ Bad:
class _State extends State<MyWidget> {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(...);
}
// Missing dispose - memory leak!
}
✅ Good:
class _State extends State<MyWidget> {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(...);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
Static Analysis
# Run analyzer
flutter analyze
# Fix auto-fixable issues
dart fix --apply
# Format code
dart format .
# Build in profile mode
flutter build ios --profile
# Run DevTools
flutter pub global activate devtools
flutter pub global run devtools
Code Coverage
# Run tests with coverage
flutter test --coverage
# Generate HTML report
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
Resources
Last Updated: 2025-11-15
Maintained By: Frontend Developer