Fixes for Apple Watch integration

haroon_dev
Haroon Amjad 2 days ago
parent e867de7b71
commit 13f2898a8b

@ -13,11 +13,16 @@ enum Durations {
yearly("yearly"); yearly("yearly");
final String value; final String value;
const Durations(this.value); const Durations(this.value);
} }
class HealthDataTransformation { class HealthDataTransformation {
Map<String, List<DataPoint>> transformVitalsToDataPoints(VitalsWRTType vitals, String filterType, String selectedSection,) { Map<String, List<DataPoint>> transformVitalsToDataPoints(
VitalsWRTType vitals,
String filterType,
String selectedSection,
) {
final Map<String, List<DataPoint>> dataPointMap = {}; final Map<String, List<DataPoint>> dataPointMap = {};
Map<String, List<Vitals>> data = vitals.getVitals(); Map<String, List<Vitals>> data = vitals.getVitals();
// Group data based on the filter type // Group data based on the filter type
@ -32,31 +37,36 @@ class HealthDataTransformation {
for (var vital in item) { for (var vital in item) {
String key = ""; String key = "";
if (vital.value == "" || vital.timestamp == "") continue; if (vital.value == "" || vital.timestamp == "") continue;
var parseDate = DateTime.parse(vital.timestamp);
DateTime parseDate;
try {
parseDate = DateTime.parse(vital.timestamp);
} catch (e) {
print('Error parsing timestamp "${vital.timestamp}": $e');
continue; // Skip this vital if timestamp is invalid
}
var currentDate = normalizeToStartOfDay(DateTime.now()); var currentDate = normalizeToStartOfDay(DateTime.now());
if (filterType == Durations.daily.value) { if (filterType == Durations.daily.value) {
if (isBetweenInclusive(parseDate, currentDate, DateTime.now())) { if (isBetweenInclusive(parseDate, currentDate, DateTime.now())) {
key = DateFormat('yyyy-MM-dd HH').format(DateTime.parse(vital.timestamp)); key = DateFormat('yyyy-MM-dd HH').format(parseDate);
groupedData.putIfAbsent(key, () => []).add(vital); groupedData.putIfAbsent(key, () => []).add(vital);
} // Group by hour } // Group by hour
} else if (filterType == Durations.weekly.value) { } else if (filterType == Durations.weekly.value) {
if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 7)), DateTime.now())) { if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 7)), DateTime.now())) {
key = DateFormat('yyyy-MM-dd').format(DateTime.parse(vital.timestamp)); key = DateFormat('yyyy-MM-dd').format(parseDate);
groupedData.putIfAbsent(key, () => []).add(vital); groupedData.putIfAbsent(key, () => []).add(vital);
} // Group by day } // Group by day
} else if (filterType == Durations.monthly.value) { } else if (filterType == Durations.monthly.value) {
if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 30)), DateTime.now())) { if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 30)), DateTime.now())) {
print("the value for the monthly filter is ${vital.value} with the timestamp ${vital.timestamp} and the current date is $currentDate and the parse date is $parseDate"); print("the value for the monthly filter is ${vital.value} with the timestamp ${vital.timestamp} and the current date is $currentDate and the parse date is $parseDate");
key = DateFormat('yyyy-MM-dd').format(DateTime.parse(vital.timestamp)); key = DateFormat('yyyy-MM-dd').format(parseDate);
groupedData.putIfAbsent(key, () => []).add(vital); groupedData.putIfAbsent(key, () => []).add(vital);
} // Group by day } // Group by day
} else if (filterType == Durations.halfYearly.value || filterType == Durations.yearly.value) { } else if (filterType == Durations.halfYearly.value || filterType == Durations.yearly.value) {
if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: filterType == Durations.halfYearly.value ? 180 : 365)), DateTime.now())) { if (isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: filterType == Durations.halfYearly.value ? 180 : 365)), DateTime.now())) {
key = DateFormat('yyyy-MM').format(DateTime.parse(vital.timestamp)); key = DateFormat('yyyy-MM').format(parseDate);
groupedData.putIfAbsent(key, () => []).add(vital); groupedData.putIfAbsent(key, () => []).add(vital);
} // Group by month } // Group by month
} else { } else {
throw ArgumentError('Invalid filter type'); throw ArgumentError('Invalid filter type');
@ -122,6 +132,7 @@ class HealthDataTransformation {
DateTime normalizeToStartOfDay(DateTime date) { DateTime normalizeToStartOfDay(DateTime date) {
return DateTime(date.year, date.month, date.day); return DateTime(date.year, date.month, date.day);
} }
bool isBetweenInclusive( bool isBetweenInclusive(
DateTime target, DateTime target,
DateTime start, DateTime start,
@ -129,6 +140,4 @@ class HealthDataTransformation {
) { ) {
return !normalizeToStartOfDay(target).isBefore(start) && !normalizeToStartOfDay(target).isAfter(end); return !normalizeToStartOfDay(target).isBefore(start) && !normalizeToStartOfDay(target).isAfter(end);
} }
} }

@ -202,7 +202,7 @@ class HealthService {
} }
var response = jsonDecode(data.asValue?.value?.toString()?.trim().replaceAll("\n", "") ?? ""); var response = jsonDecode(data.asValue?.value?.toString()?.trim().replaceAll("\n", "") ?? "");
VitalsWRTType vitals = VitalsWRTType.fromMap(response); VitalsWRTType vitals = VitalsWRTType.fromMap(response);
log("the data is ${vitals}"); // log("the data is ${vitals}");
return vitals; return vitals;
} catch (e) { } catch (e) {
print('Error getting heart rate: $e'); print('Error getting heart rate: $e');

@ -9,10 +9,22 @@ class Vitals {
this.unitOfMeasure = "", this.unitOfMeasure = "",
}); });
Map<String, dynamic> toJson() {
return {
'value': value,
'timestamp': timestamp,
'uom': unitOfMeasure,
};
}
factory Vitals.fromMap(Map<dynamic, dynamic> map) { factory Vitals.fromMap(Map<dynamic, dynamic> map) {
String timestamp = map['timestamp'] ?? map['timeStamp'] ?? "";
if (timestamp.isEmpty) {
timestamp = DateTime.now().toIso8601String();
}
return Vitals( return Vitals(
value: map['value'] ?? "", value: map['value'] ?? "",
timestamp: map['timeStamp'] ?? "", timestamp: timestamp,
unitOfMeasure: map['uom'] ?? "", unitOfMeasure: map['uom'] ?? "",
); );
} }

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:async/src/result/result.dart'; import 'package:async/src/result/result.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -80,7 +81,10 @@ class HealthConnectHelper extends WatchHelper {
@override @override
Future<dynamic> retrieveData() async { Future<dynamic> retrieveData() async {
// String retData;
// retData = Result.value(getMappedData()) as String;
return Result.value(getMappedData()); return Result.value(getMappedData());
// return retData;
} }
@override @override
@ -151,9 +155,22 @@ class HealthConnectHelper extends WatchHelper {
for (var point in data) { for (var point in data) {
if (point.value is NumericHealthValue) { if (point.value is NumericHealthValue) {
final numericValue = (point.value as NumericHealthValue).numericValue; final numericValue = (point.value as NumericHealthValue).numericValue;
String timestamp = DateTime.now().toIso8601String();
try {
if (point.dateFrom != null) {
String tempTimestamp = point.dateFrom.toIso8601String();
if (tempTimestamp.isNotEmpty) {
timestamp = tempTimestamp;
}
}
} catch (e) {
debugPrint('Error converting dateFrom to ISO8601 for $s: $e');
}
Vitals vitals = Vitals( Vitals vitals = Vitals(
value: (point.value as NumericHealthValue).numericValue.toStringAsFixed(2), value: numericValue.toStringAsFixed(2),
timestamp: point.dateFrom.toString() timestamp: timestamp
); );
mappedData[s]?.add(vitals); mappedData[s]?.add(vitals);
} }
@ -165,17 +182,41 @@ class HealthConnectHelper extends WatchHelper {
for (var point in data) { for (var point in data) {
if (point.value is NumericHealthValue) { if (point.value is NumericHealthValue) {
final numericValue = (point.value as NumericHealthValue).numericValue; final numericValue = (point.value as NumericHealthValue).numericValue;
String timestamp = DateTime.now().toIso8601String();
try {
if (point.dateFrom != null) {
String tempTimestamp = point.dateFrom.toIso8601String();
if (tempTimestamp.isNotEmpty) {
timestamp = tempTimestamp;
}
}
} catch (e) {
debugPrint('Error converting dateFrom to ISO8601 for $s: $e');
}
point.value = NumericHealthValue( point.value = NumericHealthValue(
numericValue: numericValue * 100, numericValue: numericValue * 100,
); );
Vitals vitals = Vitals(value: (point.value as NumericHealthValue).numericValue.toStringAsFixed(2), timestamp: point.dateFrom.toString()); Vitals vitals = Vitals(
value: (point.value as NumericHealthValue).numericValue.toStringAsFixed(2),
timestamp: timestamp
);
mappedData[s]?.add(vitals); mappedData[s]?.add(vitals);
} }
} }
} }
getMappedData() { getMappedData() {
return " { \"heartRate\": ${mappedData["heartRate"] ?? []}, \"sleep\": ${mappedData["sleep"] ?? []}, \"steps\": ${mappedData["steps"] ?? []}, \"activity\": ${mappedData["activity"] ?? []}, \"bloodOxygen\": ${mappedData["bloodOxygen"] ?? []}, \"bodyTemperature\": ${mappedData["bodyTemperature"] ?? []}, \"distance\": ${mappedData["distance"] ?? []} }"; return jsonEncode({
"heartRate": (mappedData["heartRate"] ?? []).map((v) => v.toJson()).toList(),
"sleep": (mappedData["sleep"] ?? []).map((v) => v.toJson()).toList(),
"steps": (mappedData["steps"] ?? []).map((v) => v.toJson()).toList(),
"activity": (mappedData["activity"] ?? []).map((v) => v.toJson()).toList(),
"bloodOxygen": (mappedData["bloodOxygen"] ?? []).map((v) => v.toJson()).toList(),
"bodyTemperature": (mappedData["bodyTemperature"] ?? []).map((v) => v.toJson()).toList(),
"distance": (mappedData["distance"] ?? []).map((v) => v.toJson()).toList(),
});
} }
getHeartData(DateTime startDate, DateTime endDate, HealthDataType types) async { getHeartData(DateTime startDate, DateTime endDate, HealthDataType types) async {

@ -240,7 +240,8 @@ class _ActivityDetailsState extends State<ActivityDetails> {
return Selector<HealthProvider, Map<String, List<DataPoint>>?>( return Selector<HealthProvider, Map<String, List<DataPoint>>?>(
selector: (_, model) => model.selectedData, selector: (_, model) => model.selectedData,
builder: (_, data, __) { builder: (_, data, __) {
if (context.read<HealthProvider>().selectedData.values.toList().first?.isEmpty == true) return SizedBox(); // if (context.read<HealthProvider>().selectedData.values.toList().first.isEmpty == true) return SizedBox();
if (context.read<HealthProvider>().selectedData.values.toList().isEmpty == true) return SizedBox();
return CustomBarChart( return CustomBarChart(
dataPoints: context.read<HealthProvider>().selectedData.values.toList().first, dataPoints: context.read<HealthProvider>().selectedData.values.toList().first,

Loading…
Cancel
Save