diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d03fab7..0b12671 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -510,7 +510,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; }; name = Profile; @@ -524,7 +524,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1631; + CURRENT_PROJECT_VERSION = 102; DEVELOPMENT_TEAM = S9YG87C297; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -533,7 +533,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.6.3; + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -647,7 +647,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; @@ -701,7 +701,7 @@ SUPPORTED_PLATFORMS = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; VALIDATE_PRODUCT = YES; }; name = Release; @@ -715,7 +715,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1631; + CURRENT_PROJECT_VERSION = 102; DEVELOPMENT_TEAM = S9YG87C297; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -724,7 +724,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.6.3; + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -744,7 +744,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1631; + CURRENT_PROJECT_VERSION = 102; DEVELOPMENT_TEAM = S9YG87C297; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -753,7 +753,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.6.3; + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 7a762e6..3d176d0 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -56,9 +56,9 @@ - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS NSCameraUsageDescription We need access to your camera so you can take a photo and make it a profile picture, or take and share a picture in real time in a voice chat room. diff --git a/lib/modules/room/online/room_online_page.dart b/lib/modules/room/online/room_online_page.dart index 0c989b6..af9b51d 100644 --- a/lib/modules/room/online/room_online_page.dart +++ b/lib/modules/room/online/room_online_page.dart @@ -13,7 +13,6 @@ import '../../../ui_kit/components/sc_page_list.dart'; import '../../../ui_kit/components/sc_tts.dart'; import '../../../ui_kit/components/text/sc_text.dart'; import '../../../ui_kit/widgets/id/sc_special_id_badge.dart'; -import '../../../shared/tools/sc_lk_dialog_util.dart'; import '../../../ui_kit/widgets/badge/sc_user_badge_strip.dart'; import '../../../ui_kit/widgets/room/room_user_info_card.dart'; @@ -44,7 +43,7 @@ class _RoomOnlinePageState if (dialogContext == null) { return; } - showBottomInBottomDialog(dialogContext, RoomUserInfoCard(userId: userId)); + RoomUserInfoCard.showPreloaded(dialogContext, userId: userId); }); } diff --git a/lib/modules/room/rank/room_gift_rank_tab_page.dart b/lib/modules/room/rank/room_gift_rank_tab_page.dart index 36e9f2a..49a644c 100644 --- a/lib/modules/room/rank/room_gift_rank_tab_page.dart +++ b/lib/modules/room/rank/room_gift_rank_tab_page.dart @@ -1,11 +1,11 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:yumi/shared/business_logic/models/res/login_res.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:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:yumi/shared/business_logic/models/res/login_res.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/main.dart'; import 'package:yumi/app_localizations.dart'; @@ -13,7 +13,6 @@ import 'package:yumi/ui_kit/components/sc_compontent.dart'; import 'package:yumi/ui_kit/components/sc_page_list.dart'; import 'package:yumi/ui_kit/components/text/sc_text.dart'; import 'package:yumi/ui_kit/components/sc_tts.dart'; -import 'package:yumi/shared/tools/sc_lk_dialog_util.dart'; import 'package:yumi/shared/business_logic/models/res/room_gift_rank_res.dart'; import 'package:yumi/ui_kit/widgets/id/sc_special_id_badge.dart'; import 'package:yumi/ui_kit/widgets/room/room_user_info_card.dart'; @@ -98,11 +97,11 @@ class _RoomGiftRankTabPageState // headdress: userInfo.userProfile?.getHeaddress()?.sourceUrl, ), onTap: () { - showBottomInBottomDialog( - navigatorKey.currentState!.context, - RoomUserInfoCard(userId: userProfile?.id), - ); SmartDialog.dismiss(tag: "showRoomGiftRankPage"); + RoomUserInfoCard.showPreloaded( + navigatorKey.currentState!.context, + userId: userProfile?.id, + ); }, ), SizedBox(width: 3.w), @@ -119,7 +118,7 @@ class _RoomGiftRankTabPageState needScroll: (userProfile?.userNickname?.characters.length ?? 0) > - 14, + 14, ), ], ), @@ -137,7 +136,7 @@ class _RoomGiftRankTabPageState animationHeight: 24.w, showTextBesideAnimated: true, animatedTextSpacing: 0, - showAnimatedGradientText: + showAnimatedGradientText: userProfile ?.shouldShowColoredSpecialIdText() ?? false, @@ -195,24 +194,24 @@ class _RoomGiftRankTabPageState SocialChatUserProfile? _mergeCurrentUserVip( SocialChatUserProfile? profile, ) { - if (profile == null || profile.vipLevelForColoredId > 0) { - return profile; - } - final currentProfile = AccountStorage().getCurrentUser()?.userProfile; - if (currentProfile == null || - currentProfile.vipLevelForColoredId <= 0 || - currentProfile.id != profile.id) { - return profile; - } - return profile.copyWith( - vipLevel: - currentProfile.vipLevel ?? - currentProfile.vipLevelForColoredId.toString(), - ); - } - - @override - empty() { + if (profile == null || profile.vipLevelForColoredId > 0) { + return profile; + } + final currentProfile = AccountStorage().getCurrentUser()?.userProfile; + if (currentProfile == null || + currentProfile.vipLevelForColoredId <= 0 || + currentProfile.id != profile.id) { + return profile; + } + return profile.copyWith( + vipLevel: + currentProfile.vipLevel ?? + currentProfile.vipLevelForColoredId.toString(), + ); + } + + @override + empty() { return mainEmpty( image: Image.asset( 'sc_images/general/sc_icon_loading.png', diff --git a/lib/modules/user/me_page2.dart b/lib/modules/user/me_page2.dart index a9b42e2..795d265 100644 --- a/lib/modules/user/me_page2.dart +++ b/lib/modules/user/me_page2.dart @@ -37,6 +37,8 @@ class MePage2 extends StatefulWidget { class _MePage2State extends State with WidgetsBindingObserver { static const Duration _counterStaleDuration = Duration(seconds: 30); + static const String _cpActivityUrl = + 'https://h5.global-interaction.com/activity/cp-space/yumi.html'; static const String _inviteActivityUrl = 'https://h5.haiyihy.com/app-invite/index.html'; static const double _inviteActivityHorizontalScale = 750 / 662; @@ -299,6 +301,21 @@ class _MePage2State extends State with WidgetsBindingObserver { ); } + void _openCpActivity() { + final cpActivityUrl = _cpActivityUrl.trim(); + if (cpActivityUrl.isEmpty) { + if (kDebugMode) { + debugPrint('[MePage2] cp activity url is empty'); + } + return; + } + + SCNavigatorUtils.push( + context, + "${SCMainRoute.webViewPage}?url=${Uri.encodeComponent(cpActivityUrl)}&showTitle=false", + ); + } + String _appendToken(String url) { final token = AccountStorage().getToken(); if (token.isEmpty) return url; @@ -480,6 +497,14 @@ class _MePage2State extends State with WidgetsBindingObserver { iconPath: 'sc_images/index/sc_icon_bag.png', onTap: () => SCNavigatorUtils.push(context, StoreRoute.bags), ), + SizedBox(width: 10.w), + _buildEntryItem( + title: 'cp', + iconPath: 'sc_images/index/sc_icon_cp_entry.png', + iconWidth: 47, + iconHeight: 50, + onTap: _openCpActivity, + ), ], ); } diff --git a/lib/modules/wallet/recharge/recharge_page.dart b/lib/modules/wallet/recharge/recharge_page.dart index eaa3c30..1eb18a3 100644 --- a/lib/modules/wallet/recharge/recharge_page.dart +++ b/lib/modules/wallet/recharge/recharge_page.dart @@ -37,11 +37,6 @@ class _RechargePageState extends State { context, listen: false, ).initializePaymentProcessor(context); - } else if (Platform.isIOS) { - Provider.of( - context, - listen: false, - ).initializePaymentProcessor(context); } } @@ -60,7 +55,7 @@ class _RechargePageState extends State { .getRechargePageScaffoldBackgroundColor(), resizeToAvoidBottomInset: false, appBar: SocialChatStandardAppBar( - title: SCAppLocalizations.of(context)!.recharge, + title: SCAppLocalizations.of(context)!.wallet, actions: [ GestureDetector( onTap: _showRecordDialog, @@ -83,38 +78,27 @@ class _RechargePageState extends State { _buildWalletSection(), SizedBox(height: 36.w), Expanded( - child: Padding( - padding: EdgeInsets.fromLTRB(12.w, 8.w, 12.w, 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildMethodSection(), - SizedBox(height: 14.w), - Expanded(child: _buildNativeProductList()), - if (Platform.isIOS) ...[ - SizedBox(height: 12.w), - _buildFooterButton( - title: - SCAppLocalizations.of( - context, - )!.restorePurchases, - onTap: () { - Provider.of( - context, - listen: false, - ).recoverTransactions(); - }, + child: + Platform.isIOS + ? const SizedBox.shrink() + : Padding( + padding: EdgeInsets.fromLTRB(12.w, 8.w, 12.w, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildMethodSection(), + SizedBox(height: 14.w), + Expanded(child: _buildNativeProductList()), + SizedBox(height: 12.w), + _buildFooterButton( + title: + SCAppLocalizations.of(context)!.recharge, + onTap: _processNativePurchase, + ), + SizedBox(height: 14.w), + ], + ), ), - ], - SizedBox(height: 12.w), - _buildFooterButton( - title: SCAppLocalizations.of(context)!.recharge, - onTap: _processNativePurchase, - ), - SizedBox(height: 14.w), - ], - ), - ), ), ], ), diff --git a/lib/services/audio/rtc_manager.dart b/lib/services/audio/rtc_manager.dart index 15ba909..6e00c7d 100644 --- a/lib/services/audio/rtc_manager.dart +++ b/lib/services/audio/rtc_manager.dart @@ -5070,10 +5070,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { if (clickUser.id == AccountStorage().getCurrentUser()?.userProfile?.id) { ///是自己,直接打开资料卡 - showBottomInBottomDialog( - context!, - RoomUserInfoCard(userId: clickUser.id), - ); + RoomUserInfoCard.showPreloaded(context!, userId: clickUser.id); } else { showBottomInBottomDialog( context!, @@ -5183,10 +5180,7 @@ class RealTimeCommunicationManager extends ChangeNotifier { if (normalizedUserId.isEmpty) { return; } - showBottomInBottomDialog( - context!, - RoomUserInfoCard(userId: normalizedUserId), - ); + RoomUserInfoCard.showPreloaded(context!, userId: normalizedUserId); } addSoundVoiceChangeListener(OnSoundVoiceChange onSoundVoiceChange) { diff --git a/lib/services/auth/user_profile_manager.dart b/lib/services/auth/user_profile_manager.dart index d5adb4e..6b640ee 100644 --- a/lib/services/auth/user_profile_manager.dart +++ b/lib/services/auth/user_profile_manager.dart @@ -250,7 +250,7 @@ class SocialChatUserProfileManager extends ChangeNotifier { return sessionSerial; } - Future roomUserCard( + Future roomUserCard( String roomId, String userId, { int? sessionSerial, @@ -272,36 +272,31 @@ class SocialChatUserProfileManager extends ChangeNotifier { isUserCardLoading = false; notifyListeners(); } - return; + return null; } try { - RoomUserCardRes? card = await SCChatRoomRepository().roomUserCard( - normalizedRoomId, - normalizedUserId, + final card = await _loadHydratedRoomUserCard( + roomId: normalizedRoomId, + userId: normalizedUserId, ); - if (requestSerial != _userCardRequestSerial) { - return; + if (requestSerial != _userCardRequestSerial || + activeSessionSerial != _activeUserCardSessionSerial) { + return null; } userCardInfo = card; userCardLoadError = null; isUserCardLoading = false; - isUserCardRelationLoading = card.userProfile != null; + isUserCardRelationLoading = false; notifyListeners(); - unawaited( - _hydrateRoomUserCard( - card: card, - userId: normalizedUserId, - requestSerial: requestSerial, - sessionSerial: activeSessionSerial, - ), - ); + return card; } catch (error, stackTrace) { if (requestSerial != _userCardRequestSerial) { - return; + return null; } userCardInfo = null; userCardLoadError = error; + isUserCardRelationLoading = false; _debugProfileLoadFailure( scope: 'roomCard', userId: normalizedUserId, @@ -314,6 +309,23 @@ class SocialChatUserProfileManager extends ChangeNotifier { notifyListeners(); } } + return null; + } + + Future preloadRoomUserCardForOpen( + String roomId, + String userId, { + int? sessionSerial, + }) { + return roomUserCard(roomId, userId, sessionSerial: sessionSerial); + } + + Future _loadHydratedRoomUserCard({ + required String roomId, + required String userId, + }) async { + final card = await SCChatRoomRepository().roomUserCard(roomId, userId); + return _withCurrentVipLevelForCard(card, userId); } Future _hydrateUserInfoById({ @@ -340,38 +352,6 @@ class SocialChatUserProfileManager extends ChangeNotifier { } } - Future _hydrateRoomUserCard({ - required RoomUserCardRes? card, - required String userId, - required int requestSerial, - required int sessionSerial, - }) async { - try { - final hydratedCard = await _withCurrentVipLevelForCard(card, userId); - if (requestSerial != _userCardRequestSerial || - sessionSerial != _activeUserCardSessionSerial || - hydratedCard == null) { - return; - } - userCardInfo = hydratedCard; - userCardLoadError = null; - isUserCardRelationLoading = false; - notifyListeners(); - } catch (error, stackTrace) { - if (requestSerial == _userCardRequestSerial && - sessionSerial == _activeUserCardSessionSerial) { - isUserCardRelationLoading = false; - notifyListeners(); - } - _debugProfileLoadFailure( - scope: 'roomCardHydrate', - userId: userId, - error: error, - stackTrace: stackTrace, - ); - } - } - void clearRoomUserCard({int? sessionSerial}) { if (sessionSerial != null && sessionSerial != _activeUserCardSessionSerial) { diff --git a/lib/ui_kit/widgets/room/empty_mai_select.dart b/lib/ui_kit/widgets/room/empty_mai_select.dart index 1b192f4..f83ecfa 100644 --- a/lib/ui_kit/widgets/room/empty_mai_select.dart +++ b/lib/ui_kit/widgets/room/empty_mai_select.dart @@ -9,7 +9,6 @@ import 'package:yumi/ui_kit/widgets/room/room_user_info_card.dart'; import 'package:provider/provider.dart'; import 'package:yumi/app/constants/sc_room_msg_type.dart'; import 'package:yumi/app/constants/sc_screen.dart'; -import 'package:yumi/shared/tools/sc_lk_dialog_util.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/shared/business_logic/models/res/mic_res.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; @@ -266,10 +265,7 @@ class EmptyMaiSelect extends StatelessWidget { context, () { Navigator.of(context).pop(); - showBottomInBottomDialog( - context, - RoomUserInfoCard(userId: clickUser?.id), - ); + RoomUserInfoCard.showPreloaded(context, userId: clickUser?.id); }, ), ); diff --git a/lib/ui_kit/widgets/room/room_user_info_card.dart b/lib/ui_kit/widgets/room/room_user_info_card.dart index dd04730..baecda2 100644 --- a/lib/ui_kit/widgets/room/room_user_info_card.dart +++ b/lib/ui_kit/widgets/room/room_user_info_card.dart @@ -48,8 +48,91 @@ import '../../../modules/chat/chat_route.dart'; class RoomUserInfoCard extends StatefulWidget { final String? userId; + final String? roomId; + final int? sessionSerial; + final bool preloaded; - const RoomUserInfoCard({super.key, this.userId}); + const RoomUserInfoCard({ + super.key, + this.userId, + this.roomId, + this.sessionSerial, + this.preloaded = false, + }); + + static int _openRequestSerial = 0; + + static Future showPreloaded( + BuildContext context, { + required String? userId, + }) async { + final normalizedUserId = (userId ?? '').trim(); + if (normalizedUserId.isEmpty) { + return; + } + final openSerial = ++_openRequestSerial; + final sourceRoomId = _resolveCurrentRoomId(context); + final dialogContext = navigatorKey.currentState?.context ?? context; + final userProvider = Provider.of( + dialogContext, + listen: false, + ); + final roomId = + sourceRoomId.isNotEmpty + ? sourceRoomId + : _resolveCurrentRoomId(dialogContext); + final sessionSerial = userProvider.beginRoomUserCardSession(); + SCLoadingManager.show(); + room_card.RoomUserCardRes? card; + try { + card = await userProvider.preloadRoomUserCardForOpen( + roomId, + normalizedUserId, + sessionSerial: sessionSerial, + ); + } finally { + if (openSerial == _openRequestSerial) { + SCLoadingManager.hide(); + } + } + if (openSerial != _openRequestSerial) { + return; + } + final latestDialogContext = navigatorKey.currentState?.context ?? context; + if (!latestDialogContext.mounted) { + userProvider.clearRoomUserCard(sessionSerial: sessionSerial); + return; + } + if (card == null) { + userProvider.clearRoomUserCard(sessionSerial: sessionSerial); + SCTts.show( + SCAppLocalizations.of(latestDialogContext)?.loadingFailedClickToRetry ?? + 'Loading failed, click to retry', + ); + return; + } + showBottomInBottomDialog( + latestDialogContext, + RoomUserInfoCard( + userId: normalizedUserId, + roomId: roomId, + sessionSerial: sessionSerial, + preloaded: true, + ), + ); + } + + static String _resolveCurrentRoomId(BuildContext context) { + try { + return Provider.of( + context, + listen: false, + ).currenRoom?.roomProfile?.roomProfile?.id ?? + ""; + } catch (_) { + return ""; + } + } @override State createState() => _RoomUserInfoCardState(); @@ -76,12 +159,16 @@ class _RoomUserInfoCardState extends State { context, listen: false, ); - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!mounted) { - return; - } - _loadRoomUserCard(); - }); + roomId = widget.roomId?.trim() ?? ""; + _userCardSessionSerial = widget.sessionSerial; + if (!widget.preloaded) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) { + return; + } + _loadRoomUserCard(); + }); + } SCAccountRepository().userIdentity(userId: widget.userId).then((v) { if (!mounted) { return; @@ -96,12 +183,7 @@ class _RoomUserInfoCardState extends State { context, listen: false, ); - roomId = - Provider.of( - context, - listen: false, - ).currenRoom?.roomProfile?.roomProfile?.id ?? - ""; + roomId = RoomUserInfoCard._resolveCurrentRoomId(context); final sessionSerial = userProvider?.beginRoomUserCardSession(); _userCardSessionSerial = sessionSerial; userProvider?.roomUserCard( @@ -244,12 +326,13 @@ class _RoomUserInfoCardState extends State { required bool relationLoading, }) { final defaultSheetHeight = screenHeight * _profileSheetHeightFactor; + final compactBadgeHeightDelta = 10.w; if (relationLoading) { - return defaultSheetHeight; + return defaultSheetHeight + compactBadgeHeightDelta; } final hasCpRelation = _hasCpRelation(profile); final hasCloseFriends = _closeFriendProfileData(profile).isNotEmpty; - var resolvedHeight = defaultSheetHeight; + var resolvedHeight = defaultSheetHeight + compactBadgeHeightDelta; if (!hasCpRelation) { resolvedHeight -= 126.w; } @@ -602,16 +685,16 @@ class _RoomUserInfoCardState extends State { ) { return SizedBox( width: double.infinity, - height: 20.w, + height: 30.w, child: Center( child: SCUserBadgeStrip( userId: userId, fallbackBadges: _roomCardFallbackBadges(ref, profile), displayScope: SCUserBadgeDisplayScope.short, - height: 20.w, - badgeHeight: 20.w, - longBadgeWidth: 44.w, - spacing: 5.w, + height: 30.w, + badgeHeight: 28.w, + longBadgeWidth: 62.w, + spacing: 6.w, maxBadges: 3, wrap: false, reserveSpace: false, diff --git a/sc_images/index/sc_icon_cp_entry.png b/sc_images/index/sc_icon_cp_entry.png new file mode 100644 index 0000000..9b2c19d Binary files /dev/null and b/sc_images/index/sc_icon_cp_entry.png differ diff --git a/需求进度.md b/需求进度.md index 3a807bf..78bc318 100644 --- a/需求进度.md +++ b/需求进度.md @@ -1,3 +1,23 @@ +# Me 页面 CP 入口需求进度(2026-06-24) + +- [x] 2026-06-24 已确认本轮需求:Me 页面 Store/Bag 旁边新增一个 `cp` 入口;点击后跳转 H5,正式 H5 链接待用户后续提供。 +- [x] 2026-06-24 已按项目约束读取现有进度文档;本轮为开发型小改动,无新增后端接口,不涉及接口 debuglog。 +- [x] 2026-06-24 已定位 Me 页面实现:`lib/modules/user/me_page2.dart`,当前 Store/Level/Bag 位于 `_buildEntryRow()`,使用 `_buildEntryItem()` 统一卡片样式。 +- [x] 2026-06-24 已确认现有 H5 打开方式:通过 `SCMainRoute.webViewPage` 进入 `WebViewPage`,页面内部会用 `SCH5UrlUtils.appendAppParams()` 补 `lang/token`。 +- [x] 2026-06-24 已通过本机 Figma Desktop MCP 读取节点 `873:592` metadata:目标为 `image 4820`,尺寸约 `46.8 × 50`。 +- [!] 2026-06-24 `get_design_context` 对该单图片节点两次调用均超时;已保留调用记录并改用 metadata + screenshot 作为实现依据。 +- [x] 2026-06-24 已通过本机 Figma Desktop MCP 获取节点 `873:592` screenshot,落地到 `build/me_cp_entry_verification/get_screenshot.png`,尺寸 `47 × 50`。 +- [x] 2026-06-24 已检查 Figma 导出图标边缘像素,无黑边;已复制为项目资源 `sc_images/index/sc_icon_cp_entry.png`。 +- [x] 2026-06-24 已实现 CP 入口:`_buildEntryRow()` 从 Store/Level/Bag 三列改为 Store/Level/Bag/cp 四列,CP 位于 Bag 右侧。 +- [x] 2026-06-24 已新增 CP H5 点击占位逻辑:`_cpActivityUrl` 为空时不跳转,仅 debug 输出;待正式 H5 链接提供后替换常量即可。 +- [x] 2026-06-24 已执行 `dart format lib/modules/user/me_page2.dart`,格式化通过。 +- [x] 2026-06-24 已执行 `flutter analyze --no-fatal-warnings --no-fatal-infos lib/modules/user/me_page2.dart`,退出码 0;报告的空 `catch` 与未引用方法为同文件既有问题,本轮未扩大清理。 +- [x] 2026-06-24 已确认 iPhone 17 Pro Max 模拟器在线,设备 ID:`8D2D87EB-4769-43B7-8DC2-580D46A76B6C`。 +- [!] 2026-06-24 按用户最新要求“不用截图”,已跳过 Me 页面截图验证。 +- [x] 2026-06-24 已结束本仓库本轮 `flutter run` / build 相关进程,未保留本轮运行会话。 +- [x] 2026-06-26 已接入 CP 入口正式 H5 链接:`https://h5.global-interaction.com/activity/cp-space/yumi.html`。 +- [x] 2026-06-26 已针对正式链接替换复跑 `dart format` 与 `flutter analyze --no-fatal-warnings --no-fatal-infos lib/modules/user/me_page2.dart`,退出码 0;仅剩同文件既有 warning/info。 + # 首充弹窗需求进度(2026-05-21) - [ ] 2026-05-22 新增问题:后台首充已配置,但前端未显示首充弹窗,房间礼物面板也未显示首充悬浮板;本轮需用 iPhone 17 Pro 模拟器实际排查并修复。 @@ -446,6 +466,8 @@ - 已按 2026-04-20 最新首页视觉需求,为 Party 房间列表前 3 个房卡接入新的本地排名边框 SVGA:桌面“房间排序前三的框”中的 3 份素材已导入工程并挂到首页房卡最上层,仅作用于当前列表前 3 项,其余房卡保持原样;后续又继续为前三房卡底部信息区补了横向与底部安全区,避免外扩边框直接压住国旗、房名和在线人数。同时 `Me` 板块里的 `Recent / Followed` tab 已继续对齐上方首页 tab 的斜体字样式,并移除了点击时的波浪反馈。 - 已按 2026-04-20 最新房间联调继续修正房主在自己房间里的麦位操作回归:当前房主/管理员点击自己所在麦位时,不再被“直接打开资料卡”逻辑短路,会重新回到底部麦位菜单,从而正常看到自己可用的上下麦/禁麦操作;同时上麦、下麦、禁麦、解禁、锁麦、解锁这些动作在接口成功后会立即回写本地麦位状态,并主动补拉一次最新麦位列表,减少房主端自己操作后 UI 状态延迟或短暂错乱。最新已继续收紧“换麦”场景:当前会先本地顺滑切到目标麦位,再在短保护窗内拦住把自己打回旧麦位的旧轮询/旧广播快照;同时补修 `MicRes.copyWith(user: null)` 实际不会清空用户的问题,避免切麦时出现双占位或 `1 -> 4 -> 1 -> 4` 这类来回闪动。 - 已按 2026-04-20 最新调整撤掉 `Wallet -> Recharge` 中新增的 MiFaPay 第三方支付 UI 与页面逻辑:当前充值页仅保留原生 `Google Pay / Apple Pay` 入口与商品列表,`Recharge methods` 区域也已收敛为单一原生支付卡片;此前接入的 MiFaPay 方法选择、底部弹窗、H5 收银台页以及对应页面级状态管理已从现有充值链路移除,避免继续对当前版本产生影响。 +- [x] 2026-06-26 App Review 收口:已调整 `Wallet -> Recharge` 页面,iOS 仅展示钱包余额,不再初始化/展示 Recharge methods、商品空态、恢复购买和充值按钮;顶部标题改为 Wallet,页面静态检查通过。 +- [x] 2026-06-26 iOS 提审版本号调整:Runner 的 `MARKETING_VERSION` 保持 `1.0.0`,`CFBundleVersion` / `CURRENT_PROJECT_VERSION` 已调整为 `102`,对应 App Store Connect 显示 `1.0.0 (102)`。 - 已按 2026-04-18 联调要求继续收口幸运礼物链路:项目默认 API host 已临时切到 `http://192.168.110.43:1100/` 方便直连测试环境;`/gift/give/lucky-gift` 请求体也已补齐为最新结构,除原有 `giftId/quantity/roomId/acceptUserIds/checkCombo` 外,会稳定携带 `gameId: null`、`accepts: []`、`dynamicContentId: null`、`songId: null` 这几组字段,便于和当前后端参数定义保持一致。 - 已继续补齐 `GAME_LUCKY_GIFT` 的 socket 播报与中奖动效:房间群消息收到该类型后,现在会统一落聊天室中奖消息、奖励弹层队列与发送者余额回写,不再只在 `3x+` 时才触发顶部奖励动画;同时全局飘窗已改为按服务端 `globalNews` 字段决定是否展示,避免再用前端本地倍率硬编码去猜。 - 已按最新 UI 口径重排幸运礼物中奖展示:顶部 `LuckGiftNomorAnimWidget` 不再叠加大头像、倍率和奖励框,只在“单个礼物倍率 `>= 10x`”或“单次中奖金币 `> 5000`”时负责播全屏 `luck_gift_reward_burst.svga`;原本的 `luck_gift_reward_frame.svga` 已改挂到房间礼物播报条最右侧,并在框内显示 `+formattedAwardAmount`,金额文案直接复用此前大头像下方那一份中奖金币额。