import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/l10n/app_localizations.dart'; import '../../../core/theme/app_colors.dart'; import '../../../data/models/asset/account_auth.dart'; import '../../../providers/security_provider.dart'; class SecurityScreen extends ConsumerWidget { const SecurityScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final cs = Theme.of(context).colorScheme; final authAsync = ref.watch(securityAuthProvider); return Scaffold( appBar: AppBar( elevation: 0, leading: IconButton( icon: const Icon(Icons.chevron_left, size: 28), onPressed: () => context.pop(), ), title: Text( AppLocalizations.of(context)!.securitySettingsTitle, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), ), centerTitle: true, ), body: authAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(AppLocalizations.of(context)!.loadFailed, style: TextStyle(color: cs.onSurface)), const SizedBox(height: 12), ElevatedButton( onPressed: () => ref.read(securityAuthProvider.notifier).refresh(), child: Text(AppLocalizations.of(context)!.retry), ), ], ), ), data: (auth) => _SecurityBody(auth: auth), ), ); } } // ── 安全设置主体 ───────────────────────────────────────────── class _SecurityBody extends ConsumerWidget { const _SecurityBody({required this.auth}); final AccountAuth auth; @override Widget build(BuildContext context, WidgetRef ref) { final cs = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; return Column( children: [ // ── 安全提示 ───────────────────────────────────── const _WarningBanner(), const SizedBox(height: 16), // ── 安全选项列表 ────────────────────────────────── Container( margin: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary, borderRadius: BorderRadius.circular(12), ), child: Column( children: [ // 谷歌认证 _SecurityItem( icon: Icons.lock_outline, title: AppLocalizations.of(context)!.authenticator, subtitle: AppLocalizations.of(context)!.authenticatorDesc, statusLabel: auth.isGoogleVerified ? AppLocalizations.of(context)!.certified : AppLocalizations.of(context)!.notCertified, statusColor: auth.isGoogleVerified ? AppColors.rise : AppColors.fall, onTap: () async { if (auth.isGoogleVerified) { // 已绑定 → 提示联系客服 _showContactDialog(context); } else { // 未绑定 → 进入绑定流程 await context.push('/user/security/google-auth'); // 返回后刷新状态 ref.read(securityAuthProvider.notifier).refresh(); } }, ), _divider(cs), // 邮箱认证 _SecurityItem( icon: Icons.mail_outline, title: AppLocalizations.of(context)!.emailAuth, subtitle: auth.email.isNotEmpty ? auth.maskedEmail : AppLocalizations.of(context)!.emailAuthDesc, statusLabel: auth.email.isNotEmpty ? AppLocalizations.of(context)!.certified : AppLocalizations.of(context)!.notCertified, statusColor: auth.email.isNotEmpty ? AppColors.rise : AppColors.fall, onTap: () {}, ), _divider(cs), // 资金密码 _SecurityItem( icon: Icons.vpn_key_outlined, title: AppLocalizations.of(context)!.fundPassword, subtitle: AppLocalizations.of(context)!.fundPasswordDesc, statusLabel: auth.isFundsVerified ? AppLocalizations.of(context)!.modifyAction : AppLocalizations.of(context)!.notSet, statusColor: auth.isFundsVerified ? AppColors.rise : AppColors.fall, onTap: () async { // fundsVerified=="1" → 修改模式,否则 → 首次设置 await context.push( '/user/security/fund-password', extra: auth.isFundsVerified, ); ref.read(securityAuthProvider.notifier).refresh(); }, ), _divider(cs), // 登录密码 _SecurityItem( icon: Icons.lock_outline, title: AppLocalizations.of(context)!.loginPasswordMenu, subtitle: AppLocalizations.of(context)!.loginPasswordDesc, statusLabel: auth.isLoginVerified ? AppLocalizations.of(context)!.alreadySet : AppLocalizations.of(context)!.notSet, statusColor: auth.isLoginVerified ? AppColors.rise : AppColors.fall, onTap: () async { await context.push('/user/security/change-password'); ref.read(securityAuthProvider.notifier).refresh(); }, isLast: true, ), ], ), ), ], ); } void _showContactDialog(BuildContext context) { final cs = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; showDialog( context: context, builder: (ctx) => Dialog( backgroundColor: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.fromLTRB(24, 28, 24, 20), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 48, height: 48, decoration: BoxDecoration( color: AppColors.brand.withAlpha(30), shape: BoxShape.circle, ), child: const Icon(Icons.headset_mic_outlined, color: AppColors.brand, size: 24), ), const SizedBox(height: 16), Text( AppLocalizations.of(context)!.hintTitle, style: TextStyle( color: cs.onSurface, fontSize: 17, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 10), Text( AppLocalizations.of(context)!.contactServiceHint, textAlign: TextAlign.center, style: TextStyle( color: cs.onSurface.withAlpha(180), fontSize: 14, height: 1.5, ), ), const SizedBox(height: 24), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () => Navigator.of(ctx).pop(), style: ElevatedButton.styleFrom( backgroundColor: AppColors.brand, foregroundColor: Colors.black, elevation: 0, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: Text(AppLocalizations.of(context)!.gotIt, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600)), ), ), ], ), ), ), ); } Widget _divider(ColorScheme cs) => Divider( height: 1, indent: 52, color: cs.outline, ); } // ── 安全提示横幅 ───────────────────────────────────────────── class _WarningBanner extends StatelessWidget { const _WarningBanner(); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.fromLTRB(16, 16, 16, 0), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( color: const Color(0xFF2D2500), border: Border.all(color: const Color(0xFF4A3A00), width: 1), borderRadius: BorderRadius.circular(10), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon(Icons.info_outline, color: AppColors.brand, size: 16), const SizedBox(width: 8), Expanded( child: Text( AppLocalizations.of(context)!.securityBannerTip, style: const TextStyle(color: AppColors.brand, fontSize: 13), ), ), ], ), ); } } // ── 安全选项行 ─────────────────────────────────────────────── class _SecurityItem extends StatelessWidget { const _SecurityItem({ required this.icon, required this.title, required this.subtitle, required this.onTap, this.statusLabel, this.statusColor, this.isLast = false, }); final IconData icon; final String title; final String subtitle; final VoidCallback onTap; final String? statusLabel; final Color? statusColor; final bool isLast; @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; return InkWell( onTap: onTap, borderRadius: isLast ? const BorderRadius.vertical(bottom: Radius.circular(12)) : BorderRadius.zero, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( children: [ Container( width: 36, height: 36, decoration: BoxDecoration( color: cs.outline.withAlpha(30), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, size: 18, color: cs.onSurface.withAlpha(153)), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( color: cs.onSurface, fontSize: 14, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( subtitle, style: TextStyle( color: cs.onSurface.withAlpha(153), fontSize: 12, ), ), ], ), ), if (statusLabel != null) ...[ Text( statusLabel!, style: TextStyle( color: statusColor, fontSize: 13, fontWeight: FontWeight.w500, ), ), const SizedBox(width: 4), ], Icon(Icons.chevron_right, size: 18, color: cs.onSurface.withAlpha(153)), ], ), ), ); } }