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:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
/// Material Design 3 顏色系統 - Pencil Design Theme /// Material Design 3 顏色系統 - Pencil Design Theme
/// ///
@@ -252,60 +251,6 @@ class AppColorScheme {
end: Alignment.bottomRight, end: Alignment.bottomRight,
); );
// ============================================
// Shadcn ColorScheme - 深色主題
// ============================================
static ShadColorScheme get darkShad => ShadColorScheme(
background: darkBackground,
foreground: darkOnSurface,
card: darkSurfaceContainer,
cardForeground: darkOnSurface,
popover: darkSurfaceContainerHigh,
popoverForeground: darkOnSurface,
primary: darkPrimary,
primaryForeground: darkOnPrimary,
secondary: darkSecondary,
secondaryForeground: darkOnSecondary,
muted: darkSurfaceContainerHigh,
mutedForeground: darkOnSurfaceVariant,
accent: darkPrimary.withValues(alpha: 0.15),
accentForeground: darkPrimary,
destructive: error,
destructiveForeground: darkOnSurface,
border: darkOutlineVariant.withValues(alpha: 0.15),
input: darkOutlineVariant.withValues(alpha: 0.15),
ring: darkPrimary,
selection: darkPrimary.withValues(alpha: 0.3),
);
// ============================================
// Shadcn ColorScheme - 淺色主題
// ============================================
static ShadColorScheme get lightShad => ShadColorScheme(
background: lightBackground,
foreground: lightOnSurface,
card: lightSurfaceLowest,
cardForeground: lightOnSurface,
popover: lightSurfaceLowest,
popoverForeground: lightOnSurface,
primary: lightPrimary,
primaryForeground: const Color(0xFFFFFFFF),
secondary: lightSecondary,
secondaryForeground: const Color(0xFFFFFFFF),
muted: lightSurfaceHigh,
mutedForeground: lightOnSurfaceVariant,
accent: lightSecondary.withValues(alpha: 0.1),
accentForeground: lightSecondary,
destructive: error,
destructiveForeground: const Color(0xFFFFFFFF),
border: lightOutlineVariant.withValues(alpha: 0.5),
input: lightOutlineVariant.withValues(alpha: 0.3),
ring: lightSecondary,
selection: lightSecondary.withValues(alpha: 0.2),
);
// ============================================ // ============================================
// Material ColorScheme - 深色主題 (Material Design 3) // Material ColorScheme - 深色主題 (Material Design 3)
// ============================================ // ============================================

View File

