import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../../data/api/report_data_source.dart'; import '../../data/content_providers.dart'; import '../../data/models/models.dart'; import '../../data/providers.dart'; import '../../routing/app_routes.dart'; import '../../theme/yanting_tokens.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 FeedPage extends HookConsumerWidget { const FeedPage({ 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 currentTopic = ref.watch(recommendTopicProvider); final snapshot = ref.watch(recommendedByTopicProvider); const topics = ['全部', '宏观', '贵金属', '大宗', '能源', '跨资产', '央行']; return snapshot.when( loading: () => const LoadingState(), error: (error, _) => ErrorState( message: error.toString(), onRetry: () => ref.invalidate(recommendedByTopicProvider), ), data: (items) { if (items.isEmpty) { return EmptyState( title: currentTopic == '全部' ? '暂无可推荐的研报解读' : '当前主题暂无内容', message: currentTopic == '全部' ? '稍后再来看看最新内容' : '换个主题,或去研报页看看全部内容', icon: currentTopic == '全部' ? Icons.inbox_outlined : Icons.filter_alt_off, ); } return ListView( padding: const EdgeInsets.fromLTRB( YantingSpacing.screenX, 4, YantingSpacing.screenX, 16, ), children: [ const PageHeader(title: '研听', subtitle: '全球机构研报中文解读'), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ for (final t in topics) Padding( padding: const EdgeInsets.only(right: YantingSpacing.x2), child: AppChip( label: t, selected: t == currentTopic, onTap: () => ref.read(recommendTopicProvider.notifier).select(t), ), ), ], ), ), const SizedBox(height: YantingSpacing.cardGap), ReportCardWidget( report: items.first, hero: true, onTap: () { ref .read(profileControllerProvider.notifier) .addHistory(items.first.id); openReportDetail( context, dataSource, items.first, player: player, onStartAudio: onStartModuleAudio, onToggleAudio: onToggleAudio, onSeekAudio: onSeekAudio, onSpeed: onSpeed, ); }, onPlayTap: () => _playFromReport(onPlay, items.first), ), const SizedBox(height: YantingSpacing.sectionGap), const SectionTitle(title: '最新解读', icon: Icons.chevron_right), for (final report in items.skip(1)) ...[ ReportCardWidget( report: report, onTap: () { ref .read(profileControllerProvider.notifier) .addHistory(report.id); openReportDetail( context, dataSource, report, player: player, onStartAudio: onStartModuleAudio, onToggleAudio: onToggleAudio, onSeekAudio: onSeekAudio, onSpeed: onSpeed, ); }, onPlayTap: () => _playFromReport(onPlay, report), ), const SizedBox(height: YantingSpacing.x3), ], ], ); }, ); } } 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, ), ); }