flutter_integrated_whb/lib/pages/home/study/face_ecognition_page.dart

196 lines
5.6 KiB
Dart

import 'dart:async';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../http/ApiService.dart';
/// 人脸识别模式
enum FaceMode { auto, manual }
class FaceRecognitionPage extends StatefulWidget {
final String studentId;
final FaceMode mode;
const FaceRecognitionPage({
Key? key,
this.studentId = '',
required this.mode,
}) : super(key: key);
@override
_FaceRecognitionPageState createState() => _FaceRecognitionPageState();
}
class _FaceRecognitionPageState extends State<FaceRecognitionPage> {
CameraController? _cameraController;
Timer? _timer;
int _attempts = 0;
String _message = '';
String _tip = '请将人脸置于圆圈内';
static const int _maxAttempts = 8;
static const Duration _interval = Duration(seconds: 2);
bool get _isManualMode => widget.mode == FaceMode.manual;
@override
void initState() {
super.initState();
_initCamera();
}
@override
void dispose() {
_timer?.cancel();
_cameraController?.dispose();
super.dispose();
}
Future<void> _initCamera() async {
final cams = await availableCameras();
final front = cams.firstWhere((c) => c.lensDirection == CameraLensDirection.front);
_cameraController = CameraController(front, ResolutionPreset.medium, enableAudio: false);
await _cameraController!.initialize();
if (!mounted) return;
setState(() {});
if (!_isManualMode) {
_timer = Timer.periodic(_interval, (_) => _captureAndUpload());
}
}
Future<void> _captureAndUpload() async {
if (_isManualMode) {
setState(() => _message = '请将人脸置于圆圈内');
} else {
if (_attempts >= _maxAttempts) return _onTimeout();
_attempts++;
}
try {
final pic = await _cameraController!.takePicture();
final res = await ApiService.getUserFace(pic.path, widget.studentId);
if (res['result'] == 'success') {
_onSuccess();
} else {
setState(() => _message = '识别失败,请重试');
}
} catch (_) {
setState(() => _message = '发生错误,请重试');
}
}
Future<void> _captureAndReload() async {
setState(() => _message = '上传中...');
try {
final pic = await _cameraController!.takePicture();
final res = await ApiService.reloadMyFace(pic.path);
if (res['result'] == 'success') {
_onSuccess();
} else {
setState(() => _message = '验证失败,请重试');
}
} catch (_) {
setState(() => _message = '发生错误,请重试');
}
}
void _onSuccess() {
_timer?.cancel();
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('验证成功')));
Future.delayed(const Duration(milliseconds: 800), () => Navigator.of(context).pop(true));
}
void _onTimeout() {
_timer?.cancel();
setState(() => _message = '人脸超时,请重新识别!');
Future.delayed(const Duration(seconds: 3), () => Navigator.of(context).pop(false));
}
@override
Widget build(BuildContext context) {
if (_cameraController == null || !_cameraController!.value.isInitialized) {
return const Scaffold(
backgroundColor: Colors.white,
body: Center(child: CircularProgressIndicator()),
);
}
final previewSize = _cameraController!.value.previewSize!;
final previewAspect = previewSize.height / previewSize.width;
final radius = (screenWidth(context) - 100) / 2;
return Scaffold(
backgroundColor: Colors.white,
appBar: MyAppbar(title: '人脸识别'),
body: Stack(
children: [
Positioned.fill(child: Container(color: Colors.white)),
Transform.translate(
offset: const Offset(0, -100),
child: Stack(
children: [
Center(
child: ClipOval(
child: AspectRatio(
aspectRatio: previewAspect,
child: CameraPreview(_cameraController!),
),
),
),
Positioned.fill(
child: CustomPaint(
painter: _WhiteMaskPainter(radius: radius),
),
),
],
),
),
Align(
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.only(top: 250),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
_tip,
style: const TextStyle(fontSize: 18, color: Colors.black87),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
if (_isManualMode)
CustomButton(text: '拍照/上传', backgroundColor: Colors.blue,onPressed: _captureAndReload,)
],
),
),
),
],
),
);
}
}
class _WhiteMaskPainter extends CustomPainter {
final double radius;
_WhiteMaskPainter({required this.radius});
@override
void paint(Canvas canvas, Size size) {
canvas.saveLayer(Offset.zero & size, Paint());
canvas.drawRect(Offset.zero & size, Paint()..color = Colors.white);
canvas.drawCircle(
size.center(Offset.zero),
radius,
Paint()..blendMode = BlendMode.clear,
);
canvas.restore();
}
@override
bool shouldRepaint(covariant CustomPainter old) => false;
}