import 'package:flutter/material.dart'; import '../../app/theme/app_colors.dart'; import '../../app/theme/app_typography.dart'; import '../../app/theme/app_spacing.dart'; /// Genex 按钮组件 /// /// 统一的按钮样式,支持 primary/secondary/outline/text 4种变体 class GenexButton extends StatelessWidget { final String label; final VoidCallback? onPressed; final GenexButtonVariant variant; final GenexButtonSize size; final IconData? icon; final bool isLoading; final bool fullWidth; const GenexButton({ super.key, required this.label, this.onPressed, this.variant = GenexButtonVariant.primary, this.size = GenexButtonSize.large, this.icon, this.isLoading = false, this.fullWidth = true, }); @override Widget build(BuildContext context) { final child = Row( mainAxisSize: fullWidth ? MainAxisSize.max : MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ if (isLoading) ...[ SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(_foregroundColor), ), ), const SizedBox(width: 8), ], if (icon != null && !isLoading) ...[ Icon(icon, size: 20), const SizedBox(width: 6), ], Text(label), ], ); final effectiveOnPressed = isLoading ? null : onPressed; Widget button; switch (variant) { case GenexButtonVariant.primary: button = ElevatedButton( onPressed: effectiveOnPressed, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: Colors.white, disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.4), disabledForegroundColor: Colors.white70, elevation: 0, shape: RoundedRectangleBorder( borderRadius: AppSpacing.borderRadiusMd, ), textStyle: _textStyle, ), child: child, ); case GenexButtonVariant.secondary: button = ElevatedButton( onPressed: effectiveOnPressed, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primarySurface, foregroundColor: AppColors.primary, elevation: 0, shape: RoundedRectangleBorder( borderRadius: AppSpacing.borderRadiusMd, ), textStyle: _textStyle, ), child: child, ); case GenexButtonVariant.outline: button = OutlinedButton( onPressed: effectiveOnPressed, style: OutlinedButton.styleFrom( foregroundColor: AppColors.primary, side: const BorderSide(color: AppColors.primary, width: 1.5), shape: RoundedRectangleBorder( borderRadius: AppSpacing.borderRadiusMd, ), textStyle: _textStyle, ), child: child, ); case GenexButtonVariant.text: button = TextButton( onPressed: effectiveOnPressed, style: TextButton.styleFrom( foregroundColor: AppColors.primary, textStyle: _textStyle, ), child: child, ); } // Use LayoutBuilder to safely handle fullWidth in unbounded contexts (e.g. Row) if (fullWidth) { return LayoutBuilder( builder: (context, constraints) => SizedBox( width: constraints.hasBoundedWidth ? double.infinity : null, height: _height, child: button, ), ); } return SizedBox(height: _height, child: button); } double get _height { switch (size) { case GenexButtonSize.large: return AppSpacing.buttonHeight; case GenexButtonSize.medium: return AppSpacing.buttonHeightSm; case GenexButtonSize.small: return 32; } } TextStyle get _textStyle { switch (size) { case GenexButtonSize.large: return AppTypography.labelLarge; case GenexButtonSize.medium: return AppTypography.labelMedium; case GenexButtonSize.small: return AppTypography.labelSmall; } } Color get _foregroundColor { switch (variant) { case GenexButtonVariant.primary: return Colors.white; default: return AppColors.primary; } } } enum GenexButtonVariant { primary, secondary, outline, text } enum GenexButtonSize { large, medium, small }