飘窗
This commit is contained in:
parent
95dcd7e625
commit
ccb5579a85
@ -120,6 +120,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
static const int _luckyGiftBurstPlaybackWatchdogMs = 8000;
|
static const int _luckyGiftBurstPlaybackWatchdogMs = 8000;
|
||||||
static const int _roomRocketLaunchRecentTtlMs = 90000;
|
static const int _roomRocketLaunchRecentTtlMs = 90000;
|
||||||
static const int _roomRocketLaunchLooseRecentTtlMs = 12000;
|
static const int _roomRocketLaunchLooseRecentTtlMs = 12000;
|
||||||
|
static const int _roomRocketRegionBroadcastRecentTtlMs = 90000;
|
||||||
static const List<Duration> _roomRocketRewardPopupRetryDelays = [
|
static const List<Duration> _roomRocketRewardPopupRetryDelays = [
|
||||||
Duration(milliseconds: 700),
|
Duration(milliseconds: 700),
|
||||||
Duration(seconds: 2),
|
Duration(seconds: 2),
|
||||||
@ -235,6 +236,8 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
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> _recentRoomRocketLaunchTimes = <String, int>{};
|
||||||
final Map<String, int> _recentRoomRocketLaunchLooseTimes = <String, int>{};
|
final Map<String, int> _recentRoomRocketLaunchLooseTimes = <String, int>{};
|
||||||
|
final Map<String, int> _recentRoomRocketRegionBroadcastTimes =
|
||||||
|
<String, int>{};
|
||||||
Timer? _roomRocketRewardPopupRetryTimer;
|
Timer? _roomRocketRewardPopupRetryTimer;
|
||||||
int get currentLuckGiftBurstPlaybackToken => _luckGiftPushPlaybackToken;
|
int get currentLuckGiftBurstPlaybackToken => _luckGiftPushPlaybackToken;
|
||||||
String? roomRedPacketBroadcastGroupId;
|
String? roomRedPacketBroadcastGroupId;
|
||||||
@ -1936,16 +1939,19 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
payload: data,
|
payload: data,
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
);
|
);
|
||||||
if (isCurrentVisibleRoom &&
|
final shouldHandleLaunch = _shouldHandleRoomRocketLaunchFromStatusPayload(
|
||||||
_shouldHandleRoomRocketLaunchFromStatusPayload(
|
rtcProvider: rtcProvider,
|
||||||
|
payload: data,
|
||||||
|
launch: launch,
|
||||||
|
);
|
||||||
|
if (shouldHandleLaunch) {
|
||||||
|
_publishRoomRocketRegionBroadcastIfNeeded(launch);
|
||||||
|
if (isCurrentVisibleRoom) {
|
||||||
|
_handleCurrentVisibleRoomRocketLaunch(
|
||||||
rtcProvider: rtcProvider,
|
rtcProvider: rtcProvider,
|
||||||
payload: data,
|
|
||||||
launch: launch,
|
launch: launch,
|
||||||
)) {
|
);
|
||||||
_handleCurrentVisibleRoomRocketLaunch(
|
}
|
||||||
rtcProvider: rtcProvider,
|
|
||||||
launch: launch,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
unawaited(rtcProvider.refreshRoomRocketStatus(roomId: roomId));
|
unawaited(rtcProvider.refreshRoomRocketStatus(roomId: roomId));
|
||||||
}
|
}
|
||||||
@ -1977,6 +1983,9 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
rtcProvider.shouldShowRoomVisualEffects &&
|
rtcProvider.shouldShowRoomVisualEffects &&
|
||||||
rtcProvider.isVoiceRoomRouteVisible;
|
rtcProvider.isVoiceRoomRouteVisible;
|
||||||
if (isCurrentVisibleRoom) {
|
if (isCurrentVisibleRoom) {
|
||||||
|
if (!isRegionBroadcast) {
|
||||||
|
_publishRoomRocketRegionBroadcastIfNeeded(launch);
|
||||||
|
}
|
||||||
_handleCurrentVisibleRoomRocketLaunch(
|
_handleCurrentVisibleRoomRocketLaunch(
|
||||||
rtcProvider: rtcProvider,
|
rtcProvider: rtcProvider,
|
||||||
launch: launch,
|
launch: launch,
|
||||||
@ -1986,6 +1995,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isCurrentRoom && !isCurrentVisibleRoom && !isRegionBroadcast) {
|
if (isCurrentRoom && !isCurrentVisibleRoom && !isRegionBroadcast) {
|
||||||
|
_publishRoomRocketRegionBroadcastIfNeeded(launch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OverlayManager().addMessage(
|
OverlayManager().addMessage(
|
||||||
@ -2056,6 +2066,47 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
unawaited(_showRoomRocketRewardPopupDialog(launch.roomId));
|
unawaited(_showRoomRocketRewardPopupDialog(launch.roomId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _publishRoomRocketRegionBroadcastIfNeeded(
|
||||||
|
RoomRocketLaunchBroadcastMessage launch,
|
||||||
|
) {
|
||||||
|
if (!launch.isValid ||
|
||||||
|
!_shouldCurrentUserPublishRoomRocketRegionBroadcast(launch)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final key = _roomRocketLaunchNoticeKey(launch);
|
||||||
|
if (key.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final now = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
_recentRoomRocketRegionBroadcastTimes.removeWhere(
|
||||||
|
(_, timestamp) => now - timestamp > _roomRocketRegionBroadcastRecentTtlMs,
|
||||||
|
);
|
||||||
|
if (_recentRoomRocketRegionBroadcastTimes.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_recentRoomRocketRegionBroadcastTimes[key] = now;
|
||||||
|
unawaited(sendRoomRocketLaunchBroadcast(launch));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _shouldCurrentUserPublishRoomRocketRegionBroadcast(
|
||||||
|
RoomRocketLaunchBroadcastMessage launch,
|
||||||
|
) {
|
||||||
|
final currentUser = AccountStorage().getCurrentUser()?.userProfile;
|
||||||
|
final currentKeys = <String>{
|
||||||
|
currentUser?.id?.trim() ?? '',
|
||||||
|
currentUser?.account?.trim() ?? '',
|
||||||
|
}..removeWhere((item) => item.isEmpty);
|
||||||
|
final triggerKeys = <String>{
|
||||||
|
launch.triggerUserId.trim(),
|
||||||
|
launch.triggerUser.userId.trim(),
|
||||||
|
launch.triggerUser.account.trim(),
|
||||||
|
}..removeWhere((item) => item.isEmpty);
|
||||||
|
if (triggerKeys.isNotEmpty) {
|
||||||
|
return currentKeys.any(triggerKeys.contains);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
String _rocketIconUrlForLevel(int level) {
|
String _rocketIconUrlForLevel(int level) {
|
||||||
final currentContext = context;
|
final currentContext = context;
|
||||||
if (currentContext == null || !currentContext.mounted) {
|
if (currentContext == null || !currentContext.mounted) {
|
||||||
@ -2228,10 +2279,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
type: 3,
|
type: 3,
|
||||||
roomId: launch.roomId,
|
roomId: launch.roomId,
|
||||||
rocketLevel: launch.safeLevel,
|
rocketLevel: launch.safeLevel,
|
||||||
userAvatarUrl: _firstNonBlank([
|
userAvatarUrl: launch.roomCoverUrl,
|
||||||
launch.roomCoverUrl,
|
|
||||||
launch.triggerUser.avatar,
|
|
||||||
]),
|
|
||||||
userName: _firstNonBlank([launch.roomName, launch.roomAccount]),
|
userName: _firstNonBlank([launch.roomName, launch.roomAccount]),
|
||||||
userId: _firstNonBlank([
|
userId: _firstNonBlank([
|
||||||
launch.triggerUser.account,
|
launch.triggerUser.account,
|
||||||
@ -2334,6 +2382,18 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
roomProfile?.roomCover,
|
roomProfile?.roomCover,
|
||||||
_payloadAssetText(payload['roomCoverUrl'] ?? payload['room_cover_url']),
|
_payloadAssetText(payload['roomCoverUrl'] ?? payload['room_cover_url']),
|
||||||
_payloadAssetText(payload['roomCover'] ?? payload['room_cover']),
|
_payloadAssetText(payload['roomCover'] ?? payload['room_cover']),
|
||||||
|
_payloadAssetText(payload['roomAvatar'] ?? payload['room_avatar']),
|
||||||
|
_payloadAssetText(payload['roomIcon'] ?? payload['room_icon']),
|
||||||
|
_payloadAssetText(payload['coverUrl'] ?? payload['cover_url']),
|
||||||
|
_payloadAssetText(payload['cover']),
|
||||||
|
_payloadAssetText(_broadcastPayloadMap(payload['room'])['coverUrl']),
|
||||||
|
_payloadAssetText(_broadcastPayloadMap(payload['room'])['cover']),
|
||||||
|
_payloadAssetText(_broadcastPayloadMap(payload['room'])['avatar']),
|
||||||
|
_payloadAssetText(
|
||||||
|
_broadcastPayloadMap(payload['roomInfo'])['coverUrl'],
|
||||||
|
),
|
||||||
|
_payloadAssetText(_broadcastPayloadMap(payload['roomInfo'])['cover']),
|
||||||
|
_payloadAssetText(_broadcastPayloadMap(payload['roomInfo'])['avatar']),
|
||||||
]),
|
]),
|
||||||
roundNo:
|
roundNo:
|
||||||
_payloadNum(payload['roundNo'] ?? payload['round_no'])?.toInt() ?? 0,
|
_payloadNum(payload['roundNo'] ?? payload['round_no'])?.toInt() ?? 0,
|
||||||
@ -3377,6 +3437,81 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> sendRoomRocketLaunchBroadcast(
|
||||||
|
RoomRocketLaunchBroadcastMessage launch,
|
||||||
|
) async {
|
||||||
|
if (!launch.isValid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var regionGroupId = roomRedPacketBroadcastGroupId?.trim() ?? '';
|
||||||
|
if (regionGroupId.isEmpty) {
|
||||||
|
await syncRoomRedPacketBroadcastGroup();
|
||||||
|
regionGroupId = roomRedPacketBroadcastGroupId?.trim() ?? '';
|
||||||
|
}
|
||||||
|
if (regionGroupId.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final message = <String, dynamic>{
|
||||||
|
'type': SCRoomMsgType.voiceRoomRocketLaunchBroadcast,
|
||||||
|
'data': _roomRocketLaunchBroadcastPayload(launch),
|
||||||
|
};
|
||||||
|
await _sendRoomRocketLaunchCustomMessage(
|
||||||
|
regionGroupId,
|
||||||
|
jsonEncode(message),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> _roomRocketLaunchBroadcastPayload(
|
||||||
|
RoomRocketLaunchBroadcastMessage launch,
|
||||||
|
) {
|
||||||
|
final launchNo = _firstNonBlank([
|
||||||
|
launch.launchNo,
|
||||||
|
_roomRocketLaunchNoticeKey(launch),
|
||||||
|
]);
|
||||||
|
return <String, dynamic>{
|
||||||
|
'roomId': launch.roomId,
|
||||||
|
'roomAccount': launch.roomAccount,
|
||||||
|
'roomName': launch.roomName,
|
||||||
|
'roomCoverUrl': launch.roomCoverUrl,
|
||||||
|
'roundNo': launch.roundNo,
|
||||||
|
'level': launch.safeLevel,
|
||||||
|
'rocketLevel': launch.safeLevel,
|
||||||
|
'rocketIconUrl': launch.rocketIconUrl,
|
||||||
|
'rocketAnimationUrl': launch.rocketAnimationUrl,
|
||||||
|
'durationSeconds': launch.durationSeconds,
|
||||||
|
'countdownSeconds': launch.durationSeconds,
|
||||||
|
'triggerUserId': launch.triggerUserId,
|
||||||
|
'triggerUser': <String, dynamic>{
|
||||||
|
'userId': launch.triggerUser.userId,
|
||||||
|
'nickname': launch.triggerUser.nickname,
|
||||||
|
'avatar': launch.triggerUser.avatar,
|
||||||
|
'account': launch.triggerUser.account,
|
||||||
|
'countryCode': launch.triggerUser.countryCode,
|
||||||
|
'countryName': launch.triggerUser.countryName,
|
||||||
|
},
|
||||||
|
'launchNo': launchNo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _sendRoomRocketLaunchCustomMessage(
|
||||||
|
String groupId,
|
||||||
|
String data,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
final textMsg = await TencentImSDKPlugin.v2TIMManager
|
||||||
|
.getMessageManager()
|
||||||
|
.createCustomMessage(data: data);
|
||||||
|
if (textMsg.code != 0 || textMsg.data?.id == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await TencentImSDKPlugin.v2TIMManager.getMessageManager().sendMessage(
|
||||||
|
id: textMsg.data!.id!,
|
||||||
|
groupID: groupId,
|
||||||
|
receiver: '',
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _sendRoomRedPacketCustomMessage(
|
Future<void> _sendRoomRedPacketCustomMessage(
|
||||||
String groupId,
|
String groupId,
|
||||||
String data,
|
String data,
|
||||||
@ -3453,6 +3588,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
_resetLuckGiftBurstQueue();
|
_resetLuckGiftBurstQueue();
|
||||||
_recentRoomRocketLaunchTimes.clear();
|
_recentRoomRocketLaunchTimes.clear();
|
||||||
_recentRoomRocketLaunchLooseTimes.clear();
|
_recentRoomRocketLaunchLooseTimes.clear();
|
||||||
|
_recentRoomRocketRegionBroadcastTimes.clear();
|
||||||
_roomRocketRewardPopupRetryTimer?.cancel();
|
_roomRocketRewardPopupRetryTimer?.cancel();
|
||||||
_roomRocketRewardPopupRetryTimer = null;
|
_roomRocketRewardPopupRetryTimer = null;
|
||||||
onNewMessageListenerGroupMap.forEach((k, v) {
|
onNewMessageListenerGroupMap.forEach((k, v) {
|
||||||
|
|||||||
@ -167,6 +167,9 @@ String _roomCoverUrl(Map<String, dynamic> data) {
|
|||||||
_asMap(data['room'])['coverUrl'],
|
_asMap(data['room'])['coverUrl'],
|
||||||
_asMap(data['room'])['cover'],
|
_asMap(data['room'])['cover'],
|
||||||
_asMap(data['room'])['avatar'],
|
_asMap(data['room'])['avatar'],
|
||||||
|
_asMap(data['roomInfo'])['coverUrl'],
|
||||||
|
_asMap(data['roomInfo'])['cover'],
|
||||||
|
_asMap(data['roomInfo'])['avatar'],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -492,12 +492,29 @@ class OverlayManager {
|
|||||||
if (previousMessage != null) {
|
if (previousMessage != null) {
|
||||||
visualTop +=
|
visualTop +=
|
||||||
_stackedVisualHeightFor(previousMessage) + _stackedFloatingGap;
|
_stackedVisualHeightFor(previousMessage) + _stackedFloatingGap;
|
||||||
|
} else if (_shouldReserveStackedSlot(message, key)) {
|
||||||
|
visualTop += _stackedReservedVisualHeightFor(key) + _stackedFloatingGap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final wrapperTop = visualTop - _stackedInternalTopFor(message);
|
final wrapperTop = visualTop - _stackedInternalTopFor(message);
|
||||||
return wrapperTop < 0 ? 0 : wrapperTop;
|
return wrapperTop < 0 ? 0 : wrapperTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _shouldReserveStackedSlot(SCFloatingMessage message, int slotKey) {
|
||||||
|
return _homeRootTabsVisible &&
|
||||||
|
_isRegionRoomRocketMessage(message) &&
|
||||||
|
slotKey == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
double _stackedReservedVisualHeightFor(int slotKey) {
|
||||||
|
switch (slotKey) {
|
||||||
|
case 4:
|
||||||
|
return 66;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double _stackedVisualHeightFor(SCFloatingMessage message) {
|
double _stackedVisualHeightFor(SCFloatingMessage message) {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@ -289,6 +289,8 @@ class RoomRocketApiMapper {
|
|||||||
return RoomRocketRewardWinner(
|
return RoomRocketRewardWinner(
|
||||||
nickname: _rewardWinnerName(entry.value, profile),
|
nickname: _rewardWinnerName(entry.value, profile),
|
||||||
avatarUrl: _rewardWinnerAvatar(entry.value, profile),
|
avatarUrl: _rewardWinnerAvatar(entry.value, profile),
|
||||||
|
isTop1: _hasTop1Reward(entry.value),
|
||||||
|
isIgniter: _hasIgniteReward(entry.value),
|
||||||
rewards: rewardItemsFromRecords(entry.value),
|
rewards: rewardItemsFromRecords(entry.value),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@ -335,6 +337,33 @@ class RoomRocketApiMapper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _hasTop1Reward(List<SCRoomRocketRewardRecordRes> records) {
|
||||||
|
return records.any((record) {
|
||||||
|
final scene = _normalizedRewardScene(record.rewardScene);
|
||||||
|
return scene.contains('TOP1') ||
|
||||||
|
scene.contains('TOPONE') ||
|
||||||
|
scene.contains('RANK1') ||
|
||||||
|
scene.contains('RANKONE') ||
|
||||||
|
scene.contains('FIRST') ||
|
||||||
|
scene.contains('KING');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _hasIgniteReward(List<SCRoomRocketRewardRecordRes> records) {
|
||||||
|
return records.any((record) {
|
||||||
|
final scene = _normalizedRewardScene(record.rewardScene);
|
||||||
|
return scene.contains('IGNITE') ||
|
||||||
|
scene.contains('SETOFF') ||
|
||||||
|
scene.contains('LAUNCH') ||
|
||||||
|
scene.contains('TRIGGER') ||
|
||||||
|
scene.contains('LIGHT');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _normalizedRewardScene(String scene) {
|
||||||
|
return scene.trim().toUpperCase().replaceAll(RegExp(r'[\s_\-]+'), '');
|
||||||
|
}
|
||||||
|
|
||||||
static String _rewardWinnerKey(SCRoomRocketRewardRecordRes record) {
|
static String _rewardWinnerKey(SCRoomRocketRewardRecordRes record) {
|
||||||
final userId = record.userId.trim();
|
final userId = record.userId.trim();
|
||||||
if (userId.isNotEmpty) {
|
if (userId.isNotEmpty) {
|
||||||
|
|||||||
@ -192,6 +192,8 @@ class RoomRocketRewardWinner {
|
|||||||
this.avatarAsset,
|
this.avatarAsset,
|
||||||
this.avatarUrl,
|
this.avatarUrl,
|
||||||
this.frameAsset,
|
this.frameAsset,
|
||||||
|
this.isTop1 = false,
|
||||||
|
this.isIgniter = false,
|
||||||
this.rewards = const <RoomRocketRewardItem>[],
|
this.rewards = const <RoomRocketRewardItem>[],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -199,6 +201,8 @@ class RoomRocketRewardWinner {
|
|||||||
final String? avatarAsset;
|
final String? avatarAsset;
|
||||||
final String? avatarUrl;
|
final String? avatarUrl;
|
||||||
final String? frameAsset;
|
final String? frameAsset;
|
||||||
|
final bool isTop1;
|
||||||
|
final bool isIgniter;
|
||||||
final List<RoomRocketRewardItem> rewards;
|
final List<RoomRocketRewardItem> rewards;
|
||||||
|
|
||||||
RoomRocketRewardWinner withRewards(List<RoomRocketRewardItem> nextRewards) {
|
RoomRocketRewardWinner withRewards(List<RoomRocketRewardItem> nextRewards) {
|
||||||
@ -207,6 +211,8 @@ class RoomRocketRewardWinner {
|
|||||||
avatarAsset: avatarAsset,
|
avatarAsset: avatarAsset,
|
||||||
avatarUrl: avatarUrl,
|
avatarUrl: avatarUrl,
|
||||||
frameAsset: frameAsset,
|
frameAsset: frameAsset,
|
||||||
|
isTop1: isTop1,
|
||||||
|
isIgniter: isIgniter,
|
||||||
rewards: nextRewards,
|
rewards: nextRewards,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -442,11 +448,7 @@ class _RewardDialogCanvas extends StatelessWidget {
|
|||||||
if (index >= winners.length) {
|
if (index >= winners.length) {
|
||||||
return _LoadMoreRow(scale: scale);
|
return _LoadMoreRow(scale: scale);
|
||||||
}
|
}
|
||||||
return _WinnerRow(
|
return _WinnerRow(scale: scale, winner: winners[index]);
|
||||||
scale: scale,
|
|
||||||
winner: winners[index],
|
|
||||||
showRocketBadge: index == 0,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -595,15 +597,10 @@ class _RewardDetailCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _WinnerRow extends StatelessWidget {
|
class _WinnerRow extends StatelessWidget {
|
||||||
const _WinnerRow({
|
const _WinnerRow({required this.scale, required this.winner});
|
||||||
required this.scale,
|
|
||||||
required this.winner,
|
|
||||||
required this.showRocketBadge,
|
|
||||||
});
|
|
||||||
|
|
||||||
final double scale;
|
final double scale;
|
||||||
final RoomRocketRewardWinner winner;
|
final RoomRocketRewardWinner winner;
|
||||||
final bool showRocketBadge;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -626,21 +623,36 @@ class _WinnerRow extends StatelessWidget {
|
|||||||
height: 39 * scale,
|
height: 39 * scale,
|
||||||
child: _WinnerAvatar(scale: scale, winner: winner),
|
child: _WinnerAvatar(scale: scale, winner: winner),
|
||||||
),
|
),
|
||||||
if (showRocketBadge)
|
if (winner.isTop1)
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 40 * scale,
|
left: 17 * scale,
|
||||||
top: 26 * scale,
|
top: 39 * scale,
|
||||||
|
width: 39 * scale,
|
||||||
|
height: 9 * scale,
|
||||||
|
child: Text(
|
||||||
|
'top1',
|
||||||
|
textScaler: TextScaler.noScaling,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: const Color(0xFF75F3CB),
|
||||||
|
fontSize: 7 * scale,
|
||||||
|
height: 1,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (winner.isIgniter)
|
||||||
|
Positioned(
|
||||||
|
left: 45 * scale,
|
||||||
|
top: -1 * scale,
|
||||||
width: 14 * scale,
|
width: 14 * scale,
|
||||||
height: 14 * scale,
|
height: 14 * scale,
|
||||||
child: ClipRRect(
|
child: Image.asset(
|
||||||
borderRadius: BorderRadius.circular(3 * scale),
|
_RewardDialogAssets.rocketBody,
|
||||||
child: Transform.rotate(
|
fit: BoxFit.contain,
|
||||||
angle: math.pi / 4,
|
|
||||||
child: Image.asset(
|
|
||||||
_RewardDialogAssets.rocketBody,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
|
|||||||
@ -267,6 +267,32 @@ void main() {
|
|||||||
expect(winners.single.avatarUrl, 'https://example.com/avatar.png');
|
expect(winners.single.avatarUrl, 'https://example.com/avatar.png');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('marks rocket reward winners by reward scene', () {
|
||||||
|
final winners = RoomRocketApiMapper.winnersFromRecords([
|
||||||
|
SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
'id': 'r1',
|
||||||
|
'userId': 'top-user',
|
||||||
|
'userNickname': 'top winner',
|
||||||
|
'rewardScene': 'TOP1',
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 100,
|
||||||
|
}),
|
||||||
|
SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
'id': 'r2',
|
||||||
|
'userId': 'ignite-user',
|
||||||
|
'userNickname': 'igniter',
|
||||||
|
'rewardScene': 'SET_OFF',
|
||||||
|
'rewardType': 'PROPS',
|
||||||
|
'rewardAmount': 1,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(winners.first.isTop1, isTrue);
|
||||||
|
expect(winners.first.isIgniter, isFalse);
|
||||||
|
expect(winners.last.isTop1, isFalse);
|
||||||
|
expect(winners.last.isIgniter, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
test('keeps nested rocket reward users separated by profile id', () {
|
test('keeps nested rocket reward users separated by profile id', () {
|
||||||
final winners = RoomRocketApiMapper.winnersFromRecords([
|
final winners = RoomRocketApiMapper.winnersFromRecords([
|
||||||
SCRoomRocketRewardRecordRes.fromJson({
|
SCRoomRocketRewardRecordRes.fromJson({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user