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'; 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 _deferredActions = Queue(); final ValueNotifier _activeListenable = ValueNotifier(false); int _activeCount = 0; bool get isActive => _activeCount > 0; ValueListenable get activeListenable => _activeListenable; SCRoomTopLayerGuardLease acquire({ required String reason, Set keepDialogTags = const {}, }) { _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 keepDialogTags = const {}}) { _activeCount += 1; if (_activeCount != 1) { return; } _activeListenable.value = true; OverlayManager().beginSuppressFloatingScreens(reason: reason); 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); _activeListenable.value = false; _drainDeferredActions(); } void _drainDeferredActions() { if (_deferredActions.isEmpty) { return; } final actions = List.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 {}, }); final String reason; final Widget child; final Set keepDialogTags; @override State createState() => _SCRoomTopLayerSuppressorState(); } class _SCRoomTopLayerSuppressorState extends State { 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); } }