优化日历界面

This commit is contained in:
DelLevin-Home
2026-08-09 14:46:50 +08:00
parent ca95a27b2b
commit 6d76c33672

View File

@@ -1,9 +1,9 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../providers/app_provider.dart'; import '../../providers/app_provider.dart';
import '../../models/data_models.dart'; import '../../models/data_models.dart';
import '../../utils/user_prefs.dart'; import '../../utils/user_prefs.dart';
import '../../widgets/fade_in_local_image.dart';
import '../movies/movie_detail_page.dart'; import '../movies/movie_detail_page.dart';
import '../movies/movie_form_page.dart'; import '../movies/movie_form_page.dart';
import '../book/book_detail_page.dart'; import '../book/book_detail_page.dart';
@@ -120,33 +120,21 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
_buildDateModeToggle(colors), _buildDateModeToggle(colors),
], ],
), ),
body: Column( body: LayoutBuilder(
children: [ builder: (context, constraints) {
_buildMonthHeader(colors), // 日历区域固定,详情区独立滚动
_buildWeekdayLabels(colors), final calendar = _buildCalendarArea(colors, today, constraints.maxWidth);
Expanded( return Column(
child: _selectedDay != null && (_dayItems[_selectedDay]?.isNotEmpty ?? false) children: [
? Column( _buildMonthHeader(colors),
children: [ _buildWeekdayLabels(colors),
SingleChildScrollView( calendar,
child: _buildCalendarGrid(colors, today), Expanded(
), child: _buildSelectedDayDetail(colors),
Expanded( ),
child: _buildSelectedDayDetail(colors), ],
), );
], },
)
: SingleChildScrollView(
child: Column(
children: [
_buildCalendarGrid(colors, today),
if (_selectedDay != null) _buildSelectedDayDetail(colors),
const SizedBox(height: 80),
],
),
),
),
],
), ),
floatingActionButton: _selectedDay != null floatingActionButton: _selectedDay != null
? FloatingActionButton( ? FloatingActionButton(
@@ -202,9 +190,28 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
// ─── 日历网格 ─── // ─── 日历网格 ───
static const double _cellHeight = 62; /// 日历区域:横滑切月 + cell 自适应
Widget _buildCalendarArea(ColorScheme colors, DateTime today, double maxWidth) {
// 可用宽度去掉左右 padding8+8每行 7 格
final cellSize = ((maxWidth - 16) / 7).clamp(44.0, 76.0);
Widget _buildCalendarGrid(ColorScheme colors, DateTime today) { // 横滑切月手势
return GestureDetector(
onHorizontalDragEnd: (details) {
final v = details.primaryVelocity;
if (v == null) return;
const threshold = 300.0;
if (v < -threshold) {
_nextMonth();
} else if (v > threshold) {
_prevMonth();
}
},
child: _buildCalendarGrid(colors, today, cellSize),
);
}
Widget _buildCalendarGrid(ColorScheme colors, DateTime today, double cellSize) {
final firstDay = DateTime(_currentMonth.year, _currentMonth.month, 1); final firstDay = DateTime(_currentMonth.year, _currentMonth.month, 1);
final lastDay = DateTime(_currentMonth.year, _currentMonth.month + 1, 0); final lastDay = DateTime(_currentMonth.year, _currentMonth.month + 1, 0);
final startOffset = firstDay.weekday - 1; final startOffset = firstDay.weekday - 1;
@@ -217,7 +224,7 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
child: Column( child: Column(
children: List.generate(rows, (row) { children: List.generate(rows, (row) {
return SizedBox( return SizedBox(
height: _cellHeight, height: cellSize,
child: Row( child: Row(
children: List.generate(7, (col) { children: List.generate(7, (col) {
final index = row * 7 + col; final index = row * 7 + col;
@@ -251,25 +258,38 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
? colors.surfaceContainerHigh ? colors.surfaceContainerHigh
: null, : null,
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
border: isToday border: isSelected
? Border.all(color: colors.primary, width: 1.5) ? Border.all(color: colors.primary.withValues(alpha: 0.3), width: 1)
: isSelected : null,
? Border.all(color: colors.primary.withValues(alpha: 0.3), width: 1)
: null,
), ),
child: hasItems child: hasItems
? _buildImageCell(colors, day, items, isToday) ? _buildImageCell(colors, day, items, isToday)
: Center( : Stack(
child: Text( children: [
'$day', Center(
style: TextStyle( child: Text(
fontSize: 13, '$day',
fontWeight: isToday ? FontWeight.w600 : FontWeight.normal, style: TextStyle(
color: isToday fontSize: 13,
? colors.primary fontWeight: isToday ? FontWeight.w600 : FontWeight.normal,
: colors.onSurface.withValues(alpha: 0.35), color: isToday
? colors.primary
: colors.onSurface.withValues(alpha: 0.35),
),
),
), ),
), if (isToday)
Positioned(
top: 4, left: 4,
child: Container(
width: 6, height: 6,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colors.primary,
),
),
),
],
), ),
), ),
); );
@@ -281,10 +301,11 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
child: Stack( child: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
Image( FadeInLocalImage(
image: FileImage(File(items.first.path)), path: items.first.path,
fit: BoxFit.cover, fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Container( duration: const Duration(milliseconds: 250),
errorWidget: Container(
color: colors.surfaceContainerHighest, color: colors.surfaceContainerHighest,
child: Center(child: Icon(Icons.image_outlined, size: 16, color: colors.onSurface.withValues(alpha: 0.2))), child: Center(child: Icon(Icons.image_outlined, size: 16, color: colors.onSurface.withValues(alpha: 0.2))),
), ),
@@ -324,6 +345,18 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
child: Text('+${items.length - 1}', style: const TextStyle(fontSize: 9, fontWeight: FontWeight.w600, color: Colors.white)), child: Text('+${items.length - 1}', style: const TextStyle(fontSize: 9, fontWeight: FontWeight.w600, color: Colors.white)),
), ),
), ),
// 今日小圆点(左上角)
if (isToday)
Positioned(
top: 4, left: 4,
child: Container(
width: 6, height: 6,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFFFFD54F),
),
),
),
], ],
), ),
); );
@@ -332,6 +365,9 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
// ─── 选中日期的详情 ─── // ─── 选中日期的详情 ───
Widget _buildSelectedDayDetail(ColorScheme colors) { Widget _buildSelectedDayDetail(ColorScheme colors) {
if (_selectedDay == null) {
return const SizedBox.shrink();
}
final items = _dayItems[_selectedDay] ?? []; final items = _dayItems[_selectedDay] ?? [];
if (items.isEmpty) { if (items.isEmpty) {
return Container( return Container(
@@ -379,10 +415,11 @@ class _MediaCalendarPageState extends State<MediaCalendarPage> {
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
child: SizedBox( child: SizedBox(
width: 40, height: 40, width: 40, height: 40,
child: Image( child: FadeInLocalImage(
image: FileImage(File(item.path)), path: item.path,
fit: BoxFit.cover, fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Container( duration: const Duration(milliseconds: 250),
errorWidget: Container(
color: colors.surfaceContainerHighest, color: colors.surfaceContainerHighest,
child: Icon(Icons.image_outlined, size: 16, color: colors.onSurface.withValues(alpha: 0.2)), child: Icon(Icons.image_outlined, size: 16, color: colors.onSurface.withValues(alpha: 0.2)),
), ),