snap_wish/lib/pages/photo_page.dart
2025-08-28 20:04:53 +08:00

345 lines
10 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 '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<String, List<Map<String, dynamic>>> _groupPhotosByDate() {
final random = Random();
final now = DateTime.now();
final photos = <Map<String, dynamic>>[];
// 生成过去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 = <String, List<Map<String, dynamic>>>{};
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<String> photos;
final int initialIndex;
const PhotoDetailPage({
super.key,
required this.photos,
required this.initialIndex,
});
@override
State<PhotoDetailPage> createState() => _PhotoDetailPageState();
}
class _PhotoDetailPageState extends State<PhotoDetailPage> {
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,
),
),
),
),
],
),
);
}
}