diff --git a/frontend/mining-app/lib/main.dart b/frontend/mining-app/lib/main.dart index 200bf33a..8be45fe3 100644 --- a/frontend/mining-app/lib/main.dart +++ b/frontend/mining-app/lib/main.dart @@ -7,6 +7,7 @@ import 'core/constants/app_colors.dart'; import 'core/network/api_client.dart'; import 'core/router/routes.dart'; import 'presentation/providers/user_providers.dart'; +import 'presentation/providers/settings_providers.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -46,10 +47,12 @@ class _MiningAppState extends ConsumerState { @override Widget build(BuildContext context) { final router = ref.watch(appRouterProvider); + final themeMode = ref.watch(themeModeProvider); return MaterialApp.router( title: '股行', debugShowCheckedModeBanner: false, + themeMode: themeMode, theme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: AppColors.primary, @@ -67,6 +70,23 @@ class _MiningAppState extends ConsumerState { ), ), ), + darkTheme: ThemeData( + colorScheme: ColorScheme.fromSeed( + seedColor: AppColors.primary, + brightness: Brightness.dark, + ), + useMaterial3: true, + appBarTheme: const AppBarTheme( + centerTitle: true, + elevation: 0, + ), + cardTheme: const CardThemeData( + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + ), + ), routerConfig: router, ); } diff --git a/frontend/mining-app/lib/presentation/pages/profile/mining_records_page.dart b/frontend/mining-app/lib/presentation/pages/profile/mining_records_page.dart index 8e9c63fa..b5410db7 100644 --- a/frontend/mining-app/lib/presentation/pages/profile/mining_records_page.dart +++ b/frontend/mining-app/lib/presentation/pages/profile/mining_records_page.dart @@ -239,9 +239,13 @@ class _MiningRecordsListPageState extends ConsumerState { // 第二行:贡献值占比 + 价格快照 Row( children: [ - _buildInfoItem('贡献值占比', _formatPercent(record.contributionRatio)), - const SizedBox(width: 24), - _buildInfoItem('价格快照', _formatPrice(record.priceSnapshot)), + Expanded( + child: _buildInfoItem('贡献值占比', _formatPercent(record.contributionRatio)), + ), + const SizedBox(width: 16), + Expanded( + child: _buildInfoItem('价格快照', _formatPrice(record.priceSnapshot)), + ), ], ), const SizedBox(height: 8), @@ -270,13 +274,16 @@ class _MiningRecordsListPageState extends ConsumerState { '$label: ', style: TextStyle(fontSize: 12, color: _grayText.withOpacity(0.7)), ), - Text( - value, - style: const TextStyle( - fontSize: 12, - color: _darkText, - fontWeight: FontWeight.w500, - fontFamily: 'monospace', + Flexible( + child: Text( + value, + style: const TextStyle( + fontSize: 12, + color: _darkText, + fontWeight: FontWeight.w500, + fontFamily: 'monospace', + ), + overflow: TextOverflow.ellipsis, ), ), ], diff --git a/frontend/mining-app/lib/presentation/pages/profile/profile_page.dart b/frontend/mining-app/lib/presentation/pages/profile/profile_page.dart index fb7d0def..1c1b709b 100644 --- a/frontend/mining-app/lib/presentation/pages/profile/profile_page.dart +++ b/frontend/mining-app/lib/presentation/pages/profile/profile_page.dart @@ -10,13 +10,9 @@ import '../../widgets/shimmer_loading.dart'; class ProfilePage extends ConsumerWidget { const ProfilePage({super.key}); - // 设计色彩 + // 品牌色彩(不随主题变化) static const Color _orange = Color(0xFFFF6B00); static const Color _green = Color(0xFF10B981); - static const Color _darkText = Color(0xFF1F2937); - static const Color _grayText = Color(0xFF6B7280); - static const Color _lightGray = Color(0xFF9CA3AF); - static const Color _bgGray = Color(0xFFF3F4F6); static const Color _red = Color(0xFFEF4444); // 预设头像颜色列表(与编辑页面保持一致) @@ -35,12 +31,13 @@ class ProfilePage extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final user = ref.watch(userNotifierProvider); final statsAsync = ref.watch(userStatsProvider); + final colorScheme = Theme.of(context).colorScheme; final isStatsLoading = statsAsync.isLoading; final stats = statsAsync.valueOrNull; return Scaffold( - backgroundColor: _bgGray, + backgroundColor: colorScheme.surfaceContainerHighest, body: SafeArea( bottom: false, child: RefreshIndicator( @@ -53,46 +50,46 @@ class ProfilePage extends ConsumerWidget { child: Column( children: [ // 用户头部信息 - _buildUserHeader(context, user), + _buildUserHeader(context, user, colorScheme), const SizedBox(height: 16), // 统计数据行 - _buildStatsRow(stats, isStatsLoading), + _buildStatsRow(context, stats, isStatsLoading, colorScheme), const SizedBox(height: 16), // 账户设置 - _buildAccountSettings(context, user), + _buildAccountSettings(context, user, colorScheme), const SizedBox(height: 16), // 记录入口 - _buildRecordsSection(context), + _buildRecordsSection(context, colorScheme), const SizedBox(height: 16), // 团队与收益 - _buildTeamEarningsSection(context), + _buildTeamEarningsSection(context, colorScheme), const SizedBox(height: 16), // 其他设置 - _buildOtherSettings(context, ref), + _buildOtherSettings(context, ref, colorScheme), const SizedBox(height: 24), // 退出登录 - _buildLogoutButton(context, ref), + _buildLogoutButton(context, ref, colorScheme), const SizedBox(height: 16), // 版本信息 - const Text( + Text( 'Version 1.0.0', style: TextStyle( fontSize: 12, - color: _lightGray, + color: colorScheme.outline, ), ), @@ -105,12 +102,12 @@ class ProfilePage extends ConsumerWidget { ); } - Widget _buildUserHeader(BuildContext context, UserState user) { + Widget _buildUserHeader(BuildContext context, UserState user, ColorScheme colorScheme) { final avatarColor = _avatarColors[user.avatarIndex % _avatarColors.length]; return Container( padding: const EdgeInsets.all(20), - color: Colors.white, + color: colorScheme.surface, child: Row( children: [ // 头像(可点击) @@ -157,10 +154,10 @@ class ProfilePage extends ConsumerWidget { user.nickname?.isNotEmpty == true ? user.nickname! : (user.realName ?? '股行用户'), - style: const TextStyle( + style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, - color: _darkText, + color: colorScheme.onSurface, ), ), const SizedBox(width: 8), @@ -198,9 +195,9 @@ class ProfilePage extends ConsumerWidget { if (user.phone != null) Text( 'ID: ${user.phone}', - style: const TextStyle( + style: TextStyle( fontSize: 14, - color: _grayText, + color: colorScheme.onSurfaceVariant, ), ), ], @@ -210,9 +207,9 @@ class ProfilePage extends ConsumerWidget { // 编辑按钮 IconButton( onPressed: () => context.push(Routes.editProfile), - icon: const Icon( + icon: Icon( Icons.edit_outlined, - color: _grayText, + color: colorScheme.onSurfaceVariant, ), ), ], @@ -220,10 +217,10 @@ class ProfilePage extends ConsumerWidget { ); } - Widget _buildStatsRow(UserStats? stats, bool isLoading) { + Widget _buildStatsRow(BuildContext context, UserStats? stats, bool isLoading, ColorScheme colorScheme) { return Container( padding: const EdgeInsets.symmetric(vertical: 16), - color: Colors.white, + color: colorScheme.surface, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -231,81 +228,85 @@ class ProfilePage extends ConsumerWidget { '参与状态', stats?.hasAdopted == true ? '已参与' : '未参与', isLoading, + colorScheme, ), - _buildDivider(), + _buildDivider(colorScheme), _buildStatItem( '引荐人数', stats?.directReferralAdoptedCount.toString() ?? '0', isLoading, + colorScheme, ), - _buildDivider(), + _buildDivider(colorScheme), _buildStatItem( '团队下贡献值', stats?.unlockedLevelDepth.toString() ?? '0', isLoading, + colorScheme, ), - _buildDivider(), + _buildDivider(colorScheme), _buildStatItem( '团队上贡献值', '15', isLoading, + colorScheme, ), ], ), ); } - Widget _buildStatItem(String label, String value, bool isLoading) { + Widget _buildStatItem(String label, String value, bool isLoading, ColorScheme colorScheme) { return Column( children: [ DataText( data: isLoading ? null : value, isLoading: isLoading, placeholder: '--', - style: const TextStyle( + style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, - color: _darkText, + color: colorScheme.onSurface, ), ), const SizedBox(height: 4), Text( label, - style: const TextStyle( + style: TextStyle( fontSize: 12, - color: _grayText, + color: colorScheme.onSurfaceVariant, ), ), ], ); } - Widget _buildDivider() { + Widget _buildDivider(ColorScheme colorScheme) { return Container( width: 1, height: 30, - color: _bgGray, + color: colorScheme.outlineVariant, ); } - Widget _buildAccountSettings(BuildContext context, UserState user) { + Widget _buildAccountSettings(BuildContext context, UserState user, ColorScheme colorScheme) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.white, + color: colorScheme.surface, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( '账户设置', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: _darkText, + color: colorScheme.onSurface, ), ), ), @@ -314,6 +315,7 @@ class ProfilePage extends ConsumerWidget { label: '账户安全', onTap: () => context.push(Routes.changePassword), showDivider: false, + colorScheme: colorScheme, ), ], ), @@ -326,16 +328,17 @@ class ProfilePage extends ConsumerWidget { Widget? trailing, required VoidCallback onTap, bool showDivider = true, + required ColorScheme colorScheme, }) { return Column( children: [ ListTile( - leading: Icon(icon, color: _grayText, size: 22), + leading: Icon(icon, color: colorScheme.onSurfaceVariant, size: 22), title: Text( label, - style: const TextStyle( + style: TextStyle( fontSize: 14, - color: _darkText, + color: colorScheme.onSurface, ), ), trailing: Row( @@ -343,7 +346,7 @@ class ProfilePage extends ConsumerWidget { children: [ if (trailing != null) trailing, if (trailing != null) const SizedBox(width: 8), - const Icon(Icons.chevron_right, color: _lightGray, size: 20), + Icon(Icons.chevron_right, color: colorScheme.outline, size: 20), ], ), onTap: onTap, @@ -354,23 +357,23 @@ class ProfilePage extends ConsumerWidget { ); } - Widget _buildRecordsSection(BuildContext context) { + Widget _buildRecordsSection(BuildContext context, ColorScheme colorScheme) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: Colors.white, + color: colorScheme.surface, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( + Text( '我的记录', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: _darkText, + color: colorScheme.onSurface, ), ), const SizedBox(height: 16), @@ -381,16 +384,19 @@ class ProfilePage extends ConsumerWidget { icon: Icons.eco, label: '参与记录', onTap: () => context.push(Routes.plantingRecords), + colorScheme: colorScheme, ), _buildRecordIcon( icon: Icons.assignment, label: '分配记录', onTap: () => context.push(Routes.miningRecords), + colorScheme: colorScheme, ), _buildRecordIcon( icon: Icons.receipt_long, label: '交易记录', onTap: () => context.push(Routes.tradingRecords), + colorScheme: colorScheme, ), ], ), @@ -403,6 +409,7 @@ class ProfilePage extends ConsumerWidget { required IconData icon, required String label, required VoidCallback onTap, + required ColorScheme colorScheme, }) { return GestureDetector( onTap: onTap, @@ -421,9 +428,9 @@ class ProfilePage extends ConsumerWidget { const SizedBox(height: 8), Text( label, - style: const TextStyle( + style: TextStyle( fontSize: 12, - color: _grayText, + color: colorScheme.onSurfaceVariant, ), ), ], @@ -431,24 +438,24 @@ class ProfilePage extends ConsumerWidget { ); } - Widget _buildTeamEarningsSection(BuildContext context) { + Widget _buildTeamEarningsSection(BuildContext context, ColorScheme colorScheme) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.white, + color: colorScheme.surface, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( '团队与收益', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: _darkText, + color: colorScheme.onSurface, ), ), ), @@ -457,33 +464,34 @@ class ProfilePage extends ConsumerWidget { label: '我的团队', onTap: () => context.push(Routes.myTeam), showDivider: false, + colorScheme: colorScheme, ), ], ), ); } - Widget _buildOtherSettings(BuildContext context, WidgetRef ref) { + Widget _buildOtherSettings(BuildContext context, WidgetRef ref, ColorScheme colorScheme) { final notificationsEnabled = ref.watch(notificationsEnabledProvider); final darkModeEnabled = ref.watch(darkModeEnabledProvider); return Container( margin: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.white, + color: colorScheme.surface, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.fromLTRB(16, 16, 16, 8), + Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( '其他设置', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: _darkText, + color: colorScheme.onSurface, ), ), ), @@ -494,6 +502,7 @@ class ProfilePage extends ConsumerWidget { onChanged: (value) { ref.read(notificationsEnabledProvider.notifier).setEnabled(value); }, + colorScheme: colorScheme, ), _buildSwitchItem( icon: Icons.dark_mode_outlined, @@ -502,17 +511,20 @@ class ProfilePage extends ConsumerWidget { onChanged: (value) { ref.read(darkModeEnabledProvider.notifier).setEnabled(value); }, + colorScheme: colorScheme, ), _buildSettingItem( icon: Icons.help_outline, label: '帮助中心', onTap: () => context.push(Routes.helpCenter), + colorScheme: colorScheme, ), _buildSettingItem( icon: Icons.info_outline, label: '关于我们', onTap: () => context.push(Routes.about), showDivider: false, + colorScheme: colorScheme, ), ], ), @@ -524,16 +536,17 @@ class ProfilePage extends ConsumerWidget { required String label, required bool value, required ValueChanged onChanged, + required ColorScheme colorScheme, }) { return Column( children: [ ListTile( - leading: Icon(icon, color: _grayText, size: 22), + leading: Icon(icon, color: colorScheme.onSurfaceVariant, size: 22), title: Text( label, - style: const TextStyle( + style: TextStyle( fontSize: 14, - color: _darkText, + color: colorScheme.onSurface, ), ), trailing: Switch( @@ -548,7 +561,7 @@ class ProfilePage extends ConsumerWidget { ); } - Widget _buildLogoutButton(BuildContext context, WidgetRef ref) { + Widget _buildLogoutButton(BuildContext context, WidgetRef ref, ColorScheme colorScheme) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: SizedBox( @@ -580,7 +593,7 @@ class ProfilePage extends ConsumerWidget { ); }, style: TextButton.styleFrom( - backgroundColor: Colors.white, + backgroundColor: colorScheme.surface, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12),