745 lines
21 KiB
Dart
745 lines
21 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
import 'package:yumi/main.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:yumi/shared/tools/sc_network_image_utils.dart';
|
|
import 'package:yumi/shared/tools/sc_room_effect_scheduler.dart';
|
|
import 'package:yumi/shared/tools/sc_entrance_vap_svga_manager.dart';
|
|
import 'package:yumi/services/audio/rtc_manager.dart';
|
|
import 'package:yumi/shared/data_sources/sources/local/data_persistence.dart';
|
|
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/floating/floating_game_screen_widget.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/floating/floating_gift_screen_widget.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/floating/floating_luck_gift_screen_widget.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/floating/floating_room_redenvelope_screen_widget.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/floating/floating_room_rocket_screen_widget.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/floating/floating_vip_entry_screen_widget.dart';
|
|
import 'package:yumi/shared/data_sources/models/message/sc_floating_message.dart';
|
|
import 'package:yumi/ui_kit/widgets/svga/sc_svga_asset_widget.dart';
|
|
|
|
typedef FloatingScreenManager = OverlayManager;
|
|
|
|
class OverlayManager {
|
|
static const int _maxLowPerformanceCompensationQueueLength = 8;
|
|
static const int _maxDeferredRegionRedPacketCount = 12;
|
|
static const Duration _compensationDedupWindow = Duration(seconds: 3);
|
|
static const Duration _redPacketFloatingDedupWindow = Duration(minutes: 30);
|
|
|
|
final SCPriorityQueue<SCFloatingMessage> _messageQueue = SCPriorityQueue(
|
|
(a, b) => b.priority.compareTo(a.priority),
|
|
);
|
|
final List<SCFloatingMessage> _deferredRegionRedPacketMessages = [];
|
|
final Map<String, DateTime> _recentCompensationKeys = {};
|
|
final Map<String, DateTime> _recentFloatingKeys = {};
|
|
bool _isPlaying = false;
|
|
OverlayEntry? _currentOverlayEntry;
|
|
SCFloatingMessage? _currentMessage;
|
|
bool _homeRootTabsVisible = false;
|
|
int _suppressedCount = 0;
|
|
|
|
bool _isProcessing = false;
|
|
bool _isDisposed = false;
|
|
|
|
static final OverlayManager _instance = OverlayManager._internal();
|
|
|
|
factory OverlayManager() => _instance;
|
|
|
|
OverlayManager._internal();
|
|
|
|
void addMessage(SCFloatingMessage message) {
|
|
if (_isDisposed || _isSuppressed) return;
|
|
if (!SCGlobalConfig.isFloatingBroadcastClosed) {
|
|
if (_isRecentFloatingDuplicate(message)) {
|
|
return;
|
|
}
|
|
if (message.type == 4) {}
|
|
_rememberFloatingMessage(message);
|
|
_enqueueMessage(
|
|
message,
|
|
debugLabel: 'floating_message_type_${message.type ?? -1}',
|
|
);
|
|
} else {
|
|
_removeActiveMessage(scheduleNext: false);
|
|
_messageQueue.clear();
|
|
_deferredRegionRedPacketMessages.clear();
|
|
_isPlaying = false;
|
|
_isProcessing = false;
|
|
_isDisposed = false;
|
|
}
|
|
}
|
|
|
|
void addLowPerformanceCompensationMessage(
|
|
SCFloatingMessage message, {
|
|
String? dedupKey,
|
|
}) {
|
|
if (_isDisposed ||
|
|
_isSuppressed ||
|
|
!SCGlobalConfig.isLowPerformanceDevice ||
|
|
SCGlobalConfig.isFloatingBroadcastClosed) {
|
|
return;
|
|
}
|
|
final key = dedupKey ?? _compensationKeyFor(message);
|
|
if (_isRecentCompensationDuplicate(key)) {
|
|
return;
|
|
}
|
|
_rememberCompensationKey(key);
|
|
_trimLowPerformanceCompensationQueue();
|
|
_enqueueMessage(
|
|
message,
|
|
debugLabel: 'low_performance_compensation_${message.type ?? -1}',
|
|
);
|
|
}
|
|
|
|
void _enqueueMessage(
|
|
SCFloatingMessage message, {
|
|
required String debugLabel,
|
|
}) {
|
|
unawaited(_warmMessageImages(message));
|
|
SCRoomEffectScheduler().scheduleDeferredEffect(
|
|
debugLabel: debugLabel,
|
|
action: () {
|
|
if (_isDisposed || _isSuppressed) {
|
|
return;
|
|
}
|
|
_messageQueue.add(message);
|
|
_safeScheduleNext();
|
|
},
|
|
);
|
|
}
|
|
|
|
bool _isRecentCompensationDuplicate(String key) {
|
|
_pruneRecentCompensationKeys();
|
|
final recentTime = _recentCompensationKeys[key];
|
|
if (recentTime == null) {
|
|
return false;
|
|
}
|
|
return DateTime.now().difference(recentTime) < _compensationDedupWindow;
|
|
}
|
|
|
|
void _rememberCompensationKey(String key) {
|
|
_recentCompensationKeys[key] = DateTime.now();
|
|
_pruneRecentCompensationKeys();
|
|
}
|
|
|
|
void _pruneRecentCompensationKeys() {
|
|
final now = DateTime.now();
|
|
_recentCompensationKeys.removeWhere(
|
|
(_, time) => now.difference(time) > _compensationDedupWindow,
|
|
);
|
|
}
|
|
|
|
bool _isRecentFloatingDuplicate(SCFloatingMessage message) {
|
|
_pruneRecentFloatingKeys();
|
|
final key = _floatingDedupKeyFor(message);
|
|
if (key == null) {
|
|
return false;
|
|
}
|
|
final recentTime = _recentFloatingKeys[key];
|
|
if (recentTime == null) {
|
|
return false;
|
|
}
|
|
return DateTime.now().difference(recentTime) <
|
|
_redPacketFloatingDedupWindow;
|
|
}
|
|
|
|
void _rememberFloatingMessage(SCFloatingMessage message) {
|
|
final key = _floatingDedupKeyFor(message);
|
|
if (key == null) {
|
|
return;
|
|
}
|
|
_recentFloatingKeys[key] = DateTime.now();
|
|
_pruneRecentFloatingKeys();
|
|
}
|
|
|
|
void _pruneRecentFloatingKeys() {
|
|
final now = DateTime.now();
|
|
_recentFloatingKeys.removeWhere(
|
|
(_, time) => now.difference(time) > _redPacketFloatingDedupWindow,
|
|
);
|
|
}
|
|
|
|
String? _floatingDedupKeyFor(SCFloatingMessage message) {
|
|
if (message.type == 3) {
|
|
final launchNo = message.giftId?.trim() ?? '';
|
|
if (launchNo.isEmpty) {
|
|
return null;
|
|
}
|
|
return 'room_rocket_launch|$launchNo';
|
|
}
|
|
if (message.type == 4) {
|
|
final packetId = message.toUserId?.trim() ?? '';
|
|
if (packetId.isEmpty) {
|
|
return null;
|
|
}
|
|
return 'room_red_packet|$packetId';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
String _compensationKeyFor(SCFloatingMessage message) {
|
|
return [
|
|
message.type,
|
|
message.roomId,
|
|
message.userId,
|
|
message.toUserId,
|
|
message.giftId,
|
|
message.number,
|
|
message.giftUrl,
|
|
].join('|');
|
|
}
|
|
|
|
void _trimLowPerformanceCompensationQueue() {
|
|
if (_messageQueue.length < _maxLowPerformanceCompensationQueueLength) {
|
|
return;
|
|
}
|
|
final retained =
|
|
_messageQueue.unorderedElements.cast<SCFloatingMessage>().toList()
|
|
..sort((a, b) => b.priority.compareTo(a.priority));
|
|
_messageQueue.clear();
|
|
for (final message in retained.take(
|
|
_maxLowPerformanceCompensationQueueLength - 1,
|
|
)) {
|
|
_messageQueue.add(message);
|
|
}
|
|
}
|
|
|
|
Future<void> _warmMessageImages(SCFloatingMessage message) async {
|
|
unawaited(
|
|
warmImageResource(
|
|
message.userAvatarUrl ?? "",
|
|
logicalWidth: 80,
|
|
logicalHeight: 80,
|
|
),
|
|
);
|
|
unawaited(
|
|
warmImageResource(
|
|
message.toUserAvatarUrl ?? "",
|
|
logicalWidth: 80,
|
|
logicalHeight: 80,
|
|
),
|
|
);
|
|
unawaited(
|
|
warmImageResource(
|
|
message.giftUrl ?? "",
|
|
logicalWidth: message.type == 5 ? 350 : 96,
|
|
logicalHeight: message.type == 5 ? 84 : 96,
|
|
),
|
|
);
|
|
if (message.type == 0) {
|
|
unawaited(_warmLuckyGiftBannerSvga());
|
|
}
|
|
}
|
|
|
|
Future<void> _warmLuckyGiftBannerSvga() async {
|
|
try {
|
|
await SCSvgaAssetWidget.preloadAsset(
|
|
FloatingLuckGiftScreenWidget.backgroundSvgaAssetPath,
|
|
);
|
|
} catch (error) {}
|
|
}
|
|
|
|
void _safeScheduleNext() {
|
|
if (_isSuppressed) return;
|
|
if (_isProcessing || _isPlaying || _messageQueue.isEmpty) return;
|
|
_isProcessing = true;
|
|
|
|
try {
|
|
_scheduleNext();
|
|
} finally {
|
|
_isProcessing = false;
|
|
}
|
|
}
|
|
|
|
void _scheduleNext() {
|
|
if (_isPlaying || _messageQueue.isEmpty || _isDisposed || _isSuppressed) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
final context = navigatorKey.currentState?.context;
|
|
if (context == null || !context.mounted) return;
|
|
|
|
// 安全地获取第一个消息
|
|
if (_messageQueue.isEmpty) return;
|
|
final messageToProcess = _messageQueue.first;
|
|
if (messageToProcess == null) {
|
|
_messageQueue.removeFirst();
|
|
_safeScheduleNext();
|
|
return;
|
|
}
|
|
|
|
if (!_shouldDisplayMessage(context, messageToProcess)) {
|
|
_messageQueue.removeFirst();
|
|
if (_shouldDeferRegionRedPacketMessage(context, messageToProcess)) {
|
|
_deferRegionRedPacketMessage(context, messageToProcess);
|
|
_safeScheduleNext();
|
|
return;
|
|
}
|
|
_logRegionRedPacketDrop(context, messageToProcess);
|
|
_safeScheduleNext();
|
|
return;
|
|
}
|
|
|
|
// 安全地移除并播放消息
|
|
final messageToPlay = _messageQueue.removeFirst();
|
|
_playMessage(messageToPlay);
|
|
} catch (e) {
|
|
_isPlaying = false;
|
|
_safeScheduleNext();
|
|
}
|
|
}
|
|
|
|
void _playMessage(SCFloatingMessage message) {
|
|
_isPlaying = true;
|
|
_currentMessage = message;
|
|
final context = navigatorKey.currentState?.context;
|
|
if (context == null || !context.mounted) {
|
|
_isPlaying = false;
|
|
_currentMessage = null;
|
|
_safeScheduleNext();
|
|
return;
|
|
}
|
|
|
|
_currentOverlayEntry = OverlayEntry(
|
|
builder:
|
|
(_) => Align(
|
|
alignment: AlignmentDirectional.topStart,
|
|
child: Transform.translate(
|
|
offset: Offset(0, 70.w),
|
|
child: RepaintBoundary(child: _buildScreenWidget(message)),
|
|
),
|
|
),
|
|
);
|
|
|
|
Overlay.of(context).insert(_currentOverlayEntry!);
|
|
}
|
|
|
|
Widget _buildScreenWidget(SCFloatingMessage message) {
|
|
bool completed = false;
|
|
|
|
void onComplete() {
|
|
if (completed) return;
|
|
completed = true;
|
|
|
|
try {
|
|
_currentOverlayEntry?.remove();
|
|
_currentOverlayEntry = null;
|
|
_isPlaying = false;
|
|
_currentMessage = null;
|
|
_safeScheduleNext();
|
|
} catch (e) {
|
|
_isPlaying = false;
|
|
_currentMessage = null;
|
|
_safeScheduleNext();
|
|
}
|
|
}
|
|
|
|
switch (message.type) {
|
|
case 0:
|
|
return FloatingLuckGiftScreenWidget(
|
|
message: message,
|
|
onAnimationCompleted: onComplete,
|
|
);
|
|
case 1:
|
|
//房间礼物
|
|
return FloatingGiftScreenWidget(
|
|
message: message,
|
|
onAnimationCompleted: onComplete,
|
|
);
|
|
case 2:
|
|
//游戏中奖
|
|
return FloatingGameScreenWidget(
|
|
message: message,
|
|
onAnimationCompleted: onComplete,
|
|
);
|
|
case 3:
|
|
//火箭
|
|
return FloatingRoomRocketScreenWidget(
|
|
message: message,
|
|
onAnimationCompleted: onComplete,
|
|
);
|
|
case 4:
|
|
//红包
|
|
return FloatingRoomRedenvelopeScreenWidget(
|
|
message: message,
|
|
onAnimationCompleted: onComplete,
|
|
);
|
|
case 5:
|
|
//VIP进房飘窗
|
|
return FloatingVipEntryScreenWidget(
|
|
message: message,
|
|
onAnimationCompleted: onComplete,
|
|
);
|
|
default:
|
|
onComplete();
|
|
return Container();
|
|
}
|
|
}
|
|
|
|
void activate() {
|
|
_isDisposed = false;
|
|
_loadSavedDisplayPreference();
|
|
}
|
|
|
|
void _loadSavedDisplayPreference() {
|
|
final account = AccountStorage().getCurrentUser()?.userProfile?.account;
|
|
final savedFloatingBroadcastScope = DataPersistence.getString(
|
|
SCGlobalConfig.floatingBroadcastScopeStorageKey(account),
|
|
);
|
|
if (savedFloatingBroadcastScope.isNotEmpty) {
|
|
final scope = SCGlobalConfig.clampFloatingBroadcastScope(
|
|
savedFloatingBroadcastScope,
|
|
);
|
|
SCGlobalConfig.floatingBroadcastScope = scope;
|
|
return;
|
|
}
|
|
final defaultEffectsEnabled = !SCGlobalConfig.isLowPerformanceDevice;
|
|
final isLegacyFloatingAnimationInGlobal = DataPersistence.getBool(
|
|
SCGlobalConfig.legacyFloatingAnimationInGlobalStorageKey(account),
|
|
defaultValue: defaultEffectsEnabled,
|
|
);
|
|
SCGlobalConfig.floatingBroadcastScope =
|
|
SCGlobalConfig.clampVisualEffectPreference(
|
|
isLegacyFloatingAnimationInGlobal,
|
|
)
|
|
? SCGlobalConfig.floatingBroadcastScopeAll
|
|
: SCGlobalConfig.floatingBroadcastScopeOff;
|
|
}
|
|
|
|
void setHomeRootTabsVisible(bool visible) {
|
|
if (_homeRootTabsVisible == visible) {
|
|
return;
|
|
}
|
|
_homeRootTabsVisible = visible;
|
|
if (!visible) {
|
|
_removeActiveRegionBroadcastMessage();
|
|
_removeRegionBroadcastMessages();
|
|
return;
|
|
}
|
|
_restoreDeferredRegionRedPacketMessages();
|
|
_safeScheduleNext();
|
|
}
|
|
|
|
void beginSuppressFloatingScreens({String reason = 'unknown'}) {
|
|
_suppressedCount += 1;
|
|
_removeActiveMessage(scheduleNext: false);
|
|
_messageQueue.clear();
|
|
_isPlaying = false;
|
|
_isProcessing = false;
|
|
}
|
|
|
|
void endSuppressFloatingScreens({String reason = 'unknown'}) {
|
|
if (_suppressedCount > 0) {
|
|
_suppressedCount -= 1;
|
|
}
|
|
if (!_isSuppressed) {
|
|
_safeScheduleNext();
|
|
}
|
|
}
|
|
|
|
void refreshDisplayPreference() {
|
|
if (_isDisposed) {
|
|
return;
|
|
}
|
|
if (SCGlobalConfig.isFloatingBroadcastClosed) {
|
|
_removeActiveMessage(scheduleNext: false);
|
|
_messageQueue.clear();
|
|
_deferredRegionRedPacketMessages.clear();
|
|
return;
|
|
}
|
|
_restoreDeferredRegionRedPacketMessages();
|
|
final context = navigatorKey.currentState?.context;
|
|
final activeMessage = _currentMessage;
|
|
if (context != null &&
|
|
context.mounted &&
|
|
activeMessage != null &&
|
|
!_shouldDisplayMessage(context, activeMessage)) {
|
|
_removeActiveMessage();
|
|
return;
|
|
}
|
|
_safeScheduleNext();
|
|
}
|
|
|
|
void dispose() {
|
|
_isDisposed = true;
|
|
_homeRootTabsVisible = false;
|
|
_suppressedCount = 0;
|
|
_currentOverlayEntry?.remove();
|
|
_currentOverlayEntry = null;
|
|
_currentMessage = null;
|
|
_messageQueue.clear();
|
|
_deferredRegionRedPacketMessages.clear();
|
|
_recentCompensationKeys.clear();
|
|
_isPlaying = false;
|
|
_isProcessing = false;
|
|
}
|
|
|
|
void removeRoom({String? roomId}) {
|
|
final normalizedRoomId = roomId?.trim() ?? '';
|
|
_removeActiveRoomMessage(
|
|
roomId: normalizedRoomId,
|
|
includeRedPacket: normalizedRoomId.isNotEmpty,
|
|
);
|
|
_removeMessagesByType(1);
|
|
_removeMessagesByType(0);
|
|
_removeMessagesByType(5);
|
|
if (normalizedRoomId.isNotEmpty) {
|
|
_removeMessagesByType(4, roomId: normalizedRoomId);
|
|
}
|
|
}
|
|
|
|
// 辅助方法:移除特定类型的消息
|
|
void _removeMessagesByType(int type, {String? roomId}) {
|
|
final normalizedRoomId = roomId?.trim() ?? '';
|
|
// 由于 PriorityQueue 没有直接的方法来移除特定元素,
|
|
// 我们需要重建队列,排除指定类型的消息
|
|
final newQueue = SCPriorityQueue<SCFloatingMessage>(
|
|
(a, b) => b.priority.compareTo(a.priority),
|
|
);
|
|
|
|
// 遍历原始队列,只添加非指定类型的消息
|
|
while (_messageQueue.isNotEmpty) {
|
|
final message = _messageQueue.removeFirst();
|
|
final matchesType = message.type == type;
|
|
final matchesRoom =
|
|
normalizedRoomId.isEmpty ||
|
|
(message.roomId ?? "").trim() == normalizedRoomId;
|
|
if (!matchesType || !matchesRoom) {
|
|
newQueue.add(message);
|
|
}
|
|
}
|
|
|
|
// 将新队列赋值给原队列
|
|
while (newQueue.isNotEmpty) {
|
|
_messageQueue.add(newQueue.removeFirst());
|
|
}
|
|
}
|
|
|
|
// 辅助方法:获取队列信息
|
|
int get queueLength => _messageQueue.length;
|
|
|
|
bool get isPlaying => _isPlaying;
|
|
|
|
bool get _isSuppressed => _suppressedCount > 0;
|
|
|
|
bool _isRegionRedPacketMessage(SCFloatingMessage message) {
|
|
return message.type == 4 && message.isRegionBroadcast;
|
|
}
|
|
|
|
bool _shouldDeferRegionRedPacketMessage(
|
|
BuildContext context,
|
|
SCFloatingMessage message,
|
|
) {
|
|
if (!_isRegionRedPacketMessage(message) ||
|
|
SCGlobalConfig.isFloatingBroadcastClosed) {
|
|
return false;
|
|
}
|
|
return !_shouldDisplayRegionBroadcastMessage(context, message);
|
|
}
|
|
|
|
void _deferRegionRedPacketMessage(
|
|
BuildContext context,
|
|
SCFloatingMessage message,
|
|
) {
|
|
final key = _floatingDedupKeyFor(message);
|
|
if (key != null &&
|
|
_deferredRegionRedPacketMessages.any(
|
|
(item) => _floatingDedupKeyFor(item) == key,
|
|
)) {
|
|
return;
|
|
}
|
|
while (_deferredRegionRedPacketMessages.length >=
|
|
_maxDeferredRegionRedPacketCount) {
|
|
_deferredRegionRedPacketMessages.removeAt(0);
|
|
}
|
|
_deferredRegionRedPacketMessages.add(message);
|
|
}
|
|
|
|
void _restoreDeferredRegionRedPacketMessages() {
|
|
if (_deferredRegionRedPacketMessages.isEmpty) {
|
|
return;
|
|
}
|
|
final messages = List<SCFloatingMessage>.from(
|
|
_deferredRegionRedPacketMessages,
|
|
);
|
|
_deferredRegionRedPacketMessages.clear();
|
|
for (final message in messages) {
|
|
_messageQueue.add(message);
|
|
}
|
|
}
|
|
|
|
void _logRegionRedPacketDrop(
|
|
BuildContext context,
|
|
SCFloatingMessage message,
|
|
) {
|
|
if (message.type != 4) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
String _displayStateForLog(BuildContext context) {
|
|
final rtcProvider = Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
);
|
|
final currentRoomId =
|
|
rtcProvider.currenRoom?.roomProfile?.roomProfile?.id?.trim() ?? "";
|
|
return 'homeVisible=$_homeRootTabsVisible '
|
|
'roomVisible=${rtcProvider.shouldShowRoomVisualEffects} '
|
|
'currentRoomId=$currentRoomId '
|
|
'scope=${SCGlobalConfig.floatingBroadcastScope}';
|
|
}
|
|
|
|
bool _shouldDisplayMessage(BuildContext context, SCFloatingMessage? message) {
|
|
if (message == null) {
|
|
return false;
|
|
}
|
|
if (SCGlobalConfig.isFloatingBroadcastClosed) {
|
|
return false;
|
|
}
|
|
if (message.isRegionBroadcast) {
|
|
return _shouldDisplayRegionBroadcastMessage(context, message);
|
|
}
|
|
if (message.type == 4) {
|
|
return _isCurrentRoomFloatingMessage(context, message);
|
|
}
|
|
if (SCGlobalConfig.isFloatingBroadcastRoomOnly) {
|
|
return _isCurrentRoomFloatingMessage(context, message);
|
|
}
|
|
if (message.type != 0 && message.type != 1 && message.type != 5) {
|
|
return true;
|
|
}
|
|
|
|
return _isCurrentRoomFloatingMessage(context, message);
|
|
}
|
|
|
|
bool _isCurrentRoomFloatingMessage(
|
|
BuildContext context,
|
|
SCFloatingMessage message,
|
|
) {
|
|
final rtcProvider = Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
);
|
|
if (!rtcProvider.shouldShowRoomVisualEffects ||
|
|
!rtcProvider.isVoiceRoomRouteVisible) {
|
|
return false;
|
|
}
|
|
final currentRoomId =
|
|
rtcProvider.currenRoom?.roomProfile?.roomProfile?.id?.trim() ?? "";
|
|
final messageRoomId = (message.roomId ?? "").trim();
|
|
if (currentRoomId.isEmpty || messageRoomId.isEmpty) {
|
|
return false;
|
|
}
|
|
return currentRoomId == messageRoomId;
|
|
}
|
|
|
|
bool _shouldDisplayRegionBroadcastMessage(
|
|
BuildContext context,
|
|
SCFloatingMessage message,
|
|
) {
|
|
if (SCGlobalConfig.isFloatingBroadcastClosed) {
|
|
return false;
|
|
}
|
|
final rtcProvider = Provider.of<RealTimeCommunicationManager>(
|
|
context,
|
|
listen: false,
|
|
);
|
|
final currentRoomId =
|
|
rtcProvider.currenRoom?.roomProfile?.roomProfile?.id?.trim() ?? "";
|
|
final messageRoomId = (message.roomId ?? "").trim();
|
|
final isCurrentVisibleRoom =
|
|
rtcProvider.shouldShowRoomVisualEffects &&
|
|
rtcProvider.isVoiceRoomRouteVisible &&
|
|
currentRoomId.isNotEmpty &&
|
|
messageRoomId.isNotEmpty &&
|
|
currentRoomId == messageRoomId;
|
|
if (isCurrentVisibleRoom) {
|
|
// 区域红包在当前房间仍然需要展示;区域礼物当前房间由 RTM 层跳过,避免和房间 IM 礼物飘屏重复。
|
|
return message.type == 4;
|
|
}
|
|
final isCurrentRoomMessage =
|
|
currentRoomId.isNotEmpty &&
|
|
messageRoomId.isNotEmpty &&
|
|
currentRoomId == messageRoomId;
|
|
if (message.type == 4 && isCurrentRoomMessage) {
|
|
return false;
|
|
}
|
|
if (message.type == 4 && rtcProvider.shouldShowRoomVisualEffects) {
|
|
return true;
|
|
}
|
|
if (message.type == 4) {
|
|
return _homeRootTabsVisible;
|
|
}
|
|
if (SCGlobalConfig.isFloatingBroadcastRoomOnly) {
|
|
return false;
|
|
}
|
|
if (rtcProvider.shouldShowRoomVisualEffects) {
|
|
return false;
|
|
}
|
|
return SCGlobalConfig.isFloatingBroadcastAll && _homeRootTabsVisible;
|
|
}
|
|
|
|
void _removeRegionBroadcastMessages() {
|
|
final newQueue = SCPriorityQueue<SCFloatingMessage>(
|
|
(a, b) => b.priority.compareTo(a.priority),
|
|
);
|
|
|
|
while (_messageQueue.isNotEmpty) {
|
|
final message = _messageQueue.removeFirst();
|
|
if (!message.isRegionBroadcast || _isRegionRedPacketMessage(message)) {
|
|
newQueue.add(message);
|
|
}
|
|
}
|
|
|
|
while (newQueue.isNotEmpty) {
|
|
_messageQueue.add(newQueue.removeFirst());
|
|
}
|
|
}
|
|
|
|
void _removeActiveRegionBroadcastMessage() {
|
|
final activeMessage = _currentMessage;
|
|
if (activeMessage == null || !activeMessage.isRegionBroadcast) {
|
|
return;
|
|
}
|
|
_currentOverlayEntry?.remove();
|
|
_currentOverlayEntry = null;
|
|
_currentMessage = null;
|
|
_isPlaying = false;
|
|
_safeScheduleNext();
|
|
}
|
|
|
|
void _removeActiveRoomMessage({
|
|
String? roomId,
|
|
bool includeRedPacket = false,
|
|
}) {
|
|
final activeMessage = _currentMessage;
|
|
final normalizedRoomId = roomId?.trim() ?? '';
|
|
if (activeMessage == null ||
|
|
(activeMessage.type != 0 &&
|
|
activeMessage.type != 1 &&
|
|
activeMessage.type != 5 &&
|
|
!(includeRedPacket && activeMessage.type == 4))) {
|
|
return;
|
|
}
|
|
if (normalizedRoomId.isNotEmpty &&
|
|
(activeMessage.roomId ?? "").trim() != normalizedRoomId) {
|
|
return;
|
|
}
|
|
_removeActiveMessage();
|
|
}
|
|
|
|
void _removeActiveMessage({bool scheduleNext = true}) {
|
|
_currentOverlayEntry?.remove();
|
|
_currentOverlayEntry = null;
|
|
_currentMessage = null;
|
|
_isPlaying = false;
|
|
if (scheduleNext) {
|
|
_safeScheduleNext();
|
|
}
|
|
}
|
|
}
|