332 lines
12 KiB
Dart
332 lines
12 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../../../app/theme/app_colors.dart';
|
|
import '../../../../app/theme/app_typography.dart';
|
|
import '../../../../app/theme/app_spacing.dart';
|
|
import '../../../../app/i18n/app_localizations.dart';
|
|
import '../../../../app/i18n/locale_manager.dart';
|
|
|
|
/// 设置页面
|
|
///
|
|
/// 账号安全、通知、支付管理、语言、货币、关于
|
|
/// 货币选择影响交易页面中的计价货币符号
|
|
class SettingsPage extends StatefulWidget {
|
|
const SettingsPage({super.key});
|
|
|
|
@override
|
|
State<SettingsPage> createState() => _SettingsPageState();
|
|
}
|
|
|
|
class _SettingsPageState extends State<SettingsPage> {
|
|
_CurrencyOption _selectedCurrency = _currencyOptions[0];
|
|
|
|
bool _notifyTrade = true;
|
|
bool _notifyExpiry = true;
|
|
bool _notifyMarket = false;
|
|
bool _notifyMarketing = false;
|
|
|
|
String get _currentLanguageDisplay {
|
|
final locale = LocaleManager.userLocale.value ??
|
|
Localizations.localeOf(context);
|
|
return LocaleManager.localeDisplayName(locale);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: Text(context.t('settings.title'))),
|
|
body: ListView(
|
|
children: [
|
|
_buildSection(context.t('settings.accountSecurity'), [
|
|
_buildTile(context.t('settings.phone'),
|
|
subtitle: '138****8888', icon: Icons.phone_rounded),
|
|
_buildTile(context.t('settings.email'),
|
|
subtitle: 'u***@email.com', icon: Icons.email_rounded),
|
|
_buildTile(context.t('settings.changePassword'),
|
|
icon: Icons.lock_rounded),
|
|
_buildTile(context.t('settings.identity'),
|
|
subtitle: 'L1',
|
|
icon: Icons.verified_user_rounded, onTap: () {
|
|
Navigator.pushNamed(context, '/kyc');
|
|
}),
|
|
]),
|
|
|
|
_buildSection(context.t('settings.paymentManage'), [
|
|
_buildTile(context.t('settings.paymentMethod'),
|
|
subtitle: 'Visa •••• 4242',
|
|
icon: Icons.credit_card_rounded),
|
|
_buildTile(context.t('settings.bankAccount'),
|
|
subtitle: 'BoA •••• 6789',
|
|
icon: Icons.account_balance_rounded),
|
|
_buildTile(context.t('settings.paymentPassword'),
|
|
icon: Icons.password_rounded),
|
|
]),
|
|
|
|
_buildSection(context.t('settings.notifications'), [
|
|
_buildSwitchTile(context.t('settings.tradeNotify'), _notifyTrade,
|
|
(v) => setState(() => _notifyTrade = v)),
|
|
_buildSwitchTile(context.t('settings.expiryRemind'), _notifyExpiry,
|
|
(v) => setState(() => _notifyExpiry = v)),
|
|
_buildSwitchTile(context.t('settings.marketChange'), _notifyMarket,
|
|
(v) => setState(() => _notifyMarket = v)),
|
|
_buildSwitchTile(
|
|
context.t('settings.marketingPush'), _notifyMarketing,
|
|
(v) => setState(() => _notifyMarketing = v)),
|
|
]),
|
|
|
|
_buildSection(context.t('settings.general'), [
|
|
_buildTile(context.t('settings.language'),
|
|
subtitle: _currentLanguageDisplay,
|
|
icon: Icons.language_rounded,
|
|
onTap: () => _showLanguagePicker(context)),
|
|
_buildTile(context.t('settings.currency'),
|
|
subtitle:
|
|
'${_selectedCurrency.code} (${_selectedCurrency.symbol})',
|
|
icon: Icons.attach_money_rounded,
|
|
onTap: () => _showCurrencyPicker(context)),
|
|
_buildTile(context.t('settings.clearCache'),
|
|
icon: Icons.cleaning_services_rounded),
|
|
]),
|
|
|
|
_buildSection(context.t('settings.about'), [
|
|
_buildTile(context.t('settings.version'),
|
|
subtitle: 'v1.0.0', icon: Icons.info_outline_rounded),
|
|
_buildTile(context.t('settings.userAgreement'),
|
|
icon: Icons.description_rounded),
|
|
_buildTile(context.t('settings.privacyPolicy'),
|
|
icon: Icons.privacy_tip_rounded),
|
|
_buildTile(context.t('settings.helpCenter'),
|
|
icon: Icons.help_outline_rounded),
|
|
]),
|
|
|
|
Padding(
|
|
padding: const EdgeInsets.all(20),
|
|
child: OutlinedButton(
|
|
onPressed: () {
|
|
Navigator.of(context)
|
|
.pushNamedAndRemoveUntil('/', (_) => false);
|
|
},
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: AppColors.error,
|
|
side: const BorderSide(color: AppColors.error),
|
|
minimumSize: const Size(double.infinity, 48),
|
|
),
|
|
child: Text(context.t('settings.logout')),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
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: [
|
|
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(context.t('settings.selectCurrency'),
|
|
style: AppTypography.h3),
|
|
),
|
|
const Divider(height: 1),
|
|
..._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(
|
|
'${context.t('settings.currencySymbol')}: ${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);
|
|
},
|
|
);
|
|
}),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 24),
|
|
child: Text(
|
|
context.t('settings.currencyNote'),
|
|
style: AppTypography.caption.copyWith(
|
|
color: AppColors.textTertiary,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showLanguagePicker(BuildContext context) {
|
|
final languages = [
|
|
('简体中文', const Locale('zh', 'CN'), '🇨🇳'),
|
|
('繁體中文', const Locale('zh', 'TW'), '🇹🇼'),
|
|
('English', const Locale('en'), '🇺🇸'),
|
|
('日本語', const Locale('ja'), '🇯🇵'),
|
|
];
|
|
|
|
final currentLocale = LocaleManager.userLocale.value ??
|
|
Localizations.localeOf(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: [
|
|
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(context.t('settings.selectLanguage'),
|
|
style: AppTypography.h3),
|
|
),
|
|
const Divider(height: 1),
|
|
...languages.map((lang) {
|
|
final (name, locale, flag) = lang;
|
|
final isSelected =
|
|
currentLocale.languageCode == locale.languageCode &&
|
|
(locale.countryCode == null ||
|
|
currentLocale.countryCode == locale.countryCode);
|
|
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: () {
|
|
LocaleManager.userLocale.value = locale;
|
|
setState(() {});
|
|
Navigator.pop(context);
|
|
},
|
|
);
|
|
}),
|
|
const SizedBox(height: 24),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildSection(String title, List<Widget> children) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(20, 20, 20, 8),
|
|
child: Text(title, style: AppTypography.labelSmall),
|
|
),
|
|
Container(
|
|
color: AppColors.surface,
|
|
child: Column(children: children),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildTile(String title,
|
|
{String? subtitle, IconData? icon, VoidCallback? onTap}) {
|
|
return ListTile(
|
|
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),
|
|
onTap: onTap ?? () {},
|
|
);
|
|
}
|
|
|
|
Widget _buildSwitchTile(
|
|
String title, bool value, ValueChanged<bool> onChanged) {
|
|
return SwitchListTile(
|
|
title: Text(title, style: AppTypography.bodyMedium),
|
|
value: value,
|
|
onChanged: onChanged,
|
|
activeColor: AppColors.primary,
|
|
);
|
|
}
|
|
}
|
|
|
|
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: 'USD', flag: '🇺🇸'),
|
|
_CurrencyOption(code: 'CNY', symbol: '¥', name: 'CNY', flag: '🇨🇳'),
|
|
_CurrencyOption(code: 'EUR', symbol: '€', name: 'EUR', flag: '🇪🇺'),
|
|
_CurrencyOption(code: 'GBP', symbol: '£', name: 'GBP', flag: '🇬🇧'),
|
|
_CurrencyOption(code: 'JPY', symbol: '¥', name: 'JPY', flag: '🇯🇵'),
|
|
_CurrencyOption(code: 'HKD', symbol: 'HK\$', name: 'HKD', flag: '🇭🇰'),
|
|
];
|