import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:url_launcher/url_launcher_string.dart'; import '../../../common/config/app_h5_urls.dart'; import '../../../common/router/app_router.dart'; import '../../../common/widgets/prototype_ui.dart'; import '../../auth/application/auth_controller.dart'; import '../../auth/data/auth_models.dart'; import '../application/profile_settings_controller.dart'; import '../data/profile_models.dart'; class ProfilePage extends ConsumerWidget { const ProfilePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final settings = ref.watch(profileSettingsControllerProvider); final auth = ref.watch(authProvider); final cs = ShadTheme.of(context).colorScheme; final loggedIn = auth.valueOrNull is LoggedInAuthState; final currentUser = auth.valueOrNull is LoggedInAuthState ? (auth.valueOrNull as LoggedInAuthState).user : null; return SafeArea( top: false, child: ListView( padding: const EdgeInsets.fromLTRB(0, 8, 0, 86), children: [ PrototypeFrame( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( '我的', style: TextStyle(fontSize: 17, fontWeight: FontWeight.w600), ), const SizedBox(height: 14), PrototypeCard( child: Row( children: [ Container( width: 46, height: 46, decoration: BoxDecoration( color: const Color(0xFFF1EFE9), borderRadius: BorderRadius.circular(999), ), child: const Icon( Icons.person_outline, color: Color(0xFF9A968D), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( currentUser?.nickname ?? '未登录', style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 4), Text( currentUser?.phone ?? '登录后可云备份、多端同步', style: TextStyle( fontSize: 12, color: cs.mutedForeground, ), ), ], ), ), if (!loggedIn) FilledButton( onPressed: () => context.push(AppRoutes.login), style: FilledButton.styleFrom( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 10, ), minimumSize: Size.zero, ), child: Text('登录'), ), ], ), ), const SizedBox(height: 12), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ _MenuRow( title: '邀请好友,各得奖励', subtitle: '需登录', icon: Icons.card_giftcard_outlined, backgroundColor: const Color(0xFFF6ECD6), iconColor: const Color(0xFFB5862A), onTap: () => _showInviteSheet(context), ), const PrototypeDivider(margin: EdgeInsets.zero), _MenuRow( title: '分享我的贵金属估值卡', subtitle: '免登录 · 自动打码金额', icon: Icons.share_outlined, backgroundColor: const Color(0xFFEAF1FF), iconColor: const Color(0xFF4F7DD1), onTap: () => _showShareCardSheet(context, currentUser?.nickname), ), ], ), ), const SizedBox(height: 12), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ _SettingRow( icon: Icons.download_outlined, title: '本地导出备份', trailing: '导出', onTap: () => _showLocalBackupSheet(context), backgroundColor: const Color(0xFFF3EFE7), iconColor: const Color(0xFF8A8780), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.cloud_outlined, title: '云备份 · 多端同步', trailing: loggedIn ? '已登录' : '登录解锁', onTap: () => _showCloudBackupSheet(context, loggedIn), backgroundColor: const Color(0xFFEAF2ED), iconColor: const Color(0xFF5E8E75), ), ], ), ), const SizedBox(height: 12), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ _SettingRow( icon: Icons.grid_view_outlined, title: '添加桌面小组件', trailing: '占位', onTap: () => _showWidgetSheet(context), backgroundColor: const Color(0xFFF6ECD6), iconColor: const Color(0xFFB5862A), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.tune_outlined, title: '纯度系数管理', trailing: '${settings.purityPresets.length} 项', onTap: () => _showPuritySheet(context, settings), backgroundColor: const Color(0xFFF4EAF8), iconColor: const Color(0xFF8A5CBF), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.percent_outlined, title: '回收折扣设置', trailing: '金 ${(settings.recycleDiscounts.values.first * 100).toStringAsFixed(0)}%', onTap: () => _showRecycleSheet(context, settings), backgroundColor: const Color(0xFFF8EFE0), iconColor: const Color(0xFFB07A32), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.palette_outlined, title: '涨跌颜色', trailing: settings.priceColorMode.label, onTap: () => _showPriceColorSheet(context, ref), backgroundColor: const Color(0xFFE9F3F1), iconColor: const Color(0xFF4E8B7B), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.currency_yen_outlined, title: '显示币种', trailing: '¥ CNY', onTap: () => _showCurrencySheet(context), backgroundColor: const Color(0xFFF1EFE9), iconColor: const Color(0xFF7F7A73), ), ], ), ), const SizedBox(height: 12), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ _SettingRow( icon: Icons.settings, title: '设置', trailing: null, onTap: () => context.push(AppRoutes.settings), backgroundColor: const Color(0xFFF1EFE9), iconColor: const Color(0xFF7F7A73), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.privacy_tip_outlined, title: '隐私政策 · 用户协议', trailing: null, onTap: () => launchUrlString( AppH5UrlsHelper.withCacheBuster( AppH5Urls.userProtocolUrl, ), mode: LaunchMode.inAppBrowserView, ), backgroundColor: const Color(0xFFF1EFE9), iconColor: const Color(0xFF7F7A73), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.info_outline, title: '免责声明 · 数据来源', trailing: null, onTap: () => _showDisclaimer(context), backgroundColor: const Color(0xFFF7F0E2), iconColor: const Color(0xFFB07A32), ), const PrototypeDivider(margin: EdgeInsets.zero), _SettingRow( icon: Icons.feedback_outlined, title: '意见反馈 · 关于金值', trailing: null, onTap: () => _showAbout(context), backgroundColor: const Color(0xFFEAF1FF), iconColor: const Color(0xFF4F7DD1), ), ], ), ), const SizedBox(height: 14), PrototypeCard( child: Text( '风险提示 · 数据来源 · 免责\n金值是贵金属资产记录与估值工具,所有信息不构成投资建议。\n· 行情 / 兑换价格均为参考,标注来源与更新时间,实际以交易系统 / 门店为准。\n· 材料价值 = 克重 × 纯度系数 × 上海金现货,非金店零售价(含工费 / 品牌溢价)、非回收实收价。\n· 资讯为信息整理,非投资建议;历史走势不代表未来。', style: TextStyle( color: cs.mutedForeground, height: 1.7, fontSize: 12, ), ), ), ], ), ), ], ), ); } void _showDisclaimer(BuildContext context) { context.push(AppRoutes.profileDisclaimer); } Future _showInviteSheet(BuildContext context) async { context.push(AppRoutes.profileInvite); } Future _showShareCardSheet( BuildContext context, String? nickname, ) async { context.push(AppRoutes.profileShare); } Future _showLocalBackupSheet(BuildContext context) async { context.push(AppRoutes.profileLocalBackup); } Future _showCloudBackupSheet( BuildContext context, bool loggedIn, ) async { context.push(AppRoutes.profileCloudBackup); } Future _showWidgetSheet(BuildContext context) async { context.push(AppRoutes.profileWidget); } Future _showPriceColorSheet(BuildContext context, WidgetRef ref) async { context.push(AppRoutes.profilePriceColor); } Future _showPuritySheet( BuildContext context, ProfileSettings settings, ) async { context.push(AppRoutes.profilePurity); } Future _showRecycleSheet( BuildContext context, ProfileSettings settings, ) async { context.push(AppRoutes.profileRecycle); } Future _showCurrencySheet(BuildContext context) async { context.push(AppRoutes.profileCurrency); } void _showAbout(BuildContext context) { context.push(AppRoutes.profileAbout); } } class _MenuRow extends StatelessWidget { const _MenuRow({ required this.title, required this.subtitle, required this.icon, required this.backgroundColor, required this.iconColor, required this.onTap, }); final String title; final String subtitle; final IconData icon; final Color backgroundColor; final Color iconColor; final VoidCallback onTap; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; return InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( children: [ Container( width: 34, height: 34, decoration: BoxDecoration( color: backgroundColor, borderRadius: BorderRadius.circular(10), ), child: Icon(icon, size: 18, color: iconColor), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 4), Text( subtitle, style: TextStyle(fontSize: 12, color: cs.mutedForeground), ), ], ), ), Icon(Icons.chevron_right, size: 16, color: cs.mutedForeground), ], ), ), ); } } class _SettingRow extends StatelessWidget { const _SettingRow({ required this.icon, required this.title, required this.onTap, required this.backgroundColor, required this.iconColor, this.trailing, }); final IconData icon; final String title; final String? trailing; final VoidCallback onTap; final Color backgroundColor; final Color iconColor; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; return InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( children: [ Container( width: 34, height: 34, decoration: BoxDecoration( color: backgroundColor, borderRadius: BorderRadius.circular(10), ), child: Icon(icon, size: 18, color: iconColor), ), const SizedBox(width: 12), Expanded( child: Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ), ), ), if (trailing != null) Text( trailing!, style: TextStyle(fontSize: 12, color: cs.mutedForeground), ), const SizedBox(width: 6), Icon(Icons.chevron_right, size: 16, color: cs.mutedForeground), ], ), ), ); } }