import 'dart:async'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:pj_supermarket_cloud/common/index.dart'; import 'package:pj_supermarket_cloud/pages/terminal/setting/controller.dart'; import 'package:pj_supermarket_cloud/pages/terminal/setting/routes/navigation.dart'; /// 管理人脸插件状态、激活和内存库重建,避免硬件状态继续堆叠到设置主 Controller。 class FaceSettingController extends GetxController { static const String _tag = '人脸设置 Controller'; final status = Rxn(); final progress = Rxn(); final lastResult = Rxn(); final isLoading = false.obs; final isActivating = false.obs; final isRegistering = false.obs; final isSyncingConfig = false.obs; final errorMessage = ''.obs; final permissionCanOpenSettings = false.obs; final showFullParameters = false.obs; final recognitionConfiguration = Rxn(); final savedRecognitionConfiguration = Rxn(); final isLoadingRecognitionConfiguration = false.obs; final isSavingRecognitionConfiguration = false.obs; final showAdvancedRecognitionConfiguration = false.obs; StreamSubscription? _progressSubscription; @override void onInit() { super.onInit(); _progressSubscription = FaceDiscernPlugs.registrationStream.listen( _handleProgress, onError: (Object error, StackTrace stack) { logger.w('|$_tag|进度监听失败error:|$error|stack:|$stack|'); }, ); refreshStatus(); refreshRecognitionConfiguration(); } @override void onClose() { _progressSubscription?.cancel(); super.onClose(); } Future refreshStatus({bool showLoading = true}) async { if (showLoading) isLoading.value = true; errorMessage.value = ''; try { final value = await AppFaceTool.getStatus(); if (value == null) { errorMessage.value = '无法读取人脸插件状态,请稍后重试'; return; } status.value = value; progress.value = value.registrationProgress; lastResult.value = value.lastRegistrationResult; isRegistering.value = value.registrationInProgress; } catch (e, stack) { errorMessage.value = '无法读取人脸插件状态,请稍后重试'; logger.e('|$_tag|刷新状态失败error:|$e|stack:|$stack|'); } finally { if (showLoading) isLoading.value = false; } } Future refreshRecognitionConfiguration() async { if (isLoadingRecognitionConfiguration.value) return; isLoadingRecognitionConfiguration.value = true; try { final value = await FaceDiscernPlugs.getRecognizeConfiguration(); savedRecognitionConfiguration.value = value; recognitionConfiguration.value = value; } on PlatformException catch (e, stack) { logger.e('|$_tag|读取识别策略失败error:|$e|stack:|$stack|'); Toast.error(msg: e.message ?? '读取人脸识别策略失败'); } catch (e, stack) { logger.e('|$_tag|读取识别策略失败error:|$e|stack:|$stack|'); Toast.error(msg: '读取人脸识别策略失败'); } finally { isLoadingRecognitionConfiguration.value = false; } } void updateRecognitionConfiguration( FaceRecognitionConfiguration Function(FaceRecognitionConfiguration value) update, ) { final current = recognitionConfiguration.value; if (current == null || isSavingRecognitionConfiguration.value) return; recognitionConfiguration.value = update(current); } Future saveRecognitionConfiguration() async { final current = recognitionConfiguration.value; if (current == null || isSavingRecognitionConfiguration.value) return; isSavingRecognitionConfiguration.value = true; try { final saved = await FaceDiscernPlugs.setRecognizeConfiguration(current); savedRecognitionConfiguration.value = saved; recognitionConfiguration.value = saved; final active = Get.isRegistered() && Get.find().isActive; Toast.success( msg: active ? '配置已保存,将在当前识别结束后生效' : '人脸识别配置已保存', ); } on PlatformException catch (e, stack) { logger.e('|$_tag|保存识别策略失败error:|$e|stack:|$stack|'); Toast.error(msg: e.message ?? '保存人脸识别配置失败'); } catch (e, stack) { logger.e('|$_tag|保存识别策略失败error:|$e|stack:|$stack|'); Toast.error(msg: '保存人脸识别配置失败'); } finally { isSavingRecognitionConfiguration.value = false; } } Future restoreDefaultRecognitionConfiguration() async { if (isSavingRecognitionConfiguration.value) return; final confirmed = await appMessageDialog( Get.context!, '是否还原为默认人脸识别策略?活体检测将关闭,相似度阈值将还原为 80%。', ); if (!confirmed) return; isSavingRecognitionConfiguration.value = true; try { final restored = await FaceDiscernPlugs.resetRecognizeConfiguration(); savedRecognitionConfiguration.value = restored; recognitionConfiguration.value = restored; final active = Get.isRegistered() && Get.find().isActive; Toast.success( msg: active ? '已还原默认配置,将在当前识别结束后生效' : '已还原默认人脸识别配置', ); } on PlatformException catch (e, stack) { logger.e('|$_tag|还原识别策略失败error:|$e|stack:|$stack|'); Toast.error(msg: e.message ?? '还原默认配置失败'); } catch (e, stack) { logger.e('|$_tag|还原识别策略失败error:|$e|stack:|$stack|'); Toast.error(msg: '还原默认配置失败'); } finally { isSavingRecognitionConfiguration.value = false; } } void toggleAdvancedRecognitionConfiguration() { showAdvancedRecognitionConfiguration.toggle(); } bool get recognitionConfigurationChanged => recognitionConfiguration.value != savedRecognitionConfiguration.value; Future syncConfig() async { if (isBusy) return; if (!AppNetworkTool.isAutoNetworkMsg()) return; isSyncingConfig.value = true; errorMessage.value = ''; try { final setting = await SyncConfigTool.autoSyncSysInfo(); if (setting == null) { throw Exception('设备配置同步无返回'); } await Get.find().getSetting(); await refreshStatus(showLoading: false); Toast.success(msg: '设备配置同步完成'); } catch (e, stack) { errorMessage.value = '设备配置同步失败,请检查网络和设备绑定状态'; logger.e('|$_tag|同步设备配置失败error:|$e|stack:|$stack|'); Toast.error(msg: errorMessage.value); } finally { isSyncingConfig.value = false; } } Future activate() async { if (isBusy) return; isActivating.value = true; errorMessage.value = ''; permissionCanOpenSettings.value = false; try { final result = await AppFaceTool.activateSdk(); permissionCanOpenSettings.value = result.canOpenSettings; if (!result.success) { errorMessage.value = result.message; Toast.error(msg: result.message); return; } Toast.success(msg: result.message); await refreshStatus(showLoading: false); } catch (e, stack) { errorMessage.value = '人脸插件激活失败,请稍后重试'; logger.e('|$_tag|激活失败error:|$e|stack:|$stack|'); Toast.error(msg: errorMessage.value); } finally { isActivating.value = false; } } Future rebuildLibrary() async { if (isBusy) return; final currentStatus = status.value; if (currentStatus == null || !currentStatus.activated) { Toast.error(msg: '请先激活人脸插件'); return; } if (currentStatus.databaseCount == 0) { goFaceManage(); return; } final confirmed = await appMessageDialog( Get.context!, '是否重新注册全部人脸?注册期间可离开此页面,支付暂不能使用人脸识别。', ); if (!confirmed) return; isRegistering.value = true; errorMessage.value = ''; try { final result = await FaceDiscernPlugs.rebuildFaceLibrary(); lastResult.value = result; if (result.failedCount > 0) { errorMessage.value = result.message; Toast.error(msg: result.message); } else { Toast.success(msg: result.message); } } on PlatformException catch (e, stack) { errorMessage.value = e.code == 'REGISTRATION_IN_PROGRESS' ? '人脸库正在注册,请稍候' : (e.message ?? '人脸库注册失败,请稍后重试'); logger.e('|$_tag|重建人脸库失败error:|$e|stack:|$stack|'); Toast.error(msg: errorMessage.value); } catch (e, stack) { errorMessage.value = '人脸库注册失败,请稍后重试'; logger.e('|$_tag|重建人脸库失败error:|$e|stack:|$stack|'); Toast.error(msg: errorMessage.value); } finally { isRegistering.value = false; await refreshStatus(showLoading: false); } } Future openPermissionSettings() async { await openAppSettings(); } /// 从人脸插件诊断页切换到独立的人脸管理路由。 void goFaceManage() { SettingNavigation.openMenu(SettingMenuType.faceSetting); } void toggleParameterVisibility() { showFullParameters.toggle(); } SysSetting? get sysSetting => Get.find().sysSetting.value; bool get isBusy => isLoading.value || isActivating.value || isRegistering.value || isSyncingConfig.value || isSavingRecognitionConfiguration.value; void _handleProgress(FaceRegistrationProgress value) { progress.value = value; isRegistering.value = value.inProgress; if (!value.inProgress && value.phase != 'idle') { refreshStatus(showLoading: false); } } }