Merge branch 'feature' of gitea.haiyihy.com:hy/chatapp3-flutter into feature

This commit is contained in:
zhx 2026-05-25 19:55:54 +08:00
commit a73e2ff14b
13 changed files with 210 additions and 177 deletions

View File

@ -346,15 +346,15 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS:
app_links: 585674be3c6661708e6cd794ab4f39fb9d8356f9
app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
audioplayers_darwin: f15e209a3e856d1a7edcf98dc029f484fead2242
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5
device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
firebase_auth: 5342db41af2ba5ed32a6177d9e326eecbebda912
firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c
firebase_crashlytics: 986773c0c7ea4c3f5a4ead141b58522fcd9dfdb1
firebase_auth: 50af8366c87bb88c80ebeae62eb60189c7246b9b
firebase_core: 995454a784ff288be5689b796deb9e9fa3601818
firebase_crashlytics: 30dcd6dfd2fe895c0848af46722a4227346c19aa
FirebaseAppCheckInterop: 06fe5a3799278ae4667e6c432edd86b1030fa3df
FirebaseAuth: a6575e5fbf46b046c58dc211a28a5fbdd8d4c83b
FirebaseAuthInterop: 7087d7a4ee4bc4de019b2d0c240974ed5d89e2fd
@ -366,47 +366,47 @@ SPEC CHECKSUMS:
FirebaseRemoteConfigInterop: 1c6135e8a094cc6368949f5faeeca7ee8948b8aa
FirebaseSessions: b9a92c1c51bbb81e78fc3142cda6d925d700f8e7
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
google_sign_in_ios: 7411fab6948df90490dc4620ecbcabdc3ca04017
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
google_sign_in_ios: b48bb9af78576358a168361173155596c845f0b9
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleSignIn: ce8c89bb9b37fb624b92e7514cc67335d1e277e4
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
HydraAsync: 8d589bd725b0224f899afafc9a396327405f8063
image_cropper: a3291c624a953049bc6a02e1f8c8ceb162a24b25
image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b
in_app_purchase_storekit: 2342c0a5da86593124d08dd13d920f39a52b273a
image_cropper: 655b3ba703c9e15e3111e79151624d6154288774
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
in_app_purchase_storekit: 22cca7d08eebca9babdf4d07d0baccb73325d3c8
libpag: 98742fad4b3ac2a2ee31e383d2483495fb9a5fb4
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
on_audio_query_ios: e5afb0d4b42cfa3e8762d8ec1953540cb4f02100
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
pag: ff30ba5e4be59380a5ddac6b183905729be15a3c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
on_audio_query_ios: 28a780e2d0d85d92d500ba6e12c6c8167022b2fa
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
pag: f01aa9017ab0e04a83ba4a20d6070a50f0ac9da8
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
SwiftyBeaver: 84069991dd5dca07d7069100985badaca7f0ce82
tancent_vap: eceaaf095167d102727cf799c75891057834c311
tencent_cloud_chat_sdk: 546bb906bbe585814e3d2d33afdb91f09c0eac44
tencent_rtc_sdk: 1ca5201f7bddc691a3a95486325ad6dc792a273d
tancent_vap: fa8ad93814a9f950514a7074c662d2c937084c68
tencent_cloud_chat_sdk: 55e5fffe20f6b7937a26a674ccccb639563a9790
tencent_rtc_sdk: f77558b6b436a149d378557c2a837f73c09061bc
TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
TXCustomBeautyProcesserPlugin: 099393b941cb40eda12b3a80bf6c0319957b1cfd
TXIMSDK_Plus_iOS_XCFramework: 5d1933192fb3b7ef2fe933f1623de4a0486a7fe2
TXLiteAVSDK_Professional: e792e6084a208ecef6196c5f28237ad8078b4d7c
url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa
video_player_avfoundation: e54d03b3b19f64f2c557354f72ce538387541ba6
video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1
wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e
webview_flutter_wkwebview: 29eb20d43355b48fe7d07113835b9128f84e3af4
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
video_player_avfoundation: 3453f792138786248960ca029747fcd9f318ef52
video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d
PODFILE CHECKSUM: a6f49a93e5f85201a2efdadcd7cf184b0e310894

View File

