Skip to content

Commit 8193218

Browse files
authored
Merge pull request #1223 from connor-callaghan/delete-by-id-and-unit-support
[Health] add delete by client id and fetch unit support
2 parents 751aa7e + dbf5c68 commit 8193218

10 files changed

Lines changed: 875 additions & 563 deletions

File tree

packages/health/android/src/main/kotlin/cachet/plugins/health/HealthDataConverter.kt

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,34 @@ class HealthDataConverter {
2121
* @return List<Map<String, Any?>> List of converted records (some records may split into multiple entries)
2222
* @throws IllegalArgumentException If the record type is not supported
2323
*/
24-
fun convertRecord(record: Any, dataType: String): List<Map<String, Any?>> {
24+
fun convertRecord(record: Any, dataType: String, dataUnit: String? = null): List<Map<String, Any?>> {
2525
val metadata = (record as Record).metadata
2626

2727
return when (record) {
2828
// Single-value instant records
29-
is WeightRecord -> listOf(createInstantRecord(metadata, record.time, record.weight.inKilograms))
30-
is HeightRecord -> listOf(createInstantRecord(metadata, record.time, record.height.inMeters))
29+
is WeightRecord -> listOf(createInstantRecord(metadata, record.time, when (dataUnit) {
30+
"POUND" -> record.weight.inPounds
31+
else -> record.weight.inKilograms
32+
}))
33+
is HeightRecord -> listOf(createInstantRecord(metadata, record.time, when (dataUnit) {
34+
"CENTIMETER" -> (record.height.inMeters * 100)
35+
"INCH" -> record.height.inInches
36+
else -> record.height.inMeters
37+
}))
3138
is BodyFatRecord -> listOf(createInstantRecord(metadata, record.time, record.percentage.value))
3239
is LeanBodyMassRecord -> listOf(createInstantRecord(metadata, record.time, record.mass.inKilograms))
3340
is HeartRateVariabilityRmssdRecord -> listOf(createInstantRecord(metadata, record.time, record.heartRateVariabilityMillis))
34-
is BodyTemperatureRecord -> listOf(createInstantRecord(metadata, record.time, record.temperature.inCelsius))
41+
is BodyTemperatureRecord -> listOf(createInstantRecord(metadata, record.time, when (dataUnit) {
42+
"DEGREE_FAHRENHEIT" -> record.temperature.inFahrenheit
43+
"KELVIN" -> record.temperature.inCelsius + 273.15
44+
else -> record.temperature.inCelsius
45+
}))
3546
is BodyWaterMassRecord -> listOf(createInstantRecord(metadata, record.time, record.mass.inKilograms))
3647
is OxygenSaturationRecord -> listOf(createInstantRecord(metadata, record.time, record.percentage.value))
37-
is BloodGlucoseRecord -> listOf(createInstantRecord(metadata, record.time, record.level.inMilligramsPerDeciliter))
48+
is BloodGlucoseRecord -> listOf(createInstantRecord(metadata, record.time, when (dataUnit) {
49+
"MILLIMOLES_PER_LITER" -> record.level.inMillimolesPerLiter
50+
else -> record.level.inMilligramsPerDeciliter
51+
}))
3852
is BasalMetabolicRateRecord -> listOf(createInstantRecord(metadata, record.time, record.basalMetabolicRate.inKilocaloriesPerDay))
3953
is RestingHeartRateRecord -> listOf(createInstantRecord(metadata, record.time, record.beatsPerMinute))
4054
is RespiratoryRateRecord -> listOf(createInstantRecord(metadata, record.time, record.rate))
@@ -236,7 +250,7 @@ class HealthDataConverter {
236250
)
237251
)
238252
}
239-
253+
240254
companion object {
241255
private const val BLOOD_PRESSURE_DIASTOLIC = "BLOOD_PRESSURE_DIASTOLIC"
242256
private const val MEAL_UNKNOWN = "UNKNOWN"

packages/health/android/src/main/kotlin/cachet/plugins/health/HealthDataOperations.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,45 @@ class HealthDataOperations(
247247
}
248248
}
249249

250+
/**
251+
* Deletes a specific health record by its client record ID and data type. Allows precise
252+
* deletion of individual health records using client-side IDs.
253+
*
254+
* @param call Method call containing 'dataTypeKey', 'recordId', and 'clientRecordId'
255+
* @param result Flutter result callback returning boolean success status
256+
*/
257+
fun deleteByClientRecordId(call: MethodCall, result: Result) {
258+
val arguments = call.arguments as? HashMap<*, *>
259+
val dataTypeKey = (arguments?.get("dataTypeKey") as? String)!!
260+
val recordId = listOfNotNull(arguments["recordId"] as? String)
261+
val clientRecordId = listOfNotNull(arguments["clientRecordId"] as? String)
262+
if (!HealthConstants.mapToType.containsKey(dataTypeKey)) {
263+
Log.w("FLUTTER_HEALTH::ERROR", "Datatype $dataTypeKey not found in HC")
264+
result.success(false)
265+
return
266+
}
267+
val classType = HealthConstants.mapToType[dataTypeKey]!!
268+
269+
scope.launch {
270+
try {
271+
healthConnectClient.deleteRecords(
272+
classType,
273+
recordId,
274+
clientRecordId
275+
)
276+
result.success(true)
277+
} catch (e: Exception) {
278+
Log.e(
279+
"FLUTTER_HEALTH::ERROR",
280+
"Error deleting record with ClientRecordId: $clientRecordId"
281+
)
282+
Log.e("FLUTTER_HEALTH::ERROR", e.message ?: "unknown error")
283+
Log.e("FLUTTER_HEALTH::ERROR", e.stackTraceToString())
284+
result.success(false)
285+
}
286+
}
287+
}
288+
250289
/**
251290
* Internal helper method to prepare Health Connect permission strings. Converts data type names
252291
* and access levels into proper permission format.

packages/health/android/src/main/kotlin/cachet/plugins/health/HealthDataReader.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import android.os.Handler
55
import android.util.Log
66
import androidx.health.connect.client.HealthConnectClient
7+
import androidx.health.connect.client.permission.HealthPermission
78
import androidx.health.connect.client.records.*
89
import androidx.health.connect.client.request.AggregateGroupByDurationRequest
910
import androidx.health.connect.client.request.AggregateRequest
@@ -40,19 +41,27 @@ class HealthDataReader(
4041
*/
4142
fun getData(call: MethodCall, result: Result) {
4243
val dataType = call.argument<String>("dataTypeKey")!!
44+
val dataUnit: String? = call.argument<String>("dataUnitKey")
4345
val startTime = Instant.ofEpochMilli(call.argument<Long>("startTime")!!)
4446
val endTime = Instant.ofEpochMilli(call.argument<Long>("endTime")!!)
4547
val healthConnectData = mutableListOf<Map<String, Any?>>()
4648
val recordingMethodsToFilter = call.argument<List<Int>>("recordingMethodsToFilter")!!
4749

4850
Log.i(
4951
"FLUTTER_HEALTH",
50-
"Getting data for $dataType between $startTime and $endTime, filtering by $recordingMethodsToFilter"
52+
"Getting data for $dataType with unit $dataUnit between $startTime and $endTime, filtering by $recordingMethodsToFilter"
5153
)
5254

5355
scope.launch {
5456
try {
55-
HealthConstants.mapToType[dataType]?.let { classType ->
57+
val grantedPermissions = healthConnectClient.permissionController.getGrantedPermissions()
58+
59+
val authorizedTypeMap = HealthConstants.mapToType.filter { (typeKey, classType) ->
60+
val requiredPermission = HealthPermission.getReadPermission(classType)
61+
grantedPermissions.contains(requiredPermission)
62+
}
63+
64+
authorizedTypeMap[dataType]?.let { classType ->
5665
val records = mutableListOf<Record>()
5766

5867
// Set up the initial request to read health records
@@ -92,7 +101,7 @@ class HealthDataReader(
92101
)
93102
for (rec in filteredRecords) {
94103
healthConnectData.addAll(
95-
dataConverter.convertRecord(rec, dataType)
104+
dataConverter.convertRecord(rec, dataType, dataUnit)
96105
)
97106
}
98107
}
@@ -105,7 +114,7 @@ class HealthDataReader(
105114
"Unable to return $dataType due to the following exception:"
106115
)
107116
Log.e("FLUTTER_HEALTH::ERROR", Log.getStackTraceString(e))
108-
result.success(null)
117+
result.success(emptyList<Map<String, Any?>>()) // Return empty list instead of null
109118
}
110119
}
111120
}

0 commit comments

Comments
 (0)