fix:按照shadcn_ui对着demo_shadcn对齐
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user