8.6 KiB
8.6 KiB
Quick Reference Guide - New UX Components
🎯 Quick Start Guide for Developers
1. Skeleton Loaders
When to use: Show during data loading to indicate progress
// Full dashboard skeleton
if (isLoading) {
return const SkeletonDashboard();
}
// Individual skeleton cards
SkeletonCard()
SkeletonStatsCard()
SkeletonListItem()
// Custom skeleton
SkeletonLoader(
width: 200.w,
height: 40.h,
borderRadius: BorderRadius.circular(12.r),
)
2. Enhanced Notifications
Import:
import '../../core/utils/snackbar_util.dart';
Usage:
// Success (Green)
SnackbarUtil.showSuccess('Group created successfully!');
// Error (Red)
SnackbarUtil.showError('Failed to save payment');
// Warning (Orange)
SnackbarUtil.showWarning('Payment deadline approaching');
// Info (Blue)
SnackbarUtil.showInfo('Feature coming soon', title: 'Coming Soon');
// With custom title
SnackbarUtil.showError(
'Please check your internet connection',
title: 'Connection Error',
);
// Loading (can be dismissed programmatically)
SnackbarUtil.showLoading('Processing payment...');
// Later...
SnackbarUtil.dismiss();
// With action button
SnackbarUtil.showWithAction(
title: 'Payment Due',
message: 'You have a pending payment of ₹5,000',
actionLabel: 'Pay Now',
onAction: () => navigateToPayment(),
type: SnackbarType.warning,
);
3. Empty States
Import:
import '../../shared/widgets/empty_state_widget.dart';
Usage:
// Pre-configured empty states
EmptyStateWidget(
type: EmptyStateType.noGroups,
actionLabel: 'Create Group',
onActionPressed: () => showCreateDialog(),
)
// Available types:
// - EmptyStateType.noGroups
// - EmptyStateType.noMembers
// - EmptyStateType.noPayments
// - EmptyStateType.noActivities
// - EmptyStateType.noResults
// - EmptyStateType.error
// - EmptyStateType.noInternet
// Custom empty state
EmptyStateWidget(
type: EmptyStateType.noGroups,
customTitle: 'Your Custom Title',
customMessage: 'Your custom message here',
actionLabel: 'Custom Action',
onActionPressed: () => doSomething(),
)
// Compact version for smaller spaces
CompactEmptyState(
icon: Icons.inbox_rounded,
message: 'No items found',
color: Colors.grey.shade600,
)
4. Interactive Cards
Import:
import '../../shared/widgets/interactive_card.dart';
Usage:
Basic Interactive Card
InteractiveCard(
onTap: () => navigateToDetails(),
child: Column(
children: [
Text('Card Title'),
Text('Card Description'),
],
),
)
Stats Card
InteractiveStatsCard(
title: 'Active Groups',
value: '12',
icon: Icons.group,
color: Colors.blue.shade600,
onTap: () => navigateToGroups(),
subtitle: 'Last updated today', // Optional
)
Quick Action Card
QuickActionCard(
title: 'Create New Group',
subtitle: 'Start a new chit fund',
icon: Icons.group_add,
color: Colors.green.shade600,
onTap: () => showCreateDialog(),
)
Activity Card
ActivityCard(
title: 'Payment Received',
description: 'John Doe paid ₹5,000',
time: '2h ago',
icon: Icons.payment,
color: Colors.green.shade600,
onTap: () => viewPaymentDetails(), // Optional
)
Advanced InteractiveCard Options
InteractiveCard(
onTap: () => doSomething(),
onLongPress: () => showOptions(),
padding: EdgeInsets.all(20.w),
margin: EdgeInsets.all(8.w),
backgroundColor: Colors.white,
elevation: 4.0,
borderRadius: BorderRadius.circular(16.r),
enableHoverEffect: true,
enableRipple: true,
splashColor: Colors.blue.withOpacity(0.2),
child: YourContent(),
)
🎨 Color Guidelines
Use these consistent colors across the app:
// Success / Positive
Colors.green.shade600 // #43A047
// Error / Negative
Colors.red.shade600 // #E53935
// Warning / Caution
Colors.orange.shade600 // #FB8C00
// Info / Neutral
Colors.blue.shade600 // #1E88E5
// Action / Primary
Colors.purple.shade600 // #8E24AA
📐 Spacing Guidelines
Use consistent spacing throughout:
// Small spacing
SizedBox(height: 8.h) // Between related items
SizedBox(width: 8.w)
// Medium spacing
SizedBox(height: 16.h) // Between sections
SizedBox(width: 16.w)
// Large spacing
SizedBox(height: 24.h) // Between major sections
SizedBox(width: 24.w)
🔧 Common Patterns
Loading Pattern
Obx(() {
if (controller.isLoading.value) {
return const SkeletonDashboard();
}
if (controller.items.isEmpty) {
return EmptyStateWidget(
type: EmptyStateType.noGroups,
onActionPressed: () => controller.createItem(),
);
}
return YourContentWidget();
})
Error Handling Pattern
try {
await someOperation();
SnackbarUtil.showSuccess('Operation completed!');
} catch (e) {
SnackbarUtil.showError(
'Something went wrong. Please try again.',
title: 'Error',
);
}
Confirmation Pattern
QuickActionCard(
title: 'Delete Group',
icon: Icons.delete,
color: Colors.red.shade600,
onTap: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Confirm Delete'),
content: Text('Are you sure?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel'),
),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
deleteGroup();
SnackbarUtil.showSuccess('Group deleted');
},
child: Text('Delete'),
),
],
),
);
},
)
⚡ Performance Tips
-
Use const constructors when possible
const SkeletonDashboard() // Good SkeletonDashboard() // Less optimal -
Avoid rebuilding expensive widgets
Obx(() { if (isLoading.value) return const SkeletonDashboard(); return const YourContent(); // const helps }) -
Reuse card instances when building lists
ListView.builder( itemBuilder: (context, index) { return ActivityCard( key: ValueKey(items[index].id), // Add key for better performance title: items[index].title, // ... ); }, )
🐛 Troubleshooting
Issue: Snackbar not showing
Solution: Make sure you're using Get.context or have a valid BuildContext
// If outside widget tree
SnackbarUtil.showError('Error message');
// Still need GetX initialized
void main() {
runApp(GetMaterialApp(home: App()));
}
Issue: Skeleton loader not animating
Solution: Ensure parent widget has proper size constraints
// Bad
Container(child: SkeletonLoader())
// Good
Container(
width: 200.w,
height: 40.h,
child: SkeletonLoader(),
)
Issue: Interactive card not responding
Solution: Check if there's a conflicting GestureDetector in parent
// Remove or set behavior
GestureDetector(
behavior: HitTestBehavior.translucent, // Add this
onTap: () {},
child: InteractiveCard(...),
)
📱 Testing Checklist
When adding new features, test:
- ✅ Loading state (skeleton loader appears)
- ✅ Empty state (shows when no data)
- ✅ Success state (content displays correctly)
- ✅ Error state (error message shows)
- ✅ Tap interactions (cards respond to touch)
- ✅ Pull-to-refresh (works on mobile)
- ✅ Notifications (appear and dismiss correctly)
🎓 Best Practices
-
Always show feedback for user actions
onPressed: () async { SnackbarUtil.showLoading('Saving...'); await save(); SnackbarUtil.dismiss(); SnackbarUtil.showSuccess('Saved!'); } -
Provide clear empty states
// Bad: Just showing nothing if (items.isEmpty) return SizedBox(); // Good: Show helpful empty state if (items.isEmpty) { return EmptyStateWidget( type: EmptyStateType.noItems, onActionPressed: () => createItem(), ); } -
Use appropriate colors for context
// Success actions SnackbarUtil.showSuccess(...) // Destructive actions SnackbarUtil.showWarning('This will delete all data') // Errors SnackbarUtil.showError('Failed to connect') -
Keep interactions consistent
// All cards should use InteractiveCard // All notifications should use SnackbarUtil // All empty states should use EmptyStateWidget
📚 More Resources
- Flutter Documentation: https://flutter.dev/docs
- GetX Documentation: https://pub.dev/packages/get
- Material Design: https://material.io/design
Happy Coding! 🚀