Instruction file imported from AdI145-12/Dukaan-AI (
.github/instructions/flutter.instructions.md). Copyright stays with the author.
Flutter Instructions (lib/**)
Widget Pattern
- Always use
ConsumerWidget(Riverpod) — NEVERStatefulWidgetunless animation controller is required - Always use
ConsumerStatefulWidgetonly whenTickerProvideris needed - Every screen widget goes in
features/<feature>/presentation/screens/ - Every reusable widget goes in
features/<feature>/presentation/widgets/orshared/widgets/
State Management — Riverpod
- Use
@riverpodannotation + code generation for all providers - For async data: use
AsyncNotifierorFutureProvider - For mutable state: use
Notifierwith explicit state classes - State classes must be
@freezedimmutable data classes - NEVER use
ref.read()insidebuild()— onlyref.watch() - NEVER use
ref.watch()inside callbacks — onlyref.read() - Provider naming:
<featureName>Provider(e.g.,studioProvider,khataProvider)
Navigation — GoRouter
- All routes defined in
lib/core/router/app_router.dart - Route names as constants in
lib/core/router/app_routes.dart - Use
context.go()for tab navigation,context.push()for stack navigation - NEVER use
Navigator.of(context).push() - Pass data via GoRouter
extraor Riverpod — never via constructor for large objects
Performance (Low-End Android — Mandatory)
- Every
ListViewmust beListView.builder— NEVERListViewwith children - Every network image must use
CachedNetworkImagewith shimmer placeholder - Wrap each list item in
RepaintBoundary - Heavy computation (base64, compression, JSON parsing > 1KB): use
compute() - Use
AutomaticKeepAliveClientMixinon tab screens to prevent rebuild on tab switch - Add
constto every widget that does not depend on runtime data
Design Tokens (Always Use These — No Hardcoded Values)
// Colors
AppColors.primary // #FF6F00 saffron orange
AppColors.surface // #FAFAFA
AppColors.background // #111111 dark
AppColors.error // #D32F2F
AppColors.textPrimary // #1A1A1A
AppColors.textMuted // #757575
// Spacing
AppSpacing.xs // 4.0
AppSpacing.sm // 8.0
AppSpacing.md // 16.0
AppSpacing.lg // 24.0
AppSpacing.xl // 32.0
// Border Radius
AppRadius.card // 12.0
AppRadius.button // 8.0
AppRadius.chip // 20.0
Error Handling Pattern
// ALWAYS handle errors like this in providers:
try {
// operation
} on FirebaseException catch (e) {
throw AppException.firebase(e.message ?? AppStrings.errorGeneric);
} on StorageException catch (e) {
throw AppException.storage(e.message);
} catch (e) {
throw AppException.unknown(e.toString());
}
// NEVER do this:
} catch (e) {
print(e); // silent failure
}
Firebase in Flutter
- Firebase service wrapper:
lib/core/firebase/firebase_service.dart— useFirebaseService.dbandFirebaseService.currentUserId - ALWAYS specify Firestore fields explicitly in queries and reads
- NEVER use wildcard reads or writes when a narrow document path works
- For real-time: use Firestore
snapshots()via repository streams - Auth state: use
FirebaseService.currentUserIdin widgets and providers; never accessFirebaseAuth.instance.currentUserdirectly in widgets
Localization
- All user-facing strings in:
lib/core/constants/app_strings.dart - Format:
AppStrings.errorNetworkRetry→"Kuch gadbad ho gayi, dobara try karein 🙏" - Hinglish for errors, Hindi for labels, English for technical terms