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'; 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 createState() => _VitalSignsState(); } class _VitalSignsState extends State with RouteAware { late final VitalSignCameraController _vitalSignCameraController; late Future cameraDevice; @override void initState() { super.initState(); cameraDevice = getFrontCamera(); // Wakelock.enable(); // keep the screen awake } Future 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 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; } } // load default void _onVitalSignCameraCreated(VitalSignCameraController controller) { _vitalSignCameraController = controller; } }