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 51e1f60d..b2b36e3c 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 @@ -11,6 +11,7 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.EventChannel import android.util.SparseArray +import android.view.View import androidx.annotation.RequiresApi import com.cloud.diplomaticquarterapp.ble.utils.EcgData import com.cloud.diplomaticquarterapp.ble.utils.HexString @@ -24,6 +25,7 @@ import com.cloud.diplomaticquarterapp.MainActivity import com.cloud.diplomaticquarterapp.check_me_pro.bean.toJson import com.cloud.diplomaticquarterapp.check_me_pro.ble.format.BpInfo import com.cloud.diplomaticquarterapp.check_me_pro.ble.format.EcgInfo +import com.cloud.diplomaticquarterapp.check_me_pro.ble.format.EcgWaveInfo import com.cloud.diplomaticquarterapp.check_me_pro.ble.format.GluInfo import com.cloud.diplomaticquarterapp.check_me_pro.ble.format.OxyInfo import com.cloud.diplomaticquarterapp.utils.UiChannel @@ -55,6 +57,7 @@ import com.lepu.blepro.utils.DateUtil import com.lepu.blepro.utils.Er1Decompress import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -98,6 +101,7 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi private const val GET_OXI_DATA_CHECK_ME_PRO = "getOxiDataFromCheckMePro" private const val GET_TEMP_DATA_CHECK_ME_PRO = "getTempDataFromCheckMePro" private const val GET_ECG_DATA_CHECK_ME_PRO = "getEcgDataFromCheckMePro" + private const val GET_ECG_WAVE_CHECK_ME_PRO = "getEcgWaveFromCheckMePro" private const val GET_GLUCOSE_DATA_CHECK_ME_PRO = "getGlucoseDataFromCheckMePro" val scan = BleScanManager() @@ -259,6 +263,8 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi getOxyDataFromCheckMePro() } else if (methodCall.method == GET_ECG_DATA_CHECK_ME_PRO) { getECGDataFromCheckMePro() + } else if (methodCall.method == GET_ECG_WAVE_CHECK_ME_PRO) { + getECGWaveFromCheckMePro(methodCall.arguments as String) } else if (methodCall.method == GET_TEMP_DATA_CHECK_ME_PRO) { getTemperatureDataFromCheckMePro() } else if (methodCall.method == SCAN_DEVICE_EKG) { @@ -508,6 +514,31 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } } + private fun getECGWaveFromCheckMePro(timeString: String) { + + val file = File(Constant.getPathX(timeString)) + val exist = file.exists() + MainScope().launch { + if (!exist) { +// if (!MainActivity.isOffline) { + bleWorker.getFile(timeString) +// } + } + val file2 = File(Constant.getPathX(timeString)) + delay(100) + BleDataWorker.fileProgressChannel.send(BleDataWorker.FileProgress(progress = 0)) + delay(100) + BleDataWorker.fileProgressChannel.send(BleDataWorker.FileProgress(progress = -100)) + if (file2.exists()) { + val info = EcgWaveInfo(file2.readBytes()) + val json = gson.toJson(info) + Log.d("ECGWaveData", json.toString()) + val returnData = mapOf("type" to "ECGWaveCheckMePro", "data" to json.toString()) + eventSink?.success(returnData) + } + } + } + private fun getTemperatureDataFromCheckMePro() { val file = File(Constant.getPathX("tmp.dat")) if (file.exists()) { diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in_one_info_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in_one_info_screen.dart index 4e9d588f..ffc4b021 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in_one_info_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_all_in_one_info_screen.dart @@ -1,4 +1,5 @@ import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_info_screen.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_bp_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_glucose_model.dart'; @@ -125,7 +126,10 @@ class CheckMeAllInOneInfoScreen extends StatelessWidget { itemBuilder: (context, index) { CheckMeECGModel checkMeECGModel = myTrackersVm.checkMeEcg[index]; return InkWell( - onTap: () => Navigator.pop(context), + onTap: () { + myTrackersVm.getEcgWaveDataFromCheckMePro(checkMeECGModel.timeString); + Navigator.push(context, MaterialPageRoute(builder: (context) => CheckMeECGInfoScreen(TrackerTypeEnum.ECGTracker))); + }, child: Container( decoration: cardRadius(12), padding: EdgeInsets.all(12.0), @@ -133,8 +137,8 @@ class CheckMeAllInOneInfoScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Date: ${checkMeECGModel.date}"), - mHeight(4.0), - Text("way: ${checkMeECGModel.way}"), + mHeight(8), + Text("TimeString: ${checkMeECGModel.timeString}"), ], ), ), @@ -249,7 +253,7 @@ class CheckMeAllInOneInfoScreen extends StatelessWidget { itemBuilder: (context, index) { CheckMeGlucoseModel checkMeGlucoseModel = myTrackersVm.checkMeGlucose[index]; return InkWell( - onTap: () => Navigator.pop(context), + onTap: () => null, child: Container( decoration: cardRadius(12), padding: EdgeInsets.all(12.0), diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_chart_view.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_chart_view.dart new file mode 100644 index 00000000..a5ba453a --- /dev/null +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_chart_view.dart @@ -0,0 +1,89 @@ +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_wave_model.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; + +class CheckMeECGChartView extends StatelessWidget { + final CheckMeECGWaveModel checkMeECGWave; + + CheckMeECGChartView({@required this.checkMeECGWave}); + + @override + Widget build(BuildContext context) { + List list = checkMeECGWave.bytes; + List> mainList = chunkIntList(list, 1250); + return ListView.separated( + shrinkWrap: true, + physics: ScrollPhysics(), + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.only(right: MediaQuery.of(context).size.width - (MediaQuery.of(context).size.width * (mainList[index].length / 1250))), + child: SizedBox( + height: 120.0, + child: LineChart( + LineChartData( + lineTouchData: LineTouchData(handleBuiltInTouches: false), + gridData: FlGridData( + show: true, + verticalInterval: 30, + horizontalInterval: 30, + getDrawingVerticalLine: (value) { + return FlLine( + color: Colors.red[300], + strokeWidth: 0.4, + ); + }, + getDrawingHorizontalLine: (value) { + return FlLine( + color: Colors.red[300], + strokeWidth: 0.4, + ); + }, + ), + titlesData: FlTitlesData(show: false), + borderData: FlBorderData( + show: false, + border: Border.all(color: const Color(0xff37434d), width: 1), + ), + minX: 0, + maxX: (mainList[index].length.toDouble() - 1), + minY: list.reduce((value, element) => value < element ? value : element).toDouble(), + maxY: list.reduce((value, element) => value > element ? value : element).toDouble(), + lineBarsData: [ + LineChartBarData( + isCurved: false, + preventCurveOverShooting: true, + barWidth: 0.5, + dotData: FlDotData(show: false), + spots: getDataList(mainList[index]), + colors: [Colors.grey[800]], + isStrokeCapRound: true, + belowBarData: BarAreaData(show: false), + ), + ], + ), + ), + ), + ); + }, + itemCount: mainList.length, + separatorBuilder: (context, index) => SizedBox(height: 14), + ); + } + + List> chunkIntList(List list, int chunkSize) { + List> chunks = []; + for (int i = 0; i < list.length; i += chunkSize) { + int end = i + chunkSize; + chunks.add(list.sublist(i, end > list.length ? list.length : end)); + } + return chunks; + } + + List getDataList(List list) { + List spotsList = []; + for (int i = 0; i < list.length; i++) { + spotsList.add(FlSpot(i.toDouble(), list[i].toDouble())); + } + return spotsList; + } +} diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_info_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_info_screen.dart new file mode 100644 index 00000000..168c117a --- /dev/null +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_info_screen.dart @@ -0,0 +1,114 @@ +import 'package:diplomaticquarterapp/config/size_config.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/checkme_ecg_chart_view.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_bp_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_glucose_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_oxi_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_temperature_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class CheckMeECGInfoScreen extends StatelessWidget { + final TrackerTypeEnum allInOneTrackerTypeEnum; + + const CheckMeECGInfoScreen(this.allInOneTrackerTypeEnum); + + String getTrackerNameByEnum(TrackerTypeEnum trackerTypeEnum) { + switch (trackerTypeEnum) { + case TrackerTypeEnum.OxymeterTracker: + return "Oxymeter"; + + case TrackerTypeEnum.BloodPressureTracker: + return "Blood Pressure"; + + case TrackerTypeEnum.BloodSugarTracker: + return "Blood Glucose"; + + case TrackerTypeEnum.ECGTracker: + return "ECG"; + + case TrackerTypeEnum.WeightScale: + return "Weight Scale"; + + case TrackerTypeEnum.Temperature: + return "Temperature"; + + case TrackerTypeEnum.Spirometer: + return "Spirometer"; + + case TrackerTypeEnum.AllInOneTracker: + return "All in One"; + } + return "All in One"; + } + + Widget buildECGDetailsWidget(MyTrackersViewModel myTrackersVm, BuildContext context) { + return Container( + decoration: cardRadius(12), + padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text("HR: ${myTrackersVm.checkMeECGWave.hr} bpm"), + Text("ST: ${myTrackersVm.checkMeECGWave.st} mV"), + Text("QRS: ${myTrackersVm.checkMeECGWave.qrs} ms"), + ], + ), + mHeight(4.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text("PVCS: ${myTrackersVm.checkMeECGWave.pvcs} "), + Text("QTC: ${myTrackersVm.checkMeECGWave.qtc} ms"), + Text("QT: ${myTrackersVm.checkMeECGWave.qt} ms"), + ], + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: "${getTrackerNameByEnum(allInOneTrackerTypeEnum)}", + showNewAppBar: true, + isShowDecPage: false, + showNewAppBarTitle: true, + backgroundColor: Color(0xffF8F8F8), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Consumer( + builder: (BuildContext context, MyTrackersViewModel myTrackersVm, Widget child) { + if (myTrackersVm.checkMeECGWave == null) { + return Padding( + padding: const EdgeInsets.all(24.0), + child: Center( + child: Text( + "Some animation with the instruction", + style: TextStyle(fontSize: 9.0), + ), + ), + ); + } + return Column( + children: [ + buildECGDetailsWidget(myTrackersVm, context), + mHeight(20), + CheckMeECGChartView(checkMeECGWave: myTrackersVm.checkMeECGWave), + ], + ); + }, + ), + ), + ), + ); + } +} 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 4d704a6a..1ce1ddf6 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 @@ -199,7 +199,19 @@ class BleChannel { try { print("----------Flutter getEcgDataFromCheckMePro -------"); final String result = await platform.invokeMethod('getEcgDataFromCheckMePro'); - print("----------Flutter getDeviceInfoCheckMePro result -------"); + print("----------Flutter getEcgDataFromCheckMePro result -------"); + print(result); + return result; + } catch (e) { + return "Error: $e"; + } + } + + static Future getEcgWaveDataFromCheckMePro(String timeString) async { + try { + print("----------Flutter getEcgWaveFromCheckMePro -------"); + final String result = await platform.invokeMethod('getEcgWaveFromCheckMePro', timeString); + print("----------Flutter getEcgWaveFromCheckMePro result -------"); print(result); return result; } catch (e) { diff --git a/lib/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_wave_model.dart b/lib/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_wave_model.dart new file mode 100644 index 00000000..6f763f1a --- /dev/null +++ b/lib/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_wave_model.dart @@ -0,0 +1,58 @@ +class CheckMeECGWaveModel { + List bytes; + int hr; + List hrList; + int hrSize; + int pvcs; + int qrs; + int qt; + int qtc; + int result; + int st; + int total; + int waveIntSize; + List waveList; + int waveSize; + int waveViewSize; + + CheckMeECGWaveModel( + {this.bytes, this.hr, this.hrList, this.hrSize, this.pvcs, this.qrs, this.qt, this.qtc, this.result, this.st, this.total, this.waveIntSize, this.waveList, this.waveSize, this.waveViewSize}); + + CheckMeECGWaveModel.fromJson(Map json) { + bytes = json['bytes'].cast(); + hr = json['hr']; + hrList = json['hrList'].cast(); + hrSize = json['hrSize']; + pvcs = json['pvcs']; + qrs = json['qrs']; + qt = json['qt']; + qtc = json['qtc']; + result = json['result']; + st = json['st']; + total = json['total']; + waveIntSize = json['waveIntSize']; + waveList = json['waveList'].cast(); + waveSize = json['waveSize']; + waveViewSize = json['waveViewSize']; + } + + Map toJson() { + final Map data = new Map(); + data['bytes'] = this.bytes; + data['hr'] = this.hr; + data['hrList'] = this.hrList; + data['hrSize'] = this.hrSize; + data['pvcs'] = this.pvcs; + data['qrs'] = this.qrs; + data['qt'] = this.qt; + data['qtc'] = this.qtc; + data['result'] = this.result; + data['st'] = this.st; + data['total'] = this.total; + data['waveIntSize'] = this.waveIntSize; + data['waveList'] = this.waveList; + data['waveSize'] = this.waveSize; + data['waveViewSize'] = this.waveViewSize; + return data; + } +} 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 31d491c2..0d7c1375 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 @@ -7,6 +7,7 @@ import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesf import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_bp_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_ecg_wave_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_glucose_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_oxi_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/checkmepro_all_in_one_models/checkme_temperature_model.dart'; @@ -45,6 +46,7 @@ String kDevicesListCheckMe = "DevicesListCheckMe"; String kCheckMeUsersList = "CheckMeUsersList"; String kTemperatureCheckMePro = "TemperatureCheckMePro"; String kECGCheckMePro = "ECGCheckMePro"; +String kECGWaveCheckMePro = "ECGWaveCheckMePro"; String kOxiCheckMePro = "OxiCheckMePro"; String kGlucoseCheckMePro = "GlucoseCheckMePro"; String kBPCheckMePro = "BPCheckMePro"; @@ -1109,6 +1111,9 @@ class MyTrackersViewModel extends ChangeNotifier { if (event['type'] == kECGCheckMePro) { updateCheckMeEcgInfoModel(json.decode(event['data'])); } + if (event['type'] == kECGWaveCheckMePro) { + updateCheckMeEcgWaveInfoModel(json.decode(event['data'])); + } if (event['type'] == kBPCheckMePro) { updateCheckMeBPInfoModel(json.decode(event['data'])); } @@ -1204,19 +1209,7 @@ class MyTrackersViewModel extends ChangeNotifier { ), ) ] else ...[ - Material( - child: Center( - child: Text( - "No Users to show", - style: TextStyle( - fontSize: SizeConfig.textMultiplier * 1.6, - fontWeight: FontWeight.w600, - letterSpacing: -0.3, - height: 13 / 10, - ), - ), - ), - ), + getNoDataWidget(context), ] ], ); @@ -1227,6 +1220,9 @@ class MyTrackersViewModel extends ChangeNotifier { } Future getTempDataFromCheckMePro() async { + if (checkMeTemperatures != null) { + checkMeTemperatures.clear(); + } await BleChannel.getTempDataFromCheckMePro(); } @@ -1241,6 +1237,9 @@ class MyTrackersViewModel extends ChangeNotifier { } Future getOxiDataFromCheckMePro() async { + if (checkMeOxi != null) { + checkMeOxi.clear(); + } await BleChannel.getOxiDataFromCheckMePro(); } @@ -1255,6 +1254,9 @@ class MyTrackersViewModel extends ChangeNotifier { } Future getECGDataFromCheckMePro() async { + if (checkMeEcg != null) { + checkMeEcg.clear(); + } await BleChannel.getEcgDataFromCheckMePro(); } @@ -1268,7 +1270,27 @@ class MyTrackersViewModel extends ChangeNotifier { notifyListeners(); } + Future getEcgWaveDataFromCheckMePro(String timeString) async { + if (checkMeECGWave != null) { + checkMeECGWave = null; + } + await BleChannel.getEcgWaveDataFromCheckMePro(timeString); + } + + CheckMeECGWaveModel checkMeECGWave; + + void updateCheckMeEcgWaveInfoModel(returnData) { + if (checkMeECGWave != null) { + checkMeECGWave = null; + } + checkMeECGWave = CheckMeECGWaveModel.fromJson(returnData); + notifyListeners(); + } + Future getBPDataFromCheckMePro(String userId) async { + if (checkMeBP != null) { + checkMeBP.clear(); + } await BleChannel.getBPDataFromCheckMePro(userId); } @@ -1283,6 +1305,9 @@ class MyTrackersViewModel extends ChangeNotifier { } Future getGlucoseDataFromCheckMePro(String userId) async { + if (checkMeGlucose != null) { + checkMeGlucose.clear(); + } await BleChannel.getGlucoseDataFromCheckMePro(userId); }