146 lines
5.4 KiB
Dart
146 lines
5.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../../../app/i18n/app_localizations.dart';
|
|
import '../../../../app/theme/app_colors.dart';
|
|
import '../../../../app/theme/app_typography.dart';
|
|
import '../../../../app/theme/app_spacing.dart';
|
|
|
|
/// 提现页面
|
|
///
|
|
/// 将平台余额提现到银行账户
|
|
/// 展示可提现余额、手续费、到账时间
|
|
class WithdrawPage extends StatefulWidget {
|
|
const WithdrawPage({super.key});
|
|
|
|
@override
|
|
State<WithdrawPage> createState() => _WithdrawPageState();
|
|
}
|
|
|
|
class _WithdrawPageState extends State<WithdrawPage> {
|
|
final _amountController = TextEditingController();
|
|
double _balance = 128.50;
|
|
|
|
double get _amount => double.tryParse(_amountController.text) ?? 0;
|
|
double get _fee => _amount * 0.005; // 0.5%
|
|
double get _receive => _amount - _fee;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: Text(context.t('withdraw.title'))),
|
|
body: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Balance
|
|
Text(context.t('withdraw.availableBalance'), style: AppTypography.bodySmall),
|
|
const SizedBox(height: 4),
|
|
Text('\$${_balance.toStringAsFixed(2)}', style: AppTypography.displayMedium),
|
|
const SizedBox(height: 24),
|
|
|
|
// Amount Input
|
|
Text(context.t('withdraw.amount'), style: AppTypography.h3),
|
|
const SizedBox(height: 12),
|
|
TextField(
|
|
controller: _amountController,
|
|
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
|
decoration: InputDecoration(
|
|
prefixText: '\$ ',
|
|
suffixIcon: TextButton(
|
|
onPressed: () {
|
|
_amountController.text = _balance.toStringAsFixed(2);
|
|
setState(() {});
|
|
},
|
|
child: Text(context.t('withdraw.all')),
|
|
),
|
|
),
|
|
style: AppTypography.priceLarge,
|
|
onChanged: (_) => setState(() {}),
|
|
),
|
|
const SizedBox(height: 24),
|
|
|
|
// Withdraw To
|
|
Text(context.t('withdraw.to'), style: AppTypography.h3),
|
|
const SizedBox(height: 12),
|
|
Container(
|
|
padding: const EdgeInsets.all(14),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.surface,
|
|
borderRadius: AppSpacing.borderRadiusMd,
|
|
border: Border.all(color: AppColors.primary),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.account_balance_rounded, color: AppColors.primary),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text('Bank of America •••• 6789', style: AppTypography.labelMedium),
|
|
Text(context.t('withdraw.savingsAccount'), style: AppTypography.caption),
|
|
],
|
|
),
|
|
),
|
|
const Icon(Icons.check_circle_rounded, color: AppColors.primary, size: 20),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
|
|
// Fee Details
|
|
if (_amount > 0) ...[
|
|
Container(
|
|
padding: AppSpacing.cardPadding,
|
|
decoration: BoxDecoration(
|
|
color: AppColors.gray50,
|
|
borderRadius: AppSpacing.borderRadiusMd,
|
|
),
|
|
child: Column(
|
|
children: [
|
|
_buildRow(context.t('withdraw.amount'), '\$${_amount.toStringAsFixed(2)}'),
|
|
_buildRow(context.t('withdraw.fee'), '-\$${_fee.toStringAsFixed(2)}'),
|
|
const Divider(height: 16),
|
|
_buildRow(context.t('withdraw.actualReceive'), '\$${_receive.toStringAsFixed(2)}', bold: true),
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
children: [
|
|
const Icon(Icons.schedule_rounded, size: 14, color: AppColors.textTertiary),
|
|
const SizedBox(width: 4),
|
|
Text(context.t('withdraw.estimateTime'), style: AppTypography.caption),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
bottomNavigationBar: Container(
|
|
padding: const EdgeInsets.all(20),
|
|
child: SizedBox(
|
|
height: AppSpacing.buttonHeight,
|
|
child: ElevatedButton(
|
|
onPressed: _amount > 0 && _amount <= _balance ? () {} : null,
|
|
child: Text('${context.t('withdraw.submit')} \$${_amount.toStringAsFixed(2)}'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildRow(String label, String value, {bool bold = false}) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(label, style: AppTypography.bodyMedium.copyWith(color: AppColors.textSecondary)),
|
|
Text(value, style: bold ? AppTypography.priceSmall : AppTypography.labelMedium),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|