diff --git a/app/lib/features/calendar/views/calendar_page.dart b/app/lib/features/calendar/views/calendar_page.dart index 86ff7a2..bc14fff 100644 --- a/app/lib/features/calendar/views/calendar_page.dart +++ b/app/lib/features/calendar/views/calendar_page.dart @@ -9,6 +9,7 @@ import 'package:nuanji_app/core/theme/app_radius.dart'; import 'package:nuanji_app/core/utils/mood_utils.dart'; import 'package:nuanji_app/data/models/journal_entry.dart'; import 'package:nuanji_app/data/repositories/journal_repository.dart'; +import '../../../widgets/error_state_widget.dart'; import '../bloc/calendar_bloc.dart'; /// 日历页面 — 月视图(心情色彩) + 周视图 + 时间轴 @@ -41,21 +42,11 @@ class _CalendarView extends StatelessWidget { } if (state is CalendarError) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.error_outline, size: 48, color: colorScheme.error), - const SizedBox(height: 16), - Text(state.message, style: theme.textTheme.bodyLarge), - const SizedBox(height: 16), - FilledButton.tonal( - onPressed: () => context.read() - .add(CalendarMonthChanged(DateTime.now())), - child: const Text('重试'), - ), - ], - ), + return ErrorStateWidget( + message: state.message, + onRetry: () => context.read() + .add(CalendarMonthChanged(DateTime.now())), + icon: Icons.error_outline, ); } diff --git a/app/lib/features/class_/views/class_page.dart b/app/lib/features/class_/views/class_page.dart index d69154d..b50819c 100644 --- a/app/lib/features/class_/views/class_page.dart +++ b/app/lib/features/class_/views/class_page.dart @@ -9,6 +9,8 @@ import 'package:nuanji_app/data/models/journal_entry.dart'; import 'package:nuanji_app/data/models/school_class.dart'; import 'package:nuanji_app/data/repositories/class_repository.dart'; import 'package:nuanji_app/data/repositories/journal_repository.dart'; +import '../../../widgets/empty_state_widget.dart'; +import '../../../widgets/error_state_widget.dart'; import '../../auth/bloc/auth_bloc.dart'; import '../bloc/class_bloc.dart'; import '../widgets/comment_bottom_sheet.dart'; @@ -46,7 +48,10 @@ class _ClassView extends StatelessWidget { if (state is ClassError) { return Scaffold( appBar: AppBar(title: const Text('班级')), - body: Center(child: Text(state.message)), + body: ErrorStateWidget( + message: state.message, + onRetry: () => context.read().add(const ClassLoadMyClasses()), + ), ); } @@ -93,22 +98,11 @@ class _ClassListView extends StatelessWidget { } Widget _buildEmptyState(BuildContext context, ColorScheme colorScheme) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.groups_outlined, size: 64, color: colorScheme.onSurface.withValues(alpha: 0.2)), - const SizedBox(height: 16), - Text('还没有加入任何班级', style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: colorScheme.onSurface.withValues(alpha: 0.5), - )), - const SizedBox(height: 24), - FilledButton.tonal( - onPressed: () => context.go('/class-code'), - child: const Text('输入班级码加入'), - ), - ], - ), + return EmptyStateWidget( + icon: Icons.group_add_rounded, + title: '还没有加入班级', + actionLabel: '通过班级码加入', + onAction: () => context.go('/class-code'), ); } } @@ -250,21 +244,11 @@ class _DiaryWallTab extends StatelessWidget { } if (state.diaryWall.isEmpty) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(Icons.auto_stories_outlined, size: 48, color: colorScheme.onSurface.withValues(alpha: 0.2)), - const SizedBox(height: 12), - Text('日记墙还是空的', style: theme.textTheme.bodyLarge?.copyWith( - color: colorScheme.onSurface.withValues(alpha: 0.5), - )), - const SizedBox(height: 8), - Text('分享你的日记到班级吧!', style: theme.textTheme.bodySmall?.copyWith( - color: colorScheme.onSurface.withValues(alpha: 0.3), - )), - ], - ), + return const EmptyStateWidget( + icon: Icons.auto_stories_rounded, + title: '日记墙还是空的', + subtitle: '分享你的日记到这里吧', + iconSize: 48, ); } @@ -441,10 +425,9 @@ class _TopicsTab extends StatelessWidget { final colorScheme = theme.colorScheme; if (topics.isEmpty) { - return Center( - child: Text('暂无主题布置', style: theme.textTheme.bodyLarge?.copyWith( - color: colorScheme.onSurface.withValues(alpha: 0.5), - )), + return const EmptyStateWidget( + icon: Icons.assignment_outlined, + title: '暂无主题布置', ); } diff --git a/app/lib/features/discover/views/discover_page.dart b/app/lib/features/discover/views/discover_page.dart index 4949ada..b77b223 100644 --- a/app/lib/features/discover/views/discover_page.dart +++ b/app/lib/features/discover/views/discover_page.dart @@ -19,6 +19,8 @@ import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_radius.dart'; import '../../../core/theme/app_shadows.dart'; import '../../../core/theme/app_typography.dart'; +import '../../../widgets/empty_state_widget.dart'; +import '../../../widgets/error_state_widget.dart'; import '../bloc/discover_bloc.dart'; import '../models/discover_models.dart'; @@ -126,66 +128,19 @@ class DiscoverPage extends StatelessWidget { /// 错误状态 Widget _buildError(BuildContext context, String message) { - return Column( - children: [ - const _LoadingSkeleton(height: 140), - const SizedBox(height: DesignTokens.spacing24), - Container( - width: double.infinity, - padding: const EdgeInsets.all(DesignTokens.spacing16), - decoration: BoxDecoration( - color: AppColors.rose.withValues(alpha: 0.1), - borderRadius: AppRadius.mdBorder, - ), - child: Column( - children: [ - Icon(Icons.cloud_off_rounded, - size: 32, color: AppColors.rose), - const SizedBox(height: DesignTokens.spacing8), - Text(message, - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.onSurfaceVariant), - textAlign: TextAlign.center), - const SizedBox(height: DesignTokens.spacing12), - TextButton.icon( - onPressed: () => context - .read() - .add(const DiscoverLoadData()), - icon: const Icon(Icons.refresh_rounded, size: 18), - label: const Text('重试'), - ), - ], - ), - ), - ], + return ErrorStateWidget( + message: message, + onRetry: () => + context.read().add(const DiscoverLoadData()), ); } /// 空数据提示 Widget _buildEmptyHint(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: DesignTokens.spacing32), - child: Center( - child: Column( - children: [ - const Text('✨', style: TextStyle(fontSize: 40)), - const SizedBox(height: DesignTokens.spacing12), - Text('还没有发现内容', - style: TextStyle( - fontSize: 15, - color: Theme.of(context).colorScheme.onSurfaceVariant, - )), - const SizedBox(height: 4), - Text('写下你的第一篇日记,出现在这里吧!', - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.onSurfaceVariant - .withValues(alpha: 0.7), - )), - ], - ), - ), + return const EmptyStateWidget( + icon: Icons.explore_rounded, + title: '还没有发现内容', + subtitle: '试试写一篇日记分享给大家吧', ); } diff --git a/app/lib/features/stickers/views/sticker_library_page.dart b/app/lib/features/stickers/views/sticker_library_page.dart index f29f812..c241c51 100644 --- a/app/lib/features/stickers/views/sticker_library_page.dart +++ b/app/lib/features/stickers/views/sticker_library_page.dart @@ -5,6 +5,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:nuanji_app/core/theme/app_colors.dart'; import 'package:nuanji_app/core/theme/app_radius.dart'; import 'package:nuanji_app/data/remote/api_client.dart'; +import '../../../widgets/empty_state_widget.dart'; +import '../../../widgets/error_state_widget.dart'; import '../bloc/sticker_bloc.dart'; /// 贴纸库页面 — 分类浏览贴纸包 @@ -64,18 +66,10 @@ class _StickerLibraryPageState extends State { } if (state.errorMessage != null) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.error_outline, size: 48, color: colorScheme.error), - const SizedBox(height: 16), - FilledButton.tonal( - onPressed: _bloc.load, - child: const Text('重试'), - ), - ], - ), + return ErrorStateWidget( + message: state.errorMessage ?? '加载失败', + onRetry: _bloc.load, + icon: Icons.error_outline, ); } @@ -169,7 +163,10 @@ class _StickerLibraryPageState extends State { // ---- 贴纸包网格 ---- Expanded( child: state.filteredPacks.isEmpty - ? const Center(child: Text('暂无贴纸包')) + ? const EmptyStateWidget( + icon: Icons.sticky_note_2_outlined, + title: '暂无贴纸包', + ) : GridView.builder( padding: const EdgeInsets.all(16), gridDelegate: