Initial commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
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<TmdbRecommendation> 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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user