Skip to content

Commit

Permalink
feat: android write
Browse files Browse the repository at this point in the history
  • Loading branch information
carozo committed Jan 6, 2025
1 parent 15e5d0b commit 3135a1d
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 33 deletions.
2 changes: 0 additions & 2 deletions example/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,3 @@ newArchEnabled=true
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true

newArchEnabled=true
20 changes: 11 additions & 9 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,23 @@ export default function App() {
setSteps(data[0]?.value);
});
write(HealthLinkDataType.BloodGlucose, {
value: 5,
});
write(HealthLinkDataType.Height, {
value: 180,
});
write(HealthLinkDataType.Weight, {
value: 80,
value: 6,
});
write(HealthLinkDataType.Steps, {
value: 100,
startDate: new Date('2024-12-31').toISOString(),
startDate: new Date('2024-12-30').toISOString(),
endDate: new Date('2024-12-31').toISOString(),
});
write(HealthLinkDataType.Weight, {
value: 58,
unit: WeightUnit.Kg,
});
write(HealthLinkDataType.Height, {
value: 165,
unit: HeighUnit.Cm,
});
write(HealthLinkDataType.HeartRate, {
value: 100,
value: 60,
});
});
}, []);
Expand Down
10 changes: 4 additions & 6 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
optionsToAndroidOptions,
type ReadOptions,
} from './types/dataTypes';
import type { HealthInputOptions, HealthValue } from 'react-native-health';
import type { HealthValue } from 'react-native-health';
import {
readDataResultDeserializer,
readIosCallback,
Expand Down Expand Up @@ -68,17 +68,15 @@ export const write = async <T extends WriteDataType>(
if (serializedData === null) {
return;
}
await writeIosCallback(dataType, serializedData as HealthInputOptions);
await writeIosCallback(dataType, serializedData as WriteOptions<T>);
} else if (Platform.OS === 'android') {
const serializedData = serializeWriteOptions(dataType, data);
console.log([serializedData as HealthConnectRecord]);
if (serializedData === null) {
return;
}
const a = await insertRecords([
serializedData as HealthConnectRecord,
]).catch((e) => {
await insertRecords([serializedData as HealthConnectRecord]).catch((e) => {
console.error(e);
});
console.log(a);
}
};
2 changes: 1 addition & 1 deletion src/types/dataTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const optionsToAndroidOptions = (
startTime: options.startDate!,
endTime: options.endDate!,
},
ascendingOrder: options.ascending,
ascendingOrder: options.ascending ?? false,
pageSize: options.limit,
};
};
104 changes: 89 additions & 15 deletions src/types/save.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { HealthInputOptions, HealthUnit } from 'react-native-health';
import { type HealthValueOptions } from 'react-native-health';
import { HealthLinkDataType } from './dataTypes';
import { Platform } from 'react-native';
import type { HealthConnectRecord } from 'react-native-health-connect';
import {
androidBloodGlucoseUnitMap,
BloodGlucoseUnit,
HeartRateUnit,
HeighUnit,
StepsUnit,
unitToIosUnitMap,
WeightUnit,
} from './units';

Expand All @@ -16,13 +18,18 @@ export interface WriteOptionsBase<T extends WriteDataType> {
? { diastolic: number; systolic: number }
: number;
time?: string;
unit?: Partial<HealthUnit>;
unit?: Unit;
metadata?: {
source?: string;
} & Record<string, any>;
}

export type Unit = BloodGlucoseUnit | WeightUnit | StepsUnit;
export type Unit =
| BloodGlucoseUnit
| WeightUnit
| StepsUnit
| HeighUnit
| HeartRateUnit;

