gcx/frontend/genex-mobile/lib/features/coupons/presentation/pages/home_page.dart

357 lines
13 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.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';
import '../widgets/receive_coupon_sheet.dart';
/// 首页 - 轻量钱包卡 + 分类网格 + AI推荐 + 精选券
///
/// 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,
),
],
),
// Lightweight Wallet Card (replaces heavy wallet)
SliverToBoxAdapter(child: _buildWalletCard(context)),
// Category Grid (8 items, 4x2)
SliverToBoxAdapter(child: _buildCategoryGrid()),
// AI Smart Suggestions
SliverToBoxAdapter(child: _buildAiSuggestions()),
// Section: Featured Coupons
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 24, 20, 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('精选好券', style: AppTypography.h2),
GestureDetector(
onTap: () {},
child: Text('查看全部', 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(
'搜索券、品牌、分类...',
style: AppTypography.bodyMedium.copyWith(color: AppColors.textTertiary),
),
],
),
),
);
}
// ============================================================
// Lightweight Wallet Card
// 点击非快捷入口区域打开完整钱包页面
// ============================================================
Widget _buildWalletCard(BuildContext context) {
return GestureDetector(
onTap: () => Navigator.pushNamed(context, '/wallet/coupons'),
child: Container(
margin: const EdgeInsets.fromLTRB(20, 8, 20, 0),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: AppColors.cardGradient,
borderRadius: AppSpacing.borderRadiusLg,
boxShadow: AppSpacing.shadowPrimary,
),
child: Column(
children: [
// Top row: wallet info + receive button
Row(
children: [
const Icon(Icons.account_balance_wallet_rounded,
size: 20, color: Colors.white),
const SizedBox(width: 8),
Text('我的钱包',
style: AppTypography.labelMedium.copyWith(color: Colors.white)),
const Spacer(),
// Summary
Text('持有 ',
style: AppTypography.bodySmall.copyWith(
color: Colors.white.withValues(alpha: 0.7),
)),
Text('4',
style: AppTypography.h3.copyWith(
color: Colors.white,
fontWeight: FontWeight.w700,
)),
Text(' 张券 总值 ',
style: AppTypography.bodySmall.copyWith(
color: Colors.white.withValues(alpha: 0.7),
)),
Text('\$235',
style: AppTypography.h3.copyWith(
color: Colors.white,
fontWeight: FontWeight.w700,
)),
const SizedBox(width: 4),
Icon(Icons.chevron_right_rounded,
size: 18, color: Colors.white.withValues(alpha: 0.7)),
],
),
const SizedBox(height: 14),
// Quick action entries
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildQuickAction(context, Icons.qr_code_rounded, '接收', () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => const ReceiveCouponSheet(),
);
}),
_buildQuickAction(context, Icons.card_giftcard_rounded, '转赠', () {
Navigator.pushNamed(context, '/transfer');
}),
_buildQuickAction(context, Icons.sell_rounded, '出售', () {
Navigator.pushNamed(context, '/sell');
}),
_buildQuickAction(context, Icons.check_circle_outline_rounded, '核销', () {
Navigator.pushNamed(context, '/redeem');
}),
],
),
],
),
),
);
}
Widget _buildQuickAction(
BuildContext context, IconData icon, String label, VoidCallback onTap) {
return GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.15),
borderRadius: AppSpacing.borderRadiusMd,
),
child: Icon(icon, size: 20, color: Colors.white),
),
const SizedBox(height: 6),
Text(
label,
style: AppTypography.caption.copyWith(
color: Colors.white.withValues(alpha: 0.9),
fontWeight: FontWeight.w500,
),
),
],
),
);
}
// ============================================================
// Category Grid (8 items, 4x2, A+C savings-focused)
// ============================================================
Widget _buildCategoryGrid() {
final categories = [
('限时抢购', Icons.flash_on_rounded, AppColors.error),
('新券首发', Icons.fiber_new_rounded, AppColors.primary),
('折扣排行', Icons.trending_up_rounded, AppColors.couponEntertainment),
('即将到期', Icons.timer_rounded, AppColors.warning),
('比价', Icons.compare_arrows_rounded, AppColors.couponShopping),
('转让市场', Icons.swap_horiz_rounded, AppColors.info),
('热门交易', Icons.local_fire_department_rounded, AppColors.couponDining),
('全部', 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: 4,
crossAxisSpacing: 4,
childAspectRatio: 0.9,
),
itemCount: categories.length,
itemBuilder: (context, index) {
final (name, icon, color) = categories[index];
return GestureDetector(
onTap: () {},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.1),
borderRadius: AppSpacing.borderRadiusMd,
),
child: Icon(icon, color: color, size: 22),
),
const SizedBox(height: 6),
Text(name, style: AppTypography.caption.copyWith(
color: AppColors.textPrimary,
fontWeight: FontWeight.w500,
)),
],
),
);
},
),
);
}
Widget _buildAiSuggestions() {
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('AI 推荐', style: AppTypography.labelSmall.copyWith(
color: AppColors.primary,
)),
const SizedBox(height: 2),
Text(
'根据你的偏好发现了3张高性价比券',
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'];