fix:优化使用常用技术框架

This commit is contained in:
jingyun
2026-06-03 16:29:53 +08:00
parent e93356e849
commit e2554edfab
22 changed files with 1319 additions and 661 deletions
+64 -46
View File
@@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.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 '../../routing/app_routes.dart';
import '../../theme/wise_tokens.dart';
@@ -9,7 +12,7 @@ import '../../widgets/mini_player.dart';
import '../../widgets/states.dart';
import '../shared/report_card_widget.dart';
class FeedPage extends StatefulWidget {
class FeedPage extends HookConsumerWidget {
const FeedPage({
required this.dataSource,
required this.onPlay,
@@ -30,24 +33,28 @@ class FeedPage extends StatefulWidget {
final VoidCallback? onSpeed;
@override
State<FeedPage> createState() => _FeedPageState();
}
Widget build(BuildContext context, WidgetRef ref) {
final topic = useState('全部');
final snapshot = ref.watch(recommendedReportsProvider);
class _FeedPageState extends State<FeedPage> {
String topic = '全部';
late Future<List<ReportCardModel>> future = widget.dataSource.recommended();
@override
Widget build(BuildContext context) {
return FutureBuilder<List<ReportCardModel>>(
future: future,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) return const LoadingState();
if (snapshot.hasError) return ErrorState(message: snapshot.error.toString(), onRetry: () => setState(() => future = widget.dataSource.recommended()));
final items = snapshot.data ?? const [];
return snapshot.when(
loading: () => const LoadingState(),
error: (error, _) => ErrorState(
message: error.toString(),
onRetry: () => ref.invalidate(recommendedReportsProvider),
),
data: (items) {
final currentTopic = topic.value;
final topics = ['全部', ...{for (final item in items) ...item.topics}];
final visible = topic == '全部' ? items : items.where((item) => item.topics.contains(topic)).toList();
if (items.isEmpty) return const EmptyState(title: '暂无可推荐的研报解读', message: '稍后再来看看最新内容');
final visible = currentTopic == '全部'
? items
: items.where((item) => item.topics.contains(currentTopic)).toList();
if (items.isEmpty) {
return const EmptyState(
title: '暂无可推荐的研报解读',
message: '稍后再来看看最新内容',
);
}
return ListView(
padding: const EdgeInsets.all(WiseSpacing.x4),
children: [
@@ -58,29 +65,37 @@ class _FeedPageState extends State<FeedPage> {
for (final t in topics)
Padding(
padding: const EdgeInsets.only(right: WiseSpacing.x2),
child: AppChip(label: t, selected: t == topic, onTap: () => setState(() => topic = t)),
child: AppChip(
label: t,
selected: t == currentTopic,
onTap: () => topic.value = t,
),
),
],
),
),
const SizedBox(height: WiseSpacing.x3),
if (visible.isEmpty)
EmptyState(title: '暂无可推荐的研报解读', message: '换个主题,或去研报页看看全部内容', icon: Icons.filter_alt_off)
const EmptyState(
title: '暂无可推荐的研报解读',
message: '换个主题,或去研报页看看全部内容',
icon: Icons.filter_alt_off,
)
else ...[
ReportCardWidget(
report: visible.first,
hero: true,
onTap: () => openReportDetail(
context,
widget.dataSource,
dataSource,
visible.first,
player: widget.player,
onStartAudio: widget.onStartModuleAudio,
onToggleAudio: widget.onToggleAudio,
onSeekAudio: widget.onSeekAudio,
onSpeed: widget.onSpeed,
player: player,
onStartAudio: onStartModuleAudio,
onToggleAudio: onToggleAudio,
onSeekAudio: onSeekAudio,
onSpeed: onSpeed,
),
onPlayTap: () => playFromReport(widget.onPlay, visible.first),
onPlayTap: () => _playFromReport(onPlay, visible.first),
),
const SizedBox(height: WiseSpacing.x5),
Text('最新解读', style: Theme.of(context).textTheme.titleMedium),
@@ -90,15 +105,15 @@ class _FeedPageState extends State<FeedPage> {
report: report,
onTap: () => openReportDetail(
context,
widget.dataSource,
dataSource,
report,
player: widget.player,
onStartAudio: widget.onStartModuleAudio,
onToggleAudio: widget.onToggleAudio,
onSeekAudio: widget.onSeekAudio,
onSpeed: widget.onSpeed,
player: player,
onStartAudio: onStartModuleAudio,
onToggleAudio: onToggleAudio,
onSeekAudio: onSeekAudio,
onSpeed: onSpeed,
),
onPlayTap: () => playFromReport(widget.onPlay, report),
onPlayTap: () => _playFromReport(onPlay, report),
),
const SizedBox(height: WiseSpacing.x3),
],
@@ -108,17 +123,20 @@ class _FeedPageState extends State<FeedPage> {
},
);
}
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,
),
);
}
}
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,
),
);
}