import 'package:flutter/cupertino.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:provider/provider.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import '../../../../modules/room/seat/sc_seat_item.dart'; class RoomSeatWidget extends StatefulWidget { const RoomSeatWidget({super.key}); @override State createState() => _RoomSeatWidgetState(); } class _RoomSeatWidgetState extends State { static const int _defaultVoiceRoomSeatCount = 10; int _lastSeatCount = 0; int _normalizeSeatCount(int? seatCount) { switch (seatCount) { case 5: case 10: case 15: case 20: return seatCount ?? 0; default: return 0; } } int _resolvedSeatCount(_RoomSeatLayoutSnapshot snapshot) { final int liveSeatCount = _normalizeSeatCount(snapshot.seatCount); final int configuredSeatCount = _normalizeSeatCount( snapshot.configuredSeatCount, ); final int seatCount = liveSeatCount > 0 ? liveSeatCount : configuredSeatCount; if (!snapshot.isExitingCurrentVoiceRoomSession && seatCount > 0) { _lastSeatCount = seatCount; } if (snapshot.isExitingCurrentVoiceRoomSession && _lastSeatCount > 0) { return _lastSeatCount; } if (snapshot.hasCurrentRoom && seatCount == 0) { return _lastSeatCount > 0 ? _lastSeatCount : _defaultVoiceRoomSeatCount; } return seatCount; } int _seatCountFromMicIndexes(Iterable micIndexes) { var maxIndex = -1; var count = 0; for (final micIndex in micIndexes) { count += 1; final resolvedIndex = micIndex.toInt(); if (resolvedIndex > maxIndex) { maxIndex = resolvedIndex; } } final indexedSeatCount = _normalizeSeatCount(maxIndex + 1); if (indexedSeatCount > 0) { return indexedSeatCount; } return _normalizeSeatCount(count); } int _seatContentVersion(RtcProvider provider) { var version = provider.roomWheatMap.length; final micIndexes = provider.roomWheatMap.keys.toList()..sort((a, b) => a.compareTo(b)); for (final micIndex in micIndexes) { final seat = provider.micAtIndexForDisplay(micIndex); final user = seat?.user; version = Object.hash( version, micIndex, seat?.micLock ?? false, seat?.micMute ?? false, user?.id ?? "", user?.userAvatar ?? "", user?.userNickname ?? "", user?.roles ?? "", user?.getHeaddress()?.sourceUrl ?? "", user?.getHeaddress()?.cover ?? "", user?.getVIP()?.name ?? "", ); } return version; } @override Widget build(BuildContext context) { return Selector( selector: (context, provider) => _RoomSeatLayoutSnapshot( seatCount: _seatCountFromMicIndexes(provider.roomWheatMap.keys), seatContentVersion: _seatContentVersion(provider), configuredSeatCount: provider.currenRoom?.roomProfile?.roomSetting?.mikeSize ?.toInt() ?? provider.previewRoomSeatCount ?? 0, hasCurrentRoom: provider.currenRoom != null, isExitingCurrentVoiceRoomSession: provider.isExitingCurrentVoiceRoomSession, ), builder: (context, snapshot, child) { final int seatCount = _resolvedSeatCount(snapshot); return seatCount == 5 ? _buildSeat5() : (seatCount == 10 ? _buildSeat10() : (seatCount == 15 ? _buildSeat15() : (seatCount == 20 ? _buildSeat20() : Container(height: 180.w)))); }, ); } _buildSeat5() { return Container( margin: EdgeInsets.only(top: 3.w, left: 10.w, right: 10.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 0)), Expanded(flex: 1, child: SCSeatItem(index: 1)), Expanded(flex: 1, child: SCSeatItem(index: 2)), Expanded(flex: 1, child: SCSeatItem(index: 3)), Expanded(flex: 1, child: SCSeatItem(index: 4)), ], ), ], ), ); } _buildSeat10() { return Container( margin: EdgeInsets.only(top: 3.w, left: 10.w, right: 10.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 0)), Expanded(flex: 1, child: SCSeatItem(index: 1)), Expanded(flex: 1, child: SCSeatItem(index: 2)), Expanded(flex: 1, child: SCSeatItem(index: 3)), Expanded(flex: 1, child: SCSeatItem(index: 4)), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(flex: 1, child: SCSeatItem(index: 5)), Expanded(flex: 1, child: SCSeatItem(index: 6)), Expanded(flex: 1, child: SCSeatItem(index: 7)), Expanded(flex: 1, child: SCSeatItem(index: 8)), Expanded(flex: 1, child: SCSeatItem(index: 9)), ], ), ], ), ); } _buildSeat15() { return Container( margin: EdgeInsets.only(top: 3.w, left: 10.w, right: 10.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 0)), Expanded(flex: 1, child: SCSeatItem(index: 1)), Expanded(flex: 1, child: SCSeatItem(index: 2)), Expanded(flex: 1, child: SCSeatItem(index: 3)), Expanded(flex: 1, child: SCSeatItem(index: 4)), ], ), Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 5)), Expanded(flex: 1, child: SCSeatItem(index: 6)), Expanded(flex: 1, child: SCSeatItem(index: 7)), Expanded(flex: 1, child: SCSeatItem(index: 8)), Expanded(flex: 1, child: SCSeatItem(index: 9)), ], ), Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 10)), Expanded(flex: 1, child: SCSeatItem(index: 11)), Expanded(flex: 1, child: SCSeatItem(index: 12)), Expanded(flex: 1, child: SCSeatItem(index: 13)), Expanded(flex: 1, child: SCSeatItem(index: 14)), ], ), ], ), ); } _buildSeat20() { return Container( margin: EdgeInsets.only(top: 3.w, left: 10.w, right: 10.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 0)), Expanded(flex: 1, child: SCSeatItem(index: 1)), Expanded(flex: 1, child: SCSeatItem(index: 2)), Expanded(flex: 1, child: SCSeatItem(index: 3)), Expanded(flex: 1, child: SCSeatItem(index: 4)), ], ), Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 5)), Expanded(flex: 1, child: SCSeatItem(index: 6)), Expanded(flex: 1, child: SCSeatItem(index: 7)), Expanded(flex: 1, child: SCSeatItem(index: 8)), Expanded(flex: 1, child: SCSeatItem(index: 9)), ], ), Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 10)), Expanded(flex: 1, child: SCSeatItem(index: 11)), Expanded(flex: 1, child: SCSeatItem(index: 12)), Expanded(flex: 1, child: SCSeatItem(index: 13)), Expanded(flex: 1, child: SCSeatItem(index: 14)), ], ), Row( children: [ Expanded(flex: 1, child: SCSeatItem(index: 15)), Expanded(flex: 1, child: SCSeatItem(index: 16)), Expanded(flex: 1, child: SCSeatItem(index: 17)), Expanded(flex: 1, child: SCSeatItem(index: 18)), Expanded(flex: 1, child: SCSeatItem(index: 19)), ], ), ], ), ); } } class _RoomSeatLayoutSnapshot { const _RoomSeatLayoutSnapshot({ required this.seatCount, required this.seatContentVersion, required this.configuredSeatCount, required this.hasCurrentRoom, required this.isExitingCurrentVoiceRoomSession, }); final int seatCount; final int seatContentVersion; final int configuredSeatCount; final bool hasCurrentRoom; final bool isExitingCurrentVoiceRoomSession; @override bool operator ==(Object other) { if (identical(this, other)) { return true; } return other is _RoomSeatLayoutSnapshot && other.seatCount == seatCount && other.seatContentVersion == seatContentVersion && other.configuredSeatCount == configuredSeatCount && other.hasCurrentRoom == hasCurrentRoom && other.isExitingCurrentVoiceRoomSession == isExitingCurrentVoiceRoomSession; } @override int get hashCode => Object.hash( seatCount, seatContentVersion, configuredSeatCount, hasCurrentRoom, isExitingCurrentVoiceRoomSession, ); }