// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../theme/app_colors.dart'; const double _regularArtSize = 96; const double _compactArtSize = 64; const double _regularIconSize = 42; const double _compactIconSize = 28; const double _regularRadius = 28; const double _compactRadius = 18; const double _maxContentWidth = 280; const double _actionMinHeight = 44; const double _artOpacity = 0.11; /// 统一空列表占位:柔和图标、标题、可选说明与操作。 class EmptyState extends StatelessWidget { const EmptyState({ super.key, required this.icon, required this.title, this.subtitle, this.actionLabel, this.onAction, this.compact = false, }); final IconData icon; final String title; final String? subtitle; final String? actionLabel; final VoidCallback? onAction; final bool compact; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; final dark = Theme.of(context).brightness == Brightness.dark; final iconColor = dark ? AppColors.blueSoft : AppColors.blue; final artSize = compact ? _compactArtSize : _regularArtSize; final iconSize = compact ? _compactIconSize : _regularIconSize; final hasAction = actionLabel != null && onAction != null; return Center( child: ConstrainedBox( key: const Key('empty-state-content'), constraints: const BoxConstraints(maxWidth: _maxContentWidth), child: Padding( padding: EdgeInsets.all(compact ? 16 : 24), child: Semantics( container: true, label: title, child: Column( mainAxisSize: MainAxisSize.min, children: [ ExcludeSemantics( child: Container( key: const Key('empty-state-art'), width: artSize, height: artSize, alignment: Alignment.center, decoration: BoxDecoration( color: AppColors.blue.withValues(alpha: _artOpacity), borderRadius: BorderRadius.circular( compact ? _compactRadius : _regularRadius, ), ), child: Icon( icon, key: const Key('empty-state-icon'), size: iconSize, color: iconColor, ), ), ), SizedBox(height: compact ? 10 : 16), ExcludeSemantics( child: Text( title, key: const Key('empty-state-title'), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: TextStyle( color: scheme.onSurface, fontSize: compact ? 14 : 16, fontWeight: FontWeight.w600, height: 1.35, ), ), ), if (subtitle != null) ...[ const SizedBox(height: 6), ExcludeSemantics( child: Text( subtitle!, maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: const TextStyle( color: AppColors.muted, fontSize: 13, height: 1.4, ), ), ), ], if (hasAction) ...[ const SizedBox(height: 10), TextButton( key: const Key('empty-state-action'), onPressed: onAction, style: TextButton.styleFrom( foregroundColor: scheme.primary, minimumSize: const Size(44, _actionMinHeight), padding: const EdgeInsets.symmetric(horizontal: 14), ), child: Text(actionLabel!), ), ], ], ), ), ), ), ); } }