updates
parent
ff7afe5997
commit
a144d5fafe
Binary file not shown.
|
After Width: | Height: | Size: 520 B |
Binary file not shown.
|
After Width: | Height: | Size: 428 B |
@ -0,0 +1,28 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class BackHomeButton extends StatelessWidget {
|
||||||
|
final void Function() onPressed;
|
||||||
|
final Size deviceSize;
|
||||||
|
|
||||||
|
const BackHomeButton({
|
||||||
|
Key? key,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.deviceSize,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.fromLTRB(15, deviceSize.height * 0.05, 0, 0),
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_back),
|
||||||
|
color: Colors.white,
|
||||||
|
iconSize: 25,
|
||||||
|
onPressed: onPressed,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vital_sign_camera/vital_sign_camera.dart';
|
||||||
|
|
||||||
|
class BoundingBoxWidget extends StatelessWidget {
|
||||||
|
final Size deviceSize;
|
||||||
|
final NormalizedFaceBox? facebox;
|
||||||
|
final VideoFrameInfo? videoFrameInfo;
|
||||||
|
|
||||||
|
const BoundingBoxWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.deviceSize,
|
||||||
|
required this.facebox,
|
||||||
|
required this.videoFrameInfo,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (facebox == null || videoFrameInfo == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a map with left, top, width, and height of the bounding box for the face
|
||||||
|
Map boundingBox = computeBoundingBox();
|
||||||
|
|
||||||
|
return Positioned(
|
||||||
|
left: boundingBox['left'],
|
||||||
|
top: boundingBox['top'],
|
||||||
|
child: Container(
|
||||||
|
width: boundingBox['width'],
|
||||||
|
height: boundingBox['height'],
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.red,
|
||||||
|
width: 2,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to compute the left, top, width, and height of the bounding box
|
||||||
|
Map computeBoundingBox() {
|
||||||
|
double width = videoFrameInfo!.width;
|
||||||
|
double height = videoFrameInfo!.height;
|
||||||
|
double windowWidth = deviceSize.width;
|
||||||
|
double windowHeight = deviceSize.height;
|
||||||
|
|
||||||
|
double screenAspectRatio = deviceSize.aspectRatio;
|
||||||
|
double frameAspectRatio = width / height;
|
||||||
|
|
||||||
|
int xTransform = 1;
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
xTransform = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double scale = 1;
|
||||||
|
if (screenAspectRatio < frameAspectRatio) {
|
||||||
|
scale = windowHeight / height;
|
||||||
|
} else {
|
||||||
|
scale = windowWidth / width;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map scaledFrameBounds = {
|
||||||
|
'x': (windowWidth - scale * width) / 2,
|
||||||
|
'y': (windowHeight - scale * height) / 2,
|
||||||
|
'width': scale * width,
|
||||||
|
'height': scale * height,
|
||||||
|
};
|
||||||
|
|
||||||
|
double x = facebox!.xCenter - facebox!.width / 2;
|
||||||
|
double y = facebox!.yCenter - facebox!.height / 2;
|
||||||
|
|
||||||
|
if (xTransform < 0) {
|
||||||
|
x = 1 - x - facebox!.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map result = {
|
||||||
|
'left': scaledFrameBounds['x'] + x * scaledFrameBounds['width'],
|
||||||
|
'top': scaledFrameBounds['y'] + y * scaledFrameBounds['height'],
|
||||||
|
'width': facebox!.width * scaledFrameBounds['width'],
|
||||||
|
'height': facebox!.height * scaledFrameBounds['height'],
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Button extends StatelessWidget {
|
||||||
|
final void Function() onPressed;
|
||||||
|
final Size deviceSize;
|
||||||
|
final String title;
|
||||||
|
final Alignment alignment;
|
||||||
|
final EdgeInsets margin;
|
||||||
|
|
||||||
|
const Button({
|
||||||
|
Key? key,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.deviceSize,
|
||||||
|
required this.title,
|
||||||
|
required this.alignment,
|
||||||
|
required this.margin,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Align(
|
||||||
|
alignment: alignment,
|
||||||
|
child: Container(
|
||||||
|
margin: margin,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Error extends StatelessWidget {
|
||||||
|
final dynamic error;
|
||||||
|
final int? errorCode;
|
||||||
|
|
||||||
|
const Error({
|
||||||
|
Key? key,
|
||||||
|
this.error,
|
||||||
|
this.errorCode,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
"$error $errorCode",
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,222 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vital_sign_camera/vital_sign_camera.dart';
|
||||||
|
import 'vital_sign_widget.dart';
|
||||||
|
|
||||||
|
class HealthResultWidget extends StatelessWidget {
|
||||||
|
final Size deviceSize;
|
||||||
|
final void Function() onTap;
|
||||||
|
final Health? healthResult;
|
||||||
|
|
||||||
|
late final VitalSign? _vitalSign;
|
||||||
|
late final HolisticAnalysis? _holisticAnalysis;
|
||||||
|
late final CardiovascularRisks? _cardiovascularRisks;
|
||||||
|
late final CovidRisk? _covidRisk;
|
||||||
|
late final ScanParameters? _scanParameters;
|
||||||
|
|
||||||
|
HealthResultWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.deviceSize,
|
||||||
|
required this.onTap,
|
||||||
|
required this.healthResult,
|
||||||
|
}) : super(key: key) {
|
||||||
|
_vitalSign = healthResult?.vitalSigns;
|
||||||
|
_holisticAnalysis = healthResult?.holisticHealth;
|
||||||
|
_cardiovascularRisks = healthResult?.risks?.cardiovascularRisks;
|
||||||
|
_covidRisk = healthResult?.risks?.covidRisk;
|
||||||
|
_scanParameters = healthResult?.scanParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Positioned(
|
||||||
|
top: deviceSize.height * 0.07,
|
||||||
|
left: deviceSize.width * 0.05,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
child: SizedBox(
|
||||||
|
width: deviceSize.width * 0.9,
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black38,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 0, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Vital Signs",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Heart Rate",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.heartRate)),
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "SPO2",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.spo2)),
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "IBI",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.ibi)),
|
||||||
|
if (_vitalSign?.stress != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Stress",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.stress)),
|
||||||
|
if (_vitalSign?.respiratoryRate != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Respiratory Rate",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult
|
||||||
|
?.vitalSigns.respiratoryRate)),
|
||||||
|
if (_vitalSign?.hrvRmssd != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "HRV RMSSD",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.hrvRmssd)),
|
||||||
|
if (_vitalSign?.hrvSdnn != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "HRV SDNN",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.hrvSdnn)),
|
||||||
|
if (_vitalSign?.temperature != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Temperature",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.temperature)),
|
||||||
|
if (_vitalSign?.bloodPressure != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Blood Pressure",
|
||||||
|
vitalSignValue:
|
||||||
|
healthResult?.vitalSigns.bloodPressure ??
|
||||||
|
""),
|
||||||
|
if (_vitalSign?.bloodPressureSystolic != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Blood Pressure Systolic",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult
|
||||||
|
?.vitalSigns.bloodPressureSystolic)),
|
||||||
|
if (_vitalSign?.bloodPressureDiastolic != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Blood Pressure Diastolic",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult
|
||||||
|
?.vitalSigns.bloodPressureDiastolic)),
|
||||||
|
if (_holisticAnalysis != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Holistic Analysis",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.bmi != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "BMI",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.holisticHealth?.bmi)),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.generalWellness != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "General Wellness",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult
|
||||||
|
?.holisticHealth?.generalWellness)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Cardiovascular Risks",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "General",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.risks?.cardiovascularRisks
|
||||||
|
?.generalRisk)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Congestive Heart Failure",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.risks?.cardiovascularRisks
|
||||||
|
?.congestiveHeartFailure)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Coronary Heart Disease",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.risks?.cardiovascularRisks
|
||||||
|
?.coronaryHeartDisease)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Intermittent Claudication",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.risks?.cardiovascularRisks
|
||||||
|
?.intermittentClaudication)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Stroke",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.risks?.cardiovascularRisks
|
||||||
|
?.stroke)),
|
||||||
|
if (_covidRisk != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Covid Risks",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_covidRisk != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Risk",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult
|
||||||
|
?.risks?.covidRisk?.covidRisk)),
|
||||||
|
if (_scanParameters != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Scan Parameters",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_scanParameters != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
vitalSignName: "Signal Quality",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult
|
||||||
|
?.scanParameters?.signalQuality)),
|
||||||
|
])))),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatValueToTwoDp(double? value) {
|
||||||
|
return (value != null) ? value.toStringAsFixed(2) : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ScanCondition extends StatelessWidget {
|
||||||
|
final String scanConditionName;
|
||||||
|
final bool isConditionSatisfied;
|
||||||
|
|
||||||
|
const ScanCondition({
|
||||||
|
Key? key,
|
||||||
|
required this.scanConditionName, // condition
|
||||||
|
required this.isConditionSatisfied, // status
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 5, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
(isConditionSatisfied)
|
||||||
|
? Image.asset('assets/images/checkmark.png', width: 14)
|
||||||
|
: Image.asset('assets/images/crossmark.png', width: 14),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(5, 0, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
scanConditionName,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vital_sign_camera/vital_sign_camera.dart';
|
||||||
|
import 'scan_condition.dart';
|
||||||
|
|
||||||
|
class ScanConditionChecklist extends StatelessWidget {
|
||||||
|
final ScanConditions conditions; // ScanCondition
|
||||||
|
|
||||||
|
const ScanConditionChecklist({
|
||||||
|
Key? key,
|
||||||
|
required this.deviceSize,
|
||||||
|
required this.conditions, // ScanCondition
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Size deviceSize;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Positioned(
|
||||||
|
top: deviceSize.height * 0.12,
|
||||||
|
left: deviceSize.width * 0.05,
|
||||||
|
child: SizedBox(
|
||||||
|
width: deviceSize.width * 0.9,
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black38,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
"Scanning Conditions",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ScanCondition(
|
||||||
|
scanConditionName: "Lighting",
|
||||||
|
isConditionSatisfied: conditions.lighting,
|
||||||
|
),
|
||||||
|
ScanCondition(
|
||||||
|
scanConditionName: "Distance",
|
||||||
|
isConditionSatisfied: conditions.distance,
|
||||||
|
),
|
||||||
|
ScanCondition(
|
||||||
|
scanConditionName: "Centered",
|
||||||
|
isConditionSatisfied: conditions.centered,
|
||||||
|
),
|
||||||
|
ScanCondition(
|
||||||
|
scanConditionName: "Movement",
|
||||||
|
isConditionSatisfied: conditions.movement,
|
||||||
|
),
|
||||||
|
ScanCondition(
|
||||||
|
scanConditionName: "FrameRate",
|
||||||
|
isConditionSatisfied: conditions.frameRate,
|
||||||
|
),
|
||||||
|
ScanCondition(
|
||||||
|
scanConditionName: "Server Ready",
|
||||||
|
isConditionSatisfied: conditions.serverReady,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vital_sign_camera/vital_sign_camera.dart';
|
||||||
|
|
||||||
|
class ScanStatus extends StatelessWidget {
|
||||||
|
final GetHealthStage? stage;
|
||||||
|
final double? remainingTime;
|
||||||
|
|
||||||
|
const ScanStatus({
|
||||||
|
Key? key,
|
||||||
|
required this.stage,
|
||||||
|
required this.remainingTime,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
getRemainingTime(),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
getScanStage(),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(height: 100),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getScanStage() {
|
||||||
|
if (stage == GetHealthStage.waitingData) {
|
||||||
|
return 'Waiting Data...';
|
||||||
|
} else if (stage == GetHealthStage.collectingData) {
|
||||||
|
return 'Collecting Data...';
|
||||||
|
} else if (stage == GetHealthStage.analyzingData) {
|
||||||
|
return 'Analyzing Data...';
|
||||||
|
}
|
||||||
|
return ''; // idle
|
||||||
|
}
|
||||||
|
|
||||||
|
String getRemainingTime() {
|
||||||
|
return (remainingTime != null && remainingTime != double.infinity)
|
||||||
|
? remainingTime!.toStringAsFixed(0)
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class StartButton extends StatelessWidget {
|
||||||
|
final void Function() onPressed;
|
||||||
|
final bool disabled;
|
||||||
|
|
||||||
|
const StartButton({
|
||||||
|
Key? key,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.disabled,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 0, 0, 50),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: (disabled) ? () {} : onPressed,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
fixedSize: const Size(100, 100),
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
backgroundColor: (disabled) ? Colors.grey : Colors.orangeAccent,
|
||||||
|
elevation: 8,
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
"START",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class VitalSignWidget extends StatelessWidget {
|
||||||
|
final String vitalSignName;
|
||||||
|
final String vitalSignValue;
|
||||||
|
final Color? textColor;
|
||||||
|
|
||||||
|
const VitalSignWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.vitalSignName,
|
||||||
|
required this.vitalSignValue,
|
||||||
|
this.textColor,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 0, 0, 2),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
vitalSignName,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: textColor ?? Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
vitalSignValue,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: textColor ?? Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,270 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vital_sign_camera/vital_sign_camera.dart';
|
||||||
|
|
||||||
|
import 'components/vital_sign_widget.dart';
|
||||||
|
|
||||||
|
class ResultScreen extends StatelessWidget {
|
||||||
|
final Health? healthResult;
|
||||||
|
|
||||||
|
late final VitalSign? _vitalSign;
|
||||||
|
late final HolisticAnalysis? _holisticAnalysis;
|
||||||
|
late final CardiovascularRisks? _cardiovascularRisks;
|
||||||
|
late final CovidRisk? _covidRisk;
|
||||||
|
late final ScanParameters? _scanParameters;
|
||||||
|
|
||||||
|
ResultScreen({
|
||||||
|
Key? key,
|
||||||
|
required this.healthResult,
|
||||||
|
}) : super(key: key) {
|
||||||
|
_vitalSign = healthResult?.vitalSigns;
|
||||||
|
_holisticAnalysis = healthResult?.holisticHealth;
|
||||||
|
_cardiovascularRisks = healthResult?.risks?.cardiovascularRisks;
|
||||||
|
_covidRisk = healthResult?.risks?.covidRisk;
|
||||||
|
_scanParameters = healthResult?.scanParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final deviceSize = MediaQuery.of(context).size;
|
||||||
|
const textColor = Color.fromARGB(255, 0, 0, 0);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Result'),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: deviceSize.width * 0.9,
|
||||||
|
child: Container(
|
||||||
|
color: const Color.fromARGB(0, 255, 255, 255),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 0, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Vital Signs",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Heart Rate",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.heartRate)),
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "SPO2",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.spo2)),
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "IBI",
|
||||||
|
vitalSignValue:
|
||||||
|
formatValueToTwoDp(healthResult?.vitalSigns.ibi)),
|
||||||
|
if (_vitalSign?.stress != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Stress",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.stress)),
|
||||||
|
if (_vitalSign?.respiratoryRate != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Respiratory Rate",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.respiratoryRate)),
|
||||||
|
if (_vitalSign?.hrvRmssd != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "HRV RMSSD",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.hrvRmssd)),
|
||||||
|
if (_vitalSign?.hrvSdnn != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "HRV SDNN",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.hrvSdnn)),
|
||||||
|
if (_vitalSign?.temperature != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Temperature",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.vitalSigns.temperature)),
|
||||||
|
if (_vitalSign?.bloodPressure != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Blood Pressure",
|
||||||
|
vitalSignValue:
|
||||||
|
healthResult?.vitalSigns.bloodPressure ?? ""),
|
||||||
|
if (_vitalSign?.bloodPressureSystolic != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Blood Pressure Systolic",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.vitalSigns.bloodPressureSystolic)),
|
||||||
|
if (_vitalSign?.bloodPressureDiastolic != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Blood Pressure Diastolic",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.vitalSigns.bloodPressureDiastolic)),
|
||||||
|
if (_holisticAnalysis != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Holistic Analysis",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.bmi != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "BMI",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.holisticHealth?.bmi)),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.generalWellness != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "General Wellness",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.holisticHealth?.generalWellness)),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.absi != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "ABSI",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.holisticHealth?.absi)),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.cardiacWorkload != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Cardiac Workload",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.holisticHealth?.cardiacWorkload)),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.pulseRespiratoryQuotient != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Pulse Respiratory Quotient",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.holisticHealth?.pulseRespiratoryQuotient)),
|
||||||
|
if (_holisticAnalysis != null &&
|
||||||
|
_holisticAnalysis?.waistToHeightRatio != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Waist to Height Ratio",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.holisticHealth?.waistToHeightRatio)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Cardiovascular Risks",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "General",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.risks?.cardiovascularRisks?.generalRisk)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Congestive Heart Failure",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.risks
|
||||||
|
?.cardiovascularRisks
|
||||||
|
?.congestiveHeartFailure)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Coronary Heart Disease",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.risks
|
||||||
|
?.cardiovascularRisks
|
||||||
|
?.coronaryHeartDisease)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Intermittent Claudication",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.risks
|
||||||
|
?.cardiovascularRisks
|
||||||
|
?.intermittentClaudication)),
|
||||||
|
if (_cardiovascularRisks != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Stroke",
|
||||||
|
vitalSignValue: formatValueToTwoDp(healthResult
|
||||||
|
?.risks?.cardiovascularRisks?.stroke)),
|
||||||
|
if (_covidRisk != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Covid Risks",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_covidRisk != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Risk",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.risks?.covidRisk?.covidRisk)),
|
||||||
|
if (_scanParameters != null)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.fromLTRB(0, 25, 0, 10),
|
||||||
|
child: const Text(
|
||||||
|
"Scan Parameters",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.amber,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_scanParameters != null)
|
||||||
|
VitalSignWidget(
|
||||||
|
textColor: textColor,
|
||||||
|
vitalSignName: "Signal Quality",
|
||||||
|
vitalSignValue: formatValueToTwoDp(
|
||||||
|
healthResult?.scanParameters?.signalQuality)),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatValueToTwoDp(double? value) {
|
||||||
|
return (value != null) ? value.toStringAsFixed(2) : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
TODO: Add your license here.
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
/// Represents the pixel format of a `Frame`.
|
||||||
|
/// * `v420`: 420 YpCbCr 8 Bi-Planar Video Range
|
||||||
|
/// * `f420`: 420 YpCbCr 8 Bi-Planar Full Range
|
||||||
|
/// * `x420`: 420 YpCbCr 10 Bi-Planar Video Range
|
||||||
|
enum PixelFormat { f420, v420, x420 }
|
||||||
|
|
||||||
|
PixelFormat pixelFormatFromString(String string) {
|
||||||
|
switch (string) {
|
||||||
|
case '420f':
|
||||||
|
return PixelFormat.f420;
|
||||||
|
case '420v':
|
||||||
|
return PixelFormat.v420;
|
||||||
|
case 'x420':
|
||||||
|
return PixelFormat.x420;
|
||||||
|
default:
|
||||||
|
// ignore: fixme
|
||||||
|
return PixelFormat.f420;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
/// The vital signs result of a scan.
|
||||||
|
class VitalSign {
|
||||||
|
final double heartRate;
|
||||||
|
final double spo2;
|
||||||
|
final double ibi;
|
||||||
|
final double? stress;
|
||||||
|
final double? stressScore;
|
||||||
|
final double? respiratoryRate;
|
||||||
|
final double? hrvSdnn;
|
||||||
|
final double? hrvRmssd;
|
||||||
|
final double? temperature;
|
||||||
|
final String? bloodPressure;
|
||||||
|
final double? bloodPressureSystolic;
|
||||||
|
final double? bloodPressureDiastolic;
|
||||||
|
final double? facialSkinAge;
|
||||||
|
final double? bloodAlcohol;
|
||||||
|
final double? bloodSugar;
|
||||||
|
final String? version;
|
||||||
|
|
||||||
|
const VitalSign(
|
||||||
|
this.heartRate,
|
||||||
|
this.spo2,
|
||||||
|
this.ibi,
|
||||||
|
this.stress,
|
||||||
|
this.stressScore,
|
||||||
|
this.respiratoryRate,
|
||||||
|
this.hrvSdnn,
|
||||||
|
this.hrvRmssd,
|
||||||
|
this.temperature,
|
||||||
|
this.bloodPressure,
|
||||||
|
this.bloodPressureSystolic,
|
||||||
|
this.bloodPressureDiastolic,
|
||||||
|
this.facialSkinAge,
|
||||||
|
this.bloodAlcohol,
|
||||||
|
this.bloodSugar,
|
||||||
|
this.version);
|
||||||
|
|
||||||
|
factory VitalSign.fromMap(Map map) {
|
||||||
|
return VitalSign(
|
||||||
|
map['heartRate'],
|
||||||
|
map['spo2'],
|
||||||
|
map['ibi'],
|
||||||
|
map['stress'],
|
||||||
|
map['stressScore'],
|
||||||
|
map['respiratoryRate'],
|
||||||
|
map['hrvSdnn'],
|
||||||
|
map['hrvRmssd'],
|
||||||
|
map['temperature'],
|
||||||
|
map['bloodPressure'],
|
||||||
|
map['bloodPressureSystolic'],
|
||||||
|
map['bloodPressureDiastolic'],
|
||||||
|
map['facialSkinAge'],
|
||||||
|
map['bloodAlcohol'],
|
||||||
|
map['bloodSugar'],
|
||||||
|
map['version']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The cardiovascular risks result of a scan.
|
||||||
|
class CardiovascularRisks {
|
||||||
|
final double generalRisk;
|
||||||
|
final double coronaryHeartDisease;
|
||||||
|
final double congestiveHeartFailure;
|
||||||
|
final double intermittentClaudication;
|
||||||
|
final double stroke;
|
||||||
|
|
||||||
|
const CardiovascularRisks(this.generalRisk, this.coronaryHeartDisease,
|
||||||
|
this.congestiveHeartFailure, this.intermittentClaudication, this.stroke);
|
||||||
|
|
||||||
|
factory CardiovascularRisks.fromMap(Map map) {
|
||||||
|
return CardiovascularRisks(
|
||||||
|
map['generalRisk'],
|
||||||
|
map['coronaryHeartDisease'],
|
||||||
|
map['congestiveHeartFailure'],
|
||||||
|
map['intermittentClaudication'],
|
||||||
|
map['stroke']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The covid risk result of a scan.
|
||||||
|
class CovidRisk {
|
||||||
|
final double covidRisk;
|
||||||
|
|
||||||
|
const CovidRisk(this.covidRisk);
|
||||||
|
|
||||||
|
factory CovidRisk.fromMap(Map map) {
|
||||||
|
return CovidRisk(map['covidRisk']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The health risks result of a scan.
|
||||||
|
class HealthRisks {
|
||||||
|
final CardiovascularRisks? cardiovascularRisks;
|
||||||
|
final CovidRisk? covidRisk;
|
||||||
|
final String version;
|
||||||
|
|
||||||
|
const HealthRisks(this.cardiovascularRisks, this.covidRisk, this.version);
|
||||||
|
|
||||||
|
factory HealthRisks.fromMap(Map map) {
|
||||||
|
return HealthRisks(
|
||||||
|
map['cardiovascularRisks'] != null
|
||||||
|
? CardiovascularRisks.fromMap(map['cardiovascularRisks'])
|
||||||
|
: null,
|
||||||
|
map['covidRisk'] != null ? CovidRisk.fromMap(map['covidRisk']) : null,
|
||||||
|
map['version']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The holistic analysis result of a scan.
|
||||||
|
class HolisticAnalysis {
|
||||||
|
final double? generalWellness;
|
||||||
|
final double? bmi;
|
||||||
|
final double? absi;
|
||||||
|
final double? cardiacWorkload;
|
||||||
|
final double? pulseRespiratoryQuotient;
|
||||||
|
final double? waistToHeightRatio;
|
||||||
|
final String? version;
|
||||||
|
|
||||||
|
const HolisticAnalysis(
|
||||||
|
this.generalWellness,
|
||||||
|
this.bmi,
|
||||||
|
this.absi,
|
||||||
|
this.cardiacWorkload,
|
||||||
|
this.pulseRespiratoryQuotient,
|
||||||
|
this.waistToHeightRatio,
|
||||||
|
this.version);
|
||||||
|
|
||||||
|
factory HolisticAnalysis.fromMap(Map map) {
|
||||||
|
return HolisticAnalysis(
|
||||||
|
map['generalWellness'],
|
||||||
|
map['bmi'],
|
||||||
|
map['absi'],
|
||||||
|
map['cardiacWorkload'],
|
||||||
|
map['pulseRespiratoryQuotient'],
|
||||||
|
map['waistToHeightRatio'],
|
||||||
|
map['version']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||||
|
import 'camera_permission.dart';
|
||||||
|
|
||||||
|
import 'camera_device.dart';
|
||||||
|
import 'vital_sign_camera_method_channel.dart';
|
||||||
|
|
||||||
|
abstract class VitalSignCameraPlatform extends PlatformInterface {
|
||||||
|
/// Constructs a VitalSignCameraPlatform.
|
||||||
|
VitalSignCameraPlatform() : super(token: _token);
|
||||||
|
|
||||||
|
static final Object _token = Object();
|
||||||
|
|
||||||
|
static VitalSignCameraPlatform _instance = MethodChannelVitalSignCamera();
|
||||||
|
|
||||||
|
/// The default instance of [VitalSignCameraPlatform] to use.
|
||||||
|
///
|
||||||
|
/// Defaults to [MethodChannelVitalSignCamera].
|
||||||
|
static VitalSignCameraPlatform get instance => _instance;
|
||||||
|
|
||||||
|
/// Platform-specific implementations should set this with their own
|
||||||
|
/// platform-specific class that extends [VitalSignCameraPlatform] when
|
||||||
|
/// they register themselves.
|
||||||
|
static set instance(VitalSignCameraPlatform instance) {
|
||||||
|
PlatformInterface.verifyToken(instance, _token);
|
||||||
|
_instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<CameraDevice>> availableCameraDevices() {
|
||||||
|
throw UnimplementedError(
|
||||||
|
'availableCameraDevices() has not been implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<CameraPermissionStatus> requestCameraPermission() {
|
||||||
|
throw UnimplementedError(
|
||||||
|
'availableCameraDevices() has not been implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<CameraPermissionStatus> getCameraPermissionStatus() {
|
||||||
|
throw UnimplementedError(
|
||||||
|
'getCameraPermissionStatus() has not been implemented.');
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue