This guide covers development workflows, common patterns, and best practices for HazeBot Admin.
- Flutter SDK 3.0+ - Installation Guide
- VS Code or Android Studio - Recommended IDEs
- Chrome - For web development
- Android Studio - For Android development (optional)
VS Code Extensions:
- Flutter
- Dart
- Flutter Widget Snippets
- Error Lens
Android Studio Plugins:
- Flutter
- Dart
During development, Flutter provides hot reload for instant UI updates:
r- Hot reload (fast, preserves state)R- Hot restart (full restart, resets state)q- Quit development server
Hot Reload (r):
- UI changes (widgets, layouts, colors)
- Text changes
- Small logic changes
- Preserves app state
Hot Restart (R):
- Changes to
main() - Static field changes
- Global variable changes
- State needs to be reset
# Run static analysis
flutter analyze
# Fix auto-fixable issues
dart fix --apply# Format all Dart files
dart format .
# Format specific file
dart format lib/main.dart
# Check formatting without changes
dart format --output=none --set-exit-if-changed .# Check for outdated packages
flutter pub outdated
# Update dependencies
flutter pub upgrade
# Get dependencies
flutter pub get
# Clean and rebuild
flutter clean
flutter pub getStandard async API call with loading/error states:
class MyScreen extends StatefulWidget {
@override
State<MyScreen> createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
bool _isLoading = false;
String? _error;
List<dynamic> _data = [];
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
try {
setState(() {
_isLoading = true;
_error = null;
});
final result = await ApiService().getData();
if (mounted) {
setState(() {
_data = result['data'] ?? [];
_isLoading = false;
});
}
} catch (e) {
if (mounted) {
setState(() {
_error = e.toString();
_isLoading = false;
});
}
}
}
@override
Widget build(BuildContext context) {
if (_isLoading) {
return Center(child: CircularProgressIndicator());
}
if (_error != null) {
return Center(child: Text('Error: $_error'));
}
return ListView.builder(
itemCount: _data.length,
itemBuilder: (context, index) {
return ListTile(title: Text(_data[index].toString()));
},
);
}
}Key Points:
- ✅ Always check
mountedbefore setState() in async callbacks - ✅ Handle loading, error, and success states
- ✅ Use try-catch for error handling
- ✅ Clear previous errors before new requests
Proper color usage for depth perception:
// Scaffold background (lowest level)
Scaffold(
backgroundColor: Theme.of(context).colorScheme.surface,
body: ...
)
// Section card (low elevation)
Card(
color: Theme.of(context).colorScheme.surfaceContainerLow,
elevation: 0,
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text('Section Title'),
// Content card inside section (higher elevation)
Card(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
elevation: 0,
child: ListTile(
title: Text('Content'),
),
),
],
),
),
)
// Input fields (highest elevation)
TextField(
decoration: InputDecoration(
filled: true,
fillColor: Theme.of(context).colorScheme.surfaceContainerHighest,
),
)Surface Hierarchy:
surface- Scaffold backgroundsurfaceContainerLow- Section cardssurfaceContainer- Default containerssurfaceContainerHigh- Content cardssurfaceContainerHighest- Input fields, search bars
Always use elevation: 0 - Android 16 uses flat design with color depth instead of shadows.
Handle different screen sizes:
class ResponsiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
// Mobile
if (width < 600) {
return MobileLayout();
}
// Tablet
else if (width < 900) {
return TabletLayout();
}
// Desktop
else {
return DesktopLayout();
}
}
}
// Or use LayoutBuilder
class AdaptiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return SingleColumnLayout();
} else {
return TwoColumnLayout();
}
},
);
}
}Breakpoints:
- Mobile: < 600px
- Tablet: 600px - 899px
- Desktop: ≥ 900px
Push new screen:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NewScreen()),
);Push with Hero animation:
Hero(
tag: 'unique-tag',
child: Image.network(imageUrl),
)
// On destination screen
Hero(
tag: 'unique-tag',
child: Image.network(imageUrl),
)Pop with result:
// Push and wait for result
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => EditScreen()),
);
if (result == true) {
_loadData(); // Refresh data
}
// Pop with result
Navigator.pop(context, true);Local State (StatefulWidget):
class Counter extends StatefulWidget {
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Text('Count: $_count');
}
}Provider (for theme/auth):
// Define provider
class ThemeProvider extends ChangeNotifier {
bool _isDark = false;
bool get isDark => _isDark;
void toggleTheme() {
_isDark = !_isDark;
notifyListeners();
}
}
// Use in widget
final themeProvider = Provider.of<ThemeProvider>(context);
themeProvider.toggleTheme();# Run all tests
flutter test
# Run specific test file
flutter test test/widget_test.dart
# Run with coverage
flutter test --coverage
# View coverage report
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.htmlimport 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter increments', (WidgetTester tester) async {
// Build widget
await tester.pumpWidget(MyApp());
// Verify initial state
expect(find.text('0'), findsOneWidget);
// Tap button
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify updated state
expect(find.text('1'), findsOneWidget);
});
}// Simple debug print
print('Debug: $value');
// Debug print (removed in release)
debugPrint('Debug: $value');
// Only in debug mode
if (kDebugMode) {
print('Debug only: $value');
}# Launch DevTools
flutter pub global activate devtools
flutter pub global run devtools
# Run app with DevTools
flutter run --observatory-port=9100DevTools Features:
- Inspector - Widget tree visualization
- Performance - Frame rendering analysis
- Memory - Memory usage tracking
- Network - HTTP request monitoring
- Logging - Console output
Hot reload not working:
# Try hot restart instead
R
# Or full rebuild
flutter clean
flutter pub get
flutter runWidget not updating:
- Check if
setState()is called - Verify
mountedbefore setState() in async - Ensure widget is in StatefulWidget, not StatelessWidget
Layout overflow:
// Wrap in SingleChildScrollView
SingleChildScrollView(
child: Column(children: [...]),
)
// Or use Flexible/Expanded
Row(
children: [
Flexible(child: Text('Long text...')),
],
)// ✅ Good - const constructors
const Text('Hello')
// ❌ Bad - creates new widget every build
Text('Hello')
// ✅ Good - extract static widgets
final _staticWidget = Text('Static');
@override
Widget build(BuildContext context) {
return Column(children: [_staticWidget]);
}// Use cached network images
CachedNetworkImage(
imageUrl: url,
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
)
// Resize images
Image.network(
url,
width: 100,
height: 100,
fit: BoxFit.cover,
)// Use ListView.builder for long lists
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(title: Text(items[index]));
},
)
// Add keys for list items
ListView.builder(
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(items[index].id),
title: Text(items[index].name),
);
},
)# Create feature branch
git checkout -b feature/new-screen
# Make changes and commit
git add .
git commit -m "feat: add new screen"
# Push to remote
git push origin feature/new-screenFollow conventional commits:
feat:- New featurefix:- Bug fixrefactor:- Code refactoringstyle:- Formatting changesdocs:- Documentationtest:- Testschore:- Maintenance
Examples:
feat: add user profile screen
fix: resolve authentication timeout
refactor: extract common widgets
style: format code with dart format
docs: update setup instructions
- 🔨 Building Guide - Build for all platforms
- 📋 Features - Understand existing features
- 🔥 Firebase Setup - Configure notifications
- 🏠 Documentation Index - All documentation
Related Resources:
- 🤖 HazeBot Backend - Bot & API server
- 📖 HazeBot API - REST API reference
- 🏗️ Flutter Documentation - Official Flutter guides
- Development Issues: Check troubleshooting section above
- Flutter Questions: Flutter Documentation
- Project Questions: Open an issue on GitHub