feat: 设置页面新增货币选择器和语言选择器
- 设置页面从StatelessWidget改为StatefulWidget - 新增货币选择器bottom sheet,支持USD/CNY/EUR/GBP/JPY/HKD - 新增语言选择器bottom sheet,支持简体中文/繁體中文/English/日本語 - 通知开关改为可交互状态 - 货币subtitle动态显示已选货币代码和符号 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
003b571f94
commit
b639e8c823
|
|
@ -1,13 +1,30 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import '../../../../app/theme/app_colors.dart';
|
||||
import '../../../../app/theme/app_typography.dart';
|
||||
import '../../../../app/theme/app_spacing.dart';
|
||||
|
||||
/// 设置页面
|
||||
///
|
||||
/// 账号安全、通知、支付管理、语言、关于
|
||||
class SettingsPage extends StatelessWidget {
|
||||
/// 账号安全、通知、支付管理、语言、货币、关于
|
||||
/// 货币选择影响交易页面中的计价货币符号
|
||||
class SettingsPage extends StatefulWidget {
|
||||
const SettingsPage({super.key});
|
||||
|
||||
@override
|
||||
State<SettingsPage> createState() => _SettingsPageState();
|
||||
}
|
||||
|
||||
class _SettingsPageState extends State<SettingsPage> {
|
||||
// 当前选中的货币 (实际应用中从持久化/状态管理读取)
|
||||
_CurrencyOption _selectedCurrency = _currencyOptions[0]; // 默认 USD
|
||||
String _selectedLanguage = '简体中文';
|
||||
|
||||
// 通知开关
|
||||
bool _notifyTrade = true;
|
||||
bool _notifyExpiry = true;
|
||||
bool _notifyMarket = false;
|
||||
bool _notifyMarketing = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
|
@ -16,39 +33,59 @@ class SettingsPage extends StatelessWidget {
|
|||
children: [
|
||||
// Account & Security
|
||||
_buildSection('账号与安全', [
|
||||
_buildTile('手机号', subtitle: '138****8888', icon: Icons.phone_rounded),
|
||||
_buildTile('邮箱', subtitle: 'u***@email.com', icon: Icons.email_rounded),
|
||||
_buildTile('手机号',
|
||||
subtitle: '138****8888', icon: Icons.phone_rounded),
|
||||
_buildTile('邮箱',
|
||||
subtitle: 'u***@email.com', icon: Icons.email_rounded),
|
||||
_buildTile('修改密码', icon: Icons.lock_rounded),
|
||||
_buildTile('身份认证', subtitle: 'L1 基础认证', icon: Icons.verified_user_rounded, onTap: () {
|
||||
_buildTile('身份认证',
|
||||
subtitle: 'L1 基础认证',
|
||||
icon: Icons.verified_user_rounded, onTap: () {
|
||||
Navigator.pushNamed(context, '/kyc');
|
||||
}),
|
||||
]),
|
||||
|
||||
// Payment
|
||||
_buildSection('支付管理', [
|
||||
_buildTile('支付方式', subtitle: 'Visa •••• 4242', icon: Icons.credit_card_rounded),
|
||||
_buildTile('银行账户', subtitle: 'BoA •••• 6789', icon: Icons.account_balance_rounded),
|
||||
_buildTile('支付方式',
|
||||
subtitle: 'Visa •••• 4242',
|
||||
icon: Icons.credit_card_rounded),
|
||||
_buildTile('银行账户',
|
||||
subtitle: 'BoA •••• 6789',
|
||||
icon: Icons.account_balance_rounded),
|
||||
_buildTile('支付密码', icon: Icons.password_rounded),
|
||||
]),
|
||||
|
||||
// Notifications
|
||||
_buildSection('通知设置', [
|
||||
_buildSwitchTile('交易通知', true),
|
||||
_buildSwitchTile('到期提醒', true),
|
||||
_buildSwitchTile('行情变动', false),
|
||||
_buildSwitchTile('营销推送', false),
|
||||
_buildSwitchTile('交易通知', _notifyTrade,
|
||||
(v) => setState(() => _notifyTrade = v)),
|
||||
_buildSwitchTile('到期提醒', _notifyExpiry,
|
||||
(v) => setState(() => _notifyExpiry = v)),
|
||||
_buildSwitchTile('行情变动', _notifyMarket,
|
||||
(v) => setState(() => _notifyMarket = v)),
|
||||
_buildSwitchTile('营销推送', _notifyMarketing,
|
||||
(v) => setState(() => _notifyMarketing = v)),
|
||||
]),
|
||||
|
||||
// General
|
||||
_buildSection('通用', [
|
||||
_buildTile('语言', subtitle: '简体中文', icon: Icons.language_rounded),
|
||||
_buildTile('货币', subtitle: 'USD', icon: Icons.attach_money_rounded),
|
||||
_buildTile('语言',
|
||||
subtitle: _selectedLanguage,
|
||||
icon: Icons.language_rounded,
|
||||
onTap: () => _showLanguagePicker(context)),
|
||||
_buildTile('货币',
|
||||
subtitle:
|
||||
'${_selectedCurrency.code} (${_selectedCurrency.symbol})',
|
||||
icon: Icons.attach_money_rounded,
|
||||
onTap: () => _showCurrencyPicker(context)),
|
||||
_buildTile('清除缓存', icon: Icons.cleaning_services_rounded),
|
||||
]),
|
||||
|
||||
// About
|
||||
_buildSection('关于', [
|
||||
_buildTile('版本', subtitle: 'v1.0.0', icon: Icons.info_outline_rounded),
|
||||
_buildTile('版本',
|
||||
subtitle: 'v1.0.0', icon: Icons.info_outline_rounded),
|
||||
_buildTile('用户协议', icon: Icons.description_rounded),
|
||||
_buildTile('隐私政策', icon: Icons.privacy_tip_rounded),
|
||||
_buildTile('帮助中心', icon: Icons.help_outline_rounded),
|
||||
|
|
@ -59,7 +96,8 @@ class SettingsPage extends StatelessWidget {
|
|||
padding: const EdgeInsets.all(20),
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (_) => false);
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil('/', (_) => false);
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: AppColors.error,
|
||||
|
|
@ -74,6 +112,152 @@ class SettingsPage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Currency Picker
|
||||
// ============================================================
|
||||
void _showCurrencyPicker(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (_) => Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.surface,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Handle
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 12),
|
||||
width: 36,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.gray200,
|
||||
borderRadius: AppSpacing.borderRadiusFull,
|
||||
),
|
||||
),
|
||||
// Title
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text('选择计价货币', style: AppTypography.h3),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
// Currency list
|
||||
..._currencyOptions.map((option) {
|
||||
final isSelected = _selectedCurrency.code == option.code;
|
||||
return ListTile(
|
||||
leading: Text(option.flag, style: const TextStyle(fontSize: 24)),
|
||||
title: Text(
|
||||
'${option.name} (${option.code})',
|
||||
style: AppTypography.bodyMedium.copyWith(
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
|
||||
color: isSelected
|
||||
? AppColors.primary
|
||||
: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
'符号: ${option.symbol}',
|
||||
style: AppTypography.caption,
|
||||
),
|
||||
trailing: isSelected
|
||||
? const Icon(Icons.check_circle_rounded,
|
||||
color: AppColors.primary, size: 22)
|
||||
: null,
|
||||
onTap: () {
|
||||
setState(() => _selectedCurrency = option);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
}),
|
||||
// Note
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 24),
|
||||
child: Text(
|
||||
'此设置影响交易页面中所有价格的计价货币显示',
|
||||
style: AppTypography.caption.copyWith(
|
||||
color: AppColors.textTertiary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Language Picker
|
||||
// ============================================================
|
||||
void _showLanguagePicker(BuildContext context) {
|
||||
final languages = [
|
||||
('简体中文', 'zh-CN', '🇨🇳'),
|
||||
('繁體中文', 'zh-TW', '🇹🇼'),
|
||||
('English', 'en', '🇺🇸'),
|
||||
('日本語', 'ja', '🇯🇵'),
|
||||
];
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (_) => Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.surface,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 12),
|
||||
width: 36,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.gray200,
|
||||
borderRadius: AppSpacing.borderRadiusFull,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text('选择语言', style: AppTypography.h3),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
...languages.map((lang) {
|
||||
final (name, _, flag) = lang;
|
||||
final isSelected = _selectedLanguage == name;
|
||||
return ListTile(
|
||||
leading: Text(flag, style: const TextStyle(fontSize: 24)),
|
||||
title: Text(
|
||||
name,
|
||||
style: AppTypography.bodyMedium.copyWith(
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
|
||||
color: isSelected
|
||||
? AppColors.primary
|
||||
: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
trailing: isSelected
|
||||
? const Icon(Icons.check_circle_rounded,
|
||||
color: AppColors.primary, size: 22)
|
||||
: null,
|
||||
onTap: () {
|
||||
setState(() => _selectedLanguage = name);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
}),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Shared Builders
|
||||
// ============================================================
|
||||
Widget _buildSection(String title, List<Widget> children) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -90,22 +274,55 @@ class SettingsPage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildTile(String title, {String? subtitle, IconData? icon, VoidCallback? onTap}) {
|
||||
Widget _buildTile(String title,
|
||||
{String? subtitle, IconData? icon, VoidCallback? onTap}) {
|
||||
return ListTile(
|
||||
leading: icon != null ? Icon(icon, size: 22, color: AppColors.textSecondary) : null,
|
||||
leading: icon != null
|
||||
? Icon(icon, size: 22, color: AppColors.textSecondary)
|
||||
: null,
|
||||
title: Text(title, style: AppTypography.bodyMedium),
|
||||
subtitle: subtitle != null ? Text(subtitle, style: AppTypography.caption) : null,
|
||||
trailing: const Icon(Icons.chevron_right_rounded, size: 20, color: AppColors.textTertiary),
|
||||
subtitle: subtitle != null
|
||||
? Text(subtitle, style: AppTypography.caption)
|
||||
: null,
|
||||
trailing: const Icon(Icons.chevron_right_rounded,
|
||||
size: 20, color: AppColors.textTertiary),
|
||||
onTap: onTap ?? () {},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSwitchTile(String title, bool value) {
|
||||
Widget _buildSwitchTile(
|
||||
String title, bool value, ValueChanged<bool> onChanged) {
|
||||
return SwitchListTile(
|
||||
title: Text(title, style: AppTypography.bodyMedium),
|
||||
value: value,
|
||||
onChanged: (_) {},
|
||||
onChanged: onChanged,
|
||||
activeColor: AppColors.primary,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Currency Options
|
||||
// ============================================================
|
||||
class _CurrencyOption {
|
||||
final String code;
|
||||
final String symbol;
|
||||
final String name;
|
||||
final String flag;
|
||||
|
||||
const _CurrencyOption({
|
||||
required this.code,
|
||||
required this.symbol,
|
||||
required this.name,
|
||||
required this.flag,
|
||||
});
|
||||
}
|
||||
|
||||
const _currencyOptions = [
|
||||
_CurrencyOption(code: 'USD', symbol: '\$', name: '美元', flag: '🇺🇸'),
|
||||
_CurrencyOption(code: 'CNY', symbol: '¥', name: '人民币', flag: '🇨🇳'),
|
||||
_CurrencyOption(code: 'EUR', symbol: '€', name: '欧元', flag: '🇪🇺'),
|
||||
_CurrencyOption(code: 'GBP', symbol: '£', name: '英镑', flag: '🇬🇧'),
|
||||
_CurrencyOption(code: 'JPY', symbol: '¥', name: '日元', flag: '🇯🇵'),
|
||||
_CurrencyOption(code: 'HKD', symbol: 'HK\$', name: '港币', flag: '🇭🇰'),
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in New Issue