You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
diplomatic-quarter/lib/vital_signs/vital_sign.dart

317 lines
10 KiB
Dart

import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:vital_sign_camera/vital_sign_camera.dart';
// import 'package:wakelock/wakelock.dart';
import '../uitl/translations_delegate_base.dart';
import 'components/scan_condition_checklist.dart';
import 'components/scan_status.dart';
import 'components/start_button.dart';
import 'result_screen.dart';
final UserInfo userInfo = UserInfo(
age: 30,
gender: Gender.male,
weight: 75, // kg, Optional
height: 164, // cm, Optional
waistCircumference: 83, // cm Optional
userId: 'dbd13e86-47f4-4a43-85f6-cf62fa750117');
final VitalSignCameraConfig config = VitalSignCameraConfig(
apiKey: 'nIsZO45woSXSfIxsL1t79MWeIpsnGQr6B941MSF2',
serverId: ServerId.awsEnterpriseProd);
class VitalSigns extends StatefulWidget {
const VitalSigns({super.key});
@override
State<VitalSigns> createState() => _VitalSignsState();
}
class _VitalSignsState extends State<VitalSigns> with RouteAware {
late final VitalSignCameraController _vitalSignCameraController;
late Future<CameraDevice?> cameraDevice;
@override
void initState() {
super.initState();
cameraDevice = getFrontCamera();
// Wakelock.enable(); // keep the screen awake
}
Future<CameraDevice?> getFrontCamera() async {
if (CameraPermissionStatus.authorized != await requestCameraPermission()) {
return null;
}
return queryCameraDevice(CameraPosition.front);
}
bool startedScanning =
false; // set true when start button is pressed, set false when health result is tapped or error occurs
bool isAllConditionsMet =
false; // check for the 6 scan conditions before enabling the start button
ScanConditions? _conditions;
GetHealthStage? _scanningStage;
double? _remainingTime;
Health? _healthResult;
NormalizedFaceBox? _normalizedFaceBox;
VideoFrameInfo? _videoFrameInfo;
dynamic _error;
int? _errorCode;
bool isCameraActive = true;
bool _showedHealthResult = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
// routeObserver.subscribe(this, ModalRoute.of(context)!);
}
@override
void dispose() {
// routeObserver.unsubscribe(this);
super.dispose();
}
@override
void didPushNext() {
setState(() {
isCameraActive = false;
});
}
@override
void didPopNext() {
setState(() {
isCameraActive = true;
startedScanning = false;
_healthResult = null;
});
}
@override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return AppScaffold(
isShowAppBar: true,
appBarTitle: TranslationBase.of(context).scanning,
showNewAppBar: true,
showNewAppBarTitle: true,
overrideUserLogin: true,
backgroundColor: Color(0xffF8F8F8),
body: Column(
children: [
if (_conditions != null)
ScanConditionChecklist(
deviceSize: deviceSize, conditions: _conditions!),
Expanded(
child: Stack(
children: [
VitalSignCamera(
onCreated: _onVitalSignCameraCreated,
isActive: isCameraActive,
userInfo: userInfo,
config: config,
device: cameraDevice,
onVideoFrameProcessed: _onVideoFrameProcessed),
Positioned.fill(
// child: CustomPaint(
// painter: OvalOverlayPainter(),
// ),
child: SvgPicture.asset(
"assets/images/svg/overlay.svg",
),
),
if (_scanningStage !=
GetHealthStage
.idle) // show remaining time count down during scan
ScanStatus(
stage: _scanningStage, remainingTime: _remainingTime),
Column(children: [
ScanConditionChecklist(
deviceSize: deviceSize, conditions: _conditions!),
if (_scanningStage == GetHealthStage.idle &&
isCameraActive) // show start button only when it is not scanning
StartButton(
onPressed: () {
setState(() {
_vitalSignCameraController.startScanning();
startedScanning = true;
_healthResult = null;
_showedHealthResult = false;
});
},
disabled: !isAllConditionsMet,
),
])
],
),
),
],
),
);
// return Scaffold(
// body: Stack(
// children: [
// VitalSignCamera(
// onCreated: _onVitalSignCameraCreated,
// isActive: isCameraActive,
// userInfo: userInfo,
// config: config,
// device: cameraDevice,
// onVideoFrameProcessed: _onVideoFrameProcessed),
// // A back button to navigate back to previous screen
// if (_scanningStage == GetHealthStage.idle && !startedScanning)
// BackHomeButton(
// onPressed: () {
// setState(() {
// isCameraActive = false;
// });
// Navigator.pop(context);
// },
// deviceSize: deviceSize),
// // A button to toggle isCameraActive
// if (_scanningStage == GetHealthStage.idle && !startedScanning)
// Button(
// onPressed: () {
// setState(() {
// isCameraActive = !isCameraActive;
// });
// },
// deviceSize: deviceSize,
// title: "Toggle isCameraActive",
// alignment: Alignment.topRight,
// margin: EdgeInsets.fromLTRB(
// 0, deviceSize.height * 0.05, deviceSize.width * 0.05, 0)),
// if (!isCameraActive)
// const Center(
// child: Text(
// "Camera is not active.",
// textAlign: TextAlign.center,
// ))
// else
// Stack(children: [
// if (_scanningStage == GetHealthStage.idle &&
// isCameraActive) // show start button only when it is not scanning
// StartButton(
// onPressed: () {
// setState(() {
// _vitalSignCameraController.startScanning();
// startedScanning = true;
// _healthResult = null;
// _showedHealthResult = false;
// });
// },
// disabled: !isAllConditionsMet,
// ),
// if (_conditions != null &&
// _scanningStage == GetHealthStage.idle &&
// !startedScanning) // show scan conditions checking only when it is not scanning or showing health result
// ScanConditionChecklist(
// deviceSize: deviceSize, conditions: _conditions!),
// if (_scanningStage !=
// GetHealthStage
// .idle) // show remaining time count down during scan
// ScanStatus(
// stage: _scanningStage, remainingTime: _remainingTime),
// if (!startedScanning ||
// _healthResult ==
// null) // show bounding box before and during scan, but not when health result is shown
// BoundingBoxWidget(
// deviceSize: deviceSize,
// facebox: _normalizedFaceBox,
// videoFrameInfo: _videoFrameInfo),
// if (_error != null) Error(error: _error, errorCode: _errorCode),
// ])
// ],
// ),
// );
}
void _onVideoFrameProcessed(VideoFrameProcessedEvent event) {
if (!_showedHealthResult &&
_healthResult == null &&
event.healthResult?.health != null) {
_showedHealthResult = true;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultScreen(
healthResult: _healthResult,
),
),
);
}
setState(() {
_conditions = event.scanConditions;
isAllConditionsMet = checkIfAllScanConditionsMet();
_scanningStage = event.healthResult?.stage;
_remainingTime = event.healthResult?.remainingTime;
_healthResult = event.healthResult?.health;
_normalizedFaceBox = event.faceBox;
_videoFrameInfo = event.videoFrameInfo;
_error = event.healthResult?.error;
_errorCode = event.healthResult?.errorCode;
if (_error != null) {
// when error occurs, reshow condition checklist & disabled start button
startedScanning = false;
isAllConditionsMet = false;
}
});
}
bool checkIfAllScanConditionsMet() {
if (_conditions?.centered == true &&
_conditions?.distance == true &&
_conditions?.frameRate == true &&
_conditions?.lighting == true &&
_conditions?.movement == true &&
_conditions?.serverReady == true) {
return true;
} else {
return false;
}
}
void _onVitalSignCameraCreated(VitalSignCameraController controller) {
_vitalSignCameraController = controller;
}
}
class OvalOverlayPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Paint overlayPaint = Paint()
..color = Colors.white.withOpacity(0.7)
..style = PaintingStyle.fill;
canvas.drawRect(
Rect.fromLTWH(0, 0, size.width, size.height),
overlayPaint,
);
final Rect ovalRect = Rect.fromCenter(
center: Offset(size.width / 2, size.height / 2),
width: size.width * 0.9,
height: size.height * 0.7,
);
final Path ovalPath = Path()..addOval(ovalRect);
canvas.clipPath(ovalPath, doAntiAlias: true);
canvas.drawRect(
Rect.fromLTWH(0, 0, size.width, size.height),
Paint()..blendMode = BlendMode.clear,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}