diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 0ec1d04..e9474c1 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1,4 +1,5 @@ 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'; @@ -127,16 +128,29 @@ class _HomeScreenState extends State { ), ), // Activity list - SliverList( - delegate: SliverChildBuilderDelegate( - (ctx, i) => _ActivityCard( - key: ValueKey(_filteredActivities[i].id), - activity: _filteredActivities[i], - onTap: () => Navigator.push(context, MaterialPageRoute( - builder: (_) => ActivityDetailScreen(activity: _filteredActivities[i]), - )), - ), - childCount: _filteredActivities.length, + 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)), @@ -156,92 +170,103 @@ class _HomeScreenState extends State { class _ActivityCard extends StatefulWidget { final Activity activity; + final double imageHeight; final VoidCallback onTap; - const _ActivityCard({super.key, required this.activity, required this.onTap}); + const _ActivityCard({ + super.key, + required this.activity, + required this.imageHeight, + required this.onTap, + }); @override State<_ActivityCard> createState() => _ActivityCardState(); } class _ActivityCardState extends State<_ActivityCard> { - bool _isJoined = false; - - String _categoryEmoji(String cat) { - const map = {'太极':'🧘','茶话会':'🍵','书法':'✍️','摄影':'📷','舞蹈':'💃','户外徒步':'🥾','手工':'🎨','唱歌':'🎵','棋牌':'♟️','读书':'📚','晨练':'🏃'}; - return map[cat] ?? '🎯'; - } - - void _joinActivity() { - setState(() { - _isJoined = true; - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('报名成功!')), - ); - } - @override Widget build(BuildContext context) { final activity = widget.activity; - final canJoin = !activity.isFull && !_isJoined; - final buttonText = _isJoined - ? '已报名' - : (activity.isFull ? '已满员' : '报名'); - - return Card( - margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), + return Material( + color: Colors.transparent, child: InkWell( onTap: widget.onTap, - borderRadius: BorderRadius.circular(16), - child: Padding( - padding: const EdgeInsets.all(16), + 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: [ - Row( - children: [ - Text(_categoryEmoji(activity.category), style: const TextStyle(fontSize: 24)), - const SizedBox(width: 8), - Expanded(child: Text(activity.title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), maxLines: 1, overflow: TextOverflow.ellipsis)), - ], + 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), + ), + ), ), - const SizedBox(height: 12), - Row( - children: [ - const Icon(Icons.access_time, size: 16, color: Color(0xFF999999)), - const SizedBox(width: 4), - Text(activity.timeDisplay, style: const TextStyle(fontSize: 16, color: Color(0xFF666666))), - const SizedBox(width: 16), - const Icon(Icons.location_on_outlined, size: 16, color: Color(0xFF999999)), - const SizedBox(width: 4), - Text(activity.distance != null ? '距你${activity.distance}km' : '', style: const TextStyle(fontSize: 16, color: Color(0xFF666666))), - ], - ), - const SizedBox(height: 12), - Row( - children: [ - Expanded( - child: Text( - '已报名 ${activity.currentParticipants}/${activity.maxParticipants}人', - style: TextStyle( - fontSize: 16, - color: activity.isFull ? const Color(0xFFF44336) : const Color(0xFF4CAF50), - fontWeight: FontWeight.w500, + 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), ), ), - ), - SizedBox( - height: 40, - child: ElevatedButton( - onPressed: canJoin ? _joinActivity : null, - style: ElevatedButton.styleFrom( - minimumSize: const Size(80, 40), - padding: const EdgeInsets.symmetric(horizontal: 20), - ), - child: Text(buttonText, style: const TextStyle(fontSize: 16)), + 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), + ), + ), + ], ), - ), - ], + ], + ), ), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index c9102be..c3f645a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: banxiang_app description: 伴享 -version: 1.1.6+8 +version: 1.1.7+9 environment: sdk: '>=3.0.0 <4.0.0' diff --git a/releases/banxiang-v1.1.7+9.apk b/releases/banxiang-v1.1.7+9.apk new file mode 100644 index 0000000..7c2b11a Binary files /dev/null and b/releases/banxiang-v1.1.7+9.apk differ