import 'package:flutter/material.dart'; import '../theme/app_theme.dart'; /// 错误状态组件 /// 用于显示错误时的友好提示 class ErrorStateWidget extends StatelessWidget { final String? title; final String? message; final String? actionLabel; final VoidCallback? onRetry; final IconData icon; final bool showDetails; const ErrorStateWidget({ super.key, this.title, this.message, this.actionLabel, this.onRetry, this.icon = Icons.error_outline, this.showDetails = false, }); /// 默认错误状态 factory ErrorStateWidget.generic({ String? message, VoidCallback? onRetry, }) { return ErrorStateWidget( title: '加载失败', message: message ?? '请检查网络连接后重试', actionLabel: '重试', onRetry: onRetry, ); } /// 权限错误 factory ErrorStateWidget.permission({ VoidCallback? onRetry, }) { return ErrorStateWidget( icon: Icons.security, title: '权限未授予', message: '需要授予应用使用权限才能追踪时间\n\n请在系统设置中开启"使用情况访问权限"', actionLabel: '去设置', onRetry: onRetry, ); } /// 网络错误 factory ErrorStateWidget.network({ VoidCallback? onRetry, }) { return ErrorStateWidget( icon: Icons.wifi_off, title: '网络连接失败', message: '无法连接到服务器\n\n请检查网络连接后重试', actionLabel: '重试', onRetry: onRetry, ); } /// 数据加载错误 factory ErrorStateWidget.dataLoad({ String? message, VoidCallback? onRetry, }) { return ErrorStateWidget( icon: Icons.cloud_off, title: '数据加载失败', message: message ?? '无法加载数据,请稍后重试', actionLabel: '重试', onRetry: onRetry, ); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 100, height: 100, decoration: BoxDecoration( color: AppTheme.errorColor.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( icon, size: 56, color: AppTheme.errorColor, ), ), const SizedBox(height: 24), Text( title ?? '出错了', style: theme.textTheme.titleLarge?.copyWith( fontWeight: FontWeight.w600, color: theme.colorScheme.error, ), textAlign: TextAlign.center, ), if (message != null) ...[ const SizedBox(height: 12), Text( message!, style: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onSurface.withOpacity(0.7), ), textAlign: TextAlign.center, ), ], if (actionLabel != null && onRetry != null) ...[ const SizedBox(height: 24), ElevatedButton.icon( onPressed: onRetry, icon: const Icon(Icons.refresh), label: Text(actionLabel!), style: ElevatedButton.styleFrom( backgroundColor: AppTheme.errorColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12, ), ), ), ], ], ), ), ); } }