chatapp3-flutter/lib/shared/tools/sc_room_effect_scheduler.dart
2026-04-21 13:44:03 +08:00

141 lines
3.5 KiB
Dart

import 'dart:async';
import 'dart:collection';
import 'package:flutter/foundation.dart';
class SCRoomEffectScheduler {
static const Duration _deferredDrainInterval = Duration(milliseconds: 60);
static final SCRoomEffectScheduler _instance =
SCRoomEffectScheduler._internal();
factory SCRoomEffectScheduler() => _instance;
SCRoomEffectScheduler._internal();
final Queue<_DeferredRoomEffectTask> _deferredTasks =
Queue<_DeferredRoomEffectTask>();
Timer? _deferredDrainTimer;
int _pendingHighCostTaskCount = 0;
int _nextTaskId = 0;
bool get hasActiveHighCostEffects => _pendingHighCostTaskCount > 0;
void registerHighCostTaskQueued({String? debugLabel}) {
_pendingHighCostTaskCount += 1;
_cancelDeferredDrain();
_log(
'register_high_cost task=${debugLabel ?? "unknown"} '
'pending=$_pendingHighCostTaskCount deferred=${_deferredTasks.length}',
);
}
void completeHighCostTask({String? debugLabel}) {
if (_pendingHighCostTaskCount > 0) {
_pendingHighCostTaskCount -= 1;
}
_log(
'complete_high_cost task=${debugLabel ?? "unknown"} '
'pending=$_pendingHighCostTaskCount deferred=${_deferredTasks.length}',
);
_scheduleDeferredDrainIfNeeded();
}
void clearHighCostTasks({String reason = 'unknown'}) {
if (_pendingHighCostTaskCount == 0) {
_scheduleDeferredDrainIfNeeded();
return;
}
_pendingHighCostTaskCount = 0;
_log(
'clear_high_cost reason=$reason '
'pending=$_pendingHighCostTaskCount deferred=${_deferredTasks.length}',
);
_scheduleDeferredDrainIfNeeded();
}
void scheduleDeferredEffect({
required String debugLabel,
required VoidCallback action,
}) {
if (!hasActiveHighCostEffects) {
action();
return;
}
final task = _DeferredRoomEffectTask(
id: _nextTaskId++,
debugLabel: debugLabel,
action: action,
);
_deferredTasks.add(task);
_log(
'defer task=${task.debugLabel} id=${task.id} '
'pending=$_pendingHighCostTaskCount deferred=${_deferredTasks.length}',
);
}
void clearDeferredTasks({String reason = 'unknown'}) {
if (_deferredTasks.isEmpty) {
_cancelDeferredDrain();
return;
}
_deferredTasks.clear();
_cancelDeferredDrain();
_log('clear_deferred reason=$reason');
}
void _scheduleDeferredDrainIfNeeded() {
if (hasActiveHighCostEffects ||
_deferredTasks.isEmpty ||
_deferredDrainTimer != null) {
return;
}
_deferredDrainTimer = Timer(_deferredDrainInterval, _drainNextDeferredTask);
}
void _drainNextDeferredTask() {
_deferredDrainTimer = null;
if (hasActiveHighCostEffects || _deferredTasks.isEmpty) {
return;
}
final task = _deferredTasks.removeFirst();
_log(
'drain_deferred task=${task.debugLabel} id=${task.id} '
'remaining=${_deferredTasks.length}',
);
try {
task.action();
} catch (error, stackTrace) {
debugPrint(
'[RoomEffectScheduler] deferred task failed: $error\n$stackTrace',
);
}
_scheduleDeferredDrainIfNeeded();
}
void _cancelDeferredDrain() {
_deferredDrainTimer?.cancel();
_deferredDrainTimer = null;
}
void _log(String message) {
debugPrint('[RoomEffectScheduler] $message');
}
}
class _DeferredRoomEffectTask {
const _DeferredRoomEffectTask({
required this.id,
required this.debugLabel,
required this.action,
});
final int id;
final String debugLabel;
final VoidCallback action;
}