data integration along with the data representation
parent
5ea70397e2
commit
bfeb3dce4e
@ -1,4 +1,4 @@
|
|||||||
package com.ejada.hmg.samsung_watch.model
|
package com.ejada.hmg.watch.huawei.samsung_watch.model
|
||||||
|
|
||||||
data class Vitals(
|
data class Vitals(
|
||||||
var value : String = "",
|
var value : String = "",
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:hmg_patient_app_new/core/common_models/data_points.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import 'model/Vitals.dart';
|
||||||
|
|
||||||
|
enum Durations {
|
||||||
|
daily("daily"),
|
||||||
|
weekly("weekly"),
|
||||||
|
monthly("weekly"),
|
||||||
|
halfYearly("halfYearly"),
|
||||||
|
yearly("yearly");
|
||||||
|
|
||||||
|
final String value;
|
||||||
|
const Durations(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
class HealthDataTransformation {
|
||||||
|
Map<String, List<DataPoint>> transformVitalsToDataPoints(VitalsWRTType vitals, String filterType, String selectedSection,) {
|
||||||
|
final Map<String, List<DataPoint>> dataPointMap = {};
|
||||||
|
Map<String, List<Vitals>> data = vitals.getVitals();
|
||||||
|
// Group data based on the filter type
|
||||||
|
Map<String, List<Vitals>> groupedData = {};
|
||||||
|
// List<List<Vitals> > items = data.values.toList();
|
||||||
|
List<String> keys = data.keys.toList();
|
||||||
|
var count = 0;
|
||||||
|
List<Vitals> item = data[selectedSection] ?? [];
|
||||||
|
// for(var item in items) {
|
||||||
|
List<DataPoint> dataPoints = [];
|
||||||
|
|
||||||
|
for (var vital in item) {
|
||||||
|
String key = "";
|
||||||
|
if (vital.value == "" || vital.timestamp == "") continue;
|
||||||
|
var parseDate = DateTime.parse(vital.timestamp);
|
||||||
|
var currentDate = normalizeToStartOfDay(DateTime.now());
|
||||||
|
if (filterType == Durations.daily.value) {
|
||||||
|
if(isBetweenInclusive(parseDate, currentDate, DateTime.now())) {
|
||||||
|
key = DateFormat('yyyy-MM-dd HH').format(DateTime.parse(vital.timestamp));
|
||||||
|
groupedData.putIfAbsent(key, () => []).add(vital);
|
||||||
|
}// Group by hour
|
||||||
|
} else if (filterType == Durations.weekly.value) {
|
||||||
|
if(isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 7)), DateTime.now())) {
|
||||||
|
key = DateFormat('yyyy-MM-dd').format(DateTime.parse(vital.timestamp));
|
||||||
|
groupedData.putIfAbsent(key, () => []).add(vital);
|
||||||
|
|
||||||
|
} // Group by day
|
||||||
|
} else if (filterType == Durations.monthly.value) {
|
||||||
|
if(isBetweenInclusive(parseDate, currentDate.subtract(Duration(days: 30)), DateTime.now())) {
|
||||||
|
key = DateFormat('yyyy-MM-dd').format(DateTime.parse(vital.timestamp));
|
||||||
|
groupedData.putIfAbsent(key, () => []).add(vital);
|
||||||
|
|
||||||
|
} // Group by day
|
||||||
|
} 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())) {
|
||||||
|
key = DateFormat('yyyy-MM').format(DateTime.parse(vital.timestamp));
|
||||||
|
groupedData.putIfAbsent(key, () => []).add(vital);
|
||||||
|
|
||||||
|
} // Group by month
|
||||||
|
} else {
|
||||||
|
throw ArgumentError('Invalid filter type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print("the size of groupData is ${groupedData.values.length}");
|
||||||
|
|
||||||
|
// Process grouped data
|
||||||
|
groupedData.forEach((key, values) {
|
||||||
|
double sum = values.fold(0, (acc, v) => acc + num.parse(v.value));
|
||||||
|
double mean = sum / values.length;
|
||||||
|
|
||||||
|
double finalValue = filterType == 'weekly' ? mean : sum;
|
||||||
|
print("the final value is $finalValue for the key $key with the original values ${values.map((v) => v.value).toList()} and uom is ${values.first.unitOfMeasure}");
|
||||||
|
dataPoints.add(DataPoint(
|
||||||
|
value: smartScale(finalValue),
|
||||||
|
label: key,
|
||||||
|
actualValue: finalValue.toStringAsFixed(2),
|
||||||
|
displayTime: key,
|
||||||
|
unitOfMeasurement:values.first.unitOfMeasure ,
|
||||||
|
time: DateTime.parse(values.first.timestamp),
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
dataPointMap[filterType] = dataPoints;
|
||||||
|
// }
|
||||||
|
return dataPointMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
double smartScale(double number) {
|
||||||
|
// if (number <= 0) return 0;
|
||||||
|
// final _random = Random();
|
||||||
|
// double ratio = number / 100;
|
||||||
|
//
|
||||||
|
// double scalingFactor = ratio > 1 ? 100 / number : 100;
|
||||||
|
//
|
||||||
|
// double result = (number / 100) * scalingFactor;
|
||||||
|
// print("the ratio is ${ratio.toInt()+1}");
|
||||||
|
// double max = (100+_random.nextInt(ratio.toInt()+10)).toDouble();
|
||||||
|
//
|
||||||
|
// return result.clamp(0, max);
|
||||||
|
|
||||||
|
if (number <= 0) return 0;
|
||||||
|
|
||||||
|
final random = Random();
|
||||||
|
|
||||||
|
// Smooth compression scaling
|
||||||
|
double baseScaled = number <20 ? number:100 * (number / (number + 100));
|
||||||
|
|
||||||
|
// Random factor between 0.9 and 1.1 (±10%)
|
||||||
|
double randomFactor = number <20 ? random.nextDouble() * 1.5: 0.9 + random.nextDouble() * 0.2;
|
||||||
|
|
||||||
|
double result = baseScaled * randomFactor;
|
||||||
|
|
||||||
|
return result.clamp(0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime normalizeToStartOfDay(DateTime date) {
|
||||||
|
return DateTime(date.year, date.month, date.day);
|
||||||
|
}
|
||||||
|
bool isBetweenInclusive(
|
||||||
|
DateTime target,
|
||||||
|
DateTime start,
|
||||||
|
DateTime end,
|
||||||
|
) {
|
||||||
|
return !normalizeToStartOfDay(target).isBefore(start) && !normalizeToStartOfDay(target).isAfter(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:async/src/result/result.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/smartwatch_health_data/watch_connectors/watch_helper.dart';
|
||||||
|
import 'package:huawei_health/huawei_health.dart';
|
||||||
|
|
||||||
|
class HuaweiHealthDataConnector extends WatchHelper{
|
||||||
|
final MethodChannel _channel = MethodChannel('huawei_watch');
|
||||||
|
@override
|
||||||
|
Future<Result<bool>> initDevice() async{
|
||||||
|
try{
|
||||||
|
await _channel.invokeMethod('init');
|
||||||
|
|
||||||
|
}catch(e){
|
||||||
|
|
||||||
|
}
|
||||||
|
// List of scopes to ask for authorization.
|
||||||
|
// Note: These scopes should also be authorized on the Huawei Developer Console.
|
||||||
|
List<Scope> scopes = [
|
||||||
|
Scope.HEALTHKIT_STEP_READ, Scope.HEALTHKIT_OXYGEN_SATURATION_READ, // View and store height and weight data in Health Service Kit.
|
||||||
|
Scope.HEALTHKIT_HEARTRATE_READ, Scope.HEALTHKIT_SLEEP_READ,
|
||||||
|
Scope.HEALTHKIT_BODYTEMPERATURE_READ, Scope.HEALTHKIT_CALORIES_READ
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
bool? result = await SettingController.getHealthAppAuthorization();
|
||||||
|
debugPrint(
|
||||||
|
'Granted Scopes for result == is $result}',
|
||||||
|
);
|
||||||
|
return Result.value(true);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Error on authorization, Error:${e.toString()}');
|
||||||
|
return Result.error(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> getActivity() async {
|
||||||
|
DataType dataTypeResult = await SettingController.readDataType(
|
||||||
|
DataType.DT_CONTINUOUS_STEPS_DELTA.name
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future getBloodOxygen() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future getBodyTemperature() {
|
||||||
|
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> getHeartRate() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> getSleep() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> getSteps() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future retrieveData() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> getDistance() {
|
||||||
|
// TODO: implement getDistance
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue