import 'package:ducafe_ui_core/ducafe_ui_core.dart'; import 'package:flutter/material.dart'; import 'package:pj_supermarket_cloud/common/models/plugs/face_recognition_session_models.dart'; import 'package:pj_supermarket_cloud/common/style/xfj_design_tokens.dart'; import 'package:pj_supermarket_cloud/common/widgets/face/face_recognition_preview_layer.dart'; /// 人脸摄像头画面组件,只负责 Texture、人脸框、摄像头状态和空画面提示。 class FaceCameraPreview extends StatelessWidget { /// 创建一个不持有识别会话和插件资源的摄像头展示区域。 const FaceCameraPreview({ super.key, required this.texture, required this.event, required this.status, this.statusText, this.statusColor, this.scale = 1, }); /// 原生创建的预览纹理;为空时展示摄像头准备状态。 final FaceRecognitionPreviewTexture? texture; /// 最近一次原生识别事件,用于绘制人脸框和方向信息。 final FaceRecognitionSessionEvent? event; /// 当前识别状态,用于展示文字和非颜色状态标识。 final FaceRecognitionSessionStatus status; /// 业务页面覆盖的摄像头状态文案;为空时沿用原生会话状态文案。 final String? statusText; /// 业务页面覆盖的摄像头状态颜色;为空时沿用原生会话状态颜色。 final Color? statusColor; /// 宿主 Engine 提供的尺寸缩放系数,副屏不得依赖主屏 ScreenUtil 全局状态。 final double scale; /// 构建固定比例的摄像头画面和状态浮层。 @override Widget build(BuildContext context) { return ColoredBox( color: const Color(0xFF102635), child: [ if (texture != null) FaceRecognitionPreviewLayer( texture: texture!, event: event, labelScale: scale, ) else _FaceCameraEmptyState(status: status, scale: scale), _FaceCameraStatusPill( status: status, text: statusText, color: statusColor, scale: scale, ).positioned( left: 18 * scale, top: 18 * scale, ), _FaceCameraResolutionLabel( texture: texture, scale: scale, ).positioned( right: 18 * scale, bottom: 16 * scale, ), ].toStack(fit: StackFit.expand), ); } } /// 摄像头 Texture 尚未创建时的明确等待或失败提示。 class _FaceCameraEmptyState extends StatelessWidget { /// 创建与当前识别状态匹配的空画面。 const _FaceCameraEmptyState({required this.status, required this.scale}); /// 决定展示加载反馈还是设备异常提示的会话状态。 final FaceRecognitionSessionStatus status; /// 宿主页面计算的尺寸缩放系数。 final double scale; /// 构建不会造成画面尺寸跳变的居中状态。 @override Widget build(BuildContext context) { final failed = status == FaceRecognitionSessionStatus.failed; return [ if (failed) Icon( Icons.videocam_off_rounded, color: Colors.white, size: 42 * scale, ) else SizedBox( width: 36 * scale, height: 36 * scale, child: const CircularProgressIndicator( color: Colors.white, strokeWidth: 3, ), ), SizedBox(height: 12 * scale), Text( failed ? '摄像头画面暂不可用' : '正在准备摄像头画面', style: TextStyle( color: Colors.white, fontSize: 16 * scale, fontWeight: FontWeight.w700, ), ), ].toColumn(mainAxisSize: MainAxisSize.min).center(); } } /// 摄像头左上角的文字状态标识,确保状态不只依赖红绿颜色表达。 class _FaceCameraStatusPill extends StatelessWidget { /// 创建当前识别阶段的状态标识。 const _FaceCameraStatusPill({ required this.status, required this.text, required this.color, required this.scale, }); /// 当前原生识别会话状态。 final FaceRecognitionSessionStatus status; /// 业务页面提供的可选状态文案。 final String? text; /// 业务页面提供的可选语义颜色。 final Color? color; /// 宿主页面计算的尺寸缩放系数。 final double scale; /// 构建包含状态点和文字的高对比标签。 @override Widget build(BuildContext context) { final resolvedText = text ?? switch (status) { FaceRecognitionSessionStatus.initializing => '初始化中', FaceRecognitionSessionStatus.success => '已识别', FaceRecognitionSessionStatus.failed => '需要重试', FaceRecognitionSessionStatus.cancelled => '已取消', _ => '识别中', }; final resolvedColor = color ?? switch (status) { FaceRecognitionSessionStatus.failed || FaceRecognitionSessionStatus.cancelled => XfjDesignTokens.danger, FaceRecognitionSessionStatus.initializing => XfjDesignTokens.warning, _ => XfjDesignTokens.success, }; return [ DecoratedBox( decoration: BoxDecoration( color: resolvedColor, shape: BoxShape.circle, ), ).width(10 * scale).height(10 * scale), SizedBox(width: 8 * scale), Text( resolvedText, style: TextStyle( color: Colors.white, fontSize: 14 * scale, fontWeight: FontWeight.w700, ), ), ] .toRow(mainAxisSize: MainAxisSize.min) .padding(horizontal: 14 * scale, vertical: 9 * scale) .decorated( color: Colors.black.withValues(alpha: 0.62), borderRadius: BorderRadius.circular(99), ); } } /// 摄像头右下角的实际纹理分辨率标签。 class _FaceCameraResolutionLabel extends StatelessWidget { /// 创建分辨率说明;纹理未就绪时使用插件既有默认分辨率。 const _FaceCameraResolutionLabel({ required this.texture, required this.scale, }); /// 当前预览纹理元数据。 final FaceRecognitionPreviewTexture? texture; /// 宿主页面计算的尺寸缩放系数。 final double scale; /// 构建不遮挡主要人脸区域的紧凑标签。 @override Widget build(BuildContext context) { return Text( '彩色摄像头 ${texture?.width ?? 1280} x ${texture?.height ?? 720}', style: TextStyle(color: Colors.white, fontSize: 13 * scale), ).padding(horizontal: 12 * scale, vertical: 8 * scale).decorated( color: Colors.black.withValues(alpha: 0.62), borderRadius: BorderRadius.circular(10), ); } }