đ Dashboard Feature Example
FLX CLI āĻĻāĻŋāϝāĻŧā§ āϤā§āϰāĻŋ āĻšāĻāϝāĻŧāĻž āĻāĻāĻāĻŋ complete dashboard feature-āĻāϰ boilerplate code exampleāĨ¤
đ Command to Generateâ
flx gen feature dashboard
đ Generated Structureâ
lib/features/dashboard/
âââ data/
â âââ datasources/
â â âââ dashboard_remote_data_source.dart
â âââ models/
â â âââ dashboard_model.dart
â âââ repositories/
â âââ dashboard_repository_impl.dart
âââ domain/
â âââ entities/
â â âââ dashboard_entity.dart
â âââ repositories/
â â âââ dashboard_repository.dart
â âââ usecases/
â âââ dashboard_usecase.dart
âââ presentation/
âââ bindings/
â âââ dashboard_binding.dart
âââ controllers/ # GetX
â âââ dashboard_controller.dart
âââ pages/
âââ dashboard_page.dart
đī¸ Domain Layerâ
Dashboard Entityâ
class DashboardEntity {
final String userId;
final String userName;
final String userEmail;
final DashboardStats stats;
final List<DashboardActivity> recentActivities;
final List<DashboardChart> charts;
final DateTime lastUpdated;
const DashboardEntity({
required this.userId,
required this.userName,
required this.userEmail,
required this.stats,
required this.recentActivities,
required this.charts,
required this.lastUpdated,
});
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is DashboardEntity &&
other.userId == userId &&
other.userName == userName &&
other.userEmail == userEmail &&
other.stats == stats &&
other.recentActivities == recentActivities &&
other.charts == charts &&
other.lastUpdated == lastUpdated;
}
@override
int get hashCode {
return userId.hashCode ^
userName.hashCode ^
userEmail.hashCode ^
stats.hashCode ^
recentActivities.hashCode ^
charts.hashCode ^
lastUpdated.hashCode;
}
}
class DashboardStats {
final int totalUsers;
final int totalOrders;
final double totalRevenue;
final int pendingTasks;
final double completionRate;
final int activeProjects;
const DashboardStats({
required this.totalUsers,
required this.totalOrders,
required this.totalRevenue,
required this.pendingTasks,
required this.completionRate,
required this.activeProjects,
});
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is DashboardStats &&
other.totalUsers == totalUsers &&
other.totalOrders == totalOrders &&
other.totalRevenue == totalRevenue &&
other.pendingTasks == pendingTasks &&
other.completionRate == completionRate &&
other.activeProjects == activeProjects;
}
@override
int get hashCode {
return totalUsers.hashCode ^
totalOrders.hashCode ^
totalRevenue.hashCode ^
pendingTasks.hashCode ^
completionRate.hashCode ^
activeProjects.hashCode;
}
}
class DashboardActivity {
final String id;
final String title;
final String description;
final String type;
final DateTime timestamp;
final String? iconUrl;
const DashboardActivity({
required this.id,
required this.title,
required this.description,
required this.type,
required this.timestamp,
this.iconUrl,
});
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is DashboardActivity &&
other.id == id &&
other.title == title &&
other.description == description &&
other.type == type &&
other.timestamp == timestamp &&
other.iconUrl == iconUrl;
}
@override
int get hashCode {
return id.hashCode ^
title.hashCode ^
description.hashCode ^
type.hashCode ^
timestamp.hashCode ^
iconUrl.hashCode;
}
}
class DashboardChart {
final String id;
final String title;
final String type; // line, bar, pie, etc.
final List<ChartDataPoint> data;
final Map<String, dynamic> config;
const DashboardChart({
required this.id,
required this.title,
required this.type,
required this.data,
required this.config,
});
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is DashboardChart &&
other.id == id &&
other.title == title &&
other.type == type &&
other.data == data &&
other.config == config;
}
@override
int get hashCode {
return id.hashCode ^
title.hashCode ^
type.hashCode ^
data.hashCode ^
config.hashCode;
}
}
class ChartDataPoint {
final String label;
final double value;
final DateTime? timestamp;
final String? color;
const ChartDataPoint({
required this.label,
required this.value,
this.timestamp,
this.color,
});
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ChartDataPoint &&
other.label == label &&
other.value == value &&
other.timestamp == timestamp &&
other.color == color;
}
@override
int get hashCode {
return label.hashCode ^
value.hashCode ^
timestamp.hashCode ^
color.hashCode;
}
}
Dashboard Repository Interfaceâ
import '../entities/dashboard_entity.dart';
abstract class DashboardRepository {
/// Get dashboard data for current user
Future<DashboardEntity> getDashboardData();
/// Get dashboard stats only
Future<DashboardStats> getDashboardStats();
/// Get recent activities
Future<List<DashboardActivity>> getRecentActivities({
int limit = 10,
});
/// Get chart data by chart ID
Future<DashboardChart> getChartData(String chartId);
/// Get all available charts
Future<List<DashboardChart>> getAllCharts();
/// Refresh dashboard data
Future<DashboardEntity> refreshDashboard();
/// Update dashboard preferences
Future<void> updateDashboardPreferences(Map<String, dynamic> preferences);
/// Export dashboard data
Future<String> exportDashboardData({
required String format, // pdf, excel, csv
String? dateRange,
});
}
Dashboard Use Caseâ
import '../entities/dashboard_entity.dart';
import '../repositories/dashboard_repository.dart';
class DashboardUseCase {
final DashboardRepository _repository;
DashboardUseCase(this._repository);
/// Get complete dashboard data
Future<DashboardEntity> getDashboardData() async {
try {
final dashboardData = await _repository.getDashboardData();
return dashboardData;
} catch (e) {
throw Exception('Failed to load dashboard: ${e.toString()}');
}
}
/// Get dashboard stats with validation
Future<DashboardStats> getDashboardStats() async {
try {
final stats = await _repository.getDashboardStats();
return _validateStats(stats);
} catch (e) {
throw Exception('Failed to load dashboard stats: ${e.toString()}');
}
}
/// Get recent activities with filtering
Future<List<DashboardActivity>> getRecentActivities({
int limit = 10,
String? activityType,
}) async {
try {
if (limit <= 0 || limit > 100) {
throw Exception('Limit must be between 1 and 100');
}
var activities = await _repository.getRecentActivities(limit: limit);
// Filter by activity type if provided
if (activityType != null && activityType.isNotEmpty) {
activities = activities
.where((activity) => activity.type == activityType)
.toList();
}
return activities;
} catch (e) {
throw Exception('Failed to load activities: ${e.toString()}');
}
}
/// Get chart data with validation
Future<DashboardChart> getChartData(String chartId) async {
if (chartId.isEmpty) {
throw Exception('Chart ID is required');
}
try {
final chart = await _repository.getChartData(chartId);
return _validateChart(chart);
} catch (e) {
throw Exception('Failed to load chart data: ${e.toString()}');
}
}
/// Get all charts with sorting
Future<List<DashboardChart>> getAllCharts({
String sortBy = 'title',
}) async {
try {
var charts = await _repository.getAllCharts();
// Sort charts
switch (sortBy) {
case 'title':
charts.sort((a, b) => a.title.compareTo(b.title));
break;
case 'type':
charts.sort((a, b) => a.type.compareTo(b.type));
break;
default:
// Keep original order
break;
}
return charts;
} catch (e) {
throw Exception('Failed to load charts: ${e.toString()}');
}
}
/// Refresh dashboard with caching logic
Future<DashboardEntity> refreshDashboard() async {
try {
final refreshedData = await _repository.refreshDashboard();
return refreshedData;
} catch (e) {
throw Exception('Failed to refresh dashboard: ${e.toString()}');
}
}
/// Update preferences with validation
Future<void> updateDashboardPreferences(
Map<String, dynamic> preferences,
) async {
if (preferences.isEmpty) {
throw Exception('Preferences cannot be empty');
}
try {
await _repository.updateDashboardPreferences(preferences);
} catch (e) {
throw Exception('Failed to update preferences: ${e.toString()}');
}
}
/// Export dashboard data with format validation
Future<String> exportDashboardData({
required String format,
String? dateRange,
}) async {
final supportedFormats = ['pdf', 'excel', 'csv'];
if (!supportedFormats.contains(format.toLowerCase())) {
throw Exception('Unsupported format: $format');
}
try {
final exportPath = await _repository.exportDashboardData(
format: format.toLowerCase(),
dateRange: dateRange,
);
return exportPath;
} catch (e) {
throw Exception('Failed to export dashboard: ${e.toString()}');
}
}
/// Calculate performance metrics
Map<String, double> calculatePerformanceMetrics(DashboardStats stats) {
return {
'user_growth_rate': _calculateGrowthRate(stats.totalUsers),
'order_conversion_rate': _calculateConversionRate(
stats.totalOrders,
stats.totalUsers,
),
'average_revenue_per_user': _calculateAverageRevenue(
stats.totalRevenue,
stats.totalUsers,
),
'task_completion_rate': stats.completionRate,
'project_efficiency': _calculateProjectEfficiency(
stats.activeProjects,
stats.pendingTasks,
),
};
}
// Private validation methods
DashboardStats _validateStats(DashboardStats stats) {
if (stats.totalUsers < 0 ||
stats.totalOrders < 0 ||
stats.totalRevenue < 0 ||
stats.pendingTasks < 0 ||
stats.activeProjects < 0) {
throw Exception('Invalid stats: negative values detected');
}
if (stats.completionRate < 0 || stats.completionRate > 100) {
throw Exception('Invalid completion rate: must be between 0 and 100');
}
return stats;
}
DashboardChart _validateChart(DashboardChart chart) {
if (chart.data.isEmpty) {
throw Exception('Chart data cannot be empty');
}
for (final dataPoint in chart.data) {
if (dataPoint.value.isNaN || dataPoint.value.isInfinite) {
throw Exception('Invalid chart data: NaN or Infinite values detected');
}
}
return chart;
}
// Private calculation methods
double _calculateGrowthRate(int totalUsers) {
// Simplified growth rate calculation
// In real app, you'd compare with previous period
return totalUsers > 0 ? 15.5 : 0.0;
}
double _calculateConversionRate(int orders, int users) {
if (users == 0) return 0.0;
return (orders / users) * 100;
}
double _calculateAverageRevenue(double revenue, int users) {
if (users == 0) return 0.0;
return revenue / users;
}
double _calculateProjectEfficiency(int projects, int pendingTasks) {
if (projects == 0) return 0.0;
final efficiency = ((projects - (pendingTasks / projects)) / projects) * 100;
return efficiency.clamp(0.0, 100.0);
}
}
đ Data Layerâ
Dashboard Modelâ
import '../../domain/entities/dashboard_entity.dart';
class DashboardModel extends DashboardEntity {
const DashboardModel({
required super.userId,
required super.userName,
required super.userEmail,
required super.stats,
required super.recentActivities,
required super.charts,
required super.lastUpdated,
});
factory DashboardModel.fromJson(Map<String, dynamic> json) {
return DashboardModel(
userId: json['user_id'] as String,
userName: json['user_name'] as String,
userEmail: json['user_email'] as String,
stats: DashboardStatsModel.fromJson(json['stats'] as Map<String, dynamic>),
recentActivities: (json['recent_activities'] as List)
.map((activity) => DashboardActivityModel.fromJson(activity))
.toList(),
charts: (json['charts'] as List)
.map((chart) => DashboardChartModel.fromJson(chart))
.toList(),
lastUpdated: DateTime.parse(json['last_updated'] as String),
);
}
Map<String, dynamic> toJson() {
return {
'user_id': userId,
'user_name': userName,
'user_email': userEmail,
'stats': (stats as DashboardStatsModel).toJson(),
'recent_activities': recentActivities
.map((activity) => (activity as DashboardActivityModel).toJson())
.toList(),
'charts': charts
.map((chart) => (chart as DashboardChartModel).toJson())
.toList(),
'last_updated': lastUpdated.toIso8601String(),
};
}
DashboardModel copyWith({
String? userId,
String? userName,
String? userEmail,
DashboardStats? stats,
List<DashboardActivity>? recentActivities,
List<DashboardChart>? charts,
DateTime? lastUpdated,
}) {
return DashboardModel(
userId: userId ?? this.userId,
userName: userName ?? this.userName,
userEmail: userEmail ?? this.userEmail,
stats: stats ?? this.stats,
recentActivities: recentActivities ?? this.recentActivities,
charts: charts ?? this.charts,
lastUpdated: lastUpdated ?? this.lastUpdated,
);
}
}
class DashboardStatsModel extends DashboardStats {
const DashboardStatsModel({
required super.totalUsers,
required super.totalOrders,
required super.totalRevenue,
required super.pendingTasks,
required super.completionRate,
required super.activeProjects,
});
factory DashboardStatsModel.fromJson(Map<String, dynamic> json) {
return DashboardStatsModel(
totalUsers: json['total_users'] as int,
totalOrders: json['total_orders'] as int,
totalRevenue: (json['total_revenue'] as num).toDouble(),
pendingTasks: json['pending_tasks'] as int,
completionRate: (json['completion_rate'] as num).toDouble(),
activeProjects: json['active_projects'] as int,
);
}
Map<String, dynamic> toJson() {
return {
'total_users': totalUsers,
'total_orders': totalOrders,
'total_revenue': totalRevenue,
'pending_tasks': pendingTasks,
'completion_rate': completionRate,
'active_projects': activeProjects,
};
}
}
class DashboardActivityModel extends DashboardActivity {
const DashboardActivityModel({
required super.id,
required super.title,
required super.description,
required super.type,
required super.timestamp,
super.iconUrl,
});
factory DashboardActivityModel.fromJson(Map<String, dynamic> json) {
return DashboardActivityModel(
id: json['id'] as String,
title: json['title'] as String,
description: json['description'] as String,
type: json['type'] as String,
timestamp: DateTime.parse(json['timestamp'] as String),
iconUrl: json['icon_url'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'description': description,
'type': type,
'timestamp': timestamp.toIso8601String(),
'icon_url': iconUrl,
};
}
}
class DashboardChartModel extends DashboardChart {
const DashboardChartModel({
required super.id,
required super.title,
required super.type,
required super.data,
required super.config,
});
factory DashboardChartModel.fromJson(Map<String, dynamic> json) {
return DashboardChartModel(
id: json['id'] as String,
title: json['title'] as String,
type: json['type'] as String,
data: (json['data'] as List)
.map((point) => ChartDataPointModel.fromJson(point))
.toList(),
config: json['config'] as Map<String, dynamic>,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'type': type,
'data': data
.map((point) => (point as ChartDataPointModel).toJson())
.toList(),
'config': config,
};
}
}
class ChartDataPointModel extends ChartDataPoint {
const ChartDataPointModel({
required super.label,
required super.value,
super.timestamp,
super.color,
});
factory ChartDataPointModel.fromJson(Map<String, dynamic> json) {
return ChartDataPointModel(
label: json['label'] as String,
value: (json['value'] as num).toDouble(),
timestamp: json['timestamp'] != null
? DateTime.parse(json['timestamp'] as String)
: null,
color: json['color'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'label': label,
'value': value,
'timestamp': timestamp?.toIso8601String(),
'color': color,
};
}
}
đ¨ Presentation Layer (GetX)â
Dashboard Controllerâ
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import '../../domain/entities/dashboard_entity.dart';
import '../../domain/usecases/dashboard_usecase.dart';
class DashboardController extends GetxController {
final DashboardUseCase _dashboardUseCase;
DashboardController(this._dashboardUseCase);
// Observable states
final _isLoading = false.obs;
final _isRefreshing = false.obs;
final _dashboardData = Rxn<DashboardEntity>();
final _stats = Rxn<DashboardStats>();
final _activities = <DashboardActivity>[].obs;
final _charts = <DashboardChart>[].obs;
final _selectedChartId = ''.obs;
final _errorMessage = ''.obs;
final _lastRefreshTime = Rxn<DateTime>();
// UI states
final _selectedTabIndex = 0.obs;
final _isGridView = true.obs;
final _showOnlyRecentActivities = true.obs;
// Getters
bool get isLoading => _isLoading.value;
bool get isRefreshing => _isRefreshing.value;
DashboardEntity? get dashboardData => _dashboardData.value;
DashboardStats? get stats => _stats.value;
List<DashboardActivity> get activities => _activities;
List<DashboardChart> get charts => _charts;
String get selectedChartId => _selectedChartId.value;
String get errorMessage => _errorMessage.value;
DateTime? get lastRefreshTime => _lastRefreshTime.value;
// UI getters
int get selectedTabIndex => _selectedTabIndex.value;
bool get isGridView => _isGridView.value;
bool get showOnlyRecentActivities => _showOnlyRecentActivities.value;
@override
void onInit() {
super.onInit();
loadDashboardData();
}
/// Load complete dashboard data
Future<void> loadDashboardData() async {
try {
_isLoading.value = true;
_errorMessage.value = '';
final data = await _dashboardUseCase.getDashboardData();
_dashboardData.value = data;
_stats.value = data.stats;
_activities.assignAll(data.recentActivities);
_charts.assignAll(data.charts);
_lastRefreshTime.value = DateTime.now();
// Select first chart by default
if (_charts.isNotEmpty) {
_selectedChartId.value = _charts.first.id;
}
} catch (e) {
_errorMessage.value = e.toString();
Get.snackbar(
'āϤā§āϰā§āĻāĻŋ!',
'āĻĄā§āϝāĻžāĻļāĻŦā§āϰā§āĻĄ āϞā§āĻĄ āĻāϰāϤ⧠āϏāĻŽāϏā§āϝāĻž: ${e.toString()}',
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
_isLoading.value = false;
}
}
/// Refresh dashboard data
Future<void> refreshDashboard() async {
try {
_isRefreshing.value = true;
_errorMessage.value = '';
final data = await _dashboardUseCase.refreshDashboard();
_dashboardData.value = data;
_stats.value = data.stats;
_activities.assignAll(data.recentActivities);
_charts.assignAll(data.charts);
_lastRefreshTime.value = DateTime.now();
Get.snackbar(
'āϏāĻĢāϞ!',
'āĻĄā§āϝāĻžāĻļāĻŦā§āϰā§āĻĄ āĻāĻĒāĻĄā§āĻ āĻšāϝāĻŧā§āĻā§',
backgroundColor: Colors.green,
colorText: Colors.white,
);
} catch (e) {
_errorMessage.value = e.toString();
Get.snackbar(
'āϤā§āϰā§āĻāĻŋ!',
'āĻĄā§āϝāĻžāĻļāĻŦā§āϰā§āĻĄ āϰāĻŋāĻĢā§āϰā§āĻļ āĻāϰāϤ⧠āϏāĻŽāϏā§āϝāĻž: ${e.toString()}',
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
_isRefreshing.value = false;
}
}
/// Load dashboard stats only
Future<void> loadStats() async {
try {
final stats = await _dashboardUseCase.getDashboardStats();
_stats.value = stats;
} catch (e) {
_errorMessage.value = e.toString();
}
}
/// Load recent activities with filtering
Future<void> loadActivities({
int limit = 10,
String? activityType,
}) async {
try {
final activities = await _dashboardUseCase.getRecentActivities(
limit: limit,
activityType: activityType,
);
_activities.assignAll(activities);
} catch (e) {
_errorMessage.value = e.toString();
Get.snackbar(
'āϤā§āϰā§āĻāĻŋ!',
'āĻāĻžāϰā§āϝāĻāϞāĻžāĻĒ āϞā§āĻĄ āĻāϰāϤ⧠āϏāĻŽāϏā§āϝāĻž: ${e.toString()}',
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
}
/// Load charts
Future<void> loadCharts({String sortBy = 'title'}) async {
try {
final charts = await _dashboardUseCase.getAllCharts(sortBy: sortBy);
_charts.assignAll(charts);
// Select first chart if none selected
if (_selectedChartId.value.isEmpty && charts.isNotEmpty) {
_selectedChartId.value = charts.first.id;
}
} catch (e) {
_errorMessage.value = e.toString();
Get.snackbar(
'āϤā§āϰā§āĻāĻŋ!',
'āĻāĻžāϰā§āĻ āϞā§āĻĄ āĻāϰāϤ⧠āϏāĻŽāϏā§āϝāĻž: ${e.toString()}',
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
}
/// Select a specific chart
void selectChart(String chartId) {
if (chartId.isNotEmpty) {
_selectedChartId.value = chartId;
}
}
/// Get selected chart
DashboardChart? getSelectedChart() {
if (_selectedChartId.value.isEmpty) return null;
try {
return _charts.firstWhere(
(chart) => chart.id == _selectedChartId.value,
);
} catch (e) {
return null;
}
}
/// Export dashboard data
Future<void> exportDashboard(String format) async {
try {
_isLoading.value = true;
final exportPath = await _dashboardUseCase.exportDashboardData(
format: format,
);
Get.snackbar(
'āϏāĻĢāϞ!',
'āĻĄā§āϝāĻžāĻļāĻŦā§āϰā§āĻĄ āĻāĻā§āϏāĻĒā§āϰā§āĻ āĻšāϝāĻŧā§āĻā§: $exportPath',
backgroundColor: Colors.green,
colorText: Colors.white,
duration: const Duration(seconds: 5),
);
} catch (e) {
Get.snackbar(
'āϤā§āϰā§āĻāĻŋ!',
'āĻāĻā§āϏāĻĒā§āϰā§āĻ āĻāϰāϤ⧠āϏāĻŽāϏā§āϝāĻž: ${e.toString()}',
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
_isLoading.value = false;
}
}
/// Calculate and get performance metrics
Map<String, double> getPerformanceMetrics() {
if (_stats.value == null) return {};
return _dashboardUseCase.calculatePerformanceMetrics(_stats.value!);
}
/// Filter activities by type
List<DashboardActivity> getFilteredActivities(String? type) {
if (type == null || type.isEmpty) {
return _activities;
}
return _activities.where((activity) => activity.type == type).toList();
}
/// Get unique activity types
List<String> getActivityTypes() {
return _activities.map((activity) => activity.type).toSet().toList();
}
/// UI methods
void setSelectedTabIndex(int index) {
_selectedTabIndex.value = index;
}
void toggleViewMode() {
_isGridView.value = !_isGridView.value;
}
void toggleActivityFilter() {
_showOnlyRecentActivities.value = !_showOnlyRecentActivities.value;
}
/// Format currency
String formatCurrency(double amount) {
return 'ā§ŗ${amount.toStringAsFixed(2)}';
}
/// Format percentage
String formatPercentage(double percentage) {
return '${percentage.toStringAsFixed(1)}%';
}
/// Format large numbers
String formatLargeNumber(int number) {
if (number >= 1000000) {
return '${(number / 1000000).toStringAsFixed(1)}M';
} else if (number >= 1000) {
return '${(number / 1000).toStringAsFixed(1)}K';
}
return number.toString();
}
/// Get time ago string
String getTimeAgo(DateTime dateTime) {
final now = DateTime.now();
final difference = now.difference(dateTime);
if (difference.inDays > 0) {
return '${difference.inDays} āĻĻāĻŋāύ āĻāĻā§';
} else if (difference.inHours > 0) {
return '${difference.inHours} āĻāύā§āĻāĻž āĻāĻā§';
} else if (difference.inMinutes > 0) {
return '${difference.inMinutes} āĻŽāĻŋāύāĻŋāĻ āĻāĻā§';
} else {
return 'āĻāĻāĻŽāĻžāϤā§āϰ';
}
}
/// Check if data is stale (older than 5 minutes)
bool get isDataStale {
if (_lastRefreshTime.value == null) return true;
final difference = DateTime.now().difference(_lastRefreshTime.value!);
return difference.inMinutes > 5;
}
/// Auto refresh if data is stale
void autoRefreshIfNeeded() {
if (isDataStale && !_isLoading.value && !_isRefreshing.value) {
refreshDashboard();
}
}
}
đ¯ Key Features Includedâ
- Complete Dashboard Overview: Stats, activities, charts
- Real-time Data: Auto-refresh capability
- Interactive Charts: Multiple chart types support
- Activity Feed: Recent activities with filtering
- Performance Metrics: Calculated KPIs
- Export Functionality: PDF, Excel, CSV export
- Responsive UI: Grid/List view toggle
- Error Handling: Comprehensive error management
- Data Validation: Input validation and sanitization
- Caching: Smart data caching and refresh logic
đ Usage Exampleâ
// In your UI
class DashboardStatsCard extends StatelessWidget {
Widget build(BuildContext context) {
final controller = Get.find<DashboardController>();
return Obx(() {
final stats = controller.stats;
if (stats == null) return CircularProgressIndicator();
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text('āĻŽā§āĻ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§: ${controller.formatLargeNumber(stats.totalUsers)}'),
Text('āĻŽā§āĻ āĻ
āϰā§āĻĄāĻžāϰ: ${controller.formatLargeNumber(stats.totalOrders)}'),
Text('āĻŽā§āĻ āĻāϝāĻŧ: ${controller.formatCurrency(stats.totalRevenue)}'),
Text('āϏāĻŽā§āĻĒā§āϰā§āĻŖāϤāĻžāϰ āĻšāĻžāϰ: ${controller.formatPercentage(stats.completionRate)}'),
],
),
),
);
});
}
}
// Activity list
class ActivityList extends StatelessWidget {
Widget build(BuildContext context) {
final controller = Get.find<DashboardController>();
return Obx(() => ListView.builder(
itemCount: controller.activities.length,
itemBuilder: (context, index) {
final activity = controller.activities[index];
return ListTile(
title: Text(activity.title),
subtitle: Text(activity.description),
trailing: Text(controller.getTimeAgo(activity.timestamp)),
);
},
));
}
}
āĻāĻ example-āĻ āϰāϝāĻŧā§āĻā§: āϏāĻŽā§āĻĒā§āϰā§āĻŖ dashboard feature āϝāĻž data visualization āĻāĻŦāĻ analytics āϏāĻš production-ready! đ