import 'package:flutter/material.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; import 'package:provider/provider.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme_extension.dart'; import '../../../core/utils/toast_utils.dart'; import '../../../providers/asset_provider.dart'; import '../../shared/ui_constants.dart'; /// 提現頁面 — 獨立頁面,替代彈窗 class WithdrawPage extends StatefulWidget { final String? balance; const WithdrawPage({super.key, this.balance}); @override State createState() => _WithdrawPageState(); } class _WithdrawPageState extends State { final _amountController = TextEditingController(); final _addressController = TextEditingController(); final _contactController = TextEditingController(); final _formKey = GlobalKey(); bool _isSubmitting = false; final _feeNotifier = ValueNotifier('提現將扣除 10% 手續費'); final _networksNotifier = ValueNotifier>([]); final _selectedNetworkNotifier = ValueNotifier(null); @override void initState() { super.initState(); _amountController.addListener(_onAmountChanged); _loadNetworks(); } @override void dispose() { _amountController.dispose(); _addressController.dispose(); _contactController.dispose(); _feeNotifier.dispose(); _networksNotifier.dispose(); _selectedNetworkNotifier.dispose(); super.dispose(); } void _onAmountChanged() { final amount = double.tryParse(_amountController.text) ?? 0; if (amount > 0) { final fee = amount * 0.1; final receivable = amount - fee; _feeNotifier.value = '手續費(10%): -${fee.toStringAsFixed(2)} USDT\n應收款: ${receivable.toStringAsFixed(2)} USDT'; } else { _feeNotifier.value = '提現將扣除 10% 手續費'; } } void _loadNetworks() { context.read().getWalletNetworks().then((list) { if (mounted) { _networksNotifier.value = list; if (list.isNotEmpty) { _selectedNetworkNotifier.value = list.first; } } }); } Future _submitWithdraw() async { if (!_formKey.currentState!.saveAndValidate()) return; if (_isSubmitting) return; setState(() => _isSubmitting = true); try { final response = await context.read().withdraw( amount: _amountController.text, withdrawAddress: _addressController.text, withdrawContact: _contactController.text.isNotEmpty ? _contactController.text : null, network: _selectedNetworkNotifier.value, ); if (!mounted) return; if (response.success) { ToastUtils.showSuccess('申請成功,請等待管理員審批'); Navigator.of(context).pop(true); } else { ToastUtils.showError(response.message ?? '申請失敗'); } } catch (e) { if (mounted) ToastUtils.showError('申請失敗: $e'); } finally { if (mounted) setState(() => _isSubmitting = false); } } // ============================================ // 構建 UI // ============================================ @override Widget build(BuildContext context) { final colorScheme = context.colors; return Scaffold( backgroundColor: colorScheme.background, appBar: AppBar( leading: IconButton( icon: const Icon(LucideIcons.arrowLeft, size: 20), onPressed: () => Navigator.of(context).pop(), ), title: Text( '提現', style: AppTextStyles.headlineLarge(context).copyWith( color: colorScheme.onSurface, ), ), backgroundColor: colorScheme.background, elevation: 0, scrolledUnderElevation: 0, centerTitle: true, ), body: SingleChildScrollView( padding: const EdgeInsets.all(AppSpacing.lg), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 餘額顯示 if (widget.balance != null) ...[ Container( width: double.infinity, padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: colorScheme.surfaceContainer, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all( color: colorScheme.outlineVariant.withValues(alpha: 0.3), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '可用餘額', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), Text( '${widget.balance} USDT', style: AppTextStyles.headlineMedium(context).copyWith( fontWeight: FontWeight.bold, color: context.appColors.up, ), ), ], ), ), const SizedBox(height: AppSpacing.lg), ], // 表單 ShadForm( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 提現金額 Text( '提現金額', style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppSpacing.sm), ShadInputFormField( id: 'amount', controller: _amountController, placeholder: const Text('請輸入提現金額 (USDT)'), keyboardType: const TextInputType.numberWithOptions(decimal: true), validator: Validators.amount, ), const SizedBox(height: AppSpacing.sm), // 手續費提示 ValueListenableBuilder( valueListenable: _feeNotifier, builder: (_, feeText, __) { return Container( width: double.infinity, padding: const EdgeInsets.symmetric( horizontal: AppSpacing.md, vertical: AppSpacing.sm, ), decoration: BoxDecoration( color: colorScheme.surfaceContainer, borderRadius: BorderRadius.circular(AppRadius.md), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.info_outline, size: 14, color: colorScheme.onSurfaceVariant), const SizedBox(width: AppSpacing.xs), Expanded( child: Text( feeText, style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), ), ], ), ); }, ), const SizedBox(height: AppSpacing.lg), // 提現網絡 ValueListenableBuilder>( valueListenable: _networksNotifier, builder: (_, networks, __) { if (networks.isEmpty) return const SizedBox.shrink(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '提現網絡', style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppSpacing.sm), ValueListenableBuilder( valueListenable: _selectedNetworkNotifier, builder: (_, selected, __) { return SizedBox( width: double.infinity, child: ShadSelect( placeholder: const Text('選擇提現網絡'), initialValue: selected, selectedOptionBuilder: (context, val) => Text(val), onChanged: (value) { if (value != null) { _selectedNetworkNotifier.value = value; } }, options: networks .map((n) => ShadOption(value: n, child: Text(n))) .toList(), ), ); }, ), const SizedBox(height: AppSpacing.lg), ], ); }, ), // 目標地址 Text( '目標地址', style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppSpacing.sm), ShadInputFormField( id: 'address', controller: _addressController, placeholder: const Text('請輸入提現地址'), validator: (v) => Validators.required(v, '提現地址'), ), const SizedBox(height: AppSpacing.lg), // 聯繫方式 Text( '聯繫方式(可選)', style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: AppSpacing.sm), ShadInputFormField( id: 'contact', controller: _contactController, placeholder: const Text('方便客服與您聯繫'), ), ], ), ), const SizedBox(height: AppSpacing.xl), // 安全提示 Container( width: double.infinity, padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: AppColorScheme.warning.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(AppRadius.md), border: Border.all( color: AppColorScheme.warning.withValues(alpha: 0.15), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.shield_outlined, size: 16, color: AppColorScheme.warning), const SizedBox(width: AppSpacing.xs), Text( '安全提示', style: AppTextStyles.labelLarge(context).copyWith( fontWeight: FontWeight.w600, color: AppColorScheme.warning, ), ), ], ), const SizedBox(height: AppSpacing.sm), Text( '• 請仔細核對提現地址,地址錯誤將導致資產無法找回\n' '• 提現申請提交後需等待管理員審批\n' '• 提現將扣除 10% 手續費', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, height: 1.6, ), ), ], ), ), const SizedBox(height: AppSpacing.xl), // 提交按鈕 SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: _isSubmitting ? null : _submitWithdraw, style: ElevatedButton.styleFrom( backgroundColor: colorScheme.primary, foregroundColor: colorScheme.onPrimary, disabledBackgroundColor: colorScheme.primary.withValues(alpha: 0.5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.lg), ), elevation: 0, ), child: _isSubmitting ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : Text( '提交申請', style: AppTextStyles.headlineMedium(context).copyWith( fontWeight: FontWeight.w600, color: colorScheme.onPrimary, ), ), ), ), const SizedBox(height: AppSpacing.lg), // 底部安全保障 Center( child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.verified_user_outlined, size: 14, color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), const SizedBox(width: AppSpacing.xs), Text( '資金安全由平台全程保障', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), ), ], ), ), ], ), ), ); } }