diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BPModelMeasuring.java b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BPModelMeasuring.java new file mode 100644 index 00000000..81c9e864 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BPModelMeasuring.java @@ -0,0 +1,17 @@ +package com.cloud.diplomaticquarterapp.ble; + +public class BPModelMeasuring { + + public int pressure; + public int pr; + public boolean deflate; + public boolean pulse; + + public BPModelMeasuring(int pressure, int pr, boolean deflate, boolean pulse) { + this.pressure = pressure; + this.pr = pr; + this.deflate = deflate; + this.pulse = pulse; + + } +} diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BPModelResult.java b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BPModelResult.java new file mode 100644 index 00000000..e07b6e42 --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BPModelResult.java @@ -0,0 +1,23 @@ +package com.cloud.diplomaticquarterapp.ble; + +public class BPModelResult { + + public boolean deflate; + public int dia; + public int mean; + public int pr; + public int pressure; + public int result; + public int sys; + + public BPModelResult(boolean deflate, int dia, int mean, int pr, int pressure, int result, int sys) { + this.deflate = deflate; + this.dia = dia; + this.mean = mean; + this.pr = pr; + this.pressure = pressure; + this.result = result; + this.sys = sys; + + } +} diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt index f73fed6e..681def83 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt @@ -10,6 +10,8 @@ import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.EventChannel import android.util.SparseArray import androidx.annotation.RequiresApi +import com.cloud.diplomaticquarterapp.ble.BPModelMeasuring +import com.cloud.diplomaticquarterapp.ble.BPModelResult import com.cloud.diplomaticquarterapp.ble.OxymeterModel import com.cloud.diplomaticquarterapp.ble.utils.EcgData import com.google.gson.Gson @@ -44,7 +46,6 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi private var eventSink: EventChannel.EventSink? = null private var ecgFileNames = arrayListOf() - private var bpFileNames = arrayListOf() var ecgList: ArrayList = arrayListOf() @@ -53,13 +54,13 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi companion object { private const val CHANNEL = "BLE-Platform-Bridge" private const val EVENTCHANNEL = "BLE-Platform-Bridge-Event" - private const val SCAN_DEVICE = "scan" + private const val SCAN_DEVICE = "scanDevices" private const val CONNECT_DEVICE = "connectDevice" private const val SCAN_DEVICE_EKG = "scan_ekg" - private const val EKG_FILES_LIST = "ekg_files_list" - private const val BP2_FILES_LIST = "bp2_files_list" - private const val EKG_FILE_DETAIL = "ekg_file_detail" - private const val DISCONNECT_DEVICE = "disconnect_device" + private const val EKG_FILES_LIST = "ecgFilesList" + private const val FACTORY_RESET_ECG = "factoryResetECG" + private const val BP2_FILES_LIST = "bp2FilesList" + private const val DISCONNECT_DEVICE = "disconnectDevice" } @@ -176,12 +177,11 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } else if (methodCall.method == SCAN_DEVICE_EKG) { // scanDeviceEKG(methodCall, result) } else if (methodCall.method == EKG_FILES_LIST) { - getEKGFilesList() + getECGFilesList(methodCall.arguments as List) + } else if (methodCall.method == FACTORY_RESET_ECG) { + factoryResetECG(methodCall.arguments as List) } else if (methodCall.method == BP2_FILES_LIST) { getBP2FilesList() - } else if (methodCall.method == EKG_FILE_DETAIL) { - val fileName = methodCall.arguments; - getEKGFileDetail(fileName.toString()) } else { result.notImplemented() } @@ -220,8 +220,8 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi LiveEventBus.get(EventMsgConst.Discovery.EventDeviceFound).observe(this.mainActivity) { val deviceName: String = "" - val returnData = mapOf("type" to "devicesList", "data" to gson.toJson(BluetoothController.getDevices())) - println("devicesList: ${BluetoothController.getDevices()}"); + val returnData = mapOf("type" to "DevicesList", "data" to gson.toJson(BluetoothController.getDevices())) + println("DevicesList: ${BluetoothController.getDevices()}"); eventSink?.success(returnData) println("EventDeviceFound") @@ -248,13 +248,13 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi val data = it.data as DeviceInfo println("DuoEK INFO DATA: $data") val returnData = mapOf("type" to "infoData", "data" to data.toString()) - eventSink?.success(returnData) + BleServiceHelper.BleServiceHelper.startRtTask(model) } LiveEventBus.get(InterfaceEvent.ER2.EventEr2FileList).observe(this.mainActivity) { BleServiceHelper.BleServiceHelper.stopRtTask(model) ecgFileNames = it.data as ArrayList - readFile() + readFileForEr2() // val fileNames = it.data as ArrayList // println("DuoEK FileNames List: ${fileNames}") // val returnData = @@ -288,13 +288,13 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } ecgFileNames.removeAt(0) - readFile() + readFileForEr2() } LiveEventBus.get(InterfaceEvent.ER2.EventEr2RtData).observe(this.mainActivity) { val data = it.data as RtData println("EventEr2RtData") - val returnData = mapOf("type" to "realtimeDataECG", "data" to gson.toJson(data)) + val returnData = mapOf("type" to "RealTimeDataECG", "data" to gson.toJson(data)) println(returnData) eventSink?.success(returnData) // DataController.receive(data.wave.ecgFloats) @@ -388,7 +388,10 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } LiveEventBus.get(InterfaceEvent.BP2.EventBp2FileList).observe(this.mainActivity) { - bpFileNames = it.data as ArrayList + BleServiceHelper.BleServiceHelper.stopRtTask(model) + ecgFileNames = it.data as ArrayList + println("EventBp2FileList: ${it.data}") + readFileForBp2() } LiveEventBus.get(InterfaceEvent.BP2.EventBp2ReadFileComplete).observe(this.mainActivity) { @@ -403,35 +406,18 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } else if (data.type == 2) { val file = EcgFile(data.content) + val ecgShorts = Er1Decompress.unCompressAlgECG(file.waveData) val ecgData = EcgData() val startTime = DateUtil.getSecondTimestamp(data.fileName) ecgData.fileName = data.fileName ecgData.duration = file.recordingTime - ecgData.shortData = Er1Decompress.unCompressAlgECG(file.waveData) -// ecgData.shortData = FilterUtil.getEcgFileFilterData(it.model, data.content) + ecgData.shortData = ecgShorts ecgData.startTime = startTime ecgList.add(ecgData) - // sampling rate:125HZ - // mV = file.waveShortData * 0.003098 - // file.measureTime:unit(s) - // file.recordingTime:unit(s) - // file.connectCable: Whether the cable is connected - // file.diagnosis:EcgDiagnosis - // diagnosis.isRegular:Whether Regular ECG Rhythm - // diagnosis.isPoorSignal:Whether Unable to analyze - // diagnosis.isLeadOff:Whether Always lead off - // diagnosis.isFastHr:Whether Fast Heart Rate - // diagnosis.isSlowHr:Whether Slow Heart Rate - // diagnosis.isIrregular:Whether Irregular ECG Rhythm - // diagnosis.isPvcs:Whether Possible ventricular premature beats - // diagnosis.isHeartPause:Whether Possible heart pause - // diagnosis.isFibrillation:Whether Possible Atrial fibrillation - // diagnosis.isWideQrs:Whether Wide QRS duration - // diagnosis.isProlongedQtc:Whether QTc is prolonged - // diagnosis.isShortQtc:Whether QTc is short - println("EcgFile : $file") + print(ecgList) + } - bpFileNames.removeAt(0) + ecgFileNames.removeAt(0) readFileForBp2() } @@ -450,20 +436,68 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi 0 -> { val bpIng = RtBpIng(data.param.paramData) - val returnData = mapOf("type" to "RealTimeDataBP2Measuring", "data" to gson.toJson(bpIng)) + //class BpRtMeasuringModel { + // bool deflate; + // int pr; + // int pressure; + // bool pulse; + val bpMeasuring = BPModelMeasuring(bpIng.pressure, bpIng.pr, bpIng.isDeflate, bpIng.isPulse); + + val returnData = mapOf("type" to "RealTimeDataBPMeasuring", "data" to gson.toJson(bpMeasuring)) eventSink?.success(returnData) } 1 -> { val bpResult = RtBpResult(data.param.paramData) - val returnData = mapOf("type" to "RealTimeDataBP2Result", "data" to gson.toJson(bpResult)) - println("RealTimeDataBP2Result FOR BP : $returnData") + val bpModel = BPModelResult(bpResult.isDeflate, bpResult.dia, bpResult.mean, bpResult.pr, bpResult.pressure, bpResult.result, bpResult.sys); + + val returnData = mapOf("type" to "RealTimeDataBPResult", "data" to gson.toJson(bpModel)) eventSink?.success(returnData) } + 2 -> { + val ecgIng = RtEcgIng(data.param.paramData) + val returnData = mapOf("type" to "RealTimeDataECGMeasuring", "data" to gson.toJson(ecgIng)) + println("RealTimeDataECGMeasuring: $returnData") + eventSink?.success(returnData) +// hr.text = "${ecgIng.hr}" +// data_log.text = "lead status:${if (ecgIng.isLeadOff) "lead off" else "lead on"}\n" + +// "pool signal:${if (ecgIng.isPoolSignal) "yes" else "no"}\n" + +// "duration: ${ecgIng.curDuration} s" +// DataController.receive(data.param.ecgFloatsFilter) + // sampling rate:250HZ + // mV = n * 0.003098 (data.param.ecgFloats = data.param.ecgShorts * 0.003098) + } + + 3 -> { + val ecgResult = RtEcgResult(data.param.paramData) + val returnData = mapOf("type" to "RealTimeDataECGResult", "data" to gson.toJson(ecgResult)) + println("RealTimeDataECGResult: $returnData") + eventSink?.success(returnData) +// hr.text = "${ecgResult.hr}" +// data_log.text = "result:${ecgResult.diagnosis.resultMess}\n" + +// "hr:${ecgResult.hr}\n" + +// "qrs:${ecgResult.qrs}\n" + +// "pvcs:${ecgResult.pvcs}\n" + +// "qtc:${ecgResult.qtc}" + // ecgResult.diagnosis:EcgDiagnosis + // diagnosis.isRegular:Whether Regular ECG Rhythm + // diagnosis.isPoorSignal:Whether Unable to analyze + // diagnosis.isLeadOff:Whether Always lead off + // diagnosis.isFastHr:Whether Fast Heart Rate + // diagnosis.isSlowHr:Whether Slow Heart Rate + // diagnosis.isIrregular:Whether Irregular ECG Rhythm + // diagnosis.isPvcs:Whether Possible ventricular premature beats + // diagnosis.isHeartPause:Whether Possible heart pause + // diagnosis.isFibrillation:Whether Possible Atrial fibrillation + // diagnosis.isWideQrs:Whether Wide QRS duration + // diagnosis.isProlongedQtc:Whether QTc is prolonged + // diagnosis.isShortQtc:Whether QTc is short + } + } @@ -474,6 +508,7 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } + @RequiresApi(Build.VERSION_CODES.Q) private fun connectDevice(device: List) { println("connectDevice: $device"); @@ -497,9 +532,9 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } - private fun readFile() { + private fun readFileForEr2() { if (ecgFileNames.size == 0) { - val returnData = mapOf("type" to "fileDetail", "data" to gson.toJson(ecgList)) + val returnData = mapOf("type" to "FileDetail", "data" to gson.toJson(ecgList)) eventSink?.success(returnData) } else { BleServiceHelper.BleServiceHelper.er2ReadFile(model, ecgFileNames[0]) @@ -508,26 +543,41 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi private fun readFileForBp2() { if (ecgFileNames.size == 0) { - val returnData = mapOf("type" to "fileDetail", "data" to gson.toJson(ecgList)) + val returnData = mapOf("type" to "FileDetail", "data" to gson.toJson(ecgList)) eventSink?.success(returnData) } else { - BleServiceHelper.BleServiceHelper.bp2ReadFile(model, bpFileNames[0]) + BleServiceHelper.BleServiceHelper.bp2ReadFile(model, ecgFileNames[0]) } } - private fun getEKGFilesList() { - //Get EKG File List - BleServiceHelper.BleServiceHelper.er2GetFileList(model) + private fun getECGFilesList(device: List) { + //Get ECG File List + val deviceName = device[0] + println("deviceName: $deviceName and model: $model") + + if (deviceName.contains("DuoEK")) { + BleServiceHelper.BleServiceHelper.er2GetFileList(model); + } else if (deviceName.contains("BP2")) { + BleServiceHelper.BleServiceHelper.bp2GetFileList(model); + } + } + + private fun factoryResetECG(device: List) { + val deviceName = device[0] + + println("deviceName: $deviceName and model: $model") + + if (deviceName.contains("DuoEK")) { + BleServiceHelper.BleServiceHelper.er2FactoryResetAll(model); + } else if (deviceName.contains("BP2")) { + BleServiceHelper.BleServiceHelper.bp2FactoryResetAll(model); + } } private fun getBP2FilesList() { - //Get EKG File List + //Get BP2 File List BleServiceHelper.BleServiceHelper.bp2GetFileList(model) } - private fun getEKGFileDetail(fileName: String) { -// readFile() -// BleServiceHelper.BleServiceHelper.er2ReadFile(model, fileName) - } } \ No newline at end of file diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart index 043a6956..070775bb 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart @@ -1,5 +1,7 @@ import 'dart:developer'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/device_types/oxymeter_connect_screen.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; @@ -30,6 +32,36 @@ class _BleDevicesScreenState extends State { super.initState(); } + bool getIfECGAvailableInBPDevice(String name) { + int index = myTrackersVm.ecgEnabledDevices.indexWhere((deviceName) => deviceName == name); + return index != -1; + } + + void onDeviceTapped(BleDeviceModel device) { + switch (device.deviceType) { + case TrackerTypeEnum.OxymeterTracker: + myTrackersVm.oxyRtModel = null; + Navigator.pushReplacement(context, FadePage(page: OxymeterConnectScreen(deviceModel: device))); + break; + case TrackerTypeEnum.BloodPressureTracker: + myTrackersVm.bpRtResultModel = null; + myTrackersVm.bpRtMeasuringModel = null; + myTrackersVm.bpCurrentStatus = null; + Navigator.pushReplacement(context, FadePage(page: BloodPressureConnectScreen(deviceModel: device, isEcgAvailable: getIfECGAvailableInBPDevice(device.name)))); + break; + case TrackerTypeEnum.BloodSugarTracker: + // TODO: Handle this case. + break; + case TrackerTypeEnum.ECGTracker: + myTrackersVm.ecgRtModel = null; + Navigator.pushReplacement(context, FadePage(page: ECGConnectScreen(deviceModel: device))); + break; + case TrackerTypeEnum.AllInOneTracker: + // TODO: Handle this case. + break; + } + } + @override Widget build(BuildContext context) { return AppScaffold( @@ -68,10 +100,7 @@ class _BleDevicesScreenState extends State { itemBuilder: (BuildContext context, int index) { BleDeviceModel device = myTrackerVm.devicesList[index]; return InkWell( - onTap: () { - myTrackerVm.oxyRtModel = null; - Navigator.pushReplacement(context, FadePage(page: OxymeterConnectScreen(deviceModel: device))); - }, + onTap: () => onDeviceTapped(device), child: MedicalProfileItem( title: "${device.name}", imagePath: 'tracker.svg', diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart index b96e9b4f..4a70468c 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart @@ -1,15 +1,20 @@ +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; +import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:flutter_toggle_tab/flutter_toggle_tab.dart'; class BloodPressureConnectScreen extends StatefulWidget { final BleDeviceModel deviceModel; + final bool isEcgAvailable; - const BloodPressureConnectScreen({this.deviceModel}); + const BloodPressureConnectScreen({this.deviceModel, this.isEcgAvailable = false}); @override State createState() => _BloodPressureConnectScreenState(); @@ -27,10 +32,286 @@ class _BloodPressureConnectScreenState extends State @override void dispose() { + myTrackersVm.bpCurrentStatus = null; + myTrackersVm.bpRtMeasuringModel = null; + myTrackersVm.bpRtResultModel = null; + myTrackersVm.ecgCurrentStatus = null; + myTrackersVm.ecgRtMeasuringModelFromBP = null; + myTrackersVm.ecgRtResultModelFromBP = null; myTrackersVm.disConnectDevice(); super.dispose(); } + Widget buildBloodPressureUI(MyTrackersViewModel myTrackersViewModel) { + return Expanded( + child: ListView( + children: [ + if (myTrackersViewModel.bpCurrentStatus == kRealTimeDataBPMeasuring) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + mHeight(24.0), + Column( + children: [ + Text(myTrackersViewModel.bpRtMeasuringModel.pressure.toString(), style: TextStyle(fontSize: 100, fontWeight: FontWeight.bold)), + Text("Pressure", style: TextStyle(fontSize: 20)), + ], + ), + mHeight(24.0), + ], + ), + ] else if (myTrackersViewModel.bpCurrentStatus == kRealTimeDataBPResult) ...[ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("Dia", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.bpRtResultModel.dia.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("Sys", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.bpRtResultModel.sys.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("♥︎", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.bpRtResultModel.pr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("/min", style: TextStyle(fontSize: 10)), + ], + ), + ], + ), + mHeight(30.0), + buildStatusForBP(myTrackersViewModel.bpRtResultModel.result), + mHeight(24.0), + ], + ), + ] else ...[ + Padding( + padding: const EdgeInsets.all(24.0), + child: Center( + child: Text( + "Some animation with the instruction", + style: TextStyle(fontSize: 9.0), + ), + ), + ) + ], + ], + ), + ); + } + + Widget buildECGUI(MyTrackersViewModel myTrackersViewModel) { + return Expanded( + child: ListView( + children: [ + if (myTrackersViewModel.ecgCurrentStatus == kRealTimeDataECGMeasuring) ...[ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("Duration", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.ecgRtMeasuringModelFromBP.curDuration.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("seconds", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("♥︎", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.ecgRtMeasuringModelFromBP.hr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("/min", style: TextStyle(fontSize: 10)), + ], + ), + ], + ), + mHeight(30.0), + ] else if (myTrackersViewModel.ecgCurrentStatus == kRealTimeDataECGResult) ...[ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("Regular", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.ecgRtResultModelFromBP.diagnosis.isRegular ? "YES" : "NO", style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("♥︎", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.ecgRtResultModelFromBP.hr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("/min", style: TextStyle(fontSize: 10)), + ], + ), + // Column( + // children: [ + // Text("Heart Pause", style: TextStyle(fontSize: 20)), + // Text(myTrackersViewModel.ecgRtResultModelFromBP.diagnosis.isHeartPause ? "YES" : "NO", style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)), + // Text("", style: TextStyle(fontSize: 10)), + // ], + // ), + ], + ), + mHeight(30.0), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceEvenly, + // children: [ + // Column( + // children: [ + // Text("Lead Off", style: TextStyle(fontSize: 20)), + // Text(myTrackersViewModel.ecgRtResultModelFromBP.diagnosis.isLeadOff ? "YES" : "NO", style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)), + // Text("", style: TextStyle(fontSize: 10)), + // ], + // ), + // Column( + // children: [ + // Text("Poor Signal", style: TextStyle(fontSize: 20)), + // Text(myTrackersViewModel.ecgRtResultModelFromBP.diagnosis.isPoorSignal ? "YES" : "NO", style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)), + // Text("", style: TextStyle(fontSize: 10)), + // ], + // ), + // Column( + // children: [ + // Text("PVCs", style: TextStyle(fontSize: 20)), + // Text(myTrackersViewModel.ecgRtResultModelFromBP.diagnosis.isPvcs ? "YES" : "NO", style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)), + // Text("", style: TextStyle(fontSize: 10)), + // ], + // ), + // ], + // ), + mHeight(30.0), + buildStatusForECG(myTrackersViewModel.ecgRtResultModelFromBP.result), + ], + ), + ] else ...[ + Padding( + padding: const EdgeInsets.all(24.0), + child: Center( + child: Text( + "Some animation with the instruction", + style: TextStyle(fontSize: 9.0), + ), + ), + ) + ], + ], + ), + ); + } + + Widget buildStatusForBP(int result) { + String resultStatus = ""; + + if (result == 0) { + resultStatus = "Normal"; + } else if (result == 1) { + resultStatus = "Unable to analyze(cuff is too loose, inflation is slow, slow air leakage, large air volume)"; + } else if (result == 2) { + resultStatus = "Waveform disorder(arm movement or other interference detected during pumping)"; + } else if (result == 3) { + resultStatus = "Weak signal, unable to detect pulse wave(clothes with interference sleeves)"; + } else { + resultStatus = "Equipment error(valve blocking, over-range blood pressure measurement, serious cuff leakage, software system abnormality, hardware system error, and other abnormalities)"; + } + return Column( + children: [ + Center(child: Text("$resultStatus", style: TextStyle(fontSize: 20))), + if (result != 0) ...[ + mHeight(24.0), + Center(child: Text("Press START/STOP Button on the device to restart.", style: TextStyle(fontSize: 15))), + ], + ], + ); + } + + Widget buildStatusForECG(int result) { + String resultStatus = ""; + + if (result == 0) { + // resultStatus = "Normal"; + resultStatus = ""; // NO NEED TO SHOW "NORMAL" + } else if (result == 1) { + resultStatus = "Unable to analyze(cuff is too loose, inflation is slow, slow air leakage, large air volume)"; + } else if (result == 2) { + resultStatus = "Waveform disorder(arm movement or other interference detected during pumping)"; + } else if (result == 3) { + resultStatus = "Weak signal, unable to detect pulse wave(clothes with interference sleeves)"; + } else { + resultStatus = "Equipment error(valve blocking, over-range blood pressure measurement, serious cuff leakage, software system abnormality, hardware system error, and other abnormalities)"; + } + return Column( + children: [ + Center(child: Text("$resultStatus", style: TextStyle(fontSize: 20))), + if (result != 0) ...[ + mHeight(24.0), + Center(child: Text("Press LIST Button on the device to restart.", style: TextStyle(fontSize: 15))), + ], + ], + ); + } + + showHistoryDialog(BuildContext context) { + return showDialog( + context: context, + builder: (context) => Container( + decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(15)), color: Colors.white), + padding: const EdgeInsets.all(20), + margin: const EdgeInsets.symmetric(vertical: 35, horizontal: 30), + child: SingleChildScrollView( + child: Consumer(builder: (BuildContext context, MyTrackersViewModel myTrackersVm, Widget child) { + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Material(child: Center(child: Text("Files History", style: TextStyle(fontSize: 20)))), + if (myTrackersVm.filesLoader) ...[ + Center(child: CircularProgressIndicator()) + ] else if (myTrackersVm.ecgHistoryFiles.isNotEmpty) ...[ + myTrackersVm.getFilesListWidget(myTrackersVm.ecgHistoryFiles, context), + mHeight(15), + Row( + children: [ + Expanded( + child: DefaultButton( + "Reset History", + () async { + myTrackersVm.clearEcgHistoryFiles(); + myTrackersVm.factoryResetECG(widget.deviceModel); + // Navigator.pop(context); + }, + textColor: Colors.white, + ), + ), + ], + ), + ] else ...[ + Material(child: Center(child: Text("No History Files to show", style: TextStyle(fontSize: 20)))), + ] + ], + ); + }), + ), + ), + ); + } + @override Widget build(BuildContext context) { return AppScaffold( @@ -39,80 +320,67 @@ class _BloodPressureConnectScreenState extends State isShowDecPage: false, showNewAppBarTitle: true, backgroundColor: Color(0xffF8F8F8), + appBarIcons: [ + if (myTrackersVm.isECGSelected) ...[ + IconButton( + onPressed: () async { + + myTrackersVm.updateFilesLoader(true); + showHistoryDialog(context); + await myTrackersVm.getEcgFilesList(widget.deviceModel); + }, + icon: Icon(Icons.format_list_numbered_rounded), + ), + ], + IconButton( + onPressed: () { + AppSharedPreferences().remove(IS_LIVECARE_APPOINTMENT); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => LandingPage()), + (Route route) => false, + ); + }, + icon: Icon(Icons.home), + ), + ], body: Padding( padding: const EdgeInsets.all(24.0), child: Consumer( builder: (BuildContext context, MyTrackersViewModel myTrackersViewModel, Widget child) { return Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - child: ListView( - children: [ - if (myTrackersViewModel.bpCurrentStatus == "RealTimeDataBP2Measuring") ...[ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - mHeight(24.0), - Column( - children: [ - Text(myTrackersViewModel.bpRtMeasuringModel.pressure.toString(), style: TextStyle(fontSize: 100, fontWeight: FontWeight.bold)), - Text("Pressure", style: TextStyle(fontSize: 20)), - ], - ), - mHeight(24.0), - ], - ), - ] else if (myTrackersViewModel.bpCurrentStatus == "RealTimeDataBP2Result") ...[ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - mHeight(24.0), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - Text("Dia", style: TextStyle(fontSize: 20)), - Text(myTrackersViewModel.bpRtResultModel.dia.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), - Text("mmHg", style: TextStyle(fontSize: 10)), - ], - ), - Column( - children: [ - Text("Sys", style: TextStyle(fontSize: 20)), - Text(myTrackersViewModel.bpRtResultModel.sys.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), - Text("mmHg", style: TextStyle(fontSize: 10)), - ], - ), - Column( - children: [ - Text("♥︎", style: TextStyle(fontSize: 20)), - Text(myTrackersViewModel.bpRtResultModel.pr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), - Text("/min", style: TextStyle(fontSize: 10)), - ], - ), - ], - ), - mHeight(24.0), - ], - ), - ] else ...[ - Padding( - padding: const EdgeInsets.all(24.0), - child: Center( - child: Text( - "Some animation with the instruction", - style: TextStyle(fontSize: 9.0), - ), - ), - ) - ], - ], + if (widget.isEcgAvailable) ...[ + FlutterToggleTab( + borderRadius: 30, + height: 40, + width: 80, + selectedIndex: myTrackersViewModel.isECGSelected ? 1 : 0, + selectedBackgroundColors: [Color(0xffD02127), Color(0xffD02127)], + selectedTextStyle: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.w700), + unSelectedTextStyle: TextStyle(color: Colors.black87, fontSize: 14, fontWeight: FontWeight.w500), + labels: ["BP", "ECG"], + selectedLabelIndex: (index) { + if (index == 1 && myTrackersViewModel.bpCurrentStatus == kRealTimeDataBPMeasuring) { + return; + } + if (index == 0 && myTrackersViewModel.ecgCurrentStatus == kRealTimeDataECGMeasuring) { + return; + } + if (index == 0) { + myTrackersViewModel.updateIsECGSelected(false); + } else { + myTrackersViewModel.updateIsECGSelected(true); + } + setState(() {}); + }, + isScroll: false, ), - ), - if (myTrackersViewModel.bpCurrentStatus != null) ...[ + ], + myTrackersViewModel.isECGSelected ? buildECGUI(myTrackersViewModel) : buildBloodPressureUI(myTrackersViewModel), + if (myTrackersViewModel.bpCurrentStatus != null || myTrackersViewModel.ecgCurrentStatus != null) ...[ Row( children: [ Expanded( @@ -122,6 +390,9 @@ class _BloodPressureConnectScreenState extends State myTrackersVm.bpCurrentStatus = null; myTrackersVm.bpRtMeasuringModel = null; myTrackersVm.bpRtResultModel = null; + myTrackersVm.ecgCurrentStatus = null; + myTrackersVm.ecgRtMeasuringModelFromBP = null; + myTrackersVm.ecgRtResultModelFromBP = null; Navigator.pop(context); }, textColor: Colors.white, diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart index e69de29b..0005bac8 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart @@ -0,0 +1,227 @@ +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart'; +import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; +import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; +import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ECGConnectScreen extends StatefulWidget { + final BleDeviceModel deviceModel; + + const ECGConnectScreen({this.deviceModel}); + + @override + State createState() => _ECGConnectScreenState(); +} + +class _ECGConnectScreenState extends State { + MyTrackersViewModel myTrackersVm; + + @override + void initState() { + myTrackersVm = context.read(); + myTrackersVm.connectDevice(widget.deviceModel); + super.initState(); + } + + @override + void dispose() { + myTrackersVm.disConnectDevice(); + super.dispose(); + } + + Widget buildStatus(int currentStatus) { + String resultStatus = ""; + + if (currentStatus == 0) { + resultStatus = "Idle"; + } else if (currentStatus == 1) { + resultStatus = "Preparing"; + } else if (currentStatus == 2) { + resultStatus = "Measuring"; + } else if (currentStatus == 3) { + resultStatus = "Saving File"; + } else if (currentStatus == 4) { + resultStatus = "File Successfully Saved"; + } else if (currentStatus == 5) { + resultStatus = "Can't measure before 30s, file was not saved"; + } else if (currentStatus == 6) { + resultStatus = "Retests"; + } else if (currentStatus == 7) { + resultStatus = "Lead Off"; + } else { + resultStatus = ""; + } + return Column( + children: [ + Center(child: Text("$resultStatus", style: TextStyle(fontSize: 20))), + if (currentStatus == 5) ...[ + mHeight(24.0), + Center(child: Text("Press hold on the device to restart.", style: TextStyle(fontSize: 15))), + ], + ], + ); + } + + + + showHistoryDialog(BuildContext context) { + return showDialog( + context: context, + builder: (context) => Container( + decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(15)), color: Colors.white), + padding: const EdgeInsets.all(20), + margin: const EdgeInsets.symmetric(vertical: 35, horizontal: 30), + child: SingleChildScrollView( + child: Consumer(builder: (BuildContext context, MyTrackersViewModel myTrackersVm, Widget child) { + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Material(child: Center(child: Text("Files History", style: TextStyle(fontSize: 20)))), + if (myTrackersVm.filesLoader) ...[ + Center(child: CircularProgressIndicator()) + ] else if (myTrackersVm.ecgHistoryFiles.isNotEmpty) ...[ + myTrackersVm.getFilesListWidget(myTrackersVm.ecgHistoryFiles, context), + mHeight(15), + Row( + children: [ + Expanded( + child: DefaultButton( + "Reset History", + () async { + myTrackersVm.clearEcgHistoryFiles(); + myTrackersVm.factoryResetECG(widget.deviceModel); + // Navigator.pop(context); + }, + textColor: Colors.white, + ), + ), + ], + ), + ] else ...[ + Material(child: Center(child: Text("No History Files to show", style: TextStyle(fontSize: 20)))), + ] + ], + ); + }), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + MyTrackersViewModel myTrackersViewModel = context.watch(); + return AppScaffold( + appBarTitle: "${widget.deviceModel.name}", + showNewAppBar: true, + isShowDecPage: false, + showNewAppBarTitle: true, + backgroundColor: Color(0xffF8F8F8), + appBarIcons: [ + IconButton( + onPressed: () async { + myTrackersViewModel.updateFilesLoader(true); + showHistoryDialog(context); + await myTrackersViewModel.getEcgFilesList(widget.deviceModel); + }, + icon: Icon(Icons.format_list_numbered_rounded), + ), + IconButton( + onPressed: () { + AppSharedPreferences().remove(IS_LIVECARE_APPOINTMENT); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => LandingPage()), + (Route route) => false, + ); + }, + icon: Icon(Icons.home), + ), + ], + body: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: ListView( + children: [ + if (myTrackersViewModel.ecgRtModel != null) ...[ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("Record Time", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.ecgRtModel.param.recordTime.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("seconds", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("♥︎", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.ecgRtModel.param.hr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("/min", style: TextStyle(fontSize: 10)), + ], + ), + ], + ), + mHeight(30.0), + buildStatus(myTrackersViewModel.ecgRtModel.param.curStatus), + ], + ) + ], + if (myTrackersViewModel.ecgRtModel == null) ...[ + Padding( + padding: const EdgeInsets.all(24.0), + child: Center( + child: Text( + "Some animation with the instruction", + style: TextStyle(fontSize: 9.0), + ), + ), + ), + ] + ], + ), + ), + if (myTrackersViewModel.ecgRtModel != null) ...[ + mHeight(10.0), + Row( + children: [ + Expanded( + flex: 2, + child: DefaultButton( + "Disconnect ${widget.deviceModel.name}", + () async { + myTrackersViewModel.ecgRtModel = null; + Navigator.pop(context); + }, + textColor: Colors.white, + ), + ), + ], + ), + ] + ], + ), + ), + ); + } +} diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart index bb3c6afc..b58650ed 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart @@ -85,6 +85,10 @@ class SelectTrackerType extends StatelessWidget { showNewAppBar: true, isHelp: true, showNewAppBarTitle: true, + onTap: () { + context.read().disConnectDevice(); + Navigator.pop(context); + }, appBarTitle: "Select Tracker", body: Container( child: SingleChildScrollView( diff --git a/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart b/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart index d0f97861..7d0783de 100644 --- a/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart +++ b/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart @@ -13,11 +13,11 @@ class BleChannel { static Future scanResults(List deviceType) async { try { String result; - print("----------Flutter Init -------"); + print("----------Flutter scanResults -------"); // if (Platform.isIOS && deviceType[0] == "ekg") { // result = await platform_ios_ekg.invokeMethod('scanEKG', deviceType); // } else { - result = await platform.invokeMethod('scan'); + result = await platform.invokeMethod('scanDevices'); // } print("----------Flutter Result -------"); print(result); @@ -44,10 +44,10 @@ class BleChannel { } } - static Future getEKGFilesList(List deviceType) async { + static Future getECGFilesList(List device) async { try { - print("----------Flutter Init -------"); - final String result = await platform.invokeMethod('ekg_files_list', deviceType); + print("----------Flutter getECGFilesList -------"); + final String result = await platform.invokeMethod('ecgFilesList', device); print("----------Flutter Result -------"); print(result); return result; @@ -56,10 +56,10 @@ class BleChannel { } } - static Future getBP2FilesList(List deviceType) async { + static Future factoryResetECG(List device) async { try { - print("----------Flutter Init -------"); - final String result = await platform.invokeMethod('bp2_files_list', deviceType); + print("----------Flutter duoEkFactoryReset -------"); + final String result = await platform.invokeMethod('factoryResetECG', device); print("----------Flutter Result -------"); print(result); return result; @@ -68,10 +68,10 @@ class BleChannel { } } - static Future getEKGFileDetails(String fileName) async { + static Future getBP2FilesList(List deviceType) async { try { - print("----------Flutter Init -------"); - final String result = await platform.invokeMethod('ekg_file_detail', fileName); + print("----------Flutter getBP2FilesList -------"); + final String result = await platform.invokeMethod('bp2FilesList', deviceType); print("----------Flutter Result -------"); print(result); return result; @@ -82,8 +82,8 @@ class BleChannel { static Future disconnect() async { try { - print("----------Flutter Init disconnect_device -------"); - final String result = await platform.invokeMethod('disconnect_device'); + print("----------Flutter disconnect -------"); + final String result = await platform.invokeMethod('disconnectDevice'); print("----------Flutter Result -------"); print(result); return result; diff --git a/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart b/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart index 4d02c56e..d9c85342 100644 --- a/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart +++ b/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart @@ -1,8 +1,11 @@ +import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; + class BleDeviceModel { String macAddr; int model; String name; int rssi; + TrackerTypeEnum deviceType; BleDeviceModel({this.macAddr, this.model, this.name, this.rssi}); @@ -11,19 +14,11 @@ class BleDeviceModel { model = json['model']; name = json['name']; rssi = json['rssi']; - } - - Map toJson() { - final Map data = new Map(); - data['macAddr'] = this.macAddr; - data['model'] = this.model; - data['name'] = this.name; - data['rssi'] = this.rssi; - return data; + deviceType = TrackerTypeEnum.AllInOneTracker; } @override String toString() { - return 'BleDeviceModel{macAddr: $macAddr, model: $model, name: $name, rssi: $rssi}'; + return 'BleDeviceModel{macAddr: $macAddr, model: $model, name: $name, rssi: $rssi, deviceType: $deviceType}'; } } diff --git a/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart b/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart index 2cb03317..2ccacdd9 100644 --- a/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart +++ b/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart @@ -56,3 +56,126 @@ class BpRtResultModel { return data; } } + +class ECGRtMeasuringModelFromBP { + int curDuration; + int hr; + bool leadOff; + bool poolSignal; + + ECGRtMeasuringModelFromBP({this.curDuration, this.hr, this.leadOff, this.poolSignal}); + + ECGRtMeasuringModelFromBP.fromJson(Map json) { + curDuration = json['curDuration']; + hr = json['hr']; + leadOff = json['leadOff']; + poolSignal = json['poolSignal']; + } + + Map toJson() { + final Map data = new Map(); + data['curDuration'] = this.curDuration; + data['hr'] = this.hr; + data['leadOff'] = this.leadOff; + data['poolSignal'] = this.poolSignal; + return data; + } +} + +class ECGRtResultModelFromBP { + Diagnosis diagnosis; + int hr; + int pvcs; + int qrs; + int qtc; + int result; + + ECGRtResultModelFromBP({this.diagnosis, this.hr, this.pvcs, this.qrs, this.qtc, this.result}); + + ECGRtResultModelFromBP.fromJson(Map json) { + diagnosis = json['diagnosis'] != null ? new Diagnosis.fromJson(json['diagnosis']) : null; + hr = json['hr']; + pvcs = json['pvcs']; + qrs = json['qrs']; + qtc = json['qtc']; + result = json['result']; + } + + Map toJson() { + final Map data = new Map(); + if (this.diagnosis != null) { + data['diagnosis'] = this.diagnosis.toJson(); + } + data['hr'] = this.hr; + data['pvcs'] = this.pvcs; + data['qrs'] = this.qrs; + data['qtc'] = this.qtc; + data['result'] = this.result; + return data; + } +} + +class Diagnosis { + List bytes; + bool isFastHr; + bool isFibrillation; + bool isHeartPause; + bool isIrregular; + bool isLeadOff; + bool isPoorSignal; + bool isProlongedQtc; + bool isPvcs; + bool isRegular; + bool isShortQtc; + bool isSlowHr; + bool isWideQrs; + + Diagnosis( + {this.bytes, + this.isFastHr, + this.isFibrillation, + this.isHeartPause, + this.isIrregular, + this.isLeadOff, + this.isPoorSignal, + this.isProlongedQtc, + this.isPvcs, + this.isRegular, + this.isShortQtc, + this.isSlowHr, + this.isWideQrs}); + + Diagnosis.fromJson(Map json) { + bytes = json['bytes'].cast(); + isFastHr = json['isFastHr']; + isFibrillation = json['isFibrillation']; + isHeartPause = json['isHeartPause']; + isIrregular = json['isIrregular']; + isLeadOff = json['isLeadOff']; + isPoorSignal = json['isPoorSignal']; + isProlongedQtc = json['isProlongedQtc']; + isPvcs = json['isPvcs']; + isRegular = json['isRegular']; + isShortQtc = json['isShortQtc']; + isSlowHr = json['isSlowHr']; + isWideQrs = json['isWideQrs']; + } + + Map toJson() { + final Map data = new Map(); + data['bytes'] = this.bytes; + data['isFastHr'] = this.isFastHr; + data['isFibrillation'] = this.isFibrillation; + data['isHeartPause'] = this.isHeartPause; + data['isIrregular'] = this.isIrregular; + data['isLeadOff'] = this.isLeadOff; + data['isPoorSignal'] = this.isPoorSignal; + data['isProlongedQtc'] = this.isProlongedQtc; + data['isPvcs'] = this.isPvcs; + data['isRegular'] = this.isRegular; + data['isShortQtc'] = this.isShortQtc; + data['isSlowHr'] = this.isSlowHr; + data['isWideQrs'] = this.isWideQrs; + return data; + } +} diff --git a/lib/pages/medical/my_trackers/ble_models/viatom_devices/ekg_file_detail_response_model.dart b/lib/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart similarity index 81% rename from lib/pages/medical/my_trackers/ble_models/viatom_devices/ekg_file_detail_response_model.dart rename to lib/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart index 18b5420f..17989e63 100644 --- a/lib/pages/medical/my_trackers/ble_models/viatom_devices/ekg_file_detail_response_model.dart +++ b/lib/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart @@ -1,13 +1,13 @@ -class EKGFileDetailResponseModel { +class ECGFileDetailModel { int duration; String fileName; List shortData; int startTime; - EKGFileDetailResponseModel( + ECGFileDetailModel( {this.duration, this.fileName, this.shortData, this.startTime}); - EKGFileDetailResponseModel.fromJson(Map json) { + ECGFileDetailModel.fromJson(Map json) { duration = json['duration']; fileName = json['fileName']; shortData = json['shortData'].cast(); diff --git a/lib/pages/medical/my_trackers/ble_models/viatom_devices/ekg_realtime_data_response.dart b/lib/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart similarity index 92% rename from lib/pages/medical/my_trackers/ble_models/viatom_devices/ekg_realtime_data_response.dart rename to lib/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart index 1b70382a..d4433f3d 100644 --- a/lib/pages/medical/my_trackers/ble_models/viatom_devices/ekg_realtime_data_response.dart +++ b/lib/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart @@ -1,10 +1,10 @@ -class EKGRealTimeDataResponseModel { +class ECGRtModel { Param param; Wave wave; - EKGRealTimeDataResponseModel({this.param, this.wave}); + ECGRtModel({this.param, this.wave}); - EKGRealTimeDataResponseModel.fromJson(Map json) { + ECGRtModel.fromJson(Map json) { param = json['param'] != null ? new Param.fromJson(json['param']) : null; wave = json['wave'] != null ? new Wave.fromJson(json['wave']) : null; } diff --git a/lib/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_param_model.dart b/lib/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_model.dart similarity index 78% rename from lib/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_param_model.dart rename to lib/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_model.dart index 4538fc16..5cc32528 100644 --- a/lib/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_param_model.dart +++ b/lib/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_model.dart @@ -1,4 +1,4 @@ -class OxyRtParamModel { +class OxyRtModel { int battery; bool isCheckProbe; bool isProbeOff; @@ -7,9 +7,9 @@ class OxyRtParamModel { int pr; int spo2; - OxyRtParamModel({this.battery, this.isCheckProbe, this.isProbeOff, this.isPulseSearching, this.pi, this.pr, this.spo2}); + OxyRtModel({this.battery, this.isCheckProbe, this.isProbeOff, this.isPulseSearching, this.pi, this.pr, this.spo2}); - OxyRtParamModel.fromJson(Map json) { + OxyRtModel.fromJson(Map json) { battery = json['battery']; isCheckProbe = json['isCheckProbe']; isProbeOff = json['isProbeOff']; diff --git a/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart b/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart index 689ac0fb..af692392 100644 --- a/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart +++ b/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart @@ -2,7 +2,13 @@ import 'dart:convert'; import 'dart:developer'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart'; -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_param_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart'; +import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/services.dart'; import 'package:flutter/cupertino.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -11,6 +17,17 @@ import 'package:flutter/material.dart'; enum TrackerTypeEnum { OxymeterTracker, BloodPressureTracker, BloodSugarTracker, ECGTracker, AllInOneTracker } +//NativeEventNames + +String kRealTimeDataBPMeasuring = "RealTimeDataBPMeasuring"; +String kRealTimeDataBPResult = "RealTimeDataBPResult"; +String kOxyRtParam = "OxyRtParam"; +String kDevicesList = "DevicesList"; +String kRealTimeDataECGMeasuring = "RealTimeDataECGMeasuring"; // This is for the device that measures BP and ECG also Like BP2 0567 +String kRealTimeDataECGResult = "RealTimeDataECGResult"; +String kRealTimeDataECG = "RealTimeDataECG"; +String kFileDetail = "FileDetail"; + class MyTrackersViewModel extends ChangeNotifier { EventChannel eventChannel = EventChannel('BLE-Platform-Bridge-Event'); @@ -25,7 +42,7 @@ class MyTrackersViewModel extends ChangeNotifier { {"model": "O2Ring"}, // DONE ], "BloodPressureTracker": [ - {"model": "BP2"}, + {"model": "BP2"}, //Done {"model": ""}, {"model": ""}, {"model": ""}, @@ -50,12 +67,14 @@ class MyTrackersViewModel extends ChangeNotifier { ], }; + List ecgEnabledDevices = ["BP2 0567", "DuoEK"]; + //************************************* OXYMETER ************************************* - OxyRtParamModel oxyRtModel; + OxyRtModel oxyRtModel; void updateOxyRtModel(Map mapData) { - oxyRtModel = OxyRtParamModel.fromJson(mapData); + oxyRtModel = OxyRtModel.fromJson(mapData); notifyListeners(); } @@ -82,20 +101,120 @@ class MyTrackersViewModel extends ChangeNotifier { notifyListeners(); } + bool isECGSelected = false; + + updateIsECGSelected(var value) { + isECGSelected = value; + notifyListeners(); + } + + //************************************* ECG ************************************* + + bool filesLoader = false; + + updateFilesLoader(var value) { + filesLoader = value; + } + + ECGRtModel ecgRtModel; + + void updateEcgRtModel(Map mapData) { + ecgRtModel = ECGRtModel.fromJson(mapData); + notifyListeners(); + } + + List ecgHistoryFiles = []; + + updateEcgHistoryFiles(var value) { + ecgHistoryFiles = value; + notifyListeners(); + } + + clearEcgHistoryFiles() { + ecgHistoryFiles.clear(); + notifyListeners(); + } + + parseEcgHistoryFiles(String mapData) { + ecgHistoryFiles.clear(); + json.decode(mapData).forEach((v) { + ecgHistoryFiles.add(new ECGFileDetailModel.fromJson(v)); + }); + notifyListeners(); + } + + String ecgCurrentStatus; + + updateEcgCurrentStatus(var value) { + ecgCurrentStatus = value; + notifyListeners(); + } + + ECGRtMeasuringModelFromBP ecgRtMeasuringModelFromBP; + + void updateEcgRtMeasuringModelFromBP(Map mapData) { + ecgRtMeasuringModelFromBP = ECGRtMeasuringModelFromBP.fromJson(mapData); + notifyListeners(); + } + + ECGRtResultModelFromBP ecgRtResultModelFromBP; + + void updateEcgRtResultModelFromBP(Map mapData) { + ecgRtResultModelFromBP = ECGRtResultModelFromBP.fromJson(mapData); + notifyListeners(); + } + + Widget getFilesListWidget(List filesList, BuildContext context) { + return Material( + child: SizedBox( + height: MediaQuery.of(context).size.height * 0.7, + child: ListView.separated( + itemCount: filesList.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + shrinkWrap: true, + reverse: false, + itemBuilder: (context, index) { + ECGFileDetailModel ecgFileDetailModel = filesList[index]; + return InkWell( + onTap: () => Navigator.push(context, FadePage(page: EKGChartView(ekgFileDetailResponseModel: ecgFileDetailModel))), + child: Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(ecgFileDetailModel.fileName), + mHeight(6.0), + Text("Duration: ${ecgFileDetailModel.duration} seconds"), + mHeight(6.0), + Text("Date: ${DateUtil.getDayMonthYearHourMinuteDateFormatted(DateTime.fromMillisecondsSinceEpoch((ecgFileDetailModel.startTime * 1000)))}"), + ], + ), + ), + ); + }, + ), + ), + ); + } + void filterOutTheSearchedDevices(List allDevices) { devicesList.clear(); notifyListeners(); if (devicesInfoJson.containsKey(currentSelectedTrackerType.name)) { - allDevices.forEach((foundDevice) { - List devicesInSelectedType = devicesInfoJson[currentSelectedTrackerType.name]; - for (var device in devicesInSelectedType) { - log("foundDevice.name: ${foundDevice.name.toString()}"); - log("device['model']: ${device['model']}"); - if (device['model'] != "" && foundDevice.name.contains(device['model'])) { - devicesList.add(foundDevice); + allDevices.forEach( + (foundDevice) { + List devicesInSelectedType = devicesInfoJson[currentSelectedTrackerType.name]; + for (var device in devicesInSelectedType) { + log("foundDevice.name: ${foundDevice.name.toString()}"); + foundDevice.deviceType = currentSelectedTrackerType; + log("device['model']: ${device['model']}"); + if (device['model'] != "" && foundDevice.name.contains(device['model'])) { + devicesList.add(foundDevice); + } } - } - }); + }, + ); notifyListeners(); } } @@ -113,34 +232,56 @@ class MyTrackersViewModel extends ChangeNotifier { } Future startSearchingForTracker() async { - log("selectedStracker: ${currentSelectedTrackerType.name}"); + log("selectedTracker: ${currentSelectedTrackerType.name}"); await checkBLEPermissions(); eventChannel.receiveBroadcastStream().listen((event) { print('Received event---: $event'); print(event['type']); - if (event['type'] == "devicesList") { + // Get Devices List + if (event['type'] == kDevicesList) { parsesDevicesList(json.decode(event['data']) as List); } - if (event['type'] == "OxyRtParam") { + // Get Oxymeter Readings + if (event['type'] == kOxyRtParam) { updateOxyRtModel(json.decode(event['data'])); } - if (event['type'] == "fileList") { - print(event['data']); - } - if (event['type'] == 'fileDetail') { - print(event['data']); - } - if (event['type'] == "RealTimeDataBP2Measuring") { + // Get Blood Pressure Readings while measuring + if (event['type'] == kRealTimeDataBPMeasuring) { updateBpRtMeasuringModel(json.decode(event['data'])); - updateBpCurrentStatus("RealTimeDataBP2Measuring"); + updateBpCurrentStatus(kRealTimeDataBPMeasuring); } - if (event['type'] == "RealTimeDataBP2Result") { + + // Get Blood Pressure Readings after result + if (event['type'] == kRealTimeDataBPResult) { updateBpRtResultModel(json.decode(event['data'])); - updateBpCurrentStatus("RealTimeDataBP2Result"); + updateBpCurrentStatus(kRealTimeDataBPResult); + } + + // Get ECG Readings while measuring with Blood Pressure Device (BP 0567) + if (event['type'] == kRealTimeDataECGMeasuring) { + updateEcgRtMeasuringModelFromBP(json.decode(event['data'])); + updateEcgCurrentStatus(kRealTimeDataECGMeasuring); + } + + // Get ECG Readings after result with Blood Pressure Device (BP 0567) + if (event['type'] == kRealTimeDataECGResult) { + updateEcgRtResultModelFromBP(json.decode(event['data'])); + updateEcgCurrentStatus(kRealTimeDataECGResult); + } + + // Get ECG Readings from ECG Device like DuoEK + if (event['type'] == kRealTimeDataECG) { + updateEcgRtModel(json.decode(event['data'])); + } + + // Get ECG File History Details + if ((currentSelectedTrackerType == TrackerTypeEnum.ECGTracker || currentSelectedTrackerType == TrackerTypeEnum.BloodPressureTracker) && event['type'] == kFileDetail) { + updateFilesLoader(false); + parseEcgHistoryFiles(event['data']); } }); @@ -154,7 +295,14 @@ class MyTrackersViewModel extends ChangeNotifier { void resetList() { devicesList.clear(); - // BleChannel.disconnect(); + } + + Future getEcgFilesList(BleDeviceModel device) async { + await BleChannel.getECGFilesList([device.name, device.model.toString()]); + } + + Future factoryResetECG(BleDeviceModel device) async { + await BleChannel.factoryResetECG([device.name, device.model.toString()]); } Future connectDevice(BleDeviceModel device) async { diff --git a/lib/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart b/lib/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart index 31469ad4..425abbfb 100644 --- a/lib/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart +++ b/lib/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart @@ -1,10 +1,10 @@ -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ekg_file_detail_response_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; class EKGChartView extends StatefulWidget { - EKGFileDetailResponseModel ekgFileDetailResponseModel; + ECGFileDetailModel ekgFileDetailResponseModel; EKGChartView({@required this.ekgFileDetailResponseModel}); diff --git a/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart b/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart index ca2efd5b..beb7be1b 100644 --- a/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart +++ b/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:convert'; -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ekg_file_detail_response_model.dart'; -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ekg_realtime_data_response.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; @@ -34,9 +34,9 @@ class _EKG_BLEState extends State { List ekgFilesList = []; - List ekgFileDetailResponseModelList = []; + List ekgFileDetailResponseModelList = []; - EKGRealTimeDataResponseModel ekgRealTimeDataResponseModel; + ECGRtModel ekgRealTimeDataResponseModel; List ecgBytesAllDataList = []; @@ -179,7 +179,7 @@ class _EKG_BLEState extends State { child: DefaultButton( "Get Files List", () async { - await BleChannel.getEKGFilesList(["oximeter", "ekg"]); + // await BleChannel.getECGFilesList(); }, textColor: Colors.white, ), @@ -247,7 +247,7 @@ class _EKG_BLEState extends State { ); } - Widget getECGFileCard(EKGFileDetailResponseModel ekgFileDetailResponseModel) { + Widget getECGFileCard(ECGFileDetailModel ekgFileDetailResponseModel) { return Container( decoration: cardRadius(12), padding: EdgeInsets.all(12.0), @@ -264,7 +264,7 @@ class _EKG_BLEState extends State { ); } - void showEKGFileDetails(EKGFileDetailResponseModel ekgFileDetailResponseModel) async { + void showEKGFileDetails(ECGFileDetailModel ekgFileDetailResponseModel) async { print("received file name: ${ekgFileDetailResponseModel.fileName}"); Navigator.push(context, FadePage(page: EKGChartView(ekgFileDetailResponseModel: ekgFileDetailResponseModel))); // await BleChannel.getEKGFileDetails(fileName); @@ -273,14 +273,14 @@ class _EKG_BLEState extends State { void parseEKGFileDetailObject(dynamic returnData) { ekgFileDetailResponseModelList.clear(); json.decode(returnData).forEach((v) { - ekgFileDetailResponseModelList.add(new EKGFileDetailResponseModel.fromJson(v)); + ekgFileDetailResponseModelList.add(new ECGFileDetailModel.fromJson(v)); }); print(ekgFileDetailResponseModelList.length); ekgValueNotifier.value = "Files Received: ${ekgFileDetailResponseModelList.length}"; } String parseEKGRealTimeDataObject(dynamic returnData) { - ekgRealTimeDataResponseModel = EKGRealTimeDataResponseModel.fromJson(json.decode(returnData)); + ekgRealTimeDataResponseModel = ECGRtModel.fromJson(json.decode(returnData)); return "HeartRate: ${ekgRealTimeDataResponseModel.param.hr} - Current State: ${ekgRealTimeDataResponseModel.param.curStatus}"; } } diff --git a/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart b/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart index cfd70729..c317fbfc 100644 --- a/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart +++ b/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart @@ -1,5 +1,5 @@ import 'dart:convert'; -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_param_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_model.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart'; import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; @@ -17,7 +17,7 @@ class _SP20PulseTrackerState extends State { EventChannel eventChannel = EventChannel('BLE-Platform-Bridge-Event'); // final bpDataNotifierMeasuring = ValueNotifier(BpRtDataMeasuringModel()); - final sp20RtParamNotifier = ValueNotifier(OxyRtParamModel()); + final sp20RtParamNotifier = ValueNotifier(OxyRtModel()); final sp20StatusNotifier = ValueNotifier(""); final bpDeviceDataNotifier = ValueNotifier(""); String deviceName = "SP20"; @@ -78,7 +78,7 @@ class _SP20PulseTrackerState extends State { if (value == "EventSp20RtParam") { return ValueListenableBuilder( valueListenable: sp20RtParamNotifier, - builder: (context, OxyRtParamModel sp20RtModel, _) { + builder: (context, OxyRtModel sp20RtModel, _) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -190,7 +190,7 @@ class _SP20PulseTrackerState extends State { } if (event['type'] == "EventSp20RtParam") { - sp20RtParamNotifier.value = OxyRtParamModel.fromJson(json.decode(event['data'])); + sp20RtParamNotifier.value = OxyRtModel.fromJson(json.decode(event['data'])); sp20StatusNotifier.value = "EventSp20RtParam"; } }); diff --git a/pubspec.yaml b/pubspec.yaml index 399979be..3e0bfa67 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -214,6 +214,7 @@ dependencies: open_filex: ^4.3.2 path_provider: ^2.0.8 flutter_blue_plus: 1.15.7 + flutter_toggle_tab: # flutter_callkit_incoming: ^1.0.3+3 # firebase_core: 1.12.0