Files
monisuo/flutter_monisuo/lib/ui/pages/asset/transfer_page.dart
sion a3a2ae76fc feat: 为划转页面确认按钮添加图标
- 添加 LucideIcons.arrowRightLeft 图标到确认按钮
- 加载状态时自动隐藏图标
- 提升用户体验和视觉识别度
2026-03-30 11:38:04 +08:00

510 lines
16 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:provider/provider.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart';
import '../../../providers/asset_provider.dart';
import '../../../data/models/account_models.dart';
import '../../shared/ui_constants.dart';
import '../../components/neon_glow.dart';
/// 划转页面 - 币安风格
class TransferPage extends StatefulWidget {
const TransferPage({super.key});
@override
State<TransferPage> createState() => _TransferPageState();
}
class _TransferPageState extends State<TransferPage> {
final _amountController = TextEditingController();
int _direction = 1; // 1: 资金→交易, 2: 交易→资金
bool _isLoading = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<AssetProvider>().refreshAll(force: true);
});
}
@override
void dispose() {
_amountController.dispose();
super.dispose();
}
/// 获取资金账户余额
String get _fundBalance {
final provider = context.read<AssetProvider>();
return provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00';
}
/// 获取交易账户 USDT 余额
String get _tradeUsdtBalance {
final provider = context.read<AssetProvider>();
final usdtHolding = provider.tradeAccounts.firstWhere(
(t) => t.coinCode.toUpperCase() == 'USDT',
orElse: () => AccountTrade(
id: 0,
userId: 0,
coinCode: 'USDT',
quantity: '0',
avgPrice: '1',
totalCost: '0',
currentValue: '0',
profit: '0',
profitRate: 0,
),
);
return usdtHolding.quantity;
}
/// 获取当前可用余额(根据方向)
String get _availableBalance {
return _direction == 1 ? _fundBalance : _tradeUsdtBalance;
}
/// 从账户名
String get _fromLabel => _direction == 1 ? '资金账户' : '交易账户';
String get _toLabel => _direction == 1 ? '交易账户' : '资金账户';
String get _fromBalance => _direction == 1 ? _fundBalance : _tradeUsdtBalance;
String get _toBalance => _direction == 1 ? _tradeUsdtBalance : _fundBalance;
/// 执行划转
Future<void> _doTransfer() async {
final amount = _amountController.text;
final available = double.tryParse(_availableBalance) ?? 0;
final transferAmount = double.tryParse(amount) ?? 0;
if (transferAmount <= 0) {
_showSnackBar('请输入有效的划转金额');
return;
}
if (transferAmount > available) {
_showSnackBar('余额不足');
return;
}
setState(() => _isLoading = true);
try {
final response = await context.read<AssetProvider>().transfer(
direction: _direction,
amount: amount,
);
if (mounted) {
if (response.success) {
_amountController.clear();
_showSnackBar('划转成功');
Navigator.of(context).pop(true);
} else {
_showSnackBar(response.message ?? '划转失败');
}
}
} finally {
if (mounted) {
setState(() => _isLoading = false);
}
}
}
void _showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
/// 设置快捷百分比金额
void _setQuickAmount(double percent) {
final available = double.tryParse(_availableBalance) ?? 0;
final amount = available * percent;
// 保留8位小数去除末尾0
_amountController.text = amount.toStringAsFixed(8).replaceAll(RegExp(r'\.?0+$'), '');
}
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor: colorScheme.background,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: colorScheme.onSurface),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
'资金划转',
style: GoogleFonts.spaceGrotesk(
fontSize: 18,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
),
),
centerTitle: true,
),
body: Consumer<AssetProvider>(
builder: (context, provider, _) {
return SingleChildScrollView(
padding: AppSpacing.pagePadding,
child: Column(
children: [
// 从账户卡片
_buildAccountCard(
label: '',
accountName: _fromLabel,
balance: _fromBalance,
isDark: isDark,
colorScheme: colorScheme,
),
// 方向切换按钮
GestureDetector(
onTap: () => setState(() => _direction = _direction == 1 ? 2 : 1),
child: Container(
margin: EdgeInsets.symmetric(vertical: AppSpacing.sm),
padding: EdgeInsets.all(AppSpacing.sm + AppSpacing.xs),
decoration: BoxDecoration(
color: colorScheme.primary,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.3),
blurRadius: 8,
),
],
),
child: Icon(
Icons.swap_vert,
color: colorScheme.onPrimary,
size: 22,
),
),
),
// 到账户卡片
_buildAccountCard(
label: '',
accountName: _toLabel,
balance: _toBalance,
isDark: isDark,
colorScheme: colorScheme,
),
SizedBox(height: AppSpacing.lg),
// 金额输入卡片
_buildAmountSection(colorScheme, isDark),
SizedBox(height: AppSpacing.lg),
// 确认按钮
SizedBox(
width: double.infinity,
child: NeonButton(
text: _isLoading ? '处理中...' : '确认划转',
icon: _isLoading ? null : LucideIcons.arrowRightLeft,
type: NeonButtonType.primary,
onPressed: _isLoading ? null : _doTransfer,
height: 52,
showGlow: true,
),
),
SizedBox(height: AppSpacing.md),
// 划转说明
_buildTips(colorScheme),
],
),
);
},
),
);
}
/// 账户卡片
Widget _buildAccountCard({
required String label,
required String accountName,
required String balance,
required bool isDark,
required ColorScheme colorScheme,
}) {
return Container(
width: double.infinity,
padding: EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: isDark ? colorScheme.surfaceContainer : colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(
color: colorScheme.outlineVariant.withOpacity(0.15),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: AppSpacing.sm, vertical: AppSpacing.xs),
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Text(
label,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: colorScheme.primary,
),
),
),
SizedBox(width: AppSpacing.sm),
Text(
accountName,
style: GoogleFonts.spaceGrotesk(
fontSize: 16,
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
),
),
],
),
SizedBox(height: AppSpacing.sm),
Row(
children: [
Text(
'可用余额',
style: TextStyle(
fontSize: 12,
color: colorScheme.onSurfaceVariant,
),
),
SizedBox(width: AppSpacing.xs),
Text(
'$balance USDT',
style: GoogleFonts.spaceGrotesk(
fontSize: 14,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
),
),
],
),
],
),
);
}
/// 金额输入区域
Widget _buildAmountSection(ColorScheme colorScheme, bool isDark) {
return Container(
width: double.infinity,
padding: EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: isDark ? colorScheme.surfaceContainer : colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(
color: colorScheme.outlineVariant.withOpacity(0.15),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'划转金额',
style: TextStyle(
fontSize: 13,
color: colorScheme.onSurfaceVariant,
),
),
SizedBox(height: AppSpacing.sm),
// 金额输入行
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: TextField(
controller: _amountController,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,8}')),
],
style: GoogleFonts.spaceGrotesk(
fontSize: 32,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
),
decoration: InputDecoration(
hintText: '0.00',
hintStyle: GoogleFonts.spaceGrotesk(
fontSize: 32,
fontWeight: FontWeight.bold,
color: colorScheme.onSurfaceVariant.withOpacity(0.3),
),
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
isDense: true,
),
),
),
Padding(
padding: EdgeInsets.only(bottom: 4),
child: Text(
'USDT',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: colorScheme.onSurfaceVariant,
),
),
),
],
),
SizedBox(height: AppSpacing.sm),
// 快捷按钮行
Row(
children: [
Text(
'可用: ${_availableBalance}',
style: TextStyle(
fontSize: 12,
color: colorScheme.onSurfaceVariant,
),
),
Spacer(),
_buildQuickButton('25%', 0.25, colorScheme),
SizedBox(width: AppSpacing.xs),
_buildQuickButton('50%', 0.50, colorScheme),
SizedBox(width: AppSpacing.xs),
_buildQuickButton('75%', 0.75, colorScheme),
SizedBox(width: AppSpacing.xs),
_buildQuickButton('全部', 1.0, colorScheme),
],
),
if (_direction == 2) ...[
SizedBox(height: AppSpacing.sm),
Container(
padding: EdgeInsets.all(AppSpacing.sm),
decoration: BoxDecoration(
color: AppColorScheme.warning.withOpacity(0.1),
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Row(
children: [
Icon(
LucideIcons.triangleAlert,
size: 14,
color: AppColorScheme.warning,
),
SizedBox(width: AppSpacing.xs),
Expanded(
child: Text(
'仅支持 USDT 资产划转到资金账户',
style: TextStyle(
fontSize: 11,
color: AppColorScheme.warning,
),
),
),
],
),
),
],
],
),
);
}
/// 快捷百分比按钮
Widget _buildQuickButton(String label, double percent, ColorScheme colorScheme) {
return GestureDetector(
onTap: () => _setQuickAmount(percent),
child: Container(
padding: EdgeInsets.symmetric(horizontal: AppSpacing.sm, vertical: AppSpacing.xs),
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Text(
label,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: colorScheme.primary,
),
),
),
);
}
/// 划转说明
Widget _buildTips(ColorScheme colorScheme) {
return Container(
padding: EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(AppRadius.md),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'划转说明',
style: GoogleFonts.spaceGrotesk(
fontSize: 12,
fontWeight: FontWeight.w600,
color: colorScheme.onSurfaceVariant,
),
),
SizedBox(height: AppSpacing.sm),
_buildTipItem('资金账户用于充提,交易账户用于买卖币种', colorScheme),
_buildTipItem('划转操作即时到账,不可撤销', colorScheme),
_buildTipItem('交易账户只有 USDT 可直接划转到资金账户', colorScheme),
_buildTipItem('其他币种需先卖出换成 USDT 后才能划转', colorScheme),
],
),
);
}
Widget _buildTipItem(String text, ColorScheme colorScheme) {
return Padding(
padding: EdgeInsets.only(bottom: AppSpacing.xs),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 4,
height: 4,
margin: EdgeInsets.only(top: 6, right: AppSpacing.sm),
decoration: BoxDecoration(
color: colorScheme.onSurfaceVariant,
shape: BoxShape.circle,
),
),
Expanded(
child: Text(
text,
style: TextStyle(
fontSize: 11,
color: colorScheme.onSurfaceVariant,
),
),
),
],
),
);
}
}