diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 420d4b1..a4235a5 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -502,7 +502,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 35; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = S9X2AJ2US9; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -511,7 +511,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -693,7 +693,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 35; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = F33K8VUZ62; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -702,7 +702,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -722,7 +722,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 35; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = F33K8VUZ62; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -731,7 +731,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/lib/services/audio/rtm_manager.dart b/lib/services/audio/rtm_manager.dart index fdcece2..d2acb25 100644 --- a/lib/services/audio/rtm_manager.dart +++ b/lib/services/audio/rtm_manager.dart @@ -76,6 +76,7 @@ class RealTimeMessagingManager extends ChangeNotifier { static const int _luckyGiftFloatMinMultiple = 5; static const int _luckyGiftBurstMinMultiple = 10; static const int _luckyGiftBurstMinAwardAmount = 5000; + static const int _luckyGiftBurstDisplayDurationMs = 2000; BuildContext? context; @@ -1019,6 +1020,7 @@ class RealTimeMessagingManager extends ChangeNotifier { userName: rewardData?.nickname, toUserName: rewardData?.acceptNickname, giftUrl: rewardData?.giftCover, + giftId: rewardData?.giftId, number: rewardData?.giftQuantity, coins: rewardData?.awardAmount, multiple: rewardData?.multiple, @@ -1765,12 +1767,15 @@ class RealTimeMessagingManager extends ChangeNotifier { ? null : _luckyGiftPushEventKey(currentPlayingLuckGift!); notifyListeners(); - Future.delayed(Duration(milliseconds: 3000), () { - currentPlayingLuckGift = null; - _currentLuckGiftPushKey = null; - notifyListeners(); - playLuckGiftBackCoins(); - }); + Future.delayed( + Duration(milliseconds: _luckyGiftBurstDisplayDurationMs), + () { + currentPlayingLuckGift = null; + _currentLuckGiftPushKey = null; + notifyListeners(); + playLuckGiftBackCoins(); + }, + ); } String _luckyGiftPushEventKey(SCBroadCastLuckGiftPush broadCastRes) { diff --git a/lib/shared/data_sources/models/message/sc_floating_message.dart b/lib/shared/data_sources/models/message/sc_floating_message.dart index fa89e5d..9c1e63f 100644 --- a/lib/shared/data_sources/models/message/sc_floating_message.dart +++ b/lib/shared/data_sources/models/message/sc_floating_message.dart @@ -7,6 +7,7 @@ class SCFloatingMessage { String? userName; // 用户昵称 String? toUserName; // 用户昵称 String? giftUrl; // 礼物图标 + String? giftId; // 礼物id int? type; int? rocketLevel; num? coins; @@ -25,6 +26,7 @@ class SCFloatingMessage { this.userName = '', this.toUserName = '', this.giftUrl = '', + this.giftId = '', this.number = 0, this.coins = 0, this.priority = 10, @@ -42,6 +44,7 @@ class SCFloatingMessage { userName = json['userName']; toUserName = json['toUserName']; giftUrl = json['giftUrl']; + giftId = json['giftId']; coins = json['coins']; number = json['number']; priority = json['priority']; @@ -60,6 +63,7 @@ class SCFloatingMessage { map['userName'] = userName; map['toUserName'] = toUserName; map['giftUrl'] = giftUrl; + map['giftId'] = giftId; map['coins'] = coins; map['number'] = number; map['priority'] = priority; diff --git a/lib/ui_kit/widgets/room/effect/luck_gift_nomor_anim_widget.dart b/lib/ui_kit/widgets/room/effect/luck_gift_nomor_anim_widget.dart index d1a311e..d0120ac 100644 --- a/lib/ui_kit/widgets/room/effect/luck_gift_nomor_anim_widget.dart +++ b/lib/ui_kit/widgets/room/effect/luck_gift_nomor_anim_widget.dart @@ -98,7 +98,7 @@ class _LuckGiftNomorAnimWidgetState extends State { child: Align( alignment: const Alignment(0, 0.12), child: Transform.translate( - offset: Offset(0, 0), + offset: Offset(5.w, -4.w), child: ConstrainedBox( constraints: BoxConstraints( maxWidth: ScreenUtil().screenWidth * 0.56, @@ -106,7 +106,7 @@ class _LuckGiftNomorAnimWidgetState extends State { child: FittedBox( fit: BoxFit.scaleDown, child: Padding( - padding: EdgeInsets.only(left: 6.w, right: 2.w), + padding: EdgeInsets.only(left: 0.w, right: 0.w), child: Text( _formatAwardAmount(rewardData.awardAmount ?? 0), maxLines: 1, diff --git a/lib/ui_kit/widgets/room/floating/floating_luck_gift_screen_widget.dart b/lib/ui_kit/widgets/room/floating/floating_luck_gift_screen_widget.dart index 900fb41..d1af83c 100644 --- a/lib/ui_kit/widgets/room/floating/floating_luck_gift_screen_widget.dart +++ b/lib/ui_kit/widgets/room/floating/floating_luck_gift_screen_widget.dart @@ -1,9 +1,11 @@ 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/ui_kit/components/sc_compontent.dart'; import 'package:yumi/ui_kit/components/text/sc_text.dart'; import 'package:yumi/app/constants/sc_global_config.dart'; +import 'package:yumi/services/general/sc_app_general_manager.dart'; import 'package:yumi/shared/tools/sc_room_utils.dart'; import 'package:yumi/main.dart'; import 'package:marquee/marquee.dart'; @@ -294,11 +296,7 @@ class _FloatingLuckGiftScreenWidgetState TextSpan(text: "from ", style: baseStyle), WidgetSpan( alignment: PlaceholderAlignment.middle, - child: netImage( - url: widget.message.giftUrl ?? "", - width: 18.w, - height: 18.w, - ), + child: _buildGiftIcon(context), ), ], ), @@ -314,6 +312,57 @@ class _FloatingLuckGiftScreenWidgetState ); } + Widget _buildGiftIcon(BuildContext context) { + final primaryGiftUrl = (widget.message.giftUrl ?? "").trim(); + final fallbackGiftUrl = _resolveFallbackGiftUrl(context); + final displayGiftUrl = + primaryGiftUrl.isNotEmpty ? primaryGiftUrl : fallbackGiftUrl; + if (displayGiftUrl.isEmpty) { + return _buildGiftIconPlaceholder(); + } + + final backupUrl = + fallbackGiftUrl.isNotEmpty && fallbackGiftUrl != displayGiftUrl + ? fallbackGiftUrl + : ""; + + return netImage( + url: displayGiftUrl, + width: 18.w, + height: 18.w, + borderRadius: BorderRadius.circular(3.w), + loadingWidget: _buildGiftIconPlaceholder(), + errorWidget: + backupUrl.isNotEmpty + ? netImage( + url: backupUrl, + width: 18.w, + height: 18.w, + borderRadius: BorderRadius.circular(3.w), + noDefaultImg: true, + loadingWidget: _buildGiftIconPlaceholder(), + errorWidget: _buildGiftIconPlaceholder(), + ) + : _buildGiftIconPlaceholder(), + ); + } + + String _resolveFallbackGiftUrl(BuildContext context) { + final giftId = (widget.message.giftId ?? "").trim(); + if (giftId.isEmpty) { + return ""; + } + final gift = Provider.of( + context, + listen: false, + ).getGiftById(giftId); + return (gift?.giftPhoto ?? "").trim(); + } + + Widget _buildGiftIconPlaceholder() { + return SizedBox(width: 18.w, height: 18.w); + } + String _formatCoins(num? coins) { final value = (coins ?? 0); if (value > 9999) { diff --git a/pubspec.yaml b/pubspec.yaml index 797ca6f..676a4da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 +version: 1.1.0+2 environment: diff --git a/需求进度.md b/需求进度.md index feedc42..a614092 100644 --- a/需求进度.md +++ b/需求进度.md @@ -41,6 +41,8 @@ - 已继续修正幸运礼物 `burst` 中央金额文案的细节对位:当前已再上移 `2` 个单位,并给金额文本左侧补出额外留白,避免斜体 `+` 号因为字形外扩而贴边或被裁掉,确保 `+金币` 能完整落在特效中部。 - 已继续按最新联调口径修正幸运礼物 `burst` 中央金额文案:当前已去掉文本里的 `+` 字符,仅保留金币数本身显示;同时维持上一版向上微调后的纵向位置,让金额落点保持在特效中部偏上的稳定区域。 - 已继续收口幸运礼物 `burst` 金额文案与 `svga` 本体的时机同步:此前中央金币文本直接跟外层中奖数据显隐,而 `svga` 自身还存在资源加载和单次播放完成的生命周期,所以两者在出现/消失时会有肉眼可见的前后差;当前已给 `SCSvgaAssetWidget` 补上播放开始/结束回调,并让 `burst` 中央金额只在 `svga` 真正开始播时显示、在它播完清帧时一并隐藏。 +- 已按 2026-04-21 最新联调继续细调幸运礼物 `burst` 中央金币文案:当前已在现有基础上再向上微调 `4` 个单位、向右微调 `5` 个单位,让金额更贴近特效中部的目标槽位;同时 `burst` 的整体展示时长也已再缩短 `1` 秒,避免命中后在屏上停留过久。 +- 已继续修复幸运礼物顶部横幅 `from` 后礼物图标偶发显示不出来的问题:此前这条紫色 lucky gift 横幅只直接使用 socket 下发的 `giftCover/giftUrl` 渲染礼物图,一旦服务端该字段为空或图片加载失败,就只会退回默认占位;当前已把 `giftId` 一并挂进 `SCFloatingMessage`,并在 `FloatingLuckGiftScreenWidget` 内增加“优先用 `giftUrl`,失败时再回退到本地礼物列表缓存中的 `giftPhoto`”的双重兜底,避免横幅末尾再出现空白占位块。 - 已优化语言房麦位/头像的二次确认交互:普通用户点击可上麦的空麦位时,当前会直接执行上麦,不再先弹出只有 `Take the mic / Cancel` 的确认层;普通用户点击房间头像或已占麦位上的用户头像时,也会直接打开个人卡片,不再额外弹出仅含 `Open user profile card / Cancel` 的底部确认。房主/管理员仍保留原有带禁麦、锁麦、邀请上麦等管理动作的底部菜单,避免误删管理能力。 - 已继续收窄语言房个人卡片前的“确认意义”弹层:当前用户在麦位上点击自己的头像时,也会直接打开自己的个人卡片,不再先弹出仅包含 `Leave the mic / Open user profile card / Cancel` 的底部菜单;同时个人卡片内的“离开麦位”入口已替换为新的 `leave` 视觉素材,和最新房间交互稿保持一致。 - 已继续微调语言房个人卡片与送礼 UI:个人卡片底部动作文案现已支持两行居中展示,避免 `Leave the mic` 这类英文按钮被硬截断;房间底部礼物入口也已切换为新的本地 `SVGA` 资源 `room_bottom_gift_button.svga`,保持房间底栏视觉和最新动效稿一致。