diff --git a/packages/health/CHANGELOG.md b/packages/health/CHANGELOG.md
index c5f6b020a..153d069b9 100644
--- a/packages/health/CHANGELOG.md
+++ b/packages/health/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 13.1.4
+
+* Fix adding mindfulness resulted in crash in iOS
+* Support SPM for iOS
+
## 13.1.3
* Fix permissions issues with iOS
@@ -24,6 +29,7 @@
## 13.0.1
* Refactored Swift native implementation - See PR [#1175](https://github.com/cph-cachet/flutter-plugins/pull/1175) and [#1208](https://github.com/cph-cachet/flutter-plugins/pull/1208) for more information:
+
```
SwiftHealthPlugin (Main Plugin Class)
├── HealthDataReader (Reading health data)
@@ -54,10 +60,12 @@ SwiftHealthPlugin (Main Plugin Class)
* iOS: Parse metadata to remove unsupported types - PR [#1120](https://github.com/cph-cachet/flutter-plugins/pull/1120)
* iOS: Add UV Index Types
* Android: Add request access to historic data [#1126](https://github.com/cph-cachet/flutter-plugins/issues/1126) - PR [#1127](https://github.com/cph-cachet/flutter-plugins/pull/1127)
+
```XML
```
+
* Android:
* Update `androidx.compose:compose-bom` to `2025.02.00`
* Update `androidx.health.connect:connect-client` to `1.1.0-alpha11`
@@ -85,10 +93,12 @@ SwiftHealthPlugin (Main Plugin Class)
* Fix [#984](https://github.com/cph-cachet/flutter-plugins/issues/984) - PR [#1055](https://github.com/cph-cachet/flutter-plugins/pull/1055)
* Add `LEAN_BODY_MASS` data type [#1078](https://github.com/cph-cachet/flutter-plugins/issues/1078) - PR [#1097](https://github.com/cph-cachet/flutter-plugins/pull/1097)
* The following AndroidManifest values are required to READ/WRITE `LEAN_BODY_MASS`:
+
```XML
```
+
* iOS: Add `WATER_TEMPERATURE` and `UNDERWATER_DEPTH` health values [#1096](https://github.com/cph-cachet/flutter-plugins/issues/1096)
* iOS: Add support for `Underwater Diving` workout [#1096](https://github.com/cph-cachet/flutter-plugins/issues/1096)
* Fix [#1072](https://github.com/cph-cachet/flutter-plugins/issues/1072) and [#1074](https://github.com/cph-cachet/flutter-plugins/issues/1074)
diff --git a/packages/health/example/ios/Flutter/AppFrameworkInfo.plist b/packages/health/example/ios/Flutter/AppFrameworkInfo.plist
index 7c5696400..1dc6cf765 100644
--- a/packages/health/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/packages/health/example/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 12.0
+ 13.0
diff --git a/packages/health/example/ios/Runner.xcodeproj/project.pbxproj b/packages/health/example/ios/Runner.xcodeproj/project.pbxproj
index b856ee37b..025a38b41 100644
--- a/packages/health/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/health/example/ios/Runner.xcodeproj/project.pbxproj
@@ -68,6 +68,7 @@
ABEE568C2D6B9E4300551983 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
F97011D03CBC7A35D177D127 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
FCEA0A19EEB97E6889BA5240 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -112,6 +113,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
+ 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
@@ -249,6 +251,7 @@
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
+ 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
ABB05D852D6BB16700FA4740 /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
@@ -485,7 +488,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -616,7 +619,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -667,7 +670,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -765,6 +768,10 @@
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
+ 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
+ };
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
diff --git a/packages/health/example/lib/main.dart b/packages/health/example/lib/main.dart
index e94fa44ce..8c3387da8 100644
--- a/packages/health/example/lib/main.dart
+++ b/packages/health/example/lib/main.dart
@@ -409,6 +409,15 @@ class HealthAppState extends State {
type: HealthDataType.HEART_RATE_VARIABILITY_RMSSD,
startTime: earlier,
endTime: now);
+
+ // Mindfulness value should be counted based on start and end time
+ success &= await health.writeHealthData(
+ value: 10,
+ type: HealthDataType.MINDFULNESS,
+ startTime: earlier,
+ endTime: now,
+ recordingMethod: RecordingMethod.automatic,
+ );
}
// Available on iOS or iOS 16.0+ only
diff --git a/packages/health/ios/Classes/HealthDataWriter.swift b/packages/health/ios/Classes/HealthDataWriter.swift
index 1ea3bf301..df19a505e 100644
--- a/packages/health/ios/Classes/HealthDataWriter.swift
+++ b/packages/health/ios/Classes/HealthDataWriter.swift
@@ -1,5 +1,5 @@
-import HealthKit
import Flutter
+import HealthKit
/// Class responsible for writing health data to HealthKit
class HealthDataWriter {
@@ -7,45 +7,54 @@ class HealthDataWriter {
let dataTypesDict: [String: HKSampleType]
let unitDict: [String: HKUnit]
let workoutActivityTypeMap: [String: HKWorkoutActivityType]
-
+
/// - Parameters:
/// - healthStore: The HealthKit store
/// - dataTypesDict: Dictionary of data types
/// - unitDict: Dictionary of units
/// - workoutActivityTypeMap: Dictionary of workout activity types
- init(healthStore: HKHealthStore, dataTypesDict: [String: HKSampleType], unitDict: [String: HKUnit], workoutActivityTypeMap: [String: HKWorkoutActivityType]) {
+ init(
+ healthStore: HKHealthStore, dataTypesDict: [String: HKSampleType],
+ unitDict: [String: HKUnit], workoutActivityTypeMap: [String: HKWorkoutActivityType]
+ ) {
self.healthStore = healthStore
self.dataTypesDict = dataTypesDict
self.unitDict = unitDict
self.workoutActivityTypeMap = workoutActivityTypeMap
}
-
+
/// Writes general health data
/// - Parameters:
/// - call: Flutter method call
/// - result: Flutter result callback
func writeData(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
guard let arguments = call.arguments as? NSDictionary,
- let value = (arguments["value"] as? Double),
- let type = (arguments["dataTypeKey"] as? String),
- let unit = (arguments["dataUnitKey"] as? String),
- let startTime = (arguments["startTime"] as? NSNumber),
- let endTime = (arguments["endTime"] as? NSNumber),
- let recordingMethod = (arguments["recordingMethod"] as? Int)
+ let value = (arguments["value"] as? Double),
+ let type = (arguments["dataTypeKey"] as? String),
+ let unit = (arguments["dataUnitKey"] as? String),
+ let startTime = (arguments["startTime"] as? NSNumber),
+ let endTime = (arguments["endTime"] as? NSNumber),
+ let recordingMethod = (arguments["recordingMethod"] as? Int)
else {
throw PluginError(message: "Invalid Arguments")
}
-
+
+ // Handle mindfulness sessions specifically
+ if type == HealthConstants.MINDFULNESS {
+ try writeMindfulness(call: call, result: result)
+ return
+ }
+
let dateFrom = HealthUtilities.dateFromMilliseconds(startTime.doubleValue)
let dateTo = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
-
+
let isManualEntry = recordingMethod == HealthConstants.RecordingMethod.manual.rawValue
let metadata: [String: Any] = [
HKMetadataKeyWasUserEntered: NSNumber(value: isManualEntry)
]
-
+
let sample: HKObject
-
+
if dataTypesDict[type]!.isKind(of: HKCategoryType.self) {
sample = HKCategorySample(
type: dataTypesDict[type] as! HKCategoryType, value: Int(value), start: dateFrom,
@@ -56,7 +65,7 @@ class HealthDataWriter {
type: dataTypesDict[type] as! HKQuantityType, quantity: quantity, start: dateFrom,
end: dateTo, metadata: metadata)
}
-
+
healthStore.save(
sample,
withCompletion: { (success, error) in
@@ -68,27 +77,27 @@ class HealthDataWriter {
}
})
}
-
+
/// Writes audiogram data
/// - Parameters:
/// - call: Flutter method call
/// - result: Flutter result callback
func writeAudiogram(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
guard let arguments = call.arguments as? NSDictionary,
- let frequencies = (arguments["frequencies"] as? [Double]),
- let leftEarSensitivities = (arguments["leftEarSensitivities"] as? [Double]),
- let rightEarSensitivities = (arguments["rightEarSensitivities"] as? [Double]),
- let startTime = (arguments["startTime"] as? NSNumber),
- let endTime = (arguments["endTime"] as? NSNumber)
+ let frequencies = (arguments["frequencies"] as? [Double]),
+ let leftEarSensitivities = (arguments["leftEarSensitivities"] as? [Double]),
+ let rightEarSensitivities = (arguments["rightEarSensitivities"] as? [Double]),
+ let startTime = (arguments["startTime"] as? NSNumber),
+ let endTime = (arguments["endTime"] as? NSNumber)
else {
throw PluginError(message: "Invalid Arguments")
}
-
+
let dateFrom = HealthUtilities.dateFromMilliseconds(startTime.doubleValue)
let dateTo = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
-
+
var sensitivityPoints = [HKAudiogramSensitivityPoint]()
-
+
for index in 0...frequencies.count - 1 {
let frequency = HKQuantity(unit: HKUnit.hertz(), doubleValue: frequencies[index])
let dbUnit = HKUnit.decibelHearingLevel()
@@ -98,23 +107,25 @@ class HealthDataWriter {
frequency: frequency, leftEarSensitivity: left, rightEarSensitivity: right)
sensitivityPoints.append(sensitivityPoint)
}
-
+
let audiogram: HKAudiogramSample
let metadataReceived = (arguments["metadata"] as? [String: Any]?)
-
+
if (metadataReceived) != nil {
guard let deviceName = metadataReceived?!["HKDeviceName"] as? String else { return }
guard let externalUUID = metadataReceived?!["HKExternalUUID"] as? String else { return }
-
+
audiogram = HKAudiogramSample(
sensitivityPoints: sensitivityPoints, start: dateFrom, end: dateTo,
- metadata: [HKMetadataKeyDeviceName: deviceName, HKMetadataKeyExternalUUID: externalUUID])
-
+ metadata: [
+ HKMetadataKeyDeviceName: deviceName, HKMetadataKeyExternalUUID: externalUUID,
+ ])
+
} else {
audiogram = HKAudiogramSample(
sensitivityPoints: sensitivityPoints, start: dateFrom, end: dateTo, metadata: nil)
}
-
+
healthStore.save(
audiogram,
withCompletion: { (success, error) in
@@ -126,29 +137,29 @@ class HealthDataWriter {
}
})
}
-
+
/// Writes blood pressure data
/// - Parameters:
/// - call: Flutter method call
/// - result: Flutter result callback
func writeBloodPressure(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
guard let arguments = call.arguments as? NSDictionary,
- let systolic = (arguments["systolic"] as? Double),
- let diastolic = (arguments["diastolic"] as? Double),
- let startTime = (arguments["startTime"] as? NSNumber),
- let endTime = (arguments["endTime"] as? NSNumber),
- let recordingMethod = (arguments["recordingMethod"] as? Int)
+ let systolic = (arguments["systolic"] as? Double),
+ let diastolic = (arguments["diastolic"] as? Double),
+ let startTime = (arguments["startTime"] as? NSNumber),
+ let endTime = (arguments["endTime"] as? NSNumber),
+ let recordingMethod = (arguments["recordingMethod"] as? Int)
else {
throw PluginError(message: "Invalid Arguments")
}
let dateFrom = HealthUtilities.dateFromMilliseconds(startTime.doubleValue)
let dateTo = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
-
+
let isManualEntry = recordingMethod == HealthConstants.RecordingMethod.manual.rawValue
let metadata = [
HKMetadataKeyWasUserEntered: NSNumber(value: isManualEntry)
]
-
+
let systolic_sample = HKQuantitySample(
type: HKSampleType.quantityType(forIdentifier: .bloodPressureSystolic)!,
quantity: HKQuantity(unit: HKUnit.millimeterOfMercury(), doubleValue: systolic),
@@ -159,8 +170,9 @@ class HealthDataWriter {
start: dateFrom, end: dateTo, metadata: metadata)
let bpCorrelationType = HKCorrelationType.correlationType(forIdentifier: .bloodPressure)!
let bpCorrelation = Set(arrayLiteral: systolic_sample, diastolic_sample)
- let blood_pressure_sample = HKCorrelation(type: bpCorrelationType , start: dateFrom, end: dateTo, objects: bpCorrelation)
-
+ let blood_pressure_sample = HKCorrelation(
+ type: bpCorrelationType, start: dateFrom, end: dateTo, objects: bpCorrelation)
+
healthStore.save(
[blood_pressure_sample],
withCompletion: { (success, error) in
@@ -172,128 +184,149 @@ class HealthDataWriter {
}
})
}
-
+
/// Writes meal nutrition data
/// - Parameters:
/// - call: Flutter method call
/// - result: Flutter result callback
func writeMeal(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
guard let arguments = call.arguments as? NSDictionary,
- let name = (arguments["name"] as? String?),
- let startTime = (arguments["start_time"] as? NSNumber),
- let endTime = (arguments["end_time"] as? NSNumber),
- let mealType = (arguments["meal_type"] as? String?),
- let recordingMethod = arguments["recordingMethod"] as? Int
+ let name = (arguments["name"] as? String?),
+ let startTime = (arguments["start_time"] as? NSNumber),
+ let endTime = (arguments["end_time"] as? NSNumber),
+ let mealType = (arguments["meal_type"] as? String?),
+ let recordingMethod = arguments["recordingMethod"] as? Int
else {
throw PluginError(message: "Invalid Arguments")
}
-
+
let dateFrom = HealthUtilities.dateFromMilliseconds(startTime.doubleValue)
let dateTo = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
-
+
let mealTypeString = mealType ?? "UNKNOWN"
-
+
let isManualEntry = recordingMethod == HealthConstants.RecordingMethod.manual.rawValue
-
- var metadata = ["HKFoodMeal": mealTypeString, HKMetadataKeyWasUserEntered: NSNumber(value: isManualEntry)] as [String : Any]
- if (name != nil) {
+
+ var metadata =
+ [
+ "HKFoodMeal": mealTypeString,
+ HKMetadataKeyWasUserEntered: NSNumber(value: isManualEntry),
+ ] as [String: Any]
+ if name != nil {
metadata[HKMetadataKeyFoodType] = "\(name!)"
}
-
+
var nutrition = Set()
for (key, identifier) in HealthConstants.NUTRITION_KEYS {
let value = arguments[key] as? Double
guard let unwrappedValue = value else { continue }
- let unit = key == "calories" ? HKUnit.kilocalorie() : key == "water" ? HKUnit.literUnit(with: .milli) : HKUnit.gram()
+ let unit =
+ key == "calories"
+ ? HKUnit.kilocalorie()
+ : key == "water" ? HKUnit.literUnit(with: .milli) : HKUnit.gram()
let nutritionSample = HKQuantitySample(
- type: HKSampleType.quantityType(forIdentifier: identifier)!, quantity: HKQuantity(unit: unit, doubleValue: unwrappedValue), start: dateFrom, end: dateTo, metadata: metadata)
+ type: HKSampleType.quantityType(forIdentifier: identifier)!,
+ quantity: HKQuantity(unit: unit, doubleValue: unwrappedValue), start: dateFrom,
+ end: dateTo, metadata: metadata)
nutrition.insert(nutritionSample)
}
-
- if #available(iOS 15.0, *){
- let type = HKCorrelationType.correlationType(forIdentifier: HKCorrelationTypeIdentifier.food)!
- let meal = HKCorrelation(type: type, start: dateFrom, end: dateTo, objects: nutrition, metadata: metadata)
-
- healthStore.save(meal, withCompletion: { (success, error) in
- if let err = error {
- print("Error Saving Meal Sample: \(err.localizedDescription)")
- }
- DispatchQueue.main.async {
- result(success)
- }
- })
+
+ if #available(iOS 15.0, *) {
+ let type = HKCorrelationType.correlationType(
+ forIdentifier: HKCorrelationTypeIdentifier.food)!
+ let meal = HKCorrelation(
+ type: type, start: dateFrom, end: dateTo, objects: nutrition, metadata: metadata)
+
+ healthStore.save(
+ meal,
+ withCompletion: { (success, error) in
+ if let err = error {
+ print("Error Saving Meal Sample: \(err.localizedDescription)")
+ }
+ DispatchQueue.main.async {
+ result(success)
+ }
+ })
} else {
result(false)
}
}
-
+
/// Writes insulin delivery data
/// - Parameters:
/// - call: Flutter method call
/// - result: Flutter result callback
func writeInsulinDelivery(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
guard let arguments = call.arguments as? NSDictionary,
- let units = (arguments["units"] as? Double),
- let reason = (arguments["reason"] as? NSNumber),
- let startTime = (arguments["startTime"] as? NSNumber),
- let endTime = (arguments["endTime"] as? NSNumber)
+ let units = (arguments["units"] as? Double),
+ let reason = (arguments["reason"] as? NSNumber),
+ let startTime = (arguments["startTime"] as? NSNumber),
+ let endTime = (arguments["endTime"] as? NSNumber)
else {
throw PluginError(message: "Invalid Arguments")
}
let dateFrom = HealthUtilities.dateFromMilliseconds(startTime.doubleValue)
let dateTo = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
-
+
let type = HKSampleType.quantityType(forIdentifier: .insulinDelivery)!
let quantity = HKQuantity(unit: HKUnit.internationalUnit(), doubleValue: units)
let metadata = [HKMetadataKeyInsulinDeliveryReason: reason]
-
- let insulin_sample = HKQuantitySample(type: type, quantity: quantity, start: dateFrom, end: dateTo, metadata: metadata)
-
- healthStore.save(insulin_sample, withCompletion: { (success, error) in
- if let err = error {
- print("Error Saving Insulin Delivery Sample: \(err.localizedDescription)")
- }
- DispatchQueue.main.async {
- result(success)
- }
- })
+
+ let insulin_sample = HKQuantitySample(
+ type: type, quantity: quantity, start: dateFrom, end: dateTo, metadata: metadata)
+
+ healthStore.save(
+ insulin_sample,
+ withCompletion: { (success, error) in
+ if let err = error {
+ print("Error Saving Insulin Delivery Sample: \(err.localizedDescription)")
+ }
+ DispatchQueue.main.async {
+ result(success)
+ }
+ })
}
-
+
/// Writes menstruation flow data
/// - Parameters:
/// - call: Flutter method call
/// - result: Flutter result callback
func writeMenstruationFlow(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
guard let arguments = call.arguments as? NSDictionary,
- let flow = (arguments["value"] as? Int),
- let endTime = (arguments["endTime"] as? NSNumber),
- let isStartOfCycle = (arguments["isStartOfCycle"] as? NSNumber),
- let recordingMethod = (arguments["recordingMethod"] as? Int)
+ let flow = (arguments["value"] as? Int),
+ let endTime = (arguments["endTime"] as? NSNumber),
+ let isStartOfCycle = (arguments["isStartOfCycle"] as? NSNumber),
+ let recordingMethod = (arguments["recordingMethod"] as? Int)
else {
- throw PluginError(message: "Invalid Arguments - value, startTime, endTime or isStartOfCycle invalid")
+ throw PluginError(
+ message: "Invalid Arguments - value, startTime, endTime or isStartOfCycle invalid")
}
guard let menstrualFlowType = HKCategoryValueMenstrualFlow(rawValue: flow) else {
throw PluginError(message: "Invalid Menstrual Flow Type")
}
-
+
let dateTime = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
-
+
let isManualEntry = recordingMethod == HealthConstants.RecordingMethod.manual.rawValue
-
+
guard let categoryType = HKSampleType.categoryType(forIdentifier: .menstrualFlow) else {
throw PluginError(message: "Invalid Menstrual Flow Type")
}
-
- let metadata = [HKMetadataKeyMenstrualCycleStart: isStartOfCycle, HKMetadataKeyWasUserEntered: NSNumber(value: isManualEntry)] as [String : Any]
-
+
+ let metadata =
+ [
+ HKMetadataKeyMenstrualCycleStart: isStartOfCycle,
+ HKMetadataKeyWasUserEntered: NSNumber(value: isManualEntry),
+ ] as [String: Any]
+
let sample = HKCategorySample(
type: categoryType,
- value: menstrualFlowType.rawValue,
- start: dateTime,
+ value: menstrualFlowType.rawValue,
+ start: dateTime,
end: dateTime,
metadata: metadata
)
-
+
healthStore.save(
sample,
withCompletion: { (success, error) in
@@ -305,24 +338,71 @@ class HealthDataWriter {
}
})
}
-
+
+ /// Writes mindfulness session data
+ /// - Parameters:
+ /// - call: Flutter method call
+ /// - result: Flutter result callback
+ func writeMindfulness(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
+ guard let arguments = call.arguments as? NSDictionary,
+ let startTime = (arguments["startTime"] as? NSNumber),
+ let endTime = (arguments["endTime"] as? NSNumber),
+ let recordingMethod = (arguments["recordingMethod"] as? Int)
+ else {
+ throw PluginError(message: "Invalid Arguments")
+ }
+
+ let dateFrom = HealthUtilities.dateFromMilliseconds(startTime.doubleValue)
+ let dateTo = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
+
+ let isManualEntry = recordingMethod == HealthConstants.RecordingMethod.manual.rawValue
+ let metadata: [String: Any] = [
+ HKMetadataKeyWasUserEntered: NSNumber(value: isManualEntry)
+ ]
+
+ guard let categoryType = HKSampleType.categoryType(forIdentifier: .mindfulSession) else {
+ throw PluginError(message: "Invalid Mindfulness Session Type")
+ }
+
+ // The duration is tracked by the start and end dates, not by the value
+ let sample = HKCategorySample(
+ type: categoryType,
+ value: HKCategoryValue.notApplicable.rawValue,
+ start: dateFrom,
+ end: dateTo,
+ metadata: metadata
+ )
+
+ healthStore.save(
+ sample,
+ withCompletion: { (success, error) in
+ if let err = error {
+ print("Error Saving Mindfulness Session: \(err.localizedDescription)")
+ }
+ DispatchQueue.main.async {
+ result(success)
+ }
+ })
+ }
+
/// Writes workout data
/// - Parameters:
/// - call: Flutter method call
/// - result: Flutter result callback
func writeWorkoutData(call: FlutterMethodCall, result: @escaping FlutterResult) throws {
guard let arguments = call.arguments as? NSDictionary,
- let activityType = (arguments["activityType"] as? String),
- let startTime = (arguments["startTime"] as? NSNumber),
- let endTime = (arguments["endTime"] as? NSNumber),
- let activityTypeValue = workoutActivityTypeMap[activityType]
+ let activityType = (arguments["activityType"] as? String),
+ let startTime = (arguments["startTime"] as? NSNumber),
+ let endTime = (arguments["endTime"] as? NSNumber),
+ let activityTypeValue = workoutActivityTypeMap[activityType]
else {
- throw PluginError(message: "Invalid Arguments - activityType, startTime or endTime invalid")
+ throw PluginError(
+ message: "Invalid Arguments - activityType, startTime or endTime invalid")
}
-
+
var totalEnergyBurned: HKQuantity?
var totalDistance: HKQuantity? = nil
-
+
// Handle optional arguments
if let teb = (arguments["totalEnergyBurned"] as? Double) {
totalEnergyBurned = HKQuantity(
@@ -332,20 +412,20 @@ class HealthDataWriter {
totalDistance = HKQuantity(
unit: unitDict[(arguments["totalDistanceUnit"] as! String)]!, doubleValue: td)
}
-
+
let dateFrom = HealthUtilities.dateFromMilliseconds(startTime.doubleValue)
let dateTo = HealthUtilities.dateFromMilliseconds(endTime.doubleValue)
-
+
let workout = HKWorkout(
- activityType: activityTypeValue,
- start: dateFrom,
- end: dateTo,
+ activityType: activityTypeValue,
+ start: dateFrom,
+ end: dateTo,
duration: dateTo.timeIntervalSince(dateFrom),
totalEnergyBurned: totalEnergyBurned ?? nil,
- totalDistance: totalDistance ?? nil,
+ totalDistance: totalDistance ?? nil,
metadata: nil
)
-
+
healthStore.save(
workout,
withCompletion: { (success, error) in
diff --git a/packages/health/ios/health.podspec b/packages/health/ios/health.podspec
index d13878710..f0eb7cd7a 100644
--- a/packages/health/ios/health.podspec
+++ b/packages/health/ios/health.podspec
@@ -3,7 +3,7 @@
#
Pod::Spec.new do |s|
s.name = 'health'
- s.version = '13.1.3'
+ s.version = '13.1.4'
s.summary = 'Wrapper for Apple\'s HealthKit on iOS and Google\'s Health Connect on Android.'
s.description = <<-DESC
Wrapper for Apple's HealthKit on iOS and Google's Health Connect on Android.
diff --git a/packages/health/lib/health.g.dart b/packages/health/lib/health.g.dart
index 12f2d3ed8..d12054286 100644
--- a/packages/health/lib/health.g.dart
+++ b/packages/health/lib/health.g.dart
@@ -6,29 +6,31 @@ part of 'health.dart';
// JsonSerializableGenerator
// **************************************************************************
-HealthDataPoint _$HealthDataPointFromJson(Map json) =>
- HealthDataPoint(
- uuid: json['uuid'] as String,
- value: HealthValue.fromJson(json['value'] as Map),
- type: $enumDecode(_$HealthDataTypeEnumMap, json['type']),
- unit: $enumDecode(_$HealthDataUnitEnumMap, json['unit']),
- dateFrom: DateTime.parse(json['dateFrom'] as String),
- dateTo: DateTime.parse(json['dateTo'] as String),
- sourcePlatform:
- $enumDecode(_$HealthPlatformTypeEnumMap, json['sourcePlatform']),
- sourceDeviceId: json['sourceDeviceId'] as String,
- sourceId: json['sourceId'] as String,
- sourceName: json['sourceName'] as String,
- recordingMethod: $enumDecodeNullable(
- _$RecordingMethodEnumMap, json['recordingMethod']) ??
- RecordingMethod.unknown,
- workoutSummary: json['workoutSummary'] == null
- ? null
- : WorkoutSummary.fromJson(
- json['workoutSummary'] as Map),
- metadata: json['metadata'] as Map?,
- deviceModel: json['deviceModel'] as String?,
- );
+HealthDataPoint _$HealthDataPointFromJson(
+ Map json,
+) => HealthDataPoint(
+ uuid: json['uuid'] as String,
+ value: HealthValue.fromJson(json['value'] as Map),
+ type: $enumDecode(_$HealthDataTypeEnumMap, json['type']),
+ unit: $enumDecode(_$HealthDataUnitEnumMap, json['unit']),
+ dateFrom: DateTime.parse(json['dateFrom'] as String),
+ dateTo: DateTime.parse(json['dateTo'] as String),
+ sourcePlatform: $enumDecode(
+ _$HealthPlatformTypeEnumMap,
+ json['sourcePlatform'],
+ ),
+ sourceDeviceId: json['sourceDeviceId'] as String,
+ sourceId: json['sourceId'] as String,
+ sourceName: json['sourceName'] as String,
+ recordingMethod:
+ $enumDecodeNullable(_$RecordingMethodEnumMap, json['recordingMethod']) ??
+ RecordingMethod.unknown,
+ workoutSummary: json['workoutSummary'] == null
+ ? null
+ : WorkoutSummary.fromJson(json['workoutSummary'] as Map),
+ metadata: json['metadata'] as Map?,
+ deviceModel: json['deviceModel'] as String?,
+);
Map _$HealthDataPointToJson(HealthDataPoint instance) =>
{
@@ -43,10 +45,9 @@ Map _$HealthDataPointToJson(HealthDataPoint instance) =>
'sourceId': instance.sourceId,
'sourceName': instance.sourceName,
'recordingMethod': _$RecordingMethodEnumMap[instance.recordingMethod]!,
- if (instance.workoutSummary?.toJson() case final value?)
- 'workoutSummary': value,
- if (instance.metadata case final value?) 'metadata': value,
- if (instance.deviceModel case final value?) 'deviceModel': value,
+ 'workoutSummary': ?instance.workoutSummary?.toJson(),
+ 'metadata': ?instance.metadata,
+ 'deviceModel': ?instance.deviceModel,
};
const _$HealthDataTypeEnumMap = {
@@ -228,74 +229,76 @@ HealthValue _$HealthValueFromJson(Map json) =>
HealthValue()..$type = json['__type'] as String?;
Map _$HealthValueToJson(HealthValue instance) =>
- {
- if (instance.$type case final value?) '__type': value,
- };
+ {'__type': ?instance.$type};
NumericHealthValue _$NumericHealthValueFromJson(Map json) =>
- NumericHealthValue(
- numericValue: json['numericValue'] as num,
- )..$type = json['__type'] as String?;
+ NumericHealthValue(numericValue: json['numericValue'] as num)
+ ..$type = json['__type'] as String?;
Map _$NumericHealthValueToJson(NumericHealthValue instance) =>
{
- if (instance.$type case final value?) '__type': value,
+ '__type': ?instance.$type,
'numericValue': instance.numericValue,
};
AudiogramHealthValue _$AudiogramHealthValueFromJson(
- Map json) =>
- AudiogramHealthValue(
- frequencies:
- (json['frequencies'] as List).map((e) => e as num).toList(),
- leftEarSensitivities: (json['leftEarSensitivities'] as List)
- .map((e) => e as num)
- .toList(),
- rightEarSensitivities: (json['rightEarSensitivities'] as List)
- .map((e) => e as num)
- .toList(),
- )..$type = json['__type'] as String?;
+ Map json,
+) => AudiogramHealthValue(
+ frequencies: (json['frequencies'] as List)
+ .map((e) => e as num)
+ .toList(),
+ leftEarSensitivities: (json['leftEarSensitivities'] as List)
+ .map((e) => e as num)
+ .toList(),
+ rightEarSensitivities: (json['rightEarSensitivities'] as List)
+ .map((e) => e as num)
+ .toList(),
+)..$type = json['__type'] as String?;
Map _$AudiogramHealthValueToJson(
- AudiogramHealthValue instance) =>
- {
- if (instance.$type case final value?) '__type': value,
- 'frequencies': instance.frequencies,
- 'leftEarSensitivities': instance.leftEarSensitivities,
- 'rightEarSensitivities': instance.rightEarSensitivities,
- };
+ AudiogramHealthValue instance,
+) => {
+ '__type': ?instance.$type,
+ 'frequencies': instance.frequencies,
+ 'leftEarSensitivities': instance.leftEarSensitivities,
+ 'rightEarSensitivities': instance.rightEarSensitivities,
+};
WorkoutHealthValue _$WorkoutHealthValueFromJson(Map json) =>
WorkoutHealthValue(
workoutActivityType: $enumDecode(
- _$HealthWorkoutActivityTypeEnumMap, json['workoutActivityType']),
+ _$HealthWorkoutActivityTypeEnumMap,
+ json['workoutActivityType'],
+ ),
totalEnergyBurned: (json['totalEnergyBurned'] as num?)?.toInt(),
totalEnergyBurnedUnit: $enumDecodeNullable(
- _$HealthDataUnitEnumMap, json['totalEnergyBurnedUnit']),
+ _$HealthDataUnitEnumMap,
+ json['totalEnergyBurnedUnit'],
+ ),
totalDistance: (json['totalDistance'] as num?)?.toInt(),
totalDistanceUnit: $enumDecodeNullable(
- _$HealthDataUnitEnumMap, json['totalDistanceUnit']),
+ _$HealthDataUnitEnumMap,
+ json['totalDistanceUnit'],
+ ),
totalSteps: (json['totalSteps'] as num?)?.toInt(),
- totalStepsUnit:
- $enumDecodeNullable(_$HealthDataUnitEnumMap, json['totalStepsUnit']),
+ totalStepsUnit: $enumDecodeNullable(
+ _$HealthDataUnitEnumMap,
+ json['totalStepsUnit'],
+ ),
)..$type = json['__type'] as String?;
Map _$WorkoutHealthValueToJson(WorkoutHealthValue instance) =>
{
- if (instance.$type case final value?) '__type': value,
+ '__type': ?instance.$type,
'workoutActivityType':
_$HealthWorkoutActivityTypeEnumMap[instance.workoutActivityType]!,
- if (instance.totalEnergyBurned case final value?)
- 'totalEnergyBurned': value,
- if (_$HealthDataUnitEnumMap[instance.totalEnergyBurnedUnit]
- case final value?)
- 'totalEnergyBurnedUnit': value,
- if (instance.totalDistance case final value?) 'totalDistance': value,
- if (_$HealthDataUnitEnumMap[instance.totalDistanceUnit] case final value?)
- 'totalDistanceUnit': value,
- if (instance.totalSteps case final value?) 'totalSteps': value,
- if (_$HealthDataUnitEnumMap[instance.totalStepsUnit] case final value?)
- 'totalStepsUnit': value,
+ 'totalEnergyBurned': ?instance.totalEnergyBurned,
+ 'totalEnergyBurnedUnit':
+ ?_$HealthDataUnitEnumMap[instance.totalEnergyBurnedUnit],
+ 'totalDistance': ?instance.totalDistance,
+ 'totalDistanceUnit': ?_$HealthDataUnitEnumMap[instance.totalDistanceUnit],
+ 'totalSteps': ?instance.totalSteps,
+ 'totalStepsUnit': ?_$HealthDataUnitEnumMap[instance.totalStepsUnit],
};
const _$HealthWorkoutActivityTypeEnumMap = {
@@ -405,31 +408,32 @@ const _$HealthWorkoutActivityTypeEnumMap = {
};
ElectrocardiogramHealthValue _$ElectrocardiogramHealthValueFromJson(
- Map json) =>
- ElectrocardiogramHealthValue(
- voltageValues: (json['voltageValues'] as List)
- .map((e) =>
- ElectrocardiogramVoltageValue.fromJson(e as Map))
- .toList(),
- averageHeartRate: json['averageHeartRate'] as num?,
- samplingFrequency: (json['samplingFrequency'] as num?)?.toDouble(),
- classification: $enumDecodeNullable(
- _$ElectrocardiogramClassificationEnumMap, json['classification']),
- )..$type = json['__type'] as String?;
+ Map json,
+) => ElectrocardiogramHealthValue(
+ voltageValues: (json['voltageValues'] as List)
+ .map(
+ (e) =>
+ ElectrocardiogramVoltageValue.fromJson(e as Map),
+ )
+ .toList(),
+ averageHeartRate: json['averageHeartRate'] as num?,
+ samplingFrequency: (json['samplingFrequency'] as num?)?.toDouble(),
+ classification: $enumDecodeNullable(
+ _$ElectrocardiogramClassificationEnumMap,
+ json['classification'],
+ ),
+)..$type = json['__type'] as String?;
Map _$ElectrocardiogramHealthValueToJson(
- ElectrocardiogramHealthValue instance) =>
- {
- if (instance.$type case final value?) '__type': value,
- 'voltageValues': instance.voltageValues.map((e) => e.toJson()).toList(),
- if (instance.averageHeartRate case final value?)
- 'averageHeartRate': value,
- if (instance.samplingFrequency case final value?)
- 'samplingFrequency': value,
- if (_$ElectrocardiogramClassificationEnumMap[instance.classification]
- case final value?)
- 'classification': value,
- };
+ ElectrocardiogramHealthValue instance,
+) => {
+ '__type': ?instance.$type,
+ 'voltageValues': instance.voltageValues.map((e) => e.toJson()).toList(),
+ 'averageHeartRate': ?instance.averageHeartRate,
+ 'samplingFrequency': ?instance.samplingFrequency,
+ 'classification':
+ ?_$ElectrocardiogramClassificationEnumMap[instance.classification],
+};
const _$ElectrocardiogramClassificationEnumMap = {
ElectrocardiogramClassification.NOT_SET: 'NOT_SET',
@@ -446,34 +450,34 @@ const _$ElectrocardiogramClassificationEnumMap = {
};
ElectrocardiogramVoltageValue _$ElectrocardiogramVoltageValueFromJson(
- Map json) =>
- ElectrocardiogramVoltageValue(
- voltage: json['voltage'] as num,
- timeSinceSampleStart: json['timeSinceSampleStart'] as num,
- )..$type = json['__type'] as String?;
+ Map json,
+) => ElectrocardiogramVoltageValue(
+ voltage: json['voltage'] as num,
+ timeSinceSampleStart: json['timeSinceSampleStart'] as num,
+)..$type = json['__type'] as String?;
Map _$ElectrocardiogramVoltageValueToJson(
- ElectrocardiogramVoltageValue instance) =>
- {
- if (instance.$type case final value?) '__type': value,
- 'voltage': instance.voltage,
- 'timeSinceSampleStart': instance.timeSinceSampleStart,
- };
+ ElectrocardiogramVoltageValue instance,
+) => {
+ '__type': ?instance.$type,
+ 'voltage': instance.voltage,
+ 'timeSinceSampleStart': instance.timeSinceSampleStart,
+};
InsulinDeliveryHealthValue _$InsulinDeliveryHealthValueFromJson(
- Map json) =>
- InsulinDeliveryHealthValue(
- units: (json['units'] as num).toDouble(),
- reason: $enumDecode(_$InsulinDeliveryReasonEnumMap, json['reason']),
- )..$type = json['__type'] as String?;
+ Map json,
+) => InsulinDeliveryHealthValue(
+ units: (json['units'] as num).toDouble(),
+ reason: $enumDecode(_$InsulinDeliveryReasonEnumMap, json['reason']),
+)..$type = json['__type'] as String?;
Map _$InsulinDeliveryHealthValueToJson(
- InsulinDeliveryHealthValue instance) =>
- {
- if (instance.$type case final value?) '__type': value,
- 'units': instance.units,
- 'reason': _$InsulinDeliveryReasonEnumMap[instance.reason]!,
- };
+ InsulinDeliveryHealthValue instance,
+) => {
+ '__type': ?instance.$type,
+ 'units': instance.units,
+ 'reason': _$InsulinDeliveryReasonEnumMap[instance.reason]!,
+};
const _$InsulinDeliveryReasonEnumMap = {
InsulinDeliveryReason.NOT_SET: 'NOT_SET',
@@ -482,127 +486,122 @@ const _$InsulinDeliveryReasonEnumMap = {
};
NutritionHealthValue _$NutritionHealthValueFromJson(
- Map json) =>
- NutritionHealthValue(
- name: json['name'] as String?,
- mealType: json['meal_type'] as String?,
- calories: (json['calories'] as num?)?.toDouble(),
- protein: (json['protein'] as num?)?.toDouble(),
- fat: (json['fat'] as num?)?.toDouble(),
- carbs: (json['carbs'] as num?)?.toDouble(),
- caffeine: (json['caffeine'] as num?)?.toDouble(),
- vitaminA: (json['vitamin_a'] as num?)?.toDouble(),
- b1Thiamine: (json['b1_thiamine'] as num?)?.toDouble(),
- b2Riboflavin: (json['b2_riboflavin'] as num?)?.toDouble(),
- b3Niacin: (json['b3_niacin'] as num?)?.toDouble(),
- b5PantothenicAcid: (json['b5_pantothenic_acid'] as num?)?.toDouble(),
- b6Pyridoxine: (json['b6_pyridoxine'] as num?)?.toDouble(),
- b7Biotin: (json['b7_biotin'] as num?)?.toDouble(),
- b9Folate: (json['b9_folate'] as num?)?.toDouble(),
- b12Cobalamin: (json['b12_cobalamin'] as num?)?.toDouble(),
- vitaminC: (json['vitamin_c'] as num?)?.toDouble(),
- vitaminD: (json['vitamin_d'] as num?)?.toDouble(),
- vitaminE: (json['vitamin_e'] as num?)?.toDouble(),
- vitaminK: (json['vitamin_k'] as num?)?.toDouble(),
- calcium: (json['calcium'] as num?)?.toDouble(),
- chloride: (json['chloride'] as num?)?.toDouble(),
- cholesterol: (json['cholesterol'] as num?)?.toDouble(),
- choline: (json['choline'] as num?)?.toDouble(),
- chromium: (json['chromium'] as num?)?.toDouble(),
- copper: (json['copper'] as num?)?.toDouble(),
- fatUnsaturated: (json['fat_unsaturated'] as num?)?.toDouble(),
- fatMonounsaturated: (json['fat_monounsaturated'] as num?)?.toDouble(),
- fatPolyunsaturated: (json['fat_polyunsaturated'] as num?)?.toDouble(),
- fatSaturated: (json['fat_saturated'] as num?)?.toDouble(),
- fatTransMonoenoic: (json['fat_trans_monoenoic'] as num?)?.toDouble(),
- fiber: (json['fiber'] as num?)?.toDouble(),
- iodine: (json['iodine'] as num?)?.toDouble(),
- iron: (json['iron'] as num?)?.toDouble(),
- magnesium: (json['magnesium'] as num?)?.toDouble(),
- manganese: (json['manganese'] as num?)?.toDouble(),
- molybdenum: (json['molybdenum'] as num?)?.toDouble(),
- phosphorus: (json['phosphorus'] as num?)?.toDouble(),
- potassium: (json['potassium'] as num?)?.toDouble(),
- selenium: (json['selenium'] as num?)?.toDouble(),
- sodium: (json['sodium'] as num?)?.toDouble(),
- sugar: (json['sugar'] as num?)?.toDouble(),
- water: (json['water'] as num?)?.toDouble(),
- zinc: (json['zinc'] as num?)?.toDouble(),
- )..$type = json['__type'] as String?;
+ Map json,
+) => NutritionHealthValue(
+ name: json['name'] as String?,
+ mealType: json['meal_type'] as String?,
+ calories: (json['calories'] as num?)?.toDouble(),
+ protein: (json['protein'] as num?)?.toDouble(),
+ fat: (json['fat'] as num?)?.toDouble(),
+ carbs: (json['carbs'] as num?)?.toDouble(),
+ caffeine: (json['caffeine'] as num?)?.toDouble(),
+ vitaminA: (json['vitamin_a'] as num?)?.toDouble(),
+ b1Thiamine: (json['b1_thiamine'] as num?)?.toDouble(),
+ b2Riboflavin: (json['b2_riboflavin'] as num?)?.toDouble(),
+ b3Niacin: (json['b3_niacin'] as num?)?.toDouble(),
+ b5PantothenicAcid: (json['b5_pantothenic_acid'] as num?)?.toDouble(),
+ b6Pyridoxine: (json['b6_pyridoxine'] as num?)?.toDouble(),
+ b7Biotin: (json['b7_biotin'] as num?)?.toDouble(),
+ b9Folate: (json['b9_folate'] as num?)?.toDouble(),
+ b12Cobalamin: (json['b12_cobalamin'] as num?)?.toDouble(),
+ vitaminC: (json['vitamin_c'] as num?)?.toDouble(),
+ vitaminD: (json['vitamin_d'] as num?)?.toDouble(),
+ vitaminE: (json['vitamin_e'] as num?)?.toDouble(),
+ vitaminK: (json['vitamin_k'] as num?)?.toDouble(),
+ calcium: (json['calcium'] as num?)?.toDouble(),
+ chloride: (json['chloride'] as num?)?.toDouble(),
+ cholesterol: (json['cholesterol'] as num?)?.toDouble(),
+ choline: (json['choline'] as num?)?.toDouble(),
+ chromium: (json['chromium'] as num?)?.toDouble(),
+ copper: (json['copper'] as num?)?.toDouble(),
+ fatUnsaturated: (json['fat_unsaturated'] as num?)?.toDouble(),
+ fatMonounsaturated: (json['fat_monounsaturated'] as num?)?.toDouble(),
+ fatPolyunsaturated: (json['fat_polyunsaturated'] as num?)?.toDouble(),
+ fatSaturated: (json['fat_saturated'] as num?)?.toDouble(),
+ fatTransMonoenoic: (json['fat_trans_monoenoic'] as num?)?.toDouble(),
+ fiber: (json['fiber'] as num?)?.toDouble(),
+ iodine: (json['iodine'] as num?)?.toDouble(),
+ iron: (json['iron'] as num?)?.toDouble(),
+ magnesium: (json['magnesium'] as num?)?.toDouble(),
+ manganese: (json['manganese'] as num?)?.toDouble(),
+ molybdenum: (json['molybdenum'] as num?)?.toDouble(),
+ phosphorus: (json['phosphorus'] as num?)?.toDouble(),
+ potassium: (json['potassium'] as num?)?.toDouble(),
+ selenium: (json['selenium'] as num?)?.toDouble(),
+ sodium: (json['sodium'] as num?)?.toDouble(),
+ sugar: (json['sugar'] as num?)?.toDouble(),
+ water: (json['water'] as num?)?.toDouble(),
+ zinc: (json['zinc'] as num?)?.toDouble(),
+)..$type = json['__type'] as String?;
Map _$NutritionHealthValueToJson(
- NutritionHealthValue instance) =>
- {
- if (instance.$type case final value?) '__type': value,
- if (instance.name case final value?) 'name': value,
- if (instance.mealType case final value?) 'meal_type': value,
- if (instance.calories case final value?) 'calories': value,
- if (instance.protein case final value?) 'protein': value,
- if (instance.fat case final value?) 'fat': value,
- if (instance.carbs case final value?) 'carbs': value,
- if (instance.caffeine case final value?) 'caffeine': value,
- if (instance.vitaminA case final value?) 'vitamin_a': value,
- if (instance.b1Thiamine case final value?) 'b1_thiamine': value,
- if (instance.b2Riboflavin case final value?) 'b2_riboflavin': value,
- if (instance.b3Niacin case final value?) 'b3_niacin': value,
- if (instance.b5PantothenicAcid case final value?)
- 'b5_pantothenic_acid': value,
- if (instance.b6Pyridoxine case final value?) 'b6_pyridoxine': value,
- if (instance.b7Biotin case final value?) 'b7_biotin': value,
- if (instance.b9Folate case final value?) 'b9_folate': value,
- if (instance.b12Cobalamin case final value?) 'b12_cobalamin': value,
- if (instance.vitaminC case final value?) 'vitamin_c': value,
- if (instance.vitaminD case final value?) 'vitamin_d': value,
- if (instance.vitaminE case final value?) 'vitamin_e': value,
- if (instance.vitaminK case final value?) 'vitamin_k': value,
- if (instance.calcium case final value?) 'calcium': value,
- if (instance.chloride case final value?) 'chloride': value,
- if (instance.cholesterol case final value?) 'cholesterol': value,
- if (instance.choline case final value?) 'choline': value,
- if (instance.chromium case final value?) 'chromium': value,
- if (instance.copper case final value?) 'copper': value,
- if (instance.fatUnsaturated case final value?) 'fat_unsaturated': value,
- if (instance.fatMonounsaturated case final value?)
- 'fat_monounsaturated': value,
- if (instance.fatPolyunsaturated case final value?)
- 'fat_polyunsaturated': value,
- if (instance.fatSaturated case final value?) 'fat_saturated': value,
- if (instance.fatTransMonoenoic case final value?)
- 'fat_trans_monoenoic': value,
- if (instance.fiber case final value?) 'fiber': value,
- if (instance.iodine case final value?) 'iodine': value,
- if (instance.iron case final value?) 'iron': value,
- if (instance.magnesium case final value?) 'magnesium': value,
- if (instance.manganese case final value?) 'manganese': value,
- if (instance.molybdenum case final value?) 'molybdenum': value,
- if (instance.phosphorus case final value?) 'phosphorus': value,
- if (instance.potassium case final value?) 'potassium': value,
- if (instance.selenium case final value?) 'selenium': value,
- if (instance.sodium case final value?) 'sodium': value,
- if (instance.sugar case final value?) 'sugar': value,
- if (instance.water case final value?) 'water': value,
- if (instance.zinc case final value?) 'zinc': value,
- };
+ NutritionHealthValue instance,
+) => {
+ '__type': ?instance.$type,
+ 'name': ?instance.name,
+ 'meal_type': ?instance.mealType,
+ 'calories': ?instance.calories,
+ 'protein': ?instance.protein,
+ 'fat': ?instance.fat,
+ 'carbs': ?instance.carbs,
+ 'caffeine': ?instance.caffeine,
+ 'vitamin_a': ?instance.vitaminA,
+ 'b1_thiamine': ?instance.b1Thiamine,
+ 'b2_riboflavin': ?instance.b2Riboflavin,
+ 'b3_niacin': ?instance.b3Niacin,
+ 'b5_pantothenic_acid': ?instance.b5PantothenicAcid,
+ 'b6_pyridoxine': ?instance.b6Pyridoxine,
+ 'b7_biotin': ?instance.b7Biotin,
+ 'b9_folate': ?instance.b9Folate,
+ 'b12_cobalamin': ?instance.b12Cobalamin,
+ 'vitamin_c': ?instance.vitaminC,
+ 'vitamin_d': ?instance.vitaminD,
+ 'vitamin_e': ?instance.vitaminE,
+ 'vitamin_k': ?instance.vitaminK,
+ 'calcium': ?instance.calcium,
+ 'chloride': ?instance.chloride,
+ 'cholesterol': ?instance.cholesterol,
+ 'choline': ?instance.choline,
+ 'chromium': ?instance.chromium,
+ 'copper': ?instance.copper,
+ 'fat_unsaturated': ?instance.fatUnsaturated,
+ 'fat_monounsaturated': ?instance.fatMonounsaturated,
+ 'fat_polyunsaturated': ?instance.fatPolyunsaturated,
+ 'fat_saturated': ?instance.fatSaturated,
+ 'fat_trans_monoenoic': ?instance.fatTransMonoenoic,
+ 'fiber': ?instance.fiber,
+ 'iodine': ?instance.iodine,
+ 'iron': ?instance.iron,
+ 'magnesium': ?instance.magnesium,
+ 'manganese': ?instance.manganese,
+ 'molybdenum': ?instance.molybdenum,
+ 'phosphorus': ?instance.phosphorus,
+ 'potassium': ?instance.potassium,
+ 'selenium': ?instance.selenium,
+ 'sodium': ?instance.sodium,
+ 'sugar': ?instance.sugar,
+ 'water': ?instance.water,
+ 'zinc': ?instance.zinc,
+};
MenstruationFlowHealthValue _$MenstruationFlowHealthValueFromJson(
- Map json) =>
- MenstruationFlowHealthValue(
- flow: $enumDecodeNullable(_$MenstrualFlowEnumMap, json['flow']),
- dateTime: DateTime.parse(json['dateTime'] as String),
- isStartOfCycle: json['isStartOfCycle'] as bool?,
- wasUserEntered: json['wasUserEntered'] as bool?,
- )..$type = json['__type'] as String?;
+ Map json,
+) => MenstruationFlowHealthValue(
+ flow: $enumDecodeNullable(_$MenstrualFlowEnumMap, json['flow']),
+ dateTime: DateTime.parse(json['dateTime'] as String),
+ isStartOfCycle: json['isStartOfCycle'] as bool?,
+ wasUserEntered: json['wasUserEntered'] as bool?,
+)..$type = json['__type'] as String?;
Map _$MenstruationFlowHealthValueToJson(
- MenstruationFlowHealthValue instance) =>
- {
- if (instance.$type case final value?) '__type': value,
- if (_$MenstrualFlowEnumMap[instance.flow] case final value?)
- 'flow': value,
- if (instance.isStartOfCycle case final value?) 'isStartOfCycle': value,
- if (instance.wasUserEntered case final value?) 'wasUserEntered': value,
- 'dateTime': instance.dateTime.toIso8601String(),
- };
+ MenstruationFlowHealthValue instance,
+) => {
+ '__type': ?instance.$type,
+ 'flow': ?_$MenstrualFlowEnumMap[instance.flow],
+ 'isStartOfCycle': ?instance.isStartOfCycle,
+ 'wasUserEntered': ?instance.wasUserEntered,
+ 'dateTime': instance.dateTime.toIso8601String(),
+};
const _$MenstrualFlowEnumMap = {
MenstrualFlow.unspecified: 'unspecified',
diff --git a/packages/health/lib/src/health_value_types.dart b/packages/health/lib/src/health_value_types.dart
index 6a8b28819..fd3b8c0aa 100644
--- a/packages/health/lib/src/health_value_types.dart
+++ b/packages/health/lib/src/health_value_types.dart
@@ -73,14 +73,18 @@ class AudiogramHealthValue extends HealthValue {
/// Create a [AudiogramHealthValue] based on a health data point from native data format.
factory AudiogramHealthValue.fromHealthDataPoint(dynamic dataPoint) =>
AudiogramHealthValue(
- frequencies: List.from(dataPoint['frequencies'] as List),
- leftEarSensitivities:
- List.from(dataPoint['leftEarSensitivities'] as List),
- rightEarSensitivities:
- List.from(dataPoint['rightEarSensitivities'] as List));
+ frequencies: List.from(dataPoint['frequencies'] as List),
+ leftEarSensitivities: List.from(
+ dataPoint['leftEarSensitivities'] as List,
+ ),
+ rightEarSensitivities: List.from(
+ dataPoint['rightEarSensitivities'] as List,
+ ),
+ );
@override
- String toString() => """$runtimeType - frequencies: ${frequencies.toString()},
+ String toString() =>
+ """$runtimeType - frequencies: ${frequencies.toString()},
left ear sensitivities: ${leftEarSensitivities.toString()},
right ear sensitivities: ${rightEarSensitivities.toString()}""";
@@ -140,43 +144,48 @@ class WorkoutHealthValue extends HealthValue {
/// Might not be available for all workouts.
HealthDataUnit? totalStepsUnit;
- WorkoutHealthValue(
- {required this.workoutActivityType,
- this.totalEnergyBurned,
- this.totalEnergyBurnedUnit,
- this.totalDistance,
- this.totalDistanceUnit,
- this.totalSteps,
- this.totalStepsUnit});
+ WorkoutHealthValue({
+ required this.workoutActivityType,
+ this.totalEnergyBurned,
+ this.totalEnergyBurnedUnit,
+ this.totalDistance,
+ this.totalDistanceUnit,
+ this.totalSteps,
+ this.totalStepsUnit,
+ });
/// Create a [WorkoutHealthValue] based on a health data point from native data format.
factory WorkoutHealthValue.fromHealthDataPoint(dynamic dataPoint) =>
WorkoutHealthValue(
- workoutActivityType: HealthWorkoutActivityType.values.firstWhere(
- (element) => element.name == dataPoint['workoutActivityType'],
- orElse: () => HealthWorkoutActivityType.OTHER,
- ),
- totalEnergyBurned: dataPoint['totalEnergyBurned'] != null
- ? (dataPoint['totalEnergyBurned'] as num).toInt()
- : null,
- totalEnergyBurnedUnit: dataPoint['totalEnergyBurnedUnit'] != null
- ? HealthDataUnit.values.firstWhere((element) =>
- element.name == dataPoint['totalEnergyBurnedUnit'])
- : null,
- totalDistance: dataPoint['totalDistance'] != null
- ? (dataPoint['totalDistance'] as num).toInt()
- : null,
- totalDistanceUnit: dataPoint['totalDistanceUnit'] != null
- ? HealthDataUnit.values.firstWhere(
- (element) => element.name == dataPoint['totalDistanceUnit'])
- : null,
- totalSteps: dataPoint['totalSteps'] != null
- ? (dataPoint['totalSteps'] as num).toInt()
- : null,
- totalStepsUnit: dataPoint['totalStepsUnit'] != null
- ? HealthDataUnit.values.firstWhere(
- (element) => element.name == dataPoint['totalStepsUnit'])
- : null);
+ workoutActivityType: HealthWorkoutActivityType.values.firstWhere(
+ (element) => element.name == dataPoint['workoutActivityType'],
+ orElse: () => HealthWorkoutActivityType.OTHER,
+ ),
+ totalEnergyBurned: dataPoint['totalEnergyBurned'] != null
+ ? (dataPoint['totalEnergyBurned'] as num).toInt()
+ : null,
+ totalEnergyBurnedUnit: dataPoint['totalEnergyBurnedUnit'] != null
+ ? HealthDataUnit.values.firstWhere(
+ (element) => element.name == dataPoint['totalEnergyBurnedUnit'],
+ )
+ : null,
+ totalDistance: dataPoint['totalDistance'] != null
+ ? (dataPoint['totalDistance'] as num).toInt()
+ : null,
+ totalDistanceUnit: dataPoint['totalDistanceUnit'] != null
+ ? HealthDataUnit.values.firstWhere(
+ (element) => element.name == dataPoint['totalDistanceUnit'],
+ )
+ : null,
+ totalSteps: dataPoint['totalSteps'] != null
+ ? (dataPoint['totalSteps'] as num).toInt()
+ : null,
+ totalStepsUnit: dataPoint['totalStepsUnit'] != null
+ ? HealthDataUnit.values.firstWhere(
+ (element) => element.name == dataPoint['totalStepsUnit'],
+ )
+ : null,
+ );
@override
Function get fromJsonFunction => _$WorkoutHealthValueFromJson;
@@ -208,13 +217,14 @@ class WorkoutHealthValue extends HealthValue {
@override
int get hashCode => Object.hash(
- workoutActivityType,
- totalEnergyBurned,
- totalEnergyBurnedUnit,
- totalDistance,
- totalDistanceUnit,
- totalSteps,
- totalStepsUnit);
+ workoutActivityType,
+ totalEnergyBurned,
+ totalEnergyBurnedUnit,
+ totalDistance,
+ totalDistanceUnit,
+ totalSteps,
+ totalStepsUnit,
+ );
}
/// A [HealthValue] object for ECGs
@@ -256,13 +266,18 @@ class ElectrocardiogramHealthValue extends HealthValue {
factory ElectrocardiogramHealthValue.fromHealthDataPoint(dynamic dataPoint) =>
ElectrocardiogramHealthValue(
voltageValues: (dataPoint['voltageValues'] as List)
- .map((voltageValue) =>
- ElectrocardiogramVoltageValue.fromHealthDataPoint(voltageValue))
+ .map(
+ (voltageValue) =>
+ ElectrocardiogramVoltageValue.fromHealthDataPoint(
+ voltageValue,
+ ),
+ )
.toList(),
averageHeartRate: dataPoint['averageHeartRate'] as num?,
samplingFrequency: dataPoint['samplingFrequency'] as double?,
- classification: ElectrocardiogramClassification.values
- .firstWhere((c) => c.value == dataPoint['classification']),
+ classification: ElectrocardiogramClassification.values.firstWhere(
+ (c) => c.value == dataPoint['classification'],
+ ),
);
@override
@@ -275,7 +290,11 @@ class ElectrocardiogramHealthValue extends HealthValue {
@override
int get hashCode => Object.hash(
- voltageValues, averageHeartRate, samplingFrequency, classification);
+ voltageValues,
+ averageHeartRate,
+ samplingFrequency,
+ classification,
+ );
@override
String toString() =>
@@ -298,10 +317,11 @@ class ElectrocardiogramVoltageValue extends HealthValue {
/// Create a [ElectrocardiogramVoltageValue] based on a health data point from native data format.
factory ElectrocardiogramVoltageValue.fromHealthDataPoint(
- dynamic dataPoint) =>
- ElectrocardiogramVoltageValue(
- voltage: dataPoint['voltage'] as num,
- timeSinceSampleStart: dataPoint['timeSinceSampleStart'] as num);
+ dynamic dataPoint,
+ ) => ElectrocardiogramVoltageValue(
+ voltage: dataPoint['voltage'] as num,
+ timeSinceSampleStart: dataPoint['timeSinceSampleStart'] as num,
+ );
@override
Function get fromJsonFunction => _$ElectrocardiogramVoltageValueFromJson;
@@ -332,10 +352,7 @@ class InsulinDeliveryHealthValue extends HealthValue {
/// If it's basal, bolus or unknown reason for insulin dosage
InsulinDeliveryReason reason;
- InsulinDeliveryHealthValue({
- required this.units,
- required this.reason,
- });
+ InsulinDeliveryHealthValue({required this.units, required this.reason});
factory InsulinDeliveryHealthValue.fromHealthDataPoint(dynamic dataPoint) {
final units = dataPoint['value'] as num;
@@ -345,8 +362,8 @@ class InsulinDeliveryHealthValue extends HealthValue {
: Map.from(dataPoint['metadata'] as Map);
final reasonIndex =
metadata == null || !metadata.containsKey('HKInsulinDeliveryReason')
- ? 0
- : metadata['HKInsulinDeliveryReason'] as double;
+ ? 0
+ : metadata['HKInsulinDeliveryReason'] as double;
final reason = InsulinDeliveryReason.values[reasonIndex.toInt()];
return InsulinDeliveryHealthValue(units: units.toDouble(), reason: reason);
@@ -632,19 +649,20 @@ class NutritionHealthValue extends HealthValue {
dataPoint = dataPoint as Map