· 6 years ago · May 02, 2020, 01:54 PM
1import 'dart:async';
2import 'dart:convert';
3import 'dart:io';
4
5import 'package:flutter/material.dart';
6import 'package:health_gauge/apis/PostMeasurementData.dart';
7import 'package:health_gauge/apis/PostSportData.dart';
8import 'package:health_gauge/apis/PostTagLabel.dart';
9import 'package:health_gauge/models/DeviceModel.dart';
10import 'package:health_gauge/models/Tag.dart';
11import 'package:health_gauge/models/TagNote.dart';
12import 'package:health_gauge/models/infoModels/DeviceInfoModel.dart';
13import 'package:health_gauge/models/infoModels/HeartInfoModel.dart';
14import 'package:health_gauge/models/infoModels/MotionInfoModel.dart';
15import 'package:health_gauge/models/infoModels/SleepInfoModel.dart';
16import 'package:health_gauge/models/infoModels/WoHeartInfoModel.dart';
17import 'package:health_gauge/models/measurement/EcgInfoReadingModel.dart';
18import 'package:health_gauge/models/measurement/MeasurementHistoryModel.dart';
19import 'package:health_gauge/screens/SettingScreen.dart';
20import 'package:health_gauge/screens/SleepHistoryPage.dart';
21import 'package:health_gauge/screens/SportActivityScreen.dart';
22import 'package:health_gauge/utils/Connections.dart';
23import 'package:health_gauge/utils/Constants.dart';
24import 'package:health_gauge/utils/DatabaseHelper.dart';
25import 'package:health_gauge/value/AppColor.dart';
26import 'package:health_gauge/value/Images.dart';
27import 'package:health_gauge/widgets/Buttons.dart';
28import 'package:health_gauge/widgets/TextUtils.dart';
29import 'package:intl/intl.dart';
30import 'package:percent_indicator/linear_percent_indicator.dart';
31import 'package:shared_preferences/shared_preferences.dart';
32
33import 'package:flutter_screenutil/flutter_screenutil.dart';
34
35import '../main.dart';
36import 'ConnectionScreen.dart';
37import 'MesurementScreen.dart';
38import 'ProfileScreen.dart';
39import 'SignInScreen.dart';
40
41Images images = new Images();
42
43class DashBoardScreen extends StatefulWidget {
44 DashBoardScreen({Key key}) : super(key: key);
45
46 @override
47 DashBoardScreenState createState() => DashBoardScreenState();
48}
49
50class DashBoardScreenState extends State<DashBoardScreen> implements PerformerListener {
51 bool isLoading;
52 bool isErrorInGetMessage = false;
53
54 SharedPreferences sharedPreferences;
55
56 String userId;
57
58 //this model is use for display measurement hr, bp and hrv
59 EcgInfoReadingModel ecgInfoReadingModel;
60
61 //this is mac address of last connected device
62 DeviceModel connectedDevice;
63
64 //this class is use for doing connection utilities like for find that "is device connected or not?"
65 Connections connections;
66
67 //this model used at activity card
68 MotionInfoModel motionInfoModel;
69
70 //this model will use in sleep card
71 SleepInfoModel sleepModel;
72
73 //this model is use for get battery level
74 DeviceInfoModel deviceInfoModel;
75
76 //this is use for store data table wise in local storage
77 final dbHelper = DatabaseHelper.instance;
78
79 double targetSteps = 2000;
80
81 Timer timer;
82
83 int targetMinute = 480;
84
85 @override
86 void initState() {
87 dbHelper.database;
88 //this is registering data listener for whenever data came from sdk then that will be in this class's listener
89 connections = Connections(performerListener: this);
90
91 getPreferences();
92
93 timerForCheckConnection();
94
95 getEcgInfoReadingData();
96 syncDataToApi();
97 super.initState();
98 }
99
100 void syncDataToApi() async {
101 await getPreferences();
102 bool isInternet = await Constants.isInternetAvailable();
103 if (isInternet && userId != null && userId.isNotEmpty && !userId.contains("Skip")) {
104 syncMotionInfoList();
105 syncSleepInfoList();
106 syncMeasurementData();
107 syncTagLabels();
108 syncTagNotes();
109 }
110 }
111
112 @override
113 Widget build(BuildContext context) {
114 return SafeArea(
115 top: false,
116 bottom: Platform.isIOS,
117 child: Scaffold(
118 appBar: AppBar(
119 leading: IconButton(
120 icon: Icon(Icons.account_circle, size: 25.0),
121 onPressed: () {
122 if (userId == null || userId.contains("Skip")) {
123 var dialog = AlertDialog(
124 title: Text(strings.appName),
125 content: Text(strings.pleaseLoginFirstToUseThisFeature),
126 actions: <Widget>[
127 FlatBtn(
128 onPressed: () {
129 Navigator.of(context, rootNavigator: true).pop();
130 },
131 text: strings.cancel),
132 FlatBtn(
133 onPressed: () async {
134 await Constants.logout();
135 Constants.navigatePushAndRemove(
136 SignInScreen(), context,
137 rootNavigation: true);
138 },
139 text: strings.ok),
140 ],
141 );
142 showDialog(
143 context: context,
144 useRootNavigator: true,
145 builder: (context) => dialog);
146 } else {
147 Constants.navigatePush(ProfileScreen(), context,
148 rootNavigation: false);
149 }
150 },
151 ),
152 title: Container(
153 child: Stack(
154 overflow: Overflow.visible,
155 alignment: Alignment.center,
156 children: <Widget>[
157 Positioned(
158 left: -16.0,
159 child: batteryWidget(),
160 ),
161 Container(
162 margin: EdgeInsets.only(left: 50.0.w),
163 alignment: Alignment.center,
164 child: Text(
165 strings.dashBoardName,
166 ),
167 ),
168 ],
169 ),
170 ),
171 actions: <Widget>[
172 bluetoothBtn(context),
173 IconButton(
174 icon: Icon(Icons.settings),
175 onPressed: () async {
176 await Constants.navigatePush(SettingScreen(), context,
177 rootNavigation: false);
178 getStepTarget();
179 getSleepTarget();
180 },
181 ),
182 ],
183 ),
184 body: layoutMain(),
185 ),
186 );
187 }
188
189 Widget batteryWidget() {
190 if (deviceInfoModel != null && deviceInfoModel.power != null) {
191 return Tooltip(
192 child: RotatedBox(
193 quarterTurns: 135,
194 child: Container(
195 child: Stack(
196 alignment: Alignment.center,
197 children: <Widget>[
198 RotatedBox(
199 quarterTurns: 45,
200 child: Image.asset(
201 "asset/battery.png",
202 color: Colors.white,
203 height: 30.0.h,
204 width: 30.0.h,
205 ),
206 ),
207 Container(
208 child: LinearPercentIndicator(
209 width: 45.0.w,
210 lineHeight: 12.0.h,
211 backgroundColor: Colors.transparent,
212 percent: (deviceInfoModel.power + 0.0) / 100,
213 center: RotatedBox(
214 quarterTurns: 45,
215 child: new CaptionText(
216 text: deviceInfoModel.power >= 100
217 ? ""
218 : "${deviceInfoModel.power}",
219 color: Colors.black)),
220 progressColor: Colors.white,
221 linearStrokeCap: LinearStrokeCap.butt,
222 ),
223 )
224 ],
225 ),
226 ),
227 ),
228 message: strings.deviceBattery,
229 );
230 }
231 return Container();
232 }
233
234 Widget bluetoothBtn(BuildContext context) {
235 return IconButton(
236 icon: Icon(
237 connectedDevice != null ? Icons.bluetooth : Icons.bluetooth_disabled),
238 onPressed: () async {
239 timer.cancel();
240 var result = await Constants.navigatePush(ConnectionScreen(performerListener: this), context, rootNavigation: false);
241 timerForCheckConnection();
242
243 var value = sharedPreferences.getString(Constants.connectedDeviceAddressPrefKey);
244 if (value != null) {
245 var val = jsonDecode(value);
246 if (val is Map) {
247 connectedDevice = DeviceModel.fromMap(val);
248 }
249 } else {
250 deviceInfoModel = null;
251 connectedDevice = null;
252 getSleepData();
253 getMotionData();
254 }
255 if (mounted) {
256 setState(() {});
257 }
258 },
259 );
260 }
261
262 Timer timerForCheckConnection() {
263 return timer = Timer.periodic(Duration(seconds: 5), (val) {
264 if(deviceInfoModel == null) {
265 connections = Connections(performerListener: this);
266 getPreferences();
267 }
268 });
269 }
270
271 Widget layoutMain() {
272 return dataLayout();
273 }
274
275 Widget dataLayout() {
276 return ListView(
277 // padding: EdgeInsets.all(8.0),
278 padding: EdgeInsets.only(top: 8.0.h, right: 8.0.w, left: 8.0.w, bottom: 8.0.h),
279 shrinkWrap: true,
280 children: <Widget>[
281 healthCard(),
282 activityCard(),
283 sleepCard(),
284 ],
285 );
286 }
287
288 Card healthCard() {
289 if (ecgInfoReadingModel == null) {
290 ecgInfoReadingModel = new EcgInfoReadingModel();
291 ecgInfoReadingModel.approxHr = 0;
292 ecgInfoReadingModel.hrv = 0;
293 ecgInfoReadingModel.approxSBP = 0;
294 }
295 return Card(
296 child: InkWell(
297 onTap: () {
298 onClickMeasurement();
299 },
300 child: Column(
301 crossAxisAlignment: CrossAxisAlignment.stretch,
302 children: <Widget>[
303 Container(
304// margin: EdgeInsets.all(8.0),
305// padding: EdgeInsets.all(8.0),
306 margin: EdgeInsets.only(top: 8.0.h, right: 8.0.w, left: 8.0.w, bottom: 8.0.h),
307 padding: EdgeInsets.only(top: 8.0.h, right: 8.0.w, left: 8.0.w, bottom: 8.0.h),
308 color: Colors.grey[200],
309
310 child: Column(
311 children: <Widget>[
312 Row(
313 mainAxisAlignment: MainAxisAlignment.spaceBetween,
314 crossAxisAlignment: CrossAxisAlignment.start,
315 children: <Widget>[
316 Body1Text(text: strings.bp),
317 Body1Text(
318 text: ecgInfoReadingModel.approxSBP != null
319 ? ecgInfoReadingModel.approxSBP.toString()
320 : strings.offLineEcgSbp),
321 ],
322 ),
323 SizedBox(height: 8.0.h),
324 Row(
325 mainAxisAlignment: MainAxisAlignment.spaceBetween,
326 crossAxisAlignment: CrossAxisAlignment.start,
327 children: <Widget>[
328 Body1Text(text: strings.heartRate),
329 Body1Text(
330 text: ecgInfoReadingModel.approxHr != null
331 ? ecgInfoReadingModel.approxHr.toString()
332 : "0"),
333 ],
334 ),
335 SizedBox(height: 8.0.h),
336 Row(
337 mainAxisAlignment: MainAxisAlignment.spaceBetween,
338 crossAxisAlignment: CrossAxisAlignment.start,
339 children: <Widget>[
340 Body1Text(text: strings.hrv),
341 Body1Text(
342 text: ecgInfoReadingModel.hrv != null
343 ? ecgInfoReadingModel.hrv.toString()
344 : "0"),
345 ],
346 ),
347 ],
348 ),
349 ),
350 Container(
351 height: 40.0.h,
352 child: Row(
353 mainAxisAlignment: MainAxisAlignment.center,
354 children: <Widget>[
355 TitleText(text: strings.health, color: AppColor.primaryColor),
356 SizedBox(width: 5.0.w),
357 Image.asset(
358 "asset/goal.png",
359 height: 25.0.h,
360 width: 25.0.w,
361 )
362 ],
363 ),
364 )
365 ],
366 ),
367 ),
368 );
369 }
370
371 Card activityCard() {
372 if (motionInfoModel == null) {
373 motionInfoModel =
374 new MotionInfoModel(calories: 0, distance: 0, date: "0", step: 0);
375 }
376 return Card(
377 child: InkWell(
378 onTap: () {
379 Constants.navigatePush(SportActivityScreen(), context);
380 },
381 child: Column(
382 crossAxisAlignment: CrossAxisAlignment.stretch,
383 children: <Widget>[
384 Container(
385// margin: EdgeInsets.all(8.0),
386// padding: EdgeInsets.all(8.0),
387 margin: EdgeInsets.only(top: 8.0.h, right: 8.0.w, left: 8.0.w, bottom: 8.0.h),
388 padding: EdgeInsets.only(top: 8.0.h, right: 8.0.w, left: 8.0.w, bottom: 8.0.h),
389 color: Colors.grey[200],
390
391 child: Column(
392 children: <Widget>[
393 Row(
394 mainAxisAlignment: MainAxisAlignment.spaceBetween,
395 crossAxisAlignment: CrossAxisAlignment.start,
396 children: <Widget>[
397 Body1Text(text: strings.complete),
398 completeTxt(),
399 ],
400 ),
401 SizedBox(height: 8.0.h),
402 Row(
403 mainAxisAlignment: MainAxisAlignment.spaceBetween,
404 crossAxisAlignment: CrossAxisAlignment.start,
405 children: <Widget>[
406 Body1Text(text: strings.steps),
407 Body1Text(
408 text: motionInfoModel.step != null
409 ? motionInfoModel.step.toString()
410 : "0"),
411 ],
412 ),
413 SizedBox(height: 8.0.h),
414 Row(
415 mainAxisAlignment: MainAxisAlignment.spaceBetween,
416 crossAxisAlignment: CrossAxisAlignment.start,
417 children: <Widget>[
418 Body1Text(text: strings.calories),
419 Body1Text(
420 text: motionInfoModel.calories != null
421 ? double.parse(motionInfoModel.calories
422 .toStringAsFixed(2))
423 .toString() +
424 strings.kml
425 : strings.zeroKml),
426 ],
427 ),
428 SizedBox(height: 8.0.h),
429 Row(
430 mainAxisAlignment: MainAxisAlignment.spaceBetween,
431 crossAxisAlignment: CrossAxisAlignment.start,
432 children: <Widget>[
433 Body1Text(text: strings.distance),
434 Body1Text(
435 text: motionInfoModel.distance != null
436 ? double.parse(motionInfoModel.distance
437 .toStringAsFixed(2))
438 .toString() +
439 strings.km
440 : strings.zeroKm),
441 ],
442 ),
443 ],
444 ),
445 ),
446 Container(
447 height: 40.0.h,
448 child: Row(
449 mainAxisAlignment: MainAxisAlignment.center,
450 children: <Widget>[
451 TitleText(
452 text: strings.activity, color: AppColor.primaryColor),
453 SizedBox(width: 5.0.w),
454 Image.asset(
455 "asset/running_sport_icon.png",
456 height: 25.0.h,
457 width: 25.0.w,
458 )
459 ],
460 ),
461 )
462 ],
463 ),
464 ),
465 );
466 }
467
468 Body1Text completeTxt() {
469 int step = 0;
470 if (motionInfoModel == null || motionInfoModel.step == null) {
471 step = 0;
472 } else {
473 step = motionInfoModel.step;
474 }
475 /*if (targetSteps < step) {
476 targetSteps = step + 0.0;
477 }*/
478 return Body1Text(
479 text: ((step * 100) / targetSteps).toStringAsFixed(2) + "%");
480 }
481
482 Card sleepCard() {
483 String time = "0";
484 String complete = "0%";
485 if (sleepModel != null) {
486 if (sleepModel.data.length > 0) {
487 int hour = sleepModel.sleepAllTime~/60;
488 int minute = (sleepModel.sleepAllTime%60).toInt();
489 time = "${hour.toString().padLeft(2, "0")} h ${minute.toString().padLeft(2, "0")} m";
490 int completePercentage = (sleepModel.sleepAllTime * 100) ~/ targetMinute;
491 complete = "$completePercentage%";
492 }
493 }
494 return Card(
495 child: InkWell(
496 onTap: () {
497 Constants.navigatePush(SleepHistoryScreen(), context);
498 },
499 child: Column(
500 crossAxisAlignment: CrossAxisAlignment.stretch,
501 children: <Widget>[
502 Container(
503// margin: EdgeInsets.all(8.0),
504// padding: EdgeInsets.all(8.0),
505 margin: EdgeInsets.only(top: 8.0.h, right: 8.0.w, left: 8.0.w, bottom: 8.0.h),
506 padding: EdgeInsets.only(top: 8.0.h, right: 8.0.w, left: 8.0.w, bottom: 8.0.h),
507 color: Colors.grey[200],
508 child: Column(
509 children: <Widget>[
510 Row(
511 mainAxisAlignment: MainAxisAlignment.spaceBetween,
512 crossAxisAlignment: CrossAxisAlignment.start,
513 children: <Widget>[
514 Body1Text(text: strings.sleepHour),
515 Body1Text(text: "$time"),
516 ],
517 ),
518 SizedBox(height: 8.0.h),
519 Row(
520 mainAxisAlignment: MainAxisAlignment.spaceBetween,
521 crossAxisAlignment: CrossAxisAlignment.start,
522 children: <Widget>[
523 Body1Text(text: strings.complete),
524 Body1Text(text: "$complete"),
525 ],
526 ),
527 ],
528 ),
529 ),
530 Container(
531 height: 40.0.h,
532 child: Row(
533 mainAxisAlignment: MainAxisAlignment.center,
534 children: <Widget>[
535 TitleText(text: strings.sleep, color: AppColor.primaryColor),
536 SizedBox(width: 5.0.w),
537 Image.asset(
538 "asset/sleep_icon.png",
539 height: 25.0.h,
540 width: 25.0.w,
541 )
542 ],
543 ),
544 )
545 ],
546 ),
547 ));
548 }
549
550 static String convertHoursMinutes(String time) {
551 //=======to calculate hours_minutes=========
552 int value_total_minutes = int.parse(time) % 60;
553 double value_total_hours = int.parse(time) / 60;
554
555 /*DecimalFormat decimalFormat = new DecimalFormat("#0");
556 String final_hours_value = String.valueOf(decimalFormat.format(value_total_hours));*/
557 return time;
558 }
559
560 void onClickGraph() {}
561
562 void onClickMeasurement() async {
563 timer.cancel();
564 await Constants.navigatePush(MeasurementScreen(), context);
565 timerForCheckConnection();
566 getEcgInfoReadingData();
567 }
568
569 //in this will get device info like battery, name, etc..
570 @override
571 void onResponseDeviceInfo(DeviceInfoModel deviceInfo) {
572 deviceInfoModel = deviceInfo;
573 print("Flutter device info" + deviceInfoModel.toString());
574 if (mounted) {
575 setState(() {});
576 }
577 }
578
579 //in this we will get activity info like steps,kms,etc.
580 @override
581 Future<void> onResponseMotionInfo(MotionInfoModel mMotionInfo) async {
582 this.motionInfoModel = mMotionInfo;
583 // print("Flutter Motion Info Model " + motionInfoModel.toString());
584 await saveMotionDataToDb(mMotionInfo);
585 if (mounted) {
586 setState(() {});
587 }
588 }
589
590 //in this we will get sleep info
591 @override
592 Future<void> onResponseSleepInfo(SleepInfoModel mSleepInfo) async {
593 //Type sleep duration (0: stay up all night, 1: sleep, 2: light sleep, 3: deep sleep, 4: wake up halfway, 5: get up)
594 sleepModel = mSleepInfo;
595 print("Flutter Sleep Info Model " + sleepModel.toString());
596 await saveSleepDataToDb(sleepModel);
597 if (mounted) {
598 setState(() {});
599 }
600 }
601
602 @override
603 void onResponsePoHeartInfo(HeartInfoModel mPoHeartInfo) {
604 //todo implement onResponsePoHeartInfo
605 }
606
607 @override
608 void onResponseWoHeartInfo(WoHeartInfoModel mWoHeartInfo) {
609 // TODO: implement onResponseWoHeartInfo
610 }
611
612 //this method is called after every update in watch..........
613 //save activity data to local and also post if internet is available
614 Future saveMotionDataToDb(MotionInfoModel mMotionInfo) async {
615 if (userId == null) {
616 return;
617 }
618
619 Map map = mMotionInfo.toMap();
620 map.putIfAbsent("user_Id", () => userId);
621
622 List<MotionInfoModel> motions =
623 await dbHelper.getActivityData(userId.toString());
624 if (motions.length > 0) {
625 MotionInfoModel model = motions.last;
626 DateTime dateTime = DateTime.parse(model.date);
627 DateTime currentDate = DateTime.now();
628 if (currentDate.isAfter(dateTime) &&
629 currentDate.difference(dateTime).inHours > 1) {
630 await postMotionData(mMotionInfo);
631 }
632 } else {
633 await postMotionData(mMotionInfo);
634 }
635 print(motions);
636 }
637
638 //save sleep data to local and also post if internet is available
639 Future saveSleepDataToDb(SleepInfoModel sleepInfoModel) async {
640 if (userId == null) {
641 return;
642 }
643 Map<String, dynamic> map = sleepInfoModel.toMap();
644 map.putIfAbsent("user_Id", () => userId);
645
646 List<SleepInfoModel> sleeps =
647 await dbHelper.getSleepData(userId.toString());
648 if (sleeps.length > 0) {
649 SleepInfoModel model = sleeps.last;
650 DateTime dateTime = DateTime.parse(model.date);
651 DateTime currentDate = DateTime.now();
652 if (currentDate.isAfter(dateTime) &&
653 currentDate.difference(dateTime).inHours > 1) {
654 postSleepData(sleepInfoModel);
655 }
656 } else {
657 postSleepData(sleepInfoModel);
658 }
659 }
660
661 //call api for post activity data
662 Future postMotionData(MotionInfoModel model) async {
663 Map<String, dynamic> dbMap = model.toMap();
664 if (model.id != null && model.id != 0) {
665 dbMap.putIfAbsent("id", () => model.id);
666 }
667 dbMap.putIfAbsent("user_Id", () => userId);
668 bool isInternet = await Constants.isInternetAvailable();
669 if (isInternet && !userId.contains("Skip")) {
670 Map map = {
671 "userid": userId,
672 "motionCalorie": model.calories,
673 "motionDate": model.date,
674 "motionDistance": model.distance,
675 "motionSteps": model.step
676 };
677 Map result = await PostSportsData().callApi(
678 Constants.baseUrl + "StoreMotionRecordDtls", jsonEncode(map));
679 print("motion data result = $result");
680 if (!result["isError"]) {
681 dbMap.putIfAbsent("IsSync", () => true);
682 } else {
683 dbMap.putIfAbsent("IsSync", () => false);
684 }
685 int insertResult = await dbHelper.insertActivityData(dbMap);
686 print("insertResult $insertResult");
687 } else {
688 dbMap.putIfAbsent("IsSync", () => false);
689 int insertResult = await dbHelper.insertActivityData(dbMap);
690 print("insertResult $insertResult");
691 }
692 }
693
694 //call api for post sleep data
695 Future postSleepData(SleepInfoModel model) async {
696 Map<String, dynamic> dbMap = model.toMap();
697 dbMap.putIfAbsent("user_Id", () => userId);
698 if (model.id != null && model.id != 0) {
699 dbMap.putIfAbsent("id", () => model.id);
700 }
701 bool isInternet = await Constants.isInternetAvailable();
702 if (isInternet && !userId.contains("Skip")) {
703 Map map = model.toMapForApi();
704 map.putIfAbsent("id", () => 0);
705 map.putIfAbsent("userid", () => userId);
706 map.putIfAbsent("username", () => "");
707 Map result = await PostSportsData()
708 .callApi(Constants.baseUrl + "StoreSleepRecordDtls", jsonEncode(map));
709 if (!result["isError"]) {
710 dbMap.putIfAbsent("IsSync", () => true);
711 } else {
712 dbMap.putIfAbsent("IsSync", () => false);
713 }
714 int insertResult = await dbHelper.insertSleepData(dbMap);
715 print("insertResult $insertResult");
716 } else {
717 dbMap.putIfAbsent("IsSync", () => false);
718 int result = await dbHelper.insertSleepData(dbMap);
719 print("insertResult $result");
720 }
721 }
722
723 //get hr, bp and hrv from local database
724 getEcgInfoReadingData() async {
725 if (sharedPreferences == null) {
726 await getPreferences();
727 }
728 await dbHelper
729 .getMeasurementData(userId)
730 .then((List<EcgInfoReadingModel> ecgList) {
731 if (ecgList.length > 0) {
732 ecgInfoReadingModel = ecgList.last;
733 if (mounted) {
734 setState(() {});
735 }
736 }
737 });
738 }
739
740 //get activity data from local
741 getMotionData() async {
742 if (sharedPreferences == null) {
743 await getPreferences();
744 }
745 if (connectedDevice == null) {
746 dbHelper
747 .getActivityData(userId.toString())
748 .then((List<MotionInfoModel> motionInfoList) {
749 if (motionInfoList.length > 0) {
750 motionInfoModel = motionInfoList.last;
751 if (mounted) {
752 setState(() {});
753 }
754 }
755 });
756 }
757 }
758
759 //get sleep data from local
760 getSleepData() async {
761 if (sharedPreferences == null) {
762 await getPreferences();
763 }
764 dbHelper
765 .getSleepData(userId.toString())
766 .then((List<SleepInfoModel> sleepInfoList) {
767 if (sleepInfoList.length > 0) {
768 sleepModel = sleepInfoList.last;
769 if (mounted) {
770 setState(() {});
771 }
772 }
773 });
774 }
775
776 syncMotionInfoList() async {
777 await getPreferences();
778 if (userId != null) {
779 try {
780 List<MotionInfoModel> motions =
781 await dbHelper.getActivityData(userId.toString());
782 for (MotionInfoModel model in motions) {
783 if (model.isSync == 0) {
784 await postMotionData(model);
785 }
786 }
787 } catch (e) {
788 print(e);
789 }
790 }
791 }
792
793 syncSleepInfoList() async {
794 await getPreferences();
795 if (userId != null) {
796 try {
797 List<SleepInfoModel> list =
798 await dbHelper.getSleepData(userId.toString());
799 for (SleepInfoModel model in list) {
800 if (model.isSync == 0) {
801 await postSleepData(model);
802 }
803 }
804 } catch (e) {
805 print(e);
806 }
807 }
808 }
809
810 syncMeasurementData() async {
811 await getPreferences();
812 if (userId != null) {
813 try {
814 List<MeasurementHistoryModel> list =
815 await dbHelper.getMeasurementData1(userId);
816 for (MeasurementHistoryModel model in list) {
817 if (model.isSync == 0) {
818 await postMeasurementData(model);
819 }
820 }
821 } catch (e) {
822 print(e);
823 }
824 }
825 }
826
827 syncTagLabels() async {
828 await getPreferences();
829 if (userId != null) {
830 List<Tag> tagList = await dbHelper.getUnSyncTagList(userId);
831 for (Tag tag in tagList) {
832 //region post to api
833 Map postMap = {
834 "ImageName" : tag.icon,
835 "UnitName" : tag.unit,
836 "LabelName": tag.label,
837 "MinRange": tag.min,
838 "MaxRange": tag.max,
839 "DefaultValue": tag.defaultValue,
840 "PrecisionDigit": tag.precision
841 };
842 Map result;
843 if(tag.apiId != null && tag.apiId.isNotEmpty){
844 postMap.putIfAbsent("ID", ()=>tag.apiId);
845 result = await PostTagLabel().callApi(Constants.baseUrl + "EditTagLabel", jsonEncode(postMap));
846 }else{
847 result = await PostTagLabel().callApi(Constants.baseUrl + "AddTagLabel", jsonEncode(postMap));
848 }
849 if (!result["isError"]) {
850 tag.apiId = result["value"];
851 tag.isSync = 1;
852 }
853 //endregion
854
855 //region update in database
856 Map map = tag.toMap();
857 map.putIfAbsent("Id", () => tag.id);
858 var value = await dbHelper.insertTag(map);
859 print("update tag $value");
860 //endregion
861 }
862 }
863 }
864
865 syncTagNotes() async {
866 await getPreferences();
867 if (userId != null) {
868 List<TagNote> tagNoteList = await dbHelper.getUnSyncTagNoteList(userId);
869 for (TagNote note in tagNoteList) {
870 //region post to api
871 String date =
872 DateFormat("yyyy/dd/mm").format(DateTime.parse(note.date));
873 Map postMap = {
874 "date": "$date",
875 "note": note.note,
876 "time": timeOfDayString(note),
877 "type": note.label,
878 "userId": userId,
879 "value": note.value
880 };
881 Map result;
882 if(note.apiId != null && note.apiId.isNotEmpty){
883 postMap.putIfAbsent("ID", ()=>note.apiId);
884 result = await PostTagLabel().callApi(Constants.baseUrl + "EditTagRecordDtls", jsonEncode(postMap));
885 }else{
886 result = await PostTagLabel().callApi(Constants.baseUrl + "StoreTagRecordDtls", jsonEncode(postMap));
887 }
888 if (!result["isError"]) {
889 note.isSync = 1;
890 note.apiId = result["value"];
891 }
892 //endregion
893
894 //region update in database
895 Map map = note.toMap();
896 map.putIfAbsent("Id", () => note.id);
897 var value = await dbHelper.insertTagNote(map);
898 print("update tag $value");
899 //endregion
900 }
901 }
902 }
903
904 String timeOfDayString(TagNote tagSlider) {
905 String time;
906 try {
907 tagSlider.time = tagSlider.time.replaceAll("TimeOfDay(", "");
908 tagSlider.time = tagSlider.time.replaceAll(")", "");
909 TimeOfDay timeOfDay = TimeOfDay(
910 hour: int.parse(tagSlider.time.split(":")[0]),
911 minute: int.parse(tagSlider.time.split(":")[1]));
912 time =
913 "${timeOfDay.hour.toString().padLeft(2, "0")}:${timeOfDay.minute.toString().padLeft(2, "0")}:00";
914 } catch (e) {
915 print(e);
916 }
917 return time ?? "00:00:00";
918 }
919
920 Future postMeasurementData(MeasurementHistoryModel model) async {
921 if (userId.contains("Skip")) {
922 return Future.value();
923 }
924 Map<String, dynamic> dbMap = new Map<String, dynamic>();
925 dbMap.putIfAbsent("user_Id", () => userId);
926 if (model.id != null && model.id != 0) {
927 dbMap.putIfAbsent("id", () => model.id);
928 }
929 bool isInternet = await Constants.isInternetAvailable();
930 if (isInternet) {
931 Map map = {
932 "birthdate": "",
933 "data": [
934 {
935 "bg_manual": 0,
936 "demographics": {"age": 0, "gender": "", "height": 0, "weight": 0},
937 "device_id": "",
938 "device_type": "",
939 "dias_healthgauge": 0,
940 "o2_manual": 0,
941 "schema": "",
942 "sys_healthgauge": 0,
943 "username": "",
944 "model_id": "PROTO_1",
945
946 "userID": userId,
947 "raw_ecg": model.ecg,
948 "raw_ppg": model.ppg,
949 "raw_times": [], //todo this is remaining
950 "hrv_device": model.hrv,
951 "dias_device": model.dbp,
952 "hr_device": model.hr,
953 "sys_device": model.sbp,
954 "timestamp":
955 DateTime.parse(model.date).millisecondsSinceEpoch.toString(),
956 "sys_manual": model.tSbp ?? 0,
957 "dias_manual": model.tDbp ?? 0,
958 "hr_manual": model.tHr ?? 0,
959 }
960 ]
961 };
962 Map result = await PostMeasurementData()
963 .callApi(Constants.baseUrl + "estimate", jsonEncode(map));
964 if (!result["isError"]) {
965 await dbHelper.updateSyncInMeasurement(model.id);
966 }
967 }
968 }
969
970 @override
971 void onConnectIosDevice(DeviceModel device) async {
972 connectedDevice = device;
973 if (sharedPreferences == null) {
974 sharedPreferences = await SharedPreferences.getInstance();
975 }
976 sharedPreferences.setString(
977 Constants.connectedDeviceAddressPrefKey, jsonEncode(device.toMap()));
978 if (mounted) {
979 setState(() {});
980 }
981 }
982
983 Future<void> callApi() async {
984 isLoading = false;
985 if (mounted) {
986 setState(() {});
987 }
988 }
989
990 void popTillThis() {
991 Navigator.of(context).popUntil((route) => route.isFirst);
992 getEcgInfoReadingData();
993 if(timer == null || !timer.isActive){
994 timerForCheckConnection();
995 }
996 }
997
998 getPreferences() async {
999 sharedPreferences = await SharedPreferences.getInstance();
1000 userId = sharedPreferences.getString(Constants.prefUserIdKeyInt);
1001
1002 getStepTarget();
1003 getSleepTarget();
1004
1005 String value = sharedPreferences.getString(Constants.connectedDeviceAddressPrefKey);
1006 if (value != null) {
1007 var val = jsonDecode(value);
1008 if (val is Map) {
1009 connectedDevice = DeviceModel.fromMap(val);
1010 }
1011 }
1012 //region this is checking that device is connected or not
1013 Future.delayed(Duration(milliseconds: 500)).then((_) {
1014 connections.isConnected().then((bool isConnected) {
1015 if (isConnected == null || !isConnected) {
1016 //code for not connected
1017 connectedDevice = null;
1018 deviceInfoModel = null;
1019 sharedPreferences.remove(Constants.connectedDeviceAddressPrefKey);
1020 getSleepData();
1021 getMotionData();
1022 if (mounted) {
1023 setState(() {});
1024 }
1025 }else{
1026 //code for connected
1027 //region set default
1028 var wearOnLeft = sharedPreferences.getBool(Constants.isWearOnLeftKey) ?? true;
1029 connections.setWearType(wearOnLeft);
1030
1031 bool isLiftTheWristBrightnessOn = sharedPreferences.getBool(Constants.isLiftTheWristBrightnessOnKey) ?? true;
1032 bool isDoNotDisturb = sharedPreferences.getBool(Constants.isDoNotDisturbKey) ?? false;
1033 bool timeFormat24h = sharedPreferences.getBool(Constants.isTimeFormat24hKey) ?? true;
1034 bool isHourlyHrMonitorOn = sharedPreferences.getBool(Constants.isHourlyHrMonitorOnKey) ?? false;
1035
1036 if(Platform.isAndroid){
1037 connections.setLiftTheWristBrightnessOn(isLiftTheWristBrightnessOn);
1038 connections.setDoNotDisturb(isDoNotDisturb);
1039 connections.setTimeFormat(timeFormat24h);
1040 connections.setHourlyHrMonitorOn(isHourlyHrMonitorOn);
1041 }else{
1042 Map map = {
1043 "hrMonitor":isHourlyHrMonitorOn,
1044 "liftBrighten":isLiftTheWristBrightnessOn,
1045 "doNotDisturb":isDoNotDisturb,
1046 "timeFormat":timeFormat24h,
1047 };
1048 connections.sendDataToSDK(map);
1049 }
1050
1051 //endregion
1052 }
1053 });
1054 });
1055 //endregion
1056
1057 if (mounted) {
1058 setState(() {});
1059 }
1060 }
1061
1062 void getStepTarget() {
1063 String strJsonForStep =
1064 sharedPreferences.getString(Constants.prefSavedStepTarget);
1065 if (strJsonForStep != null && strJsonForStep.isNotEmpty) {
1066 Map map = jsonDecode(strJsonForStep);
1067 if (map != null && map.containsKey("userId")) {
1068 if (map["userId"] == userId) {
1069 if (map.containsKey("step") && map["step"] > 0) {
1070 targetSteps = map["step"].toDouble();
1071 }
1072 }
1073 }
1074 }
1075 }
1076
1077 void getSleepTarget() {
1078 String strJson1 = sharedPreferences.getString(Constants.prefSavedSleepTarget);
1079 if (strJson1 != null && strJson1.isNotEmpty) {
1080 Map map = jsonDecode(strJson1);
1081 if (map != null && map.containsKey("userId")) {
1082 if (map["userId"] == userId) {
1083 int hour = 8;
1084 int minute = 0;
1085 if (map.containsKey("hour")) {
1086 hour = map["hour"].toInt();
1087 }
1088 if (map.containsKey("minute")) {
1089 minute = map["minute"].toInt();
1090 }
1091 targetMinute = (hour*60) + minute;
1092 }
1093 }
1094 }
1095 }
1096}