refactor(app): 迁移 4 个页面到共享 EmptyStateWidget + ErrorStateWidget
迁移统计: - discover_page: _buildError → ErrorStateWidget, _buildEmptyHint → EmptyStateWidget - sticker_library_page: 错误 + 空列表 → 共享组件 - class_page: 错误/班级列表空/日记墙空/话题空 → 共享组件 (4 处) - calendar_page: CalendarError → ErrorStateWidget 统一体验: 所有页面空状态使用一致的 icon + title + subtitle + CTA 布局
This commit is contained in:
@@ -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<CalendarBloc>()
|
||||
.add(CalendarMonthChanged(DateTime.now())),
|
||||
child: const Text('重试'),
|
||||
),
|
||||
],
|
||||
),
|
||||
return ErrorStateWidget(
|
||||
message: state.message,
|
||||
onRetry: () => context.read<CalendarBloc>()
|
||||
.add(CalendarMonthChanged(DateTime.now())),
|
||||
icon: Icons.error_outline,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ClassBloc>().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: '暂无主题布置',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<DiscoverBloc>()
|
||||
.add(const DiscoverLoadData()),
|
||||
icon: const Icon(Icons.refresh_rounded, size: 18),
|
||||
label: const Text('重试'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
return ErrorStateWidget(
|
||||
message: message,
|
||||
onRetry: () =>
|
||||
context.read<DiscoverBloc>().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: '试试写一篇日记分享给大家吧',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<StickerLibraryPage> {
|
||||
}
|
||||
|
||||
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<StickerLibraryPage> {
|
||||
// ---- 贴纸包网格 ----
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user