// 首页 — 日记流 + 心情概览 import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:nuanji_app/core/theme/app_colors.dart'; import 'package:nuanji_app/data/models/journal_entry.dart'; import 'package:nuanji_app/data/repositories/journal_repository.dart'; import '../bloc/home_bloc.dart'; /// 首页 — 展示最近日记流和心情概览 class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => HomeBloc( journalRepository: context.read(), )..add(const HomeLoadData()), child: const _HomeView(), ); } } class _HomeView extends StatelessWidget { const _HomeView(); @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; return BlocBuilder( builder: (context, state) { return Scaffold( appBar: AppBar( title: Text( '暖记', style: theme.textTheme.headlineSmall?.copyWith( fontFamily: 'Caveat', color: colorScheme.primary, ), ), actions: [ IconButton( onPressed: () => context.go('/stickers'), icon: const Icon(Icons.emoji_emotions_outlined), tooltip: '贴纸库', ), IconButton( onPressed: () => context.go('/templates'), icon: const Icon(Icons.dashboard_customize_outlined), tooltip: '模板', ), ], ), body: state is HomeLoading ? const Center(child: CircularProgressIndicator()) : state is HomeLoaded ? _buildContent(context, state) : _buildContent(context, const HomeLoaded()), ); }, ); } Widget _buildContent(BuildContext context, HomeLoaded state) { return RefreshIndicator( onRefresh: () async { context.read().add(const HomeRefresh()); }, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 心情快速选择卡片 _QuickMoodCard( hasTodayEntry: state.hasTodayEntry, topMood: state.topMood, streakDays: state.streakDays, ), const SizedBox(height: 20), // 最近日记 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '最近日记', style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), ), TextButton( onPressed: () => context.go('/calendar'), child: const Text('查看全部'), ), ], ), const SizedBox(height: 12), state.recentJournals.isEmpty ? const _EmptyJournalState() : _JournalList(journals: state.recentJournals), ], ), ), ); } } /// 心情快速选择卡片 class _QuickMoodCard extends StatelessWidget { const _QuickMoodCard({ required this.hasTodayEntry, this.topMood, this.streakDays = 0, }); final bool hasTodayEntry; final Mood? topMood; final int streakDays; @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; final moods = [ ('😊', '开心', Mood.happy), ('😌', '平静', Mood.calm), ('😢', '难过', Mood.sad), ('😠', '生气', Mood.angry), ('🤔', '思考', Mood.thinking), ]; return Card( elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(22)), color: colorScheme.primaryContainer.withValues(alpha: 0.3), child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('今天心情如何?', style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600)), const Spacer(), if (streakDays > 0) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: AppColors.tertiary.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(8), ), child: Text('🔥 连续 $streakDays 天', style: theme.textTheme.labelSmall), ), if (hasTodayEntry) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: AppColors.secondary.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(8), ), child: Text('✅ 今日已写', style: theme.textTheme.labelSmall), ), ], ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: moods.map((mood) { final isTop = topMood == mood.$3; return GestureDetector( onTap: () => context.push('/editor'), child: Column( children: [ Container( width: 44, height: 44, decoration: BoxDecoration( shape: BoxShape.circle, color: (AppColors.moodColors[mood.$3.value] ?? colorScheme.primary) .withValues(alpha: isTop ? 0.3 : 0.15), border: isTop ? Border.all(color: AppColors.accent, width: 2) : null, ), alignment: Alignment.center, child: Text(mood.$1, style: const TextStyle(fontSize: 22)), ), const SizedBox(height: 4), Text(mood.$2, style: theme.textTheme.labelSmall?.copyWith( color: colorScheme.onSurface.withValues(alpha: 0.6), )), ], ), ); }).toList(), ), ], ), ), ); } } /// 日记列表 class _JournalList extends StatelessWidget { const _JournalList({required this.journals}); final List journals; @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; return Column( children: journals.map((journal) { final moodColor = AppColors.moodColors[journal.mood.value] ?? colorScheme.primary; return Card( margin: const EdgeInsets.only(bottom: 12), elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide(color: colorScheme.outlineVariant), ), child: InkWell( onTap: () => context.push('/editor?id=${journal.id}'), borderRadius: BorderRadius.circular(16), child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Container( width: 40, height: 40, decoration: BoxDecoration( color: moodColor.withValues(alpha: 0.2), shape: BoxShape.circle, ), alignment: Alignment.center, child: Text(_moodEmoji(journal.mood), style: const TextStyle(fontSize: 20)), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(journal.title, style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600), maxLines: 1, overflow: TextOverflow.ellipsis), const SizedBox(height: 4), Text('${journal.date.month}月${journal.date.day}日', style: theme.textTheme.bodySmall?.copyWith( color: colorScheme.onSurface.withValues(alpha: 0.5)), ), ], ), ), Icon(Icons.chevron_right, color: colorScheme.onSurface.withValues(alpha: 0.3)), ], ), ), ), ); }).toList(), ); } String _moodEmoji(Mood mood) => switch (mood) { Mood.happy => '😊', Mood.calm => '😌', Mood.sad => '😢', Mood.angry => '😠', Mood.thinking => '🤔', }; } /// 空日记状态 class _EmptyJournalState extends StatelessWidget { const _EmptyJournalState(); @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; return Center( child: Padding( padding: const EdgeInsets.symmetric(vertical: 48), child: Column( children: [ Icon(Icons.edit_note_rounded, size: 64, color: colorScheme.onSurface.withValues(alpha: 0.2)), const SizedBox(height: 16), Text('开始你的第一篇手账日记吧!', style: theme.textTheme.bodyLarge?.copyWith(color: colorScheme.onSurface.withValues(alpha: 0.5))), const SizedBox(height: 24), FilledButton.icon( onPressed: () => context.push('/editor'), icon: const Icon(Icons.add_rounded), label: const Text('写日记'), ), ], ), ), ); } }