幸运礼物全局飘窗
This commit is contained in:
parent
07624ac105
commit
27c74abf7e
@ -72,6 +72,7 @@ import 'package:yumi/ui_kit/widgets/room/red_packet/room_red_packet_open_dialog.
|
||||
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/floating/floating_lucky_gift_global_screen_widget.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/cp/room_cp_invite_dialog.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/cp/room_cp_relation_formed_effect.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/room_msg_item.dart';
|
||||
@ -3691,23 +3692,45 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
}
|
||||
|
||||
SCFloatingMessage _buildLuckyGiftFloatingMessage(
|
||||
SCBroadCastLuckGiftPush broadCastRes,
|
||||
) {
|
||||
SCBroadCastLuckGiftPush broadCastRes, {
|
||||
int type = 0,
|
||||
bool isRegionBroadcast = false,
|
||||
}) {
|
||||
final rewardData = broadCastRes.data;
|
||||
final resolvedGiftUrl = _resolveLuckyGiftGiftPhoto(rewardData);
|
||||
final userId = _firstNonBlank([
|
||||
rewardData?.sendUserId,
|
||||
rewardData?.senderUserId,
|
||||
rewardData?.userId,
|
||||
rewardData?.account,
|
||||
]);
|
||||
final userName = _firstNonBlank([
|
||||
rewardData?.nickname,
|
||||
rewardData?.account,
|
||||
userId,
|
||||
]);
|
||||
final eventId = _firstNonBlank([
|
||||
rewardData?.businessId,
|
||||
rewardData?.orderId,
|
||||
rewardData?.msg,
|
||||
]);
|
||||
return SCFloatingMessage(
|
||||
type: 0,
|
||||
userId: rewardData?.sendUserId,
|
||||
type: type,
|
||||
userId: userId,
|
||||
roomId: rewardData?.roomId,
|
||||
toUserId: rewardData?.acceptUserId,
|
||||
userAvatarUrl: rewardData?.userAvatar,
|
||||
userName: rewardData?.nickname,
|
||||
userName: userName,
|
||||
toUserName: rewardData?.acceptNickname,
|
||||
giftUrl: resolvedGiftUrl,
|
||||
giftId: rewardData?.giftId,
|
||||
gameId: eventId,
|
||||
number: rewardData?.giftQuantity,
|
||||
coins: rewardData?.awardAmount,
|
||||
multiple: rewardData?.multiple,
|
||||
displayText: rewardData?.msg,
|
||||
broadcastScope:
|
||||
isRegionBroadcast ? SCFloatingMessage.broadcastScopeRegion : '',
|
||||
priority: 1000,
|
||||
);
|
||||
}
|
||||
@ -3715,6 +3738,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
void _handleLuckyGiftGlobalNews(
|
||||
SCBroadCastLuckGiftPush broadCastRes, {
|
||||
required String source,
|
||||
bool isRegionBroadcast = false,
|
||||
}) {
|
||||
final rewardData = broadCastRes.data;
|
||||
if (rewardData == null) {
|
||||
@ -3723,8 +3747,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
if (_isLuckyGiftInCurrentRoom(broadCastRes)) {
|
||||
addluckGiftPushQueue(broadCastRes);
|
||||
}
|
||||
if (!rewardData.shouldShowGlobalNews ||
|
||||
(rewardData.multiple ?? 0) < _luckyGiftFloatMinMultiple) {
|
||||
if (!rewardData.shouldShowGlobalNews) {
|
||||
return;
|
||||
}
|
||||
if (source == 'broadcast' && _isLuckyGiftInCurrentRoom(broadCastRes)) {
|
||||
@ -3736,6 +3759,19 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (source == 'broadcast') {
|
||||
OverlayManager().addMessage(
|
||||
_buildLuckyGiftFloatingMessage(
|
||||
broadCastRes,
|
||||
type: FloatingLuckyGiftGlobalScreenWidget.floatingType,
|
||||
isRegionBroadcast: isRegionBroadcast,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if ((rewardData.multiple ?? 0) < _luckyGiftFloatMinMultiple) {
|
||||
return;
|
||||
}
|
||||
OverlayManager().addMessage(_buildLuckyGiftFloatingMessage(broadCastRes));
|
||||
}
|
||||
|
||||
@ -3832,6 +3868,17 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
final resolvedGiftUrl = _resolveLuckyGiftGiftPhoto(rewardData);
|
||||
final senderId = _firstNonBlank([
|
||||
rewardData.sendUserId,
|
||||
rewardData.senderUserId,
|
||||
rewardData.userId,
|
||||
rewardData.account,
|
||||
]);
|
||||
final senderName = _firstNonBlank([
|
||||
rewardData.nickname,
|
||||
rewardData.account,
|
||||
senderId,
|
||||
]);
|
||||
final roomMsg = Msg(
|
||||
groupId: '',
|
||||
msg: '',
|
||||
@ -3845,8 +3892,8 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
roomMsg.number = 0;
|
||||
roomMsg.awardAmount = rewardData.awardAmount;
|
||||
roomMsg.user = SocialChatUserProfile(
|
||||
id: rewardData.sendUserId,
|
||||
userNickname: rewardData.nickname,
|
||||
id: senderId,
|
||||
userNickname: senderName,
|
||||
userAvatar: rewardData.userAvatar,
|
||||
);
|
||||
roomMsg.toUser = SocialChatUserProfile(
|
||||
@ -3869,8 +3916,8 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
giftTab: 'LUCK',
|
||||
);
|
||||
highlightMsg.user = SocialChatUserProfile(
|
||||
id: rewardData.sendUserId,
|
||||
userNickname: rewardData.nickname,
|
||||
id: senderId,
|
||||
userNickname: senderName,
|
||||
);
|
||||
addMsg(highlightMsg);
|
||||
}
|
||||
@ -3878,8 +3925,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
addluckGiftPushQueue(broadCastRes);
|
||||
_handleLuckyGiftGlobalNews(broadCastRes, source: 'room_group');
|
||||
|
||||
if (rewardData.sendUserId ==
|
||||
AccountStorage().getCurrentUser()?.userProfile?.id) {
|
||||
if (senderId == AccountStorage().getCurrentUser()?.userProfile?.id) {
|
||||
Provider.of<GiftProvider>(
|
||||
context!,
|
||||
listen: false,
|
||||
@ -5917,7 +5963,11 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
'multipleType=${broadCastRes.data?.multipleType} '
|
||||
'globalNews=${broadCastRes.data?.globalNews}',
|
||||
);
|
||||
_handleLuckyGiftGlobalNews(broadCastRes, source: 'broadcast');
|
||||
_handleLuckyGiftGlobalNews(
|
||||
broadCastRes,
|
||||
source: 'broadcast',
|
||||
isRegionBroadcast: isRegionBroadcastGroup,
|
||||
);
|
||||
} else if (type == "REGISTER_REWARD_GRANTED") {
|
||||
await DataPersistence.setPendingRegisterRewardDialog(true);
|
||||
await DataPersistence.clearAwaitRegisterRewardSocket();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/// data : {"acceptNickname":"Sukabuliete","acceptUserId":"1957345312961527809","account":"8826602","avatarFrameCover":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/svga_cover/manager-33adbddc-b68c-407d-8cbb-3c7b9878b953.png","avatarFrameSvg":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/svgasource/manager-97edd7e3-0335-4521-8eb0-5a84b009d2a9.svga","balance":1611358.0,"giftCandy":1000.0,"giftCover":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/gifts/manager-effb4f1c-872d-4abf-8797-9987bf206006.png","giftQuantity":1,"globalNews":true,"multiple":1,"multipleType":"WIN","nickname":"Sukabuliete","regionCode":"AF","roomAccount":"8826602","roomId":"1957345511792508929","sendUserId":"1957345312961527809","sysOrigin":"YUMI","userAvatar":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/avatar/0e031d7e-d269-44fe-98eb-543060d37f07.jpg"}
|
||||
/// type : "GAME_LUCKY_GIFT"
|
||||
// data : {"acceptNickname":"Sukabuliete","acceptUserId":"1957345312961527809","account":"8826602","avatarFrameCover":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/svga_cover/manager-33adbddc-b68c-407d-8cbb-3c7b9878b953.png","avatarFrameSvg":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/svgasource/manager-97edd7e3-0335-4521-8eb0-5a84b009d2a9.svga","balance":1611358.0,"giftCandy":1000.0,"giftCover":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/gifts/manager-effb4f1c-872d-4abf-8797-9987bf206006.png","giftQuantity":1,"globalNews":true,"multiple":1,"multipleType":"WIN","nickname":"Sukabuliete","regionCode":"AF","roomAccount":"8826602","roomId":"1957345511792508929","sendUserId":"1957345312961527809","sysOrigin":"YUMI","userAvatar":"https://tkm-yumi.oss-ap-southeast-1.aliyuncs.com/avatar/0e031d7e-d269-44fe-98eb-543060d37f07.jpg"}
|
||||
// type : "GAME_LUCKY_GIFT"
|
||||
|
||||
class SCBroadCastLuckGiftPush {
|
||||
SCBroadCastLuckGiftPush({Data? data, String? type}) {
|
||||
@ -82,8 +82,15 @@ class Data {
|
||||
String? roomId,
|
||||
String? giftId,
|
||||
String? sendUserId,
|
||||
String? senderUserId,
|
||||
String? userId,
|
||||
String? sysOrigin,
|
||||
String? userAvatar,
|
||||
String? businessId,
|
||||
String? orderId,
|
||||
String? msg,
|
||||
num? winAmount,
|
||||
num? winMultiple,
|
||||
}) {
|
||||
_acceptNickname = acceptNickname;
|
||||
_acceptUserId = acceptUserId;
|
||||
@ -103,9 +110,16 @@ class Data {
|
||||
_roomAccount = roomAccount;
|
||||
_roomId = roomId;
|
||||
_sendUserId = sendUserId;
|
||||
_senderUserId = senderUserId;
|
||||
_userId = userId;
|
||||
_giftId = giftId;
|
||||
_sysOrigin = sysOrigin;
|
||||
_userAvatar = userAvatar;
|
||||
_businessId = businessId;
|
||||
_orderId = orderId;
|
||||
_msg = msg;
|
||||
_winAmount = winAmount;
|
||||
_winMultiple = winMultiple;
|
||||
}
|
||||
|
||||
Data.fromJson(dynamic json) {
|
||||
@ -115,21 +129,37 @@ class Data {
|
||||
_avatarFrameCover = _asString(json['avatarFrameCover']);
|
||||
_avatarFrameSvg = _asString(json['avatarFrameSvg']);
|
||||
_balance = _asNum(json['balance']);
|
||||
_awardAmount = _asNum(json['awardAmount']);
|
||||
_awardAmount = _asNum(json['awardAmount'] ?? json['winAmount']);
|
||||
_giftCandy = _asNum(json['giftCandy']);
|
||||
_giftCover = _asString(json['giftCover']);
|
||||
_giftCover = _firstText(
|
||||
_asString(json['giftCover']),
|
||||
_firstText(_asString(json['giftUrl']), _asString(json['giftIcon'])),
|
||||
);
|
||||
_giftQuantity = _asNum(json['giftQuantity']);
|
||||
_globalNews = _asBool(json['globalNews']);
|
||||
_multiple = _asNum(json['multiple']);
|
||||
_multiple = _asNum(json['multiple'] ?? json['winMultiple']);
|
||||
_multipleType = _asString(json['multipleType']);
|
||||
_nickname = _asString(json['nickname']);
|
||||
_nickname = _firstText(
|
||||
_asString(json['nickname']),
|
||||
_firstText(_asString(json['userNickname']), _asString(json['userName'])),
|
||||
);
|
||||
_regionCode = _asString(json['regionCode']);
|
||||
_roomAccount = _asString(json['roomAccount']);
|
||||
_roomId = _asString(json['roomId']);
|
||||
_sendUserId = _asString(json['sendUserId']);
|
||||
_senderUserId = _asString(json['senderUserId']);
|
||||
_userId = _asString(json['userId']);
|
||||
_sendUserId = _firstText(
|
||||
_asString(json['sendUserId']),
|
||||
_firstText(_senderUserId, _userId),
|
||||
);
|
||||
_sysOrigin = _asString(json['sysOrigin']);
|
||||
_userAvatar = _asString(json['userAvatar']);
|
||||
_giftId = _asString(json['giftId']);
|
||||
_businessId = _asString(json['businessId']);
|
||||
_orderId = _asString(json['orderId']);
|
||||
_msg = _asString(json['msg']);
|
||||
_winAmount = _asNum(json['winAmount']);
|
||||
_winMultiple = _asNum(json['winMultiple']);
|
||||
}
|
||||
String? _acceptNickname;
|
||||
String? _acceptUserId;
|
||||
@ -149,9 +179,16 @@ class Data {
|
||||
String? _roomAccount;
|
||||
String? _roomId;
|
||||
String? _sendUserId;
|
||||
String? _senderUserId;
|
||||
String? _userId;
|
||||
String? _giftId;
|
||||
String? _sysOrigin;
|
||||
String? _userAvatar;
|
||||
String? _businessId;
|
||||
String? _orderId;
|
||||
String? _msg;
|
||||
num? _winAmount;
|
||||
num? _winMultiple;
|
||||
String? get acceptNickname => _acceptNickname;
|
||||
String? get acceptUserId => _acceptUserId;
|
||||
String? get account => _account;
|
||||
@ -171,8 +208,15 @@ class Data {
|
||||
String? get roomAccount => _roomAccount;
|
||||
String? get roomId => _roomId;
|
||||
String? get sendUserId => _sendUserId;
|
||||
String? get senderUserId => _senderUserId;
|
||||
String? get userId => _userId;
|
||||
String? get sysOrigin => _sysOrigin;
|
||||
String? get userAvatar => _userAvatar;
|
||||
String? get businessId => _businessId;
|
||||
String? get orderId => _orderId;
|
||||
String? get msg => _msg;
|
||||
num? get winAmount => _winAmount;
|
||||
num? get winMultiple => _winMultiple;
|
||||
String get normalizedMultipleType =>
|
||||
(_multipleType ?? '').trim().toUpperCase();
|
||||
bool get shouldShowGlobalNews => _globalNews ?? false;
|
||||
@ -203,8 +247,15 @@ class Data {
|
||||
roomId: _firstText(_roomId, incoming.roomId),
|
||||
giftId: _firstText(_giftId, incoming.giftId),
|
||||
sendUserId: _firstText(_sendUserId, incoming.sendUserId),
|
||||
senderUserId: _firstText(_senderUserId, incoming.senderUserId),
|
||||
userId: _firstText(_userId, incoming.userId),
|
||||
sysOrigin: _firstText(_sysOrigin, incoming.sysOrigin),
|
||||
userAvatar: _firstText(_userAvatar, incoming.userAvatar),
|
||||
businessId: _firstText(_businessId, incoming.businessId),
|
||||
orderId: _firstText(_orderId, incoming.orderId),
|
||||
msg: _firstText(_msg, incoming.msg),
|
||||
winAmount: _sumNum(_winAmount, incoming.winAmount),
|
||||
winMultiple: _maxNum(_winMultiple, incoming.winMultiple),
|
||||
);
|
||||
}
|
||||
|
||||
@ -313,9 +364,16 @@ class Data {
|
||||
map['roomAccount'] = _roomAccount;
|
||||
map['roomId'] = _roomId;
|
||||
map['sendUserId'] = _sendUserId;
|
||||
map['senderUserId'] = _senderUserId;
|
||||
map['userId'] = _userId;
|
||||
map['sysOrigin'] = _sysOrigin;
|
||||
map['userAvatar'] = _userAvatar;
|
||||
map['giftId'] = _giftId;
|
||||
map['businessId'] = _businessId;
|
||||
map['orderId'] = _orderId;
|
||||
map['msg'] = _msg;
|
||||
map['winAmount'] = _winAmount;
|
||||
map['winMultiple'] = _winMultiple;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import 'package:yumi/shared/data_sources/sources/local/data_persistence.dart';
|
||||
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/floating/floating_game_screen_widget.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/floating/floating_gift_screen_widget.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/floating/floating_lucky_gift_global_screen_widget.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/floating/floating_luck_gift_screen_widget.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/floating/floating_room_redenvelope_screen_widget.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/floating/floating_room_rocket_screen_widget.dart';
|
||||
@ -207,6 +208,27 @@ class OverlayManager {
|
||||
}
|
||||
return 'game_win_fallback|$roomId|$userId|$gameId|$coins';
|
||||
}
|
||||
if (message.type == FloatingLuckyGiftGlobalScreenWidget.floatingType) {
|
||||
final eventId = message.gameId?.trim() ?? '';
|
||||
if (eventId.isNotEmpty) {
|
||||
return 'global_lucky_gift_win|$eventId';
|
||||
}
|
||||
final roomId = message.roomId?.trim() ?? '';
|
||||
final userId = message.userId?.trim() ?? '';
|
||||
final toUserId = message.toUserId?.trim() ?? '';
|
||||
final giftId = message.giftId?.trim() ?? '';
|
||||
final coins = message.coins ?? 0;
|
||||
final multiple = message.multiple ?? 0;
|
||||
if (roomId.isEmpty &&
|
||||
userId.isEmpty &&
|
||||
toUserId.isEmpty &&
|
||||
giftId.isEmpty &&
|
||||
coins == 0 &&
|
||||
multiple == 0) {
|
||||
return null;
|
||||
}
|
||||
return 'global_lucky_gift_win_fallback|$roomId|$userId|$toUserId|$giftId|$coins|$multiple';
|
||||
}
|
||||
if (message.type == 6) {
|
||||
final roomId = message.roomId?.trim() ?? '';
|
||||
final action = message.giftId?.trim() ?? '';
|
||||
@ -226,7 +248,8 @@ class OverlayManager {
|
||||
}
|
||||
|
||||
Duration _floatingDedupWindowFor(SCFloatingMessage message) {
|
||||
if (message.type == 2) {
|
||||
if (message.type == 2 ||
|
||||
message.type == FloatingLuckyGiftGlobalScreenWidget.floatingType) {
|
||||
return _gameWinFloatingDedupWindow;
|
||||
}
|
||||
if (message.type == 6) {
|
||||
@ -503,6 +526,12 @@ class OverlayManager {
|
||||
message: message,
|
||||
onAnimationCompleted: onComplete,
|
||||
);
|
||||
case FloatingLuckyGiftGlobalScreenWidget.floatingType:
|
||||
// Global lucky gift win.
|
||||
return FloatingLuckyGiftGlobalScreenWidget(
|
||||
message: message,
|
||||
onAnimationCompleted: onComplete,
|
||||
);
|
||||
case 3:
|
||||
//火箭
|
||||
return FloatingRoomRocketScreenWidget(
|
||||
@ -744,6 +773,12 @@ class OverlayManager {
|
||||
if (normalizedRoomId.isNotEmpty) {
|
||||
_removeMessagesByType(2, roomId: normalizedRoomId);
|
||||
}
|
||||
if (normalizedRoomId.isNotEmpty) {
|
||||
_removeMessagesByType(
|
||||
FloatingLuckyGiftGlobalScreenWidget.floatingType,
|
||||
roomId: normalizedRoomId,
|
||||
);
|
||||
}
|
||||
if (normalizedRoomId.isNotEmpty) {
|
||||
_removeMessagesByType(4, roomId: normalizedRoomId);
|
||||
}
|
||||
@ -803,6 +838,11 @@ class OverlayManager {
|
||||
return message.type == 2 && message.isRegionBroadcast;
|
||||
}
|
||||
|
||||
bool _isRegionLuckyGiftGlobalMessage(SCFloatingMessage message) {
|
||||
return message.type == FloatingLuckyGiftGlobalScreenWidget.floatingType &&
|
||||
message.isRegionBroadcast;
|
||||
}
|
||||
|
||||
bool _isRegionCpGiftMessage(SCFloatingMessage message) {
|
||||
return message.type == 1 &&
|
||||
message.isRegionBroadcast &&
|
||||
@ -817,6 +857,7 @@ class OverlayManager {
|
||||
return _isRegionRedPacketMessage(message) ||
|
||||
_isRegionRoomRocketMessage(message) ||
|
||||
_isRegionGameWinMessage(message) ||
|
||||
_isRegionLuckyGiftGlobalMessage(message) ||
|
||||
_isRegionCpGiftMessage(message) ||
|
||||
_isRegionCpRelationMessage(message);
|
||||
}
|
||||
@ -948,19 +989,22 @@ class OverlayManager {
|
||||
message.type == 3 ||
|
||||
message.type == 6 ||
|
||||
_isRegionCpGiftMessage(message);
|
||||
final isGlobalWinBroadcast =
|
||||
message.type == 2 ||
|
||||
message.type == FloatingLuckyGiftGlobalScreenWidget.floatingType;
|
||||
if (isCurrentVisibleRoom) {
|
||||
// 区域红包/火箭/CP 类飘窗在当前房间仍然需要展示;普通区域礼物当前房间由 RTM 层跳过,避免和房间 IM 礼物飘屏重复。
|
||||
return isGlobalStackedBroadcast || message.type == 2;
|
||||
return isGlobalStackedBroadcast || isGlobalWinBroadcast;
|
||||
}
|
||||
final isCurrentRoomMessage =
|
||||
currentRoomId.isNotEmpty &&
|
||||
messageRoomId.isNotEmpty &&
|
||||
currentRoomId == messageRoomId;
|
||||
if ((isGlobalStackedBroadcast || message.type == 2) &&
|
||||
if ((isGlobalStackedBroadcast || isGlobalWinBroadcast) &&
|
||||
isCurrentRoomMessage) {
|
||||
return false;
|
||||
}
|
||||
if (message.type == 2) {
|
||||
if (isGlobalWinBroadcast) {
|
||||
if (SCGlobalConfig.isFloatingBroadcastRoomOnly) {
|
||||
return false;
|
||||
}
|
||||
@ -1024,6 +1068,8 @@ class OverlayManager {
|
||||
(activeMessage.type == 0 ||
|
||||
activeMessage.type == 1 ||
|
||||
activeMessage.type == 2 ||
|
||||
activeMessage.type ==
|
||||
FloatingLuckyGiftGlobalScreenWidget.floatingType ||
|
||||
activeMessage.type == 3 ||
|
||||
activeMessage.type == 5 ||
|
||||
(includeRedPacket && activeMessage.type == 4)) &&
|
||||
@ -1064,6 +1110,7 @@ class OverlayManager {
|
||||
type == 0 ||
|
||||
type == 1 ||
|
||||
type == 2 ||
|
||||
type == FloatingLuckyGiftGlobalScreenWidget.floatingType ||
|
||||
type == 3 ||
|
||||
type == 5 ||
|
||||
(includeRedPacket && type == 4);
|
||||
|
||||
@ -0,0 +1,375 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_debouncer/flutter_debouncer.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:yumi/main.dart';
|
||||
import 'package:yumi/services/audio/rtc_manager.dart';
|
||||
import 'package:yumi/shared/data_sources/models/message/sc_floating_message.dart';
|
||||
import 'package:yumi/shared/tools/sc_network_image_utils.dart';
|
||||
import 'package:yumi/shared/tools/sc_room_utils.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_pag_effect_overlay.dart';
|
||||
|
||||
class FloatingLuckyGiftGlobalScreenWidget extends StatefulWidget {
|
||||
const FloatingLuckyGiftGlobalScreenWidget({
|
||||
super.key,
|
||||
required this.message,
|
||||
required this.onAnimationCompleted,
|
||||
});
|
||||
|
||||
static const int floatingType = 7;
|
||||
static const double bannerWidth = 350;
|
||||
static const double bannerHeight = 94;
|
||||
static const String backgroundPagAssetPath =
|
||||
"sc_images/room/anim/luck_gift/base_lucky_gift_res.pag";
|
||||
|
||||
final SCFloatingMessage message;
|
||||
final VoidCallback onAnimationCompleted;
|
||||
|
||||
@override
|
||||
State<FloatingLuckyGiftGlobalScreenWidget> createState() =>
|
||||
_FloatingLuckyGiftGlobalScreenWidgetState();
|
||||
}
|
||||
|
||||
class _FloatingLuckyGiftGlobalScreenWidgetState
|
||||
extends State<FloatingLuckyGiftGlobalScreenWidget>
|
||||
with TickerProviderStateMixin {
|
||||
final Debouncer _debouncer = Debouncer();
|
||||
late final AnimationController _controller;
|
||||
late final Animation<Offset> _offsetAnimation;
|
||||
late final AnimationController _swipeController;
|
||||
late final Animation<Offset> _swipeAnimation;
|
||||
|
||||
bool _isSwipeAnimating = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 5),
|
||||
vsync: this,
|
||||
);
|
||||
_swipeController = AnimationController(
|
||||
duration: const Duration(milliseconds: 550),
|
||||
vsync: this,
|
||||
);
|
||||
_offsetAnimation = Tween<Offset>(
|
||||
begin: const Offset(1, 0),
|
||||
end: const Offset(-1, 0),
|
||||
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));
|
||||
_swipeAnimation = Tween<Offset>(
|
||||
begin: Offset.zero,
|
||||
end: const Offset(-1.5, 0),
|
||||
).animate(CurvedAnimation(parent: _swipeController, curve: Curves.easeIn));
|
||||
|
||||
_controller.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed && !_isSwipeAnimating) {
|
||||
widget.onAnimationCompleted();
|
||||
}
|
||||
});
|
||||
_swipeController.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
widget.onAnimationCompleted();
|
||||
}
|
||||
});
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_controller.forward();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_swipeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: GestureDetector(
|
||||
onTap: _handleTap,
|
||||
onHorizontalDragEnd: _handleHorizontalDragEnd,
|
||||
child: SlideTransition(
|
||||
position: _isSwipeAnimating ? _swipeAnimation : _offsetAnimation,
|
||||
child: SizedBox(
|
||||
width: FloatingLuckyGiftGlobalScreenWidget.bannerWidth.w,
|
||||
height: FloatingLuckyGiftGlobalScreenWidget.bannerHeight.w,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned.fill(child: _buildBackground()),
|
||||
Positioned(left: 30.w, top: 22.w, child: _buildAvatar()),
|
||||
Positioned(
|
||||
left: 88.w,
|
||||
top: 26.w,
|
||||
width: 160.w,
|
||||
height: 45.w,
|
||||
child: _buildTextBlock(),
|
||||
),
|
||||
Positioned(
|
||||
right: 23.w,
|
||||
top: 24.w,
|
||||
width: 61.w,
|
||||
height: 45.w,
|
||||
child: _buildMultiple(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBackground() {
|
||||
return RoomRocketPagPreview(
|
||||
resource: FloatingLuckyGiftGlobalScreenWidget.backgroundPagAssetPath,
|
||||
width: FloatingLuckyGiftGlobalScreenWidget.bannerWidth.w,
|
||||
height: FloatingLuckyGiftGlobalScreenWidget.bannerHeight.w,
|
||||
fit: BoxFit.fill,
|
||||
clipBehavior: Clip.none,
|
||||
defaultBuilder: (_) => _buildFallbackBackground(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFallbackBackground() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(47.w),
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [Color(0xFF2E185E), Color(0xFF6B38D6), Color(0xFF8D5CFF)],
|
||||
),
|
||||
border: Border.all(color: const Color(0xFFFFE7A7), width: 1.w),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAvatar() {
|
||||
const fallbackAsset = "sc_images/general/sc_icon_avar_defalt.png";
|
||||
final avatarUrl = (widget.message.userAvatarUrl ?? "").trim();
|
||||
final avatar =
|
||||
avatarUrl.isEmpty
|
||||
? Image.asset(
|
||||
fallbackAsset,
|
||||
width: 48.w,
|
||||
height: 48.w,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Image(
|
||||
image: buildCachedImageProvider(
|
||||
avatarUrl,
|
||||
logicalWidth: 48.w,
|
||||
logicalHeight: 48.w,
|
||||
),
|
||||
width: 48.w,
|
||||
height: 48.w,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder:
|
||||
(_, __, ___) => Image.asset(
|
||||
fallbackAsset,
|
||||
width: 48.w,
|
||||
height: 48.w,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
return Container(
|
||||
width: 48.w,
|
||||
height: 48.w,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: const Color(0xFFFFF4C2), width: 1.5.w),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: avatar,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTextBlock() {
|
||||
final title = _winnerName();
|
||||
final subtitle = "wins ${_formatCoins(widget.message.coins)} coins";
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_singleLineText(
|
||||
title,
|
||||
TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 19.sp,
|
||||
fontWeight: FontWeight.w800,
|
||||
height: 1,
|
||||
decoration: TextDecoration.none,
|
||||
shadows: _textShadows(),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 7.w),
|
||||
_singleLineText(
|
||||
subtitle,
|
||||
TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13.sp,
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1,
|
||||
decoration: TextDecoration.none,
|
||||
shadows: _textShadows(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMultiple() {
|
||||
return Center(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
"x${_formatMultiple(widget.message.multiple)}",
|
||||
maxLines: 1,
|
||||
textScaler: TextScaler.noScaling,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 32.sp,
|
||||
fontWeight: FontWeight.w800,
|
||||
height: 1,
|
||||
decoration: TextDecoration.none,
|
||||
shadows: _textShadows(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _singleLineText(String text, TextStyle style) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
text,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.visible,
|
||||
textScaler: TextScaler.noScaling,
|
||||
style: style,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Shadow> _textShadows() {
|
||||
return [
|
||||
Shadow(
|
||||
color: const Color(0xFF3A166F).withValues(alpha: 0.9),
|
||||
blurRadius: 4.w,
|
||||
offset: Offset(0, 1.w),
|
||||
),
|
||||
Shadow(
|
||||
color: Colors.black.withValues(alpha: 0.24),
|
||||
blurRadius: 6.w,
|
||||
offset: Offset(0, 1.5.w),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
void _handleTap() {
|
||||
_debouncer.debounce(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
onDebounce: () {
|
||||
final currentContext = navigatorKey.currentState?.context;
|
||||
if (currentContext == null || !currentContext.mounted) {
|
||||
return;
|
||||
}
|
||||
final messageRoomId = (widget.message.roomId ?? "").trim();
|
||||
if (messageRoomId.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final rtcProvider = Provider.of<RealTimeCommunicationManager>(
|
||||
currentContext,
|
||||
listen: false,
|
||||
);
|
||||
final currentRoomId =
|
||||
rtcProvider.currenRoom?.roomProfile?.roomProfile?.id?.trim() ?? "";
|
||||
final isSameVisibleRoom =
|
||||
rtcProvider.shouldShowRoomVisualEffects &&
|
||||
rtcProvider.isVoiceRoomRouteVisible &&
|
||||
currentRoomId.isNotEmpty &&
|
||||
currentRoomId == messageRoomId;
|
||||
if (isSameVisibleRoom) {
|
||||
return;
|
||||
}
|
||||
SCRoomUtils.goRoom(messageRoomId, currentContext, fromFloting: true);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _handleHorizontalDragEnd(DragEndDetails details) {
|
||||
final velocity = details.primaryVelocity ?? 0;
|
||||
if (velocity < 0) {
|
||||
_handleSwipeLeft();
|
||||
}
|
||||
}
|
||||
|
||||
void _handleSwipeLeft() {
|
||||
if (_isSwipeAnimating) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isSwipeAnimating = true;
|
||||
});
|
||||
_controller.stop();
|
||||
_swipeController.reset();
|
||||
_swipeController.forward();
|
||||
}
|
||||
|
||||
String _winnerName() {
|
||||
return _firstNonBlank([
|
||||
widget.message.userName,
|
||||
widget.message.userId,
|
||||
"Lucky Gift",
|
||||
]);
|
||||
}
|
||||
|
||||
String _firstNonBlank(Iterable<String?> values) {
|
||||
for (final value in values) {
|
||||
final text = value?.trim();
|
||||
if (text != null && text.isNotEmpty) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
String _formatMultiple(num? value) {
|
||||
final multiple = value ?? 0;
|
||||
if (multiple <= 0) {
|
||||
return "0";
|
||||
}
|
||||
if (multiple == multiple.roundToDouble()) {
|
||||
return multiple.toInt().toString();
|
||||
}
|
||||
return multiple.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
String _formatCoins(num? value) {
|
||||
final coins = value ?? 0;
|
||||
if (coins >= 1000000) {
|
||||
return "${(coins / 1000000).toStringAsFixed(1)}M";
|
||||
}
|
||||
if (coins >= 100000) {
|
||||
return "${(coins / 1000).toStringAsFixed(0)}k";
|
||||
}
|
||||
if (coins == coins.roundToDouble()) {
|
||||
return coins.toInt().toString();
|
||||
}
|
||||
return coins.toStringAsFixed(2);
|
||||
}
|
||||
}
|
||||
BIN
sc_images/room/anim/luck_gift/base_lucky_gift_res.pag
Normal file
BIN
sc_images/room/anim/luck_gift/base_lucky_gift_res.pag
Normal file
Binary file not shown.
@ -38,5 +38,36 @@ void main() {
|
||||
expect(merged.data?.multiple, 30);
|
||||
expect(merged.data?.multipleType, 'BIG_WIN');
|
||||
});
|
||||
|
||||
test('parses global lucky gift win payload aliases', () {
|
||||
final message = SCBroadCastLuckGiftPush.fromJson({
|
||||
'type': 'GAME_LUCKY_GIFT',
|
||||
'data': {
|
||||
'acceptUserId': '123456',
|
||||
'businessId': 'admin-sim-lucky-gift-1779714977048',
|
||||
'giftId': '1',
|
||||
'giftQuantity': 1,
|
||||
'globalNews': true,
|
||||
'msg': '123456 play lucky_gift get x 10 win 1000 coins!!!',
|
||||
'multipleType': 'WIN',
|
||||
'orderId': 'admin-sim-order-1779714977048',
|
||||
'roomId': '123456',
|
||||
'senderUserId': '123456',
|
||||
'userId': '123456',
|
||||
'winAmount': 1000,
|
||||
'winMultiple': 10,
|
||||
},
|
||||
});
|
||||
|
||||
expect(message.data?.sendUserId, '123456');
|
||||
expect(message.data?.awardAmount, 1000);
|
||||
expect(message.data?.multiple, 10);
|
||||
expect(message.data?.shouldShowGlobalNews, isTrue);
|
||||
expect(message.data?.businessId, 'admin-sim-lucky-gift-1779714977048');
|
||||
expect(
|
||||
message.data?.msg,
|
||||
'123456 play lucky_gift get x 10 win 1000 coins!!!',
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user