import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; import 'package:provider/provider.dart'; import '../../../../core/theme/app_theme.dart'; import '../../../../core/theme/app_color_scheme.dart'; import '../../../../core/theme/app_spacing.dart'; import '../../../../core/utils/toast_utils.dart'; import '../../../../providers/asset_provider.dart'; import '../../../components/glass_panel.dart'; import '../../../components/neon_glow.dart'; import '../../../shared/ui_constants.dart'; // ============================================ // Dialog helpers — shared sub-widgets // ============================================ /// 信息行 — 用于对话框中显示 label/value 键值对 class InfoRow extends StatelessWidget { final String label; final String value; final bool isBold; const InfoRow({ super.key, required this.label, required this.value, this.isBold = false, }); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), Text( value, style: AppTextStyles.bodyMedium(context).copyWith( fontWeight: isBold ? FontWeight.bold : FontWeight.w400, ), ), ], ); } } /// 钱包地址卡片 — 用于充值结果对话框中展示钱包地址 class WalletAddressCard extends StatelessWidget { final String address; final String network; const WalletAddressCard({ super.key, required this.address, required this.network, }); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Container( padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: colorScheme.surfaceContainerHigh, borderRadius: BorderRadius.circular(AppRadius.md), border: Border.all( color: colorScheme.outlineVariant.withValues(alpha: 0.3), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( address, style: AppTextStyles.bodyMedium(context).copyWith( fontFamily: 'monospace', ), ), ), GestureDetector( onTap: () { Clipboard.setData(ClipboardData(text: address)); ToastUtils.show('地址已复制到剪贴板'); }, child: Container( padding: const EdgeInsets.all(AppSpacing.xs), decoration: BoxDecoration( color: colorScheme.primary.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Icon( LucideIcons.copy, size: 16, color: colorScheme.primary, ), ), ), ], ), const SizedBox(height: AppSpacing.sm), Text( '网络: $network', style: AppTextStyles.bodySmall(context), ), ], ), ); } } // ============================================ // Dialog functions — kept from original with style updates // ============================================ /// 充值对话框 void showDepositDialog(BuildContext context) { final amountController = TextEditingController(); final formKey = GlobalKey(); final colorScheme = Theme.of(context).colorScheme; showShadDialog( context: context, builder: (ctx) => Dialog( backgroundColor: const Color(0x00000000), child: GlassPanel( borderRadius: BorderRadius.circular(AppRadius.lg), padding: const EdgeInsets.all(AppSpacing.lg), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '充值', style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w700, ), ), const SizedBox(height: AppSpacing.xs), Text( 'Asset: USDT', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), ], ), Container( padding: const EdgeInsets.all(AppSpacing.sm), decoration: BoxDecoration( color: colorScheme.surfaceContainerHigh, borderRadius: BorderRadius.circular(AppRadius.md), ), child: Icon( LucideIcons.wallet, color: colorScheme.secondary, ), ), ], ), const SizedBox(height: AppSpacing.lg), ShadForm( key: formKey, child: ShadInputFormField( id: 'amount', controller: amountController, label: const Text('充值金额'), placeholder: const Text('最低 1000 USDT'), keyboardType: const TextInputType.numberWithOptions(decimal: true), validator: (v) { if (v == null || v.isEmpty) return '请输入金额'; final n = double.tryParse(v); if (n == null || n <= 0) return '请输入有效金额'; if (n < 1000) return '单笔最低充值1000 USDT'; return null; }, ), ), const SizedBox(height: AppSpacing.lg), Row( children: [ Expanded( child: NeonButton( text: '取消', type: NeonButtonType.outline, onPressed: () => Navigator.of(ctx).pop(), height: 48, showGlow: false, ), ), const SizedBox(width: AppSpacing.sm), Expanded( child: NeonButton( text: '下一步', type: NeonButtonType.primary, onPressed: () async { if (formKey.currentState!.saveAndValidate()) { Navigator.of(ctx).pop(); final response = await context.read().deposit( amount: amountController.text, ); if (context.mounted) { if (response.success && response.data != null) { showDepositResultDialog(context, response.data!); } else { showResultDialog(context, '申请失败', response.message); } } } }, height: 48, showGlow: true, ), ), ], ), ], ), ), ), ); } /// 充值结果对话框 — 展示钱包地址和确认打款 void showDepositResultDialog(BuildContext context, Map data) { final orderNo = data['orderNo'] as String? ?? ''; final amount = data['amount']?.toString() ?? '0.00'; final walletAddress = data['walletAddress'] as String? ?? ''; final walletNetwork = data['walletNetwork'] as String? ?? 'TRC20'; final colorScheme = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; showShadDialog( context: context, builder: (ctx) => Dialog( backgroundColor: const Color(0x00000000), child: GlassPanel( borderRadius: BorderRadius.circular(AppRadius.lg), padding: const EdgeInsets.all(AppSpacing.lg), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ NeonIcon( icon: Icons.check_circle, color: AppColorScheme.getUpColor(isDark), size: 24, ), const SizedBox(width: AppSpacing.sm), Text( '充值申请成功', style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w700, ), ), ], ), const SizedBox(height: AppSpacing.lg), InfoRow(label: '订单号', value: orderNo), const SizedBox(height: AppSpacing.sm), InfoRow(label: '充值金额', value: '$amount USDT', isBold: true), const SizedBox(height: AppSpacing.lg), Text( '请向以下地址转账:', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), const SizedBox(height: AppSpacing.sm), WalletAddressCard(address: walletAddress, network: walletNetwork), const SizedBox(height: AppSpacing.md), Container( padding: const EdgeInsets.all(AppSpacing.sm), decoration: BoxDecoration( color: AppColorScheme.warning.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(AppRadius.md), border: Border.all( color: AppColorScheme.warning.withValues(alpha: 0.2), ), ), child: Row( children: [ Icon(Icons.info_outline, size: 16, color: AppColorScheme.warning), const SizedBox(width: AppSpacing.sm), Expanded( child: Text( '转账完成后请点击"已打款"按钮确认', style: AppTextStyles.bodyMedium(context).copyWith( color: AppColorScheme.warning, ), ), ), ], ), ), const SizedBox(height: AppSpacing.lg), Row( children: [ Expanded( child: NeonButton( text: '稍后确认', type: NeonButtonType.outline, onPressed: () => Navigator.of(ctx).pop(), height: 44, showGlow: false, ), ), const SizedBox(width: AppSpacing.sm), Expanded( child: NeonButton( text: '已打款', type: NeonButtonType.primary, onPressed: () async { Navigator.of(ctx).pop(); final response = await context.read().confirmPay(orderNo); if (context.mounted) { showResultDialog( context, response.success ? '确认成功' : '确认失败', response.success ? '请等待管理员审核' : response.message, ); } }, height: 44, showGlow: true, ), ), ], ), ], ), ), ), ); } /// 提现对话框 void showWithdrawDialog(BuildContext context, String? balance) { final amountController = TextEditingController(); final addressController = TextEditingController(); final contactController = TextEditingController(); final formKey = GlobalKey(); final colorScheme = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; showShadDialog( context: context, builder: (ctx) => Dialog( backgroundColor: const Color(0x00000000), child: GlassPanel( borderRadius: BorderRadius.circular(AppRadius.lg), padding: const EdgeInsets.all(AppSpacing.lg), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(AppSpacing.sm), decoration: BoxDecoration( color: colorScheme.primary.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(AppRadius.md), ), child: Icon( LucideIcons.wallet, color: colorScheme.primary, ), ), const SizedBox(width: AppSpacing.sm), Text( '提现', style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w700, ), ), ], ), const SizedBox(height: AppSpacing.xs), Text( '安全地将您的资产转移到外部钱包地址', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), if (balance != null) ...[ const SizedBox(height: AppSpacing.md), Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.md, vertical: AppSpacing.sm, ), decoration: BoxDecoration( color: AppColorScheme.getUpBackgroundColor(isDark), borderRadius: BorderRadius.circular(AppRadius.full), border: Border.all( color: AppColorScheme.getUpColor(isDark).withValues(alpha: 0.2), ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text( '可用余额: ', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), Text( '$balance USDT', style: AppTextStyles.labelLarge(context).copyWith( fontWeight: FontWeight.bold, color: AppColorScheme.getUpColor(isDark), ), ), ], ), ), ], const SizedBox(height: AppSpacing.lg), ShadForm( key: formKey, child: Column( children: [ ShadInputFormField( id: 'amount', controller: amountController, label: const Text('提现金额'), placeholder: const Text('请输入提现金额(USDT)'), keyboardType: const TextInputType.numberWithOptions(decimal: true), validator: Validators.amount, ), const SizedBox(height: AppSpacing.md), ShadInputFormField( id: 'address', controller: addressController, label: const Text('目标地址'), placeholder: const Text('请输入提现地址'), validator: (v) => Validators.required(v, '提现地址'), ), const SizedBox(height: AppSpacing.md), ShadInputFormField( id: 'contact', controller: contactController, label: const Text('联系方式(可选)'), placeholder: const Text('联系方式'), ), ], ), ), const SizedBox(height: AppSpacing.lg), Row( children: [ Expanded( child: NeonButton( text: '取消', type: NeonButtonType.outline, onPressed: () => Navigator.of(ctx).pop(), height: 44, showGlow: false, ), ), const SizedBox(width: AppSpacing.sm), Expanded( child: NeonButton( text: '提交', type: NeonButtonType.primary, onPressed: () async { if (formKey.currentState!.saveAndValidate()) { Navigator.of(ctx).pop(); final response = await context.read().withdraw( amount: amountController.text, withdrawAddress: addressController.text, withdrawContact: contactController.text.isNotEmpty ? contactController.text : null, ); if (context.mounted) { showResultDialog( context, response.success ? '申请成功' : '申请失败', response.success ? '请等待管理员审批' : response.message, ); } } }, height: 44, showGlow: true, ), ), ], ), const SizedBox(height: AppSpacing.md), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.verified_user, size: 12, color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), const SizedBox(width: AppSpacing.xs), Text( 'End-to-End Encrypted Transaction', style: AppTextStyles.bodySmall(context).copyWith( fontSize: 10, color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), ), ], ), ], ), ), ), ), ); } /// 通用结果对话框 — 展示操作成功/失败信息 void showResultDialog(BuildContext context, String title, String? message) { final colorScheme = Theme.of(context).colorScheme; showShadDialog( context: context, builder: (ctx) => Dialog( backgroundColor: const Color(0x00000000), child: GlassPanel( borderRadius: BorderRadius.circular(AppRadius.lg), padding: const EdgeInsets.all(AppSpacing.lg), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( title, style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w700, ), ), if (message != null) ...[ const SizedBox(height: AppSpacing.sm), Text( message, style: AppTextStyles.bodyLarge(context).copyWith( color: colorScheme.onSurfaceVariant, ), textAlign: TextAlign.center, ), ], const SizedBox(height: AppSpacing.lg), SizedBox( width: double.infinity, child: NeonButton( text: '确定', type: NeonButtonType.primary, onPressed: () => Navigator.of(ctx).pop(), height: 44, showGlow: false, ), ), ], ), ), ), ); }