From 6a7fa5a0677e5563bd516584753553c685fe5e4d Mon Sep 17 00:00:00 2001 From: jingyun <> Date: Sun, 7 Jun 2026 11:16:38 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E5=B7=B2=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/features/profile/profile_page.dart | 288 +++++++++++++++++++------ 1 file changed, 222 insertions(+), 66 deletions(-) diff --git a/lib/features/profile/profile_page.dart b/lib/features/profile/profile_page.dart index 392b6f3..ce95516 100644 --- a/lib/features/profile/profile_page.dart +++ b/lib/features/profile/profile_page.dart @@ -54,75 +54,70 @@ class ProfilePage extends ConsumerWidget { ), children: [ const PageHeader(title: '我的'), - AppCard( - color: colors.secondary, - child: Row( - children: [ - CircleAvatar( - radius: 27, - backgroundColor: colors.background, - foregroundColor: colors.mutedForeground, - child: const Icon(AppIcons.user, size: 28), - ), - const SizedBox(width: 15), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - auth.loggedIn ? '已登录' : '未登录', - style: YantingText.cardTitle.copyWith( - fontSize: 18, - color: colors.foreground, - ), - ), - const SizedBox(height: 5), - Text( - auth.loggedIn ? '收藏、历史和听单已在本地同步' : '登录后同步收藏、历史和听单', - style: YantingText.meta.copyWith( - height: 1.5, - color: colors.mutedForeground, - ), - ), - ], - ), - ), - ], + if (auth.loggedIn) ...[ + const _LoggedInHeader(), + const SizedBox(height: YantingSpacing.x3), + _StatsCard( + favoriteCount: favoriteCount, + historyCount: historyCount, + savedListenCount: savedListenCount, ), - ), - const SizedBox(height: YantingSpacing.x3), - AppButton( - label: auth.loggedIn ? '退出登录' : '登录 / 注册', - expand: true, - onPressed: auth.loggedIn - ? () => ref.read(authControllerProvider.notifier).logout() - : () => showLoginSheet( - context, - reason: '登录后同步收藏、历史和听单', - onPhoneLogin: () => _login(ref, LoginMethod.phone), - onSecondaryLogin: () => _login(ref, LoginMethod.wechat), + ] else ...[ + AppCard( + color: colors.secondary, + child: Row( + children: [ + CircleAvatar( + radius: 27, + backgroundColor: colors.background, + foregroundColor: colors.mutedForeground, + child: const Icon(AppIcons.user, size: 28), ), - ), + const SizedBox(width: 15), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '未登录', + style: YantingText.cardTitle.copyWith( + fontSize: 18, + color: colors.foreground, + ), + ), + const SizedBox(height: 5), + Text( + '登录后同步收藏、历史和听单', + style: YantingText.meta.copyWith( + height: 1.5, + color: colors.mutedForeground, + ), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: YantingSpacing.x3), + AppButton( + label: '登录 / 注册', + expand: true, + onPressed: () => showLoginSheet( + context, + reason: '登录后同步收藏、历史和听单', + onPhoneLogin: () => _login(ref, LoginMethod.phone), + onSecondaryLogin: () => _login(ref, LoginMethod.wechat), + ), + ), + ], const SizedBox(height: 18), _MenuGroup( children: [ - _MenuRow( - icon: AppIcons.history, - title: '本地浏览记录', - trailing: '$historyCount 条 · 本地临时', - onTap: () => _showProfileListSheet( - context, - ref, - title: '本地浏览记录', - snapshot: historySnapshot, - emptyTitle: '暂无本地浏览记录', - emptyMessage: '打开研报详情或播放音频后会出现在这里', - ), - ), _MenuRow( icon: AppIcons.heart, title: '我的收藏', - trailing: '$favoriteCount 条', + trailing: '$favoriteCount 篇', onTap: () => _showLoginAwareList( context, ref, @@ -135,18 +130,37 @@ class ProfilePage extends ConsumerWidget { ), _MenuRow( icon: AppIcons.headphones, - title: '已存听单', - trailing: '$savedListenCount 条', + title: '保存的听单', + trailing: '$savedListenCount 篇', onTap: () => _showLoginAwareList( context, ref, auth, - title: '已存听单', + title: '保存的听单', snapshot: savedListenSnapshot, - emptyTitle: '暂无已存听单', + emptyTitle: '暂无保存的听单', emptyMessage: '在音频研报详情页保存听单后会出现在这里', ), ), + _MenuRow( + icon: AppIcons.history, + title: '浏览/收听历史', + trailing: '$historyCount 条', + onTap: () => _showProfileListSheet( + context, + ref, + title: '浏览/收听历史', + snapshot: historySnapshot, + emptyTitle: '暂无浏览/收听历史', + emptyMessage: '打开研报详情或播放音频后会出现在这里', + ), + ), + _MenuRow( + icon: Icons.download_outlined, + title: '下载记录', + trailing: 'Phase 1 预留', + onTap: () => showAppToast(context, '下载记录将在后续版本接入'), + ), ], ), const SizedBox(height: YantingSpacing.x3), @@ -157,6 +171,12 @@ class ProfilePage extends ConsumerWidget { title: '设置', onTap: () => context.push(AppRoutes.settings), ), + if (auth.loggedIn) + _MenuRow( + icon: Icons.logout, + title: '退出登录', + onTap: () => ref.read(authControllerProvider.notifier).logout(), + ), _MenuRow( icon: AppIcons.fileList, title: '用户协议', @@ -316,6 +336,142 @@ class ProfilePage extends ConsumerWidget { } } +class _LoggedInHeader extends StatelessWidget { + const _LoggedInHeader(); + + @override + Widget build(BuildContext context) { + return AppCard( + color: const Color(0xFF133D00), + borderColor: const Color(0xFF133D00), + padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 30), + child: Row( + children: [ + CircleAvatar( + radius: 34, + backgroundColor: const Color(0xFF385E26), + foregroundColor: YantingColors.primary, + child: Text( + '研', + style: YantingText.sectionTitle.copyWith( + color: YantingColors.primary, + fontSize: 27, + ), + ), + ), + const SizedBox(width: 22), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '研界用户', + style: YantingText.sectionTitle.copyWith( + color: Colors.white, + fontSize: 22, + ), + ), + const SizedBox(height: 4), + Text( + '已登录 · 手机号', + style: YantingText.body.copyWith( + color: Colors.white.withValues(alpha: 0.75), + fontSize: 15, + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class _StatsCard extends StatelessWidget { + const _StatsCard({ + required this.favoriteCount, + required this.historyCount, + required this.savedListenCount, + }); + + final int favoriteCount; + final int historyCount; + final int savedListenCount; + + @override + Widget build(BuildContext context) { + final colors = ShadTheme.of(context).colorScheme; + return AppCard( + padding: EdgeInsets.zero, + child: Row( + children: [ + Expanded( + child: _StatCell(value: favoriteCount, label: '收藏'), + ), + SizedBox( + height: 66, + child: VerticalDivider( + width: 1, + thickness: 1, + color: colors.border, + ), + ), + Expanded( + child: _StatCell(value: historyCount, label: '历史'), + ), + SizedBox( + height: 66, + child: VerticalDivider( + width: 1, + thickness: 1, + color: colors.border, + ), + ), + Expanded( + child: _StatCell(value: savedListenCount, label: '听单'), + ), + ], + ), + ); + } +} + +class _StatCell extends StatelessWidget { + const _StatCell({required this.value, required this.label}); + + final int value; + final String label; + + @override + Widget build(BuildContext context) { + final colors = ShadTheme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.symmetric(vertical: 18), + child: Column( + children: [ + Text( + '$value', + style: YantingText.sectionTitle.copyWith( + color: const Color(0xFF163E08), + fontSize: 22, + fontFeatures: YantingTypographyFeatures.tabularNums, + ), + ), + const SizedBox(height: 3), + Text( + label, + style: YantingText.meta.copyWith( + color: colors.mutedForeground, + fontSize: 14, + ), + ), + ], + ), + ); + } +} + class _MenuGroup extends StatelessWidget { const _MenuGroup({required this.children}); @@ -361,7 +517,7 @@ class _MenuRow extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15), child: Row( children: [ - Icon(icon, size: 20, color: colors.foreground), + Icon(icon, size: 20, color: const Color(0xFF143B05)), const SizedBox(width: 13), Expanded(child: Text(title, style: YantingText.body)), if (trailing != null)