export type WriteOptions<T extends WriteDataType> = WriteOptionsBase<T> &
(T extends HealthLinkDataType.Steps
Expand All @@ -39,37 +46,104 @@ export type WriteDataType =
export const serializeWriteOptions = <T extends WriteDataType>(
dataType: T,
options: WriteOptions<T>
): HealthInputOptions | HealthConnectRecord | null => {
): HealthValueOptions | HealthConnectRecord | null => {
if (Platform.OS === 'ios') {
switch (dataType) {
default:
return options;
let iosOptions: HealthValueOptions = {
unit: options.unit && unitToIosUnitMap[options.unit],
value:
options.unit === WeightUnit.Kg
? (options.value ?? 0) * 1000
: options.unit === HeighUnit.Cm
? (options.value ?? 0) / 100
: (options.value ?? 0),
};
return iosOptions;
}
} else if (Platform.OS === 'android') {
let androidOptions = {
recordType: dataType,
startTime: options.startDate,
endTime: options.endDate,
};
switch (dataType) {
case HealthLinkDataType.BloodGlucose:
const unit = options.unit
? androidBloodGlucoseUnitMap[
options.unit as unknown as BloodGlucoseUnit
]
: 'millimolesPerLiter';
//@ts-ignore
return {
...androidOptions,
recordType: 'BloodGlucose',
relationToMeal: options.metadata?.relationToMeal ?? 0,
mealType: options.metadata?.mealType ?? 0,
specimenSource: options.metadata?.specimenSource ?? 0,
time: options.time ?? options.startDate ?? new Date().toISOString(),
level: {
unit,
value: options.value,
unit:
options.unit === BloodGlucoseUnit.MgPerdL
? 'milligramsPerDeciliter'
: 'millimolesPerLiter',
value: options.value as number,
},
};
case HealthLinkDataType.Steps:
return {
...androidOptions,
recordType: 'Steps',
count: options.value ?? 0,
startTime: options.startDate ?? new Date().toISOString(),
endTime: options.endDate ?? new Date().toISOString(),
};
case HealthLinkDataType.Weight:
return {
...androidOptions,
recordType: 'Weight',
time: options.time ?? options.startDate ?? new Date().toISOString(),
weight: {
unit:
(options.unit as unknown as WeightUnit) === WeightUnit.Kg
? 'kilograms'
: (options.unit as unknown as WeightUnit) === WeightUnit.Gram
? 'grams'
: 'pounds',
value: options.value as number,
},
};
case HealthLinkDataType.Height:
return {
...androidOptions,
recordType: 'Height',
time: options.time ?? options.startDate ?? new Date().toISOString(),
height: {
unit:
(options.unit as unknown as HeighUnit) === HeighUnit.Cm ||
(options.unit as unknown as HeighUnit) === HeighUnit.Meter
? 'meters'
: (options.unit as unknown as HeighUnit) === HeighUnit.Foot
? 'feet'
: 'inches',
value:
(options.unit as unknown as HeighUnit) === HeighUnit.Cm
? (options.value as number) / 100
: (options.value as number),
},
};
case HealthLinkDataType.HeartRate:
return {
...androidOptions,
recordType: 'HeartRate',
startTime: options.startDate ?? new Date().toISOString(),
endTime: options.endDate ?? new Date().toISOString(),
samples: [
{
time:
options.time ?? options.startDate ?? new Date().toISOString(),
beatsPerMinute: options.value as number,
},
],
};
default:
return null;
}
}
//@ts-ignore
return options;
};

Expand Down
19 changes: 19 additions & 0 deletions src/types/units.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { HealthUnit } from 'react-native-health';
import type { RecordResult } from 'react-native-health-connect';

export enum BloodGlucoseUnit {
Expand All @@ -22,6 +23,10 @@ export enum StepsUnit {
Count = 'count',
}

export enum HeartRateUnit {
Bpm = 'bpm',
}

export const androidHeightUnitMap = (
data: RecordResult<'Height'>,
unit?: string
Expand Down Expand Up @@ -60,3 +65,17 @@ export const androidBloodGlucoseUnitMap = {
[BloodGlucoseUnit.MgPerdL]: 'milligramsPerDeciliter',
[BloodGlucoseUnit.MmolPerL]: 'millimolesPerLiter',
};

export const unitToIosUnitMap = {
[HeighUnit.Meter]: HealthUnit.meter,
[HeighUnit.Foot]: HealthUnit.foot,
[HeighUnit.Inch]: HealthUnit.inch,
[WeightUnit.Gram]: HealthUnit.gram,
[WeightUnit.Pounds]: HealthUnit.pound,
[StepsUnit.Count]: HealthUnit.count,
[BloodGlucoseUnit.MgPerdL]: HealthUnit.mgPerdL,
[BloodGlucoseUnit.MmolPerL]: HealthUnit.mmolPerL,
[HeighUnit.Cm]: HealthUnit.meter,
[WeightUnit.Kg]: HealthUnit.gram,
[HeartRateUnit.Bpm]: HealthUnit.bpm,
};

0 comments on commit 3135a1d

Please sign in to comment.