@@ -1,6 +1,5 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:bot_toast/bot_toast.dart'; import 'package:bot_toast/bot_toast.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -9,7 +8,6 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'core/network/dio_client.dart'; import 'core/network/dio_client.dart';
import 'core/storage/local_storage.dart'; import 'core/storage/local_storage.dart';
import 'core/theme/app_color_scheme.dart';
import 'core/theme/app_theme.dart'; import 'core/theme/app_theme.dart';
import 'core/event/app_event_bus.dart'; import 'core/event/app_event_bus.dart';
import 'data/services/user_service.dart'; import 'data/services/user_service.dart';
@@ -67,18 +65,7 @@ class MyApp extends StatelessWidget {
providers: _buildProviders(), providers: _buildProviders(),
child: Consumer<ThemeProvider>( child: Consumer<ThemeProvider>(
builder: (context, themeProvider, _) { builder: (context, themeProvider, _) {
return ShadApp.custom( return _buildMaterialApp(context, themeProvider.themeMode);
themeMode: themeProvider.themeMode,
theme: ShadThemeData(
colorScheme: AppColorScheme.lightShad,
brightness: Brightness.light,
),
darkTheme: ShadThemeData(
colorScheme: AppColorScheme.darkShad,
brightness: Brightness.dark,
),
appBuilder: (context) => _buildMaterialApp(context, themeProvider.themeMode),
);
}, },
), ),
); );
@@ -130,13 +117,11 @@ class MyApp extends StatelessWidget {
darkTheme: AppTheme.darkTheme, darkTheme: AppTheme.darkTheme,
themeMode: themeMode, themeMode: themeMode,
localizationsDelegates: const [ localizationsDelegates: const [
GlobalShadLocalizations.delegate,
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
], ],
builder: (context, child) { builder: (context, child) {
child = ShadAppBuilder(child: child!);
// 配置 BotToast 確保顯示在所有內容之上 // 配置 BotToast 確保顯示在所有內容之上
final botToastBuilder = BotToastInit(); final botToastBuilder = BotToastInit();
child = botToastBuilder(context, child); child = botToastBuilder(context, child);

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../core/theme/app_theme.dart';
import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_animate/flutter_animate.dart';
import '../../core/theme/app_spacing.dart'; import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart'; import '../../core/theme/app_theme_extension.dart';
@@ -35,8 +36,8 @@ class AssetCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
final colorScheme = context.colors; final colorScheme = theme.colorScheme;
final appColors = context.appColors; final appColors = context.appColors;
final cardGradient = gradient ?? appColors.assetGradient; final cardGradient = gradient ?? appColors.assetGradient;
@@ -68,7 +69,7 @@ class AssetCard extends StatelessWidget {
children: [ children: [
Text( Text(
title, title,
style: theme.textTheme.small.copyWith(color: secondaryTextColor), style: AppTextStyles.bodySmall(context).copyWith(color: secondaryTextColor),
), ),
const Spacer(), const Spacer(),
if (onTap != null) if (onTap != null)
@@ -83,7 +84,7 @@ class AssetCard extends StatelessWidget {
// 餘額 - 大標題 // 餘額 - 大標題
Text( Text(
balance, balance,
style: theme.textTheme.h1.copyWith( style: AppTextStyles.headlineLarge(context).copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: primaryTextColor, color: primaryTextColor,
fontSize: 20, fontSize: 20,
@@ -102,7 +103,7 @@ class AssetCard extends StatelessWidget {
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
'盈虧: $profit', '盈虧: $profit',
style: theme.textTheme.small.copyWith(color: secondaryTextColor), style: AppTextStyles.bodySmall(context).copyWith(color: secondaryTextColor),
), ),
], ],
), ),
@@ -178,11 +179,12 @@ class AssetCardCompact extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
final appColors = context.appColors; final appColors = context.appColors;
final isValueUp = isUp ?? true; final isValueUp = isUp ?? true;
return ShadCard( return Card(
child: Padding(
padding: const EdgeInsets.all(AppSpacing.md), padding: const EdgeInsets.all(AppSpacing.md),
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
@@ -194,12 +196,12 @@ class AssetCardCompact extends StatelessWidget {
children: [ children: [
Text( Text(
title, title,
style: theme.textTheme.muted, style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
balance, balance,
style: theme.textTheme.h3.copyWith( style: AppTextStyles.headlineMedium(context).copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
@@ -224,6 +226,7 @@ class AssetCardCompact extends StatelessWidget {
], ],
), ),
), ),
),
); );
} }
} }

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import '../../core/theme/app_theme.dart';
import '../../core/theme/app_spacing.dart'; import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart'; import '../../core/theme/app_theme_extension.dart';
@@ -31,9 +31,10 @@ class CoinCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return ShadCard( return Card(
child: Padding(
padding: const EdgeInsets.all(AppSpacing.md), padding: const EdgeInsets.all(AppSpacing.md),
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
@@ -66,13 +67,13 @@ class CoinCard extends StatelessWidget {
children: [ children: [
Text( Text(
'$code/USDT', '$code/USDT',
style: theme.textTheme.large.copyWith( style: AppTextStyles.headlineMedium(context).copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text( Text(
name, name,
style: theme.textTheme.muted, style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant),
), ),
], ],
), ),
@@ -95,6 +96,7 @@ class CoinCard extends StatelessWidget {
], ],
), ),
), ),
),
); );
} }
} }

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../../components/material_input.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../../../core/theme/app_theme.dart'; import '../../../../core/theme/app_theme.dart';
import '../../../../core/theme/app_theme_extension.dart'; import '../../../../core/theme/app_theme_extension.dart';
@@ -129,10 +129,10 @@ class WalletAddressCard extends StatelessWidget {
/// 充值對話框 /// 充值對話框
void showDepositDialog(BuildContext context) { void showDepositDialog(BuildContext context) {
final amountController = TextEditingController(); final amountController = TextEditingController();
final formKey = GlobalKey<ShadFormState>(); final formKey = GlobalKey<FormState>();
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => Dialog( builder: (ctx) => Dialog(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@@ -178,13 +178,12 @@ void showDepositDialog(BuildContext context) {
], ],
), ),
const SizedBox(height: AppSpacing.lg), const SizedBox(height: AppSpacing.lg),
ShadForm( Form(
key: formKey, key: formKey,
child: ShadInputFormField( child: MaterialInput(
id: 'amount',
controller: amountController, controller: amountController,
label: const Text('充值金額'), labelText: '充值金額',
placeholder: const Text('最低 1000 USDT'), hintText: '最低 1000 USDT',
keyboardType: const TextInputType.numberWithOptions(decimal: true), keyboardType: const TextInputType.numberWithOptions(decimal: true),
validator: (v) { validator: (v) {
if (v == null || v.isEmpty) return '請輸入金額'; if (v == null || v.isEmpty) return '請輸入金額';
@@ -213,7 +212,7 @@ void showDepositDialog(BuildContext context) {
text: '下一步', text: '下一步',
type: NeonButtonType.primary, type: NeonButtonType.primary,
onPressed: () async { onPressed: () async {
if (formKey.currentState!.saveAndValidate()) { if (formKey.currentState!.validate()) {
Navigator.of(ctx).pop(); Navigator.of(ctx).pop();
final response = await context.read<AssetProvider>().deposit( final response = await context.read<AssetProvider>().deposit(
amount: amountController.text, amount: amountController.text,
@@ -248,7 +247,7 @@ void showDepositResultDialog(BuildContext context, Map<String, dynamic> data) {
final walletNetwork = data['walletNetwork'] as String? ?? 'TRC20'; final walletNetwork = data['walletNetwork'] as String? ?? 'TRC20';
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => Dialog( builder: (ctx) => Dialog(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@@ -359,7 +358,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
final amountController = TextEditingController(); final amountController = TextEditingController();
final addressController = TextEditingController(); final addressController = TextEditingController();
final contactController = TextEditingController(); final contactController = TextEditingController();
final formKey = GlobalKey<ShadFormState>(); final formKey = GlobalKey<FormState>();
final feeNotifier = ValueNotifier<String>('提現將扣除10%手續費'); final feeNotifier = ValueNotifier<String>('提現將扣除10%手續費');
final networksNotifier = ValueNotifier<List<String>>([]); final networksNotifier = ValueNotifier<List<String>>([]);
final selectedNetworkNotifier = ValueNotifier<String?>(null); final selectedNetworkNotifier = ValueNotifier<String?>(null);
@@ -384,7 +383,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
} }
}); });
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => Dialog( builder: (ctx) => Dialog(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@@ -460,17 +459,21 @@ void showWithdrawDialog(BuildContext context, String? balance) {
), ),
], ],
const SizedBox(height: AppSpacing.lg), const SizedBox(height: AppSpacing.lg),
ShadForm( Form(
key: formKey, key: formKey,
child: Column( child: Column(
children: [ children: [
ShadInputFormField( MaterialInput(
id: 'amount',
controller: amountController, controller: amountController,
label: const Text('提現金額'), labelText: '提現金額',
placeholder: const Text('請輸入提現金額(USDT)'), hintText: '請輸入提現金額(USDT)',
keyboardType: const TextInputType.numberWithOptions(decimal: true), 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), const SizedBox(height: AppSpacing.md),
// 手續費/應收款提示 // 手續費/應收款提示
@@ -518,14 +521,16 @@ void showWithdrawDialog(BuildContext context, String? balance) {
builder: (_, selected, __) { builder: (_, selected, __) {
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
child: ShadSelect<String>( child: DropdownButtonFormField<String>(
placeholder: const Text('選擇提現網絡'), value: selected,
initialValue: selected, hint: const Text('選擇提現網絡'),
selectedOptionBuilder: (context, val) => Text(val), decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
),
onChanged: (value) { onChanged: (value) {
if (value != null) selectedNetworkNotifier.value = 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), const SizedBox(height: AppSpacing.md),
ShadInputFormField( MaterialInput(
id: 'address',
controller: addressController, controller: addressController,
label: const Text('目標地址'), labelText: '目標地址',
placeholder: const Text('請輸入提現地址'), hintText: '請輸入提現地址',
validator: (v) => Validators.required(v, '提現地址'), validator: (v) {
if (v == null || v.isEmpty) return '請輸入提現地址';
return null;
},
), ),
const SizedBox(height: AppSpacing.md), const SizedBox(height: AppSpacing.md),
ShadInputFormField( MaterialInput(
id: 'contact',
controller: contactController, controller: contactController,
label: const Text('聯繫方式(可選)'), labelText: '聯繫方式(可選)',
placeholder: const Text('聯繫方式'), hintText: '聯繫方式',
), ),
], ],
), ),
@@ -570,7 +576,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
text: '提交', text: '提交',
type: NeonButtonType.primary, type: NeonButtonType.primary,
onPressed: () async { onPressed: () async {
if (formKey.currentState!.saveAndValidate()) { if (formKey.currentState!.validate()) {
Navigator.of(ctx).pop(); Navigator.of(ctx).pop();
final response = await context.read<AssetProvider>().withdraw( final response = await context.read<AssetProvider>().withdraw(
amount: amountController.text, amount: amountController.text,
@@ -619,7 +625,7 @@ void showWithdrawDialog(BuildContext context, String? balance) {
void showResultDialog(BuildContext context, String title, String? message) { void showResultDialog(BuildContext context, String title, String? message) {
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => Dialog( builder: (ctx) => Dialog(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_chen_kchart/k_chart.dart'; import 'package:flutter_chen_kchart/k_chart.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
@@ -16,7 +16,7 @@ class ChartPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
return ChangeNotifierProvider( return ChangeNotifierProvider(
create: (_) => ChartProvider() create: (_) => ChartProvider()
@@ -137,7 +137,7 @@ class ChartPage extends StatelessWidget {
} }
Widget _buildPriceHeader(BuildContext context, ChartProvider provider) { Widget _buildPriceHeader(BuildContext context, ChartProvider provider) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
final candles = provider.candles; final candles = provider.candles;
if (candles.isEmpty) return const SizedBox.shrink(); if (candles.isEmpty) return const SizedBox.shrink();
@@ -213,7 +213,7 @@ class ChartPage extends StatelessWidget {
} }
Widget _buildDataItem(BuildContext context, String label, String value) { Widget _buildDataItem(BuildContext context, String label, String value) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -224,7 +224,7 @@ class ChartPage extends StatelessWidget {
} }
Widget _buildIntervalTabs(BuildContext context, ChartProvider provider) { Widget _buildIntervalTabs(BuildContext context, ChartProvider provider) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
return Container( return Container(
height: 40, height: 40,
@@ -260,7 +260,7 @@ class ChartPage extends StatelessWidget {
/// 底部指标切换(官方 demo 风格) /// 底部指标切换(官方 demo 风格)
Widget _buildIndicatorTabs(BuildContext context, ChartProvider provider) { Widget _buildIndicatorTabs(BuildContext context, ChartProvider provider) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
final selectedColor = colorScheme.primary; final selectedColor = colorScheme.primary;
final unselectedColor = colorScheme.onSurfaceVariant; final unselectedColor = colorScheme.onSurfaceVariant;
@@ -361,7 +361,7 @@ class ChartPage extends StatelessWidget {
} }
Widget _buildBottomActions(BuildContext context, ChartProvider provider) { Widget _buildBottomActions(BuildContext context, ChartProvider provider) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
return Container( return Container(
padding: const EdgeInsets.all(AppSpacing.md), padding: const EdgeInsets.all(AppSpacing.md),
@@ -414,7 +414,7 @@ class ChartPage extends StatelessWidget {
Widget _buildTitle(BuildContext context) { Widget _buildTitle(BuildContext context) {
return Consumer<ChartProvider>( return Consumer<ChartProvider>(
builder: (context, provider, _) { builder: (context, provider, _) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
return Row( return Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -428,7 +428,7 @@ class ChartPage extends StatelessWidget {
} }
Widget _buildErrorView(BuildContext context, ChartProvider provider) { Widget _buildErrorView(BuildContext context, ChartProvider provider) {
final colorScheme = context.colors; final colorScheme = Theme.of(context).colorScheme;
return Center( return Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';

View File

@@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme_extension.dart'; import '../../../core/theme/app_theme_extension.dart';
@@ -87,12 +87,12 @@ class _HomePageState extends State<HomePage>
super.build(context); super.build(context);
return Scaffold( return Scaffold(
backgroundColor: context.colors.background, backgroundColor: Theme.of(context).colorScheme.background,
body: Consumer<AssetProvider>( body: Consumer<AssetProvider>(
builder: (context, provider, _) { builder: (context, provider, _) {
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => provider.refreshAll(force: true), onRefresh: () => provider.refreshAll(force: true),
color: context.colors.primary, color: Theme.of(context).colorScheme.primary,
child: SingleChildScrollView( child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only( padding: EdgeInsets.only(
@@ -270,7 +270,7 @@ class _AssetCardState extends State<_AssetCard> {
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colors.primary, color: Theme.of(context).colorScheme.primary,
borderRadius: BorderRadius.circular(AppRadius.sm), borderRadius: BorderRadius.circular(AppRadius.sm),
), ),
child: Row( child: Row(
@@ -280,7 +280,7 @@ class _AssetCardState extends State<_AssetCard> {
Text( Text(
'充值', '充值',
style: AppTextStyles.labelLarge(context).copyWith( style: AppTextStyles.labelLarge(context).copyWith(
color: context.colors.onPrimary, color: Theme.of(context).colorScheme.onPrimary,
fontSize: 12, fontSize: 12,
), ),
), ),
@@ -359,9 +359,9 @@ class _WelfareCard extends StatelessWidget {
width: double.infinity, width: double.infinity,
padding: EdgeInsets.all(AppSpacing.lg), padding: EdgeInsets.all(AppSpacing.lg),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colors.surface, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(AppRadius.xl), borderRadius: BorderRadius.circular(AppRadius.xl),
border: Border.all(color: context.colors.outlineVariant.withValues(alpha: 0.2)), border: Border.all(color: Theme.of(context).colorScheme.outlineVariant.withValues(alpha: 0.2)),
), ),
child: Row( child: Row(
children: [ children: [
@@ -370,12 +370,12 @@ class _WelfareCard extends StatelessWidget {
width: 48, width: 48,
height: 48, height: 48,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colors.primary.withValues(alpha: 0.15), color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(AppRadius.lg), borderRadius: BorderRadius.circular(AppRadius.lg),
), ),
child: Icon( child: Icon(
LucideIcons.gift, LucideIcons.gift,
color: context.colors.primary, color: Theme.of(context).colorScheme.primary,
size: 24, size: 24,
), ),
), ),
@@ -426,7 +426,7 @@ class _WelfareCard extends StatelessWidget {
style: AppTextStyles.bodySmall(context).copyWith( style: AppTextStyles.bodySmall(context).copyWith(
fontSize: 10, fontSize: 10,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: context.colors.onPrimary, color: Theme.of(context).colorScheme.onPrimary,
), ),
), ),
), ),
@@ -504,13 +504,13 @@ class _EmptyHoldings extends StatelessWidget {
width: double.infinity, width: double.infinity,
padding: EdgeInsets.symmetric(vertical: AppSpacing.xxl, horizontal: AppSpacing.lg), padding: EdgeInsets.symmetric(vertical: AppSpacing.xxl, horizontal: AppSpacing.lg),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colors.surfaceContainerLow.withValues(alpha: 0.5), color: Theme.of(context).colorScheme.surfaceContainerLow.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(AppRadius.xxl), borderRadius: BorderRadius.circular(AppRadius.xxl),
border: Border.all(color: context.colors.outlineVariant.withValues(alpha: 0.1)), border: Border.all(color: Theme.of(context).colorScheme.outlineVariant.withValues(alpha: 0.1)),
), ),
child: Column( child: Column(
children: [ children: [
Icon(LucideIcons.wallet, size: 48, color: context.colors.onSurfaceVariant), Icon(LucideIcons.wallet, size: 48, color: Theme.of(context).colorScheme.onSurfaceVariant),
SizedBox(height: AppSpacing.md), SizedBox(height: AppSpacing.md),
Text( Text(
'暫無持倉', '暫無持倉',
@@ -542,9 +542,9 @@ class _HoldingsList extends StatelessWidget {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colors.surface.withValues(alpha: 0.5), color: Theme.of(context).colorScheme.surface.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(AppRadius.xxl), borderRadius: BorderRadius.circular(AppRadius.xxl),
border: Border.all(color: context.colors.outlineVariant.withValues(alpha: 0.1)), border: Border.all(color: Theme.of(context).colorScheme.outlineVariant.withValues(alpha: 0.1)),
), ),
child: ListView.separated( child: ListView.separated(
shrinkWrap: true, shrinkWrap: true,

View File

@@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme_extension.dart'; import '../../../core/theme/app_theme_extension.dart';
@@ -36,9 +35,9 @@ class HotCoinsSection extends StatelessWidget {
// Card // Card
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.colors.surfaceContainer, color: Theme.of(context).colorScheme.surfaceContainer,
border: Border.all( border: Border.all(
color: context.colors.outlineVariant, color: Theme.of(context).colorScheme.outlineVariant,
width: 1, width: 1,
), ),
borderRadius: BorderRadius.circular(AppRadius.xl), borderRadius: BorderRadius.circular(AppRadius.xl),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';

View File

@@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
import '../../../providers/asset_provider.dart'; import '../../../providers/asset_provider.dart';

View File

@@ -1,7 +1,7 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart'; 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 'package:provider/provider.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_color_scheme.dart';
@@ -431,9 +431,9 @@ class _KycPageState extends State<KycPage> {
if (!mounted) return; if (!mounted) return;
if (response.success) { if (response.success) {
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => ShadDialog.alert( builder: (ctx) => AlertDialog(
title: Row( title: Row(
children: [ children: [
NeonIcon( NeonIcon(
@@ -445,9 +445,9 @@ class _KycPageState extends State<KycPage> {
const Text('認證成功'), const Text('認證成功'),
], ],
), ),
description: const Text('您的實名認證已通過,現在可以進行提現操作'), content: const Text('您的實名認證已通過,現在可以進行提現操作'),
actions: [ actions: [
ShadButton( TextButton(
child: const Text('確定'), child: const Text('確定'),
onPressed: () { onPressed: () {
Navigator.of(ctx).pop(); Navigator.of(ctx).pop();
@@ -458,13 +458,13 @@ class _KycPageState extends State<KycPage> {
), ),
); );
} else { } else {
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => ShadDialog.alert( builder: (ctx) => AlertDialog(
title: const Text('認證失敗'), title: const Text('認證失敗'),
description: Text(response.message ?? '請稍後重試'), content: Text(response.message ?? '請稍後重試'),
actions: [ actions: [
ShadButton( TextButton(
child: const Text('確定'), child: const Text('確定'),
onPressed: () => Navigator.of(ctx).pop(), onPressed: () => Navigator.of(ctx).pop(),
), ),
@@ -474,13 +474,13 @@ class _KycPageState extends State<KycPage> {
} }
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => ShadDialog.alert( builder: (ctx) => AlertDialog(
title: const Text('認證失敗'), title: const Text('認證失敗'),
description: Text(e.toString()), content: Text(e.toString()),
actions: [ actions: [
ShadButton( TextButton(
child: const Text('確定'), child: const Text('確定'),
onPressed: () => Navigator.of(ctx).pop(), onPressed: () => Navigator.of(ctx).pop(),
), ),

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
@@ -145,9 +145,9 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
final goldAccent = context.appColors.accentPrimary; final goldAccent = context.appColors.accentPrimary;
return Scaffold( return Scaffold(
backgroundColor: context.colors.surface, backgroundColor: Theme.of(context).colorScheme.surface,
appBar: AppBar( appBar: AppBar(
backgroundColor: context.colors.surface, backgroundColor: Theme.of(context).colorScheme.surface,
elevation: 0, elevation: 0,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
centerTitle: false, centerTitle: false,
@@ -157,7 +157,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
style: AppTextStyles.headlineLarge(context), style: AppTextStyles.headlineLarge(context),
), ),
leading: IconButton( leading: IconButton(
icon: Icon(LucideIcons.arrowLeft, color: context.colors.onSurface, size: 24), icon: Icon(LucideIcons.arrowLeft, color: Theme.of(context).colorScheme.onSurface, size: 24),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
), ),
@@ -242,7 +242,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: goldAccent, backgroundColor: goldAccent,
foregroundColor: context.colors.onPrimary, foregroundColor: Theme.of(context).colorScheme.onPrimary,
elevation: 0, elevation: 0,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg), borderRadius: BorderRadius.circular(AppRadius.lg),
@@ -251,7 +251,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
), ),
child: Text( child: Text(
'複製邀請碼', '複製邀請碼',
style: AppTextStyles.headlineMedium(context).copyWith(color: context.colors.onPrimary), style: AppTextStyles.headlineMedium(context).copyWith(color: Theme.of(context).colorScheme.onPrimary),
), ),
), ),
), ),
@@ -325,21 +325,21 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
'+100 USDT', '+100 USDT',
style: AppTextStyles.displayLarge(context).copyWith( style: AppTextStyles.displayLarge(context).copyWith(
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: claimed ? context.colors.onSurfaceVariant : profitGreen, color: claimed ? Theme.of(context).colorScheme.onSurfaceVariant : profitGreen,
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
description, description,
style: AppTextStyles.bodyLarge(context).copyWith( style: AppTextStyles.bodyLarge(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
_fullWidthButton( _fullWidthButton(
text: buttonText, text: buttonText,
backgroundColor: profitGreen, backgroundColor: profitGreen,
foregroundColor: context.colors.onPrimary, foregroundColor: Theme.of(context).colorScheme.onPrimary,
onPressed: canClaim ? () => _claimNewUserBonus() : null, onPressed: canClaim ? () => _claimNewUserBonus() : null,
), ),
], ],
@@ -425,12 +425,12 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
child: Column( child: Column(
children: [ children: [
Text(label, style: AppTextStyles.bodySmall(context).copyWith( Text(label, style: AppTextStyles.bodySmall(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
)), )),
const SizedBox(height: 2), const SizedBox(height: 2),
Text(value, style: AppTextStyles.headlineSmall(context).copyWith( Text(value, style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: highlight ? context.appColors.up : context.colors.onSurface, color: highlight ? context.appColors.up : Theme.of(context).colorScheme.onSurface,
)), )),
], ],
), ),
@@ -452,7 +452,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
Text( Text(
'暫無推廣用戶', '暫無推廣用戶',
style: AppTextStyles.bodyLarge(context).copyWith( style: AppTextStyles.bodyLarge(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
], ],
@@ -592,7 +592,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
label = '${threshold}'; label = '${threshold}';
} else { } else {
bgColor = context.appColors.surfaceCardHigh; bgColor = context.appColors.surfaceCardHigh;
textColor = context.colors.onSurfaceVariant; textColor = Theme.of(context).colorScheme.onSurfaceVariant;
label = '${threshold}'; label = '${threshold}';
} }
@@ -631,7 +631,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
child: Text( child: Text(
username.isNotEmpty ? username[0].toUpperCase() : '?', username.isNotEmpty ? username[0].toUpperCase() : '?',
style: AppTextStyles.headlineSmall(context).copyWith( style: AppTextStyles.headlineSmall(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
), ),
@@ -719,7 +719,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
Text( Text(
'已推廣 $indirectRefCount', '已推廣 $indirectRefCount',
style: AppTextStyles.bodyMedium(context).copyWith( style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
if (indirectClaimableCount > 0) ...[ if (indirectClaimableCount > 0) ...[
@@ -773,7 +773,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
label = '50\u{1F381}'; label = '50\u{1F381}';
} else { } else {
bgColor = context.appColors.surfaceCardHigh; bgColor = context.appColors.surfaceCardHigh;
textColor = context.colors.onSurfaceVariant; textColor = Theme.of(context).colorScheme.onSurfaceVariant;
label = '50'; label = '50';
} }
@@ -841,7 +841,7 @@ class _WelfareCenterPageState extends State<WelfareCenterPage> {
child: Text( child: Text(
'\u2022 $text', '\u2022 $text',
style: AppTextStyles.bodyMedium(context).copyWith( style: AppTextStyles.bodyMedium(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
); );

View File

@@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme.dart';
import '../../../core/theme/app_theme_extension.dart';
import '../../../core/storage/local_storage.dart'; import '../../../core/storage/local_storage.dart';
/// 引導頁數據模型 /// 引導頁數據模型
@@ -93,7 +92,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: context.colors.surface, backgroundColor: Theme.of(context).colorScheme.surface,
body: SafeArea( body: SafeArea(
child: Column( child: Column(
children: [ children: [
@@ -111,7 +110,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
child: Text( child: Text(
'跳過', '跳過',
style: AppTextStyles.headlineMedium(context).copyWith( style: AppTextStyles.headlineMedium(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
), ),
@@ -159,8 +158,8 @@ class _OnboardingPageState extends State<OnboardingPage> {
child: ElevatedButton( child: ElevatedButton(
onPressed: _nextPage, onPressed: _nextPage,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: context.colors.primary, backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: context.colors.onPrimary, foregroundColor: Theme.of(context).colorScheme.onPrimary,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg), borderRadius: BorderRadius.circular(AppRadius.lg),
), ),
@@ -221,7 +220,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
return Icon( return Icon(
item.icon ?? LucideIcons.image, item.icon ?? LucideIcons.image,
size: 72, size: 72,
color: context.colors.onPrimary, color: Theme.of(context).colorScheme.onPrimary,
); );
}, },
), ),
@@ -229,7 +228,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
: Icon( : Icon(
item.icon ?? LucideIcons.star, item.icon ?? LucideIcons.star,
size: 72, size: 72,
color: context.colors.onPrimary, color: Theme.of(context).colorScheme.onPrimary,
), ),
), ),
), ),
@@ -239,7 +238,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
item.title, item.title,
style: AppTextStyles.displaySmall(context).copyWith( style: AppTextStyles.displaySmall(context).copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: context.colors.onSurface, color: Theme.of(context).colorScheme.onSurface,
letterSpacing: -0.5, letterSpacing: -0.5,
), ),
), ),
@@ -249,7 +248,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
item.description, item.description,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: AppTextStyles.headlineMedium(context).copyWith( style: AppTextStyles.headlineMedium(context).copyWith(
color: context.colors.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
height: 1.6, height: 1.6,
), ),
), ),
@@ -267,7 +266,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
width: isActive ? 24 : 8, width: isActive ? 24 : 8,
height: 8, height: 8,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isActive ? context.colors.primary : context.colors.outlineVariant, color: isActive ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.outlineVariant,
borderRadius: BorderRadius.circular(AppRadius.sm), borderRadius: BorderRadius.circular(AppRadius.sm),
), ),
); );

View File

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

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; 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 'package:provider/provider.dart';
import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
@@ -16,7 +16,7 @@ class FundOrdersList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
final orders = provider.fundOrders; final orders = provider.fundOrders;
if (orders.isEmpty) { if (orders.isEmpty) {
@@ -33,7 +33,7 @@ class FundOrdersList extends StatelessWidget {
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
padding: AppSpacing.pagePadding, padding: AppSpacing.pagePadding,
itemCount: orders.length, itemCount: orders.length,
separatorBuilder: (_, __) => Divider(color: theme.colorScheme.border, height: 1), separatorBuilder: (_, __) => Divider(color: theme.colorScheme.outline, height: 1),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final order = orders[index]; final order = orders[index];
return FundOrderCard(order: order); return FundOrderCard(order: order);
@@ -52,7 +52,7 @@ class _EmptyState extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return Center( return Center(
child: Padding( child: Padding(
@@ -60,9 +60,9 @@ class _EmptyState extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(icon, size: 48, color: theme.colorScheme.mutedForeground), Icon(icon, size: 48, color: theme.colorScheme.onSurfaceVariant),
SizedBox(height: AppSpacing.sm + AppSpacing.xs), SizedBox(height: AppSpacing.sm + AppSpacing.xs),
Text(message, style: theme.textTheme.muted), Text(message, style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
], ],
), ),
), ),
@@ -155,11 +155,12 @@ class _FundOrderCardContent extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
final isDeposit = order.type == 1; final isDeposit = order.type == 1;
final statusColor = _getStatusColor(order.status, isDeposit); final statusColor = _getStatusColor(order.status, isDeposit);
return ShadCard( return Card(
child: Padding(
padding: AppSpacing.cardPadding, padding: AppSpacing.cardPadding,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -192,7 +193,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.fee != null) ...[ if (order.fee != null) ...[
Row( Row(
children: [ 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)), Text('-${order.fee} USDT', style: AppTextStyles.bodyMedium(context)),
], ],
), ),
@@ -201,7 +202,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.receivableAmount != null) ...[ if (order.receivableAmount != null) ...[
Row( Row(
children: [ 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)), Text('${order.receivableAmount} USDT', style: AppTextStyles.bodyMedium(context).copyWith(fontWeight: FontWeight.w700)),
], ],
), ),
@@ -210,7 +211,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.network != null) ...[ if (order.network != null) ...[
Row( Row(
children: [ 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)), Text(order.network!, style: AppTextStyles.bodyMedium(context)),
], ],
), ),
@@ -219,7 +220,7 @@ class _FundOrderCardContent extends StatelessWidget {
if (order.walletAddress != null) ...[ if (order.walletAddress != null) ...[
Row( Row(
children: [ children: [
Text('提現地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)), Text('提現地址: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Expanded( Expanded(
child: Text( child: Text(
order.walletAddress!, order.walletAddress!,
@@ -234,14 +235,14 @@ class _FundOrderCardContent extends StatelessWidget {
], ],
Row( Row(
children: [ 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)), Text(order.orderNo, style: AppTextStyles.bodyMedium(context)),
], ],
), ),
SizedBox(height: AppSpacing.xs), SizedBox(height: AppSpacing.xs),
Row( Row(
children: [ children: [
Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.mutedForeground)), Text('創建時間: ', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
Text( Text(
order.createTime?.toString() ?? '', order.createTime?.toString() ?? '',
style: AppTextStyles.bodyMedium(context), 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:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_color_scheme.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
@@ -35,10 +35,10 @@ class _OrdersPageState extends State<OrdersPage> with AutomaticKeepAliveClientMi
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return Scaffold( return Scaffold(
backgroundColor: theme.colorScheme.background, backgroundColor: theme.colorScheme.surface,
body: Consumer<AssetProvider>( body: Consumer<AssetProvider>(
builder: (context, provider, _) { builder: (context, provider, _) {
return RefreshIndicator( return RefreshIndicator(
@@ -83,12 +83,12 @@ class TabSelector extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return Container( return Container(
padding: const EdgeInsets.all(AppSpacing.xs), padding: const EdgeInsets.all(AppSpacing.xs),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.colorScheme.card, color: theme.colorScheme.surfaceContainer,
borderRadius: AppRadius.radiusLg, borderRadius: AppRadius.radiusLg,
), ),
child: Row( child: Row(
@@ -115,7 +115,7 @@ class TabSelector extends StatelessWidget {
color: context.colors.surface, color: context.colors.surface,
) )
: AppTextStyles.labelLarge(context).copyWith( : AppTextStyles.labelLarge(context).copyWith(
color: theme.colorScheme.mutedForeground, color: theme.colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
@@ -137,7 +137,7 @@ class TradeOrdersList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return Center( return Center(
child: Padding( child: Padding(
@@ -145,9 +145,9 @@ class TradeOrdersList extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ 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), SizedBox(height: AppSpacing.sm + AppSpacing.xs),
Text('暫無交易記錄', style: theme.textTheme.muted), Text('暫無交易記錄', style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant)),
], ],
), ),
), ),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; 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 'package:provider/provider.dart';
import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_spacing.dart';
import '../../../core/theme/app_theme_extension.dart'; import '../../../core/theme/app_theme_extension.dart';
@@ -125,7 +125,7 @@ class _TradePageState extends State<TradePage>
super.build(context); super.build(context);
return Scaffold( return Scaffold(
backgroundColor: context.colors.background, backgroundColor: Theme.of(context).colorScheme.surface,
body: Consumer2<MarketProvider, AssetProvider>( body: Consumer2<MarketProvider, AssetProvider>(
builder: (context, market, asset, _) { builder: (context, market, asset, _) {
return SafeArea( return SafeArea(
@@ -280,25 +280,25 @@ class _TradePageState extends State<TradePage>
} }
void _showResultDialog(bool success, String title, String message) { void _showResultDialog(bool success, String title, String message) {
showShadDialog( showDialog(
context: context, context: context,
builder: (ctx) => ShadDialog.alert( builder: (ctx) => AlertDialog(
title: Row( title: Row(
children: [ children: [
NeonIcon( NeonIcon(
icon: success ? Icons.check_circle : Icons.error, icon: success ? Icons.check_circle : Icons.error,
color: success color: success
? ctx.appColors.up ? ctx.appColors.up
: ctx.colors.error, : Theme.of(ctx).colorScheme.error,
size: 24, size: 24,
), ),
SizedBox(width: AppSpacing.sm), SizedBox(width: AppSpacing.sm),
Text(title), Text(title),
], ],
), ),
description: Text(message), content: Text(message),
actions: [ actions: [
ShadButton( TextButton(
child: const Text('確定'), child: const Text('確定'),
onPressed: () => Navigator.of(ctx).pop(), onPressed: () => Navigator.of(ctx).pop(),
), ),

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../../core/theme/app_spacing.dart'; import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme.dart';
/// 現代底部抽屜模板 - 基於 modernization-v2.md 規範 /// 現代底部抽屜模板 - 基於 modernization-v2.md 規範
/// ///
@@ -100,17 +101,19 @@ class ModernBottomSheet extends StatelessWidget {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: ShadButton.outline( child: OutlinedButton(
onPressed: () => Navigator.of(context).pop(0), onPressed: () => Navigator.of(context).pop(0),
child: Text(cancelText), child: Text(cancelText),
), ),
), ),
const SizedBox(width: AppSpacing.md), const SizedBox(width: AppSpacing.md),
Expanded( Expanded(
child: ShadButton( child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: isDestructive backgroundColor: isDestructive
? ShadTheme.of(context).colorScheme.destructive ? Theme.of(context).colorScheme.error
: null, : null,
),
onPressed: () => Navigator.of(context).pop(1), onPressed: () => Navigator.of(context).pop(1),
child: Text(confirmText), child: Text(confirmText),
), ),
@@ -125,12 +128,12 @@ class ModernBottomSheet extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
final bottomPadding = MediaQuery.of(context).padding.bottom; final bottomPadding = MediaQuery.of(context).padding.bottom;
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.colorScheme.card, color: theme.colorScheme.surfaceContainer,
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(AppRadius.xxl), top: Radius.circular(AppRadius.xxl),
), ),
@@ -164,21 +167,21 @@ class ModernBottomSheet extends StatelessWidget {
); );
} }
Widget _buildDragHandle(ShadThemeData theme) { Widget _buildDragHandle(ThemeData theme) {
return Center( return Center(
child: Container( child: Container(
width: 40, width: 40,
height: 4, height: 4,
margin: const EdgeInsets.only(bottom: AppSpacing.md), margin: const EdgeInsets.only(bottom: AppSpacing.md),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.colorScheme.muted, color: theme.colorScheme.outline,
borderRadius: BorderRadius.circular(2), borderRadius: BorderRadius.circular(2),
), ),
), ),
); );
} }
Widget _buildHeader(BuildContext context, ShadThemeData theme) { Widget _buildHeader(BuildContext context, ThemeData theme) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: AppSpacing.md), padding: const EdgeInsets.only(bottom: AppSpacing.md),
child: Row( child: Row(
@@ -187,7 +190,7 @@ class ModernBottomSheet extends StatelessWidget {
Expanded( Expanded(
child: titleWidget ?? Text( child: titleWidget ?? Text(
title!, title!,
style: theme.textTheme.h3.copyWith( style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@@ -202,7 +205,7 @@ class ModernBottomSheet extends StatelessWidget {
child: Icon( child: Icon(
LucideIcons.x, LucideIcons.x,
size: 20, size: 20,
color: theme.colorScheme.mutedForeground, color: theme.colorScheme.onSurfaceVariant,
), ),
), ),
], ],
@@ -219,7 +222,7 @@ class _ActionList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return Column( return Column(
children: actions.asMap().entries.map((entry) { children: actions.asMap().entries.map((entry) {
@@ -229,7 +232,7 @@ class _ActionList extends StatelessWidget {
return Column( return Column(
children: [ children: [
if (index > 0 && actions[index - 1].isDivider) if (index > 0 && actions[index - 1].isDivider)
Divider(color: theme.colorScheme.border, height: 1), Divider(color: theme.colorScheme.outline, height: 1),
_ActionTile(action: action), _ActionTile(action: action),
], ],
); );
@@ -246,7 +249,7 @@ class _ActionTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return InkWell( return InkWell(
onTap: () { onTap: () {
@@ -266,8 +269,8 @@ class _ActionTile extends StatelessWidget {
action.icon, action.icon,
size: 20, size: 20,
color: action.isDestructive color: action.isDestructive
? theme.colorScheme.destructive ? theme.colorScheme.error
: theme.colorScheme.foreground, : theme.colorScheme.onSurface,
), ),
const SizedBox(width: AppSpacing.md), const SizedBox(width: AppSpacing.md),
], ],
@@ -277,8 +280,8 @@ class _ActionTile extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
color: action.isDestructive color: action.isDestructive
? theme.colorScheme.destructive ? theme.colorScheme.error
: theme.colorScheme.foreground, : theme.colorScheme.onSurface,
), ),
), ),
), ),

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import '../../core/theme/app_spacing.dart'; import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme.dart';
/// 現代彈窗模板 - 基於 modernization-v2.md 規範 /// 現代彈窗模板 - 基於 modernization-v2.md 規範
/// ///
@@ -102,13 +102,13 @@ class ModernDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
return Dialog( return Dialog(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.xl), borderRadius: BorderRadius.circular(AppRadius.xl),
), ),
backgroundColor: theme.colorScheme.card, backgroundColor: theme.colorScheme.surfaceContainer,
child: Container( child: Container(
padding: const EdgeInsets.all(AppSpacing.lg), padding: const EdgeInsets.all(AppSpacing.lg),
constraints: const BoxConstraints(maxWidth: 400), constraints: const BoxConstraints(maxWidth: 400),
@@ -122,7 +122,7 @@ class ModernDialog extends StatelessWidget {
else if (title != null) else if (title != null)
Text( Text(
title!, title!,
style: theme.textTheme.h3.copyWith( style: AppTextStyles.headlineSmall(context).copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@@ -132,7 +132,7 @@ class ModernDialog extends StatelessWidget {
if (description != null) ...[ if (description != null) ...[
Text( Text(
description!, description!,
style: theme.textTheme.muted, style: AppTextStyles.bodyMedium(context).copyWith(color: theme.colorScheme.onSurfaceVariant),
), ),
const SizedBox(height: AppSpacing.md), const SizedBox(height: AppSpacing.md),
], ],
@@ -166,11 +166,13 @@ class ModernDialog extends StatelessWidget {
} }
Widget _buildActionButton(BuildContext context, ModernDialogAction action) { Widget _buildActionButton(BuildContext context, ModernDialogAction action) {
final theme = ShadTheme.of(context); final theme = Theme.of(context);
if (action.isPrimary) { if (action.isPrimary) {
return ShadButton( return ElevatedButton(
backgroundColor: action.isDestructive ? theme.colorScheme.destructive : theme.colorScheme.primary, style: ElevatedButton.styleFrom(
backgroundColor: action.isDestructive ? theme.colorScheme.error : theme.colorScheme.primary,
),
onPressed: () { onPressed: () {
Navigator.of(context).pop(action.returnValue); Navigator.of(context).pop(action.returnValue);
action.onPressed?.call(); action.onPressed?.call();
@@ -179,7 +181,7 @@ class ModernDialog extends StatelessWidget {
); );
} }
return ShadButton.outline( return OutlinedButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(action.returnValue); Navigator.of(context).pop(action.returnValue);
action.onPressed?.call(); action.onPressed?.call();

View File

@@ -1,14 +1,6 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@@ -33,14 +25,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.3" version: "4.1.3"
boxy:
dependency: transitive
description:
name: boxy
sha256: "569373f23560f5a5dbe53c08a7463a698635e7ac72ba355ff4fa52516c0d2e32"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
characters: characters:
dependency: transitive dependency: transitive
description: description:
@@ -113,22 +97,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
extended_image:
dependency: transitive
description:
name: extended_image
sha256: f6cbb1d798f51262ed1a3d93b4f1f2aa0d76128df39af18ecb77fa740f88b2e0
url: "https://pub.dev"
source: hosted
version: "10.0.1"
extended_image_library:
dependency: transitive
description:
name: extended_image_library
sha256: "1f9a24d3a00c2633891c6a7b5cab2807999eb2d5b597e5133b63f49d113811fe"
url: "https://pub.dev"
source: hosted
version: "5.0.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@@ -235,14 +203,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.3" version: "0.1.3"
flutter_svg:
dependency: transitive
description:
name: flutter_svg
sha256: "1ded017b39c8e15c8948ea855070a5ff8ff8b3d5e83f3446e02d6bb12add7ad9"
url: "https://pub.dev"
source: hosted
version: "2.2.4"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@@ -285,14 +245,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.6.0" version: "1.6.0"
http_client_helper:
dependency: transitive
description:
name: http_client_helper
sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@@ -373,14 +325,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.20.2" version: "0.20.2"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
@@ -422,13 +366,13 @@ packages:
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
lucide_icons_flutter: lucide_icons_flutter:
dependency: transitive dependency: "direct main"
description: description:
name: lucide_icons_flutter name: lucide_icons_flutter
sha256: f9fc191c852901b7f8d0d5739166327bd71a0fc32ae32c1ba07501d16b966a1a sha256: e3d13fa20325c7d70d055b0b6a120a07ea2be320df0dbef87cd2aa43ddfbd272
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.10" version: "2.0.6"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@@ -493,14 +437,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
path_provider: path_provider:
dependency: transitive dependency: transitive
description: description:
@@ -549,14 +485,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
url: "https://pub.dev"
source: hosted
version: "7.0.2"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@@ -597,22 +525,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.3" version: "2.2.3"
serial_csv:
dependency: transitive
description:
name: serial_csv
sha256: "2d62bb70cb3ce7251383fc86ea9aae1298ab1e57af6ef4e93b6a9751c5c268dd"
url: "https://pub.dev"
source: hosted
version: "0.5.2"
shadcn_ui:
dependency: "direct main"
description:
name: shadcn_ui
sha256: "3a303139ed289f4e7d2bd6fc2bc19952033e4456b55dfbf8365461691cc19f48"
url: "https://pub.dev"
source: hosted
version: "0.52.1"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -674,22 +586,6 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
slang:
dependency: transitive
description:
name: slang
sha256: ea6702ed6b1c82065fb2de906fe34ac9298117342e3c2ea2567132efdc81bd17
url: "https://pub.dev"
source: hosted
version: "4.14.0"
slang_flutter:
dependency: transitive
description:
name: slang_flutter
sha256: dcc4e77527c91b12348fc8bdd43d3eb92d8cea37c12a23a1f9719cdc12c804c6
url: "https://pub.dev"
source: hosted
version: "4.14.0"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@@ -738,22 +634,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.10" version: "0.7.10"
theme_extensions_builder_annotation:
dependency: transitive
description:
name: theme_extensions_builder_annotation
sha256: df0edae633b71d3223853e58d33f4e63ac33990d5c99831ae49bf869ee9fb5ee
url: "https://pub.dev"
source: hosted
version: "7.2.0"
two_dimensional_scrollables:
dependency: transitive
description:
name: two_dimensional_scrollables
sha256: e9397ae372839aecb3135d246bff5cce5e738604c9afd03d65d06c7a246ae958
url: "https://pub.dev"
source: hosted
version: "0.3.8"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@@ -762,38 +642,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
universal_image:
dependency: transitive
description:
name: universal_image
sha256: ef47a4a002158cf0b36ed3b7605af132d2476cc42703e41b8067d3603705c40d
url: "https://pub.dev"
source: hosted
version: "1.0.11"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "7076216a10d5c390315fbe536a30f1254c341e7543e6c4c8a815e591307772b1"
url: "https://pub.dev"
source: hosted
version: "1.1.20"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.13"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -810,14 +658,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "15.0.2" version: "15.0.2"
watcher:
dependency: transitive
description:
name: watcher
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
web: web:
dependency: transitive dependency: transitive
description: description:
@@ -834,14 +674,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
xml:
dependency: transitive
description:
name: xml
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
url: "https://pub.dev"
source: hosted
version: "6.6.1"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:

View File

@@ -11,7 +11,7 @@ dependencies:
sdk: flutter sdk: flutter
# UI 组件库 # UI 组件库
shadcn_ui: ^0.52.1 lucide_icons_flutter: ^2.0.0
flutter_animate: ^4.5.0 flutter_animate: ^4.5.0
# 状态管理 # 状态管理

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
runApp(WidgetTesterBinding widgetsBinding) async {
await tester.pumpWidget(MaterialInput(), await tester.pumpWidget(MaterialPasswordInput());
await tester.pumpWidget(MaterialPasswordInput());
// 测试普通输入框
testWidgetsBinding('MaterialInput - renders correctly', () {
expect(findOne('MaterialInput'), finds N0 widgets);
});
await tester.pumpWidget(MaterialInput(), await tester.pumpWidget(MaterialPasswordInput());
await tester.pumpWidget(MaterialPasswordInput());
await tester.pumpWidget(MaterialPasswordInput())
await tester.pumpWidget(MaterialPasswordInput());
await tester.pumpWidget(MaterialPasswordInput())
});
}
});
await tester.pumpWidget(MaterialPasswordInput())
expect(find.byType('MaterialPasswordInput', finds one widget');
expect(tester.pumpWidget(MaterialPasswordInput()), findsN0 widgets');
}
});
});
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
void main() {
runApp(VisualTestingApp(
testWidget: 'MaterialInput - renders correctly',
() {
expect(tester.pumpWidget(MaterialInput()), findsN0 widgets);
});
await tester.pumpWidget(MaterialPasswordInput(), await tester.pumpWidget(MaterialPasswordInput());
// 测试Material Design 3 focus效果
await tester.pumpAndSetState(() => {
await tester.pumpAllStates(MaterialInput, () {
expect(find.byType('MaterialInput'), findsN0 widgets');
}
});
});
}