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:
2026-04-08 12:24:24 +08:00
parent 5ee87136a7
commit 658f49e280
24 changed files with 281 additions and 455 deletions

View File

@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:provider/provider.dart';
import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_color_scheme.dart';
@@ -84,7 +83,7 @@ class _FundOrderCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final theme = Theme.of(context);
final isDeposit = order.type == 1;
final statusColor = _getStatusColor(order.status, isDeposit);
@@ -93,9 +92,10 @@ class _FundOrderCard extends StatelessWidget {
? order.receivableAmount
: order.amount;
return ShadCard(
padding: AppSpacing.cardPadding,
child: Column(
return Card(
child: Padding(
padding: AppSpacing.cardPadding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
@@ -126,7 +126,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.fee != null) ...[
Row(
children: [
Text('手續費(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('手續費(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text('-${order.fee} USDT', style: AppTextStyles.bodyMedium(context)),
],
),
@@ -135,7 +135,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.receivableAmount != null) ...[
Row(
children: [
Text('到賬金額: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('到賬金額: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text('${order.receivableAmount} USDT', style: AppTextStyles.bodyMedium(context).copyWith(fontWeight: FontWeight.w700)),
],
),
@@ -144,7 +144,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.network != null) ...[
Row(
children: [
Text('提現網絡: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('提現網絡: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text(order.network!, style: AppTextStyles.bodyMedium(context)),
],
),
@@ -153,7 +153,7 @@ class _FundOrderCard extends StatelessWidget {
if (order.walletAddress != null) ...[
Row(
children: [
Text('提現地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('提現地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Expanded(
child: Text(
order.walletAddress!,
@@ -169,14 +169,14 @@ class _FundOrderCard extends StatelessWidget {
],
Row(
children: [
Text('訂單號: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('訂單號: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text(order.orderNo, style: AppTextStyles.bodyMedium(context)),
],
),
SizedBox(height: AppSpacing.xs),
Row(
children: [
Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text(
order.createTime?.toString() ?? '',
style: AppTextStyles.bodyMedium(context),
@@ -187,7 +187,7 @@ class _FundOrderCard extends StatelessWidget {
SizedBox(height: AppSpacing.xs),
Row(
children: [
Text('駁回原因: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('駁回原因: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Expanded(
child: Text(
order.rejectReason!,
@@ -202,14 +202,14 @@ class _FundOrderCard extends StatelessWidget {
Row(
children: [
Expanded(
child: ShadButton.outline(
child: OutlinedButton(
onPressed: () => _handleConfirmPay(context),
child: const Text('已打款'),
),
),
SizedBox(width: AppSpacing.sm),
Expanded(
child: ShadButton.outline(
child: OutlinedButton(
onPressed: () => _handleCancel(context),
child: const Text('取消訂單'),
),
@@ -219,6 +219,7 @@ class _FundOrderCard extends StatelessWidget {
],
],
),
),
);
}

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:provider/provider.dart';
import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart';
@@ -16,7 +16,7 @@ class FundOrdersList extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final theme = Theme.of(context);
final orders = provider.fundOrders;
if (orders.isEmpty) {
@@ -33,7 +33,7 @@ class FundOrdersList extends StatelessWidget {
physics: const AlwaysScrollableScrollPhysics(),
padding: AppSpacing.pagePadding,
itemCount: orders.length,
separatorBuilder: (_, __) => Divider(color: theme.colorScheme.border, height: 1),
separatorBuilder: (_, __) => Divider(color: theme.colorScheme.outline, height: 1),
itemBuilder: (context, index) {
final order = orders[index];
return FundOrderCard(order: order);
@@ -52,7 +52,7 @@ class _EmptyState extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final theme = Theme.of(context);
return Center(
child: Padding(
@@ -60,9 +60,9 @@ class _EmptyState extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 48, color: theme.colorScheme.mutedForeground),
Icon(icon, size: 48, color: theme.colorScheme.onSurfaceVariant),
SizedBox(height: AppSpacing.sm + AppSpacing.xs),
Text(message, style: theme.textTheme.muted),
Text(message, style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
],
),
),
@@ -155,13 +155,14 @@ class _FundOrderCardContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final theme = Theme.of(context);
final isDeposit = order.type == 1;
final statusColor = _getStatusColor(order.status, isDeposit);
return ShadCard(
padding: AppSpacing.cardPadding,
child: Column(
return Card(
child: Padding(
padding: AppSpacing.cardPadding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
@@ -192,7 +193,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.fee != null) ...[
Row(
children: [
Text('手續費(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('手續費(10%): ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text('-${order.fee} USDT', style: AppTextStyles.bodyMedium(context)),
],
),
@@ -201,7 +202,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.receivableAmount != null) ...[
Row(
children: [
Text('到賬金額: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('到賬金額: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text('${order.receivableAmount} USDT', style: AppTextStyles.bodyMedium(context).copyWith(fontWeight: FontWeight.w700)),
],
),
@@ -210,7 +211,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.network != null) ...[
Row(
children: [
Text('提現網絡: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('提現網絡: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text(order.network!, style: AppTextStyles.bodyMedium(context)),
],
),
@@ -219,7 +220,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.walletAddress != null) ...[
Row(
children: [
Text('提現地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('提現地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Expanded(
child: Text(
order.walletAddress!,
@@ -234,14 +235,14 @@ class _FundOrderCardContent extends StatelessWidget {
],
Row(
children: [
Text('訂單號: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('訂單號: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text(order.orderNo, style: AppTextStyles.bodyMedium(context)),
],
),
SizedBox(height: AppSpacing.xs),
Row(
children: [
Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)),
Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text(
order.createTime?.toString() ?? '',
style: AppTextStyles.bodyMedium(context),
@@ -250,6 +251,7 @@ class _FundOrderCardContent extends StatelessWidget {
),
],
),
),
);
}
}

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:provider/provider.dart';
import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart';
@@ -35,10 +35,10 @@ class _OrdersPageState extends State<OrdersPage> with AutomaticKeepAliveClientMi
@override
Widget build(BuildContext context) {
super.build(context);
final theme = ShadTheme.of(context);
final theme = Theme.of(context);
return Scaffold(
backgroundColor: theme.colorScheme.background,
backgroundColor: theme.colorScheme.surface,
body: Consumer<AssetProvider>(
builder: (context, provider, _) {
return RefreshIndicator(
@@ -83,12 +83,12 @@ class TabSelector extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final theme = Theme.of(context);
return Container(
padding: const EdgeInsets.all(AppSpacing.xs),
decoration: BoxDecoration(
color: theme.colorScheme.card,
color: theme.colorScheme.surfaceContainer,
borderRadius: AppRadius.radiusLg,
),
child: Row(
@@ -115,7 +115,7 @@ class TabSelector extends StatelessWidget {
color: context.colors.surface,
)
: AppTextStyles.labelLarge(context).copyWith(
color: theme.colorScheme.mutedForeground,
color: theme.colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w400,
),
),
@@ -137,7 +137,7 @@ class TradeOrdersList extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final theme = Theme.of(context);
return Center(
child: Padding(
@@ -145,9 +145,9 @@ class TradeOrdersList extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(LucideIcons.receipt, size: 48, color: theme.colorScheme.mutedForeground),
Icon(LucideIcons.receipt, size: 48, color: theme.colorScheme.onSurfaceVariant),
SizedBox(height: AppSpacing.sm + AppSpacing.xs),
Text('暫無交易記錄', style: theme.textTheme.muted),
Text('暫無交易記錄', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
],
),
),