import 'package:flutter/material.dart'; import "package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart"; import '../models/activity.dart'; import '../services/activity_service.dart'; import '../utils/constants.dart'; import 'activity_detail_screen.dart'; import 'create_activity_screen.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { String _selectedCategory = '全部'; String _timeFilter = '全部'; List _activities = []; bool _loading = true; @override void initState() { super.initState(); _loadActivities(); } void _loadActivities() { setState(() { _activities = ActivityService.getMockActivities(); _loading = false; }); } List get _filteredActivities { return _activities.where((a) { if (_selectedCategory != '全部' && a.category != _selectedCategory) return false; if (_timeFilter == '今天') { return DateUtils.isSameDay(a.time, DateTime.now()); } if (_timeFilter == '明天') { final tomorrow = DateTime.now().add(const Duration(days: 1)); return DateUtils.isSameDay(a.time, tomorrow); } return true; }).toList(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.location_on, size: 18, color: Color(0xFF1976D2)), const SizedBox(width: 4), const Text('成都', style: TextStyle(fontSize: 16, color: Color(0xFF666666))), const SizedBox(width: 16), Expanded( child: Container( height: 36, decoration: BoxDecoration( color: const Color(0xFFF5F5F5), borderRadius: BorderRadius.circular(18), ), child: const Row( children: [ SizedBox(width: 12), Icon(Icons.search, size: 20, color: Color(0xFF999999)), SizedBox(width: 8), Text('搜索活动', style: TextStyle(fontSize: 14, color: Color(0xFF999999))), ], ), ), ), ], ), ), body: _loading ? const Center(child: CircularProgressIndicator()) : RefreshIndicator( onRefresh: () async => _loadActivities(), child: CustomScrollView( slivers: [ // Category chips SliverToBoxAdapter( child: SizedBox( height: 48, child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16), children: AppConstants.activityCategories.map((cat) { final selected = _selectedCategory == cat; return Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(cat, style: TextStyle(fontSize: 14, color: selected ? Colors.white : const Color(0xFF666666))), selected: selected, selectedColor: const Color(0xFF1976D2), backgroundColor: const Color(0xFFF5F5F5), onSelected: (_) => setState(() => _selectedCategory = cat), ), ); }).toList(), ), ), ), // Time filter SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( children: ['全部', '今天', '明天', '本周'].map((t) { final selected = _timeFilter == t; return Padding( padding: const EdgeInsets.only(right: 12), child: GestureDetector( onTap: () => setState(() => _timeFilter = t), child: Text(t, style: TextStyle( fontSize: 16, color: selected ? const Color(0xFF1976D2) : const Color(0xFF999999), fontWeight: selected ? FontWeight.w600 : FontWeight.normal, )), ), ); }).toList(), ), ), ), // Activity list SliverToBoxAdapter( child: MasonryGridView.count( crossAxisCount: 2, mainAxisSpacing: 10, crossAxisSpacing: 10, padding: const EdgeInsets.all(12), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _filteredActivities.length, itemBuilder: (ctx, index) { final activity = _filteredActivities[index]; return _ActivityCard( key: ValueKey(activity.id), activity: activity, imageHeight: index.isOdd ? 160.0 : 210.0, onTap: () => Navigator.push( context, MaterialPageRoute( builder: (_) => ActivityDetailScreen(activity: activity), ), ), ); }, ), ), const SliverToBoxAdapter(child: SizedBox(height: 80)), ], ), ), floatingActionButton: FloatingActionButton.extended( onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const CreateActivityScreen())), icon: const Icon(Icons.add), label: const Text('发起活动', style: TextStyle(fontSize: 16)), backgroundColor: const Color(0xFF1976D2), foregroundColor: Colors.white, ), ); } } class _ActivityCard extends StatefulWidget { final Activity activity; final double imageHeight; final VoidCallback onTap; const _ActivityCard({ super.key, required this.activity, required this.imageHeight, required this.onTap, }); @override State<_ActivityCard> createState() => _ActivityCardState(); } class _ActivityCardState extends State<_ActivityCard> { @override Widget build(BuildContext context) { final activity = widget.activity; return Material( color: Colors.transparent, child: InkWell( onTap: widget.onTap, borderRadius: BorderRadius.circular(12), child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.06), blurRadius: 6, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12), ), child: Image.network( "https://picsum.photos/seed/${activity.title.hashCode.abs()}/400/300", height: widget.imageHeight, width: double.infinity, fit: BoxFit.cover, errorBuilder: (_, __, ___) => Container( height: widget.imageHeight, color: const Color(0xFFE0E0E0), ), ), ), Padding( padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( activity.title, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w700, color: Color(0xFF333333), ), ), const SizedBox(height: 4), Row( children: [ CircleAvatar( radius: 10, backgroundImage: NetworkImage( "https://i.pravatar.cc/40?img=${activity.category.hashCode.abs() % 40 + 1}", ), ), const SizedBox(width: 4), Text( activity.category, style: const TextStyle( fontSize: 12, color: Color(0xFF999999), ), ), const Spacer(), Text( "${activity.currentParticipants}人", style: const TextStyle( fontSize: 12, color: Color(0xFFFF6B35), ), ), ], ), ], ), ), ], ), ), ), ); } }