// Author: fruit.com.cn import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../core/data/models/drama.dart'; import '../../core/data/services/catalog_controller.dart'; import '../../core/formatting/count_format.dart'; import '../../core/theme/app_colors.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/empty_state.dart'; import '../../core/widgets/plain_page_scaffold.dart'; import '../../core/widgets/remote_image.dart'; import '../../l10n/app_localizations.dart'; import '../drama_detail/drama_detail_view.dart'; const int _topCount = 50; const double _rankColumnWidth = 56; const double _coverWidth = 72; const double _coverHeight = 96; const double _rowGap = 12; const Color _rankSilver = Color(0xFFB8860B); const Color _rankBronze = Color(0xFF8C837B); /// 剧场榜单页:按播放量降序展示 TOP 榜单。 class RankingPage extends StatelessWidget { const RankingPage({super.key}); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final dramas = [...context.read().dramas] ..sort((a, b) => b.viewCount.compareTo(a.viewCount)); final top = dramas.take(_topCount).toList(); return PlainPageScaffold( pageKey: const Key('ranking-page'), backKey: const Key('ranking-back'), title: l10n.topCharts, subtitle: l10n.rankingSubtitle, child: top.isEmpty ? EmptyState(icon: Icons.leaderboard_outlined, title: l10n.noStories) : ListView.separated( padding: const EdgeInsets.fromLTRB(14, 4, 14, 24), itemCount: top.length, separatorBuilder: (_, _) => const SizedBox(height: _rowGap), itemBuilder: (context, index) => _RankingRow(index: index, drama: top[index], l10n: l10n), ), ); } } class _RankingRow extends StatelessWidget { const _RankingRow({ required this.index, required this.drama, required this.l10n, }); final int index; final Drama drama; final AppLocalizations l10n; int get _rank => index + 1; Color get _rankColor => switch (_rank) { 1 => AppColors.blue, 2 => _rankSilver, 3 => _rankBronze, _ => AppColors.subtle, }; double get _rankSize => _rank == 1 ? 22 : (_rank <= 3 ? 20 : 18); @override Widget build(BuildContext context) { final genre = drama.genre.isEmpty ? drama.category : drama.genre; return Container( decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(14), boxShadow: const [AppTheme.cardShadow], ), child: Material( color: Colors.transparent, borderRadius: BorderRadius.circular(14), clipBehavior: Clip.antiAlias, child: InkWell( key: Key('ranking-row-$index'), onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => DramaDetailPage(drama: drama)), ), child: Padding( padding: const EdgeInsets.all(10), child: Row( children: [ SizedBox( width: _rankColumnWidth, child: Text( l10n.topLabel(_rank), key: Key('ranking-top-$_rank'), textAlign: TextAlign.center, maxLines: 1, style: TextStyle( color: _rankColor, fontSize: _rankSize, fontWeight: FontWeight.w900, ), ), ), ClipRRect( borderRadius: BorderRadius.circular(10), child: SizedBox( width: _coverWidth, height: _coverHeight, child: RemoteImage( drama.posterUrl, fit: BoxFit.cover, showFallbackIcon: true, fallbackAspectRatio: 3 / 4, ), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( drama.title, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.onSurface, fontSize: 15, fontWeight: FontWeight.w700, ), ), if (genre.isNotEmpty) ...[ const SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: AppColors.raised, borderRadius: BorderRadius.circular(6), ), child: Text( genre, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.muted, fontSize: 11, ), ), ), ], const SizedBox(height: 8), Row( children: [ const Icon( Icons.local_fire_department_rounded, color: AppColors.blue, size: 12, ), const SizedBox(width: 4), Flexible( child: Text( l10n.heatLabel( formatInteractionCount(drama.viewCount), ), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.muted, fontSize: 11, ), ), ), ], ), ], ), ), ], ), ), ), ), ); } }