import 'dart:io' show Platform; import 'package:flutter/material.dart'; import '../../../core/contracts/tmdb.dart'; import '../../../shared/utils/media_nav.dart'; import '../../../shared/widgets/hover_scrollable_row.dart'; import '../../../shared/widgets/section_header.dart'; import '../../../shared/widgets/tmdb_poster_card.dart'; class TmdbRecommendationSection extends StatelessWidget { final List items; final String imageBaseUrl; final String fallbackMediaType; final Widget? leading; const TmdbRecommendationSection({ super.key, required this.items, required this.imageBaseUrl, required this.fallbackMediaType, this.leading, }); @override Widget build(BuildContext context) { if (items.isEmpty) return const SizedBox.shrink(); final list = items.length > 20 ? items.sublist(0, 20) : items; final isAndroid = Platform.isAndroid; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (leading != null) leading!, const Padding( padding: EdgeInsets.fromLTRB(0, 16, 0, 4), child: SectionHeader(label: '推荐'), ), SizedBox( height: isAndroid ? 210 : 280, child: HoverScrollableRow( builder: (_, controller) => ListView.separated( controller: controller, scrollDirection: Axis.horizontal, padding: EdgeInsets.zero, itemCount: list.length, separatorBuilder: (_, _) => const SizedBox(width: 12), itemBuilder: (_, i) { final item = list[i]; final type = item.mediaType ?? fallbackMediaType; final tappable = type == 'movie' || type == 'tv'; return TmdbPosterCard( title: item.title, posterPath: item.posterPath, voteAverage: item.voteAverage, mediaTypeLabel: _typeLabel(item.mediaType), imageBaseUrl: imageBaseUrl, width: isAndroid ? 105 : 150, onTap: tappable ? () => goTmdbDetail( context, tmdbId: item.id, mediaType: type, seed: item, ) : null, ); }, ), ), ), ], ); } static String? _typeLabel(String? mediaType) => switch (mediaType) { 'tv' => '剧集', 'movie' => '电影', _ => null, }; }