import 'package:flutter/material.dart'; import 'dart:math'; class PhotoPage extends StatelessWidget { const PhotoPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ const PhotoTimeline(), Positioned( top: 0, left: 0, right: 0, child: Container( height: 80, padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), decoration: BoxDecoration( color: Colors.white.withOpacity(0.95), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: const Center( child: Text( 'SnapWish', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.deepPurple, ), ), ), ), ), ], ), ); } } class PhotoTimeline extends StatelessWidget { const PhotoTimeline({super.key}); // 生成带日期的模拟照片数据 Map>> _groupPhotosByDate() { final random = Random(); final now = DateTime.now(); final photos = >[]; // 生成过去30天的模拟数据 for (int i = 0; i < 30; i++) { final date = now.subtract(Duration(days: i)); final photoCount = random.nextInt(5) + 1; // 每天1-5张照片 for (int j = 0; j < photoCount; j++) { photos.add({ 'id': 'photo_${i}_$j', 'title': '照片 ${i * 5 + j + 1}', 'date': date, }); } } // 按日期分组 final grouped = >>{}; for (final photo in photos) { final date = photo['date'] as DateTime; final key = _formatDateKey(date); grouped.putIfAbsent(key, () => []).add(photo); } return grouped; } String _formatDateKey(DateTime date) { final now = DateTime.now(); final today = DateTime(now.year, now.month, now.day); final yesterday = today.subtract(const Duration(days: 1)); final dateDay = DateTime(date.year, date.month, date.day); if (dateDay == today) { return '今天'; } else if (dateDay == yesterday) { return '昨天'; } else if (date.year == now.year) { return '${date.month}月${date.day}日'; } else { return '${date.year}年${date.month}月${date.day}日'; } } @override Widget build(BuildContext context) { final groupedPhotos = _groupPhotosByDate(); final sortedKeys = groupedPhotos.keys.toList() ..sort((a, b) { // 将中文日期转换为可排序的格式 final dateA = _parseDateKey(a); final dateB = _parseDateKey(b); return dateB.compareTo(dateA); // 降序排列 }); return ListView.builder( padding: const EdgeInsets.only(top: 88, bottom: 16), itemCount: sortedKeys.length, itemBuilder: (context, index) { final dateKey = sortedKeys[index]; final photos = groupedPhotos[dateKey]!; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( dateKey, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.deepPurple, ), ), ), GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 16), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 4, mainAxisSpacing: 4, childAspectRatio: 1, ), itemCount: photos.length, itemBuilder: (context, photoIndex) { final photo = photos[photoIndex]; return GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => PhotoDetailPage( photos: photos.map((p) => p['title'] as String).toList(), initialIndex: photoIndex, ), ), ); }, child: Container( decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(8), ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.photo, size: 40, color: Colors.grey), const SizedBox(height: 4), Text( photo['title'] as String, style: const TextStyle(fontSize: 12), overflow: TextOverflow.ellipsis, ), ], ), ), ), ); }, ), ], ); }, ); } DateTime _parseDateKey(String key) { final now = DateTime.now(); if (key == '今天') { return now; } else if (key == '昨天') { return now.subtract(const Duration(days: 1)); } else if (key.contains('年')) { // 格式:2024年5月15日 final match = RegExp(r'(\d+)年(\d+)月(\d+)日').firstMatch(key); if (match != null) { return DateTime( int.parse(match.group(1)!), int.parse(match.group(2)!), int.parse(match.group(3)!), ); } } else { // 格式:5月15日 final match = RegExp(r'(\d+)月(\d+)日').firstMatch(key); if (match != null) { return DateTime( now.year, int.parse(match.group(1)!), int.parse(match.group(2)!), ); } } return now; } } class PhotoDetailPage extends StatefulWidget { final List photos; final int initialIndex; const PhotoDetailPage({ super.key, required this.photos, required this.initialIndex, }); @override State createState() => _PhotoDetailPageState(); } class _PhotoDetailPageState extends State { late int _currentIndex; late PageController _pageController; @override void initState() { super.initState(); _currentIndex = widget.initialIndex; _pageController = PageController(initialPage: _currentIndex); } @override void dispose() { _pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, actions: [ IconButton( icon: const Icon(Icons.favorite_border), onPressed: () { // TODO: 实现收藏功能 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('收藏功能待实现')), ); }, ), IconButton( icon: const Icon(Icons.share), onPressed: () { // TODO: 实现分享功能 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('分享功能待实现')), ); }, ), IconButton( icon: const Icon(Icons.delete), onPressed: () { // TODO: 实现删除功能 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('删除功能待实现')), ); }, ), ], ), body: Stack( children: [ PageView.builder( controller: _pageController, itemCount: widget.photos.length, onPageChanged: (index) { setState(() { _currentIndex = index; }); }, itemBuilder: (context, index) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 0.7, color: Colors.grey[800], child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.photo, size: 100, color: Colors.white), const SizedBox(height: 20), Text( widget.photos[index], style: const TextStyle( color: Colors.white, fontSize: 24, ), ), ], ), ), ), ], ), ); }, ), Positioned( bottom: 20, left: 0, right: 0, child: Center( child: Text( '${_currentIndex + 1} / ${widget.photos.length}', style: const TextStyle( color: Colors.white, fontSize: 16, ), ), ), ), ], ), ); } }