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

214 lines
7.0 KiB
Dart

import 'package:diplomaticquarterapp/vital_signs/result_screen.dart';
import 'package:flutter/material.dart';
import 'package:vital_sign_camera/vital_sign_camera.dart';
// import 'package:wakelock/wakelock.dart';
import 'components/bounding_box_widget.dart';
import 'components/error.dart';
import 'components/scan_condition_checklist.dart';
import 'components/scan_status.dart';
import 'components/start_button.dart';
import 'components/back_button.dart';
import 'components/button.dart';
// import 'result_screen.dart';
// import 'main.dart';
final UserInfo userInfo = UserInfo(
age: 30,
gender: Gender.male,
weight: 60,
// kg, Optional
height: 170,
// cm, Optional
waistCircumference: 71,
// 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 _showingResultPage = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
// routeObserver.subscribe(this, ModalRoute.of(context)!);
}
@override
void dispose() {
// routeObserver.unsubscribe(this);
super.dispose();
}
@override
void didPushNext() {
setState(() {
_showingResultPage = true;
isCameraActive = false;
});
}
@override
void didPopNext() {
setState(() {
isCameraActive = true;
startedScanning = false;
_healthResult = null;
_showingResultPage = false;
});
}
@override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
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;
});
},
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 (_showingResultPage) {
return;
}
if (_healthResult == null && event.healthResult?.health != null && event.healthResult?.stage == GetHealthStage.analyzingData) {
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;
}
}
// load default
void _onVitalSignCameraCreated(VitalSignCameraController controller) {
_vitalSignCameraController = controller;
}
}