You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
6.2 KiB
183 lines
6.2 KiB
import 'package:device_plugin_interface/device_plugin_interface.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
import '../../core/utils/logger.dart';
|
|
import '../../core/utils/version_compare.dart';
|
|
import '../../devices/device_hub.dart';
|
|
import '../../routes/app_routes.dart';
|
|
import '../models/appconfig.dart';
|
|
import '../models/appconfig_model.dart';
|
|
|
|
/// 连上设备后的固件升级检查(一次会话只提醒一次)——厂商无关。
|
|
///
|
|
/// 当前版本来自在线会话的 [DeviceInfo.firmwareVersion],最新版本来自
|
|
/// `user_getappconfig` 下发的产品配置(按设备名匹配)。
|
|
class OtaCheckService extends GetxService {
|
|
static const String _tag = 'OtaCheckService';
|
|
|
|
static bool _hasCheckedInCurrentSession = false;
|
|
static bool _isCheckingInProgress = false;
|
|
|
|
static OtaCheckService get to => Get.find<OtaCheckService>();
|
|
|
|
/// 重置检查状态(仅在应用重启时调用)
|
|
static void resetCheckStatus() {
|
|
_hasCheckedInCurrentSession = false;
|
|
_isCheckingInProgress = false;
|
|
}
|
|
|
|
bool shouldCheckOta() => !_hasCheckedInCurrentSession && !_isCheckingInProgress;
|
|
|
|
void _markAsChecked() {
|
|
_hasCheckedInCurrentSession = true;
|
|
_isCheckingInProgress = false;
|
|
}
|
|
|
|
bool _isCurrentlyOnHomePage() {
|
|
final currentRoute = Get.currentRoute;
|
|
return currentRoute == Routes.home || currentRoute == Routes.initial;
|
|
}
|
|
|
|
DBProduct? _findProduct(String name) {
|
|
if (!AppConfig.isInitialized()) return null;
|
|
final n = name.trim().toUpperCase();
|
|
if (n.isEmpty) return null;
|
|
for (final p in AppConfig.config.products) {
|
|
final pn = p.devicename.trim().toUpperCase();
|
|
if (pn.isEmpty) continue;
|
|
if (pn.contains(n) || n.contains(pn)) return p;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// 执行一次检查。[isFullyConnected] 为 false 直接跳过。返回是否真的检查了。
|
|
Future<bool> performOtaCheck(bool isFullyConnected) async {
|
|
bool isForceUpdate = false;
|
|
try {
|
|
if (!shouldCheckOta()) return false;
|
|
if (!isFullyConnected) return false;
|
|
if (!_isCurrentlyOnHomePage()) return false;
|
|
|
|
final session = DeviceHub.to.sessionWith(DeviceCapability.ota);
|
|
if (session == null) return false;
|
|
_isCheckingInProgress = true;
|
|
|
|
final currentVersion = session.info.firmwareVersion ?? '';
|
|
final product = _findProduct(session.info.name);
|
|
final latestVersion = product?.version?.split('+').first.trim() ?? '';
|
|
Logger.d(_tag, '当前版本: $currentVersion, 最新版本: $latestVersion');
|
|
|
|
final hasUpdate = latestVersion.isNotEmpty &&
|
|
(currentVersion.isEmpty ||
|
|
VersionCompare.isNewer(latestVersion, currentVersion));
|
|
if (hasUpdate) {
|
|
isForceUpdate = product?.isforceupdate ?? false;
|
|
if (_isCurrentlyOnHomePage()) {
|
|
_showOtaUpgradeDialog(latestVersion);
|
|
}
|
|
} else {
|
|
Logger.d(_tag, '当前已是最新版本');
|
|
}
|
|
|
|
if (!isForceUpdate) _markAsChecked();
|
|
_isCheckingInProgress = false;
|
|
return true;
|
|
} catch (e) {
|
|
Logger.e(_tag, '检查OTA升级失败: $e');
|
|
if (!isForceUpdate) _markAsChecked();
|
|
_isCheckingInProgress = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void _showOtaUpgradeDialog(String latestVersion) {
|
|
if (!_isCurrentlyOnHomePage()) return;
|
|
final isDarkMode = Get.isDarkMode;
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.headset,
|
|
color: isDarkMode ? const Color(0xFF0066CC) : Colors.blue[600],
|
|
size: 24.sp,
|
|
),
|
|
SizedBox(width: 8.w),
|
|
Flexible(
|
|
child: Text(
|
|
'ota_newVersionFound'.tr,
|
|
style: TextStyle(
|
|
color: isDarkMode ? Colors.white : Colors.blue[700],
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 20.sp,
|
|
),
|
|
softWrap: true,
|
|
maxLines: 2,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'${'latestFirmwareVersion'.tr}: $latestVersion',
|
|
style: TextStyle(
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
|
|
fontWeight: FontWeight.w500,
|
|
fontSize: 16.sp,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
actions: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
TextButton(
|
|
onPressed: () => Get.back(),
|
|
child: Text(
|
|
'talkLater'.tr,
|
|
style: TextStyle(
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
|
|
),
|
|
),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
Get.toNamed(Routes.otaUpgrade);
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor:
|
|
isDarkMode ? const Color(0xFF0066CC) : Colors.blue[600],
|
|
foregroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8.sp),
|
|
),
|
|
side: isDarkMode
|
|
? BorderSide(color: Colors.grey[800]!, width: 1)
|
|
: BorderSide.none,
|
|
),
|
|
child: Text('ota_updateNow'.tr, style: TextStyle(fontSize: 14.sp)),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.sp)),
|
|
backgroundColor: isDarkMode ? const Color(0xFF1A1A1A) : Colors.white,
|
|
),
|
|
barrierDismissible: true,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> getCheckStatus() => {
|
|
'hasCheckedInCurrentSession': _hasCheckedInCurrentSession,
|
|
'isCheckingInProgress': _isCheckingInProgress,
|
|
'currentRoute': Get.currentRoute,
|
|
'isOnHomePage': _isCurrentlyOnHomePage(),
|
|
};
|
|
}
|
|
|