bug fix
This commit is contained in:
parent
7bce08a3b4
commit
e9ee3e9c02
@ -581,6 +581,14 @@ class _SCMessageChatPageState extends State<SCMessageChatPage> {
|
||||
// 监听消息扩展更新
|
||||
onRecvMessageExtensionsChanged: (msgID, extensions) {
|
||||
for (var ext in extensions) {
|
||||
if (ext.extensionKey == scChatBubbleMessageExtensionKey) {
|
||||
_MessageItem.updateChatBubbleExtensionCache(
|
||||
msgID,
|
||||
ext.extensionValue,
|
||||
);
|
||||
setState(() {});
|
||||
continue;
|
||||
}
|
||||
if (ext.extensionKey == "packetID") {
|
||||
String packetID = ext.extensionValue;
|
||||
SCMessageUtils.redPacketFutureCache[packetID] =
|
||||
@ -985,6 +993,9 @@ class _SCMessageChatPageState extends State<SCMessageChatPage> {
|
||||
|
||||
class _MessageItem extends StatelessWidget {
|
||||
static bool _isOpeningCpInviteDialog = false;
|
||||
static final Map<String, Future<PropsResources?>>
|
||||
_chatBubbleExtensionFutures = {};
|
||||
static final Map<String, PropsResources?> _chatBubbleExtensionCache = {};
|
||||
|
||||
final V2TimMessage message;
|
||||
final V2TimMessage? preMessage;
|
||||
@ -2630,7 +2641,74 @@ class _MessageItem extends StatelessWidget {
|
||||
if (chatBubbleUrl.isNotEmpty) {
|
||||
return _buildVipTextBubble(content: content, imageUrl: chatBubbleUrl);
|
||||
}
|
||||
return _buildDefaultTextBubble(content);
|
||||
final msgID = message.msgID?.trim();
|
||||
if (msgID == null ||
|
||||
msgID.isEmpty ||
|
||||
message.elemType != MessageElemType.V2TIM_ELEM_TYPE_TEXT) {
|
||||
return _buildDefaultTextBubble(content);
|
||||
}
|
||||
return FutureBuilder<PropsResources?>(
|
||||
future: _chatBubbleFromMessageExtension(message),
|
||||
builder: (_, snapshot) {
|
||||
final extensionBubbleUrl = _resolveChatBubbleImageUrl(snapshot.data);
|
||||
if (extensionBubbleUrl.isNotEmpty) {
|
||||
return _buildVipTextBubble(
|
||||
content: content,
|
||||
imageUrl: extensionBubbleUrl,
|
||||
);
|
||||
}
|
||||
return _buildDefaultTextBubble(content);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static void updateChatBubbleExtensionCache(
|
||||
String msgID,
|
||||
String extensionValue,
|
||||
) {
|
||||
final id = msgID.trim();
|
||||
if (id.isEmpty) {
|
||||
return;
|
||||
}
|
||||
_chatBubbleExtensionCache[id] = scDecodeChatBubbleSnapshotValue(
|
||||
extensionValue,
|
||||
);
|
||||
_chatBubbleExtensionFutures.remove(id);
|
||||
}
|
||||
|
||||
Future<PropsResources?> _chatBubbleFromMessageExtension(
|
||||
V2TimMessage message,
|
||||
) {
|
||||
final msgID = message.msgID?.trim();
|
||||
if (msgID == null || msgID.isEmpty) {
|
||||
return Future.value(null);
|
||||
}
|
||||
if (_chatBubbleExtensionCache.containsKey(msgID)) {
|
||||
return Future.value(_chatBubbleExtensionCache[msgID]);
|
||||
}
|
||||
return _chatBubbleExtensionFutures.putIfAbsent(msgID, () async {
|
||||
if (message.isSupportMessageExtension == false) {
|
||||
_chatBubbleExtensionCache[msgID] = null;
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final result = await TencentImSDKPlugin.v2TIMManager
|
||||
.getMessageManager()
|
||||
.getMessageExtensions(msgID: msgID);
|
||||
final extensions = result.data ?? const <V2TimMessageExtension>[];
|
||||
for (final extension in extensions) {
|
||||
if (extension.extensionKey == scChatBubbleMessageExtensionKey) {
|
||||
final bubble = scDecodeChatBubbleSnapshotValue(
|
||||
extension.extensionValue,
|
||||
);
|
||||
_chatBubbleExtensionCache[msgID] = bubble;
|
||||
return bubble;
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
_chatBubbleExtensionCache[msgID] = null;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildDefaultTextBubble(String content) {
|
||||
|
||||
@ -776,14 +776,7 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
|
||||
targetGroupKey,
|
||||
targetUserIds,
|
||||
);
|
||||
return;
|
||||
}
|
||||
_handleStandardGiftComboVisuals(
|
||||
msg,
|
||||
giftPhoto,
|
||||
targetGroupKey,
|
||||
targetUserIds,
|
||||
);
|
||||
}
|
||||
|
||||
void _enqueueCpGiftFloatingIfNeeded(Msg msg) {
|
||||
@ -946,45 +939,6 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
|
||||
}
|
||||
}
|
||||
|
||||
void _handleStandardGiftComboVisuals(
|
||||
Msg msg,
|
||||
String giftPhoto,
|
||||
String? targetGroupKey,
|
||||
List<String> targetUserIds,
|
||||
) {
|
||||
if ((msg.number ?? 0) <= 0) {
|
||||
return;
|
||||
}
|
||||
if (!_shouldPlaySeatFlightGiftAnimation(msg) ||
|
||||
targetGroupKey == null ||
|
||||
targetUserIds.isEmpty ||
|
||||
giftPhoto.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final flightBatchKey = _buildGiftFlightBatchKey(msg, targetUserIds);
|
||||
if (targetUserIds.length > 1 &&
|
||||
!_markGiftFlightBatchForPlayback(flightBatchKey)) {
|
||||
return;
|
||||
}
|
||||
final sessionKey = _buildLuckyGiftComboSessionKey(msg, targetGroupKey);
|
||||
final session = _luckyGiftComboSessions.putIfAbsent(
|
||||
sessionKey,
|
||||
() => _LuckyGiftComboSession(),
|
||||
);
|
||||
session.endTimer?.cancel();
|
||||
session.clearQueueTimer?.cancel();
|
||||
|
||||
_enqueueTrackedSeatFlightAnimations(
|
||||
sessionKey: sessionKey,
|
||||
giftPhoto: giftPhoto,
|
||||
targetUserIds: targetUserIds,
|
||||
animationCount: _resolveTrackedAnimationCount(msg),
|
||||
batchKey: flightBatchKey,
|
||||
);
|
||||
|
||||
_scheduleGiftAnimationSessionEnd(sessionKey);
|
||||
}
|
||||
|
||||
void _handleLuckyGiftComboVisuals(
|
||||
Msg msg,
|
||||
String giftPhoto,
|
||||
@ -1357,26 +1311,6 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
|
||||
_giftVisualBatchDedupeTimers.clear();
|
||||
}
|
||||
|
||||
bool _shouldPlaySeatFlightGiftAnimation(Msg msg) {
|
||||
final gift = msg.gift;
|
||||
if (gift == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final giftPhoto = (gift.giftPhoto ?? "").trim();
|
||||
if (giftPhoto.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
final giftPhotoExt = _normalizedGiftResourceExtension(giftPhoto);
|
||||
if (_isAnimatedGiftResource(giftPhotoExt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final giftSourceUrl = (gift.giftSourceUrl ?? "").trim();
|
||||
final sourceExt = _normalizedGiftResourceExtension(giftSourceUrl);
|
||||
return !_isAnimatedGiftResource(sourceExt);
|
||||
}
|
||||
|
||||
bool _isAnimatedGiftResource(String extension) {
|
||||
return extension == ".svga" || extension == ".mp4" || extension == ".vap";
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation_result.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member_info.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_image_elem.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_extension.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_receipt.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_msg_create_info_result.dart';
|
||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart';
|
||||
@ -2644,14 +2645,18 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
if (createTextMessageRes.code == 0) {
|
||||
// 文本信息创建成功
|
||||
String id = createTextMessageRes.data!.id!;
|
||||
final chatBubble =
|
||||
AccountStorage().getCurrentUser()?.userProfile?.getChatBox();
|
||||
final chatBubbleCloudCustomData = scEncodeChatBubbleCloudCustomData(
|
||||
AccountStorage().getCurrentUser()?.userProfile?.getChatBox(),
|
||||
chatBubble,
|
||||
);
|
||||
final chatBubbleSnapshotValue = scEncodeChatBubbleSnapshotValue(
|
||||
chatBubble,
|
||||
);
|
||||
// 发送文本消息
|
||||
// 在sendMessage时,若只填写receiver则发个人用户单聊消息
|
||||
// 若只填写groupID则发群组消息
|
||||
// 若填写了receiver与groupID则发群内的个人用户,消息在群聊中显示,只有指定receiver能看见
|
||||
String receiveId = toConversation.userID!;
|
||||
V2TimValueCallback<V2TimMessage> sendMessageRes = await TencentImSDKPlugin
|
||||
.v2TIMManager
|
||||
.getMessageManager()
|
||||
@ -2660,11 +2665,20 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
receiver: toConversation.userID!, // 接收人id
|
||||
needReadReceipt: true,
|
||||
groupID: '', // 是否需要已读回执
|
||||
isSupportMessageExtension: chatBubbleSnapshotValue != null,
|
||||
cloudCustomData: chatBubbleCloudCustomData,
|
||||
);
|
||||
if (sendMessageRes.code == 0) {
|
||||
// 发送成功
|
||||
_onNew1v1Message(sendMessageRes.data);
|
||||
if (chatBubbleSnapshotValue != null) {
|
||||
unawaited(
|
||||
_setC2CChatBubbleMessageExtension(
|
||||
sendMessageRes.data?.msgID,
|
||||
chatBubbleSnapshotValue,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
SCTts.show(
|
||||
'create fail,code:${sendMessageRes.code},${sendMessageRes.desc}',
|
||||
@ -2673,6 +2687,33 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setC2CChatBubbleMessageExtension(
|
||||
String? msgID,
|
||||
String snapshotValue,
|
||||
) async {
|
||||
final id = msgID?.trim();
|
||||
if (id == null || id.isEmpty) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await TencentImSDKPlugin.v2TIMManager
|
||||
.getMessageManager()
|
||||
.setMessageExtensions(
|
||||
msgID: id,
|
||||
extensions: [
|
||||
V2TimMessageExtension(
|
||||
extensionKey: scChatBubbleMessageExtensionKey,
|
||||
extensionValue: snapshotValue,
|
||||
),
|
||||
],
|
||||
);
|
||||
} catch (error) {
|
||||
if (kDebugMode) {
|
||||
debugPrint('[chat_bubble] set extension failed msgID=$id error=$error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///发送单聊自定义消息
|
||||
Future<void> sendC2CCustomMsg(
|
||||
String msg,
|
||||
|
||||
@ -322,37 +322,82 @@ class SCConfigRepositoryImp implements SocialChatConfigRepository {
|
||||
///sys/version/manage/release/latest
|
||||
@override
|
||||
Future<SCVersionManageLatestRes> versionManageLatest() async {
|
||||
final result = await http.get<SCVersionManageLatestRes>(
|
||||
"ee9584f714ded864780e47dab2cf4a2e84ac21c90fcd0966a13d2ce9e8845eb8e580afbe66f9f0fef79429cd5c1e0687",
|
||||
fromJson: (json) {
|
||||
_debugVersionResponse('releaseLatest', json);
|
||||
return SCVersionManageLatestRes.fromJson(json);
|
||||
},
|
||||
);
|
||||
return result;
|
||||
const apiName = 'releaseLatest';
|
||||
const path = '/sys/version/manage/release/latest';
|
||||
const queryParams = <String, dynamic>{};
|
||||
_debugVersionRequest(apiName, path, queryParams);
|
||||
try {
|
||||
final result = await http.get<SCVersionManageLatestRes>(
|
||||
"ee9584f714ded864780e47dab2cf4a2e84ac21c90fcd0966a13d2ce9e8845eb8e580afbe66f9f0fef79429cd5c1e0687",
|
||||
queryParams: queryParams,
|
||||
fromJson: (json) {
|
||||
_debugVersionResponse(apiName, path, json);
|
||||
return SCVersionManageLatestRes.fromJson(json);
|
||||
},
|
||||
);
|
||||
return result;
|
||||
} catch (error) {
|
||||
_debugVersionError(apiName, path, queryParams, error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
///sys/version/manage/latest/review
|
||||
@override
|
||||
Future<VersionManageLatesReviewRes> versionManageLatestReview() async {
|
||||
final result = await http.get<VersionManageLatesReviewRes>(
|
||||
"ee9584f714ded864780e47dab2cf4a2e11ce42bdd061186d4efe3305b73f10fe574aff257ce7e668d08f4caccd1c6232",
|
||||
fromJson: (json) {
|
||||
_debugVersionResponse('latestReview', json);
|
||||
return VersionManageLatesReviewRes.fromJson(json);
|
||||
},
|
||||
);
|
||||
return result;
|
||||
const apiName = 'latestReview';
|
||||
const path = '/sys/version/manage/latest/review';
|
||||
const queryParams = <String, dynamic>{};
|
||||
_debugVersionRequest(apiName, path, queryParams);
|
||||
try {
|
||||
final result = await http.get<VersionManageLatesReviewRes>(
|
||||
"ee9584f714ded864780e47dab2cf4a2e11ce42bdd061186d4efe3305b73f10fe574aff257ce7e668d08f4caccd1c6232",
|
||||
queryParams: queryParams,
|
||||
fromJson: (json) {
|
||||
_debugVersionResponse(apiName, path, json);
|
||||
return VersionManageLatesReviewRes.fromJson(json);
|
||||
},
|
||||
);
|
||||
return result;
|
||||
} catch (error) {
|
||||
_debugVersionError(apiName, path, queryParams, error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void _debugVersionResponse(String name, dynamic json) {
|
||||
void _debugVersionRequest(
|
||||
String name,
|
||||
String path,
|
||||
Map<String, dynamic> queryParams,
|
||||
) {
|
||||
debugPrint(
|
||||
'[SCVersionUtils][API] $name request path=$path params=$queryParams',
|
||||
);
|
||||
}
|
||||
|
||||
void _debugVersionResponse(String name, String path, dynamic json) {
|
||||
try {
|
||||
debugPrint('[SCVersionUtils] $name rawBody=${jsonEncode(json)}');
|
||||
debugPrint(
|
||||
'[SCVersionUtils][API] $name response path=$path rawBody=${jsonEncode(json)}',
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('[SCVersionUtils] $name rawBody=$json encodeError=$e');
|
||||
debugPrint(
|
||||
'[SCVersionUtils][API] $name response path=$path rawBody=$json encodeError=$e',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _debugVersionError(
|
||||
String name,
|
||||
String path,
|
||||
Map<String, dynamic> queryParams,
|
||||
Object error,
|
||||
) {
|
||||
debugPrint(
|
||||
'[SCVersionUtils][API] $name failed path=$path params=$queryParams error=$error',
|
||||
);
|
||||
}
|
||||
|
||||
///sys/config/customer-service
|
||||
@override
|
||||
Future<SocialChatUserProfile> customerService() async {
|
||||
|
||||
@ -3,14 +3,19 @@ import 'dart:convert';
|
||||
import 'package:yumi/shared/business_logic/models/res/login_res.dart';
|
||||
|
||||
const String scChatBubbleCloudDataKey = 'scChatBubble';
|
||||
const String scChatBubbleMessageExtensionKey = scChatBubbleCloudDataKey;
|
||||
|
||||
String? scEncodeChatBubbleCloudCustomData(PropsResources? chatBubble) {
|
||||
if (!_hasChatBubbleImage(chatBubble)) {
|
||||
final snapshot = scChatBubbleSnapshotJson(chatBubble);
|
||||
if (snapshot == null) {
|
||||
return null;
|
||||
}
|
||||
return jsonEncode(<String, dynamic>{
|
||||
scChatBubbleCloudDataKey: chatBubble!.toJson(),
|
||||
});
|
||||
return jsonEncode(<String, dynamic>{scChatBubbleCloudDataKey: snapshot});
|
||||
}
|
||||
|
||||
String? scEncodeChatBubbleSnapshotValue(PropsResources? chatBubble) {
|
||||
final snapshot = scChatBubbleSnapshotJson(chatBubble);
|
||||
return snapshot == null ? null : jsonEncode(snapshot);
|
||||
}
|
||||
|
||||
PropsResources? scDecodeChatBubbleFromCloudCustomData(String? cloudCustomData) {
|
||||
@ -31,6 +36,48 @@ PropsResources? scDecodeChatBubbleFromCloudCustomData(String? cloudCustomData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PropsResources? scDecodeChatBubbleSnapshotValue(String? snapshotValue) {
|
||||
final raw = snapshotValue?.trim();
|
||||
if (raw == null || raw.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final decoded = jsonDecode(raw);
|
||||
if (decoded is Map) {
|
||||
return PropsResources.fromJson(decoded);
|
||||
}
|
||||
} catch (_) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, dynamic>? scChatBubbleSnapshotJson(PropsResources? resource) {
|
||||
if (!_hasChatBubbleImage(resource)) {
|
||||
return null;
|
||||
}
|
||||
final map = <String, dynamic>{};
|
||||
void put(String key, String? value) {
|
||||
final text = value?.trim();
|
||||
if (text != null && text.isNotEmpty) {
|
||||
map[key] = text;
|
||||
}
|
||||
}
|
||||
|
||||
put('id', resource?.id);
|
||||
put('name', resource?.name);
|
||||
put('type', resource?.type);
|
||||
put('cover', resource?.cover);
|
||||
put('expand', resource?.expand);
|
||||
put('sourceUrl', resource?.sourceUrl);
|
||||
put('imSendCoverUrl', resource?.imSendCoverUrl);
|
||||
put('imOpenedUrl', resource?.imOpenedUrl);
|
||||
put('imOpenedUrlTwo', resource?.imOpenedUrlTwo);
|
||||
put('imNotOpenedUrl', resource?.imNotOpenedUrl);
|
||||
put('roomSendCoverUrl', resource?.roomSendCoverUrl);
|
||||
put('roomOpenedUrl', resource?.roomOpenedUrl);
|
||||
put('roomNotOpenedUrl', resource?.roomNotOpenedUrl);
|
||||
return map;
|
||||
}
|
||||
|
||||
bool _hasChatBubbleImage(PropsResources? resource) {
|
||||
if (resource == null) {
|
||||
return false;
|
||||
|
||||
@ -29,10 +29,17 @@ class SCVersionUtils {
|
||||
'review=${_versionInfoDebug(versionInfo.review)} '
|
||||
'latest=${_versionInfoDebug(versionInfo.latest)}',
|
||||
);
|
||||
final review = _selectCurrentPlatformVersion(
|
||||
versionInfo.review,
|
||||
source: 'latestReview.review',
|
||||
);
|
||||
if (versionInfo.review != null) {
|
||||
SCGlobalConfig.isReview =
|
||||
"${versionInfo.review?.version}" == SCGlobalConfig.version;
|
||||
_debugLog('checkReview isReview=${SCGlobalConfig.isReview}');
|
||||
review != null && "${review.version}" == SCGlobalConfig.version;
|
||||
_debugLog(
|
||||
'checkReview isReview=${SCGlobalConfig.isReview} '
|
||||
'selectedReview=${_versionInfoDebug(review)}',
|
||||
);
|
||||
}
|
||||
final latest = await _resolveLatestVersion(versionInfo.latest);
|
||||
final shouldForceUpdate = latest != null && _shouldForceUpdate(latest);
|
||||
@ -96,20 +103,56 @@ class SCVersionUtils {
|
||||
static Future<SCVersionManageLatestRes?> _resolveLatestVersion(
|
||||
SCVersionManageLatestRes? latest,
|
||||
) async {
|
||||
if (!_isVersionInfoEmpty(latest)) {
|
||||
return latest;
|
||||
final selectedLatest = _selectCurrentPlatformVersion(
|
||||
latest,
|
||||
source: 'latestReview.latest',
|
||||
);
|
||||
if (selectedLatest != null) {
|
||||
return selectedLatest;
|
||||
}
|
||||
_debugLog('checkReview latestReview latest empty, fallback releaseLatest');
|
||||
_debugLog(
|
||||
'checkReview latestReview latest unavailable for current platform, '
|
||||
'fallback releaseLatest',
|
||||
);
|
||||
try {
|
||||
final fallback = await SCConfigRepositoryImp().versionManageLatest();
|
||||
_debugLog('checkReview fallbackLatest=${_versionInfoDebug(fallback)}');
|
||||
return _isVersionInfoEmpty(fallback) ? latest : fallback;
|
||||
return _selectCurrentPlatformVersion(fallback, source: 'releaseLatest');
|
||||
} catch (e) {
|
||||
_debugLog('checkReview fallback releaseLatest failed error=$e');
|
||||
return latest;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static SCVersionManageLatestRes? _selectCurrentPlatformVersion(
|
||||
SCVersionManageLatestRes? version, {
|
||||
required String source,
|
||||
}) {
|
||||
if (_isVersionInfoEmpty(version)) {
|
||||
_debugLog('checkReview ignore $source reason=empty');
|
||||
return null;
|
||||
}
|
||||
final currentVersion = version!;
|
||||
if (_isCurrentPlatformVersion(currentVersion)) {
|
||||
_debugLog(
|
||||
'checkReview select $source currentPlatform=${_currentPlatformName()} '
|
||||
'version=${currentVersion.version} '
|
||||
'buildVersion=${currentVersion.buildVersion} '
|
||||
'downloadUrl=${currentVersion.downloadUrl}',
|
||||
);
|
||||
return currentVersion;
|
||||
}
|
||||
_debugLog(
|
||||
'checkReview ignore $source reason=platform_mismatch '
|
||||
'currentPlatform=${_currentPlatformName()} '
|
||||
'responsePlatform=${currentVersion.platform} '
|
||||
'version=${currentVersion.version} '
|
||||
'buildVersion=${currentVersion.buildVersion} '
|
||||
'downloadUrl=${currentVersion.downloadUrl}',
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool _isVersionInfoEmpty(SCVersionManageLatestRes? version) {
|
||||
if (version == null) {
|
||||
return true;
|
||||
@ -145,6 +188,25 @@ class SCVersionUtils {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool _isCurrentPlatformVersion(SCVersionManageLatestRes version) {
|
||||
return _normalizePlatform(version.platform) == _currentPlatformKey();
|
||||
}
|
||||
|
||||
static String _currentPlatformName() {
|
||||
return Platform.isIOS ? 'iOS' : 'Android';
|
||||
}
|
||||
|
||||
static String _currentPlatformKey() {
|
||||
return Platform.isIOS ? 'ios' : 'android';
|
||||
}
|
||||
|
||||
static String _normalizePlatform(String? platform) {
|
||||
return (platform ?? '').trim().toLowerCase().replaceAll(
|
||||
RegExp(r'[^a-z0-9]'),
|
||||
'',
|
||||
);
|
||||
}
|
||||
|
||||
static List<int> _versionParts(String? version) {
|
||||
final normalized = version?.trim() ?? "";
|
||||
if (normalized.isEmpty) {
|
||||
@ -277,6 +339,14 @@ class SCVersionUtils {
|
||||
|
||||
static Future<void> _openUpdateUrl(SCVersionManageLatestRes latest) async {
|
||||
final url = _resolveDownloadUrl(latest);
|
||||
final urlSource =
|
||||
(latest.downloadUrl ?? "").trim().isNotEmpty
|
||||
? 'api_downloadUrl'
|
||||
: (Platform.isIOS ? 'local_appStore' : 'local_googlePlay');
|
||||
_debugLog(
|
||||
'openUpdateUrl currentPlatform=${_currentPlatformName()} '
|
||||
'responsePlatform=${latest.platform} source=$urlSource url=$url',
|
||||
);
|
||||
if (url.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user