import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/contracts/library.dart'; import '../../../providers/di_providers.dart'; import '../../../providers/session_provider.dart'; import '../../../shared/utils/cross_server_search_key.dart'; import 'media_info_section.dart'; import 'multi_source_section.dart'; class SourceSelectionSection extends ConsumerWidget { final CrossServerSearchReq? req; final List localSources; final int selectedSourceIdx; final CrossServerSourceCard? selectedCrossServerCard; final String? currentServerName; final String? excludedServerIdOverride; final EmbyRawItem? localMediaInfoItem; final void Function(EmbyRawMediaSource src, int index) onLocalSourceTap; final void Function(CrossServerSourceCard card) onCrossServerSourceTap; final String title; final bool showLoadingWhenEmpty; final bool externalLoading; final String loadingText; final Widget? leading; const SourceSelectionSection({ super.key, required this.req, required this.localSources, required this.selectedSourceIdx, required this.selectedCrossServerCard, required this.onLocalSourceTap, required this.onCrossServerSourceTap, this.currentServerName, this.excludedServerIdOverride, this.localMediaInfoItem, this.title = '多源聚合', this.showLoadingWhenEmpty = false, this.externalLoading = false, this.loadingText = '正在查找可用版本…', this.leading, }); @override Widget build(BuildContext context, WidgetRef ref) { final searchReq = req; final card = selectedCrossServerCard; final currentLocalSourceId = card == null && selectedSourceIdx < localSources.length ? localSources[selectedSourceIdx].Id : null; final selectedCrossServerKey = card != null ? '${card.serverId}|${card.mediaSourceId}' : null; final EmbyRawMediaSource? mediaSource = card?.mediaSource ?? (selectedSourceIdx < localSources.length ? localSources[selectedSourceIdx] : null); final EmbyRawItem? mediaItem = card?.item ?? localMediaInfoItem; final multiSourceVisibility = searchReq == null ? _MultiSourceVisibility.hidden : _multiSourceVisibility(ref, searchReq); final mediaInfo = mediaSource != null && mediaItem != null && MediaInfoSection.hasVisibleContent( item: mediaItem, selectedSource: mediaSource, ) ? MediaInfoSection( item: mediaItem, selectedSource: mediaSource, embedded: true, ) : null; final bool hasContent = multiSourceVisibility != _MultiSourceVisibility.hidden || mediaInfo != null; if (!hasContent) return const SizedBox.shrink(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (leading != null) ...[leading!, const SizedBox(height: 16)], if (searchReq != null) MultiSourceSection( req: searchReq, embedded: true, localSources: localSources, currentLocalSourceId: currentLocalSourceId, currentServerName: currentServerName, excludedServerIdOverride: excludedServerIdOverride, selectedCrossServerKey: selectedCrossServerKey, title: title, showLoadingWhenEmpty: showLoadingWhenEmpty, externalLoading: externalLoading, loadingText: loadingText, onLocalSourceTap: onLocalSourceTap, onSourceTap: (serverId, itemId, {mediaSourceId, card}) async { if (card != null) onCrossServerSourceTap(card); }, ), if (mediaInfo != null) mediaInfo, ], ); } _MultiSourceVisibility _multiSourceVisibility( WidgetRef ref, CrossServerSearchReq searchReq, ) { final session = ref.watch(activeSessionProvider); if (session == null) return _MultiSourceVisibility.hidden; final key = ( activeServerId: session.serverId, anchorType: searchReq.anchorType, providerIdQuery: encodeProviderIdsForKey(searchReq.providerIds), seriesProviderIdQuery: encodeProviderIdsForKey( searchReq.seriesProviderIds ?? const {}, ), parentIndexNumber: searchReq.parentIndexNumber ?? -1, indexNumber: searchReq.indexNumber ?? -1, itemName: searchReq.itemName, excludedServerId: excludedServerIdOverride ?? session.serverId, ); final asyncResult = ref.watch(crossServerSearchDataProvider(key)); final remoteCards = asyncResult.maybeWhen( data: (list) => list, orElse: () => asyncResult.value ?? const [], ); if (localSources.isNotEmpty || remoteCards.isNotEmpty) { return _MultiSourceVisibility.content; } final loading = externalLoading || asyncResult.isLoading; if (showLoadingWhenEmpty && loading) return _MultiSourceVisibility.loading; return _MultiSourceVisibility.hidden; } } enum _MultiSourceVisibility { hidden, loading, content }