import 'package:flutter/material.dart'; import '../../../../app/i18n/app_localizations.dart'; import '../../../../app/theme/app_colors.dart'; import '../../../../app/theme/app_typography.dart'; import '../../../../app/theme/app_spacing.dart'; import '../../../../shared/widgets/coupon_card.dart'; import '../../../ai_agent/presentation/widgets/ai_fab.dart'; /// A2. 首页 - 搜索栏 + Banner + 热门分类 + 精选券 + AI Agent /// /// Tab导航:首页/市场/我的券/消息/我的 class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ CustomScrollView( slivers: [ // Floating App Bar SliverAppBar( floating: true, pinned: false, backgroundColor: AppColors.background, elevation: 0, toolbarHeight: 60, title: _buildSearchBar(context), actions: [ IconButton( icon: const Icon(Icons.qr_code_scanner_rounded, size: 24), onPressed: () {}, color: AppColors.textPrimary, ), ], ), // Banner Carousel SliverToBoxAdapter(child: _buildBanner(context)), // Category Grid SliverToBoxAdapter(child: _buildCategoryGrid(context)), // AI Smart Suggestions SliverToBoxAdapter(child: _buildAiSuggestions(context)), // Section: Featured Coupons SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(20, 24, 20, 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(context.t('home.featuredCoupons'), style: AppTypography.h2), GestureDetector( onTap: () {}, child: Text(context.t('home.viewAllCoupons'), style: AppTypography.labelSmall.copyWith( color: AppColors.primary, )), ), ], ), ), ), // Coupon List SliverPadding( padding: AppSpacing.pagePadding, sliver: SliverList( delegate: SliverChildBuilderDelegate( (context, index) => Padding( padding: const EdgeInsets.only(bottom: 12), child: CouponCard( brandName: _mockBrands[index % _mockBrands.length], couponName: _mockNames[index % _mockNames.length], faceValue: _mockFaceValues[index % _mockFaceValues.length], currentPrice: _mockPrices[index % _mockPrices.length], creditRating: _mockRatings[index % _mockRatings.length], expiryDate: DateTime.now().add(Duration(days: (index + 1) * 5)), onTap: () { Navigator.pushNamed(context, '/coupon/detail'); }, ), ), childCount: 10, ), ), ), const SliverPadding(padding: EdgeInsets.only(bottom: 100)), ], ), // AI FAB Positioned( right: 20, bottom: 100, child: AiFab( unreadCount: 3, onTap: () { Navigator.pushNamed(context, '/ai-chat'); }, ), ), ], ), ); } Widget _buildSearchBar(BuildContext context) { return GestureDetector( onTap: () { Navigator.pushNamed(context, '/search'); }, child: Container( height: 40, decoration: BoxDecoration( color: AppColors.gray50, borderRadius: AppSpacing.borderRadiusFull, border: Border.all(color: AppColors.borderLight), ), child: Row( children: [ const SizedBox(width: 14), const Icon(Icons.search_rounded, size: 20, color: AppColors.textTertiary), const SizedBox(width: 8), Text( context.t('home.searchHint'), style: AppTypography.bodyMedium.copyWith(color: AppColors.textTertiary), ), ], ), ), ); } Widget _buildBanner(BuildContext context) { return Container( height: 160, margin: const EdgeInsets.fromLTRB(20, 8, 20, 0), child: PageView.builder( itemCount: 3, itemBuilder: (context, index) { final colors = [ AppColors.primaryGradient, AppColors.successGradient, AppColors.cardGradient, ]; final titleKeys = ['home.bannerNewUser', 'home.bannerDiscount', 'home.bannerHot']; final subtitleKeys = ['home.bannerNewUserDesc', 'home.bannerDiscountDesc', 'home.bannerHotDesc']; return Container( margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( gradient: colors[index], borderRadius: AppSpacing.borderRadiusLg, ), padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.end, children: [ Text( context.t(titleKeys[index]), style: AppTypography.h1.copyWith(color: Colors.white), ), const SizedBox(height: 4), Text( context.t(subtitleKeys[index]), style: AppTypography.bodyMedium.copyWith( color: Colors.white.withValues(alpha: 0.8), ), ), ], ), ); }, ), ); } Widget _buildCategoryGrid(BuildContext context) { final categoryKeys = [ ('home.dining', Icons.restaurant_rounded, AppColors.couponDining), ('home.shopping', Icons.shopping_bag_rounded, AppColors.couponShopping), ('home.entertainment', Icons.sports_esports_rounded, AppColors.couponEntertainment), ('home.travel', Icons.directions_car_rounded, AppColors.couponTravel), ('home.lifestyle', Icons.home_rounded, AppColors.couponOther), ('home.brand', Icons.storefront_rounded, AppColors.primary), ('home.discount', Icons.local_offer_rounded, AppColors.error), ('home.allCategories', Icons.grid_view_rounded, AppColors.textSecondary), ]; return Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 0), child: GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, mainAxisSpacing: 8, crossAxisSpacing: 8, childAspectRatio: 0.85, ), itemCount: categoryKeys.length, itemBuilder: (context, index) { final (key, icon, color) = categoryKeys[index]; return GestureDetector( onTap: () {}, child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 48, height: 48, decoration: BoxDecoration( color: color.withValues(alpha: 0.1), borderRadius: AppSpacing.borderRadiusMd, ), child: Icon(icon, color: color, size: 24), ), const SizedBox(height: 6), Text(context.t(key), style: AppTypography.caption.copyWith( color: AppColors.textPrimary, fontWeight: FontWeight.w500, )), ], ), ); }, ), ); } Widget _buildAiSuggestions(BuildContext context) { return Container( margin: const EdgeInsets.fromLTRB(20, 16, 20, 0), padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColors.primarySurface, borderRadius: AppSpacing.borderRadiusMd, border: Border.all(color: AppColors.primary.withValues(alpha: 0.15)), ), child: Row( children: [ Container( width: 32, height: 32, decoration: BoxDecoration( gradient: AppColors.primaryGradient, borderRadius: AppSpacing.borderRadiusSm, ), child: const Icon(Icons.auto_awesome_rounded, color: Colors.white, size: 16), ), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(context.t('home.aiRecommend'), style: AppTypography.labelSmall.copyWith( color: AppColors.primary, )), const SizedBox(height: 2), Text( context.t('home.aiRecommendDesc'), style: AppTypography.bodySmall, maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), const Icon(Icons.chevron_right_rounded, color: AppColors.primary, size: 20), ], ), ); } } // Mock data const _mockBrands = ['Starbucks', 'Amazon', 'Walmart', 'Target', 'Nike']; const _mockNames = ['星巴克 \$25 礼品卡', 'Amazon \$100 购物券', 'Walmart \$50 生活券', 'Target \$30 折扣券', 'Nike \$80 运动券']; const _mockFaceValues = [25.0, 100.0, 50.0, 30.0, 80.0]; const _mockPrices = [21.25, 85.0, 42.5, 24.0, 68.0]; const _mockRatings = ['AAA', 'AA', 'AAA', 'A', 'AA'];