chatapp3-flutter/lib/shared/data_sources/sources/local/floating_screen_manager.dart
2026-04-09 21:32:23 +08:00

212 lines
6.1 KiB
Dart

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_entrance_vap_svga_manager.dart';
import 'package:yumi/services/audio/rtc_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/shared/data_sources/models/message/sc_floating_message.dart';
typedef FloatingScreenManager = OverlayManager;
class OverlayManager {
final SCPriorityQueue<SCFloatingMessage> _messageQueue = SCPriorityQueue(
(a, b) => b.priority.compareTo(a.priority),
);
bool _isPlaying = false;
OverlayEntry? _currentOverlayEntry;
bool _isProcessing = false;
bool _isDisposed = false;
static final OverlayManager _instance =
OverlayManager._internal();
factory OverlayManager() => _instance;
OverlayManager._internal();
void addMessage(SCFloatingMessage message) {
if (_isDisposed) return;
if (SCGlobalConfig.isFloatingAnimationInGlobal) {
_messageQueue.add(message);
_safeScheduleNext();
} else {
_messageQueue.clear();
_isPlaying = false;
_isProcessing = false;
_isDisposed = false;
}
}
void _safeScheduleNext() {
if (_isProcessing || _isPlaying || _messageQueue.isEmpty) return;
_isProcessing = true;
try {
_scheduleNext();
} finally {
_isProcessing = false;
}
}
void _scheduleNext() {
if (_isPlaying || _messageQueue.isEmpty || _isDisposed) return;
try {
final context = navigatorKey.currentState?.context;
if (context == null || !context.mounted) return;
// 安全地获取第一个消息
if (_messageQueue.isEmpty) return;
final messageToProcess = _messageQueue.first;
if (messageToProcess?.type == 1) {
final rtcProvider = Provider.of<RealTimeCommunicationManager>(context, listen: false);
if (rtcProvider.currenRoom == null) {
// 从队列中移除第一个元素
_messageQueue.removeFirst();
_safeScheduleNext();
return;
}
}
// 安全地移除并播放消息
final messageToPlay = _messageQueue.removeFirst();
_playMessage(messageToPlay);
} catch (e) {
debugPrint('播放悬浮消息出错: $e');
_isPlaying = false;
_safeScheduleNext();
}
}
void _playMessage(SCFloatingMessage message) {
_isPlaying = true;
final context = navigatorKey.currentState?.context;
if (context == null || !context.mounted) {
_isPlaying = false;
_safeScheduleNext();
return;
}
_currentOverlayEntry = OverlayEntry(
builder:
(_) => Align(
alignment: AlignmentDirectional.topStart,
child: Transform.translate(
offset: Offset(0, 70.w),
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;
_safeScheduleNext();
} catch (e) {
debugPrint('清理悬浮消息出错: $e');
_isPlaying = false;
_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,
);
default:
onComplete();
return Container();
}
}
void activate() {
_isDisposed = false;
}
void dispose() {
_isDisposed = true;
_currentOverlayEntry?.remove();
_currentOverlayEntry = null;
_messageQueue.clear();
_isPlaying = false;
_isProcessing = false;
}
void removeRoom() {
// 正确地从 PriorityQueue 中移除特定类型的消息
_removeMessagesByType(1);
}
// 辅助方法:移除特定类型的消息
void _removeMessagesByType(int type) {
// 由于 PriorityQueue 没有直接的方法来移除特定元素,
// 我们需要重建队列,排除指定类型的消息
final newQueue = SCPriorityQueue<SCFloatingMessage>(
(a, b) => b.priority.compareTo(a.priority),
);
// 遍历原始队列,只添加非指定类型的消息
while (_messageQueue.isNotEmpty) {
final message = _messageQueue.removeFirst();
if (message.type != type) {
newQueue.add(message);
}
}
// 将新队列赋值给原队列
while (newQueue.isNotEmpty) {
_messageQueue.add(newQueue.removeFirst());
}
}
// 辅助方法:获取队列信息
int get queueLength => _messageQueue.length;
bool get isPlaying => _isPlaying;
}