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(); /// 重置检查状态(仅在应用重启时调用) 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 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 getCheckStatus() => { 'hasCheckedInCurrentSession': _hasCheckedInCurrentSession, 'isCheckingInProgress': _isCheckingInProgress, 'currentRoute': Get.currentRoute, 'isOnHomePage': _isCurrentlyOnHomePage(), }; }