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,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)
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,15 +179,16 @@ 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(
|
||||||
padding: const EdgeInsets.all(AppSpacing.md),
|
child: Padding(
|
||||||
child: InkWell(
|
padding: const EdgeInsets.all(AppSpacing.md),
|
||||||
onTap: onTap,
|
child: InkWell(
|
||||||
child: Row(
|
onTap: onTap,
|
||||||
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -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 {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,11 +31,12 @@ 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(
|
||||||
padding: const EdgeInsets.all(AppSpacing.md),
|
child: Padding(
|
||||||
child: InkWell(
|
padding: const EdgeInsets.all(AppSpacing.md),
|
||||||
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -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 {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,22 +178,21 @@ 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,
|
labelText: '充值金額',
|
||||||
label: const Text('充值金額'),
|
hintText: '最低 1000 USDT',
|
||||||
placeholder: const Text('最低 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 '請輸入金額';
|
final n = double.tryParse(v);
|
||||||
final n = double.tryParse(v);
|
if (n == null || n <= 0) return '請輸入有效金額';
|
||||||
if (n == null || n <= 0) return '請輸入有效金額';
|
if (n < 1000) return '單筆最低充值1000 USDT';
|
||||||
if (n < 1000) return '單筆最低充值1000 USDT';
|
return null;
|
||||||
return null;
|
},
|
||||||
},
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: AppSpacing.lg),
|
const SizedBox(height: AppSpacing.lg),
|
||||||
Row(
|
Row(
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,9 +92,10 @@ class _FundOrderCard extends StatelessWidget {
|
|||||||
? order.receivableAmount
|
? order.receivableAmount
|
||||||
: order.amount;
|
: order.amount;
|
||||||
|
|
||||||
return ShadCard(
|
return Card(
|
||||||
padding: AppSpacing.cardPadding,
|
child: Padding(
|
||||||
child: Column(
|
padding: AppSpacing.cardPadding,
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@@ -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 {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,13 +155,14 @@ 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(
|
||||||
padding: AppSpacing.cardPadding,
|
child: Padding(
|
||||||
child: Column(
|
padding: AppSpacing.cardPadding,
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@@ -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 {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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(
|
||||||
backgroundColor: isDestructive
|
style: ElevatedButton.styleFrom(
|
||||||
? ShadTheme.of(context).colorScheme.destructive
|
backgroundColor: isDestructive
|
||||||
: null,
|
? Theme.of(context).colorScheme.error
|
||||||
|
: 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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
# 状态管理
|
# 状态管理
|
||||||
|
|||||||
29
flutter_monisuo/test/input_test.dart
Normal file
29
flutter_monisuo/test/input_test.dart
Normal 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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
19
flutter_monisuo/test/input_visual_test.dart
Normal file
19
flutter_monisuo/test/input_visual_test.dart
Normal 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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user