import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../data/api/report_data_source.dart'; import '../../data/content_providers.dart'; import '../../data/models/models.dart'; import '../../routing/app_routes.dart'; import '../../theme/app_icons.dart'; import '../../theme/yanting_text.dart'; import '../../theme/yanting_tokens.dart'; import '../../widgets/app_card.dart'; import '../../widgets/badges.dart'; import '../../widgets/mini_player.dart'; import '../../widgets/page_header.dart'; import '../../widgets/states.dart'; import '../shared/report_card_widget.dart'; class HomePage extends HookConsumerWidget { const HomePage({ required this.dataSource, required this.onPlay, this.player = const PlayerStateModel(), this.onStartModuleAudio, this.onToggleAudio, this.onSeekAudio, this.onSpeed, super.key, }); final ReportDataSource dataSource; final void Function(AudioItem item) onPlay; final PlayerStateModel player; final void Function( String audioId, String reportId, String title, int durationSec, )? onStartModuleAudio; final VoidCallback? onToggleAudio; final void Function(int delta)? onSeekAudio; final VoidCallback? onSpeed; @override Widget build(BuildContext context, WidgetRef ref) { final snapshot = ref.watch(recommendedReportsProvider); return snapshot.when( loading: () => const LoadingState(), error: (error, _) => ErrorState( message: error.toString(), onRetry: () => ref.invalidate(recommendedReportsProvider), ), data: (items) { return SingleChildScrollView( padding: const EdgeInsets.fromLTRB( YantingSpacing.screenX, 4, YantingSpacing.screenX, 16, ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const PageHeader(title: '研听', subtitle: '全球机构研报中文解读'), const SectionTitle(title: '推荐'), if (items.isEmpty) const EmptyState(title: '暂无可推荐的研报解读', message: '稍后再来看看最新内容') else ReportCardWidget( report: items.first, hero: true, onTap: () => openReportDetail( context, dataSource, items.first, player: player, onStartAudio: onStartModuleAudio, onToggleAudio: onToggleAudio, onSeekAudio: onSeekAudio, onSpeed: onSpeed, ), onPlayTap: () => _playFromReport(onPlay, items.first), ), const SizedBox(height: YantingSpacing.x6), for (final item in _directoryItems) Padding( padding: const EdgeInsets.only(bottom: 8), child: _DirectoryCard(item: item), ), ], ), ); }, ); } } class _DirectoryItem { const _DirectoryItem({ required this.title, required this.subtitle, required this.icon, required this.path, }); final String title; final String subtitle; final IconData icon; final String path; } class _DirectoryCard extends StatelessWidget { const _DirectoryCard({required this.item}); final _DirectoryItem item; @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); return AppCard( onTap: () => context.push(item.path), padding: const EdgeInsets.all(16), child: Row( children: [ Container( width: 44, height: 44, decoration: BoxDecoration( color: theme.colorScheme.secondary, borderRadius: BorderRadius.circular(8), ), child: Icon( item.icon, size: 20, color: theme.colorScheme.secondaryForeground, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Flexible( child: Text(item.title, style: YantingText.listTitle), ), if (item.title == '推荐') ...[ const SizedBox(width: 8), const AppBadge(text: '首页', kind: BadgeKind.tier), ], ], ), const SizedBox(height: 2), Text(item.subtitle, style: YantingText.meta), ], ), ), Icon( LucideIcons.chevronRight, size: 16, color: theme.colorScheme.mutedForeground, ), ], ), ); } } const _directoryItems = [ _DirectoryItem( title: '推荐', subtitle: '主题筛选后的重点研报解读', icon: AppIcons.sparkle, path: AppRoutes.home, ), _DirectoryItem( title: '研报', subtitle: '搜索、筛选和浏览全部研报', icon: AppIcons.article, path: AppRoutes.reports, ), _DirectoryItem( title: '机构', subtitle: '按机构查看来源与覆盖主题', icon: AppIcons.bank, path: AppRoutes.institutions, ), _DirectoryItem( title: '听单', subtitle: '继续收听音频解读', icon: AppIcons.headphones, path: AppRoutes.listen, ), _DirectoryItem( title: '我的', subtitle: '登录、收藏与合规说明', icon: AppIcons.user, path: AppRoutes.profile, ), ]; void _playFromReport( void Function(AudioItem item) onPlay, ReportCardModel report, ) { onPlay( AudioItem( audioId: 'local_${report.id}', reportId: report.id, titleCn: report.titleCn, reportTitleCn: report.titleCn, durationSec: 180, institution: report.institution, ), ); }