增加异步执行

This commit is contained in:
roxy 2026-05-16 07:18:55 +08:00
parent 8bf3d679a7
commit 024bcf4ffc
4 changed files with 120 additions and 35 deletions

View File

@ -292,6 +292,20 @@ class _PendingRoomStartupSeatAction {
final String? inviterId;
}
class _PersistedVoiceRoomCleanupRequest {
const _PersistedVoiceRoomCleanupRequest({
required this.staleRoomId,
required this.targetRoomId,
required this.restoreOnlineHeartbeatWhenIdle,
this.clearMarkerOnly = false,
});
final String staleRoomId;
final String targetRoomId;
final bool restoreOnlineHeartbeatWhenIdle;
final bool clearMarkerOnly;
}
class RealTimeCommunicationManager extends ChangeNotifier {
static const String _roomRocketRewardDialogTag = 'showRoomRocketRewardDialog';
static const String _roomRocketPagLaunchDialogTag =
@ -1798,10 +1812,11 @@ class RealTimeCommunicationManager extends ChangeNotifier {
if (!context.mounted) {
return;
}
await cleanupPersistedVoiceRoomSessionBeforeEntry(targetRoomId: roomId);
if (!context.mounted) {
return;
}
final persistedRoomCleanupRequest =
_preparePersistedVoiceRoomCleanupBeforeEntry(
targetRoomId: roomId,
restoreOnlineHeartbeatWhenIdle: false,
);
if (roomId == currenRoom?.roomProfile?.roomProfile?.id) {
if (_currentRoomIsEntryPreview ||
_roomStartupStatus == RoomStartupStatus.loading) {
@ -1810,6 +1825,9 @@ class RealTimeCommunicationManager extends ChangeNotifier {
}
_startVoiceRoomForegroundService();
VoiceRoomRoute.openVoiceRoom(context);
_startPersistedVoiceRoomCleanupInBackground(
persistedRoomCleanupRequest,
);
return;
}
@ -1848,6 +1866,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
_refreshRoomRedPacketListAfterEntry(roomId: roomId);
_startVoiceRoomForegroundService();
VoiceRoomRoute.openVoiceRoom(context);
_startPersistedVoiceRoomCleanupInBackground(persistedRoomCleanupRequest);
if (shouldRejoinRoomRtc) {
unawaited(_rejoinCurrentRoomRtcForSameRoomReuse(roomId));
}
@ -1883,6 +1902,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
);
_startVoiceRoomForegroundService();
VoiceRoomRoute.openVoiceRoom(context);
_startPersistedVoiceRoomCleanupInBackground(persistedRoomCleanupRequest);
notifyListeners();
final entryRequestSerial = ++_roomEntryRequestSerial;
if (preEnteredRoom != null) {
@ -2505,14 +2525,70 @@ class RealTimeCommunicationManager extends ChangeNotifier {
Future<void> cleanupPersistedVoiceRoomSessionBeforeEntry({
String? targetRoomId,
bool restoreOnlineHeartbeatWhenIdle = true,
}) {
final cleanupRequest = _preparePersistedVoiceRoomCleanupBeforeEntry(
targetRoomId: targetRoomId,
restoreOnlineHeartbeatWhenIdle: restoreOnlineHeartbeatWhenIdle,
);
return _runPersistedVoiceRoomCleanup(cleanupRequest);
}
_PersistedVoiceRoomCleanupRequest?
_preparePersistedVoiceRoomCleanupBeforeEntry({
String? targetRoomId,
bool restoreOnlineHeartbeatWhenIdle = true,
}) {
final staleRoomId = DataPersistence.getLastTimeRoomId().trim();
if (staleRoomId.isEmpty) {
return null;
}
final currentRoomId =
(currenRoom?.roomProfile?.roomProfile?.id ?? "").trim();
if (currentRoomId.isNotEmpty) {
return null;
}
final currentUserId =
(AccountStorage().getCurrentUser()?.userProfile?.id ?? "").trim();
if (currentUserId.isEmpty || AccountStorage().getToken().trim().isEmpty) {
return null;
}
final normalizedTargetRoomId = (targetRoomId ?? "").trim();
if (normalizedTargetRoomId.isNotEmpty &&
normalizedTargetRoomId == staleRoomId) {
return null;
}
final staleRoomUserId = DataPersistence.getLastTimeRoomUserId().trim();
return _PersistedVoiceRoomCleanupRequest(
staleRoomId: staleRoomId,
targetRoomId: normalizedTargetRoomId,
restoreOnlineHeartbeatWhenIdle: restoreOnlineHeartbeatWhenIdle,
clearMarkerOnly:
staleRoomUserId.isNotEmpty && staleRoomUserId != currentUserId,
);
}
void _startPersistedVoiceRoomCleanupInBackground(
_PersistedVoiceRoomCleanupRequest? cleanupRequest,
) {
unawaited(_runPersistedVoiceRoomCleanup(cleanupRequest));
}
Future<void> _runPersistedVoiceRoomCleanup(
_PersistedVoiceRoomCleanupRequest? cleanupRequest,
) {
if (cleanupRequest == null) {
return Future<void>.value();
}
final runningTask = _persistedRoomCleanupTask;
if (runningTask != null) {
return runningTask;
}
final task = _cleanupPersistedVoiceRoomSessionBeforeEntry(
targetRoomId: targetRoomId,
);
final task = _cleanupPersistedVoiceRoomSessionBeforeEntry(cleanupRequest);
_persistedRoomCleanupTask = task;
return task.whenComplete(() {
if (identical(_persistedRoomCleanupTask, task)) {
@ -2521,28 +2597,11 @@ class RealTimeCommunicationManager extends ChangeNotifier {
});
}
Future<void> _cleanupPersistedVoiceRoomSessionBeforeEntry({
String? targetRoomId,
}) async {
final staleRoomId = DataPersistence.getLastTimeRoomId().trim();
if (staleRoomId.isEmpty) {
return;
}
final currentRoomId =
(currenRoom?.roomProfile?.roomProfile?.id ?? "").trim();
if (currentRoomId.isNotEmpty) {
return;
}
final currentUserId =
(AccountStorage().getCurrentUser()?.userProfile?.id ?? "").trim();
if (currentUserId.isEmpty || AccountStorage().getToken().trim().isEmpty) {
return;
}
final staleRoomUserId = DataPersistence.getLastTimeRoomUserId().trim();
if (staleRoomUserId.isNotEmpty && staleRoomUserId != currentUserId) {
Future<void> _cleanupPersistedVoiceRoomSessionBeforeEntry(
_PersistedVoiceRoomCleanupRequest cleanupRequest,
) async {
final staleRoomId = cleanupRequest.staleRoomId;
if (cleanupRequest.clearMarkerOnly) {
await _clearPersistedRoomMarkerIfMatches(staleRoomId);
return;
}
@ -2563,7 +2622,11 @@ class RealTimeCommunicationManager extends ChangeNotifier {
);
if (didClean) {
await _clearPersistedRoomMarkerIfMatches(staleRoomId);
if ((targetRoomId ?? "").trim() != staleRoomId) {
final currentRoomId =
(currenRoom?.roomProfile?.roomProfile?.id ?? "").trim();
if (cleanupRequest.restoreOnlineHeartbeatWhenIdle &&
cleanupRequest.targetRoomId != staleRoomId &&
currentRoomId.isEmpty) {
await SCHeartbeatUtils.scheduleHeartbeat(
SCHeartbeatStatus.ONLINE.name,
false,

View File

@ -286,7 +286,12 @@ class SCRoomRocketStatusRes {
bool? get enabled => _enabled;
bool get isEnabled => _enabled != false;
bool get isEnabled {
final normalizedStatus = (_status ?? '').trim().toUpperCase();
return _configured != false &&
_enabled != false &&
normalizedStatus != 'DISABLED';
}
int? get roundNo => _roundNo;

View File

@ -38,15 +38,17 @@ class RoomRocketFloatingEntry extends StatelessWidget {
return const SizedBox.shrink();
}
final level = _currentEntryLevel(status);
if (level == null || level.rocketIconUrl.trim().isEmpty) {
return const SizedBox.shrink();
}
final percent = _entryPercent(status);
final shouldShake =
(status.shake ?? false) ||
(level != null && percent > level.shakeThresholdPercent);
(status.shake ?? false) || percent > level.shakeThresholdPercent;
return SCDebounceWidget(
onTap: () => _showRocketDialog(context, status),
child: _RoomRocketEntryButton(
iconUrl: level?.rocketIconUrl ?? '',
progressUrl: level?.progressBarUrl ?? '',
iconUrl: level.rocketIconUrl,
progressUrl: level.progressBarUrl,
progressPercent: percent,
shake: shouldShake,
loading: false,

View File

@ -138,6 +138,21 @@ void main() {
expect(RoomRocketApiMapper.levelsFromStatus(status), isNull);
});
test('treats unconfigured or disabled-status rocket as unavailable', () {
final unconfigured = SCRoomRocketStatusRes.fromJson({
'configured': false,
'enabled': true,
'status': 'ENABLED',
});
final disabledStatus = SCRoomRocketStatusRes.fromJson({
'configured': true,
'status': 'DISABLED',
});
expect(unconfigured.isEnabled, isFalse);
expect(disabledStatus.isEnabled, isFalse);
});
test(
'uses top-level reward preview for the response level instead of current level',
() {