修改bug
This commit is contained in:
parent
f025c18211
commit
b045b3b784
@ -1275,11 +1275,15 @@ class _MessageItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (cpStatusLineText != null) _buildCpStatusLine(cpStatusLineText),
|
||||||
if (cpRelationFormedCard != null)
|
if (cpRelationFormedCard != null)
|
||||||
cpRelationFormedCard
|
Padding(
|
||||||
else if (cpStatusLineText != null)
|
padding: EdgeInsets.only(
|
||||||
_buildCpStatusLine(cpStatusLineText)
|
top: cpStatusLineText == null ? 0 : 10.w,
|
||||||
else
|
),
|
||||||
|
child: cpRelationFormedCard,
|
||||||
|
)
|
||||||
|
else if (cpStatusLineText == null)
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -1647,12 +1651,14 @@ class _MessageItem extends StatelessWidget {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final state = _cpInviteStateFromData(data);
|
final state = _cpInviteStateFromData(data);
|
||||||
if (state == _CpInviteMessageState.pending ||
|
if (state == _CpInviteMessageState.pending) {
|
||||||
state == _CpInviteMessageState.accepted) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final localizations = SCAppLocalizations.of(context)!;
|
final localizations = SCAppLocalizations.of(context)!;
|
||||||
final relationType = _cpRelationTypeFromMessageData(data);
|
final relationType = _cpRelationTypeFromMessageData(data);
|
||||||
|
if (state == _CpInviteMessageState.accepted) {
|
||||||
|
return _cpAcceptedStatusLineText(relationType);
|
||||||
|
}
|
||||||
if (state == _CpInviteMessageState.expired) {
|
if (state == _CpInviteMessageState.expired) {
|
||||||
if (relationType != "CP") {
|
if (relationType != "CP") {
|
||||||
return "The ${scCpRelationPossessiveLabel(relationType)} invitation timed out.";
|
return "The ${scCpRelationPossessiveLabel(relationType)} invitation timed out.";
|
||||||
@ -1670,6 +1676,19 @@ class _MessageItem extends StatelessWidget {
|
|||||||
: "You declined the other party's $relationLabel invitation.";
|
: "You declined the other party's $relationLabel invitation.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _cpAcceptedStatusLineText(String relationType) {
|
||||||
|
final localizations = SCAppLocalizations.of(context)!;
|
||||||
|
switch (scNormalizeCpRelationType(relationType)) {
|
||||||
|
case "BROTHER":
|
||||||
|
return "Have become sworn brothers";
|
||||||
|
case "SISTERS":
|
||||||
|
return "Have become sisters";
|
||||||
|
case "CP":
|
||||||
|
default:
|
||||||
|
return localizations.closeFriendsHaveBecome;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _showCpInviteDialogFromMessage(
|
void _showCpInviteDialogFromMessage(
|
||||||
Map<String, dynamic> data,
|
Map<String, dynamic> data,
|
||||||
SCSystemInvitMessageRes? cpInvite,
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
|||||||
@ -370,11 +370,15 @@ class _MessageItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (cpStatusLineText != null) _buildCpStatusLine(cpStatusLineText),
|
||||||
if (cpRelationFormedCard != null)
|
if (cpRelationFormedCard != null)
|
||||||
cpRelationFormedCard
|
Padding(
|
||||||
else if (cpStatusLineText != null)
|
padding: EdgeInsets.only(
|
||||||
_buildCpStatusLine(cpStatusLineText)
|
top: cpStatusLineText == null ? 0 : 10.w,
|
||||||
else
|
),
|
||||||
|
child: cpRelationFormedCard,
|
||||||
|
)
|
||||||
|
else if (cpStatusLineText == null)
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
@ -834,10 +838,6 @@ class _MessageItem extends StatelessWidget {
|
|||||||
if (data == null) {
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final noticeType = data["noticeType"]?.toString() ?? "";
|
|
||||||
if (noticeType == SCSysytemMessageType.CP_BUILD.name) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final state = _cpInviteStateFromData(data);
|
final state = _cpInviteStateFromData(data);
|
||||||
if (state == _CpInviteMessageState.pending || !_isCpInvitePayload(data)) {
|
if (state == _CpInviteMessageState.pending || !_isCpInvitePayload(data)) {
|
||||||
return null;
|
return null;
|
||||||
@ -846,10 +846,10 @@ class _MessageItem extends StatelessWidget {
|
|||||||
if (state == _CpInviteMessageState.expired) {
|
if (state == _CpInviteMessageState.expired) {
|
||||||
return localizations.closeFriendInviteTimedOut;
|
return localizations.closeFriendInviteTimedOut;
|
||||||
}
|
}
|
||||||
final inviterView = _isCurrentUserCpInviter(data);
|
|
||||||
if (state == _CpInviteMessageState.accepted) {
|
if (state == _CpInviteMessageState.accepted) {
|
||||||
return null;
|
return _cpAcceptedStatusLineText(_cpRelationTypeFromMessageData(data));
|
||||||
}
|
}
|
||||||
|
final inviterView = _isCurrentUserCpInviter(data);
|
||||||
return inviterView
|
return inviterView
|
||||||
? localizations.otherDeclinedCloseFriendInvite
|
? localizations.otherDeclinedCloseFriendInvite
|
||||||
: localizations.youDeclinedCloseFriendInvite;
|
: localizations.youDeclinedCloseFriendInvite;
|
||||||
@ -1147,6 +1147,20 @@ class _MessageItem extends StatelessWidget {
|
|||||||
], fallback: "");
|
], fallback: "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _cpRelationTypeFromMessageData(Map<String, dynamic> data) {
|
||||||
|
final invite = _cpInviteFromMessageData(data);
|
||||||
|
final content = _cpContentMap(data);
|
||||||
|
return scNormalizeCpRelationType(
|
||||||
|
_firstNonBlankString([
|
||||||
|
invite?.relationType,
|
||||||
|
data["relationType"]?.toString(),
|
||||||
|
data["relation_type"]?.toString(),
|
||||||
|
content["relationType"]?.toString(),
|
||||||
|
content["relation_type"]?.toString(),
|
||||||
|
], fallback: "CP"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _cpContentMap(Map<String, dynamic> data) {
|
Map<String, dynamic> _cpContentMap(Map<String, dynamic> data) {
|
||||||
final content = data["content"];
|
final content = data["content"];
|
||||||
try {
|
try {
|
||||||
@ -1202,6 +1216,19 @@ class _MessageItem extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _cpAcceptedStatusLineText(String relationType) {
|
||||||
|
final localizations = SCAppLocalizations.of(context)!;
|
||||||
|
switch (scNormalizeCpRelationType(relationType)) {
|
||||||
|
case "BROTHER":
|
||||||
|
return "Have become sworn brothers";
|
||||||
|
case "SISTERS":
|
||||||
|
return "Have become sisters";
|
||||||
|
case "CP":
|
||||||
|
default:
|
||||||
|
return localizations.closeFriendsHaveBecome;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String _cpDisplayName({
|
String _cpDisplayName({
|
||||||
String? nickname,
|
String? nickname,
|
||||||
String? account,
|
String? account,
|
||||||
|
|||||||
@ -33,14 +33,25 @@ import 'package:yumi/shared/business_logic/models/res/sc_sign_in_reward_res.dart
|
|||||||
import 'package:yumi/shared/business_logic/models/res/sc_sign_in_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/sc_sign_in_res.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/sc_violation_handle_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/sc_violation_handle_res.dart';
|
||||||
import 'package:yumi/shared/business_logic/repositories/user_repository.dart';
|
import 'package:yumi/shared/business_logic/repositories/user_repository.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/remote/net/api.dart'
|
||||||
show BaseNetworkClient;
|
show BaseNetworkClient;
|
||||||
import 'package:yumi/shared/data_sources/sources/remote/net/network_client.dart';
|
import 'package:yumi/shared/data_sources/sources/remote/net/network_client.dart';
|
||||||
import 'package:yumi/shared/tools/sc_mobile_login_context.dart';
|
import 'package:yumi/shared/tools/sc_mobile_login_context.dart';
|
||||||
import 'package:yumi/shared/tools/sc_room_profile_cache.dart';
|
import 'package:yumi/shared/tools/sc_room_profile_cache.dart';
|
||||||
|
|
||||||
|
class _CpRequestCacheEntry<T> {
|
||||||
|
const _CpRequestCacheEntry(this.value, this.createdAt);
|
||||||
|
|
||||||
|
final T value;
|
||||||
|
final DateTime createdAt;
|
||||||
|
|
||||||
|
bool isFresh(Duration ttl) => DateTime.now().difference(createdAt) < ttl;
|
||||||
|
}
|
||||||
|
|
||||||
class SCAccountRepository implements SocialChatUserRepository {
|
class SCAccountRepository implements SocialChatUserRepository {
|
||||||
static SCAccountRepository? _instance;
|
static SCAccountRepository? _instance;
|
||||||
|
static const Duration _cpRelationRequestCacheTtl = Duration(seconds: 2);
|
||||||
|
|
||||||
SCAccountRepository._internal();
|
SCAccountRepository._internal();
|
||||||
|
|
||||||
@ -48,6 +59,12 @@ class SCAccountRepository implements SocialChatUserRepository {
|
|||||||
return _instance ??= SCAccountRepository._internal();
|
return _instance ??= SCAccountRepository._internal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Map<String, _CpRequestCacheEntry<List<CPRes>>> _cpPairsCache = {};
|
||||||
|
final Map<String, Future<List<CPRes>>> _cpPairsInFlight = {};
|
||||||
|
final Map<String, _CpRequestCacheEntry<SCCpCabinRes>> _cpCabinCache = {};
|
||||||
|
final Map<String, Future<SCCpCabinRes>> _cpCabinInFlight = {};
|
||||||
|
int _cpRelationCacheEpoch = 0;
|
||||||
|
|
||||||
void _cpDebugLog(String message) {
|
void _cpDebugLog(String message) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
debugPrint('[CP][API] $message');
|
debugPrint('[CP][API] $message');
|
||||||
@ -78,6 +95,52 @@ class SCAccountRepository implements SocialChatUserRepository {
|
|||||||
'levels=${config.levels.map((level) => "{level=${level.level}, name=${level.levelName}, required=${level.requiredIntimacyValue}, rights=${level.rights.length}, unlocked=${level.unlocked}}").toList()}}';
|
'levels=${config.levels.map((level) => "{level=${level.level}, name=${level.levelName}, required=${level.requiredIntimacyValue}, rights=${level.rights.length}, unlocked=${level.unlocked}}").toList()}}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _currentCpCacheSessionKey() {
|
||||||
|
final currentUserId =
|
||||||
|
AccountStorage().getCurrentUser()?.userProfile?.id?.trim() ?? '';
|
||||||
|
if (currentUserId.isNotEmpty) {
|
||||||
|
return currentUserId;
|
||||||
|
}
|
||||||
|
final token = AccountStorage().getToken().trim();
|
||||||
|
return token.isEmpty ? 'anonymous' : token;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _normalizedCpRelationType(String relationType) {
|
||||||
|
final normalized = relationType.trim().toUpperCase();
|
||||||
|
return normalized.isEmpty ? 'CP' : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _cpPairsCacheKey(String relationType) {
|
||||||
|
return '${_currentCpCacheSessionKey()}|${_normalizedCpRelationType(relationType)}';
|
||||||
|
}
|
||||||
|
|
||||||
|
String _cpCabinCacheKey(String userId, String relationType) {
|
||||||
|
return '${_currentCpCacheSessionKey()}|${userId.trim()}|${_normalizedCpRelationType(relationType)}';
|
||||||
|
}
|
||||||
|
|
||||||
|
T? _freshCpCacheValue<T>(
|
||||||
|
Map<String, _CpRequestCacheEntry<T>> cache,
|
||||||
|
String key,
|
||||||
|
) {
|
||||||
|
final entry = cache[key];
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (entry.isFresh(_cpRelationRequestCacheTtl)) {
|
||||||
|
return entry.value;
|
||||||
|
}
|
||||||
|
cache.remove(key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearCpRelationRequestCache() {
|
||||||
|
_cpRelationCacheEpoch++;
|
||||||
|
_cpPairsCache.clear();
|
||||||
|
_cpPairsInFlight.clear();
|
||||||
|
_cpCabinCache.clear();
|
||||||
|
_cpCabinInFlight.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<SocialChatLoginRes> getUser(String id) async {
|
Future<SocialChatLoginRes> getUser(String id) async {
|
||||||
final result = await http.get(
|
final result = await http.get(
|
||||||
@ -1272,23 +1335,55 @@ class SCAccountRepository implements SocialChatUserRepository {
|
|||||||
///user/cp-relationship/pair
|
///user/cp-relationship/pair
|
||||||
@override
|
@override
|
||||||
Future<List<CPRes>> cpRelationshipPairs({String relationType = 'CP'}) async {
|
Future<List<CPRes>> cpRelationshipPairs({String relationType = 'CP'}) async {
|
||||||
_cpDebugLog('pair request relationType=$relationType');
|
final normalizedRelationType = _normalizedCpRelationType(relationType);
|
||||||
try {
|
final cacheKey = _cpPairsCacheKey(normalizedRelationType);
|
||||||
final result = await http.get<List<CPRes>>(
|
final cached = _freshCpCacheValue(_cpPairsCache, cacheKey);
|
||||||
"/user/cp-relationship/pair",
|
if (cached != null) {
|
||||||
queryParams: {"relationType": relationType},
|
_cpDebugLog('pair cache hit relationType=$normalizedRelationType');
|
||||||
fromJson:
|
return cached;
|
||||||
(json) => (json as List).map((e) => CPRes.fromJson(e)).toList(),
|
|
||||||
);
|
|
||||||
_cpDebugLog(
|
|
||||||
'pair response relationType=$relationType count=${result.length} '
|
|
||||||
'pairs=${result.map(_cpPairSummary).toList()}',
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
|
||||||
_cpDebugLog('pair failed relationType=$relationType error=$error');
|
|
||||||
rethrow;
|
|
||||||
}
|
}
|
||||||
|
final inFlight = _cpPairsInFlight[cacheKey];
|
||||||
|
if (inFlight != null) {
|
||||||
|
_cpDebugLog('pair join in-flight relationType=$normalizedRelationType');
|
||||||
|
return inFlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cpDebugLog('pair request relationType=$normalizedRelationType');
|
||||||
|
final requestEpoch = _cpRelationCacheEpoch;
|
||||||
|
late final Future<List<CPRes>> trackedRequest;
|
||||||
|
trackedRequest = http
|
||||||
|
.get<List<CPRes>>(
|
||||||
|
"/user/cp-relationship/pair",
|
||||||
|
queryParams: {"relationType": normalizedRelationType},
|
||||||
|
fromJson:
|
||||||
|
(json) => (json as List).map((e) => CPRes.fromJson(e)).toList(),
|
||||||
|
)
|
||||||
|
.then((result) {
|
||||||
|
if (requestEpoch == _cpRelationCacheEpoch) {
|
||||||
|
_cpPairsCache[cacheKey] = _CpRequestCacheEntry(
|
||||||
|
result,
|
||||||
|
DateTime.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_cpDebugLog(
|
||||||
|
'pair response relationType=$normalizedRelationType count=${result.length} '
|
||||||
|
'pairs=${result.map(_cpPairSummary).toList()}',
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.catchError((error) {
|
||||||
|
_cpDebugLog(
|
||||||
|
'pair failed relationType=$normalizedRelationType error=$error',
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
.whenComplete(() {
|
||||||
|
if (_cpPairsInFlight[cacheKey] == trackedRequest) {
|
||||||
|
_cpPairsInFlight.remove(cacheKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_cpPairsInFlight[cacheKey] = trackedRequest;
|
||||||
|
return trackedRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
///user/cp-relationship/send-apply
|
///user/cp-relationship/send-apply
|
||||||
@ -1308,6 +1403,7 @@ class SCAccountRepository implements SocialChatUserRepository {
|
|||||||
allowNullBody: true,
|
allowNullBody: true,
|
||||||
fromJson: (json) => json,
|
fromJson: (json) => json,
|
||||||
);
|
);
|
||||||
|
_clearCpRelationRequestCache();
|
||||||
_cpDebugLog('sendApply success data=$parm');
|
_cpDebugLog('sendApply success data=$parm');
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -1330,6 +1426,7 @@ class SCAccountRepository implements SocialChatUserRepository {
|
|||||||
allowNullBody: true,
|
allowNullBody: true,
|
||||||
fromJson: (json) => json,
|
fromJson: (json) => json,
|
||||||
);
|
);
|
||||||
|
_clearCpRelationRequestCache();
|
||||||
_cpDebugLog('processApply success data=$parm');
|
_cpDebugLog('processApply success data=$parm');
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -1355,6 +1452,7 @@ class SCAccountRepository implements SocialChatUserRepository {
|
|||||||
allowNullBody: true,
|
allowNullBody: true,
|
||||||
fromJson: (json) => json,
|
fromJson: (json) => json,
|
||||||
);
|
);
|
||||||
|
_clearCpRelationRequestCache();
|
||||||
_cpDebugLog('dismissApply success query=$parm');
|
_cpDebugLog('dismissApply success query=$parm');
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -1413,22 +1511,52 @@ class SCAccountRepository implements SocialChatUserRepository {
|
|||||||
String userId, {
|
String userId, {
|
||||||
String relationType = 'CP',
|
String relationType = 'CP',
|
||||||
}) async {
|
}) async {
|
||||||
final query = {"userId": userId, "relationType": relationType};
|
final normalizedRelationType = _normalizedCpRelationType(relationType);
|
||||||
_cpDebugLog('cabin request query=$query');
|
final query = {"userId": userId, "relationType": normalizedRelationType};
|
||||||
try {
|
final cacheKey = _cpCabinCacheKey(userId, normalizedRelationType);
|
||||||
final result = await http.get<SCCpCabinRes>(
|
final cached = _freshCpCacheValue(_cpCabinCache, cacheKey);
|
||||||
"/user/cp/cabin",
|
if (cached != null) {
|
||||||
queryParams: query,
|
_cpDebugLog('cabin cache hit query=$query');
|
||||||
fromJson: (json) => SCCpCabinRes.fromJson(json),
|
return cached;
|
||||||
);
|
|
||||||
_cpDebugLog(
|
|
||||||
'cabin response query=$query result=${_cpCabinSummary(result)}',
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
|
||||||
_cpDebugLog('cabin failed query=$query error=$error');
|
|
||||||
rethrow;
|
|
||||||
}
|
}
|
||||||
|
final inFlight = _cpCabinInFlight[cacheKey];
|
||||||
|
if (inFlight != null) {
|
||||||
|
_cpDebugLog('cabin join in-flight query=$query');
|
||||||
|
return inFlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cpDebugLog('cabin request query=$query');
|
||||||
|
final requestEpoch = _cpRelationCacheEpoch;
|
||||||
|
late final Future<SCCpCabinRes> trackedRequest;
|
||||||
|
trackedRequest = http
|
||||||
|
.get<SCCpCabinRes>(
|
||||||
|
"/user/cp/cabin",
|
||||||
|
queryParams: query,
|
||||||
|
fromJson: (json) => SCCpCabinRes.fromJson(json),
|
||||||
|
)
|
||||||
|
.then((result) {
|
||||||
|
if (requestEpoch == _cpRelationCacheEpoch) {
|
||||||
|
_cpCabinCache[cacheKey] = _CpRequestCacheEntry(
|
||||||
|
result,
|
||||||
|
DateTime.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_cpDebugLog(
|
||||||
|
'cabin response query=$query result=${_cpCabinSummary(result)}',
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.catchError((error) {
|
||||||
|
_cpDebugLog('cabin failed query=$query error=$error');
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
.whenComplete(() {
|
||||||
|
if (_cpCabinInFlight[cacheKey] == trackedRequest) {
|
||||||
|
_cpCabinInFlight.remove(cacheKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_cpCabinInFlight[cacheKey] = trackedRequest;
|
||||||
|
return trackedRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
///user/cp/cabin/value
|
///user/cp/cabin/value
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user