import 'package:flutter/material.dart'; import '../../tool/gradientText.dart'; // 注意:如果 UserPage, SongListPage 等只是作为内部卡片展示,不需要再 import 用于 Navigator push // 但如果其他卡片还需要跳转,保留 import 即可 import '../user/userpage.dart'; import '../songlistpage.dart'; import '../scorelist.dart'; import 'package:provider/provider.dart'; import '../../providers/user_provider.dart'; class HomePage extends StatelessWidget { // ✅ 1. 添加回调函数参数 final Function(int)? onSwitchTab; const HomePage({super.key, this.onSwitchTab}); @override Widget build(BuildContext context) { final userProvider = context.watch(); return Scaffold( backgroundColor: Colors.transparent, body: SafeArea( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ====================== 顶部 Header ====================== SizedBox( width: double.infinity, height: 100, child: Stack( children: [ const Padding( padding: EdgeInsets.only(left: 30, top: 60), child: Text( "Tool", style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold), ), ), Positioned( right: 20, top: 25, child: Row( children: [ GradientText( data: userProvider.username, style: const TextStyle(fontSize: 19, fontWeight: FontWeight.bold), gradientLayers: [ GradientLayer( gradient: const LinearGradient( colors: [Colors.pinkAccent, Colors.orangeAccent], ), blendMode: BlendMode.srcIn, ), ], ), const SizedBox(width: 8), ClipRRect( borderRadius: BorderRadius.circular(0), // 修正语法错误,原代码可能有误 child: SizedBox( width: 54, height: 54, child: userProvider.avatarUrl.isNotEmpty ? Image.network( userProvider.avatarUrl, fit: BoxFit.cover, ) : Container( color: Colors.grey[200], child: const Icon(Icons.person, size: 30), ), ), ) ], ), ), ], ), ), const SizedBox(height: 30), // ====================== 横向卡片区域 ====================== SizedBox( height: 180, child: SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10).copyWith(bottom: 30), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ✅ 2. 修改:用户中心 -> 切换到 Tab 3 (UserPage) _buildCardWithTitle( context: context, title: "用户中心", icon: Icons.person_outline, // 不再传递 targetPage,而是传递 targetIndex targetIndex: 3, gradient: const LinearGradient( colors: [Colors.black, Colors.grey], begin: Alignment.topLeft, end: Alignment.bottomRight, ), shadowColor: Colors.black38, ), const SizedBox(width: 20), // 歌曲列表 (保持原有跳转逻辑或自行定义) _buildCardWithTitle( context: context, title: "歌曲列表", icon: Icons.music_note_outlined, targetPage: const SongListPage(), // 假设这个还是用 Push 跳转 gradient: const LinearGradient( colors: [Color(0xFFff9a9e), Color(0xFFfecfef)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), shadowColor: const Color(0xFFff9a9e).withOpacity(0.6), ), const SizedBox(width: 20), // ✅ 3. 修改:成绩管理 -> 切换到 Tab 1 (ScorePage) _buildCardWithTitle( context: context, title: "成绩管理", icon: Icons.score, targetIndex: 1, gradient: const LinearGradient( colors: [Color(0xFF84fab0), Color(0xFF8fd3f4)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), shadowColor: const Color(0xFF84fab0).withOpacity(0.6), ), const SizedBox(width: 20), // 娱乐功能 _buildCardWithTitle( context: context, title: "娱乐功能", icon: Icons.kebab_dining_sharp, targetPage: const ScoreListPage(), gradient: const LinearGradient( colors: [Colors.lightBlueAccent, Colors.blueAccent], begin: Alignment.topLeft, end: Alignment.bottomRight, ), shadowColor: Colors.lightBlue.withOpacity(0.6), ), const SizedBox(width: 20), // 评分列表 _buildCardWithTitle( context: context, title: "评分列表", icon: Icons.star, targetPage: const ScoreListPage(), gradient: const LinearGradient( colors: [Colors.redAccent, Colors.pinkAccent], begin: Alignment.topLeft, end: Alignment.bottomRight, ), shadowColor: Colors.red.withOpacity(0.6), ), const SizedBox(width: 20), ], ), ), ), // ====================== 海报 ====================== // 假设 PosterImage 是你自定义的一个 Widget const PosterImage(imageUrl: 'https://cdn.godserver.cn/post/post%20unionapp1.png'), const SizedBox(height: 20), // ====================== 新增:用户数据展示卡片 ====================== const _UserInfoCard(), const SizedBox(height: 30), ], ), ), ), ); } // ✅ 4. 修改构建方法,支持 targetIndex 和 targetPage 两种模式 Widget _buildCardWithTitle({ required BuildContext context, required String title, required IconData icon, int? targetIndex, // 新增:如果是切换 Tab,传这个 Widget? targetPage, // 保留:如果是页面跳转,传这个 required LinearGradient gradient, required Color shadowColor, }) { return Column( mainAxisSize: MainAxisSize.min, children: [ GestureDetector( onTap: () { if (targetIndex != null && onSwitchTab != null) { // ✅ 执行 Tab 切换 onSwitchTab!(targetIndex); } else if (targetPage != null) { // ✅ 执行页面跳转 Navigator.push( context, MaterialPageRoute(builder: (context) => targetPage), ); } }, child: _buildCustomCardBody( gradient: gradient, shadowColor: shadowColor, icon: icon, ), ), const SizedBox(height: 12), Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, letterSpacing: 0.5, ), textAlign: TextAlign.center, ), ], ); } Widget _buildCustomCardBody({ required LinearGradient gradient, required Color shadowColor, required IconData icon, }) { return Container( width: 100, height: 100, decoration: BoxDecoration( gradient: gradient, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: shadowColor, blurRadius: 15, spreadRadius: 3, offset: const Offset(4, 6), ), ], ), child: Center( child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white.withOpacity(0.25), shape: BoxShape.circle, ), child: Icon( icon, size: 36, color: Colors.white, ), ), ), ); } } // ====================== 新增:用户数据卡片组件 ====================== class _UserInfoCard extends StatelessWidget { const _UserInfoCard(); @override Widget build(BuildContext context) { final userProvider = Provider.of(context); return Padding( // 内边距和海报完全一致,保证同宽 padding: const EdgeInsets.symmetric(horizontal: 17.0), child: Container( width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: Colors.white.withOpacity(0.8), boxShadow: [ BoxShadow( color: Colors.pink.shade100, blurRadius: 4, offset: const Offset(0, 6), spreadRadius: 1, ), ], ), padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题 const Text( "当前用户信息", style: TextStyle( fontSize: 18, color: Colors.purpleAccent, fontWeight: FontWeight.bold, ), ), const Divider(height: 5, thickness: 1), const SizedBox(height: 6), // 用户信息行 Row( children: [ // 头像 ClipRRect( borderRadius: BorderRadius.circular(0), child: SizedBox( width: 60, height: 60, child: userProvider.avatarUrl.isNotEmpty ? Image.network( userProvider.avatarUrl, fit: BoxFit.cover, ) : Container( color: Colors.grey[200], child: const Icon(Icons.person, size: 30), ), ), ), const SizedBox(width: 18), // 文字信息 Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ GradientText( data:"用户名:${userProvider.username}", style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), gradientLayers: [ GradientLayer( gradient: const LinearGradient( colors: [Colors.blueAccent, Colors.green], ), blendMode: BlendMode.srcIn, ), ], ), const SizedBox(height: 6), Text( userProvider.username == "未登录" ? "状态:未登录" : "状态:已登录", style: TextStyle( fontSize: 14, color: userProvider.username == "未登录" ? Colors.red : Colors.green, ), ), ], ), ), ], ), ], ), ), ); } } class PosterImage extends StatelessWidget { final String imageUrl; const PosterImage({Key? key, required this.imageUrl}) : super(key: key); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: ConstrainedBox( constraints: const BoxConstraints( maxWidth: 800, ), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.purpleAccent.withOpacity(0.14), blurRadius: 12, offset: const Offset(0, 10), spreadRadius: 10, ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.network( imageUrl, fit: BoxFit.cover, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ), ); }, errorBuilder: (context, error, stackTrace) { return const Center( child: Icon(Icons.broken_image, size: 50, color: Colors.grey), ); }, ), ), ), ), ); } }