diff --git a/assets/l10n/intl_en.json b/assets/l10n/intl_en.json index bca0970..43bde15 100644 --- a/assets/l10n/intl_en.json +++ b/assets/l10n/intl_en.json @@ -724,7 +724,7 @@ "roomRocketNoteTitle": "Note", "roomRocketNoteSectionTitle": "Each time a VIP", "roomRocketNoteSectionBody": "1. Each time a VIP level is purchased, it is valid for 30 days, and can be manually renewed after expiration.", - "roomRocketRewardEmptyText": "No rewards earned. Better luck next time.", + "roomRocketRewardEmptyText": "No reward", "roomRocketRecordEmptyText": "No reward records", "launchRocket": "Launch Rocket", "roomRocketFuelFullNotice": "Rocket fuel is full! Launching in {1}s!" diff --git a/lib/modules/room/voice_room_page.dart b/lib/modules/room/voice_room_page.dart index b6145cf..71d62a6 100644 --- a/lib/modules/room/voice_room_page.dart +++ b/lib/modules/room/voice_room_page.dart @@ -560,7 +560,6 @@ class _VoiceRoomPageState extends State ///礼物上飘动画 _floatingGiftListener(Msg msg) { final rtcProvider = Provider.of(context, listen: false); - rtcProvider.scheduleRoomRocketStatusRefreshForGift(); if (!rtcProvider.shouldShowRoomVisualEffects) { return; } diff --git a/lib/services/audio/rtc_manager.dart b/lib/services/audio/rtc_manager.dart index 8d30e8b..07f8f0a 100644 --- a/lib/services/audio/rtc_manager.dart +++ b/lib/services/audio/rtc_manager.dart @@ -305,6 +305,12 @@ class RealTimeCommunicationManager extends ChangeNotifier { Duration(seconds: 5), Duration(seconds: 10), ]; + static const List _roomRocketEntryReadyFallbackDelays = [ + Duration(milliseconds: 300), + Duration(milliseconds: 900), + Duration(milliseconds: 1800), + Duration(milliseconds: 3200), + ]; static const int _roomPasswordNotTrueErrorCode = 9005; static const Duration _micListPollingInterval = Duration(seconds: 2); @@ -347,6 +353,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { ValueNotifier? _roomRocketLaunchTopAvatarNotifier; Timer? _roomRocketGiftRefreshTimer; final List _roomRocketPostLaunchRefreshTimers = []; + final List _roomRocketEntryReadyFallbackTimers = []; Timer? _roomRedPacketPresenceTimer; Future? _rtcEnginePrewarmTask; Future? _pendingRoomSwitchRtcLeaveTask; @@ -495,6 +502,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { _releaseRoomRocketLaunchTopAvatarNotifier(); _roomRocketGiftRefreshTimer?.cancel(); _roomRocketGiftRefreshTimer = null; + _cancelRoomRocketEntryReadyFallbacks(); _cancelRoomRocketPostLaunchStatusRefresh(); } _roomVisualEffectsEnabled = enabled; @@ -506,7 +514,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { if (visible) { final roomId = (currenRoom?.roomProfile?.roomProfile?.id ?? "").trim(); if (roomId.isNotEmpty) { - rtmProvider?.handleVoiceRoomReadyForRocketRewards(roomId); + _scheduleRoomRocketEntryReadyFallback(roomId); } } } @@ -2603,6 +2611,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { setRoomVisualEffectsEnabled(true); if (shouldOpenRoomPage) { VoiceRoomRoute.openVoiceRoom(context!); + setVoiceRoomRouteVisible(true); } unawaited( _bootstrapEnteredVoiceRoomSession( @@ -2703,7 +2712,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { roomId: roomId, ); _loadRoomSecondaryData(); - rtmProvider?.handleVoiceRoomReadyForRocketRewards(roomId); + _scheduleRoomRocketEntryReadyFallback(roomId); } catch (error, stackTrace) { if (!_isActiveRoomStartup(entryRequestSerial, roomId)) { return; @@ -2825,6 +2834,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { roomRocketStatus = res; notifyListeners(); _scheduleRoomRocketAssetPreload(roomId, res, afterRoomEntry: true); + _scheduleRoomRocketEntryReadyFallback(roomId); }) .catchError((e) {}); _loadRoomRocketRewardPopups(roomId); @@ -2947,6 +2957,42 @@ class RealTimeCommunicationManager extends ChangeNotifier { }); } + void _scheduleRoomRocketEntryReadyFallback(String roomId) { + final normalizedRoomId = roomId.trim(); + if (normalizedRoomId.isEmpty) { + return; + } + _notifyRoomRocketEntryReadyIfCurrent(normalizedRoomId); + for (final delay in _roomRocketEntryReadyFallbackDelays) { + final timer = Timer(delay, () { + _roomRocketEntryReadyFallbackTimers.removeWhere( + (item) => !item.isActive, + ); + _notifyRoomRocketEntryReadyIfCurrent(normalizedRoomId); + }); + _roomRocketEntryReadyFallbackTimers.add(timer); + } + } + + void _notifyRoomRocketEntryReadyIfCurrent(String roomId) { + final normalizedRoomId = roomId.trim(); + final currentRoomId = + currenRoom?.roomProfile?.roomProfile?.id?.trim() ?? ""; + if (normalizedRoomId.isEmpty || + currentRoomId != normalizedRoomId || + !_voiceRoomRouteVisible) { + return; + } + rtmProvider?.handleVoiceRoomReadyForRocketRewards(normalizedRoomId); + } + + void _cancelRoomRocketEntryReadyFallbacks() { + for (final timer in _roomRocketEntryReadyFallbackTimers) { + timer.cancel(); + } + _roomRocketEntryReadyFallbackTimers.clear(); + } + void scheduleRoomRocketPostLaunchStatusRefresh({String? roomId}) { final resolvedRoomId = (roomId ?? currenRoom?.roomProfile?.roomProfile?.id ?? "").trim(); @@ -3482,9 +3528,6 @@ class RealTimeCommunicationManager extends ChangeNotifier { final exitRtmProvider = rtmProvider; final navigationContext = context; try { - exitRtmProvider?.msgAllListener = null; - exitRtmProvider?.msgChatListener = null; - exitRtmProvider?.msgGiftListener = null; SCGiftVapSvgaManager().stopPlayback(); setRoomVisualEffectsEnabled(false); SCHeartbeatUtils.cancelTimer(); @@ -3520,9 +3563,6 @@ class RealTimeCommunicationManager extends ChangeNotifier { final isPreviewOnlyExit = _currentRoomIsEntryPreview; final exitRtmProvider = rtmProvider; try { - exitRtmProvider?.msgAllListener = null; - exitRtmProvider?.msgChatListener = null; - exitRtmProvider?.msgGiftListener = null; SCGiftVapSvgaManager().stopPlayback(); setRoomVisualEffectsEnabled(false); SCHeartbeatUtils.cancelTimer(); diff --git a/lib/services/audio/rtm_manager.dart b/lib/services/audio/rtm_manager.dart index 0a47650..960d5cc 100644 --- a/lib/services/audio/rtm_manager.dart +++ b/lib/services/audio/rtm_manager.dart @@ -135,6 +135,7 @@ class RealTimeMessagingManager extends ChangeNotifier { static const int _roomRocketRegionBroadcastRecentTtlMs = 90000; static const int _roomRocketRewardPendingTtlMs = 120000; static const int _roomRocketRewardProbeTtlMs = 120000; + static const int _roomRocketLaunchCountdownRetainMs = 10000; static const Duration _createRoomGroupTimeout = Duration(seconds: 12); static const List _roomRocketRewardPopupRetryDelays = [ Duration(milliseconds: 700), @@ -262,6 +263,12 @@ class RealTimeMessagingManager extends ChangeNotifier { final _pendingRoomRocketRewardPopups = {}; final Map _recentRoomRocketRewardProbeTimes = {}; + final Map _roomRocketLaunchCountdownDueTimes = {}; + final Map _roomRocketLaunchCountdownKeysByRoom = + {}; + final _pendingRoomRocketCountdownLaunches = + {}; + final Map _roomRocketLaunchEffectTimers = {}; Timer? _roomRocketRewardPopupRetryTimer; Timer? _roomRocketRoomReadyRewardRetryTimer; int get currentLuckGiftBurstPlaybackToken => _luckGiftPushPlaybackToken; @@ -1163,6 +1170,7 @@ class RealTimeMessagingManager extends ChangeNotifier { } addMsg(Msg msg) { + _scheduleRoomRocketStatusRefreshForGiftMessage(msg); final mergedGiftMsg = _mergeGiftMessageIfNeeded(msg); if (mergedGiftMsg != null) { msgAllListener?.call(mergedGiftMsg); @@ -1249,6 +1257,33 @@ class RealTimeMessagingManager extends ChangeNotifier { } } + void _scheduleRoomRocketStatusRefreshForGiftMessage(Msg msg) { + if (msg.type != SCRoomMsgType.gift && + msg.type != SCRoomMsgType.luckGiftAnimOther) { + return; + } + final currentContext = context; + if (currentContext == null || !currentContext.mounted) { + return; + } + final rtcProvider = Provider.of( + currentContext, + listen: false, + ); + final currentRoomId = + (rtcProvider.currenRoom?.roomProfile?.roomProfile?.id ?? '').trim(); + if (currentRoomId.isEmpty) { + return; + } + final messageRoomId = msg.type == SCRoomMsgType.gift ? msg.msg?.trim() : ''; + if (messageRoomId != null && + messageRoomId.isNotEmpty && + messageRoomId != currentRoomId) { + return; + } + rtcProvider.scheduleRoomRocketStatusRefreshForGift(roomId: currentRoomId); + } + void _cacheRoomRedPacketMessage(Msg msg) { try { final decoded = jsonDecode(msg.msg ?? ''); @@ -1985,6 +2020,7 @@ class RealTimeMessagingManager extends ChangeNotifier { publishRegionBroadcast: true, ); } else { + _rememberRoomRocketLaunchCountdown(launch); _markRoomRocketRewardProbe(launch.roomId); _publishRoomRocketRegionBroadcastIfNeeded(launch); } @@ -2002,6 +2038,7 @@ class RealTimeMessagingManager extends ChangeNotifier { if (!launch.isValid) { return; } + _rememberRoomRocketLaunchCountdown(launch); var isCurrentRoom = false; var isCurrentVisibleRoom = false; @@ -2092,14 +2129,22 @@ class RealTimeMessagingManager extends ChangeNotifier { final pending = _pendingRoomRocketRewardPopups[normalizedRoomId]; final hasProbe = _recentRoomRocketRewardProbeTimes[normalizedRoomId] != null; - if (pending == null && !hasProbe) { + final hasLaunch = + _pendingRoomRocketCountdownLaunches[normalizedRoomId] != null; + if (pending == null && !hasProbe && !hasLaunch) { return; } if (!_isCurrentVisibleVoiceRoom(normalizedRoomId)) { _scheduleRoomRocketReadyRewardRetry(normalizedRoomId, attempt); return; } - if (pending == null && attempt == 0) { + final resumedLaunch = _resumeRoomRocketLaunchForCurrentRoom( + normalizedRoomId, + ); + if (pending == null && !hasProbe) { + return; + } + if (!resumedLaunch && pending == null && attempt == 0) { _scheduleRoomRocketReadyRewardRetry(normalizedRoomId, attempt); return; } @@ -2180,15 +2225,219 @@ class RealTimeMessagingManager extends ChangeNotifier { _recentRoomRocketRewardProbeTimes.clear(); _roomRocketRoomReadyRewardRetryTimer?.cancel(); _roomRocketRoomReadyRewardRetryTimer = null; + _clearRoomRocketLaunchCountdownState(); + } + + void _rememberRoomRocketLaunchCountdown( + RoomRocketLaunchBroadcastMessage launch, + ) { + if (!launch.isValid) { + return; + } + final now = DateTime.now().millisecondsSinceEpoch; + _pruneRoomRocketLaunchCountdowns(now); + final key = _roomRocketLaunchCountdownKey(launch); + final existingDueAt = _roomRocketLaunchCountdownDueTimes[key]; + final dueAt = + existingDueAt != null && existingDueAt > now + ? existingDueAt + : now + _roomRocketLaunchCountdownDelay(launch).inMilliseconds; + _roomRocketLaunchCountdownDueTimes[key] = dueAt; + _roomRocketLaunchCountdownKeysByRoom[launch.roomId] = key; + _pendingRoomRocketCountdownLaunches[launch.roomId] = launch; + } + + void _scheduleRoomRocketLaunchEffectsAfterCountdown( + RoomRocketLaunchBroadcastMessage launch, + ) { + if (!launch.isValid) { + return; + } + _rememberRoomRocketLaunchCountdown(launch); + final key = _roomRocketLaunchCountdownKey(launch); + final delay = _roomRocketLaunchCountdownRemaining(launch.roomId); + final dueAt = + _roomRocketLaunchCountdownDueTimes[key] ?? + DateTime.now().millisecondsSinceEpoch; + _roomRocketLaunchEffectTimers[key]?.cancel(); + _roomRocketLaunchEffectTimers[key] = Timer(delay, () { + _roomRocketLaunchEffectTimers.remove(key); + if (_roomRocketLaunchCountdownDueTimes[key] != dueAt) { + return; + } + _roomRocketLaunchCountdownDueTimes.remove(key); + if (_roomRocketLaunchCountdownKeysByRoom[launch.roomId] == key) { + _roomRocketLaunchCountdownKeysByRoom.remove(launch.roomId); + } + final pendingLaunch = + _pendingRoomRocketCountdownLaunches.remove(launch.roomId) ?? launch; + _playRoomRocketLaunchEffectsAndReward(pendingLaunch); + }); + } + + void _playRoomRocketLaunchEffectsAndReward( + RoomRocketLaunchBroadcastMessage launch, + ) { + _clearRoomRocketLaunchCountdownForRoom(launch.roomId); + if (!_isCurrentVisibleVoiceRoom(launch.roomId)) { + _markRoomRocketRewardProbe(launch.roomId); + return; + } + final currentContext = context; + if (currentContext == null || !currentContext.mounted) { + _markRoomRocketRewardProbe(launch.roomId); + return; + } + final rtcProvider = Provider.of( + currentContext, + listen: false, + ); + final shouldFetchReward = + _pendingRoomRocketRewardPopups.containsKey(launch.roomId) || + _recentRoomRocketRewardProbeTimes.containsKey(launch.roomId); + final pending = _pendingRoomRocketRewardPopups.remove(launch.roomId); + _recentRoomRocketRewardProbeTimes.remove(launch.roomId); + rtcProvider.handleRoomRocketLaunchBroadcast(launch); + if (shouldFetchReward) { + unawaited( + _showRoomRocketRewardPopupDialog( + launch.roomId, + initialRoomRecords: + pending?.initialRoomRecords ?? + const [], + ), + ); + } + } + + bool _resumeRoomRocketLaunchForCurrentRoom(String roomId) { + final normalizedRoomId = roomId.trim(); + final launch = _pendingRoomRocketCountdownLaunches[normalizedRoomId]; + if (launch == null || !_isCurrentVisibleVoiceRoom(normalizedRoomId)) { + return false; + } + final currentContext = context; + if (currentContext == null || !currentContext.mounted) { + return false; + } + final rtcProvider = Provider.of( + currentContext, + listen: false, + ); + final remaining = _roomRocketLaunchCountdownRemaining(normalizedRoomId); + if (remaining > Duration.zero) { + _addRoomRocketLaunchNoticeIfNeeded( + rtcProvider: rtcProvider, + launch: launch, + secondsOverride: _roomRocketRemainingSeconds(remaining), + ); + _scheduleRoomRocketLaunchEffectsAfterCountdown(launch); + } else { + _playRoomRocketLaunchEffectsAndReward(launch); + } + return true; + } + + int _roomRocketRemainingSeconds(Duration duration) { + final seconds = (duration.inMilliseconds / 1000).ceil(); + return seconds.clamp(1, 60).toInt(); + } + + Duration _roomRocketLaunchCountdownRemaining(String roomId) { + final normalizedRoomId = roomId.trim(); + if (normalizedRoomId.isEmpty) { + return Duration.zero; + } + final now = DateTime.now().millisecondsSinceEpoch; + _pruneRoomRocketLaunchCountdowns(now); + final key = _roomRocketLaunchCountdownKeysByRoom[normalizedRoomId]; + final dueAt = key == null ? null : _roomRocketLaunchCountdownDueTimes[key]; + if (dueAt == null || dueAt <= now) { + return Duration.zero; + } + return Duration(milliseconds: dueAt - now); + } + + Duration _roomRocketLaunchCountdownDelay( + RoomRocketLaunchBroadcastMessage launch, + ) { + final seconds = launch.durationSeconds <= 0 ? 10 : launch.durationSeconds; + return Duration(seconds: seconds.clamp(0, 60).toInt()); + } + + String _roomRocketLaunchCountdownKey( + RoomRocketLaunchBroadcastMessage launch, + ) { + final launchKey = _roomRocketLaunchNoticeKey(launch); + if (launchKey.isNotEmpty) { + return launchKey; + } + return 'rocket_launch_countdown|${launch.roomId}'; + } + + void _pruneRoomRocketLaunchCountdowns(int now) { + final expiredKeys = {}; + _roomRocketLaunchCountdownDueTimes.removeWhere((key, dueAt) { + final expired = now - dueAt > _roomRocketLaunchCountdownRetainMs; + if (expired) { + expiredKeys.add(key); + } + return expired; + }); + if (expiredKeys.isEmpty) { + return; + } + _roomRocketLaunchCountdownKeysByRoom.removeWhere( + (_, key) => expiredKeys.contains(key), + ); + _pendingRoomRocketCountdownLaunches.removeWhere( + (roomId, _) => !_roomRocketLaunchCountdownKeysByRoom.containsKey(roomId), + ); + } + + void _clearRoomRocketLaunchCountdownState() { + _roomRocketLaunchCountdownDueTimes.clear(); + _roomRocketLaunchCountdownKeysByRoom.clear(); + _pendingRoomRocketCountdownLaunches.clear(); + for (final timer in _roomRocketLaunchEffectTimers.values) { + timer.cancel(); + } + _roomRocketLaunchEffectTimers.clear(); + } + + void _clearRoomRocketLaunchCountdownForRoom(String roomId) { + final normalizedRoomId = roomId.trim(); + final key = _roomRocketLaunchCountdownKeysByRoom.remove(normalizedRoomId); + if (key != null) { + _roomRocketLaunchCountdownDueTimes.remove(key); + _roomRocketLaunchEffectTimers.remove(key)?.cancel(); + } + _pendingRoomRocketCountdownLaunches.remove(normalizedRoomId); } void _handleCurrentVisibleRoomRocketLaunch({ required RealTimeCommunicationManager rtcProvider, required RoomRocketLaunchBroadcastMessage launch, bool publishRegionBroadcast = false, + }) { + if (_addRoomRocketLaunchNoticeIfNeeded( + rtcProvider: rtcProvider, + launch: launch, + publishRegionBroadcast: publishRegionBroadcast, + )) { + _markRoomRocketRewardProbe(launch.roomId); + _scheduleRoomRocketLaunchEffectsAfterCountdown(launch); + } + } + + bool _addRoomRocketLaunchNoticeIfNeeded({ + required RealTimeCommunicationManager rtcProvider, + required RoomRocketLaunchBroadcastMessage launch, + bool publishRegionBroadcast = false, + int? secondsOverride, }) { if (!_isCurrentVisibleVoiceRoom(launch.roomId)) { - return; + return false; } final launchKey = _roomRocketLaunchNoticeKey(launch); final looseLaunchKey = _roomRocketLaunchLooseKey(launch); @@ -2199,26 +2448,27 @@ class RealTimeMessagingManager extends ChangeNotifier { _recentRoomRocketLaunchTimes.containsKey(launchKey)) || (looseLaunchKey.isNotEmpty && _recentRoomRocketLaunchLooseTimes.containsKey(looseLaunchKey)); - if (!alreadyHandled && launchKey.isNotEmpty) { - _recentRoomRocketLaunchTimes[launchKey] = now; - if (looseLaunchKey.isNotEmpty) { - _recentRoomRocketLaunchLooseTimes[looseLaunchKey] = now; - } - addMsg( - _buildRoomRocketLaunchNoticeMsg( - _firstNonBlank([ - rtcProvider.currenRoom?.roomProfile?.roomProfile?.roomAccount, - launch.roomAccount, - ]), - launch, - ), - ); - if (publishRegionBroadcast) { - _publishRoomRocketRegionBroadcastIfNeeded(launch); - } - rtcProvider.handleRoomRocketLaunchBroadcast(launch); + if (alreadyHandled || launchKey.isEmpty) { + return false; } - unawaited(_showRoomRocketRewardPopupDialog(launch.roomId)); + _recentRoomRocketLaunchTimes[launchKey] = now; + if (looseLaunchKey.isNotEmpty) { + _recentRoomRocketLaunchLooseTimes[looseLaunchKey] = now; + } + addMsg( + _buildRoomRocketLaunchNoticeMsg( + _firstNonBlank([ + rtcProvider.currenRoom?.roomProfile?.roomProfile?.roomAccount, + launch.roomAccount, + ]), + launch, + secondsOverride: secondsOverride, + ), + ); + if (publishRegionBroadcast) { + _publishRoomRocketRegionBroadcastIfNeeded(launch); + } + return true; } void _publishRoomRocketRegionBroadcastIfNeeded( @@ -2294,7 +2544,9 @@ class RealTimeMessagingManager extends ChangeNotifier { if (!_isCurrentVisibleVoiceRoom(roomId)) { return; } - if (res.records.isEmpty && initialRoomRecords.isEmpty) { + if (res.records.isEmpty && + initialRoomRecords.isEmpty && + attempt < _roomRocketRewardPopupRetryDelays.length) { _scheduleRoomRocketRewardPopupRetry( roomId, attempt, @@ -2453,9 +2705,12 @@ class RealTimeMessagingManager extends ChangeNotifier { Msg _buildRoomRocketLaunchNoticeMsg( String groupId, - RoomRocketLaunchBroadcastMessage launch, - ) { - final seconds = launch.durationSeconds <= 0 ? 10 : launch.durationSeconds; + RoomRocketLaunchBroadcastMessage launch, { + int? secondsOverride, + }) { + final seconds = + secondsOverride ?? + (launch.durationSeconds <= 0 ? 10 : launch.durationSeconds); return Msg( groupId: groupId, msg: seconds.toString(), diff --git a/lib/ui_kit/widgets/room/rocket/room_rocket_reward_dialog.dart b/lib/ui_kit/widgets/room/rocket/room_rocket_reward_dialog.dart index 1e67126..d0bfe6f 100644 --- a/lib/ui_kit/widgets/room/rocket/room_rocket_reward_dialog.dart +++ b/lib/ui_kit/widgets/room/rocket/room_rocket_reward_dialog.dart @@ -35,7 +35,7 @@ class RoomRocketRewardDialog extends StatelessWidget { final emptyText = _translate( localizations, 'roomRocketRewardEmptyText', - 'No rewards earned. Better luck next time.', + 'No reward', ); final contentDirection = Directionality.of(context); final resolvedRewards = _normalizeRewards( @@ -257,7 +257,7 @@ class _RewardDialogCanvas extends StatelessWidget { if (isEmpty) _buildEmptyState() else ...[ - _buildRewardGrid(), + rewards.isEmpty ? _buildRewardEmptyState() : _buildRewardGrid(), _buildWinnerList(), ], _buildLoadingText(), @@ -380,9 +380,6 @@ class _RewardDialogCanvas extends StatelessWidget { } Widget _buildRewardGrid() { - if (rewards.isEmpty) { - return const SizedBox.shrink(); - } final columns = math.max(3, (rewards.length / 2).ceil()); return Positioned( left: s(28), @@ -425,6 +422,45 @@ class _RewardDialogCanvas extends StatelessWidget { ); } + Widget _buildRewardEmptyState() { + return Positioned( + left: s(0), + top: s(268), + width: s(_designWidth), + height: s(178), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + _RewardDialogAssets.empty, + width: s(72), + height: s(72), + fit: BoxFit.contain, + ), + SizedBox(height: s(10)), + SizedBox( + width: s(250), + child: Text( + emptyText, + textDirection: contentDirection, + textScaler: TextScaler.noScaling, + maxLines: 2, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white.withValues(alpha: 0.72), + fontSize: s(13), + height: 1.25, + fontWeight: FontWeight.w600, + decoration: TextDecoration.none, + ), + ), + ), + ], + ), + ); + } + Widget _buildWinnerList() { return Positioned( left: s(12), diff --git a/test/room_rocket_reward_dialog_loader_test.dart b/test/room_rocket_reward_dialog_loader_test.dart index 3fb48f8..bda3aa8 100644 --- a/test/room_rocket_reward_dialog_loader_test.dart +++ b/test/room_rocket_reward_dialog_loader_test.dart @@ -1,5 +1,8 @@ +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:yumi/shared/business_logic/models/res/sc_room_rocket_api_res.dart'; +import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_dialog.dart'; +import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_reward_dialog.dart'; import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_reward_dialog_loader.dart'; void main() { @@ -27,6 +30,30 @@ void main() { expect(records.map((item) => item.rewardAmount), [5000, 5200]); }); }); + + group('room rocket reward dialog', () { + testWidgets('shows reward empty state when room winners exist', ( + tester, + ) async { + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: RoomRocketRewardDialog( + rewards: [], + winners: [ + RoomRocketRewardWinner(nickname: 'test man'), + ], + loadingText: '', + useMockFallback: false, + ), + ), + ), + ); + + expect(find.text('No reward'), findsOneWidget); + expect(find.text('test man'), findsOneWidget); + }); + }); } SCRoomRocketRewardRecordRes _rewardRecord({