Files
monisuo/flutter_monisuo/lib/ui/pages/asset/transfer_page.dart
2026-04-08 01:09:57 +08:00

989 lines
32 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 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_theme_extension.dart';
import '../../../core/theme/app_spacing.dart';
import '../../../providers/asset_provider.dart';
import '../../../data/models/account_models.dart';
/// 劃轉頁面 - 現代化設計版本
class TransferPage extends StatefulWidget {
const TransferPage({super.key});
@override
State<TransferPage> createState() => _TransferPageState();
}
class _TransferPageState extends State<TransferPage>
with TickerProviderStateMixin {
final _amountController = TextEditingController();
final _focusNode = FocusNode();
int _direction = 1; // 1: 資金→交易, 2: 交易→資金
bool _isLoading = false;
// Animation controllers
late AnimationController _swapAnimationController;
late AnimationController _amountAnimationController;
late AnimationController _balanceAnimationController;
late Animation<double> _swapAnimation;
late Animation<double> _amountScaleAnimation;
// Balance animation values
String _displayedFromBalance = '0.00';
String _displayedToBalance = '0.00';
String _targetFromBalance = '0.00';
String _targetToBalance = '0.00';
@override
void initState() {
super.initState();
// Initialize swap animation
_swapAnimationController = AnimationController(
duration: const Duration(milliseconds: 600),
vsync: this,
);
_swapAnimation = CurvedAnimation(
parent: _swapAnimationController,
curve: Curves.easeInOutCubic,
);
// Initialize amount scale animation
_amountAnimationController = AnimationController(
duration: const Duration(milliseconds: 200),
vsync: this,
);
_amountScaleAnimation = Tween<double>(begin: 1.0, end: 1.05).animate(
CurvedAnimation(
parent: _amountAnimationController,
curve: Curves.easeInOut,
),
);
// Initialize balance animation
_balanceAnimationController = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
)..addListener(_updateBalanceAnimation);
_amountController.addListener(_onAmountChanged);
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<AssetProvider>().refreshAll(force: true);
_updateBalanceTargets();
});
}
@override
void dispose() {
_amountController.removeListener(_onAmountChanged);
_amountController.dispose();
_focusNode.dispose();
_swapAnimationController.dispose();
_amountAnimationController.dispose();
_balanceAnimationController.removeListener(_updateBalanceAnimation);
_balanceAnimationController.dispose();
super.dispose();
}
void _onAmountChanged() {
// Trigger amount input animation
_amountAnimationController.forward().then((_) {
_amountAnimationController.reverse();
});
}
void _updateBalanceTargets() {
setState(() {
_targetFromBalance = _fromBalance;
_targetToBalance = _toBalance;
_displayedFromBalance = _targetFromBalance;
_displayedToBalance = _targetToBalance;
});
}
void _updateBalanceAnimation() {
// This will be used for smooth balance transitions
}
// ============================================
// 數據訪問
// ============================================
String get _fundBalance {
try {
final provider = context.read<AssetProvider>();
final balance = provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00';
return _formatBalance(balance);
} catch (e) {
return '0.00';
}
}
String get _tradeUsdtBalance {
try {
final provider = context.read<AssetProvider>();
if (provider.tradeAccounts.isEmpty) {
return '0.00';
}
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 _formatBalance(usdtHolding.quantity);
} catch (e) {
return '0.00';
}
}
String get _availableBalance => _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;
IconData get _fromIcon => _direction == 1 ? LucideIcons.wallet : LucideIcons.trendingUp;
IconData get _toIcon => _direction == 1 ? LucideIcons.trendingUp : LucideIcons.wallet;
// ============================================
// 業務邏輯
// ============================================
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('劃轉成功');
await Future.delayed(const Duration(milliseconds: 500));
if (mounted) {
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),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
);
}
void _setQuickAmount(double percent) {
final available = double.tryParse(_availableBalance) ?? 0;
final amount = available * percent;
// 向下截斷到2位小數避免四捨五入超出餘額
_amountController.text =
((amount * 100).truncateToDouble() / 100).toStringAsFixed(2);
// Trigger haptic feedback
HapticFeedback.selectionClick();
}
Future<void> _toggleDirection() async {
// Trigger haptic feedback
HapticFeedback.mediumImpact();
await _swapAnimationController.forward();
setState(() {
_direction = _direction == 1 ? 2 : 1;
_updateBalanceTargets();
});
_swapAnimationController.reset();
}
// ============================================
// 構建 UI
// ============================================
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: colorScheme.surface,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
leading: IconButton(
icon: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(12),
),
child: Icon(LucideIcons.arrowLeft, color: colorScheme.onSurface, size: 20),
),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
'賬戶劃轉',
style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.w700,
),
),
centerTitle: true,
),
body: Consumer<AssetProvider>(
builder: (context, provider, _) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
colorScheme.surface,
colorScheme.surfaceContainerLowest.withValues(alpha: 0.3),
],
),
),
child: SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(AppSpacing.lg, AppSpacing.sm, AppSpacing.lg, AppSpacing.xl),
child: Column(
children: [
_buildTransferDirectionCard(),
const SizedBox(height: AppSpacing.xl),
_buildAmountSection(),
const SizedBox(height: AppSpacing.xl),
_buildTipsCard(),
const SizedBox(height: AppSpacing.xl + AppSpacing.sm),
_buildConfirmButton(),
const SizedBox(height: AppSpacing.lg),
],
),
),
);
},
),
);
}
// ============================================
// Transfer direction card - Modern Design
// ============================================
Widget _buildTransferDirectionCard() {
final colorScheme = Theme.of(context).colorScheme;
final isDark = colorScheme.brightness == Brightness.dark;
// Gold gradient colors
final goldStart = isDark ? const Color(0xFFD4AF37) : const Color(0xFFF59E0B);
final goldEnd = isDark ? const Color(0xFFFFD700) : const Color(0xFFFFA500);
return Container(
width: double.infinity,
padding: const EdgeInsets.all(AppSpacing.lg),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: isDark
? [
colorScheme.surfaceContainerHigh,
colorScheme.surfaceContainer,
]
: [
Colors.white,
colorScheme.surfaceContainerLow,
],
),
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(
color: colorScheme.shadow.withValues(alpha: isDark ? 0.3 : 0.08),
blurRadius: 24,
offset: const Offset(0, 8),
),
BoxShadow(
color: goldStart.withValues(alpha: 0.1),
blurRadius: 16,
offset: const Offset(0, 4),
spreadRadius: 2,
),
],
border: Border.all(
color: colorScheme.outlineVariant.withValues(alpha: 0.3),
width: 1,
),
),
child: Column(
children: [
// From Account Card
_AnimatedAccountCard(
key: ValueKey('from-$_direction'),
label: '',
accountName: _fromLabel,
balance: _displayedFromBalance,
icon: _fromIcon,
isSource: true,
animation: _swapAnimation,
),
// Swap Button - Enhanced Design
Padding(
padding: const EdgeInsets.symmetric(vertical: AppSpacing.md),
child: GestureDetector(
onTap: _toggleDirection,
child: Container(
width: 56,
height: 56,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [goldStart, goldEnd],
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: goldStart.withValues(alpha: 0.4),
blurRadius: 16,
offset: const Offset(0, 4),
),
BoxShadow(
color: goldStart.withValues(alpha: 0.2),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Container(
margin: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: colorScheme.surface,
shape: BoxShape.circle,
),
child: Container(
margin: const EdgeInsets.all(2),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [goldStart, goldEnd],
),
shape: BoxShape.circle,
),
child: Icon(
LucideIcons.arrowUpDown,
size: 24,
color: colorScheme.surface,
),
),
),
),
),
),
// To Account Card
_AnimatedAccountCard(
key: ValueKey('to-$_direction'),
label: '',
accountName: _toLabel,
balance: _displayedToBalance,
icon: _toIcon,
isSource: false,
animation: _swapAnimation,
),
],
),
);
}
// ============================================
// Amount input section - Enhanced Design
// ============================================
Widget _buildAmountSection() {
final colorScheme = Theme.of(context).colorScheme;
final isDark = colorScheme.brightness == Brightness.dark;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header with label and max button
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
LucideIcons.coins,
size: 20,
color: colorScheme.onSurfaceVariant,
),
const SizedBox(width: 8),
Text(
'劃轉金額',
style: AppTextStyles.headlineSmall(context).copyWith(
color: colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
],
),
Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _setQuickAmount(1.0),
borderRadius: BorderRadius.circular(16),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
colorScheme.secondary.withValues(alpha: 0.15),
colorScheme.secondary.withValues(alpha: 0.05),
],
),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: colorScheme.secondary.withValues(alpha: 0.3),
width: 1,
),
),
child: Text(
'全部',
style: AppTextStyles.labelLarge(context).copyWith(
color: colorScheme.secondary,
fontWeight: FontWeight.w600,
),
),
),
),
),
],
),
const SizedBox(height: 16),
// Amount input card with glow effect
AnimatedBuilder(
animation: _amountScaleAnimation,
builder: (context, child) {
return Transform.scale(
scale: _amountScaleAnimation.value,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
boxShadow: _focusNode.hasFocus
? [
BoxShadow(
color: colorScheme.secondary.withValues(alpha: 0.2),
blurRadius: 16,
spreadRadius: 2,
),
]
: [],
),
child: Container(
width: double.infinity,
height: 80,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.lg, vertical: AppSpacing.md),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: isDark
? [
colorScheme.surfaceContainerHighest,
colorScheme.surfaceContainerHigh,
]
: [
Colors.white,
colorScheme.surfaceContainerLow,
],
),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: _focusNode.hasFocus
? colorScheme.secondary
: colorScheme.outlineVariant.withValues(alpha: 0.5),
width: _focusNode.hasFocus ? 2 : 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.shadow.withValues(alpha: isDark ? 0.2 : 0.05),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: Row(
children: [
Expanded(
child: TextField(
controller: _amountController,
focusNode: _focusNode,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,8}')),
],
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w700,
color: colorScheme.onSurface,
letterSpacing: -0.5,
),
decoration: InputDecoration(
hintText: '0.00',
hintStyle: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w700,
color: colorScheme.onSurfaceVariant.withValues(alpha: 0.3),
letterSpacing: -0.5,
),
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
isDense: true,
),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(12),
),
child: Text(
'USDT',
style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.onSurfaceVariant,
),
),
),
],
),
),
),
);
},
),
const SizedBox(height: 16),
// Available balance display
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHighest.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'可用餘額',
style: AppTextStyles.bodyMedium(context).copyWith(
color: colorScheme.onSurfaceVariant,
),
),
Text(
'${_formatBalance(_availableBalance)} USDT',
style: AppTextStyles.bodyLarge(context).copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
),
),
],
),
),
const SizedBox(height: 20),
// Percent buttons - Capsule design with gradient
Row(
children: [
_buildPercentButton('25%', 0.25, 0),
const SizedBox(width: 8),
_buildPercentButton('50%', 0.50, 1),
const SizedBox(width: 8),
_buildPercentButton('75%', 0.75, 2),
const SizedBox(width: 8),
_buildPercentButton('100%', 1.0, 3),
],
),
],
);
}
Widget _buildPercentButton(String label, double percent, int index) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = colorScheme.brightness == Brightness.dark;
final goldStart = isDark ? const Color(0xFFD4AF37) : const Color(0xFFF59E0B);
final goldEnd = isDark ? const Color(0xFFFFD700) : const Color(0xFFFFA500);
return Expanded(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _setQuickAmount(percent),
borderRadius: BorderRadius.circular(20),
child: Container(
height: 44,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
goldStart.withValues(alpha: 0.12),
goldEnd.withValues(alpha: 0.08),
],
),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: goldStart.withValues(alpha: 0.25),
width: 1.5,
),
),
child: Center(
child: Text(
label,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: goldStart,
),
),
),
),
),
),
);
}
// ============================================
// Tips card - Refined Design
// ============================================
Widget _buildTipsCard() {
final colorScheme = Theme.of(context).colorScheme;
final isDark = colorScheme.brightness == Brightness.dark;
final successColor = isDark ? const Color(0xFF4ADE80) : const Color(0xFF10B981);
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
successColor.withValues(alpha: 0.08),
successColor.withValues(alpha: 0.03),
],
),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: successColor.withValues(alpha: 0.2),
width: 1,
),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: successColor.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(8),
),
child: Icon(
LucideIcons.sparkles,
size: 18,
color: successColor,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'即時到賬',
style: AppTextStyles.bodyMedium(context).copyWith(
color: successColor,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 2),
Text(
'劃轉即時到賬,無需手續費',
style: AppTextStyles.bodySmall(context).copyWith(
color: successColor.withValues(alpha: 0.8),
),
),
],
),
),
],
),
);
}
// ============================================
// Confirm button - Premium Design
// ============================================
Widget _buildConfirmButton() {
final colorScheme = Theme.of(context).colorScheme;
final isDark = colorScheme.brightness == Brightness.dark;
final goldStart = isDark ? const Color(0xFFD4AF37) : const Color(0xFFF59E0B);
final goldEnd = isDark ? const Color(0xFFFFD700) : const Color(0xFFFFA500);
final hasAmount = _amountController.text.isNotEmpty && double.tryParse(_amountController.text) != null && double.parse(_amountController.text) > 0;
return Container(
height: 60,
decoration: BoxDecoration(
gradient: hasAmount && !_isLoading
? LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [goldStart, goldEnd],
)
: null,
color: hasAmount && !_isLoading ? null : colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(20),
boxShadow: hasAmount && !_isLoading
? [
BoxShadow(
color: goldStart.withValues(alpha: 0.4),
blurRadius: 20,
offset: const Offset(0, 8),
),
BoxShadow(
color: goldStart.withValues(alpha: 0.2),
blurRadius: 8,
offset: const Offset(0, 4),
),
]
: [
BoxShadow(
color: colorScheme.shadow.withValues(alpha: 0.08),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: _isLoading ? null : _doTransfer,
borderRadius: BorderRadius.circular(20),
child: Center(
child: _isLoading
? SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2.5,
valueColor: AlwaysStoppedAnimation<Color>(
isDark ? Colors.white : colorScheme.onSurface,
),
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
LucideIcons.arrowRight,
size: 22,
color: hasAmount ? Colors.white : colorScheme.onSurfaceVariant,
),
const SizedBox(width: 8),
Text(
'確認劃轉',
style: TextStyle(
color: hasAmount ? Colors.white : colorScheme.onSurfaceVariant,
fontSize: 18,
fontWeight: FontWeight.w700,
letterSpacing: 0.5,
),
),
],
),
),
),
),
);
}
// ============================================
// Helpers
// ============================================
String _formatBalance(String balance) {
final val = double.tryParse(balance);
if (val == null) return '0.00';
return val.toStringAsFixed(2);
}
}
// ============================================
// Animated Account Card Widget
// ============================================
class _AnimatedAccountCard extends StatelessWidget {
final String label;
final String accountName;
final String balance;
final IconData icon;
final bool isSource;
final Animation<double> animation;
const _AnimatedAccountCard({
super.key,
required this.label,
required this.accountName,
required this.balance,
required this.icon,
required this.isSource,
required this.animation,
});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = colorScheme.brightness == Brightness.dark;
final goldColor = isDark ? const Color(0xFFD4AF37) : const Color(0xFFF59E0B);
return AnimatedBuilder(
animation: animation,
builder: (context, child) {
return Transform.translate(
offset: Offset(0, animation.value * (isSource ? -10 : 10)),
child: Opacity(
opacity: 1.0 - (animation.value * 0.3),
child: child,
),
);
},
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: isDark
? colorScheme.surfaceContainer.withValues(alpha: 0.5)
: colorScheme.surface.withValues(alpha: 0.8),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: colorScheme.outlineVariant.withValues(alpha: 0.2),
width: 1,
),
),
child: Row(
children: [
// Icon container with gradient
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
goldColor.withValues(alpha: 0.15),
goldColor.withValues(alpha: 0.05),
],
),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: goldColor.withValues(alpha: 0.2),
width: 1,
),
),
child: Icon(
icon,
size: 22,
color: goldColor,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: AppTextStyles.bodySmall(context).copyWith(
color: colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
Text(
accountName,
style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w600,
),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'¥ $balance',
style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w700,
color: colorScheme.onSurface,
),
),
const SizedBox(height: 4),
Text(
'USDT',
style: AppTextStyles.bodySmall(context).copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
),
],
),
),
);
}
}