From 04644ea3f82240aa8c9d7fbf4e322852e58377d4 Mon Sep 17 00:00:00 2001 From: hailin Date: Mon, 15 Dec 2025 02:16:36 -0800 Subject: [PATCH] =?UTF-8?q?feat(profile):=20=E6=B7=BB=E5=8A=A0=E9=80=80?= =?UTF-8?q?=E5=87=BA=E7=99=BB=E5=BD=95=E5=92=8C=E5=88=87=E6=8D=A2=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在版本信息栏添加构建模式显示(Debug/Release/Profile) - 在版本信息栏下方添加切换账号按钮(暂显示即将上线提示) - 在版本信息栏下方添加退出登录按钮(带确认对话框) - 退出登录后清除本地数据并跳转到向导页 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../presentation/pages/profile_page.dart | 267 ++++++++++++++---- 1 file changed, 213 insertions(+), 54 deletions(-) diff --git a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart index 297ea328..360dc3c2 100644 --- a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart +++ b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -802,66 +803,71 @@ class _ProfilePageState extends ConsumerState { return Container( height: 48, padding: const EdgeInsets.only(top: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Stack( + alignment: Alignment.center, children: [ - // 页面标题 - const Text( - '我的', - style: TextStyle( - fontSize: 20, - fontFamily: 'Inter', - fontWeight: FontWeight.w700, - color: Color(0xFF5D4037), + // 页面标题(居中显示) + const Center( + child: Text( + '我的', + style: TextStyle( + fontSize: 20, + fontFamily: 'Inter', + fontWeight: FontWeight.w700, + color: Color(0xFF5D4037), + ), ), ), - // 通知图标(带未读角标) - GestureDetector( - onTap: _goToNotifications, - child: Container( - width: 40, - height: 40, - alignment: Alignment.center, - child: Stack( - clipBehavior: Clip.none, - children: [ - const Icon( - Icons.notifications_outlined, - size: 26, - color: Color(0xFF5D4037), - ), - // 未读角标 - if (_unreadNotificationCount > 0) - Positioned( - top: -4, - right: -4, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 2, - ), - decoration: BoxDecoration( - color: const Color(0xFFD4AF37), - borderRadius: BorderRadius.circular(10), - ), - constraints: const BoxConstraints( - minWidth: 18, - minHeight: 18, - ), - child: Text( - _unreadNotificationCount > 99 - ? '99+' - : _unreadNotificationCount.toString(), - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Colors.white, + // 通知图标(右侧,带未读角标) + Positioned( + right: 0, + child: GestureDetector( + onTap: _goToNotifications, + child: Container( + width: 40, + height: 40, + alignment: Alignment.center, + child: Stack( + clipBehavior: Clip.none, + children: [ + const Icon( + Icons.notifications_outlined, + size: 26, + color: Color(0xFF5D4037), + ), + // 未读角标 + if (_unreadNotificationCount > 0) + Positioned( + top: -4, + right: -4, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 2, + ), + decoration: BoxDecoration( + color: const Color(0xFFD4AF37), + borderRadius: BorderRadius.circular(10), + ), + constraints: const BoxConstraints( + minWidth: 18, + minHeight: 18, + ), + child: Text( + _unreadNotificationCount > 99 + ? '99+' + : _unreadNotificationCount.toString(), + style: const TextStyle( + fontSize: 10, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, ), ), - ), - ], + ], + ), ), ), ), @@ -1309,6 +1315,9 @@ class _ProfilePageState extends ConsumerState { const SizedBox(height: 16), // 应用版本信息 _buildAppVersionInfo(), + const SizedBox(height: 16), + // 账号操作按钮 + _buildAccountActionButtons(), ], ), ); @@ -2711,6 +2720,8 @@ class _ProfilePageState extends ConsumerState { const SizedBox(height: 8), _buildVersionInfoRow('构建号', _buildNumber), const SizedBox(height: 8), + _buildVersionInfoRow('构建模式', kReleaseMode ? 'Release' : (kDebugMode ? 'Debug' : 'Profile')), + const SizedBox(height: 8), _buildVersionInfoRow('包名', _packageName), const Divider( height: 24, @@ -2771,4 +2782,152 @@ class _ProfilePageState extends ConsumerState { ], ); } + + /// 构建账号操作按钮(切换账号、退出登录) + Widget _buildAccountActionButtons() { + return Column( + children: [ + // 切换账号按钮 + GestureDetector( + onTap: _onSwitchAccount, + child: Container( + width: double.infinity, + height: 48, + decoration: BoxDecoration( + color: const Color(0xFFFFF5E6), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: const Color(0x33D4AF37), + width: 1, + ), + ), + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.swap_horiz, + size: 20, + color: Color(0xFF8B5A2B), + ), + SizedBox(width: 8), + Text( + '切换账号', + style: TextStyle( + fontSize: 15, + fontFamily: 'Inter', + fontWeight: FontWeight.w500, + height: 1.5, + color: Color(0xFF5D4037), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 12), + // 退出登录按钮 + GestureDetector( + onTap: _onLogout, + child: Container( + width: double.infinity, + height: 48, + decoration: BoxDecoration( + color: const Color(0xFFFFF5E6), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: const Color(0x33E57373), + width: 1, + ), + ), + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.logout, + size: 20, + color: Color(0xFFE57373), + ), + SizedBox(width: 8), + Text( + '退出登录', + style: TextStyle( + fontSize: 15, + fontFamily: 'Inter', + fontWeight: FontWeight.w500, + height: 1.5, + color: Color(0xFFE57373), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 32), // 底部留白 + ], + ); + } + + /// 切换账号 + void _onSwitchAccount() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('切换账号'), + content: const Text('多账号管理功能即将上线,敬请期待。'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('确定'), + ), + ], + ), + ); + } + + /// 退出登录 + void _onLogout() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('退出登录'), + content: const Text('确定要退出当前账号吗?\n\n退出后需要重新导入助记词才能恢复账号。'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('取消'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + _performLogout(); + }, + style: TextButton.styleFrom( + foregroundColor: const Color(0xFFE57373), + ), + child: const Text('退出'), + ), + ], + ), + ); + } + + /// 执行退出登录 + Future _performLogout() async { + try { + final accountService = ref.read(accountServiceProvider); + // 清除所有本地数据 + await accountService.logout(); + // 导航到向导页 + if (mounted) { + context.go(RoutePaths.guide); + } + } catch (e) { + debugPrint('[ProfilePage] 退出登录失败: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('退出登录失败: $e')), + ); + } + } + } }