修改bug

This commit is contained in:
roxy 2026-06-02 13:57:50 +08:00
parent 7e10b77d10
commit 5501345a7e
15 changed files with 155 additions and 552 deletions

View File

@ -16,7 +16,7 @@ class SCVariant1Config implements AppConfig {
@override
String get apiHost => const String.fromEnvironment(
'API_HOST',
defaultValue: 'https://jvapi.haiyihy.com/',
defaultValue: 'http://192.168.110.64:1100/',
); // --dart-define=API_HOST 线https://jvapi.haiyihy.com/
@override

View File

@ -168,8 +168,7 @@ class SCGlobalConfig {
}
static String clampFloatingBroadcastScope(String value) {
final scope = normalizeFloatingBroadcastScope(value);
return _isLowPerformanceDevice ? floatingBroadcastScopeOff : scope;
return normalizeFloatingBroadcastScope(value);
}
static String floatingBroadcastScopeStorageKey(String? account) {
@ -188,8 +187,7 @@ class SCGlobalConfig {
static bool get isLowPerformanceDevice => _isLowPerformanceDevice;
static bool get allowsHighCostAnimations =>
!_isLowPerformanceDevice && sdkInt > maxSdkNoAnim;
static bool get allowsHighCostAnimations => true;
static int get recommendedImageCacheBytes =>
_isLowPerformanceDevice ? 40 * 1024 * 1024 : 100 * 1024 * 1024;
@ -211,19 +209,17 @@ class SCGlobalConfig {
isLowRamDevice ||
processorCount <= 6 ||
matchesKnownLowPerformanceModel;
resetVisualEffectSwitchesToRecommendedDefaults();
}
static bool clampVisualEffectPreference(bool enabled) {
return !_isLowPerformanceDevice && enabled;
return enabled;
}
static void resetVisualEffectSwitchesToRecommendedDefaults() {
final enabled = !_isLowPerformanceDevice;
isEntryVehicleAnimation = enabled;
isGiftSpecialEffects = enabled;
isFloatingAnimationInGlobal = enabled;
isLuckGiftSpecialEffects = enabled;
isEntryVehicleAnimation = true;
isGiftSpecialEffects = true;
isFloatingAnimationInGlobal = true;
isLuckGiftSpecialEffects = true;
}
///

View File

@ -23,7 +23,6 @@ import 'package:yumi/shared/tools/sc_message_utils.dart';
import 'package:yumi/shared/tools/sc_user_id_utils.dart';
import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart';
import 'package:yumi/shared/business_logic/models/res/login_res.dart';
import 'package:yumi/shared/business_logic/models/res/sc_vip_res.dart';
import 'package:yumi/services/audio/rtm_manager.dart';
import 'package:marquee/marquee.dart';
import 'package:provider/provider.dart';
@ -59,7 +58,6 @@ import 'package:yumi/shared/tools/sc_message_notifier.dart';
import 'package:yumi/shared/tools/sc_path_utils.dart';
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/shared/data_sources/sources/repositories/sc_vip_repository_imp.dart';
import 'package:yumi/services/auth/user_profile_manager.dart';
import 'package:yumi/modules/index/main_route.dart';
import 'package:yumi/ui_kit/widgets/sc_nine_patch_image.dart';
@ -81,29 +79,6 @@ const EdgeInsets _vipBubbleCenterSliceRatio = EdgeInsets.fromLTRB(
);
const EdgeInsets _vipBubbleSourceEdgeInset = EdgeInsets.all(2);
String _resolveVipChatBubbleImageUrl(SCVipResourceRes? resource) {
final candidates = <String?>[
resource?.sourceResourceUrl,
resource?.previewUrl,
resource?.coverUrl,
resource?.cover,
];
return _firstNonBlankChatBubbleUrl([
...candidates.where((value) => SCNetworkSvgaWidget.isSvga(value)),
...candidates,
]);
}
String _firstNonBlankChatBubbleUrl(Iterable<String?> values) {
for (final value in values) {
final text = value?.trim();
if (text != null && text.isNotEmpty) {
return text;
}
}
return "";
}
class SCMessageChatPage extends StatefulWidget {
final V2TimConversation? conversation;
final bool shrinkWrap;
@ -144,8 +119,6 @@ class _SCMessageChatPageState extends State<SCMessageChatPage> {
///
bool canSendMsg = false;
SocialChatUserProfile? friend;
SCVipResourceRes? _selfVipChatBubble;
bool _isSelfVipChatBubbleLoading = false;
final Map<String, _CpInviteMessageState> _localCpInviteStates = {};
///
@ -196,7 +169,6 @@ class _SCMessageChatPageState extends State<SCMessageChatPage> {
rtmProvider?.onRevokeMessageListener = _onRevokeMessage;
rtmProvider?.onNewMessageCurrentConversationListener = _onNewMessage;
loadMsg();
_loadSelfVipChatBubble();
if (_isC2CConversation && friend == null) {
loadFriend();
@ -385,171 +357,6 @@ class _SCMessageChatPageState extends State<SCMessageChatPage> {
});
}
Future<void> _loadSelfVipChatBubble() async {
if (_isSelfVipChatBubbleLoading) return;
final currentUserId = AccountStorage().getCurrentUser()?.userProfile?.id;
if (currentUserId == null || currentUserId.isEmpty) return;
_isSelfVipChatBubbleLoading = true;
final repository = SCVipRepositoryImp();
SCVipHomeRes? vipHome;
SCVipResourceRes? chatBubble;
try {
final home = await repository.vipHome();
vipHome = home;
chatBubble = _resolveSelfVipChatBubbleFromHome(home);
} catch (error) {}
if (chatBubble == null) {
try {
final status = await repository.vipStatus();
chatBubble = _resolveSelfVipChatBubbleFromStatus(status);
if (chatBubble == null &&
vipHome != null &&
_isUsableVipStatus(status)) {
chatBubble = _firstUsableVipChatBubble([
_currentVipLevelConfig(
vipHome,
targetLevel: status.levelInt,
targetLevelCode: status.levelCode,
)?.chatBubble,
]);
}
} catch (error) {}
}
if (!mounted) return;
setState(() {
_selfVipChatBubble = chatBubble;
_isSelfVipChatBubbleLoading = false;
});
}
SCVipResourceRes? _resolveSelfVipChatBubbleFromHome(SCVipHomeRes home) {
final status = home.state;
if (status?.active == false) {
return null;
}
final config = _currentVipLevelConfig(home);
if (_isUsableVipStatus(status)) {
return _firstUsableVipChatBubble([
status?.chatBubble,
config?.chatBubble,
]);
}
final profileLevel =
AccountStorage().getCurrentUser()?.userProfile?.vipLevelForColoredId ??
0;
if (profileLevel > 0) {
return _firstUsableVipChatBubble([config?.chatBubble]);
}
return null;
}
SCVipResourceRes? _resolveSelfVipChatBubbleFromStatus(SCVipStatusRes status) {
if (!_isUsableVipStatus(status)) {
return null;
}
return _firstUsableVipChatBubble([status.chatBubble]);
}
SCVipLevelConfigRes? _currentVipLevelConfig(
SCVipHomeRes home, {
int? targetLevel,
String? targetLevelCode,
}) {
final status = home.state;
final statusLevel = _vipLevelIntFromStatus(status);
final profileLevel =
AccountStorage().getCurrentUser()?.userProfile?.vipLevelForColoredId ??
0;
final resolvedTargetLevel =
(targetLevel ?? 0) > 0
? targetLevel!
: (statusLevel > 0 ? statusLevel : profileLevel);
final statusLevelCode =
targetLevelCode?.trim() ?? status?.levelCode?.trim();
for (final level in home.levels) {
if (resolvedTargetLevel > 0 && level.levelInt == resolvedTargetLevel) {
return level;
}
}
if (statusLevelCode != null && statusLevelCode.isNotEmpty) {
for (final level in home.levels) {
if (_sameVipLevelCode(level.levelCode, statusLevelCode)) {
return level;
}
}
}
return null;
}
bool _isUsableVipStatus(SCVipStatusRes? status) {
return status != null &&
status.active != false &&
(_vipLevelIntFromStatus(status) > 0 ||
_hasNonBlankText(status.levelCode) ||
_hasNonBlankText(status.displayName) ||
_resolveVipChatBubbleImageUrl(status.chatBubble).isNotEmpty);
}
int _vipLevelIntFromStatus(SCVipStatusRes? status) {
final explicitLevel = status?.levelInt ?? 0;
if (explicitLevel > 0) {
return explicitLevel;
}
return _parseVipLevelText(status?.levelCode) ??
_parseVipLevelText(status?.displayName) ??
0;
}
int? _parseVipLevelText(String? value) {
final text = value?.trim();
if (text == null || text.isEmpty) {
return null;
}
final match = RegExp(
r'(?:S?VIP)?\s*([1-9]\d*)',
caseSensitive: false,
).firstMatch(text);
return int.tryParse(match?.group(1) ?? '');
}
bool _sameVipLevelCode(String? left, String? right) {
final normalizedLeft = left?.replaceAll(RegExp(r'\s+'), '').toLowerCase();
final normalizedRight = right?.replaceAll(RegExp(r'\s+'), '').toLowerCase();
return normalizedLeft != null &&
normalizedLeft.isNotEmpty &&
normalizedLeft == normalizedRight;
}
bool _hasNonBlankText(String? value) {
return value?.trim().isNotEmpty ?? false;
}
SCVipResourceRes? _firstUsableVipChatBubble(
Iterable<SCVipResourceRes?> resources,
) {
for (final resource in resources) {
if (_resolveVipChatBubbleImageUrl(resource).isNotEmpty) {
return resource;
}
}
return null;
}
String _vipChatBubbleLogValue(SCVipResourceRes? resource) {
if (resource == null) return 'null';
return '{id:${resource.resourceId},name:${resource.name},'
'previewUrl:${resource.previewUrl},'
'sourceUrl:${resource.sourceResourceUrl},'
'selectedUrl:${_resolveVipChatBubbleImageUrl(resource)}}';
}
///
Widget _msgList() {
return SmartRefresher(
@ -595,7 +402,6 @@ class _SCMessageChatPageState extends State<SCMessageChatPage> {
delegate: SliverChildBuilderDelegate(
(c, i) => _MessageItem(
message: currentConversationMessageList[i],
selfVipChatBubble: _selfVipChatBubble,
currentConversation: currentConversation,
preMessage:
i > 0 ? currentConversationMessageList[i - 1] : null,
@ -1182,7 +988,6 @@ class _MessageItem extends StatelessWidget {
final V2TimMessage message;
final V2TimMessage? preMessage;
final SCVipResourceRes? selfVipChatBubble;
final V2TimConversation? currentConversation;
BusinessLogicStrategy get _strategy => SCGlobalConfig.businessLogicStrategy;
@ -1201,7 +1006,6 @@ class _MessageItem extends StatelessWidget {
_MessageItem({
required this.message,
this.selfVipChatBubble,
this.currentConversation,
this.preMessage,
// this.userProfile,
@ -2827,24 +2631,18 @@ class _MessageItem extends StatelessWidget {
if (chatBubbleUrl.isNotEmpty) {
return _buildVipTextBubble(content: content, imageUrl: chatBubbleUrl);
}
if (message.isSelf ?? false) {
final vipChatBubbleUrl = _resolveVipChatBubbleImageUrl(selfVipChatBubble);
if (vipChatBubbleUrl.isNotEmpty) {
return _buildVipTextBubble(
content: content,
imageUrl: vipChatBubbleUrl,
);
}
}
return _buildDefaultTextBubble(content);
}
PropsResources? _currentUserChatBubble() {
final memoryBubble =
AccountStorage().getCurrentUser()?.userProfile?.getChatBox();
final currentUser = AccountStorage().getCurrentUser();
final memoryBubble = currentUser?.userProfile?.getChatBox();
if (_resolveChatBubbleImageUrl(memoryBubble).isNotEmpty) {
return memoryBubble;
}
if (currentUser?.userProfile != null) {
return memoryBubble;
}
final userJson = DataPersistence.getCurrentUser();
if (userJson.isEmpty) {

View File

@ -1900,16 +1900,6 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
'animationCount=$animationCount',
);
SCGiftVapSvgaManager().play(gift.giftSourceUrl!);
} else if (!_isCpGift(gift) &&
SCGlobalConfig.isLowPerformanceDevice &&
SCGlobalConfig.isGiftSpecialEffects &&
(rtcProvider?.shouldShowRoomVisualEffects ?? false)) {
_enqueueLowPerformanceGiftCompensation(
gift: gift,
receiver: u.user,
quantity: quantity,
coins: coins,
);
} else {
_giftFxLog(
'skip local play because visual effects disabled '
@ -1936,52 +1926,10 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
}
}
void _enqueueLowPerformanceGiftCompensation({
required SocialChatGiftRes gift,
required SocialChatUserProfile? receiver,
required int quantity,
required num coins,
}) {
final sender = AccountStorage().getCurrentUser()?.userProfile;
final roomId = rtcProvider?.currenRoom?.roomProfile?.roomProfile?.id ?? "";
_enqueueGiftFloatingMessage(
SCFloatingMessage(
type: 1,
priority: 900,
userId: sender?.id ?? "",
toUserId: receiver?.id ?? "",
userAvatarUrl: sender?.userAvatar ?? "",
toUserAvatarUrl: receiver?.userAvatar ?? "",
userName: sender?.userNickname ?? "",
toUserName: receiver?.userNickname ?? "",
giftUrl: gift.giftPhoto ?? "",
giftId: gift.id,
giftTab: _floatingGiftTabFor(gift),
number: quantity,
coins: coins,
roomId: roomId,
),
dedupKey: _giftFloatingDedupKey(
roomId: roomId,
senderId: sender?.id,
receiverId: receiver?.id,
giftId: gift.id,
quantity: quantity,
),
);
}
void _enqueueGiftFloatingMessage(
SCFloatingMessage message, {
String? dedupKey,
}) {
if (SCGlobalConfig.isLowPerformanceDevice) {
OverlayManager().addLowPerformanceCompensationMessage(
message,
dedupKey: dedupKey,
);
return;
}
OverlayManager().addMessage(message);
}

View File

@ -6,24 +6,24 @@ class BaishunLoadingView extends StatelessWidget {
const BaishunLoadingView({
super.key,
this.message = 'Loading game...',
this.backgroundColor = const Color(0xFF081915),
});
final String message;
final Color backgroundColor;
@override
Widget build(BuildContext context) {
return Positioned.fill(
child: Container(
color: Colors.black.withValues(alpha: 0.42),
color: backgroundColor,
alignment: Alignment.center,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 22.w, vertical: 18.w),
decoration: BoxDecoration(
color: const Color(0xFF102D28).withValues(alpha: 0.92),
borderRadius: BorderRadius.circular(16.w),
border: Border.all(
color: Colors.white.withValues(alpha: 0.1),
),
border: Border.all(color: Colors.white.withValues(alpha: 0.1)),
),
child: Column(
mainAxisSize: MainAxisSize.min,

View File

@ -295,6 +295,9 @@ class _BagsChatboxPageState
res.propsResources?.id ?? "",
unload,
);
try {
await profileManager.fetchUserProfileData(loadGuardCount: false);
} catch (_) {}
if (!mounted) {
return false;
}
@ -305,8 +308,11 @@ class _BagsChatboxPageState
myChatbox = null;
SCTts.show(localizations.successfullyUnloaded);
}
profileManager.syncCurrentUserChatBubble(
unload ? null : res.propsResources,
expireTime: res.expireTime?.toString(),
);
setState(() {});
profileManager.fetchUserProfileData(loadGuardCount: false);
return true;
} catch (e) {
return false;

View File

@ -13,8 +13,6 @@ import 'package:yumi/shared/tools/sc_room_utils.dart';
import 'package:yumi/shared/tools/sc_room_top_layer_guard.dart';
import 'package:yumi/shared/tools/sc_cp_relation_notice_utils.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/sources/local/floating_screen_manager.dart';
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
import 'package:yumi/shared/data_sources/sources/repositories/sc_room_repository_imp.dart';
import 'package:yumi/shared/data_sources/sources/repositories/sc_vip_repository_imp.dart';
@ -3864,46 +3862,6 @@ class RealTimeCommunicationManager extends ChangeNotifier {
return "";
}
String _resolveEntryCompensationCover(PropsResources? resource) {
return _firstNonBlankEntryResource([
resource?.roomSendCoverUrl,
resource?.roomOpenedUrl,
resource?.cover,
resource?.roomNotOpenedUrl,
]);
}
void _enqueueLowPerformanceEntryCompensation({
required Msg joinMsg,
required PropsResources resource,
required String roomId,
}) {
if (!SCGlobalConfig.isLowPerformanceDevice ||
!shouldShowRoomVisualEffects ||
roomId.isEmpty) {
return;
}
final coverUrl = _resolveEntryCompensationCover(resource);
OverlayManager().addLowPerformanceCompensationMessage(
SCFloatingMessage(
type: 5,
priority: 950,
userId: joinMsg.user?.id ?? "",
roomId: roomId,
userAvatarUrl: joinMsg.user?.userAvatar ?? "",
userName: joinMsg.user?.userNickname ?? "",
giftUrl: coverUrl,
fallbackUrl: coverUrl,
),
dedupKey: [
"entry",
roomId,
joinMsg.user?.id ?? "",
resource.id ?? "",
].join("|"),
);
}
void _playRoomEntryEffects(
Msg joinMsg, {
required int entryRequestSerial,
@ -3931,24 +3889,6 @@ class RealTimeCommunicationManager extends ChangeNotifier {
type: SCGiftVapSvgaManager.entryEffectType,
);
});
} else if (sourceUrl.isNotEmpty &&
SCGlobalConfig.isLowPerformanceDevice &&
SCGlobalConfig.isEntryVehicleAnimation &&
shouldShowRoomVisualEffects &&
_isCurrentRoomEntrySession(entryRequestSerial, roomId)) {
_roomEntryEffectTimer?.cancel();
_roomEntryEffectTimer = Timer(const Duration(milliseconds: 550), () {
_roomEntryEffectTimer = null;
if (!shouldShowRoomVisualEffects ||
!_isCurrentRoomEntrySession(entryRequestSerial, roomId)) {
return;
}
_enqueueLowPerformanceEntryCompensation(
joinMsg: joinMsg,
resource: entryResource,
roomId: roomId,
);
});
}
}
if (rtmProvider?.msgUserJoinListener != null) {
@ -5296,11 +5236,10 @@ class RealTimeCommunicationManager extends ChangeNotifier {
);
final targetIndex = micGoUpRes.micIndex ?? index;
final selfMicMuted = micGoUpRes.micMute ?? false;
final switched = await _switchRoomRtcToBroadcaster(
muted: (micGoUpRes.micMute ?? false) || isMic,
keepAudioPublishing:
((micGoUpRes.micMute ?? false) || isMic) &&
_currentUserPublishingRoomMusic,
muted: selfMicMuted,
keepAudioPublishing: selfMicMuted && _currentUserPublishingRoomMusic,
);
if (!switched) {
await _switchRoomRtcToAudience();
@ -5356,6 +5295,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
roomToken: micGoUpRes.roomToken,
);
}
isMic = selfMicMuted;
_syncSelfMicRuntimeState();
if (roomWheatMap[targetIndex]?.micMute ?? false) {
///

View File

@ -256,13 +256,6 @@ class RealTimeMessagingManager extends ChangeNotifier {
SCFloatingMessage message, {
String? dedupKey,
}) {
if (SCGlobalConfig.isLowPerformanceDevice) {
OverlayManager().addLowPerformanceCompensationMessage(
message,
dedupKey: dedupKey,
);
return;
}
OverlayManager().addMessage(message);
}
@ -283,23 +276,6 @@ class RealTimeMessagingManager extends ChangeNotifier {
].join("|");
}
String _entryFloatingDedupKey({
required String? roomId,
required String? userId,
required String? resourceId,
}) {
return ["entry", roomId ?? "", userId ?? "", resourceId ?? ""].join("|");
}
String _resolveEntryCompensationCover(PropsResources? resource) {
return _firstNonBlank([
resource?.roomSendCoverUrl,
resource?.roomOpenedUrl,
resource?.cover,
resource?.roomNotOpenedUrl,
]);
}
String _firstNonBlank(Iterable<String?> values) {
for (final value in values) {
final text = value?.trim();
@ -6387,29 +6363,6 @@ class RealTimeMessagingManager extends ChangeNotifier {
priority: SCGiftVapSvgaManager.entryEffectPriority,
type: SCGiftVapSvgaManager.entryEffectType,
);
} else if (SCGlobalConfig.isLowPerformanceDevice &&
SCGlobalConfig.isEntryVehicleAnimation &&
shouldShowRoomVisualEffects) {
final roomId =
rtcProvider.currenRoom?.roomProfile?.roomProfile?.id ?? "";
final coverUrl = _resolveEntryCompensationCover(entryResource);
OverlayManager().addLowPerformanceCompensationMessage(
SCFloatingMessage(
type: 5,
priority: 950,
userId: msg.user?.id ?? "",
roomId: roomId,
userAvatarUrl: msg.user?.userAvatar ?? "",
userName: msg.user?.userNickname ?? "",
giftUrl: coverUrl,
fallbackUrl: coverUrl,
),
dedupKey: _entryFloatingDedupKey(
roomId: roomId,
userId: msg.user?.id,
resourceId: entryResource.id,
),
);
}
}
} else if (msg.type == SCRoomMsgType.gift) {
@ -6460,46 +6413,6 @@ class RealTimeMessagingManager extends ChangeNotifier {
'giftId=${gift.id} giftName=${gift.giftName}',
);
SCGiftVapSvgaManager().play(giftSourceUrl);
} else if (!scIsCpGift(gift) &&
SCGlobalConfig.isLowPerformanceDevice &&
SCGlobalConfig.isGiftSpecialEffects &&
rtcProvider.shouldShowRoomVisualEffects) {
final roomId =
(msg.msg?.trim().isNotEmpty ?? false)
? msg.msg ?? ""
: rtcProvider
.currenRoom
?.roomProfile
?.roomProfile
?.id ??
"";
final quantity = msg.number ?? 0;
final coins = quantity * (gift.giftCandy ?? 0);
_enqueueGiftFloatingMessage(
SCFloatingMessage(
type: 1,
priority: 900,
userId: msg.user?.id ?? "",
toUserId: msg.toUser?.id ?? "",
userAvatarUrl: msg.user?.userAvatar ?? "",
userName: msg.user?.userNickname ?? "",
toUserName: msg.toUser?.userNickname ?? "",
toUserAvatarUrl: msg.toUser?.userAvatar ?? "",
giftUrl: gift.giftPhoto,
giftId: gift.id,
giftTab: _floatingGiftTabFor(gift),
number: quantity,
coins: coins,
roomId: roomId,
),
dedupKey: _giftFloatingDedupKey(
roomId: roomId,
senderId: msg.user?.id,
receiverId: msg.toUser?.id,
giftId: gift.id,
quantity: quantity,
),
);
} else {
_giftFxLog(
'skip player play because visual effects disabled '

View File

@ -14,6 +14,7 @@ import 'package:yumi/shared/business_logic/models/res/login_res.dart';
import 'package:yumi/shared/business_logic/models/res/room_user_card_res.dart';
import 'package:yumi/shared/business_logic/models/res/sc_user_identity_res.dart';
import 'package:yumi/shared/business_logic/models/res/sc_vip_res.dart';
import 'package:yumi/shared/data_sources/models/enum/sc_props_type.dart';
import 'package:yumi/shared/tools/sc_cp_relation_level_utils.dart';
import 'package:yumi/shared/tools/sc_cp_relation_notice_utils.dart';
@ -92,6 +93,32 @@ class SocialChatUserProfileManager extends ChangeNotifier {
notifyListeners();
}
void syncCurrentUserChatBubble(
PropsResources? chatBubble, {
String? expireTime,
}) {
final profile = currentUserProfile;
if (profile == null) {
return;
}
final useProps = <UseProps>[
...?profile.useProps?.where(
(item) => item.propsResources?.type != SCPropsType.CHAT_BUBBLE.name,
),
];
if (chatBubble != null) {
useProps.add(
UseProps(
expireTime: expireTime ?? "4102444800000",
propsResources: chatBubble,
userId: profile.id,
),
);
}
syncCurrentUserProfile(profile.copyWith(useProps: useProps));
}
Future fetchUserProfileData({
bool loadGuardCount = true,
bool refreshFamilyData = false,

View File

@ -26,9 +26,7 @@ import 'package:yumi/ui_kit/widgets/svga/sc_svga_asset_widget.dart';
typedef FloatingScreenManager = OverlayManager;
class OverlayManager {
static const int _maxLowPerformanceCompensationQueueLength = 8;
static const int _maxDeferredRegionRedPacketCount = 12;
static const Duration _compensationDedupWindow = Duration(seconds: 3);
static const Duration _redPacketFloatingDedupWindow = Duration(minutes: 30);
static const Duration _rocketFloatingFallbackDedupWindow = Duration(
seconds: 30,
@ -43,7 +41,6 @@ class OverlayManager {
(a, b) => b.priority.compareTo(a.priority),
);
final List<SCFloatingMessage> _deferredRegionRedPacketMessages = [];
final Map<String, DateTime> _recentCompensationKeys = {};
final Map<String, DateTime> _recentFloatingKeys = {};
final Map<int, OverlayEntry> _stackedOverlayEntries = {};
final Map<int, SCFloatingMessage> _stackedMessages = {};
@ -84,28 +81,6 @@ class OverlayManager {
}
}
void addLowPerformanceCompensationMessage(
SCFloatingMessage message, {
String? dedupKey,
}) {
if (_isDisposed ||
_isSuppressed ||
!SCGlobalConfig.isLowPerformanceDevice ||
SCGlobalConfig.isFloatingBroadcastClosed) {
return;
}
final key = dedupKey ?? _compensationKeyFor(message);
if (_isRecentCompensationDuplicate(key)) {
return;
}
_rememberCompensationKey(key);
_trimLowPerformanceCompensationQueue();
_enqueueMessage(
message,
debugLabel: 'low_performance_compensation_${message.type ?? -1}',
);
}
void _enqueueMessage(
SCFloatingMessage message, {
required String debugLabel,
@ -123,27 +98,6 @@ class OverlayManager {
);
}
bool _isRecentCompensationDuplicate(String key) {
_pruneRecentCompensationKeys();
final recentTime = _recentCompensationKeys[key];
if (recentTime == null) {
return false;
}
return DateTime.now().difference(recentTime) < _compensationDedupWindow;
}
void _rememberCompensationKey(String key) {
_recentCompensationKeys[key] = DateTime.now();
_pruneRecentCompensationKeys();
}
void _pruneRecentCompensationKeys() {
final now = DateTime.now();
_recentCompensationKeys.removeWhere(
(_, time) => now.difference(time) > _compensationDedupWindow,
);
}
bool _isRecentFloatingDuplicate(SCFloatingMessage message) {
_pruneRecentFloatingKeys();
final key = _floatingDedupKeyFor(message);
@ -261,33 +215,6 @@ class OverlayManager {
return _redPacketFloatingDedupWindow;
}
String _compensationKeyFor(SCFloatingMessage message) {
return [
message.type,
message.roomId,
message.userId,
message.toUserId,
message.giftId,
message.number,
message.giftUrl,
].join('|');
}
void _trimLowPerformanceCompensationQueue() {
if (_messageQueue.length < _maxLowPerformanceCompensationQueueLength) {
return;
}
final retained =
_messageQueue.unorderedElements.cast<SCFloatingMessage>().toList()
..sort((a, b) => b.priority.compareTo(a.priority));
_messageQueue.clear();
for (final message in retained.take(
_maxLowPerformanceCompensationQueueLength - 1,
)) {
_messageQueue.add(message);
}
}
Future<void> _warmMessageImages(SCFloatingMessage message) async {
unawaited(
warmImageResource(
@ -671,7 +598,7 @@ class OverlayManager {
SCGlobalConfig.floatingBroadcastScope = scope;
return;
}
final defaultEffectsEnabled = !SCGlobalConfig.isLowPerformanceDevice;
const defaultEffectsEnabled = true;
final isLegacyFloatingAnimationInGlobal = DataPersistence.getBool(
SCGlobalConfig.legacyFloatingAnimationInGlobalStorageKey(account),
defaultValue: defaultEffectsEnabled,
@ -752,7 +679,6 @@ class OverlayManager {
_removeAllStackedMessages();
_messageQueue.clear();
_deferredRegionRedPacketMessages.clear();
_recentCompensationKeys.clear();
_isPlaying = false;
_isProcessing = false;
}

View File

@ -1,14 +1,20 @@
import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:yumi/shared/data_sources/sources/local/data_persistence.dart';
class SCLuckyGiftWinSoundPlayer {
static const String assetPath =
"sc_images/room/anim/luck_gift/lucky_gift_win.mp3";
static const Duration _sameEventDedupeWindow = Duration(seconds: 3);
static const Duration _stopDelay = Duration(milliseconds: 3200);
static const double _volume = 0.75;
static final AudioPlayer _player = AudioPlayer();
static String? _lastEventKey;
static DateTime? _lastPlayedAt;
static bool _loaded = false;
static bool _playing = false;
static Future<void>? _loadFuture;
static Future<void>? _startFuture;
static Timer? _stopTimer;
static String buildEventKey({
String? giftId,
@ -26,25 +32,75 @@ class SCLuckyGiftWinSoundPlayer {
static Future<void> play({String? eventKey}) async {
if (DataPersistence.getPlayGiftMusic()) {
unawaited(stop());
return;
}
final normalizedEventKey = (eventKey ?? '').trim();
final now = DateTime.now();
final lastPlayedAt = _lastPlayedAt;
if (normalizedEventKey.isNotEmpty &&
normalizedEventKey == _lastEventKey &&
lastPlayedAt != null &&
now.difference(lastPlayedAt) < _sameEventDedupeWindow) {
return;
}
_lastEventKey = normalizedEventKey.isEmpty ? null : normalizedEventKey;
_lastPlayedAt = now;
try {
await _player.stop();
await _player.play(AssetSource(assetPath));
} catch (error) {}
await _ensureLoaded();
_extendStopWindow();
if (_playing || _startFuture != null) {
return;
}
_startFuture = _startPlayback();
await _startFuture;
} catch (error) {
_startFuture = null;
}
_startFuture = null;
}
static Future<void> stop() async {
_stopTimer?.cancel();
_stopTimer = null;
try {
if (_player.state != PlayerState.stopped) {
await _player.stop();
}
} catch (error) {
_playing = false;
return;
}
_playing = false;
}
static Future<void> _ensureLoaded() {
if (_loaded) {
return Future<void>.value();
}
final loadFuture = _loadFuture;
if (loadFuture != null) {
return loadFuture;
}
_loadFuture = _load();
return _loadFuture!;
}
static Future<void> _load() async {
try {
await _player.setReleaseMode(ReleaseMode.loop);
await _player.setVolume(_volume);
await _player.setSource(AssetSource(assetPath));
_loaded = true;
} catch (error) {
_loadFuture = null;
rethrow;
}
}
static Future<void> _startPlayback() async {
await _player.seek(Duration.zero);
await _player.resume();
_playing = true;
}
static void _extendStopWindow() {
_stopTimer?.cancel();
_stopTimer = Timer(_stopDelay, () {
unawaited(stop());
});
}
static String _formatNum(num? value) {

View File

@ -288,7 +288,7 @@ class SCChatRoomHelper {
}
static void roomSCGlobalConfig(String roomId) {
final defaultEffectsEnabled = !SCGlobalConfig.isLowPerformanceDevice;
const defaultEffectsEnabled = true;
final account = AccountStorage().getCurrentUser()?.userProfile?.account;
SCGlobalConfig
.isGiftSpecialEffects = SCGlobalConfig.clampVisualEffectPreference(

View File

@ -1,5 +1,3 @@
import 'package:extended_image/extended_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_debouncer/flutter_debouncer.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -70,7 +68,11 @@ class _PropsBagChatboxDetailDialogState
],
),
SizedBox(height: 25.w),
netImage(url: widget.res.propsResources?.cover??"",width: 80.w,height: 25.w),
netImage(
url: widget.res.propsResources?.cover ?? "",
width: 80.w,
height: 25.w,
),
SizedBox(height: 30.w),
GestureDetector(
child: Container(
@ -136,6 +138,11 @@ class _PropsBagChatboxDetailDialogState
}
void _use(BagsListRes res, bool unload) {
final localizations = SCAppLocalizations.of(context)!;
final profileManager = Provider.of<SocialChatUserProfileManager>(
context,
listen: false,
);
SCLoadingManager.show();
SCStoreRepositoryImp()
.switchPropsUse(
@ -144,18 +151,25 @@ class _PropsBagChatboxDetailDialogState
unload,
)
.then((value) async {
await Provider.of<SocialChatUserProfileManager>(
context,
listen: false,
).fetchUserProfileData(loadGuardCount: false);
try {
await profileManager.fetchUserProfileData(loadGuardCount: false);
} catch (_) {}
if (!mounted) {
SCLoadingManager.hide();
return;
}
profileManager.syncCurrentUserChatBubble(
unload ? null : res.propsResources,
expireTime: res.expireTime?.toString(),
);
Future.delayed(Duration(milliseconds: 400), () {
SCLoadingManager.hide();
SmartDialog.dismiss(tag: "showPropsDetail");
});
if (!unload) {
SCTts.show(SCAppLocalizations.of(context)!.successfulWear);
SCTts.show(localizations.successfulWear);
} else {
SCTts.show(SCAppLocalizations.of(context)!.successfullyUnloaded);
SCTts.show(localizations.successfullyUnloaded);
}
})
.catchError((e) {

View File

@ -65,10 +65,6 @@ class _RoomAnimationQueueScreenState extends State<RoomAnimationQueueScreen> {
}
void _enqueueVipEntryFloatingMessage(Msg msg) {
if (SCGlobalConfig.isLowPerformanceDevice &&
((msg.user?.getMountains()?.sourceUrl ?? "").trim().isNotEmpty)) {
return;
}
final floatPicture = msg.user?.getFloatPicture();
final floatPictureUrl = _resolveVipFloatPictureUrl(floatPicture);
final floatPictureFallbackUrl = _resolveVipFloatPictureFallbackUrl(
@ -86,33 +82,16 @@ class _RoomAnimationQueueScreenState extends State<RoomAnimationQueueScreen> {
if (roomId.isEmpty) {
return;
}
final isLowPerformance = SCGlobalConfig.isLowPerformanceDevice;
final displayUrl =
isLowPerformance && floatPictureFallbackUrl.isNotEmpty
? floatPictureFallbackUrl
: floatPictureUrl;
final floatingMessage = SCFloatingMessage(
type: 5,
userId: msg.user?.id,
roomId: roomId,
userAvatarUrl: msg.user?.userAvatar,
userName: msg.user?.userNickname,
giftUrl: displayUrl,
giftUrl: floatPictureUrl,
fallbackUrl: floatPictureFallbackUrl,
priority: 900,
);
if (isLowPerformance) {
OverlayManager().addLowPerformanceCompensationMessage(
floatingMessage,
dedupKey: [
"entry_float",
roomId,
msg.user?.id ?? "",
floatPicture?.id ?? "",
].join("|"),
);
return;
}
OverlayManager().addMessage(floatingMessage);
}