import 'dart:io' show Platform; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/contracts/library.dart'; import '../../../providers/di_providers.dart'; import '../../../providers/emby_headers_provider.dart'; import '../../../providers/session_provider.dart'; import '../../../shared/mappers/media_image_url.dart'; import '../../../shared/theme/app_theme.dart'; import '../../../shared/widgets/hover_scrollable_row.dart'; import '../../../shared/widgets/media_poster_card.dart'; import 'section_container.dart'; typedef AdditionalPartTap = void Function(EmbyRawItem item); class AdditionalPartsSection extends ConsumerWidget { final String itemId; final bool embedded; final String? serverId; final AdditionalPartTap? onItemTap; final Widget? leading; const AdditionalPartsSection({ super.key, required this.itemId, this.embedded = false, this.serverId, this.onItemTap, this.leading, }); @override Widget build(BuildContext context, WidgetRef ref) { final scopedServerId = serverId; final AsyncValue> asyncItems; final String? baseUrl; final String? token; final Map? imageHeaders; if (scopedServerId != null) { asyncItems = ref.watch( tmdbServerScopedAdditionalPartsProvider(( serverId: scopedServerId, itemId: itemId, )), ); final auth = ref .watch(tmdbServerScopedAuthProvider(scopedServerId)) .value; baseUrl = auth?.baseUrl; token = auth?.token; imageHeaders = auth?.imageHeaders; } else { final session = ref.watch(activeSessionProvider); if (session == null) return const SizedBox.shrink(); asyncItems = ref.watch(additionalPartsDataProvider(itemId)); baseUrl = session.serverUrl; token = session.token; imageHeaders = ref.watch(embyImageHeadersProvider).value; } return asyncItems.when( loading: () => const SizedBox.shrink(), error: (error, stackTrace) => const SizedBox.shrink(), data: (items) { if (items.isEmpty || baseUrl == null || token == null) { return const SizedBox.shrink(); } final hPad = SectionContainer.hPadOf(context); final resolvedBaseUrl = baseUrl; final resolvedToken = token; final isAndroid = Platform.isAndroid; return SectionContainer( title: '附加片段', embedded: embedded, leadingDivider: embedded, leading: leading, child: SizedBox( height: isAndroid ? 210 : 300, child: Theme( data: AppTheme.dark(), child: HoverScrollableRow( builder: (_, controller) => ListView.builder( controller: controller, scrollDirection: Axis.horizontal, padding: EdgeInsets.symmetric(horizontal: hPad), itemCount: items.length, itemBuilder: (_, i) { final item = items[i]; final imageUrl = EmbyImageUrl.primary( baseUrl: resolvedBaseUrl, token: resolvedToken, item: item, maxHeight: 480, ); return Padding( padding: EdgeInsets.only( right: i < items.length - 1 ? 12 : 0, ), child: MediaPosterCard( item: item, imageUrl: imageUrl, width: isAndroid ? 105 : 160, showHoverPlayIcon: false, enableContextMenu: false, imageHeaders: imageHeaders, onTap: () { final tap = onItemTap; if (tap != null) { tap(item); } else { context.pushReplacement( '/media/${item.Id}', extra: item, ); } }, ), ); }, ), ), ), ), ); }, ); } }