import 'version_source_card.dart'; class VersionSourceGroup { final List members; VersionSourceGroup(List members) : assert(members.isNotEmpty), members = List.unmodifiable(members); VersionSourceCardData get representative => members.first; VersionSourceCardData? get activeMember { for (final member in members) { if (member.isCurrent || member.selected) return member; } return null; } bool get hasActiveMember => activeMember != null; bool get hasCurrentMember => members.any((member) => member.isCurrent); List get serverNames => List.unmodifiable([for (final member in members) member.serverName]); VersionSourceCardData get displayData { final visibleMember = activeMember ?? representative; final names = serverNames; final hasCurrent = hasCurrentMember; final hasSelected = !hasCurrent && members.any((member) => member.selected); final serverList = names.join('、'); return VersionSourceCardData( topLabel: visibleMember.topLabel, sizeBytes: visibleMember.sizeBytes, bitrate: visibleMember.bitrate, serverName: visibleMember.serverName, serverKey: visibleMember.serverKey, isCurrent: hasCurrent, selected: hasSelected, onTap: visibleMember.onTap, tooltip: names.length > 1 ? '可用服务器:$serverList' : visibleMember.tooltip, resolutionLabel: visibleMember.resolutionLabel, sourceKey: visibleMember.sourceKey, mergedServerNames: names, ); } } String? versionGroupKeyOf({ required int? sizeBytes, required String resolutionLabel, }) { if (sizeBytes == null || sizeBytes <= 0) return null; return '$sizeBytes|${resolutionLabel.trim().toUpperCase()}'; } List groupVersionEntries( List entries, ) { final groupedMembers = >>{}; final orderedMemberLists = >[]; for (final entry in entries) { final groupKey = versionGroupKeyOf( sizeBytes: entry.sizeBytes, resolutionLabel: entry.resolutionLabel, ); if (groupKey == null) { orderedMemberLists.add([entry]); continue; } final candidateGroups = groupedMembers[groupKey] ?? const []; List? matchingGroup; for (final candidateGroup in candidateGroups) { final alreadyContainsServer = candidateGroup.any( (member) => member.serverKey == entry.serverKey, ); if (!alreadyContainsServer) { matchingGroup = candidateGroup; break; } } if (matchingGroup != null && entry.serverKey.isNotEmpty) { matchingGroup.add(entry); continue; } final newMembers = [entry]; groupedMembers.putIfAbsent(groupKey, () => []).add(newMembers); orderedMemberLists.add(newMembers); } return [ for (final members in orderedMemberLists) VersionSourceGroup(members), ]; }