280 lines
10 KiB
Dart
280 lines
10 KiB
Dart
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<FacePluginStatus>();
|
|
final progress = Rxn<FaceRegistrationProgress>();
|
|
final lastResult = Rxn<FaceRegistrationResult>();
|
|
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<FaceRecognitionConfiguration>();
|
|
final savedRecognitionConfiguration = Rxn<FaceRecognitionConfiguration>();
|
|
final isLoadingRecognitionConfiguration = false.obs;
|
|
final isSavingRecognitionConfiguration = false.obs;
|
|
final showAdvancedRecognitionConfiguration = false.obs;
|
|
|
|
StreamSubscription<FaceRegistrationProgress>? _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<void> 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<void> 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<void> 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<FaceRecognitionSessionService>() &&
|
|
Get.find<FaceRecognitionSessionService>().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<void> 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<FaceRecognitionSessionService>() &&
|
|
Get.find<FaceRecognitionSessionService>().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<void> 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<SettingController>().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<void> 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<void> 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<void> openPermissionSettings() async {
|
|
await openAppSettings();
|
|
}
|
|
|
|
/// 从人脸插件诊断页切换到独立的人脸管理路由。
|
|
void goFaceManage() {
|
|
SettingNavigation.openMenu(SettingMenuType.faceSetting);
|
|
}
|
|
|
|
void toggleParameterVisibility() {
|
|
showFullParameters.toggle();
|
|
}
|
|
|
|
SysSetting? get sysSetting => Get.find<SettingController>().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);
|
|
}
|
|
}
|
|
}
|