184 lines
4.9 KiB
Dart
184 lines
4.9 KiB
Dart
import 'dart:async';
|
|
import 'dart:collection';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
import 'package:yumi/shared/data_sources/sources/local/floating_screen_manager.dart';
|
|
import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart';
|
|
import 'package:yumi/shared/tools/sc_room_effect_scheduler.dart';
|
|
import 'package:yumi/ui_kit/widgets/room/anim/room_entrance_widget.dart';
|
|
|
|
class SCRoomTopLayerGuard {
|
|
static const int _maxDeferredActions = 16;
|
|
static const String _redPacketOpenDialogTag = 'showRoomRedPacketOpenDialog';
|
|
static const String _roomRocketRewardDialogTag = 'showRoomRocketRewardDialog';
|
|
static const String _roomRocketPagLaunchDialogTag =
|
|
'showRoomRocketPagLaunchDialog';
|
|
|
|
static final SCRoomTopLayerGuard _instance = SCRoomTopLayerGuard._internal();
|
|
|
|
factory SCRoomTopLayerGuard() => _instance;
|
|
|
|
SCRoomTopLayerGuard._internal();
|
|
|
|
final Queue<VoidCallback> _deferredActions = Queue<VoidCallback>();
|
|
final ValueNotifier<bool> _activeListenable = ValueNotifier<bool>(false);
|
|
int _activeCount = 0;
|
|
|
|
bool get isActive => _activeCount > 0;
|
|
|
|
ValueListenable<bool> get activeListenable => _activeListenable;
|
|
|
|
SCRoomTopLayerGuardLease acquire({
|
|
required String reason,
|
|
Set<String> keepDialogTags = const <String>{},
|
|
}) {
|
|
_begin(reason, keepDialogTags: keepDialogTags);
|
|
return SCRoomTopLayerGuardLease._(this, reason);
|
|
}
|
|
|
|
void runWhenInactive(VoidCallback action) {
|
|
if (!isActive) {
|
|
action();
|
|
return;
|
|
}
|
|
while (_deferredActions.length >= _maxDeferredActions) {
|
|
_deferredActions.removeFirst();
|
|
}
|
|
_deferredActions.add(action);
|
|
}
|
|
|
|
void _begin(String reason, {Set<String> keepDialogTags = const <String>{}}) {
|
|
_activeCount += 1;
|
|
if (_activeCount != 1) {
|
|
return;
|
|
}
|
|
_activeListenable.value = true;
|
|
OverlayManager().beginSuppressFloatingScreens(reason: reason);
|
|
SCRoomEffectScheduler().beginSuppressEffects(reason: reason);
|
|
SCRoomEffectScheduler().clearDeferredTasks(reason: reason);
|
|
RoomEntranceHelper.clearQueue();
|
|
SCGiftVapSvgaManager().stopPlayback();
|
|
SCGiftVapSvgaManager().pauseAnim();
|
|
if (!keepDialogTags.contains(_redPacketOpenDialogTag)) {
|
|
unawaited(SmartDialog.dismiss(tag: _redPacketOpenDialogTag));
|
|
}
|
|
if (!keepDialogTags.contains(_roomRocketRewardDialogTag)) {
|
|
unawaited(SmartDialog.dismiss(tag: _roomRocketRewardDialogTag));
|
|
}
|
|
if (!keepDialogTags.contains(_roomRocketPagLaunchDialogTag)) {
|
|
unawaited(SmartDialog.dismiss(tag: _roomRocketPagLaunchDialogTag));
|
|
}
|
|
}
|
|
|
|
void _release(String reason) {
|
|
if (_activeCount <= 0) {
|
|
return;
|
|
}
|
|
_activeCount -= 1;
|
|
if (_activeCount != 0) {
|
|
return;
|
|
}
|
|
OverlayManager().endSuppressFloatingScreens(reason: reason);
|
|
SCRoomEffectScheduler().endSuppressEffects(reason: reason);
|
|
SCGiftVapSvgaManager().resumeAnim();
|
|
_activeListenable.value = false;
|
|
_drainDeferredActions();
|
|
}
|
|
|
|
void _drainDeferredActions() {
|
|
if (_deferredActions.isEmpty) {
|
|
return;
|
|
}
|
|
final actions = List<VoidCallback>.from(_deferredActions);
|
|
_deferredActions.clear();
|
|
scheduleMicrotask(() {
|
|
for (final action in actions) {
|
|
if (isActive) {
|
|
runWhenInactive(action);
|
|
continue;
|
|
}
|
|
action();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
class SCRoomTopLayerSuppressor extends StatefulWidget {
|
|
const SCRoomTopLayerSuppressor({
|
|
super.key,
|
|
required this.reason,
|
|
required this.child,
|
|
this.keepDialogTags = const <String>{},
|
|
});
|
|
|
|
final String reason;
|
|
final Widget child;
|
|
final Set<String> keepDialogTags;
|
|
|
|
@override
|
|
State<SCRoomTopLayerSuppressor> createState() =>
|
|
_SCRoomTopLayerSuppressorState();
|
|
}
|
|
|
|
class _SCRoomTopLayerSuppressorState extends State<SCRoomTopLayerSuppressor> {
|
|
SCRoomTopLayerGuardLease? _lease;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_acquire();
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(covariant SCRoomTopLayerSuppressor oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
if (oldWidget.reason == widget.reason &&
|
|
setEquals(oldWidget.keepDialogTags, widget.keepDialogTags)) {
|
|
return;
|
|
}
|
|
_release();
|
|
_acquire();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_release();
|
|
super.dispose();
|
|
}
|
|
|
|
void _acquire() {
|
|
_lease = SCRoomTopLayerGuard().acquire(
|
|
reason: widget.reason,
|
|
keepDialogTags: widget.keepDialogTags,
|
|
);
|
|
}
|
|
|
|
void _release() {
|
|
_lease?.release();
|
|
_lease = null;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return widget.child;
|
|
}
|
|
}
|
|
|
|
class SCRoomTopLayerGuardLease {
|
|
SCRoomTopLayerGuardLease._(this._guard, this.reason);
|
|
|
|
final SCRoomTopLayerGuard _guard;
|
|
final String reason;
|
|
bool _released = false;
|
|
|
|
void release() {
|
|
if (_released) {
|
|
return;
|
|
}
|
|
_released = true;
|
|
_guard._release(reason);
|
|
}
|
|
}
|