From 91b8cca41c5c939b11df75b8fde6792aec82ed8d Mon Sep 17 00:00:00 2001 From: hailin Date: Wed, 14 Jan 2026 19:22:03 -0800 Subject: [PATCH] feat(mining-app): implement hide/show amounts toggle - Add hideAmountsProvider to control amount visibility - Add tap handler to eye icon in total contribution card - Toggle icon between visibility_outlined and visibility_off_outlined - Hide amounts with **** when toggled in: - Total contribution value - Three column stats (personal, team level, team bonus) - Today's estimated earnings - Contribution detail summary rows Co-Authored-By: Claude Opus 4.5 --- .../pages/contribution/contribution_page.dart | 50 +++++++++++++------ .../providers/contribution_providers.dart | 3 ++ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/frontend/mining-app/lib/presentation/pages/contribution/contribution_page.dart b/frontend/mining-app/lib/presentation/pages/contribution/contribution_page.dart index fe4cfe5b..e814f8f8 100644 --- a/frontend/mining-app/lib/presentation/pages/contribution/contribution_page.dart +++ b/frontend/mining-app/lib/presentation/pages/contribution/contribution_page.dart @@ -71,16 +71,16 @@ class ContributionPage extends ConsumerWidget { sliver: SliverList( delegate: SliverChildListDelegate([ // 总贡献值卡片 - _buildTotalContributionCard(contribution, isLoading), + _buildTotalContributionCard(ref, contribution, isLoading), const SizedBox(height: 16), // 三栏统计 - _buildThreeColumnStats(contribution, isLoading), + _buildThreeColumnStats(ref, contribution, isLoading), const SizedBox(height: 16), // 今日预估收益 - _buildTodayEstimateCard(estimatedEarnings, isLoading || isStatsLoading), + _buildTodayEstimateCard(ref, estimatedEarnings, isLoading || isStatsLoading), const SizedBox(height: 16), // 贡献值明细(三类汇总) - _buildContributionDetailCard(context, contribution, isLoading), + _buildContributionDetailCard(context, ref, contribution, isLoading), const SizedBox(height: 16), // 团队层级统计 _buildTeamStatsCard(contribution, isLoading), @@ -156,8 +156,9 @@ class ContributionPage extends ConsumerWidget { ); } - Widget _buildTotalContributionCard(Contribution? contribution, bool isLoading) { + Widget _buildTotalContributionCard(WidgetRef ref, Contribution? contribution, bool isLoading) { final total = contribution?.totalContribution ?? '0'; + final hideAmounts = ref.watch(hideAmountsProvider); return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -174,12 +175,21 @@ class ContributionPage extends ConsumerWidget { '总贡献值', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: _grayText), ), - Icon(Icons.visibility_outlined, color: _grayText.withOpacity(0.5), size: 18), + GestureDetector( + onTap: () { + ref.read(hideAmountsProvider.notifier).state = !hideAmounts; + }, + child: Icon( + hideAmounts ? Icons.visibility_off_outlined : Icons.visibility_outlined, + color: _grayText.withOpacity(0.5), + size: 18, + ), + ), ], ), const SizedBox(height: 8), DataText( - data: isLoading ? null : formatAmount(total), + data: isLoading ? null : (hideAmounts ? '******' : formatAmount(total)), isLoading: isLoading, placeholder: '----', style: const TextStyle( @@ -214,7 +224,8 @@ class ContributionPage extends ConsumerWidget { ); } - Widget _buildThreeColumnStats(Contribution? contribution, bool isLoading) { + Widget _buildThreeColumnStats(WidgetRef ref, Contribution? contribution, bool isLoading) { + final hideAmounts = ref.watch(hideAmountsProvider); return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -223,15 +234,15 @@ class ContributionPage extends ConsumerWidget { ), child: Row( children: [ - _buildStatColumn('个人贡献值', contribution?.personalContribution, isLoading, false), - _buildStatColumn('团队层级', contribution?.teamLevelContribution, isLoading, true), - _buildStatColumn('团队奖励', contribution?.teamBonusContribution, isLoading, true), + _buildStatColumn('个人贡献值', contribution?.personalContribution, isLoading, false, hideAmounts), + _buildStatColumn('团队层级', contribution?.teamLevelContribution, isLoading, true, hideAmounts), + _buildStatColumn('团队奖励', contribution?.teamBonusContribution, isLoading, true, hideAmounts), ], ), ); } - Widget _buildStatColumn(String label, String? value, bool isLoading, bool showLeftBorder) { + Widget _buildStatColumn(String label, String? value, bool isLoading, bool showLeftBorder, bool hideAmounts) { return Expanded( child: Container( decoration: showLeftBorder @@ -245,7 +256,7 @@ class ContributionPage extends ConsumerWidget { Text(label, style: const TextStyle(fontSize: 12, color: _grayText)), const SizedBox(height: 4), DataText( - data: value != null ? formatAmount(value) : null, + data: value != null ? (hideAmounts ? '****' : formatAmount(value)) : null, isLoading: isLoading, placeholder: '--', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: _darkText), @@ -257,7 +268,8 @@ class ContributionPage extends ConsumerWidget { ); } - Widget _buildTodayEstimateCard(EstimatedEarnings earnings, bool isLoading) { + Widget _buildTodayEstimateCard(WidgetRef ref, EstimatedEarnings earnings, bool isLoading) { + final hideAmounts = ref.watch(hideAmountsProvider); return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -306,7 +318,7 @@ class ContributionPage extends ConsumerWidget { TextSpan( children: [ TextSpan( - text: earnings.isValid ? formatAmount(earnings.dailyShares) : '--', + text: hideAmounts ? '****' : (earnings.isValid ? formatAmount(earnings.dailyShares) : '--'), style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, @@ -329,9 +341,11 @@ class ContributionPage extends ConsumerWidget { Widget _buildContributionDetailCard( BuildContext context, + WidgetRef ref, Contribution? contribution, bool isLoading, ) { + final hideAmounts = ref.watch(hideAmountsProvider); return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( @@ -374,6 +388,7 @@ class ContributionPage extends ConsumerWidget { title: '本人种植', subtitle: '个人认种榴莲树产生的贡献值', amount: contribution?.personalContribution ?? '0', + hideAmounts: hideAmounts, ), const Divider(height: 24), _buildDetailSummaryRow( @@ -382,6 +397,7 @@ class ContributionPage extends ConsumerWidget { title: '团队层级', subtitle: '直推及间推用户认种产生的贡献值', amount: contribution?.teamLevelContribution ?? '0', + hideAmounts: hideAmounts, ), const Divider(height: 24), _buildDetailSummaryRow( @@ -390,6 +406,7 @@ class ContributionPage extends ConsumerWidget { title: '团队奖励', subtitle: '满足条件后获得的额外奖励贡献值', amount: contribution?.teamBonusContribution ?? '0', + hideAmounts: hideAmounts, ), ], ), @@ -445,6 +462,7 @@ class ContributionPage extends ConsumerWidget { required String title, required String subtitle, required String amount, + required bool hideAmounts, }) { return Row( children: [ @@ -475,7 +493,7 @@ class ContributionPage extends ConsumerWidget { ), ), Text( - formatAmount(amount), + hideAmounts ? '****' : formatAmount(amount), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: _green), ), ], diff --git a/frontend/mining-app/lib/presentation/providers/contribution_providers.dart b/frontend/mining-app/lib/presentation/providers/contribution_providers.dart index 585c57e1..57e8e29c 100644 --- a/frontend/mining-app/lib/presentation/providers/contribution_providers.dart +++ b/frontend/mining-app/lib/presentation/providers/contribution_providers.dart @@ -173,3 +173,6 @@ final estimatedEarningsProvider = Provider.family((re isValid: true, ); }); + +/// 控制是否隐藏金额显示的状态 +final hideAmountsProvider = StateProvider((ref) => false);