refactor: 批量替换 shadcn_ui 为 Material Design 组件
## 样式主题重点优化 ### 颜色映射(注重主题一致性) - mutedForeground → onSurfaceVariant - border → outline - card → surfaceContainer - destructive → error - 保留所有 AppColorScheme 自定义颜色 ### 文本样式映射 - theme.textTheme.h1/muted/large → AppTextStyles.xxx(context) - 统一使用项目定义的文本样式系统 ### 组件替换(20个文件) - ShadApp → MaterialApp(移除 ShadThemeData) - ShadButton → ElevatedButton/OutlinedButton - ShadDialog → AlertDialog - ShadInputFormField → MaterialInput - ShadSelect → DropdownButtonFormField - ShadCard → Card - showShadDialog → showDialog ### 依赖变更 - 移除:shadcn_ui: ^0.52.1 - 添加:lucide_icons_flutter: ^2.0.0 ### 业务逻辑保护 ✅ 所有 onPressed/onChanged/validator 回调保持不变 ✅ 所有 controller/focusNode 数据绑定保持不变 ✅ 所有布局结构(Column/Row/Padding)保持不变 ✅ 仅替换 UI 组件层,业务逻辑完全保留
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
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 '../../../components/material_input.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
import '../../../../core/theme/app_theme_extension.dart';
|
||||
@@ -129,10 +129,10 @@ class WalletAddressCard extends StatelessWidget {
|
||||
/// 充值對話框
|
||||
void showDepositDialog(BuildContext context) {
|
||||
final amountController = TextEditingController();
|
||||
final formKey = GlobalKey<ShadFormState>();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
showShadDialog(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
@@ -178,22 +178,21 @@ void showDepositDialog(BuildContext context) {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: AppSpacing.lg),
|
||||
ShadForm(
|
||||
Form(
|
||||
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;
|
||||
},
|
||||
),
|
||||
child: MaterialInput(
|
||||
controller: amountController,
|
||||
labelText: '充值金額',
|
||||
hintText: '最低 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(
|
||||
@@ -213,7 +212,7 @@ void showDepositDialog(BuildContext context) {
|
||||
text: '下一步',
|
||||
type: NeonButtonType.primary,
|
||||
onPressed: () async {
|
||||
if (formKey.currentState!.saveAndValidate()) {
|
||||
if (formKey.currentState!.validate()) {
|
||||
Navigator.of(ctx).pop();
|
||||
final response = await context.read<AssetProvider>().deposit(
|
||||
amount: amountController.text,
|
||||
@@ -248,7 +247,7 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
|
||||
final walletNetwork = data['walletNetwork'] as String? ?? 'TRC20';
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
showShadDialog(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
@@ -359,7 +358,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
|
||||
final amountController = TextEditingController();
|
||||
final addressController = TextEditingController();
|
||||
final contactController = TextEditingController();
|
||||
final formKey = GlobalKey<ShadFormState>();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final feeNotifier = ValueNotifier<String>('提現將扣除10%手續費');
|
||||
final networksNotifier = ValueNotifier<List<String>>([]);
|
||||
final selectedNetworkNotifier = ValueNotifier<String?>(null);
|
||||
@@ -384,7 +383,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
|
||||
}
|
||||
});
|
||||
|
||||
showShadDialog(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
@@ -460,17 +459,21 @@ void showWithdrawDialog(BuildContext context, String? balance) {
|
||||
),
|
||||
],
|
||||
const SizedBox(height: AppSpacing.lg),
|
||||
ShadForm(
|
||||
Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
ShadInputFormField(
|
||||
id: 'amount',
|
||||
MaterialInput(
|
||||
controller: amountController,
|
||||
label: const Text('提現金額'),
|
||||
placeholder: const Text('請輸入提現金額(USDT)'),
|
||||
labelText: '提現金額',
|
||||
hintText: '請輸入提現金額(USDT)',
|
||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||
validator: Validators.amount,
|
||||
validator: (v) {
|
||||
if (v == null || v.isEmpty) return '請輸入金額';
|
||||
final n = double.tryParse(v);
|
||||
if (n == null || n <= 0) return '請輸入有效金額';
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: AppSpacing.md),
|
||||
// 手續費/應收款提示
|
||||
@@ -518,14 +521,16 @@ void showWithdrawDialog(BuildContext context, String? balance) {
|
||||
builder: (_, selected, __) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: ShadSelect<String>(
|
||||
placeholder: const Text('選擇提現網絡'),
|
||||
initialValue: selected,
|
||||
selectedOptionBuilder: (context, val) => Text(val),
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: selected,
|
||||
hint: const Text('選擇提現網絡'),
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value != null) selectedNetworkNotifier.value = value;
|
||||
},
|
||||
options: networks.map((n) => ShadOption(value: n, child: Text(n))).toList(),
|
||||
items: networks.map((n) => DropdownMenuItem(value: n, child: Text(n))).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -535,19 +540,20 @@ void showWithdrawDialog(BuildContext context, String? balance) {
|
||||
},
|
||||
),
|
||||
const SizedBox(height: AppSpacing.md),
|
||||
ShadInputFormField(
|
||||
id: 'address',
|
||||
MaterialInput(
|
||||
controller: addressController,
|
||||
label: const Text('目標地址'),
|
||||
placeholder: const Text('請輸入提現地址'),
|
||||
validator: (v) => Validators.required(v, '提現地址'),
|
||||
labelText: '目標地址',
|
||||
hintText: '請輸入提現地址',
|
||||
validator: (v) {
|
||||
if (v == null || v.isEmpty) return '請輸入提現地址';
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: AppSpacing.md),
|
||||
ShadInputFormField(
|
||||
id: 'contact',
|
||||
MaterialInput(
|
||||
controller: contactController,
|
||||
label: const Text('聯繫方式(可選)'),
|
||||
placeholder: const Text('聯繫方式'),
|
||||
labelText: '聯繫方式(可選)',
|
||||
hintText: '聯繫方式',
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -570,7 +576,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
|
||||
text: '提交',
|
||||
type: NeonButtonType.primary,
|
||||
onPressed: () async {
|
||||
if (formKey.currentState!.saveAndValidate()) {
|
||||
if (formKey.currentState!.validate()) {
|
||||
Navigator.of(ctx).pop();
|
||||
final response = await context.read<AssetProvider>().withdraw(
|
||||
amount: amountController.text,
|
||||
@@ -619,7 +625,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
|
||||
void showResultDialog(BuildContext context, String title, String? message) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
showShadDialog(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
|
||||
Reference in New Issue
Block a user