feat: add day detail screen with swipe-to-delete and undo
Adds DayDetailScreen showing all entries for a selected day with swipe-to-delete and an undo snackbar. CalendarScreen gains a tappable day header (Today / Yesterday / Month Day) that pushes the detail screen.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../core/database/app_database.dart';
|
||||
import '../../core/providers/mood_provider.dart';
|
||||
import 'widgets/day_entry_card.dart';
|
||||
|
||||
const _weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||
const _months = [
|
||||
'January', 'February', 'March', 'April', 'May', 'June',
|
||||
'July', 'August', 'September', 'October', 'November', 'December',
|
||||
];
|
||||
|
||||
class DayDetailScreen extends ConsumerWidget {
|
||||
const DayDetailScreen({super.key, required this.day});
|
||||
|
||||
final DateTime day;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final entriesAsync = ref.watch(moodEntriesForDayProvider(day));
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_appBarTitle(day)),
|
||||
centerTitle: false,
|
||||
),
|
||||
body: entriesAsync.when(
|
||||
data: (entries) => entries.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
'No entries',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: Theme.of(context).colorScheme.outline),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
itemCount: entries.length,
|
||||
itemBuilder: (context, i) => _SwipeToDeleteCard(
|
||||
entry: entries[i],
|
||||
onDelete: () => _deleteWithUndo(context, ref, entries[i]),
|
||||
),
|
||||
),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (_, __) => const SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _deleteWithUndo(BuildContext context, WidgetRef ref, MoodEntry entry) {
|
||||
ref.read(moodEntryNotifierProvider.notifier).deleteEntry(entry.id);
|
||||
ScaffoldMessenger.of(context)
|
||||
..clearSnackBars()
|
||||
..showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text('Entry deleted'),
|
||||
action: SnackBarAction(
|
||||
label: 'Undo',
|
||||
onPressed: () => ref.read(moodEntryNotifierProvider.notifier).addEntry(
|
||||
moodLevel: entry.moodLevel,
|
||||
note: entry.note,
|
||||
timestamp: entry.timestamp,
|
||||
sleepMinutes: entry.sleepMinutes,
|
||||
energyLevel: entry.energyLevel,
|
||||
positivityLevel: entry.positivityLevel,
|
||||
selfWorthLevel: entry.selfWorthLevel,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static String _appBarTitle(DateTime day) {
|
||||
final now = DateTime.now();
|
||||
final today = DateTime(now.year, now.month, now.day);
|
||||
final yesterday = today.subtract(const Duration(days: 1));
|
||||
if (day == today) return 'Today';
|
||||
if (day == yesterday) return 'Yesterday';
|
||||
return '${_weekdays[day.weekday - 1]}, ${day.day} ${_months[day.month - 1]}';
|
||||
}
|
||||
}
|
||||
|
||||
class _SwipeToDeleteCard extends StatelessWidget {
|
||||
const _SwipeToDeleteCard({required this.entry, required this.onDelete});
|
||||
|
||||
final MoodEntry entry;
|
||||
final VoidCallback onDelete;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
return Dismissible(
|
||||
key: ValueKey(entry.id),
|
||||
direction: DismissDirection.endToStart,
|
||||
onDismissed: (_) => onDelete(),
|
||||
background: Container(
|
||||
alignment: Alignment.centerRight,
|
||||
padding: const EdgeInsets.only(right: 24),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: cs.errorContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(Icons.delete_outline, color: cs.onErrorContainer),
|
||||
),
|
||||
child: DayEntryCard(entry: entry),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user