Files
xianyan/lib/core/layout/overview_dashboard.dart
Developer ca68fe29c7 chore: 批量整理优化项目代码与配置
- 新增模型目录占位文件与翻译类型拆分
- 调整路由配置与桌面端窗口初始化
- 移除多处冗余图表配置项
- 重构右侧面板注册表与三栏布局组件
- 添加智能AppBar、拖拽书签等新功能组件
- 优化安卓编译配置与多平台插件注册
- 新增翻译覆盖率测试与共享组件
- 格式化代码与修复静态分析警告
2026-05-29 10:08:02 +08:00

344 lines
12 KiB
Dart

/// ============================================================
/// 闲言APP — 概览仪表盘
/// 创建时间: 2026-05-29
/// 更新时间: 2026-05-29
/// 作用: 宽屏分屏右侧面板的空状态页面,显示概览信息
/// 上次更新: 快捷操作和数据统计添加flutter_staggered_animations交错入场动画
/// ============================================================
import 'package:flutter/cupertino.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../theme/app_theme.dart';
import '../theme/app_spacing.dart';
import '../../shared/widgets/containers/glass_container.dart';
import '../../features/home/providers/home_provider.dart';
import '../../features/home/providers/favorite_provider.dart';
import '../../features/home/providers/likes_provider.dart';
import '../../features/auth/providers/auth_provider.dart';
import '../../features/mine/signin/providers/signin_provider.dart';
import '../router/app_routes.dart';
import '../router/app_nav_extension.dart';
class OverviewDashboard extends ConsumerWidget {
const OverviewDashboard({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return SingleChildScrollView(
padding: const EdgeInsets.all(AppSpacing.md),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildGreeting(context),
const SizedBox(height: AppSpacing.lg),
_buildTodayRecommend(context, ref),
const SizedBox(height: AppSpacing.lg),
_buildQuickActions(context),
const SizedBox(height: AppSpacing.lg),
_buildRecentHistory(context),
const SizedBox(height: AppSpacing.lg),
_buildStats(context, ref),
const SizedBox(height: AppSpacing.xxl),
],
),
);
}
Widget _buildGreeting(BuildContext context) {
final ext = AppTheme.ext(context);
final hour = DateTime.now().hour;
final greeting = switch (hour) {
>= 6 && < 12 => '早上好 ☀️',
>= 12 && < 14 => '中午好 🌤️',
>= 14 && < 18 => '下午好 🌅',
>= 18 && < 22 => '晚上好 🌙',
_ => '夜深了 🌛',
};
return GlassContainer(
depth: GlassDepth.elevated,
padding: const EdgeInsets.all(AppSpacing.lg),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
greeting,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: ext.textPrimary,
),
),
const SizedBox(height: AppSpacing.xs),
Text(
'选择左侧内容查看详情',
style: TextStyle(fontSize: 14, color: ext.textSecondary),
),
],
),
),
],
),
);
}
Widget _buildTodayRecommend(BuildContext context, WidgetRef ref) {
final ext = AppTheme.ext(context);
final homeState = ref.watch(homeProvider);
final recommends = homeState.dailySentences;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'✨ 今日推荐',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: ext.textPrimary,
),
),
const SizedBox(height: AppSpacing.sm),
SizedBox(
height: 120,
child: recommends.isEmpty
? GlassContainer(
padding: const EdgeInsets.all(AppSpacing.md),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('📭', style: TextStyle(fontSize: 28)),
const SizedBox(height: AppSpacing.xs),
Text(
'暂无推荐内容',
style: TextStyle(fontSize: 13, color: ext.textHint),
),
],
),
),
)
: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: recommends.length,
separatorBuilder: (_, __) =>
const SizedBox(width: AppSpacing.sm),
itemBuilder: (context, index) {
final sentence = recommends[index];
return GlassContainer(
width: 180,
padding: const EdgeInsets.all(AppSpacing.md),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
sentence.text,
style: TextStyle(
fontSize: 13,
color: ext.textPrimary,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const Spacer(),
Text(
sentence.author != null
? '—— ${sentence.author}'
: '—— 佚名',
style: TextStyle(fontSize: 11, color: ext.textHint),
),
],
),
);
},
),
),
],
);
}
Widget _buildQuickActions(BuildContext context) {
final ext = AppTheme.ext(context);
final actions = <({String emoji, String label, String route})>[
(emoji: '🔍', label: '搜索', route: AppRoutes.search),
(emoji: '', label: '收藏', route: AppRoutes.favorites),
(emoji: '📖', label: '稍后读', route: AppRoutes.readLater),
(emoji: '🕐', label: '历史', route: AppRoutes.history),
(emoji: '', label: '签到', route: AppRoutes.signin),
(emoji: '📊', label: '阅读报告', route: AppRoutes.readingReport),
(emoji: '🌤️', label: '每日推荐', route: AppRoutes.dailyCard),
(emoji: '⚙️', label: '设置', route: AppRoutes.generalSettings),
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'🚀 快捷操作',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: ext.textPrimary,
),
),
const SizedBox(height: AppSpacing.sm),
AnimationLimiter(
child: Wrap(
spacing: AppSpacing.sm,
runSpacing: AppSpacing.sm,
children: actions.asMap().entries.map((entry) {
return AnimationConfiguration.staggeredList(
position: entry.key,
duration: const Duration(milliseconds: 375),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: GestureDetector(
onTap: () => context.appPush(entry.value.route),
child: GlassContainer(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(entry.value.emoji,
style: const TextStyle(fontSize: 16)),
const SizedBox(width: AppSpacing.xs),
Text(
entry.value.label,
style: TextStyle(
fontSize: 13, color: ext.textPrimary),
),
],
),
),
),
),
),
);
}).toList(),
),
),
],
);
}
Widget _buildRecentHistory(BuildContext context) {
final ext = AppTheme.ext(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'🕐 最近浏览',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: ext.textPrimary,
),
),
const SizedBox(height: AppSpacing.sm),
GlassContainer(
padding: const EdgeInsets.all(AppSpacing.md),
child: Center(
child: Column(
children: [
const Text('📭', style: TextStyle(fontSize: 32)),
const SizedBox(height: AppSpacing.sm),
Text(
'暂无浏览记录',
style: TextStyle(fontSize: 13, color: ext.textHint),
),
],
),
),
),
],
);
}
Widget _buildStats(BuildContext context, WidgetRef ref) {
final ext = AppTheme.ext(context);
final authState = ref.watch(authProvider);
final favoriteState = ref.watch(favoriteProvider);
final likesState = ref.watch(likesProvider);
final signinState = ref.watch(signinProvider);
final readCount = authState.user?.signinDays ?? 0;
final favCount = favoriteState.total;
final likeCount = likesState.total;
final streakDays = signinState.continuous;
final stats = [
('📖', '阅读', '$readCount'),
('', '收藏', '$favCount'),
('👍', '点赞', '$likeCount'),
('🔥', '连续', '$streakDays天'),
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'📊 数据统计',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: ext.textPrimary,
),
),
const SizedBox(height: AppSpacing.sm),
AnimationLimiter(
child: Row(
children: stats.asMap().entries.map((entry) {
final stat = entry.value;
return AnimationConfiguration.staggeredList(
position: entry.key,
duration: const Duration(milliseconds: 375),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Expanded(
child: GlassContainer(
padding: const EdgeInsets.all(AppSpacing.sm),
margin: const EdgeInsets.symmetric(
horizontal: AppSpacing.xs / 2,
),
child: Column(
children: [
Text(stat.$1, style: const TextStyle(fontSize: 20)),
const SizedBox(height: 4),
Text(
stat.$3,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: ext.textPrimary,
),
),
Text(
stat.$2,
style: TextStyle(fontSize: 11, color: ext.textHint),
),
],
),
),
),
),
),
);
}).toList(),
),
),
],
);
}
}