又一版
This commit is contained in:
parent
51083ef57f
commit
be6b2f8f88
@ -58,7 +58,6 @@
|
|||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:taskAffinity=""
|
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.org.yumiparty
|
package com.org.yumiparty
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import com.android.installreferrer.api.InstallReferrerClient
|
import com.android.installreferrer.api.InstallReferrerClient
|
||||||
import com.android.installreferrer.api.InstallReferrerStateListener
|
import com.android.installreferrer.api.InstallReferrerStateListener
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
@ -59,6 +60,11 @@ class MainActivity : FlutterActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
setIntent(intent)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
installReferrerClient?.endConnection()
|
installReferrerClient?.endConnection()
|
||||||
installReferrerClient = null
|
installReferrerClient = null
|
||||||
|
|||||||
@ -54,7 +54,9 @@ class VoiceRoomForegroundService : Service() {
|
|||||||
packageManager.getLaunchIntentForPackage(packageName)
|
packageManager.getLaunchIntentForPackage(packageName)
|
||||||
?: Intent(this, MainActivity::class.java)
|
?: Intent(this, MainActivity::class.java)
|
||||||
).apply {
|
).apply {
|
||||||
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||||
|
Intent.FLAG_ACTIVITY_CLEAR_TOP or
|
||||||
|
Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||||
}
|
}
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
this,
|
this,
|
||||||
|
|||||||
@ -559,10 +559,9 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
|
|||||||
|
|
||||||
///礼物上飘动画
|
///礼物上飘动画
|
||||||
_floatingGiftListener(Msg msg) {
|
_floatingGiftListener(Msg msg) {
|
||||||
if (!Provider.of<RtcProvider>(
|
final rtcProvider = Provider.of<RtcProvider>(context, listen: false);
|
||||||
context,
|
rtcProvider.scheduleRoomRocketStatusRefreshForGift();
|
||||||
listen: false,
|
if (!rtcProvider.shouldShowRoomVisualEffects) {
|
||||||
).shouldShowRoomVisualEffects) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Provider.of<GiftProvider>(context, listen: false).hideLGiftAnimal) {
|
if (Provider.of<GiftProvider>(context, listen: false).hideLGiftAnimal) {
|
||||||
|
|||||||
@ -48,6 +48,7 @@ import '../../shared/data_sources/models/enum/sc_heartbeat_status.dart';
|
|||||||
import '../../shared/data_sources/models/enum/sc_room_info_event_type.dart';
|
import '../../shared/data_sources/models/enum/sc_room_info_event_type.dart';
|
||||||
import '../../shared/data_sources/models/enum/sc_room_roles_type.dart';
|
import '../../shared/data_sources/models/enum/sc_room_roles_type.dart';
|
||||||
import '../../shared/business_logic/models/res/sc_is_follow_room_res.dart';
|
import '../../shared/business_logic/models/res/sc_is_follow_room_res.dart';
|
||||||
|
import '../../shared/business_logic/models/res/sc_room_rocket_api_res.dart';
|
||||||
import '../../shared/business_logic/models/res/sc_room_red_packet_config_res.dart';
|
import '../../shared/business_logic/models/res/sc_room_red_packet_config_res.dart';
|
||||||
import '../../shared/business_logic/models/res/sc_room_red_packet_list_res.dart';
|
import '../../shared/business_logic/models/res/sc_room_red_packet_list_res.dart';
|
||||||
import '../../shared/business_logic/models/res/sc_room_rocket_status_res.dart';
|
import '../../shared/business_logic/models/res/sc_room_rocket_status_res.dart';
|
||||||
@ -56,6 +57,7 @@ import '../../shared/business_logic/models/res/sc_vip_res.dart';
|
|||||||
import '../../shared/tools/sc_room_profile_cache.dart';
|
import '../../shared/tools/sc_room_profile_cache.dart';
|
||||||
import '../../ui_kit/components/sc_float_ichart.dart';
|
import '../../ui_kit/components/sc_float_ichart.dart';
|
||||||
import '../../ui_kit/widgets/room/rocket/room_rocket_pag_effect_overlay.dart';
|
import '../../ui_kit/widgets/room/rocket/room_rocket_pag_effect_overlay.dart';
|
||||||
|
import '../../ui_kit/widgets/room/rocket/room_rocket_api_mapper.dart';
|
||||||
import '../../ui_kit/widgets/room/rocket/room_rocket_reward_dialog_loader.dart';
|
import '../../ui_kit/widgets/room/rocket/room_rocket_reward_dialog_loader.dart';
|
||||||
|
|
||||||
typedef OnSoundVoiceChange = Function(num index, int volum);
|
typedef OnSoundVoiceChange = Function(num index, int volum);
|
||||||
@ -292,6 +294,9 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
static const String _roomRocketRewardDialogTag = 'showRoomRocketRewardDialog';
|
static const String _roomRocketRewardDialogTag = 'showRoomRocketRewardDialog';
|
||||||
static const String _roomRocketPagLaunchDialogTag =
|
static const String _roomRocketPagLaunchDialogTag =
|
||||||
'showRoomRocketPagLaunchDialog';
|
'showRoomRocketPagLaunchDialog';
|
||||||
|
static const Duration _roomRocketGiftRefreshDelay = Duration(
|
||||||
|
milliseconds: 700,
|
||||||
|
);
|
||||||
static const int _roomPasswordNotTrueErrorCode = 9005;
|
static const int _roomPasswordNotTrueErrorCode = 9005;
|
||||||
|
|
||||||
static const Duration _micListPollingInterval = Duration(seconds: 2);
|
static const Duration _micListPollingInterval = Duration(seconds: 2);
|
||||||
@ -331,6 +336,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
Timer? _onlineUsersPollingTimer;
|
Timer? _onlineUsersPollingTimer;
|
||||||
Timer? _roomEntryEffectTimer;
|
Timer? _roomEntryEffectTimer;
|
||||||
Timer? _roomRocketLaunchAnimationTimer;
|
Timer? _roomRocketLaunchAnimationTimer;
|
||||||
|
Timer? _roomRocketGiftRefreshTimer;
|
||||||
String? _lastRoomRocketLaunchNoticeKey;
|
String? _lastRoomRocketLaunchNoticeKey;
|
||||||
Timer? _roomRedPacketPresenceTimer;
|
Timer? _roomRedPacketPresenceTimer;
|
||||||
Future<void>? _rtcEnginePrewarmTask;
|
Future<void>? _rtcEnginePrewarmTask;
|
||||||
@ -477,6 +483,8 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
_roomEntryEffectTimer = null;
|
_roomEntryEffectTimer = null;
|
||||||
_roomRocketLaunchAnimationTimer?.cancel();
|
_roomRocketLaunchAnimationTimer?.cancel();
|
||||||
_roomRocketLaunchAnimationTimer = null;
|
_roomRocketLaunchAnimationTimer = null;
|
||||||
|
_roomRocketGiftRefreshTimer?.cancel();
|
||||||
|
_roomRocketGiftRefreshTimer = null;
|
||||||
}
|
}
|
||||||
_roomVisualEffectsEnabled = enabled;
|
_roomVisualEffectsEnabled = enabled;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -2753,6 +2761,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
(_) => RoomRocketRewardDialogLoader(
|
(_) => RoomRocketRewardDialogLoader(
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
initialPopupRecords: res.records,
|
initialPopupRecords: res.records,
|
||||||
|
userProfileResolver: roomRocketRewardUserProfileForRecord,
|
||||||
onClose: () {
|
onClose: () {
|
||||||
SmartDialog.dismiss(tag: _roomRocketRewardDialogTag);
|
SmartDialog.dismiss(tag: _roomRocketRewardDialogTag);
|
||||||
if (recordIds.isNotEmpty) {
|
if (recordIds.isNotEmpty) {
|
||||||
@ -2795,6 +2804,19 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
_publishRoomRocketLaunchNoticeIfNeeded(previousStatus, res);
|
_publishRoomRocketLaunchNoticeIfNeeded(previousStatus, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scheduleRoomRocketStatusRefreshForGift({String? roomId}) {
|
||||||
|
final resolvedRoomId =
|
||||||
|
(roomId ?? currenRoom?.roomProfile?.roomProfile?.id ?? "").trim();
|
||||||
|
if (resolvedRoomId.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_roomRocketGiftRefreshTimer?.cancel();
|
||||||
|
_roomRocketGiftRefreshTimer = Timer(_roomRocketGiftRefreshDelay, () {
|
||||||
|
_roomRocketGiftRefreshTimer = null;
|
||||||
|
unawaited(refreshRoomRocketStatus(roomId: resolvedRoomId));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void handleRoomRocketLaunchBroadcast(
|
void handleRoomRocketLaunchBroadcast(
|
||||||
RoomRocketLaunchBroadcastMessage launch,
|
RoomRocketLaunchBroadcastMessage launch,
|
||||||
) {
|
) {
|
||||||
@ -3000,6 +3022,63 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoomRocketRewardUserProfile? roomRocketRewardUserProfileForRecord(
|
||||||
|
SCRoomRocketRewardRecordRes record,
|
||||||
|
) {
|
||||||
|
final keys =
|
||||||
|
<String>{
|
||||||
|
record.userId.trim(),
|
||||||
|
record.account.trim(),
|
||||||
|
}.where((item) => item.isNotEmpty).toSet();
|
||||||
|
if (keys.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (final profile in _roomRocketKnownUserProfiles()) {
|
||||||
|
if (_roomRocketProfileMatches(profile, keys)) {
|
||||||
|
return RoomRocketRewardUserProfile(
|
||||||
|
userId: profile.id?.trim() ?? '',
|
||||||
|
account: profile.account?.trim() ?? '',
|
||||||
|
nickname: profile.userNickname?.trim() ?? '',
|
||||||
|
avatarUrl: profile.userAvatar?.trim() ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterable<SocialChatUserProfile> _roomRocketKnownUserProfiles() sync* {
|
||||||
|
final currentUser = AccountStorage().getCurrentUser()?.userProfile;
|
||||||
|
if (currentUser != null) {
|
||||||
|
yield currentUser;
|
||||||
|
}
|
||||||
|
final ownerProfile = currenRoom?.roomProfile?.userProfile;
|
||||||
|
if (ownerProfile != null) {
|
||||||
|
yield ownerProfile;
|
||||||
|
}
|
||||||
|
for (final user in onlineUsers) {
|
||||||
|
yield user;
|
||||||
|
}
|
||||||
|
for (final seat in roomWheatMap.values) {
|
||||||
|
final user = seat.user;
|
||||||
|
if (user != null) {
|
||||||
|
yield user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final user in SCRoomUtils.roomUsersMap.values) {
|
||||||
|
yield user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _roomRocketProfileMatches(
|
||||||
|
SocialChatUserProfile profile,
|
||||||
|
Set<String> keys,
|
||||||
|
) {
|
||||||
|
return [profile.id, profile.account, profile.inRoomId].any((value) {
|
||||||
|
final text = value?.trim() ?? '';
|
||||||
|
return text.isNotEmpty && keys.contains(text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
///获取在线用户
|
///获取在线用户
|
||||||
Future<void> fetchOnlineUsersList({bool notifyIfUnchanged = true}) async {
|
Future<void> fetchOnlineUsersList({bool notifyIfUnchanged = true}) async {
|
||||||
final roomId = currenRoom?.roomProfile?.roomProfile?.id ?? "";
|
final roomId = currenRoom?.roomProfile?.roomProfile?.id ?? "";
|
||||||
@ -3491,6 +3570,8 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
|||||||
_roomEntryEffectTimer = null;
|
_roomEntryEffectTimer = null;
|
||||||
_roomRocketLaunchAnimationTimer?.cancel();
|
_roomRocketLaunchAnimationTimer?.cancel();
|
||||||
_roomRocketLaunchAnimationTimer = null;
|
_roomRocketLaunchAnimationTimer = null;
|
||||||
|
_roomRocketGiftRefreshTimer?.cancel();
|
||||||
|
_roomRocketGiftRefreshTimer = null;
|
||||||
_lastRoomRocketLaunchNoticeKey = null;
|
_lastRoomRocketLaunchNoticeKey = null;
|
||||||
_stopRoomRedPacketPresenceHeartbeat();
|
_stopRoomRedPacketPresenceHeartbeat();
|
||||||
_previewRoomSeatCount = null;
|
_previewRoomSeatCount = null;
|
||||||
|
|||||||
@ -50,6 +50,7 @@ import 'package:yumi/shared/data_sources/models/message/big_broadcast_group_mess
|
|||||||
import 'package:yumi/shared/data_sources/models/message/room_rocket_launch_broadcast_message.dart';
|
import 'package:yumi/shared/data_sources/models/message/room_rocket_launch_broadcast_message.dart';
|
||||||
import 'package:yumi/shared/data_sources/models/message/sc_floating_message.dart';
|
import 'package:yumi/shared/data_sources/models/message/sc_floating_message.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/sc_broad_cast_luck_gift_push.dart';
|
import 'package:yumi/shared/business_logic/models/res/sc_broad_cast_luck_gift_push.dart';
|
||||||
|
import 'package:yumi/shared/business_logic/models/res/sc_room_rocket_api_res.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/broad_cast_mic_change_push.dart'
|
import 'package:yumi/shared/business_logic/models/res/broad_cast_mic_change_push.dart'
|
||||||
hide Data;
|
hide Data;
|
||||||
import 'package:yumi/shared/business_logic/models/res/gift_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/gift_res.dart';
|
||||||
@ -60,6 +61,7 @@ import 'package:yumi/ui_kit/widgets/room/invite/invite_room_dialog.dart';
|
|||||||
import 'package:yumi/ui_kit/widgets/room/red_packet/room_red_packet_models.dart';
|
import 'package:yumi/ui_kit/widgets/room/red_packet/room_red_packet_models.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/room/red_packet/room_red_packet_open_dialog.dart';
|
import 'package:yumi/ui_kit/widgets/room/red_packet/room_red_packet_open_dialog.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/room/red_packet/room_red_packet_pending_cache.dart';
|
import 'package:yumi/ui_kit/widgets/room/red_packet/room_red_packet_pending_cache.dart';
|
||||||
|
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_api_mapper.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_reward_dialog_loader.dart';
|
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_reward_dialog_loader.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/room/room_msg_item.dart';
|
import 'package:yumi/ui_kit/widgets/room/room_msg_item.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/login_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/login_res.dart';
|
||||||
@ -116,6 +118,13 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
static const int _luckyGiftBurstMergeWindowMs = 1800;
|
static const int _luckyGiftBurstMergeWindowMs = 1800;
|
||||||
static const int _luckyGiftBurstRecentEventTtlMs = 5000;
|
static const int _luckyGiftBurstRecentEventTtlMs = 5000;
|
||||||
static const int _luckyGiftBurstPlaybackWatchdogMs = 8000;
|
static const int _luckyGiftBurstPlaybackWatchdogMs = 8000;
|
||||||
|
static const int _roomRocketLaunchRecentTtlMs = 90000;
|
||||||
|
static const int _roomRocketLaunchLooseRecentTtlMs = 12000;
|
||||||
|
static const List<Duration> _roomRocketRewardPopupRetryDelays = [
|
||||||
|
Duration(milliseconds: 700),
|
||||||
|
Duration(seconds: 2),
|
||||||
|
Duration(seconds: 5),
|
||||||
|
];
|
||||||
|
|
||||||
BuildContext? context;
|
BuildContext? context;
|
||||||
|
|
||||||
@ -224,6 +233,9 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
Timer? _luckGiftPushPlayTimer;
|
Timer? _luckGiftPushPlayTimer;
|
||||||
int _luckGiftPushPlaybackToken = 0;
|
int _luckGiftPushPlaybackToken = 0;
|
||||||
final Map<String, int> _recentLuckGiftPushEventTimes = <String, int>{};
|
final Map<String, int> _recentLuckGiftPushEventTimes = <String, int>{};
|
||||||
|
final Map<String, int> _recentRoomRocketLaunchTimes = <String, int>{};
|
||||||
|
final Map<String, int> _recentRoomRocketLaunchLooseTimes = <String, int>{};
|
||||||
|
Timer? _roomRocketRewardPopupRetryTimer;
|
||||||
int get currentLuckGiftBurstPlaybackToken => _luckGiftPushPlaybackToken;
|
int get currentLuckGiftBurstPlaybackToken => _luckGiftPushPlaybackToken;
|
||||||
String? roomRedPacketBroadcastGroupId;
|
String? roomRedPacketBroadcastGroupId;
|
||||||
String? roomRedPacketBroadcastRegionCode;
|
String? roomRedPacketBroadcastRegionCode;
|
||||||
@ -1904,7 +1916,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
|
|
||||||
void _handleVoiceRoomRocketStatusUpdate(dynamic payload) {
|
void _handleVoiceRoomRocketStatusUpdate(dynamic payload) {
|
||||||
final data = _broadcastPayloadMap(payload);
|
final data = _broadcastPayloadMap(payload);
|
||||||
final roomId = _payloadText(data['roomId']);
|
final roomId = _payloadRoomId(data);
|
||||||
if (!_isCurrentVoiceRoom(roomId)) {
|
if (!_isCurrentVoiceRoom(roomId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1916,11 +1928,21 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
currentContext,
|
currentContext,
|
||||||
listen: false,
|
listen: false,
|
||||||
);
|
);
|
||||||
_publishRoomRocketLaunchNoticeFromStatusPayload(
|
final launch = _buildRoomRocketLaunchFromStatusPayload(
|
||||||
rtcProvider: rtcProvider,
|
rtcProvider: rtcProvider,
|
||||||
payload: data,
|
payload: data,
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
);
|
);
|
||||||
|
if (_shouldHandleRoomRocketLaunchFromStatusPayload(
|
||||||
|
rtcProvider: rtcProvider,
|
||||||
|
payload: data,
|
||||||
|
launch: launch,
|
||||||
|
)) {
|
||||||
|
_handleCurrentVisibleRoomRocketLaunch(
|
||||||
|
rtcProvider: rtcProvider,
|
||||||
|
launch: launch,
|
||||||
|
);
|
||||||
|
}
|
||||||
unawaited(rtcProvider.refreshRoomRocketStatus(roomId: roomId));
|
unawaited(rtcProvider.refreshRoomRocketStatus(roomId: roomId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1948,16 +1970,10 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
rtcProvider.shouldShowRoomVisualEffects &&
|
rtcProvider.shouldShowRoomVisualEffects &&
|
||||||
rtcProvider.isVoiceRoomRouteVisible;
|
rtcProvider.isVoiceRoomRouteVisible;
|
||||||
if (isCurrentVisibleRoom) {
|
if (isCurrentVisibleRoom) {
|
||||||
addMsg(
|
_handleCurrentVisibleRoomRocketLaunch(
|
||||||
_buildRoomRocketLaunchNoticeMsg(
|
rtcProvider: rtcProvider,
|
||||||
_firstNonBlank([
|
launch: launch,
|
||||||
rtcProvider.currenRoom?.roomProfile?.roomProfile?.roomAccount,
|
|
||||||
launch.roomAccount,
|
|
||||||
]),
|
|
||||||
launch,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
rtcProvider.handleRoomRocketLaunchBroadcast(launch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1970,7 +1986,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
|
|
||||||
void _handleVoiceRoomRocketRewardPopup(dynamic payload) {
|
void _handleVoiceRoomRocketRewardPopup(dynamic payload) {
|
||||||
final data = _broadcastPayloadMap(payload);
|
final data = _broadcastPayloadMap(payload);
|
||||||
final roomId = _payloadText(data['roomId']);
|
final roomId = _payloadRoomId(data);
|
||||||
final currentRoomId = _currentVoiceRoomId();
|
final currentRoomId = _currentVoiceRoomId();
|
||||||
final resolvedRoomId = roomId.isEmpty ? currentRoomId : roomId;
|
final resolvedRoomId = roomId.isEmpty ? currentRoomId : roomId;
|
||||||
if (resolvedRoomId.isEmpty ||
|
if (resolvedRoomId.isEmpty ||
|
||||||
@ -1981,13 +1997,45 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final userIds = _payloadStringList(data['userIds']);
|
final initialRoomRecords = _roomRocketRewardRecordsFromPayload(data);
|
||||||
final currentUserId =
|
unawaited(
|
||||||
AccountStorage().getCurrentUser()?.userProfile?.id?.trim() ?? '';
|
_showRoomRocketRewardPopupDialog(
|
||||||
if (currentUserId.isEmpty || !userIds.contains(currentUserId)) {
|
resolvedRoomId,
|
||||||
return;
|
initialRoomRecords: initialRoomRecords,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleCurrentVisibleRoomRocketLaunch({
|
||||||
|
required RealTimeCommunicationManager rtcProvider,
|
||||||
|
required RoomRocketLaunchBroadcastMessage launch,
|
||||||
|
}) {
|
||||||
|
final launchKey = _roomRocketLaunchNoticeKey(launch);
|
||||||
|
final looseLaunchKey = _roomRocketLaunchLooseKey(launch);
|
||||||
|
final now = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
_pruneRecentRoomRocketLaunches(now);
|
||||||
|
final alreadyHandled =
|
||||||
|
(launchKey.isNotEmpty &&
|
||||||
|
_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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
rtcProvider.handleRoomRocketLaunchBroadcast(launch);
|
||||||
}
|
}
|
||||||
unawaited(_showRoomRocketRewardPopupDialog(resolvedRoomId));
|
unawaited(_showRoomRocketRewardPopupDialog(launch.roomId));
|
||||||
}
|
}
|
||||||
|
|
||||||
String _rocketIconUrlForLevel(int level) {
|
String _rocketIconUrlForLevel(int level) {
|
||||||
@ -2008,16 +2056,29 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showRoomRocketRewardPopupDialog(String roomId) async {
|
Future<void> _showRoomRocketRewardPopupDialog(
|
||||||
|
String roomId, {
|
||||||
|
int attempt = 0,
|
||||||
|
List<SCRoomRocketRewardRecordRes> initialRoomRecords =
|
||||||
|
const <SCRoomRocketRewardRecordRes>[],
|
||||||
|
}) async {
|
||||||
try {
|
try {
|
||||||
final res = await SCChatRoomRepository().roomRocketRewardPopups(roomId);
|
final res = await SCChatRoomRepository().roomRocketRewardPopups(roomId);
|
||||||
if (res.records.isEmpty) {
|
if (res.records.isEmpty && initialRoomRecords.isEmpty) {
|
||||||
|
_scheduleRoomRocketRewardPopupRetry(
|
||||||
|
roomId,
|
||||||
|
attempt,
|
||||||
|
initialRoomRecords: initialRoomRecords,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_roomRocketRewardPopupRetryTimer?.cancel();
|
||||||
|
_roomRocketRewardPopupRetryTimer = null;
|
||||||
final recordIds = res.records
|
final recordIds = res.records
|
||||||
.map((item) => item.id)
|
.map((item) => item.id)
|
||||||
.where((item) => item.isNotEmpty)
|
.where((item) => item.isNotEmpty)
|
||||||
.toList(growable: false);
|
.toList(growable: false);
|
||||||
|
final userProfileResolver = _roomRocketRewardUserProfileResolver();
|
||||||
SmartDialog.dismiss(tag: _roomRocketRewardDialogTag);
|
SmartDialog.dismiss(tag: _roomRocketRewardDialogTag);
|
||||||
SmartDialog.show(
|
SmartDialog.show(
|
||||||
tag: _roomRocketRewardDialogTag,
|
tag: _roomRocketRewardDialogTag,
|
||||||
@ -2030,6 +2091,8 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
(_) => RoomRocketRewardDialogLoader(
|
(_) => RoomRocketRewardDialogLoader(
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
initialPopupRecords: res.records,
|
initialPopupRecords: res.records,
|
||||||
|
initialRoomRecords: initialRoomRecords,
|
||||||
|
userProfileResolver: userProfileResolver,
|
||||||
onClose: () {
|
onClose: () {
|
||||||
SmartDialog.dismiss(tag: _roomRocketRewardDialogTag);
|
SmartDialog.dismiss(tag: _roomRocketRewardDialogTag);
|
||||||
if (recordIds.isNotEmpty) {
|
if (recordIds.isNotEmpty) {
|
||||||
@ -2040,7 +2103,83 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (_) {}
|
} catch (_) {
|
||||||
|
_scheduleRoomRocketRewardPopupRetry(
|
||||||
|
roomId,
|
||||||
|
attempt,
|
||||||
|
initialRoomRecords: initialRoomRecords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _scheduleRoomRocketRewardPopupRetry(
|
||||||
|
String roomId,
|
||||||
|
int attempt, {
|
||||||
|
List<SCRoomRocketRewardRecordRes> initialRoomRecords =
|
||||||
|
const <SCRoomRocketRewardRecordRes>[],
|
||||||
|
}) {
|
||||||
|
if (attempt >= _roomRocketRewardPopupRetryDelays.length ||
|
||||||
|
!_isCurrentVoiceRoom(roomId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_roomRocketRewardPopupRetryTimer?.cancel();
|
||||||
|
_roomRocketRewardPopupRetryTimer = Timer(
|
||||||
|
_roomRocketRewardPopupRetryDelays[attempt],
|
||||||
|
() {
|
||||||
|
_roomRocketRewardPopupRetryTimer = null;
|
||||||
|
unawaited(
|
||||||
|
_showRoomRocketRewardPopupDialog(
|
||||||
|
roomId,
|
||||||
|
attempt: attempt + 1,
|
||||||
|
initialRoomRecords: initialRoomRecords,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomRocketRewardUserProfileResolver? _roomRocketRewardUserProfileResolver() {
|
||||||
|
final currentContext = context;
|
||||||
|
if (currentContext == null || !currentContext.mounted) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final rtcProvider = Provider.of<RealTimeCommunicationManager>(
|
||||||
|
currentContext,
|
||||||
|
listen: false,
|
||||||
|
);
|
||||||
|
return rtcProvider.roomRocketRewardUserProfileForRecord;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SCRoomRocketRewardRecordRes> _roomRocketRewardRecordsFromPayload(
|
||||||
|
Map<String, dynamic> payload,
|
||||||
|
) {
|
||||||
|
final candidates = [
|
||||||
|
payload['roomRecords'],
|
||||||
|
payload['roomRewardRecords'],
|
||||||
|
payload['room_reward_records'],
|
||||||
|
payload['allRecords'],
|
||||||
|
payload['allRewardRecords'],
|
||||||
|
payload['all_reward_records'],
|
||||||
|
payload['rewardRecords'],
|
||||||
|
payload['reward_records'],
|
||||||
|
payload['rewardRecordList'],
|
||||||
|
payload['recordList'],
|
||||||
|
payload['records'],
|
||||||
|
payload['list'],
|
||||||
|
payload['items'],
|
||||||
|
payload['rows'],
|
||||||
|
];
|
||||||
|
for (final candidate in candidates) {
|
||||||
|
final records = SCRoomRocketRewardRecordRes.listFromJson(candidate);
|
||||||
|
if (records.isNotEmpty) {
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return const <SCRoomRocketRewardRecordRes>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
SCFloatingMessage _buildRoomRocketLaunchFloatingMessage(
|
SCFloatingMessage _buildRoomRocketLaunchFloatingMessage(
|
||||||
@ -2095,47 +2234,87 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _publishRoomRocketLaunchNoticeFromStatusPayload({
|
String _roomRocketLaunchLooseKey(RoomRocketLaunchBroadcastMessage launch) {
|
||||||
|
if (launch.roomId.isEmpty) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return ['rocket_launch_loose', launch.roomId, launch.safeLevel].join('|');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _shouldHandleRoomRocketLaunchFromStatusPayload({
|
||||||
|
required RealTimeCommunicationManager rtcProvider,
|
||||||
|
required Map<String, dynamic> payload,
|
||||||
|
required RoomRocketLaunchBroadcastMessage launch,
|
||||||
|
}) {
|
||||||
|
final currentPercent = _roomRocketPayloadPercent(payload);
|
||||||
|
if (currentPercent < 99.5) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final previousPercent = _roomRocketStatusPercent(
|
||||||
|
rtcProvider.roomRocketStatus,
|
||||||
|
);
|
||||||
|
if (previousPercent < 99.5) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final launchKey = _roomRocketLaunchNoticeKey(launch);
|
||||||
|
if (launchKey.isEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_pruneRecentRoomRocketLaunches(DateTime.now().millisecondsSinceEpoch);
|
||||||
|
final looseLaunchKey = _roomRocketLaunchLooseKey(launch);
|
||||||
|
return !_recentRoomRocketLaunchTimes.containsKey(launchKey) &&
|
||||||
|
(looseLaunchKey.isEmpty ||
|
||||||
|
!_recentRoomRocketLaunchLooseTimes.containsKey(looseLaunchKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomRocketLaunchBroadcastMessage _buildRoomRocketLaunchFromStatusPayload({
|
||||||
required RealTimeCommunicationManager rtcProvider,
|
required RealTimeCommunicationManager rtcProvider,
|
||||||
required Map<String, dynamic> payload,
|
required Map<String, dynamic> payload,
|
||||||
required String roomId,
|
required String roomId,
|
||||||
}) {
|
}) {
|
||||||
final previousPercent = _roomRocketStatusPercent(
|
final roomProfile = rtcProvider.currenRoom?.roomProfile?.roomProfile;
|
||||||
rtcProvider.roomRocketStatus,
|
|
||||||
);
|
|
||||||
final currentPercent = _roomRocketPayloadPercent(payload);
|
|
||||||
if (previousPercent >= 99.5 || currentPercent < 99.5) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final groupId =
|
|
||||||
(rtcProvider.currenRoom?.roomProfile?.roomProfile?.roomAccount ?? '')
|
|
||||||
.trim();
|
|
||||||
if (groupId.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final level = _roomRocketPayloadLevel(
|
final level = _roomRocketPayloadLevel(
|
||||||
payload,
|
payload,
|
||||||
rtcProvider.roomRocketStatus?.currentLevel ??
|
rtcProvider.roomRocketStatus?.currentLevel ??
|
||||||
rtcProvider.roomRocketStatus?.level?.toInt() ??
|
rtcProvider.roomRocketStatus?.level?.toInt() ??
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
addMsg(
|
return RoomRocketLaunchBroadcastMessage(
|
||||||
Msg(
|
roomId: roomId,
|
||||||
groupId: groupId,
|
roomAccount: _firstNonBlank([
|
||||||
msg: _roomRocketPayloadNoticeSeconds(payload).toString(),
|
roomProfile?.roomAccount,
|
||||||
type: SCRoomMsgType.rocketLaunchNotice,
|
_payloadText(payload['roomAccount'] ?? payload['room_account']),
|
||||||
number: _roomRocketPayloadNoticeSeconds(payload),
|
]),
|
||||||
rocketIconUrl: _firstNonBlank([
|
roomName: _firstNonBlank([
|
||||||
_rocketIconFromPayload(payload),
|
roomProfile?.roomName,
|
||||||
_rocketIconUrlForLevel(level),
|
_payloadText(payload['roomName'] ?? payload['room_name']),
|
||||||
]),
|
]),
|
||||||
giftBatchId: _roomRocketLaunchNoticeKeyForValues(
|
roomCoverUrl: _firstNonBlank([
|
||||||
roomId: roomId,
|
roomProfile?.roomCover,
|
||||||
level: level,
|
_payloadAssetText(payload['roomCoverUrl'] ?? payload['room_cover_url']),
|
||||||
roundNo: _payloadNum(payload['roundNo'])?.toInt() ?? 0,
|
_payloadAssetText(payload['roomCover'] ?? payload['room_cover']),
|
||||||
launchNo: _payloadText(payload['launchNo']),
|
]),
|
||||||
),
|
roundNo:
|
||||||
|
_payloadNum(payload['roundNo'] ?? payload['round_no'])?.toInt() ?? 0,
|
||||||
|
level: level,
|
||||||
|
rocketIconUrl: _firstNonBlank([
|
||||||
|
_rocketIconFromPayload(payload),
|
||||||
|
_rocketIconUrlForLevel(level),
|
||||||
|
]),
|
||||||
|
rocketAnimationUrl: _rocketAnimationFromPayload(payload),
|
||||||
|
durationSeconds: _roomRocketPayloadNoticeSeconds(payload),
|
||||||
|
triggerUser: const RoomRocketLaunchTriggerUser(
|
||||||
|
userId: '',
|
||||||
|
nickname: '',
|
||||||
|
avatar: '',
|
||||||
|
account: '',
|
||||||
|
countryCode: '',
|
||||||
|
countryName: '',
|
||||||
),
|
),
|
||||||
|
triggerUserId: _payloadText(
|
||||||
|
payload['triggerUserId'] ?? payload['trigger_user_id'],
|
||||||
|
),
|
||||||
|
launchNo: _payloadText(payload['launchNo'] ?? payload['launch_no']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2160,7 +2339,9 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
double _roomRocketPayloadPercent(Map<String, dynamic> payload) {
|
double _roomRocketPayloadPercent(Map<String, dynamic> payload) {
|
||||||
final value = _payloadNum(
|
final value = _payloadNum(
|
||||||
payload['displayPercent'] ??
|
payload['displayPercent'] ??
|
||||||
|
payload['display_percent'] ??
|
||||||
payload['energyPercent'] ??
|
payload['energyPercent'] ??
|
||||||
|
payload['energy_percent'] ??
|
||||||
payload['percent'],
|
payload['percent'],
|
||||||
);
|
);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
@ -2168,9 +2349,14 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
final percent = raw > 0 && raw <= 1 ? raw * 100 : raw;
|
final percent = raw > 0 && raw <= 1 ? raw * 100 : raw;
|
||||||
return percent.clamp(0, 100).toDouble();
|
return percent.clamp(0, 100).toDouble();
|
||||||
}
|
}
|
||||||
final currentEnergy = _payloadNum(payload['currentEnergy']);
|
final currentEnergy = _payloadNum(
|
||||||
|
payload['currentEnergy'] ?? payload['current_energy'],
|
||||||
|
);
|
||||||
final maxEnergy = _payloadNum(
|
final maxEnergy = _payloadNum(
|
||||||
payload['maxEnergy'] ?? payload['needEnergy'],
|
payload['maxEnergy'] ??
|
||||||
|
payload['max_energy'] ??
|
||||||
|
payload['needEnergy'] ??
|
||||||
|
payload['need_energy'],
|
||||||
);
|
);
|
||||||
if (currentEnergy == null || maxEnergy == null || maxEnergy <= 0) {
|
if (currentEnergy == null || maxEnergy == null || maxEnergy <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -2181,8 +2367,11 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
int _roomRocketPayloadLevel(Map<String, dynamic> payload, int fallback) {
|
int _roomRocketPayloadLevel(Map<String, dynamic> payload, int fallback) {
|
||||||
final value = _payloadNum(
|
final value = _payloadNum(
|
||||||
payload['currentLevel'] ??
|
payload['currentLevel'] ??
|
||||||
|
payload['current_level'] ??
|
||||||
payload['level'] ??
|
payload['level'] ??
|
||||||
payload['rocketLevel'] ??
|
payload['rocketLevel'] ??
|
||||||
|
payload['rocket_level'] ??
|
||||||
|
payload['from_level'] ??
|
||||||
payload['fromLevel'],
|
payload['fromLevel'],
|
||||||
);
|
);
|
||||||
return (value?.toInt() ?? fallback).clamp(1, 99).toInt();
|
return (value?.toInt() ?? fallback).clamp(1, 99).toInt();
|
||||||
@ -2192,8 +2381,12 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
final seconds =
|
final seconds =
|
||||||
_payloadNum(
|
_payloadNum(
|
||||||
payload['countdownSeconds'] ??
|
payload['countdownSeconds'] ??
|
||||||
|
payload['countdown_seconds'] ??
|
||||||
payload['launchDelaySeconds'] ??
|
payload['launchDelaySeconds'] ??
|
||||||
|
payload['launch_delay_seconds'] ??
|
||||||
payload['delaySeconds'] ??
|
payload['delaySeconds'] ??
|
||||||
|
payload['delay_seconds'] ??
|
||||||
|
payload['duration_seconds'] ??
|
||||||
payload['durationSeconds'],
|
payload['durationSeconds'],
|
||||||
)?.toInt() ??
|
)?.toInt() ??
|
||||||
10;
|
10;
|
||||||
@ -2206,6 +2399,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
String _rocketIconFromPayload(Map<String, dynamic> payload) {
|
String _rocketIconFromPayload(Map<String, dynamic> payload) {
|
||||||
return _firstNonBlank([
|
return _firstNonBlank([
|
||||||
_payloadAssetText(payload['rocketIconUrl']),
|
_payloadAssetText(payload['rocketIconUrl']),
|
||||||
|
_payloadAssetText(payload['rocket_icon_url']),
|
||||||
_payloadAssetText(payload['rocketIcon']),
|
_payloadAssetText(payload['rocketIcon']),
|
||||||
_payloadAssetText(payload['rocketUrl']),
|
_payloadAssetText(payload['rocketUrl']),
|
||||||
_payloadAssetText(payload['rocketImageUrl']),
|
_payloadAssetText(payload['rocketImageUrl']),
|
||||||
@ -2213,6 +2407,49 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _rocketAnimationFromPayload(Map<String, dynamic> payload) {
|
||||||
|
return _firstNonBlank([
|
||||||
|
_payloadAssetText(payload['rocketAnimationUrl']),
|
||||||
|
_payloadAssetText(payload['rocket_animation_url']),
|
||||||
|
_payloadAssetText(payload['rocketSvgaUrl']),
|
||||||
|
_payloadAssetText(payload['rocket_svga_url']),
|
||||||
|
_payloadAssetText(payload['animationUrl']),
|
||||||
|
_payloadAssetText(payload['animation_url']),
|
||||||
|
_payloadAssetText(payload['launchAnimationUrl']),
|
||||||
|
_payloadAssetText(payload['launch_animation_url']),
|
||||||
|
_payloadAssetText(payload['svgaUrl']),
|
||||||
|
_payloadAssetText(payload['sourceUrl']),
|
||||||
|
_payloadAssetText(payload['source_url']),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _payloadRoomId(Map<String, dynamic> payload) {
|
||||||
|
return _firstNonBlank([
|
||||||
|
_payloadText(payload['roomId']),
|
||||||
|
_payloadText(payload['room_id']),
|
||||||
|
_payloadText(payload['roomID']),
|
||||||
|
_payloadText(payload['voiceRoomId']),
|
||||||
|
_payloadText(payload['voice_room_id']),
|
||||||
|
_payloadText(payload['chatRoomId']),
|
||||||
|
_payloadText(payload['chat_room_id']),
|
||||||
|
_payloadText(_broadcastPayloadMap(payload['room'])['id']),
|
||||||
|
_payloadText(_broadcastPayloadMap(payload['room'])['roomId']),
|
||||||
|
_payloadText(_broadcastPayloadMap(payload['room'])['room_id']),
|
||||||
|
_payloadText(_broadcastPayloadMap(payload['roomInfo'])['id']),
|
||||||
|
_payloadText(_broadcastPayloadMap(payload['roomInfo'])['roomId']),
|
||||||
|
_payloadText(_broadcastPayloadMap(payload['roomInfo'])['room_id']),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _pruneRecentRoomRocketLaunches(int now) {
|
||||||
|
_recentRoomRocketLaunchTimes.removeWhere(
|
||||||
|
(_, timestamp) => now - timestamp > _roomRocketLaunchRecentTtlMs,
|
||||||
|
);
|
||||||
|
_recentRoomRocketLaunchLooseTimes.removeWhere(
|
||||||
|
(_, timestamp) => now - timestamp > _roomRocketLaunchLooseRecentTtlMs,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
String _roomRocketLaunchNoticeKeyForValues({
|
String _roomRocketLaunchNoticeKeyForValues({
|
||||||
required String roomId,
|
required String roomId,
|
||||||
required int level,
|
required int level,
|
||||||
@ -2398,37 +2635,35 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
} else if (type == "ROCKET_ENERGY_LAUNCH") {
|
} else if (type == "ROCKET_ENERGY_LAUNCH") {
|
||||||
///火箭触发飘屏
|
///火箭触发飘屏
|
||||||
var fdata = data["data"];
|
var fdata = data["data"];
|
||||||
final launchRoomId = _payloadText(fdata["roomId"]);
|
final payload = _broadcastPayloadMap(fdata);
|
||||||
|
final launchRoomId = _payloadRoomId(payload);
|
||||||
if (_isCurrentHiddenVoiceRoom(launchRoomId)) {
|
if (_isCurrentHiddenVoiceRoom(launchRoomId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final rocketIconUrl = _firstNonBlank([
|
final rocketIconUrl = _firstNonBlank([
|
||||||
_payloadText(fdata["rocketIconUrl"]),
|
_rocketIconFromPayload(payload),
|
||||||
_payloadText(fdata["rocketIcon"]),
|
_payloadAssetText(payload["giftUrl"]),
|
||||||
_payloadText(fdata["rocketUrl"]),
|
_payloadAssetText(payload["giftIcon"]),
|
||||||
_payloadText(fdata["rocketImageUrl"]),
|
|
||||||
_payloadText(fdata["giftUrl"]),
|
|
||||||
_payloadText(fdata["giftIcon"]),
|
|
||||||
]);
|
]);
|
||||||
SCFloatingMessage msg = SCFloatingMessage(
|
SCFloatingMessage msg = SCFloatingMessage(
|
||||||
type: 3,
|
type: 3,
|
||||||
roomId: launchRoomId,
|
roomId: launchRoomId,
|
||||||
rocketLevel: fdata["fromLevel"],
|
rocketLevel: _roomRocketPayloadLevel(payload, 1),
|
||||||
userAvatarUrl: _firstNonBlank([
|
userAvatarUrl: _firstNonBlank([
|
||||||
_payloadText(fdata["roomCoverUrl"]),
|
_payloadAssetText(payload["roomCoverUrl"]),
|
||||||
_payloadText(fdata["roomCover"]),
|
_payloadAssetText(payload["roomCover"]),
|
||||||
_payloadText(fdata["roomAvatar"]),
|
_payloadAssetText(payload["roomAvatar"]),
|
||||||
_payloadText(fdata["roomIcon"]),
|
_payloadAssetText(payload["roomIcon"]),
|
||||||
_payloadText(fdata["coverUrl"]),
|
_payloadAssetText(payload["coverUrl"]),
|
||||||
_payloadText(fdata["cover"]),
|
_payloadAssetText(payload["cover"]),
|
||||||
_payloadText(fdata["userAvatar"]),
|
_payloadAssetText(payload["userAvatar"]),
|
||||||
]),
|
]),
|
||||||
userName: _firstNonBlank([
|
userName: _firstNonBlank([
|
||||||
_payloadText(fdata["roomName"]),
|
_payloadText(payload["roomName"]),
|
||||||
_payloadText(fdata["roomAccount"]),
|
_payloadText(payload["roomAccount"]),
|
||||||
_payloadText(fdata["nickname"]),
|
_payloadText(payload["nickname"]),
|
||||||
]),
|
]),
|
||||||
userId: fdata["actualAccount"],
|
userId: _payloadText(payload["actualAccount"]),
|
||||||
giftUrl: rocketIconUrl,
|
giftUrl: rocketIconUrl,
|
||||||
fallbackUrl: rocketIconUrl,
|
fallbackUrl: rocketIconUrl,
|
||||||
priority: 1000,
|
priority: 1000,
|
||||||
@ -3167,6 +3402,10 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
roomGiftMsgList.clear();
|
roomGiftMsgList.clear();
|
||||||
roomChatMsgList.clear();
|
roomChatMsgList.clear();
|
||||||
_resetLuckGiftBurstQueue();
|
_resetLuckGiftBurstQueue();
|
||||||
|
_recentRoomRocketLaunchTimes.clear();
|
||||||
|
_recentRoomRocketLaunchLooseTimes.clear();
|
||||||
|
_roomRocketRewardPopupRetryTimer?.cancel();
|
||||||
|
_roomRocketRewardPopupRetryTimer = null;
|
||||||
onNewMessageListenerGroupMap.forEach((k, v) {
|
onNewMessageListenerGroupMap.forEach((k, v) {
|
||||||
v = null;
|
v = null;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -604,17 +604,41 @@ class SCRoomRocketKingUserRes {
|
|||||||
|
|
||||||
factory SCRoomRocketKingUserRes.fromJson(dynamic json) {
|
factory SCRoomRocketKingUserRes.fromJson(dynamic json) {
|
||||||
final data = _asMap(json);
|
final data = _asMap(json);
|
||||||
final profile = _asMap(data['userProfile'] ?? data['user']);
|
final profile = _asMap(
|
||||||
|
data['userProfile'] ??
|
||||||
|
data['user'] ??
|
||||||
|
data['userInfo'] ??
|
||||||
|
data['profile'],
|
||||||
|
);
|
||||||
return SCRoomRocketKingUserRes(
|
return SCRoomRocketKingUserRes(
|
||||||
rank: _intValue(data['rank'] ?? data['ranking']),
|
rank: _intValue(data['rank'] ?? data['ranking']),
|
||||||
userId: _stringValue(data['userId'] ?? profile['id']),
|
userId: _stringValue(data['userId'] ?? profile['id']),
|
||||||
userAvatar: _stringValue(
|
userAvatar: _firstAssetString([
|
||||||
data['userAvatar'] ??
|
data['userAvatar'],
|
||||||
data['avatar'] ??
|
data['userAvatarUrl'],
|
||||||
data['avatarUrl'] ??
|
data['avatar'],
|
||||||
profile['userAvatar'] ??
|
data['avatarUrl'],
|
||||||
profile['avatar'],
|
data['headImg'],
|
||||||
),
|
data['headUrl'],
|
||||||
|
data['photo'],
|
||||||
|
data['portrait'],
|
||||||
|
data['profileImageUrl'],
|
||||||
|
data['profilePicture'],
|
||||||
|
data['avatarResource'],
|
||||||
|
data['userAvatarResource'],
|
||||||
|
profile['userAvatar'],
|
||||||
|
profile['userAvatarUrl'],
|
||||||
|
profile['avatar'],
|
||||||
|
profile['avatarUrl'],
|
||||||
|
profile['headImg'],
|
||||||
|
profile['headUrl'],
|
||||||
|
profile['photo'],
|
||||||
|
profile['portrait'],
|
||||||
|
profile['profileImageUrl'],
|
||||||
|
profile['profilePicture'],
|
||||||
|
profile['avatarResource'],
|
||||||
|
profile['userAvatarResource'],
|
||||||
|
]),
|
||||||
userNickname: _stringValue(
|
userNickname: _stringValue(
|
||||||
data['userNickname'] ??
|
data['userNickname'] ??
|
||||||
data['nickname'] ??
|
data['nickname'] ??
|
||||||
@ -771,7 +795,7 @@ class SCRoomRocketRewardPopupRes {
|
|||||||
factory SCRoomRocketRewardPopupRes.fromJson(dynamic json) {
|
factory SCRoomRocketRewardPopupRes.fromJson(dynamic json) {
|
||||||
final data = _asMap(json);
|
final data = _asMap(json);
|
||||||
return SCRoomRocketRewardPopupRes(
|
return SCRoomRocketRewardPopupRes(
|
||||||
records: SCRoomRocketRewardRecordRes.listFromJson(data['records']),
|
records: _rewardRecordList(data),
|
||||||
cursor: _intValue(data['cursor'], fallback: 1),
|
cursor: _intValue(data['cursor'], fallback: 1),
|
||||||
limit: _intValue(data['limit'], fallback: 10),
|
limit: _intValue(data['limit'], fallback: 10),
|
||||||
emptyReason: _stringValue(data['emptyReason']),
|
emptyReason: _stringValue(data['emptyReason']),
|
||||||
@ -804,7 +828,7 @@ class SCRoomRocketRewardRecordsRes {
|
|||||||
factory SCRoomRocketRewardRecordsRes.fromJson(dynamic json) {
|
factory SCRoomRocketRewardRecordsRes.fromJson(dynamic json) {
|
||||||
final data = _asMap(json);
|
final data = _asMap(json);
|
||||||
return SCRoomRocketRewardRecordsRes(
|
return SCRoomRocketRewardRecordsRes(
|
||||||
records: SCRoomRocketRewardRecordRes.listFromJson(data['records']),
|
records: _rewardRecordList(data),
|
||||||
cursor: _intValue(data['cursor'], fallback: 1),
|
cursor: _intValue(data['cursor'], fallback: 1),
|
||||||
limit: _intValue(data['limit'], fallback: 10),
|
limit: _intValue(data['limit'], fallback: 10),
|
||||||
emptyReason: _stringValue(data['emptyReason']),
|
emptyReason: _stringValue(data['emptyReason']),
|
||||||
@ -855,39 +879,222 @@ class SCRoomRocketRewardRecordRes {
|
|||||||
|
|
||||||
factory SCRoomRocketRewardRecordRes.fromJson(dynamic json) {
|
factory SCRoomRocketRewardRecordRes.fromJson(dynamic json) {
|
||||||
final data = _asMap(json);
|
final data = _asMap(json);
|
||||||
|
final user = _asMap(data['user']);
|
||||||
|
final userInfo = _asMap(data['userInfo'] ?? data['user_info']);
|
||||||
|
final receiver = _asMap(data['receiver']);
|
||||||
|
final receiveUser = _asMap(data['receiveUser'] ?? data['receive_user']);
|
||||||
|
final acceptUser = _asMap(data['acceptUser'] ?? data['accept_user']);
|
||||||
|
final recipient = _asMap(
|
||||||
|
data['recipient'] ?? data['targetUser'] ?? data['target_user'],
|
||||||
|
);
|
||||||
|
final winner = _asMap(
|
||||||
|
data['winner'] ?? data['winnerUser'] ?? data['winner_user'],
|
||||||
|
);
|
||||||
|
final profile = _asMap(
|
||||||
|
_firstPayload([
|
||||||
|
data['userProfile'],
|
||||||
|
data['user_profile'],
|
||||||
|
user['userProfile'],
|
||||||
|
user['user_profile'],
|
||||||
|
user['profile'],
|
||||||
|
userInfo['userProfile'],
|
||||||
|
userInfo['user_profile'],
|
||||||
|
userInfo['profile'],
|
||||||
|
receiver['userProfile'],
|
||||||
|
receiver['user_profile'],
|
||||||
|
receiver['profile'],
|
||||||
|
receiveUser['userProfile'],
|
||||||
|
receiveUser['user_profile'],
|
||||||
|
receiveUser['profile'],
|
||||||
|
acceptUser['userProfile'],
|
||||||
|
acceptUser['user_profile'],
|
||||||
|
acceptUser['profile'],
|
||||||
|
recipient['userProfile'],
|
||||||
|
recipient['user_profile'],
|
||||||
|
recipient['profile'],
|
||||||
|
winner['userProfile'],
|
||||||
|
winner['user_profile'],
|
||||||
|
winner['profile'],
|
||||||
|
userInfo,
|
||||||
|
data['profile'],
|
||||||
|
user,
|
||||||
|
receiver,
|
||||||
|
receiveUser,
|
||||||
|
acceptUser,
|
||||||
|
recipient,
|
||||||
|
winner,
|
||||||
|
]),
|
||||||
|
);
|
||||||
return SCRoomRocketRewardRecordRes(
|
return SCRoomRocketRewardRecordRes(
|
||||||
id: _stringValue(data['id']),
|
id: _stringValue(data['id']),
|
||||||
launchNo: _stringValue(data['launchNo']),
|
launchNo: _stringValue(data['launchNo'] ?? data['launch_no']),
|
||||||
roomId: _stringValue(data['roomId']),
|
roomId: _stringValue(data['roomId'] ?? data['room_id']),
|
||||||
dayKey: _stringValue(data['dayKey']),
|
dayKey: _stringValue(data['dayKey'] ?? data['day_key']),
|
||||||
roundNo: _intValue(data['roundNo']),
|
roundNo: _intValue(data['roundNo'] ?? data['round_no']),
|
||||||
level: _intValue(data['level']),
|
level: _intValue(data['level']),
|
||||||
userId: _stringValue(data['userId']),
|
userId: _stringValue(
|
||||||
userAvatar: _stringValue(
|
_firstPayload([
|
||||||
data['userAvatar'] ??
|
data['userId'],
|
||||||
data['avatar'] ??
|
data['user_id'],
|
||||||
data['avatarUrl'] ??
|
data['uid'],
|
||||||
_asMap(data['userProfile'] ?? data['user'])['userAvatar'] ??
|
data['receiverUserId'],
|
||||||
_asMap(data['userProfile'] ?? data['user'])['avatar'],
|
data['receiveUserId'],
|
||||||
|
data['acceptUserId'],
|
||||||
|
data['recipientUserId'],
|
||||||
|
data['targetUserId'],
|
||||||
|
data['winnerUserId'],
|
||||||
|
data['receiver_user_id'],
|
||||||
|
data['receive_user_id'],
|
||||||
|
data['accept_user_id'],
|
||||||
|
data['recipient_user_id'],
|
||||||
|
data['target_user_id'],
|
||||||
|
data['winner_user_id'],
|
||||||
|
profile['id'],
|
||||||
|
profile['userId'],
|
||||||
|
profile['user_id'],
|
||||||
|
profile['uid'],
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
|
userAvatar: _firstAssetString([
|
||||||
|
data['userAvatar'],
|
||||||
|
data['user_avatar'],
|
||||||
|
data['userAvatarUrl'],
|
||||||
|
data['user_avatar_url'],
|
||||||
|
data['receiverAvatar'],
|
||||||
|
data['receiver_avatar'],
|
||||||
|
data['receiverUserAvatar'],
|
||||||
|
data['receiver_user_avatar'],
|
||||||
|
data['receiveUserAvatar'],
|
||||||
|
data['receive_user_avatar'],
|
||||||
|
data['acceptUserAvatar'],
|
||||||
|
data['accept_user_avatar'],
|
||||||
|
data['recipientAvatar'],
|
||||||
|
data['recipient_avatar'],
|
||||||
|
data['targetUserAvatar'],
|
||||||
|
data['target_user_avatar'],
|
||||||
|
data['winnerAvatar'],
|
||||||
|
data['winner_avatar'],
|
||||||
|
data['avatar'],
|
||||||
|
data['avatarUrl'],
|
||||||
|
data['avatar_url'],
|
||||||
|
data['headImg'],
|
||||||
|
data['head_img'],
|
||||||
|
data['headUrl'],
|
||||||
|
data['head_url'],
|
||||||
|
data['headIcon'],
|
||||||
|
data['head_icon'],
|
||||||
|
data['photo'],
|
||||||
|
data['photoUrl'],
|
||||||
|
data['photo_url'],
|
||||||
|
data['portrait'],
|
||||||
|
data['profileImageUrl'],
|
||||||
|
data['profile_image_url'],
|
||||||
|
data['profilePicture'],
|
||||||
|
data['profile_picture'],
|
||||||
|
data['avatarResource'],
|
||||||
|
data['avatar_resource'],
|
||||||
|
data['userAvatarResource'],
|
||||||
|
data['user_avatar_resource'],
|
||||||
|
profile['userAvatar'],
|
||||||
|
profile['user_avatar'],
|
||||||
|
profile['userAvatarUrl'],
|
||||||
|
profile['user_avatar_url'],
|
||||||
|
profile['avatar'],
|
||||||
|
profile['avatarUrl'],
|
||||||
|
profile['avatar_url'],
|
||||||
|
profile['headImg'],
|
||||||
|
profile['head_img'],
|
||||||
|
profile['headUrl'],
|
||||||
|
profile['head_url'],
|
||||||
|
profile['headIcon'],
|
||||||
|
profile['head_icon'],
|
||||||
|
profile['photo'],
|
||||||
|
profile['photoUrl'],
|
||||||
|
profile['photo_url'],
|
||||||
|
profile['portrait'],
|
||||||
|
profile['profileImageUrl'],
|
||||||
|
profile['profile_image_url'],
|
||||||
|
profile['profilePicture'],
|
||||||
|
profile['profile_picture'],
|
||||||
|
profile['avatarResource'],
|
||||||
|
profile['avatar_resource'],
|
||||||
|
profile['userAvatarResource'],
|
||||||
|
profile['user_avatar_resource'],
|
||||||
|
profile['imageUrl'],
|
||||||
|
profile['image_url'],
|
||||||
|
profile['image'],
|
||||||
|
profile['iconUrl'],
|
||||||
|
profile['icon_url'],
|
||||||
|
profile['icon'],
|
||||||
|
]),
|
||||||
userNickname: _stringValue(
|
userNickname: _stringValue(
|
||||||
data['userNickname'] ??
|
data['userNickname'] ??
|
||||||
|
data['user_nickname'] ??
|
||||||
|
data['userName'] ??
|
||||||
|
data['user_name'] ??
|
||||||
|
data['receiverNickname'] ??
|
||||||
|
data['receiver_nickname'] ??
|
||||||
|
data['receiveNickname'] ??
|
||||||
|
data['receive_nickname'] ??
|
||||||
|
data['acceptNickname'] ??
|
||||||
|
data['accept_nickname'] ??
|
||||||
|
data['recipientNickname'] ??
|
||||||
|
data['recipient_nickname'] ??
|
||||||
|
data['targetNickname'] ??
|
||||||
|
data['target_nickname'] ??
|
||||||
|
data['winnerNickname'] ??
|
||||||
|
data['winner_nickname'] ??
|
||||||
data['nickname'] ??
|
data['nickname'] ??
|
||||||
data['nickName'] ??
|
data['nickName'] ??
|
||||||
_asMap(data['userProfile'] ?? data['user'])['userNickname'] ??
|
data['nick_name'] ??
|
||||||
_asMap(data['userProfile'] ?? data['user'])['nickname'] ??
|
data['nick'] ??
|
||||||
_asMap(data['userProfile'] ?? data['user'])['nickName'],
|
data['displayName'] ??
|
||||||
|
data['display_name'] ??
|
||||||
|
data['name'] ??
|
||||||
|
profile['userNickname'] ??
|
||||||
|
profile['user_nickname'] ??
|
||||||
|
profile['userName'] ??
|
||||||
|
profile['user_name'] ??
|
||||||
|
profile['nickname'] ??
|
||||||
|
profile['nickName'] ??
|
||||||
|
profile['nick_name'] ??
|
||||||
|
profile['nick'] ??
|
||||||
|
profile['displayName'] ??
|
||||||
|
profile['display_name'] ??
|
||||||
|
profile['name'],
|
||||||
),
|
),
|
||||||
account: _stringValue(
|
account: _stringValue(
|
||||||
data['account'] ??
|
_firstPayload([
|
||||||
_asMap(data['userProfile'] ?? data['user'])['account'],
|
data['account'],
|
||||||
|
data['actualAccount'],
|
||||||
|
data['receiverAccount'],
|
||||||
|
data['receiveAccount'],
|
||||||
|
data['acceptAccount'],
|
||||||
|
data['recipientAccount'],
|
||||||
|
data['targetAccount'],
|
||||||
|
data['winnerAccount'],
|
||||||
|
data['actual_account'],
|
||||||
|
data['receiver_account'],
|
||||||
|
data['receive_account'],
|
||||||
|
data['accept_account'],
|
||||||
|
data['recipient_account'],
|
||||||
|
data['target_account'],
|
||||||
|
data['winner_account'],
|
||||||
|
profile['account'],
|
||||||
|
profile['actualAccount'],
|
||||||
|
profile['actual_account'],
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
rewardScene: _stringValue(data['rewardScene']),
|
rewardScene: _stringValue(data['rewardScene'] ?? data['reward_scene']),
|
||||||
rewardType: _stringValue(data['rewardType']),
|
rewardType: _stringValue(data['rewardType'] ?? data['reward_type']),
|
||||||
rewardItemId: _stringValue(data['rewardItemId']),
|
rewardItemId: _stringValue(
|
||||||
rewardName: _stringValue(data['rewardName']),
|
data['rewardItemId'] ?? data['reward_item_id'],
|
||||||
rewardCover: _stringValue(data['rewardCover']),
|
),
|
||||||
rewardAmount: _rewardAmountValue(data['rewardAmount']) ?? 0,
|
rewardName: _stringValue(data['rewardName'] ?? data['reward_name']),
|
||||||
|
rewardCover: _stringValue(data['rewardCover'] ?? data['reward_cover']),
|
||||||
|
rewardAmount:
|
||||||
|
_rewardAmountValue(data['rewardAmount'] ?? data['reward_amount']) ??
|
||||||
|
0,
|
||||||
rocketIconUrl: _firstAssetString([
|
rocketIconUrl: _firstAssetString([
|
||||||
data['rocket_icon_url'],
|
data['rocket_icon_url'],
|
||||||
data['rocketIconUrl'],
|
data['rocketIconUrl'],
|
||||||
@ -903,12 +1110,12 @@ class SCRoomRocketRewardRecordRes {
|
|||||||
_asMap(data['config'])['rocketIconUrl'],
|
_asMap(data['config'])['rocketIconUrl'],
|
||||||
_asMap(data['config'])['rocketIcon'],
|
_asMap(data['config'])['rocketIcon'],
|
||||||
]),
|
]),
|
||||||
expireDays: _dayValue(data['expireDays']),
|
expireDays: _dayValue(data['expireDays'] ?? data['expire_days']),
|
||||||
grantStatus: _stringValue(data['grantStatus']),
|
grantStatus: _stringValue(data['grantStatus'] ?? data['grant_status']),
|
||||||
popupStatus: _stringValue(data['popupStatus']),
|
popupStatus: _stringValue(data['popupStatus'] ?? data['popup_status']),
|
||||||
grantTime: _stringValue(data['grantTime']),
|
grantTime: _stringValue(data['grantTime'] ?? data['grant_time']),
|
||||||
createTime: _stringValue(data['createTime']),
|
createTime: _stringValue(data['createTime'] ?? data['create_time']),
|
||||||
errorMessage: _stringValue(data['errorMessage']),
|
errorMessage: _stringValue(data['errorMessage'] ?? data['error_message']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,10 +1150,7 @@ class SCRoomRocketRewardRecordRes {
|
|||||||
if (account.trim().isNotEmpty) {
|
if (account.trim().isNotEmpty) {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
if (userId.trim().isNotEmpty) {
|
return 'User';
|
||||||
return 'ID:$userId';
|
|
||||||
}
|
|
||||||
return 'You';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String get displayAmount {
|
String get displayAmount {
|
||||||
@ -988,13 +1192,73 @@ class SCRoomRocketRewardRecordRes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<SCRoomRocketRewardRecordRes> listFromJson(dynamic value) {
|
static List<SCRoomRocketRewardRecordRes> listFromJson(dynamic value) {
|
||||||
if (value is! Iterable) {
|
return _rewardRecordList(value);
|
||||||
return const <SCRoomRocketRewardRecordRes>[];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<SCRoomRocketRewardRecordRes> _rewardRecordList(dynamic value) {
|
||||||
|
if (value is Iterable && value is! String) {
|
||||||
return value
|
return value
|
||||||
.map(SCRoomRocketRewardRecordRes.fromJson)
|
.map(SCRoomRocketRewardRecordRes.fromJson)
|
||||||
.toList(growable: false);
|
.toList(growable: false);
|
||||||
}
|
}
|
||||||
|
final data = _asMap(value);
|
||||||
|
if (data.isEmpty) {
|
||||||
|
return const <SCRoomRocketRewardRecordRes>[];
|
||||||
|
}
|
||||||
|
if (_looksLikeRewardRecord(data)) {
|
||||||
|
return [SCRoomRocketRewardRecordRes.fromJson(data)];
|
||||||
|
}
|
||||||
|
final candidates = [
|
||||||
|
data['roomRecords'],
|
||||||
|
data['roomRewardRecords'],
|
||||||
|
data['room_reward_records'],
|
||||||
|
data['allRecords'],
|
||||||
|
data['allRewardRecords'],
|
||||||
|
data['all_reward_records'],
|
||||||
|
data['rewardRecords'],
|
||||||
|
data['reward_records'],
|
||||||
|
data['rewardRecordList'],
|
||||||
|
data['recordList'],
|
||||||
|
data['records'],
|
||||||
|
data['list'],
|
||||||
|
data['items'],
|
||||||
|
data['rows'],
|
||||||
|
data['content'],
|
||||||
|
data['data'],
|
||||||
|
];
|
||||||
|
for (final candidate in candidates) {
|
||||||
|
if (identical(candidate, value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final records = _rewardRecordList(candidate);
|
||||||
|
if (records.isNotEmpty) {
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return const <SCRoomRocketRewardRecordRes>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _looksLikeRewardRecord(Map<String, dynamic> data) {
|
||||||
|
const rewardKeys = [
|
||||||
|
'rewardScene',
|
||||||
|
'reward_scene',
|
||||||
|
'rewardType',
|
||||||
|
'reward_type',
|
||||||
|
'rewardItemId',
|
||||||
|
'reward_item_id',
|
||||||
|
'rewardName',
|
||||||
|
'reward_name',
|
||||||
|
'rewardCover',
|
||||||
|
'reward_cover',
|
||||||
|
'rewardAmount',
|
||||||
|
'reward_amount',
|
||||||
|
'grantStatus',
|
||||||
|
'grant_status',
|
||||||
|
'popupStatus',
|
||||||
|
'popup_status',
|
||||||
|
];
|
||||||
|
return rewardKeys.any(data.containsKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _asMap(dynamic value) {
|
Map<String, dynamic> _asMap(dynamic value) {
|
||||||
@ -1032,14 +1296,32 @@ String _assetString(dynamic value) {
|
|||||||
final map = _asMap(value);
|
final map = _asMap(value);
|
||||||
return _firstAssetString([
|
return _firstAssetString([
|
||||||
map['sourceUrl'],
|
map['sourceUrl'],
|
||||||
|
map['source_url'],
|
||||||
map['url'],
|
map['url'],
|
||||||
|
map['cdnUrl'],
|
||||||
|
map['cdn_url'],
|
||||||
|
map['ossUrl'],
|
||||||
|
map['oss_url'],
|
||||||
map['resourceUrl'],
|
map['resourceUrl'],
|
||||||
|
map['resource_url'],
|
||||||
map['fileUrl'],
|
map['fileUrl'],
|
||||||
|
map['file_url'],
|
||||||
|
map['thumbUrl'],
|
||||||
|
map['thumb_url'],
|
||||||
|
map['thumbnail'],
|
||||||
|
map['small'],
|
||||||
|
map['medium'],
|
||||||
|
map['large'],
|
||||||
|
map['originUrl'],
|
||||||
|
map['origin_url'],
|
||||||
map['src'],
|
map['src'],
|
||||||
map['path'],
|
map['path'],
|
||||||
map['cover'],
|
map['cover'],
|
||||||
map['imageUrl'],
|
map['imageUrl'],
|
||||||
|
map['image_url'],
|
||||||
|
map['image'],
|
||||||
map['svgUrl'],
|
map['svgUrl'],
|
||||||
|
map['svg_url'],
|
||||||
map['svg'],
|
map['svg'],
|
||||||
map['value'],
|
map['value'],
|
||||||
]);
|
]);
|
||||||
@ -1048,14 +1330,32 @@ String _assetString(dynamic value) {
|
|||||||
if (map.isNotEmpty) {
|
if (map.isNotEmpty) {
|
||||||
return _firstAssetString([
|
return _firstAssetString([
|
||||||
map['sourceUrl'],
|
map['sourceUrl'],
|
||||||
|
map['source_url'],
|
||||||
map['url'],
|
map['url'],
|
||||||
|
map['cdnUrl'],
|
||||||
|
map['cdn_url'],
|
||||||
|
map['ossUrl'],
|
||||||
|
map['oss_url'],
|
||||||
map['resourceUrl'],
|
map['resourceUrl'],
|
||||||
|
map['resource_url'],
|
||||||
map['fileUrl'],
|
map['fileUrl'],
|
||||||
|
map['file_url'],
|
||||||
|
map['thumbUrl'],
|
||||||
|
map['thumb_url'],
|
||||||
|
map['thumbnail'],
|
||||||
|
map['small'],
|
||||||
|
map['medium'],
|
||||||
|
map['large'],
|
||||||
|
map['originUrl'],
|
||||||
|
map['origin_url'],
|
||||||
map['src'],
|
map['src'],
|
||||||
map['path'],
|
map['path'],
|
||||||
map['cover'],
|
map['cover'],
|
||||||
map['imageUrl'],
|
map['imageUrl'],
|
||||||
|
map['image_url'],
|
||||||
|
map['image'],
|
||||||
map['svgUrl'],
|
map['svgUrl'],
|
||||||
|
map['svg_url'],
|
||||||
map['svg'],
|
map['svg'],
|
||||||
map['value'],
|
map['value'],
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -17,12 +17,15 @@ class RoomRocketLaunchBroadcastMessage {
|
|||||||
factory RoomRocketLaunchBroadcastMessage.fromJson(dynamic json) {
|
factory RoomRocketLaunchBroadcastMessage.fromJson(dynamic json) {
|
||||||
final data = _asMap(json);
|
final data = _asMap(json);
|
||||||
return RoomRocketLaunchBroadcastMessage(
|
return RoomRocketLaunchBroadcastMessage(
|
||||||
roomId: _stringValue(data['roomId']),
|
roomId: _roomId(data),
|
||||||
roomAccount: _stringValue(data['roomAccount']),
|
roomAccount: _stringValue(data['roomAccount'] ?? data['room_account']),
|
||||||
roomName: _stringValue(data['roomName']),
|
roomName: _stringValue(data['roomName'] ?? data['room_name']),
|
||||||
roomCoverUrl: _roomCoverUrl(data),
|
roomCoverUrl: _roomCoverUrl(data),
|
||||||
roundNo: _intValue(data['roundNo']),
|
roundNo: _intValue(data['roundNo'] ?? data['round_no']),
|
||||||
level: _intValue(data['level'], fallback: 1),
|
level: _intValue(
|
||||||
|
data['level'] ?? data['rocketLevel'] ?? data['rocket_level'],
|
||||||
|
fallback: 1,
|
||||||
|
),
|
||||||
rocketIconUrl: _rocketIconUrl(data),
|
rocketIconUrl: _rocketIconUrl(data),
|
||||||
rocketAnimationUrl: _rocketAnimationUrl(data),
|
rocketAnimationUrl: _rocketAnimationUrl(data),
|
||||||
durationSeconds: _firstIntValue([
|
durationSeconds: _firstIntValue([
|
||||||
@ -36,9 +39,13 @@ class RoomRocketLaunchBroadcastMessage {
|
|||||||
_asMap(data['config'])['countdownSeconds'],
|
_asMap(data['config'])['countdownSeconds'],
|
||||||
_asMap(data['config'])['launchDelaySeconds'],
|
_asMap(data['config'])['launchDelaySeconds'],
|
||||||
], fallback: 10),
|
], fallback: 10),
|
||||||
triggerUser: RoomRocketLaunchTriggerUser.fromJson(data['triggerUser']),
|
triggerUser: RoomRocketLaunchTriggerUser.fromJson(
|
||||||
triggerUserId: _stringValue(data['triggerUserId']),
|
data['triggerUser'] ?? data['trigger_user'],
|
||||||
launchNo: _stringValue(data['launchNo']),
|
),
|
||||||
|
triggerUserId: _stringValue(
|
||||||
|
data['triggerUserId'] ?? data['trigger_user_id'],
|
||||||
|
),
|
||||||
|
launchNo: _stringValue(data['launchNo'] ?? data['launch_no']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,9 +95,13 @@ class RoomRocketLaunchTriggerUser {
|
|||||||
factory RoomRocketLaunchTriggerUser.fromJson(dynamic json) {
|
factory RoomRocketLaunchTriggerUser.fromJson(dynamic json) {
|
||||||
final data = _asMap(json);
|
final data = _asMap(json);
|
||||||
return RoomRocketLaunchTriggerUser(
|
return RoomRocketLaunchTriggerUser(
|
||||||
userId: _stringValue(data['userId']),
|
userId: _stringValue(data['userId'] ?? data['user_id']),
|
||||||
nickname: _stringValue(data['nickname']),
|
nickname: _stringValue(data['nickname'] ?? data['userNickname']),
|
||||||
avatar: _stringValue(data['avatar']),
|
avatar: _firstAssetString([
|
||||||
|
data['avatar'],
|
||||||
|
data['avatarUrl'],
|
||||||
|
data['userAvatar'],
|
||||||
|
]),
|
||||||
account: _stringValue(data['account']),
|
account: _stringValue(data['account']),
|
||||||
countryCode: _stringValue(data['countryCode']),
|
countryCode: _stringValue(data['countryCode']),
|
||||||
countryName: _stringValue(data['countryName']),
|
countryName: _stringValue(data['countryName']),
|
||||||
@ -122,13 +133,36 @@ String _stringValue(dynamic value) {
|
|||||||
return value.toString().trim();
|
return value.toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _roomId(Map<String, dynamic> data) {
|
||||||
|
return _firstAssetString([
|
||||||
|
data['roomId'],
|
||||||
|
data['room_id'],
|
||||||
|
data['roomID'],
|
||||||
|
data['voiceRoomId'],
|
||||||
|
data['voice_room_id'],
|
||||||
|
data['chatRoomId'],
|
||||||
|
data['chat_room_id'],
|
||||||
|
_asMap(data['room'])['id'],
|
||||||
|
_asMap(data['room'])['roomId'],
|
||||||
|
_asMap(data['room'])['room_id'],
|
||||||
|
_asMap(data['roomInfo'])['id'],
|
||||||
|
_asMap(data['roomInfo'])['roomId'],
|
||||||
|
_asMap(data['roomInfo'])['room_id'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
String _roomCoverUrl(Map<String, dynamic> data) {
|
String _roomCoverUrl(Map<String, dynamic> data) {
|
||||||
return _firstAssetString([
|
return _firstAssetString([
|
||||||
data['roomCoverUrl'],
|
data['roomCoverUrl'],
|
||||||
|
data['room_cover_url'],
|
||||||
data['roomCover'],
|
data['roomCover'],
|
||||||
|
data['room_cover'],
|
||||||
data['roomAvatar'],
|
data['roomAvatar'],
|
||||||
|
data['room_avatar'],
|
||||||
data['roomIcon'],
|
data['roomIcon'],
|
||||||
|
data['room_icon'],
|
||||||
data['coverUrl'],
|
data['coverUrl'],
|
||||||
|
data['cover_url'],
|
||||||
data['cover'],
|
data['cover'],
|
||||||
_asMap(data['room'])['coverUrl'],
|
_asMap(data['room'])['coverUrl'],
|
||||||
_asMap(data['room'])['cover'],
|
_asMap(data['room'])['cover'],
|
||||||
@ -162,11 +196,17 @@ String _rocketAnimationUrl(Map<String, dynamic> data) {
|
|||||||
return _firstAssetString([
|
return _firstAssetString([
|
||||||
data['rocket_animation_url'],
|
data['rocket_animation_url'],
|
||||||
data['rocketAnimationUrl'],
|
data['rocketAnimationUrl'],
|
||||||
|
data['rocket_animation'],
|
||||||
data['rocketSvgaUrl'],
|
data['rocketSvgaUrl'],
|
||||||
|
data['rocket_svga_url'],
|
||||||
data['animationUrl'],
|
data['animationUrl'],
|
||||||
|
data['animation_url'],
|
||||||
data['svgaUrl'],
|
data['svgaUrl'],
|
||||||
|
data['svga_url'],
|
||||||
data['rocketLaunchSvgaUrl'],
|
data['rocketLaunchSvgaUrl'],
|
||||||
|
data['rocket_launch_svga_url'],
|
||||||
data['launchAnimationUrl'],
|
data['launchAnimationUrl'],
|
||||||
|
data['launch_animation_url'],
|
||||||
data['launchAnimation'],
|
data['launchAnimation'],
|
||||||
data['launchSvgaUrl'],
|
data['launchSvgaUrl'],
|
||||||
data['rocketAnimation'],
|
data['rocketAnimation'],
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:yumi/shared/tools/sc_network_image_utils.dart';
|
||||||
import 'package:yumi/ui_kit/components/sc_rotating_dots_loading.dart';
|
import 'package:yumi/ui_kit/components/sc_rotating_dots_loading.dart';
|
||||||
|
|
||||||
int? _resolveMemCacheDimension(double? logicalSize) {
|
int? _resolveMemCacheDimension(double? logicalSize) {
|
||||||
@ -39,10 +40,12 @@ class CustomCachedImage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final normalizedUrl = normalizeImageResourceUrl(imageUrl);
|
||||||
return ClipRRect(
|
return ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(borderRadius),
|
borderRadius: BorderRadius.circular(borderRadius),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: imageUrl,
|
imageUrl: normalizedUrl,
|
||||||
|
httpHeaders: buildNetworkImageHeaders(normalizedUrl),
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
memCacheWidth: _resolveMemCacheDimension(width),
|
memCacheWidth: _resolveMemCacheDimension(width),
|
||||||
|
|||||||
@ -151,16 +151,12 @@ class _FloatingRoomRocketScreenWidgetState
|
|||||||
duration: Duration(milliseconds: 350),
|
duration: Duration(milliseconds: 350),
|
||||||
onDebounce: () {
|
onDebounce: () {
|
||||||
final roomId = widget.message.roomId?.trim() ?? '';
|
final roomId = widget.message.roomId?.trim() ?? '';
|
||||||
final currentContext = navigatorKey.currentState?.context;
|
final currentContext =
|
||||||
if (roomId.isEmpty ||
|
navigatorKey.currentState?.context ?? context;
|
||||||
currentContext == null ||
|
if (roomId.isEmpty || !currentContext.mounted) {
|
||||||
!currentContext.mounted ||
|
|
||||||
SCRoomUtils.isCurrentRoom(roomId, currentContext)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (roomId.isNotEmpty) {
|
SCRoomUtils.goRoom(roomId, currentContext, fromFloting: true);
|
||||||
SCRoomUtils.goRoom(roomId, currentContext, fromFloting: true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -209,7 +205,7 @@ class _FloatingRoomRocketScreenWidgetState
|
|||||||
Positioned(
|
Positioned(
|
||||||
left: 65.w,
|
left: 65.w,
|
||||||
top: 9.w,
|
top: 9.w,
|
||||||
width: 126.w,
|
width: 112.w,
|
||||||
child: Text(
|
child: Text(
|
||||||
roomName,
|
roomName,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@ -227,7 +223,7 @@ class _FloatingRoomRocketScreenWidgetState
|
|||||||
Positioned(
|
Positioned(
|
||||||
left: 65.w,
|
left: 65.w,
|
||||||
top: 31.w,
|
top: 31.w,
|
||||||
width: 126.w,
|
width: 112.w,
|
||||||
child: Text(
|
child: Text(
|
||||||
SCAppLocalizations.of(context)?.launchRocket ??
|
SCAppLocalizations.of(context)?.launchRocket ??
|
||||||
'Launch Rocket',
|
'Launch Rocket',
|
||||||
@ -244,14 +240,14 @@ class _FloatingRoomRocketScreenWidgetState
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 201.w,
|
left: 191.w,
|
||||||
top: 8.w,
|
top: -2.w,
|
||||||
width: 40.w,
|
width: 60.w,
|
||||||
height: 40.w,
|
height: 60.w,
|
||||||
child: _RocketIcon(url: rocketIconUrl),
|
child: _RocketIcon(url: rocketIconUrl),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 249.w,
|
left: 262.w,
|
||||||
top: 14.w,
|
top: 14.w,
|
||||||
width: 42.w,
|
width: 42.w,
|
||||||
height: 28.w,
|
height: 28.w,
|
||||||
@ -315,7 +311,7 @@ class _RocketIcon extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(5.w),
|
padding: EdgeInsets.all(7.5.w),
|
||||||
child:
|
child:
|
||||||
url.trim().isEmpty
|
url.trim().isEmpty
|
||||||
? Image.asset(
|
? Image.asset(
|
||||||
@ -324,8 +320,8 @@ class _RocketIcon extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: netImage(
|
: netImage(
|
||||||
url: url,
|
url: url,
|
||||||
width: 30.w,
|
width: 45.w,
|
||||||
height: 30.w,
|
height: 45.w,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
noDefaultImg: true,
|
noDefaultImg: true,
|
||||||
errorWidget: Image.asset(
|
errorWidget: Image.asset(
|
||||||
|
|||||||
@ -7,6 +7,23 @@ import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_note_dialog.dart';
|
|||||||
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_record_dialog.dart';
|
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_record_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.dart';
|
||||||
|
|
||||||
|
typedef RoomRocketRewardUserProfileResolver =
|
||||||
|
RoomRocketRewardUserProfile? Function(SCRoomRocketRewardRecordRes record);
|
||||||
|
|
||||||
|
class RoomRocketRewardUserProfile {
|
||||||
|
const RoomRocketRewardUserProfile({
|
||||||
|
required this.userId,
|
||||||
|
required this.account,
|
||||||
|
required this.nickname,
|
||||||
|
required this.avatarUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String userId;
|
||||||
|
final String account;
|
||||||
|
final String nickname;
|
||||||
|
final String avatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
class RoomRocketApiMapper {
|
class RoomRocketApiMapper {
|
||||||
const RoomRocketApiMapper._();
|
const RoomRocketApiMapper._();
|
||||||
|
|
||||||
@ -257,25 +274,93 @@ class RoomRocketApiMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<RoomRocketRewardWinner> winnersFromRecords(
|
static List<RoomRocketRewardWinner> winnersFromRecords(
|
||||||
List<SCRoomRocketRewardRecordRes> records,
|
List<SCRoomRocketRewardRecordRes> records, {
|
||||||
) {
|
RoomRocketRewardUserProfileResolver? userProfileResolver,
|
||||||
|
}) {
|
||||||
final grouped = <String, List<SCRoomRocketRewardRecordRes>>{};
|
final grouped = <String, List<SCRoomRocketRewardRecordRes>>{};
|
||||||
for (final record in records) {
|
for (final record in records) {
|
||||||
final key = record.userId.isNotEmpty ? record.userId : record.launchNo;
|
final key = _rewardWinnerKey(record);
|
||||||
grouped.putIfAbsent(key, () => []).add(record);
|
grouped.putIfAbsent(key, () => []).add(record);
|
||||||
}
|
}
|
||||||
return grouped.entries
|
return grouped.entries
|
||||||
.map((entry) {
|
.map((entry) {
|
||||||
final first = entry.value.first;
|
final first = entry.value.first;
|
||||||
|
final profile = userProfileResolver?.call(first);
|
||||||
return RoomRocketRewardWinner(
|
return RoomRocketRewardWinner(
|
||||||
nickname: first.displayName,
|
nickname: _rewardWinnerName(entry.value, profile),
|
||||||
avatarUrl: first.userAvatar.isEmpty ? null : first.userAvatar,
|
avatarUrl: _rewardWinnerAvatar(entry.value, profile),
|
||||||
rewards: rewardItemsFromRecords(entry.value),
|
rewards: rewardItemsFromRecords(entry.value),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.toList(growable: false);
|
.toList(growable: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String _rewardWinnerName(
|
||||||
|
List<SCRoomRocketRewardRecordRes> records,
|
||||||
|
RoomRocketRewardUserProfile? profile,
|
||||||
|
) {
|
||||||
|
final profileName = profile?.nickname.trim() ?? '';
|
||||||
|
if (profileName.isNotEmpty) {
|
||||||
|
return profileName;
|
||||||
|
}
|
||||||
|
for (final record in records) {
|
||||||
|
final nickname = record.userNickname.trim();
|
||||||
|
if (nickname.isNotEmpty) {
|
||||||
|
return nickname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (final record in records) {
|
||||||
|
final account = record.account.trim();
|
||||||
|
if (account.isNotEmpty) {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records.isEmpty ? 'User' : records.first.displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String? _rewardWinnerAvatar(
|
||||||
|
List<SCRoomRocketRewardRecordRes> records,
|
||||||
|
RoomRocketRewardUserProfile? profile,
|
||||||
|
) {
|
||||||
|
final profileAvatar = profile?.avatarUrl.trim() ?? '';
|
||||||
|
if (profileAvatar.isNotEmpty) {
|
||||||
|
return profileAvatar;
|
||||||
|
}
|
||||||
|
for (final record in records) {
|
||||||
|
final avatar = record.userAvatar.trim();
|
||||||
|
if (avatar.isNotEmpty) {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _rewardWinnerKey(SCRoomRocketRewardRecordRes record) {
|
||||||
|
final userId = record.userId.trim();
|
||||||
|
if (userId.isNotEmpty) {
|
||||||
|
return 'user:$userId';
|
||||||
|
}
|
||||||
|
final account = record.account.trim();
|
||||||
|
if (account.isNotEmpty) {
|
||||||
|
return 'account:$account';
|
||||||
|
}
|
||||||
|
final profileKey = [
|
||||||
|
record.userNickname.trim(),
|
||||||
|
record.userAvatar.trim(),
|
||||||
|
].where((item) => item.isNotEmpty).join('|');
|
||||||
|
if (profileKey.isNotEmpty) {
|
||||||
|
return 'profile:$profileKey';
|
||||||
|
}
|
||||||
|
final recordKey = [
|
||||||
|
record.launchNo.trim(),
|
||||||
|
record.id.trim(),
|
||||||
|
].where((item) => item.isNotEmpty).join('|');
|
||||||
|
if (recordKey.isNotEmpty) {
|
||||||
|
return 'record:$recordKey';
|
||||||
|
}
|
||||||
|
return 'record:${identityHashCode(record)}';
|
||||||
|
}
|
||||||
|
|
||||||
static List<RoomRocketRecordItem> recordItemsFromRecords(
|
static List<RoomRocketRecordItem> recordItemsFromRecords(
|
||||||
List<SCRoomRocketRewardRecordRes> records,
|
List<SCRoomRocketRewardRecordRes> records,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -16,12 +16,16 @@ class RoomRocketRewardDialogLoader extends StatefulWidget {
|
|||||||
required this.roomId,
|
required this.roomId,
|
||||||
this.selectedReward,
|
this.selectedReward,
|
||||||
this.initialPopupRecords = const <SCRoomRocketRewardRecordRes>[],
|
this.initialPopupRecords = const <SCRoomRocketRewardRecordRes>[],
|
||||||
|
this.initialRoomRecords = const <SCRoomRocketRewardRecordRes>[],
|
||||||
|
this.userProfileResolver,
|
||||||
this.onClose,
|
this.onClose,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String roomId;
|
final String roomId;
|
||||||
final RoomRocketRewardItem? selectedReward;
|
final RoomRocketRewardItem? selectedReward;
|
||||||
final List<SCRoomRocketRewardRecordRes> initialPopupRecords;
|
final List<SCRoomRocketRewardRecordRes> initialPopupRecords;
|
||||||
|
final List<SCRoomRocketRewardRecordRes> initialRoomRecords;
|
||||||
|
final RoomRocketRewardUserProfileResolver? userProfileResolver;
|
||||||
final VoidCallback? onClose;
|
final VoidCallback? onClose;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -47,8 +51,14 @@ class _RoomRocketRewardDialogLoaderState
|
|||||||
if (widget.initialPopupRecords.isNotEmpty) {
|
if (widget.initialPopupRecords.isNotEmpty) {
|
||||||
_popupRecords.addAll(widget.initialPopupRecords);
|
_popupRecords.addAll(widget.initialPopupRecords);
|
||||||
_rewards = RoomRocketApiMapper.rewardItemsFromRecords(_popupRecords);
|
_rewards = RoomRocketApiMapper.rewardItemsFromRecords(_popupRecords);
|
||||||
_winners = RoomRocketApiMapper.winnersFromRecords(_popupRecords);
|
|
||||||
}
|
}
|
||||||
|
if (widget.initialRoomRecords.isNotEmpty) {
|
||||||
|
_roomRecords.addAll(widget.initialRoomRecords);
|
||||||
|
}
|
||||||
|
_winners = RoomRocketApiMapper.winnersFromRecords(
|
||||||
|
_visibleRoomRewardRecords(),
|
||||||
|
userProfileResolver: widget.userProfileResolver,
|
||||||
|
);
|
||||||
unawaited(_load(reset: true));
|
unawaited(_load(reset: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,13 +99,25 @@ class _RoomRocketRewardDialogLoaderState
|
|||||||
..addAll(nextPopupRecords);
|
..addAll(nextPopupRecords);
|
||||||
_roomRecords
|
_roomRecords
|
||||||
..clear()
|
..clear()
|
||||||
..addAll(nextRoomRecords);
|
..addAll(
|
||||||
|
_mergeRewardRecords([
|
||||||
|
...widget.initialRoomRecords,
|
||||||
|
...nextRoomRecords,
|
||||||
|
]),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
_roomRecords.addAll(nextRoomRecords);
|
final mergedRoomRecords = _mergeRewardRecords([
|
||||||
|
..._roomRecords,
|
||||||
|
...nextRoomRecords,
|
||||||
|
]);
|
||||||
|
_roomRecords
|
||||||
|
..clear()
|
||||||
|
..addAll(mergedRoomRecords);
|
||||||
}
|
}
|
||||||
_rewards = RoomRocketApiMapper.rewardItemsFromRecords(_popupRecords);
|
_rewards = RoomRocketApiMapper.rewardItemsFromRecords(_popupRecords);
|
||||||
_winners = RoomRocketApiMapper.winnersFromRecords(
|
_winners = RoomRocketApiMapper.winnersFromRecords(
|
||||||
_visibleRoomRewardRecords(),
|
_visibleRoomRewardRecords(),
|
||||||
|
userProfileResolver: widget.userProfileResolver,
|
||||||
);
|
);
|
||||||
_hasMore = nextRoomRecords.length >= _rewardDialogPageSize;
|
_hasMore = nextRoomRecords.length >= _rewardDialogPageSize;
|
||||||
if (_hasMore) {
|
if (_hasMore) {
|
||||||
@ -108,6 +130,7 @@ class _RoomRocketRewardDialogLoaderState
|
|||||||
'loaded cursor=$requestCursor '
|
'loaded cursor=$requestCursor '
|
||||||
'popupCount=${nextPopupRecords.length} '
|
'popupCount=${nextPopupRecords.length} '
|
||||||
'popupTotal=${_popupRecords.length} '
|
'popupTotal=${_popupRecords.length} '
|
||||||
|
'initialRoomCount=${widget.initialRoomRecords.length} '
|
||||||
'roomCount=${nextRoomRecords.length} '
|
'roomCount=${nextRoomRecords.length} '
|
||||||
'roomTotal=${_roomRecords.length} '
|
'roomTotal=${_roomRecords.length} '
|
||||||
'visibleRoomTotal=${_visibleRoomRewardRecords().length} '
|
'visibleRoomTotal=${_visibleRoomRewardRecords().length} '
|
||||||
@ -181,6 +204,20 @@ class _RoomRocketRewardDialogLoaderState
|
|||||||
return matched.isEmpty ? _roomRecords : matched;
|
return matched.isEmpty ? _roomRecords : matched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<SCRoomRocketRewardRecordRes> _mergeRewardRecords(
|
||||||
|
List<SCRoomRocketRewardRecordRes> records,
|
||||||
|
) {
|
||||||
|
final result = <SCRoomRocketRewardRecordRes>[];
|
||||||
|
final seen = <String>{};
|
||||||
|
for (final record in records) {
|
||||||
|
final id = record.id.trim();
|
||||||
|
if (id.isEmpty || seen.add(id)) {
|
||||||
|
result.add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return RoomRocketRewardDialog(
|
return RoomRocketRewardDialog(
|
||||||
|
|||||||
@ -62,16 +62,17 @@ void main() {
|
|||||||
|
|
||||||
test('extracts launch pag urls from nested resource payloads', () {
|
test('extracts launch pag urls from nested resource payloads', () {
|
||||||
final launch = RoomRocketLaunchBroadcastMessage.fromJson({
|
final launch = RoomRocketLaunchBroadcastMessage.fromJson({
|
||||||
'roomId': 'room-1',
|
|
||||||
'rocketAnimationResource': {
|
'rocketAnimationResource': {
|
||||||
'sourceUrl': 'https://cdn.example.com/rocket/launch.pag',
|
'sourceUrl': 'https://cdn.example.com/rocket/launch.pag',
|
||||||
},
|
},
|
||||||
'rocketIcon': {'url': 'https://cdn.example.com/rocket/icon.png'},
|
'rocketIcon': {'url': 'https://cdn.example.com/rocket/icon.png'},
|
||||||
'room': {
|
'room': {
|
||||||
|
'id': 'room-1',
|
||||||
'cover': {'url': 'https://cdn.example.com/room/cover.png'},
|
'cover': {'url': 'https://cdn.example.com/room/cover.png'},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(launch.roomId, 'room-1');
|
||||||
expect(
|
expect(
|
||||||
launch.rocketAnimationUrl,
|
launch.rocketAnimationUrl,
|
||||||
'https://cdn.example.com/rocket/launch.pag',
|
'https://cdn.example.com/rocket/launch.pag',
|
||||||
@ -79,4 +80,36 @@ void main() {
|
|||||||
expect(launch.rocketIconUrl, 'https://cdn.example.com/rocket/icon.png');
|
expect(launch.rocketIconUrl, 'https://cdn.example.com/rocket/icon.png');
|
||||||
expect(launch.roomCoverUrl, 'https://cdn.example.com/room/cover.png');
|
expect(launch.roomCoverUrl, 'https://cdn.example.com/room/cover.png');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('extracts launch data from snake case broadcast payloads', () {
|
||||||
|
final launch = RoomRocketLaunchBroadcastMessage.fromJson({
|
||||||
|
'room_id': 'room-1',
|
||||||
|
'room_account': '10001',
|
||||||
|
'room_name': 'Rocket Room',
|
||||||
|
'round_no': 3,
|
||||||
|
'rocket_level': 2,
|
||||||
|
'launch_no': 'launch-3',
|
||||||
|
'rocket_animation_url': 'https://cdn.example.com/rocket/launch.pag',
|
||||||
|
'rocket_icon_url': 'https://cdn.example.com/rocket/icon.png',
|
||||||
|
'trigger_user': {
|
||||||
|
'user_id': 'u1',
|
||||||
|
'userAvatar': {'sourceUrl': 'https://cdn.example.com/avatar.png'},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(launch.isValid, isTrue);
|
||||||
|
expect(launch.roomId, 'room-1');
|
||||||
|
expect(launch.roomAccount, '10001');
|
||||||
|
expect(launch.roomName, 'Rocket Room');
|
||||||
|
expect(launch.roundNo, 3);
|
||||||
|
expect(launch.safeLevel, 2);
|
||||||
|
expect(launch.launchNo, 'launch-3');
|
||||||
|
expect(
|
||||||
|
launch.rocketAnimationUrl,
|
||||||
|
'https://cdn.example.com/rocket/launch.pag',
|
||||||
|
);
|
||||||
|
expect(launch.rocketIconUrl, 'https://cdn.example.com/rocket/icon.png');
|
||||||
|
expect(launch.triggerUser.userId, 'u1');
|
||||||
|
expect(launch.triggerUser.avatar, 'https://cdn.example.com/avatar.png');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -175,6 +175,117 @@ void main() {
|
|||||||
expect(recordRewards.single.displayText, '7d');
|
expect(recordRewards.single.displayText, '7d');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('parses rocket reward winner avatars from nested resource payloads', () {
|
||||||
|
final winners = RoomRocketApiMapper.winnersFromRecords([
|
||||||
|
SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
'id': 'r1',
|
||||||
|
'userId': 'u1',
|
||||||
|
'userInfo': {
|
||||||
|
'nickname': 'winner',
|
||||||
|
'avatar': {'sourceUrl': 'https://example.com/avatar.png'},
|
||||||
|
},
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 100,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(winners.single.nickname, 'winner');
|
||||||
|
expect(winners.single.avatarUrl, 'https://example.com/avatar.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parses rocket reward winner profile from receiver aliases', () {
|
||||||
|
final record = SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
'id': 'r1',
|
||||||
|
'acceptUserId': 'u1',
|
||||||
|
'acceptNickname': 'winner',
|
||||||
|
'acceptUserAvatar': {'cdn_url': 'https://example.com/avatar.png'},
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 100,
|
||||||
|
});
|
||||||
|
final winners = RoomRocketApiMapper.winnersFromRecords([record]);
|
||||||
|
|
||||||
|
expect(record.userId, 'u1');
|
||||||
|
expect(record.displayName, 'winner');
|
||||||
|
expect(winners.single.nickname, 'winner');
|
||||||
|
expect(winners.single.avatarUrl, 'https://example.com/avatar.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hydrates rocket reward winners from room user profiles', () {
|
||||||
|
final records = [
|
||||||
|
SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
'id': 'r1',
|
||||||
|
'userId': '2042274349',
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 100,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
final winners = RoomRocketApiMapper.winnersFromRecords(
|
||||||
|
records,
|
||||||
|
userProfileResolver:
|
||||||
|
(_) => const RoomRocketRewardUserProfile(
|
||||||
|
userId: 'u1',
|
||||||
|
account: '2042274349',
|
||||||
|
nickname: 'winner',
|
||||||
|
avatarUrl: 'https://example.com/avatar.png',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(records.single.displayName, 'User');
|
||||||
|
expect(winners.single.nickname, 'winner');
|
||||||
|
expect(winners.single.avatarUrl, 'https://example.com/avatar.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps nested rocket reward users separated by profile id', () {
|
||||||
|
final winners = RoomRocketApiMapper.winnersFromRecords([
|
||||||
|
SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
'id': 'r1',
|
||||||
|
'launchNo': 'launch-1',
|
||||||
|
'userInfo': {'id': 'u1', 'nickname': 'winner 1'},
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 100,
|
||||||
|
}),
|
||||||
|
SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
'id': 'r2',
|
||||||
|
'launchNo': 'launch-1',
|
||||||
|
'userInfo': {'id': 'u2', 'nickname': 'winner 2'},
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 100,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(winners, hasLength(2));
|
||||||
|
expect(winners.map((item) => item.nickname), ['winner 1', 'winner 2']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parses room reward records from alternate response keys', () {
|
||||||
|
final records =
|
||||||
|
SCRoomRocketRewardRecordsRes.fromJson({
|
||||||
|
'room_reward_records': [
|
||||||
|
{
|
||||||
|
'id': 'r1',
|
||||||
|
'launch_no': 'launch-1',
|
||||||
|
'room_id': 'room-1',
|
||||||
|
'user_info': {'id': 'u1', 'user_nickname': 'winner 1'},
|
||||||
|
'reward_type': 'GOLD',
|
||||||
|
'reward_amount': 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'r2',
|
||||||
|
'launch_no': 'launch-1',
|
||||||
|
'room_id': 'room-1',
|
||||||
|
'user_info': {'id': 'u2', 'user_nickname': 'winner 2'},
|
||||||
|
'reward_type': 'GOLD',
|
||||||
|
'reward_amount': 200,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).records;
|
||||||
|
final winners = RoomRocketApiMapper.winnersFromRecords(records);
|
||||||
|
|
||||||
|
expect(records.map((item) => item.userId), ['u1', 'u2']);
|
||||||
|
expect(winners, hasLength(2));
|
||||||
|
expect(winners.last.rewards.single.amount, '200');
|
||||||
|
});
|
||||||
|
|
||||||
test('parses rocket level contents response from go api', () {
|
test('parses rocket level contents response from go api', () {
|
||||||
final contents = SCRoomRocketLevelContentsRes.fromJson({
|
final contents = SCRoomRocketLevelContentsRes.fromJson({
|
||||||
'configured': true,
|
'configured': true,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user