@ -19,7 +19,6 @@ import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart';
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
import 'package:yumi/shared/data_sources/sources/remote/net/api.dart';
import 'package:yumi/shared/data_sources/sources/repositories/sc_room_repository_imp.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/tools/sc_cp_gift_relation_utils.dart';
import 'package:yumi/main.dart';
@ -1520,8 +1519,6 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
'giftType=$giftType',
);
await _showCpGiftRelationCheckToastIfNeeded(request);
try {
final repository = SCChatRoomRepository();
_giftFxLog(
@ -1728,49 +1725,6 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
);
}
Future<void> _showCpGiftRelationCheckToastIfNeeded(
_GiftSendRequest request,
) async {
final relationType = request.cpRelationType;
if (relationType == null || relationType.trim().isEmpty) {
return;
}
final acceptUserId = request.acceptUserIds
.map((userId) => userId.trim())
.firstWhere((userId) => userId.isNotEmpty, orElse: () => '');
if (acceptUserId.isEmpty) {
return;
}
try {
final result = await SCAccountRepository().cpGiftRelationCheck(
acceptUserId: acceptUserId,
relationType: relationType,
);
final message = result.msg.trim();
_giftFxLog(
'cp gift relation check '
'acceptUserId=$acceptUserId '
'relationType=$relationType '
'status=${result.status} '
'msg=$message '
'userCount=${result.userRelationCount}/${result.maxRelationCount} '
'acceptCount=${result.acceptUserRelationCount}/${result.maxRelationCount}',
);
if (!result.status &&
message.isNotEmpty &&
message.toUpperCase() != 'OK') {
SCTts.show(message);
}
} catch (error) {
_giftFxLog(
'cp gift relation check skipped '
'acceptUserId=$acceptUserId '
'relationType=$relationType '
'error=$error',
);
}
}
Future<List<MicRes>> _giveBackpackGiftToRecipients(
SCChatRoomRepository repository,
_GiftSendRequest request,

View File

@ -7,7 +7,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:yumi/app_localizations.dart';
import 'package:yumi/app/constants/sc_global_config.dart';
import 'package:yumi/main.dart' show modalRouteObserver;
import 'package:yumi/main.dart' show routeObserver;
import 'package:yumi/ui_kit/components/sc_compontent.dart';
import 'package:yumi/services/audio/rtc_manager.dart';
import 'package:yumi/ui_kit/widgets/room/room_bottom_widget.dart';
@ -83,7 +83,7 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
bool _roomProviderRebuildScheduled = false;
bool _roomRouteVisibleScheduled = false;
bool _roomVisualEffectsEnsureScheduled = false;
ModalRoute<dynamic>? _routeObserverRoute;
PageRoute<dynamic>? _routeObserverRoute;
SCRoomTopLayerGuardLease? _coveredRouteGuardLease;
bool _roomRouteVisible = false;
@ -91,9 +91,6 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
void initState() {
super.initState();
_tabController = TabController(length: _chatTabCount, vsync: this);
SCRoomTopLayerGuard().activeListenable.addListener(
_handleRoomTopLayerGuardChanged,
);
_tabController.addListener(_handleTabChange);
_subscription = eventBus.on<SCGiveRoomLuckPageDisposeEvent>().listen((
event,
@ -123,12 +120,12 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
context.read<RoomMusicManager>().attachRtcProvider(rtcProvider);
}
final route = ModalRoute.of(context);
if (route != null && _routeObserverRoute != route) {
if (route is PageRoute<dynamic> && _routeObserverRoute != route) {
if (_routeObserverRoute != null) {
modalRouteObserver.unsubscribe(this);
routeObserver.unsubscribe(this);
}
_routeObserverRoute = route;
modalRouteObserver.subscribe(this, route);
routeObserver.subscribe(this, route);
if (route.isCurrent) {
_scheduleRoomRouteVisible();
} else {
@ -140,10 +137,7 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
@override
void dispose() {
SCRoomTopLayerGuard().activeListenable.removeListener(
_handleRoomTopLayerGuardChanged,
);
modalRouteObserver.unsubscribe(this);
routeObserver.unsubscribe(this);
_routeObserverRoute = null;
_releaseCoveredRouteGuard();
_setRoomRouteVisible(false);
@ -215,13 +209,6 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
_coveredRouteGuardLease = null;
}
void _handleRoomTopLayerGuardChanged() {
if (!SCRoomTopLayerGuard().isActive || !mounted) {
return;
}
_clearTransientRoomVisualEffects(reason: 'room_top_layer_guard');
}
void _setRoomRouteVisible(bool visible) {
if (_roomRouteVisible == visible) {
return;

View File

@ -1588,7 +1588,7 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
if (payload.rightUserId.trim().isEmpty) {
return;
}
const cancelText = 'unbing';
const cancelText = 'unbind';
SCLoadingManager.show(context: context);
late final _ProfileRelationProgressData progress;
try {
@ -1629,7 +1629,10 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
Future<_ProfileRelationProgressData> _loadProfileRelationProgressData(
_ProfileRelationProgressPayload payload,
) async {
final partnerUserId = payload.rightUserId.trim();
final partnerUserId = _counterpartUserIdForCurrentUser(
leftUserId: payload.leftUserId,
rightUserId: payload.rightUserId,
);
final fallback = _ProfileRelationProgressData.fallback(payload);
if (partnerUserId.isEmpty) {
return fallback;
@ -1666,11 +1669,34 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
}
}
String _counterpartUserIdForCurrentUser({
required String leftUserId,
required String rightUserId,
}) {
final currentUserId =
AccountStorage().getCurrentUser()?.userProfile?.id?.trim() ?? "";
final leftId = leftUserId.trim();
final rightId = rightUserId.trim();
if (currentUserId.isEmpty) {
return rightId;
}
if (currentUserId == leftId) {
return rightId;
}
if (currentUserId == rightId) {
return leftId;
}
return rightId;
}
Future<void> _showProfileRelationDismissConfirm(
_ProfileRelationProgressPayload payload, {
int? dismissCost,
}) async {
final partnerUserId = payload.rightUserId.trim();
final partnerUserId = _counterpartUserIdForCurrentUser(
leftUserId: payload.leftUserId,
rightUserId: payload.rightUserId,
);
if (partnerUserId.isEmpty) {
return;
}

View File

@ -544,10 +544,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
int? get previewRoomSeatCount => _previewRoomSeatCount;
bool get shouldShowRoomVisualEffects =>
currenRoom != null &&
_roomVisualEffectsEnabled &&
_voiceRoomRouteVisible &&
!SCRoomTopLayerGuard().isActive;
currenRoom != null && _roomVisualEffectsEnabled && _voiceRoomRouteVisible;
void _startVoiceRoomForegroundService() {
final roomProfile = currenRoom?.roomProfile?.roomProfile;

View File

@ -3100,7 +3100,10 @@ class RealTimeMessagingManager extends ChangeNotifier {
}
}
void _enqueueCpRelationBroadcastFloatingIfNeeded(Msg msg) {
void _enqueueCpRelationBroadcastFloatingIfNeeded(
Msg msg, {
bool isRegionBroadcast = false,
}) {
if (msg.type != SCRoomMsgType.cpSystemNotice) {
return;
}
@ -3108,8 +3111,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
if (action != "RELATION_ESTABLISHED" && action != "RELATION_JOINED_ROOM") {
return;
}
if (!_isLiveCpRelationBroadcastMessage(msg) ||
!_shouldShowCpRelationBroadcastFloating(msg.groupId ?? "")) {
if (!_isLiveCpRelationBroadcastMessage(msg)) {
return;
}
final relationType = scNormalizeCpRelationType(msg.role);
@ -3132,6 +3134,8 @@ class RealTimeMessagingManager extends ChangeNotifier {
giftTab: relationType,
displayText: msg.msg ?? "",
durationSeconds: 5,
broadcastScope:
isRegionBroadcast ? SCFloatingMessage.broadcastScopeRegion : '',
),
);
}
@ -3187,23 +3191,6 @@ class RealTimeMessagingManager extends ChangeNotifier {
return DateTime.now().millisecondsSinceEpoch - timestamp < 60000;
}
bool _shouldShowCpRelationBroadcastFloating(String groupId) {
final normalizedGroupId = groupId.trim();
final currentContext = context;
if (normalizedGroupId.isEmpty ||
currentContext == null ||
!currentContext.mounted ||
!_isCurrentVoiceRoomGroup(normalizedGroupId)) {
return false;
}
final rtcProvider = Provider.of<RealTimeCommunicationManager>(
currentContext,
listen: false,
);
return rtcProvider.shouldShowRoomVisualEffects &&
rtcProvider.isVoiceRoomRouteVisible;
}
String _roomMsgUserId(SocialChatUserProfile? profile) {
return _firstCpInviteValue([profile?.id, profile?.account]) ?? "";
}
@ -6044,6 +6031,34 @@ class RealTimeMessagingManager extends ChangeNotifier {
if (isRegionBroadcastGroup) {
_handleRegionGiftBroadcast(data["data"]);
}
} else if (type == SCRoomMsgType.cpSystemNotice) {
final payload = data["data"] ?? data;
final payloadMap = _broadcastPayloadMap(payload);
if (payloadMap.isEmpty) {
return;
}
final msg = Msg.fromJson(payloadMap);
msg.type ??= SCRoomMsgType.cpSystemNotice;
msg.groupId = _firstNonBlank([
msg.groupId,
_payloadText(payloadMap["groupId"]),
_payloadText(payloadMap["roomId"]),
_payloadText(data["groupId"]),
_payloadText(data["roomId"]),
]);
msg.noticeAction ??= data["noticeAction"]?.toString();
if ((msg.role ?? "").trim().isEmpty) {
msg.role = _firstNonBlank([
_payloadText(payloadMap["role"]),
_payloadText(payloadMap["relationType"]),
_payloadText(data["role"]),
_payloadText(data["relationType"]),
]);
}
_enqueueCpRelationBroadcastFloatingIfNeeded(
msg,
isRegionBroadcast: isRegionBroadcastGroup,
);
} else if (type == SCRoomMsgType.inviteRoom) {
///
var fdata = data["data"];

View File

@ -631,10 +631,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
required String relationType,
String? fallbackText,
}) async {
if (!_isCurrentUserId(userId)) {
return null;
}
final partnerUserId = _cpPartnerUserId(userId, cpPair);
final partnerUserId = _cpPartnerUserIdForCurrentUser(cpPair);
if (partnerUserId.isEmpty) {
return null;
}
@ -659,14 +656,21 @@ class SocialChatUserProfileManager extends ChangeNotifier {
}
}
String _cpPartnerUserId(String userId, CPRes cpPair) {
final currentId = userId.trim();
String _cpPartnerUserIdForCurrentUser(CPRes cpPair) {
final currentUserId =
AccountStorage().getCurrentUser()?.userProfile?.id?.trim() ?? "";
if (currentUserId.isEmpty) {
return "";
}
final meUserId = cpPair.meUserId?.trim() ?? "";
final cpUserId = cpPair.cpUserId?.trim() ?? "";
if (currentId.isNotEmpty && currentId == cpUserId) {
if (currentUserId == meUserId) {
return cpUserId;
}
if (currentUserId == cpUserId) {
return meUserId;
}
return cpUserId;
return "";
}
bool _hasCpPair(CPRes? pair) {

View File

@ -803,10 +803,22 @@ class OverlayManager {
return message.type == 2 && message.isRegionBroadcast;
}
bool _isRegionCpGiftMessage(SCFloatingMessage message) {
return message.type == 1 &&
message.isRegionBroadcast &&
scIsCpGiftTab(message.giftTab);
}
bool _isRegionCpRelationMessage(SCFloatingMessage message) {
return message.type == 6 && message.isRegionBroadcast;
}
bool _isCrossRoomRegionFloatingMessage(SCFloatingMessage message) {
return _isRegionRedPacketMessage(message) ||
_isRegionRoomRocketMessage(message) ||
_isRegionGameWinMessage(message);
_isRegionGameWinMessage(message) ||
_isRegionCpGiftMessage(message) ||
_isRegionCpRelationMessage(message);
}
bool _shouldDeferRegionRedPacketMessage(
@ -931,15 +943,20 @@ class OverlayManager {
currentRoomId.isNotEmpty &&
messageRoomId.isNotEmpty &&
currentRoomId == messageRoomId;
final isGlobalStackedBroadcast =
message.type == 4 ||
message.type == 3 ||
message.type == 6 ||
_isRegionCpGiftMessage(message);
if (isCurrentVisibleRoom) {
// / RTM IM
return message.type == 4 || message.type == 3 || message.type == 2;
// //CP RTM IM
return isGlobalStackedBroadcast || message.type == 2;
}
final isCurrentRoomMessage =
currentRoomId.isNotEmpty &&
messageRoomId.isNotEmpty &&
currentRoomId == messageRoomId;
if ((message.type == 4 || message.type == 3 || message.type == 2) &&
if ((isGlobalStackedBroadcast || message.type == 2) &&
isCurrentRoomMessage) {
return false;
}
@ -952,11 +969,10 @@ class OverlayManager {
}
return SCGlobalConfig.isFloatingBroadcastAll && _homeRootTabsVisible;
}
if ((message.type == 4 || message.type == 3) &&
rtcProvider.shouldShowRoomVisualEffects) {
if (isGlobalStackedBroadcast && rtcProvider.shouldShowRoomVisualEffects) {
return true;
}
if (message.type == 4 || message.type == 3) {
if (isGlobalStackedBroadcast) {
return _homeRootTabsVisible;
}
if (SCGlobalConfig.isFloatingBroadcastRoomOnly) {

View File

@ -1524,25 +1524,12 @@ class SCAccountRepository implements SocialChatUserRepository {
String relationType = 'CP',
}) async {
final query = {"acceptUserId": acceptUserId, "relationType": relationType};
_cpDebugLog('giftRelationCheck request query=$query');
try {
final result = await http.get<SCCpGiftRelationCheckRes>(
"/user/cp-relationship/gift-relation/check",
queryParams: query,
extra: const {BaseNetworkClient.silentErrorToastKey: true},
fromJson: SCCpGiftRelationCheckRes.fromJson,
);
_cpDebugLog(
'giftRelationCheck response query=$query '
'status=${result.status} msg=${result.msg} '
'userFull=${result.userRelationFull} '
'acceptFull=${result.acceptUserRelationFull}',
);
return result;
} catch (error) {
_cpDebugLog('giftRelationCheck failed query=$query error=$error');
rethrow;
}
return http.get<SCCpGiftRelationCheckRes>(
"/user/cp-relationship/gift-relation/check",
queryParams: query,
extra: const {BaseNetworkClient.silentErrorToastKey: true},
fromJson: SCCpGiftRelationCheckRes.fromJson,
);
}
///user/cp/cabin

View File

@ -5,9 +5,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:yumi/shared/data_sources/sources/local/floating_screen_manager.dart';
import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart';
import 'package:yumi/shared/tools/sc_room_effect_scheduler.dart';
import 'package:yumi/ui_kit/widgets/room/anim/room_entrance_widget.dart';
class SCRoomTopLayerGuard {
static const int _maxDeferredActions = 16;
@ -56,11 +53,6 @@ class SCRoomTopLayerGuard {
}
_activeListenable.value = true;
OverlayManager().beginSuppressFloatingScreens(reason: reason);
SCRoomEffectScheduler().beginSuppressEffects(reason: reason);
SCRoomEffectScheduler().clearDeferredTasks(reason: reason);
RoomEntranceHelper.clearQueue();
SCGiftVapSvgaManager().stopPlayback();
SCGiftVapSvgaManager().pauseAnim();
if (!keepDialogTags.contains(_redPacketOpenDialogTag)) {
unawaited(SmartDialog.dismiss(tag: _redPacketOpenDialogTag));
}
@ -81,8 +73,6 @@ class SCRoomTopLayerGuard {
return;
}
OverlayManager().endSuppressFloatingScreens(reason: reason);
SCRoomEffectScheduler().endSuppressEffects(reason: reason);
SCGiftVapSvgaManager().resumeAnim();
_activeListenable.value = false;
_drainDeferredActions();
}

View File

@ -37,7 +37,7 @@ class RoomCpProgressDialog extends StatelessWidget {
this.targetValue = 1,
this.expAwayText = '0',
this.nextLevelText = 'Lv. 1',
this.cancelText = 'unbing',
this.cancelText = 'unbind',
this.dismissTag = dialogTag,
this.onCancel,
});
@ -68,7 +68,7 @@ class RoomCpProgressDialog extends StatelessWidget {
double targetValue = 1,
String expAwayText = '0',
String nextLevelText = 'Lv. 1',
String cancelText = 'unbing',
String cancelText = 'unbind',
String dismissTag = dialogTag,
VoidCallback? onCancel,
}) async {
@ -495,7 +495,7 @@ class _CancelButton extends StatelessWidget {
fit: BoxFit.fill,
),
Text(
text.trim().isEmpty ? 'unbing' : text.trim(),
text.trim().isEmpty ? 'unbind' : text.trim(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:yumi/shared/data_sources/models/message/sc_floating_message.dart';
@ -157,7 +159,7 @@ class _FloatingCpRelationScreenWidgetState
}
final explicitText = widget.message.displayText?.trim() ?? "";
if (explicitText.isNotEmpty) {
return _stripSystemNotificationPrefix(explicitText);
return _stripSystemNotificationPrefix(_repairMojibake(explicitText));
}
return _stripSystemNotificationPrefix(
scBuildCpRelationEstablishedNotice(
@ -169,7 +171,7 @@ class _FloatingCpRelationScreenWidgetState
}
String _shortName(String? value) {
final text = value?.trim() ?? "";
final text = _repairMojibake(value?.trim() ?? "");
if (text.length <= 14) {
return text;
}
@ -188,7 +190,7 @@ class _FloatingCpRelationScreenWidgetState
}
String _stripSystemNotificationPrefix(String text) {
return text
return _repairMojibake(text)
.replaceFirst(
RegExp(
r'^\s*[\[\【]\s*sys(?:tem|term)\s+notification\s*[\]\】]\s*',
@ -199,6 +201,35 @@ class _FloatingCpRelationScreenWidgetState
.trim();
}
String _repairMojibake(String value) {
final text = value.trim();
if (text.isEmpty || !_looksLikeMojibake(text)) {
return text;
}
try {
final repaired = utf8.decode(latin1.encode(text), allowMalformed: true);
return _mojibakeScore(repaired) < _mojibakeScore(text) ? repaired : text;
} catch (_) {
return text;
}
}
bool _looksLikeMojibake(String value) {
return value.contains('Ã') ||
value.contains('Â') ||
value.contains('â') ||
value.contains('ð') ||
value.contains('<EFBFBD>');
}
int _mojibakeScore(String value) {
var score = 0;
for (final marker in const ['Ã', 'Â', 'â', 'ð', '<EFBFBD>']) {
score += marker.allMatches(value).length;
}
return score;
}
List<Color> _relationColors(String? relationType) {
switch (scNormalizeCpRelationType(relationType)) {
case "BROTHER":

View File

@ -612,16 +612,16 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
) {
return SizedBox(
width: double.infinity,
height: 16.w,
height: 20.w,
child: Center(
child: SCUserBadgeStrip(
userId: userId,
fallbackBadges: _roomCardFallbackBadges(ref, profile),
displayScope: SCUserBadgeDisplayScope.short,
height: 16.w,
badgeHeight: 16.w,
longBadgeWidth: 32.w,
spacing: 4.w,
height: 20.w,
badgeHeight: 20.w,
longBadgeWidth: 44.w,
spacing: 5.w,
maxBadges: 3,
wrap: false,
reserveSpace: false,
@ -1633,7 +1633,7 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
SocialChatUserProfile? profile,
) async {
final cp = _cpProfileData(profile);
const cancelText = 'unbing';
const cancelText = 'unbind';
SCLoadingManager.show();
late final _RoomCpProgressData progress;
try {
@ -1673,7 +1673,10 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
}
Future<_RoomCpProgressData> _loadCpProgressData(_RoomProfileCpData cp) async {
final partnerUserId = cp.rightUserId.trim();
final partnerUserId = _counterpartUserIdForCurrentUser(
leftUserId: cp.leftUserId,
rightUserId: cp.rightUserId,
);
final fallback = _RoomCpProgressData.fallback(cp);
if (partnerUserId.isEmpty) {
return fallback;
@ -1707,13 +1710,36 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
}
}
String _counterpartUserIdForCurrentUser({
required String leftUserId,
required String rightUserId,
}) {
final currentUserId =
AccountStorage().getCurrentUser()?.userProfile?.id?.trim() ?? "";
final leftId = leftUserId.trim();
final rightId = rightUserId.trim();
if (currentUserId.isEmpty) {
return rightId;
}
if (currentUserId == leftId) {
return rightId;
}
if (currentUserId == rightId) {
return leftId;
}
return rightId;
}
Future<void> _showCpDismissConfirm(
BuildContext context,
_RoomProfileCpData cp, {
int? dismissCost,
}) async {
final l10n = SCAppLocalizations.of(context)!;
final partnerUserId = cp.rightUserId.trim();
final partnerUserId = _counterpartUserIdForCurrentUser(
leftUserId: cp.leftUserId,
rightUserId: cp.rightUserId,
);
if (partnerUserId.isEmpty) {
return;
}