import 'package:flutter/material.dart'; import 'package:flutter_remix/flutter_remix.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/app_toast.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, 20), 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, onTap: () => _showInviteSheet(context), ), const PrototypeDivider(margin: EdgeInsets.zero), _MenuRow( title: '分享我的贵金属估值卡', subtitle: '免登录 · 自动打码金额', icon: Icons.share_outlined, 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), // ), // const PrototypeDivider(margin: EdgeInsets.zero), // SettingRow( // icon: Icons.cloud_outlined, // title: '云备份 · 多端同步', // trailing: loggedIn ? '已登录' : '登录解锁', // onTap: () => _showCloudBackupSheet(context, loggedIn), // ), // ], // ), // ), // const SizedBox(height: 12), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ SettingRow( icon: Icons.tune_outlined, title: '纯度系数管理', trailing: '${settings.purityPresets.length} 项', onTap: () => _showPuritySheet(context, settings), ), const PrototypeDivider(margin: EdgeInsets.zero), SettingRow( icon: Icons.percent_outlined, title: '回收折扣设置', trailing: '金 ${(settings.recycleDiscounts.values.first * 100).toStringAsFixed(0)}%', onTap: () => _showRecycleSheet(context, settings), ), const PrototypeDivider(margin: EdgeInsets.zero), SettingRow( icon: Icons.palette_outlined, title: '涨跌颜色', trailing: settings.priceColorMode.label, onTap: () { final nextMode = settings.priceColorMode == PriceColorMode.redUpGreenDown ? PriceColorMode.greenUpRedDown : PriceColorMode.redUpGreenDown; ref .read(profileSettingsControllerProvider.notifier) .setPriceColorMode(nextMode); toastInfo(msg: '已切换为「${nextMode.label}」'); }, ), const PrototypeDivider(margin: EdgeInsets.zero), SettingRow( icon: Icons.currency_yen_outlined, title: '显示币种', trailing: '¥ CNY', onTap: () => toastInfo(msg: '当前仅支持 ¥ CNY'), ), const PrototypeDivider(margin: EdgeInsets.zero), SettingRow( icon: Icons.grid_view_outlined, title: '添加桌面小组件', trailing: '占位', onTap: () => _showWidgetSheet(context), ), ], ), ), const SizedBox(height: 12), PrototypeCard( padding: EdgeInsets.zero, child: Column( children: [ SettingRow( icon: Icons.settings, title: '设置', trailing: null, onTap: () => context.push(AppRoutes.settings), ), const PrototypeDivider(margin: EdgeInsets.zero), SettingRow( icon: FlutterRemix.file_list_3_line, title: '用户协议', onTap: () => launchUrlString( AppH5UrlsHelper.withCacheBuster( AppH5Urls.userProtocolUrl, ), mode: LaunchMode.inAppBrowserView, ), ), const PrototypeDivider(margin: EdgeInsets.zero), SettingRow( icon: FlutterRemix.shield_check_line, title: '隐私政策', onTap: () => launchUrlString( AppH5UrlsHelper.withCacheBuster(AppH5Urls.privacyUrl), mode: LaunchMode.inAppBrowserView, ), ), const PrototypeDivider(margin: EdgeInsets.zero), SettingRow( icon: Icons.info_outline, title: '免责声明', trailing: null, onTap: () => _showDisclaimer(context), ), // const PrototypeDivider(margin: EdgeInsets.zero), // SettingRow( // icon: Icons.feedback_outlined, // title: '意见反馈 · 关于金值', // trailing: null, // onTap: () => _showAbout(context), // ), ], ), ), 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 _showPuritySheet( BuildContext context, ProfileSettings settings, ) async { context.push(AppRoutes.profilePurity); } Future _showRecycleSheet( BuildContext context, ProfileSettings settings, ) async { context.push(AppRoutes.profileRecycle); } 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.onTap, }); final String title; final String subtitle; final IconData icon; 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: [ Icon(icon, size: 20, color: const Color(0xFF8A8780)), 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, this.trailing, this.destructive = false, }); final IconData icon; final String title; final String? trailing; final VoidCallback onTap; final bool destructive; @override Widget build(BuildContext context) { final cs = ShadTheme.of(context).colorScheme; final color = destructive ? cs.destructive : cs.foreground; return InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( children: [ Icon(icon, size: 20, color: const Color(0xFF8A8780)), const SizedBox(width: 12), Expanded( child: Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: color, ), ), ), 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), ], ), ), ); } }