import 'package:flutter/material.dart'; import '../core/app_colors.dart'; import '../core/app_design_tokens.dart'; enum AppButtonVariant { primary, secondary, outline, ghost, danger, gradientOutline } class AppButton extends StatelessWidget { final String label; final VoidCallback? onPressed; final IconData? icon; final AppButtonVariant variant; final Color? color; final LinearGradient? gradient; final bool loading; final double height; final bool expand; const AppButton({ super.key, required this.label, this.onPressed, this.icon, this.variant = AppButtonVariant.primary, this.color, this.gradient, this.loading = false, this.height = 50, this.expand = true, }); @override Widget build(BuildContext context) { final enabled = onPressed != null && !loading; final baseColor = color ?? AppColors.primary; final child = _ButtonContent( label: label, icon: icon, loading: loading, foreground: _foreground(baseColor), ); if (variant == AppButtonVariant.gradientOutline) { return _GradientOutlineButton( label: label, icon: icon, loading: loading, enabled: enabled, height: height, expand: expand, gradient: gradient ?? AppColors.actionOutlineGradient, onPressed: onPressed, ); } final decoration = _decoration(baseColor, enabled); final width = expand ? double.infinity : null; return SizedBox( height: height, width: width, child: Material( color: Colors.transparent, child: InkWell( onTap: enabled ? onPressed : null, borderRadius: AppRadius.lgBorder, child: Ink( decoration: decoration, child: Center(child: child), ), ), ), ); } Color _foreground(Color baseColor) { return switch (variant) { AppButtonVariant.primary => Colors.white, AppButtonVariant.secondary => baseColor, AppButtonVariant.outline => baseColor, AppButtonVariant.ghost => baseColor, AppButtonVariant.danger => variant == AppButtonVariant.danger && color == null ? AppColors.error : Colors.white, AppButtonVariant.gradientOutline => AppColors.textPrimary, }; } BoxDecoration _decoration(Color baseColor, bool enabled) { final disabledColor = const Color(0xFFE5E7EB); return switch (variant) { AppButtonVariant.primary => BoxDecoration( color: enabled ? baseColor : disabledColor, borderRadius: AppRadius.lgBorder, boxShadow: enabled ? AppShadows.soft : AppShadows.none, ), AppButtonVariant.secondary => BoxDecoration( color: enabled ? baseColor.withValues(alpha: 0.10) : disabledColor, borderRadius: AppRadius.lgBorder, ), AppButtonVariant.outline => BoxDecoration( color: Colors.white, borderRadius: AppRadius.lgBorder, border: Border.all(color: enabled ? baseColor.withValues(alpha: 0.38) : disabledColor), ), AppButtonVariant.ghost => BoxDecoration( color: enabled ? baseColor.withValues(alpha: 0.08) : disabledColor, borderRadius: AppRadius.lgBorder, ), AppButtonVariant.danger => BoxDecoration( color: enabled ? (color ?? AppColors.error) : disabledColor, borderRadius: AppRadius.lgBorder, ), AppButtonVariant.gradientOutline => const BoxDecoration(), }; } } class _ButtonContent extends StatelessWidget { final String label; final IconData? icon; final bool loading; final Color foreground; const _ButtonContent({ required this.label, required this.icon, required this.loading, required this.foreground, }); @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ if (loading) SizedBox( width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2, color: foreground), ) else if (icon != null) Icon(icon, size: 19, color: foreground), if (loading || icon != null) const SizedBox(width: 8), Flexible( child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: AppTextStyles.button.copyWith(color: foreground), ), ), ], ); } } class _GradientOutlineButton extends StatelessWidget { final String label; final IconData? icon; final bool loading; final bool enabled; final double height; final bool expand; final LinearGradient gradient; final VoidCallback? onPressed; const _GradientOutlineButton({ required this.label, required this.icon, required this.loading, required this.enabled, required this.height, required this.expand, required this.gradient, required this.onPressed, }); @override Widget build(BuildContext context) { return Container( height: height, width: expand ? double.infinity : null, padding: const EdgeInsets.all(1.5), decoration: BoxDecoration( gradient: enabled ? gradient : null, color: enabled ? null : AppColors.borderLight, borderRadius: AppRadius.lgBorder, boxShadow: enabled ? AppShadows.soft : AppShadows.none, ), child: Material( color: Colors.white, borderRadius: BorderRadius.circular(AppRadius.lg - 1.5), child: InkWell( onTap: enabled ? onPressed : null, borderRadius: BorderRadius.circular(AppRadius.lg - 1.5), child: Center( child: _ButtonContent( label: label, icon: icon, loading: loading, foreground: AppColors.textPrimary, ), ), ), ), ); } } class AppIconTile extends StatelessWidget { final IconData icon; final Color color; final Color backgroundColor; final double size; final double iconSize; final BorderRadius? borderRadius; const AppIconTile({ super.key, required this.icon, required this.color, required this.backgroundColor, this.size = 44, this.iconSize = 22, this.borderRadius, }); @override Widget build(BuildContext context) => Container( width: size, height: size, decoration: BoxDecoration( color: backgroundColor, borderRadius: borderRadius ?? AppRadius.mdBorder, border: Border.all(color: color.withValues(alpha: 0.16)), ), child: Icon(icon, size: iconSize, color: color), ); }