增加异步执行

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

View File

@ -286,7 +286,12 @@ class SCRoomRocketStatusRes {
bool? get enabled => _enabled; 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; int? get roundNo => _roundNo;

View File

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

View File

@ -138,6 +138,21 @@ void main() {
expect(RoomRocketApiMapper.levelsFromStatus(status), isNull); 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( test(
'uses top-level reward preview for the response level instead of current level', 'uses top-level reward preview for the response level instead of current level',
() { () {