@adminide-stack/yantra-mobile 12.0.140 → 12.0.141-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/features/devices/readings.js.map +1 -1
- package/lib/features/devices/session.js +2 -22
- package/lib/features/devices/session.js.map +1 -1
- package/lib/screens/Devices/index.js +3 -205
- package/lib/screens/Devices/index.js.map +1 -1
- package/package.json +4 -4
- package/lib/features/devices/bodyComposition.js +0 -116
- package/lib/features/devices/bodyComposition.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readings.js","sources":["../../../src/features/devices/readings.ts"],"sourcesContent":["/**\n * What a paired Bluetooth device measured, and how it reaches the Fitness\n * backend.\n *\n * The backend keeps ONE day per source and replaces it whole on every upload,\n * so a reading is never sent alone: the app keeps every reading it took (the\n * device store), and each upload rebuilds the full `device` day for the dates\n * that changed. A blood-pressure reading in the evening never wipes the\n * morning's weigh-in.\n *\n * Reading ids are stable (device + what + when): a monitor that sends its\n * whole memory on every connection, or the same reading arriving twice, is\n * stored once.\n */\n\nimport type { BodyComposition } from './bodyComposition';\nimport { sanitizeDay, hasData } from '../health/buildDays';\nimport type { TimedValue } from '../health/model';\nimport type { HealthDay, HealthReading, HealthWorkout, MealRelation } from '../health/types';\nimport type { ZoneClock } from '../health/time';\nimport { zoneMinutes } from '../health/zones';\n\ninterface ReadingBase {\n id: string;\n /** Epoch ms of the measurement. */\n at: number;\n deviceId: string;\n deviceName: string;\n}\n\nexport interface BodyReading extends ReadingBase {\n kind: 'body';\n weightKg?: number;\n bodyFatPct?: number;\n leanMassKg?: number;\n bmi?: number;\n /**\n * Whole-body impedance in ohms, when the scale sends it. A scale that only\n * reports weight and impedance (RENPHO's common protocol) leaves body fat\n * to Yantra's own estimate; one that computes body fat itself (R-A017) also\n * fills bodyFatPct and bmi.\n */\n impedanceOhm?: number;\n /**\n * The full body composition (muscle, bone, water, BMR, metabolic age ...),\n * computed from weight + body fat + the person's height/age/sex when all are\n * known (bodyComposition.ts). Shown on the reading; the backend day keeps\n * the fields it supports.\n */\n composition?: BodyComposition;\n}\n\nexport interface BloodPressureReading extends ReadingBase {\n kind: 'blood-pressure';\n systolic: number;\n diastolic: number;\n pulse?: number;\n /** What the monitor flagged (moved, loose cuff, irregular pulse), in words. */\n problems?: string[];\n}\n\nexport interface TemperatureReading extends ReadingBase {\n kind: 'temperature';\n celsius: number;\n}\n\nexport interface OxygenReading extends ReadingBase {\n kind: 'spo2';\n spo2: number;\n pulse?: number;\n}\n\nexport interface GlucoseReading extends ReadingBase {\n kind: 'glucose';\n mgdl: number;\n meal?: MealRelation;\n}\n\n/** A heart-rate strap worn for a session: the samples, summed up when it ended. */\nexport interface HeartRateSession extends ReadingBase {\n kind: 'heart-rate';\n /** `at` is the start. */\n end: number;\n /** run | walk | cycle | strength | hiit | other, as the person picked it. */\n workoutType: string;\n avgHr: number;\n maxHr: number;\n /** At most one sample every few seconds (see thinSamples); emptied once saved, see compactSession. */\n samples: TimedValue[];\n /** Minutes per heart-rate zone, kept when the samples are let go. */\n zoneMinutes?: number[];\n}\n\n/**\n * A finished exercise a device recorded itself: a jump-rope session or a\n * treadmill walk/run. Becomes one HealthWorkout in the day (readings with no\n * heart-rate samples, unlike HeartRateSession).\n */\nexport interface WorkoutReading extends ReadingBase {\n kind: 'workout';\n /** `at` is the start. */\n end: number;\n /** jump-rope | run | walk | ... lowercased. */\n workoutType: string;\n durationMin: number;\n calories?: number;\n distanceMeters?: number;\n /** Jump rope only: the number of skips. */\n jumps?: number;\n avgHr?: number;\n maxHr?: number;\n}\n\n/** A tape-measure girth reading of one body part. Only the waist has a home in the day. */\nexport interface BodyMeasurementReading extends ReadingBase {\n kind: 'body-measurement';\n /** waist | chest | hip | left_arm | ... as the tape reported it. */\n bodyPart: string;\n cm: number;\n}\n\nexport type DeviceReading =\n | BodyReading\n | BloodPressureReading\n | TemperatureReading\n | OxygenReading\n | GlucoseReading\n | HeartRateSession\n | WorkoutReading\n | BodyMeasurementReading;\n\nconst round1 = (n: number) => Math.round(n * 10) / 10;\n\n/** A stable id: the same measurement from the same device always gets the same one. */\nexport function readingId(deviceId: string, kind: DeviceReading['kind'], at: number, extra?: string | number): string {\n return [deviceId, kind, Math.round(at / 1000), extra].filter((p) => p !== undefined && p !== '').join(':');\n}\n\n/** Keep one heart-rate sample per `everyMs`: enough for zones, few enough to store and save. */\nexport function thinSamples(samples: readonly TimedValue[], everyMs = 5_000): TimedValue[] {\n const out: TimedValue[] = [];\n let last = -Infinity;\n for (const s of [...samples].sort((a, b) => a.t - b.t)) {\n if (s.t - last >= everyMs) {\n out.push(s);\n last = s.t;\n }\n }\n return out;\n}\n\nconst latestOf = <T extends DeviceReading>(list: readonly T[], has: (r: T) => boolean): T | undefined =>\n list.filter(has).reduce<T | undefined>((a, b) => (!a || b.at >= a.at ? b : a), undefined);\n\nexport interface DeviceDaysOptions {\n clock: ZoneClock;\n syncedAt: string;\n /** 208 - 0.7 x age, for heart-rate zones; undefined when the birth date is unknown. */\n maxHr?: number;\n /** Only these dates (the ones a new reading touched); every date when omitted. */\n dates?: ReadonlySet<string>;\n}\n\n/** Every reading -> one `device` HealthDay per local date, cleaned exactly as the backend cleans. */\nexport function deviceHealthDays(\n readings: readonly DeviceReading[],\n opts: DeviceDaysOptions,\n): { days: HealthDay[]; dropped: string[] } {\n const byDate = new Map<string, DeviceReading[]>();\n for (const r of readings) {\n const date = opts.clock.dateOf(r.at);\n if (opts.dates && !opts.dates.has(date)) continue;\n byDate.set(date, [...(byDate.get(date) ?? []), r]);\n }\n const dropped: string[] = [];\n const days: HealthDay[] = [];\n for (const [date, list] of [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b))) {\n const day: HealthDay = { date, source: 'device' };\n const body = list.filter((r): r is BodyReading => r.kind === 'body');\n const weight = latestOf(body, (r) => r.weightKg !== undefined);\n if (weight) day.weightKg = weight.weightKg;\n const fat = latestOf(body, (r) => r.bodyFatPct !== undefined);\n if (fat) day.bodyFatPct = fat.bodyFatPct;\n const lean = latestOf(body, (r) => r.leanMassKg !== undefined);\n if (lean) day.leanMassKg = lean.leanMassKg;\n const bmi = latestOf(body, (r) => r.bmi !== undefined);\n if (bmi) day.bmi = bmi.bmi;\n const temp = latestOf(\n list.filter((r): r is TemperatureReading => r.kind === 'temperature'),\n () => true,\n );\n if (temp) day.bodyTempC = temp.celsius;\n const spo2 = latestOf(\n list.filter((r): r is OxygenReading => r.kind === 'spo2'),\n () => true,\n );\n if (spo2) day.spo2 = spo2.spo2;\n const waist = latestOf(\n list.filter((r): r is BodyMeasurementReading => r.kind === 'body-measurement' && r.bodyPart === 'waist'),\n () => true,\n );\n if (waist) day.waistCm = waist.cm;\n\n const readingsOut: HealthReading[] = [];\n for (const r of list) {\n if (r.kind === 'blood-pressure') {\n readingsOut.push({\n id: r.id,\n at: new Date(r.at).toISOString(),\n kind: 'blood-pressure',\n systolic: r.systolic,\n diastolic: r.diastolic,\n ...(r.pulse !== undefined ? { pulse: r.pulse } : {}),\n device: r.deviceName,\n });\n } else if (r.kind === 'glucose') {\n readingsOut.push({\n id: r.id,\n at: new Date(r.at).toISOString(),\n kind: 'glucose',\n glucoseMgDl: r.mgdl,\n ...(r.meal ? { meal: r.meal } : {}),\n device: r.deviceName,\n });\n }\n }\n if (readingsOut.length) day.readings = readingsOut.sort((a, b) => a.at.localeCompare(b.at));\n\n const workouts: HealthWorkout[] = list\n .filter((r): r is HeartRateSession => r.kind === 'heart-rate')\n .sort((a, b) => a.at - b.at)\n .map((s) => {\n const w: HealthWorkout = {\n id: s.id,\n start: new Date(s.at).toISOString(),\n end: new Date(s.end).toISOString(),\n type: s.workoutType,\n durationMin: round1((s.end - s.at) / 60_000),\n avgHr: s.avgHr,\n maxHr: s.maxHr,\n };\n if (opts.maxHr && s.samples.length) {\n w.zoneMinutes = zoneMinutes(s.samples, { start: s.at, end: s.end }, opts.maxHr);\n } else if (s.zoneMinutes) w.zoneMinutes = s.zoneMinutes;\n return w;\n });\n // Device-recorded workouts (jump rope, treadmill): same HealthWorkout shape, no HR samples.\n for (const s of list.filter((r): r is WorkoutReading => r.kind === 'workout').sort((a, b) => a.at - b.at)) {\n const w: HealthWorkout = {\n id: s.id,\n start: new Date(s.at).toISOString(),\n end: new Date(s.end).toISOString(),\n type: s.workoutType,\n durationMin: round1(s.durationMin),\n ...(s.calories !== undefined ? { calories: s.calories } : {}),\n ...(s.distanceMeters !== undefined ? { distanceMeters: s.distanceMeters } : {}),\n ...(s.avgHr !== undefined ? { avgHr: s.avgHr } : {}),\n ...(s.maxHr !== undefined ? { maxHr: s.maxHr } : {}),\n };\n workouts.push(w);\n }\n if (workouts.length) day.workouts = workouts.sort((a, b) => a.start.localeCompare(b.start));\n\n const clean = sanitizeDay(day, dropped);\n if (hasData(clean)) days.push({ ...clean, syncedAt: opts.syncedAt });\n }\n return { days, dropped };\n}\n\n/** One line for a reading, as the person reads it (\"82.4 kg, body fat 23.1%\"). */\nexport function describeReading(r: DeviceReading, units: 'metric' | 'imperial' = 'metric'): string {\n const kg = (v: number) => (units === 'imperial' ? `${round1(v / 0.45359237)} lb` : `${round1(v)} kg`);\n switch (r.kind) {\n case 'body': {\n const parts: string[] = [];\n if (r.weightKg !== undefined) parts.push(kg(r.weightKg));\n if (r.bodyFatPct !== undefined) parts.push(`body fat ${round1(r.bodyFatPct)}%`);\n if (r.bmi !== undefined) parts.push(`BMI ${round1(r.bmi)}`);\n return parts.join(', ') || 'A measurement with no weight';\n }\n case 'blood-pressure':\n return `${Math.round(r.systolic)}/${Math.round(r.diastolic)} mmHg${r.pulse ? `, pulse ${Math.round(r.pulse)}` : ''}`;\n case 'temperature':\n return units === 'imperial' ? `${round1((r.celsius * 9) / 5 + 32)} °F` : `${round1(r.celsius)} °C`;\n case 'spo2':\n return `Blood oxygen ${Math.round(r.spo2)}%${r.pulse ? `, pulse ${Math.round(r.pulse)}` : ''}`;\n case 'glucose':\n return `${Math.round(r.mgdl)} mg/dL${r.meal ? `, ${r.meal.replace('-', ' ')}` : ''}`;\n case 'heart-rate': {\n const minutes = Math.round((r.end - r.at) / 60_000);\n return `${minutes} min, average ${Math.round(r.avgHr)} bpm, max ${Math.round(r.maxHr)}`;\n }\n case 'workout': {\n const parts: string[] = [`${Math.round(r.durationMin)} min`];\n if (r.jumps !== undefined) parts.unshift(`${r.jumps} jumps`);\n if (r.distanceMeters !== undefined) parts.push(`${round1(r.distanceMeters / 1000)} km`);\n if (r.calories !== undefined) parts.push(`${Math.round(r.calories)} kcal`);\n return parts.join(', ');\n }\n case 'body-measurement': {\n const part = r.bodyPart.replace(/_/g, ' ');\n return units === 'imperial' ? `${part} ${round1(r.cm / 2.54)} in` : `${part} ${round1(r.cm)} cm`;\n }\n default:\n return '';\n }\n}\n\n/**\n * A session's samples are only needed until they are uploaded and saved to\n * the health store; after that the zones are kept and the samples let go, so\n * the phone's store stays small.\n */\nexport function compactSession(s: HeartRateSession, maxHr: number | undefined): HeartRateSession {\n if (!s.samples.length) return s;\n const zones = maxHr ? zoneMinutes(s.samples, { start: s.at, end: s.end }, maxHr) : s.zoneMinutes;\n return { ...s, samples: [], ...(zones ? { zoneMinutes: zones } : {}) };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"readings.js","sources":["../../../src/features/devices/readings.ts"],"sourcesContent":["/**\n * What a paired Bluetooth device measured, and how it reaches the Fitness\n * backend.\n *\n * The backend keeps ONE day per source and replaces it whole on every upload,\n * so a reading is never sent alone: the app keeps every reading it took (the\n * device store), and each upload rebuilds the full `device` day for the dates\n * that changed. A blood-pressure reading in the evening never wipes the\n * morning's weigh-in.\n *\n * Reading ids are stable (device + what + when): a monitor that sends its\n * whole memory on every connection, or the same reading arriving twice, is\n * stored once.\n */\n\nimport { sanitizeDay, hasData } from '../health/buildDays';\nimport type { TimedValue } from '../health/model';\nimport type { HealthDay, HealthReading, HealthWorkout, MealRelation } from '../health/types';\nimport type { ZoneClock } from '../health/time';\nimport { zoneMinutes } from '../health/zones';\n\ninterface ReadingBase {\n id: string;\n /** Epoch ms of the measurement. */\n at: number;\n deviceId: string;\n deviceName: string;\n}\n\nexport interface BodyReading extends ReadingBase {\n kind: 'body';\n weightKg?: number;\n bodyFatPct?: number;\n leanMassKg?: number;\n bmi?: number;\n /**\n * Whole-body impedance in ohms, when the scale sends it. A scale that only\n * reports weight and impedance (RENPHO's common protocol) leaves body fat\n * to Yantra's own estimate; one that computes body fat itself (R-A017) also\n * fills bodyFatPct and bmi.\n */\n impedanceOhm?: number;\n}\n\nexport interface BloodPressureReading extends ReadingBase {\n kind: 'blood-pressure';\n systolic: number;\n diastolic: number;\n pulse?: number;\n /** What the monitor flagged (moved, loose cuff, irregular pulse), in words. */\n problems?: string[];\n}\n\nexport interface TemperatureReading extends ReadingBase {\n kind: 'temperature';\n celsius: number;\n}\n\nexport interface OxygenReading extends ReadingBase {\n kind: 'spo2';\n spo2: number;\n pulse?: number;\n}\n\nexport interface GlucoseReading extends ReadingBase {\n kind: 'glucose';\n mgdl: number;\n meal?: MealRelation;\n}\n\n/** A heart-rate strap worn for a session: the samples, summed up when it ended. */\nexport interface HeartRateSession extends ReadingBase {\n kind: 'heart-rate';\n /** `at` is the start. */\n end: number;\n /** run | walk | cycle | strength | hiit | other, as the person picked it. */\n workoutType: string;\n avgHr: number;\n maxHr: number;\n /** At most one sample every few seconds (see thinSamples); emptied once saved, see compactSession. */\n samples: TimedValue[];\n /** Minutes per heart-rate zone, kept when the samples are let go. */\n zoneMinutes?: number[];\n}\n\n/**\n * A finished exercise a device recorded itself: a jump-rope session or a\n * treadmill walk/run. Becomes one HealthWorkout in the day (readings with no\n * heart-rate samples, unlike HeartRateSession).\n */\nexport interface WorkoutReading extends ReadingBase {\n kind: 'workout';\n /** `at` is the start. */\n end: number;\n /** jump-rope | run | walk | ... lowercased. */\n workoutType: string;\n durationMin: number;\n calories?: number;\n distanceMeters?: number;\n /** Jump rope only: the number of skips. */\n jumps?: number;\n avgHr?: number;\n maxHr?: number;\n}\n\n/** A tape-measure girth reading of one body part. Only the waist has a home in the day. */\nexport interface BodyMeasurementReading extends ReadingBase {\n kind: 'body-measurement';\n /** waist | chest | hip | left_arm | ... as the tape reported it. */\n bodyPart: string;\n cm: number;\n}\n\nexport type DeviceReading =\n | BodyReading\n | BloodPressureReading\n | TemperatureReading\n | OxygenReading\n | GlucoseReading\n | HeartRateSession\n | WorkoutReading\n | BodyMeasurementReading;\n\nconst round1 = (n: number) => Math.round(n * 10) / 10;\n\n/** A stable id: the same measurement from the same device always gets the same one. */\nexport function readingId(deviceId: string, kind: DeviceReading['kind'], at: number, extra?: string | number): string {\n return [deviceId, kind, Math.round(at / 1000), extra].filter((p) => p !== undefined && p !== '').join(':');\n}\n\n/** Keep one heart-rate sample per `everyMs`: enough for zones, few enough to store and save. */\nexport function thinSamples(samples: readonly TimedValue[], everyMs = 5_000): TimedValue[] {\n const out: TimedValue[] = [];\n let last = -Infinity;\n for (const s of [...samples].sort((a, b) => a.t - b.t)) {\n if (s.t - last >= everyMs) {\n out.push(s);\n last = s.t;\n }\n }\n return out;\n}\n\nconst latestOf = <T extends DeviceReading>(list: readonly T[], has: (r: T) => boolean): T | undefined =>\n list.filter(has).reduce<T | undefined>((a, b) => (!a || b.at >= a.at ? b : a), undefined);\n\nexport interface DeviceDaysOptions {\n clock: ZoneClock;\n syncedAt: string;\n /** 208 - 0.7 x age, for heart-rate zones; undefined when the birth date is unknown. */\n maxHr?: number;\n /** Only these dates (the ones a new reading touched); every date when omitted. */\n dates?: ReadonlySet<string>;\n}\n\n/** Every reading -> one `device` HealthDay per local date, cleaned exactly as the backend cleans. */\nexport function deviceHealthDays(\n readings: readonly DeviceReading[],\n opts: DeviceDaysOptions,\n): { days: HealthDay[]; dropped: string[] } {\n const byDate = new Map<string, DeviceReading[]>();\n for (const r of readings) {\n const date = opts.clock.dateOf(r.at);\n if (opts.dates && !opts.dates.has(date)) continue;\n byDate.set(date, [...(byDate.get(date) ?? []), r]);\n }\n const dropped: string[] = [];\n const days: HealthDay[] = [];\n for (const [date, list] of [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b))) {\n const day: HealthDay = { date, source: 'device' };\n const body = list.filter((r): r is BodyReading => r.kind === 'body');\n const weight = latestOf(body, (r) => r.weightKg !== undefined);\n if (weight) day.weightKg = weight.weightKg;\n const fat = latestOf(body, (r) => r.bodyFatPct !== undefined);\n if (fat) day.bodyFatPct = fat.bodyFatPct;\n const lean = latestOf(body, (r) => r.leanMassKg !== undefined);\n if (lean) day.leanMassKg = lean.leanMassKg;\n const bmi = latestOf(body, (r) => r.bmi !== undefined);\n if (bmi) day.bmi = bmi.bmi;\n const temp = latestOf(\n list.filter((r): r is TemperatureReading => r.kind === 'temperature'),\n () => true,\n );\n if (temp) day.bodyTempC = temp.celsius;\n const spo2 = latestOf(\n list.filter((r): r is OxygenReading => r.kind === 'spo2'),\n () => true,\n );\n if (spo2) day.spo2 = spo2.spo2;\n const waist = latestOf(\n list.filter((r): r is BodyMeasurementReading => r.kind === 'body-measurement' && r.bodyPart === 'waist'),\n () => true,\n );\n if (waist) day.waistCm = waist.cm;\n\n const readingsOut: HealthReading[] = [];\n for (const r of list) {\n if (r.kind === 'blood-pressure') {\n readingsOut.push({\n id: r.id,\n at: new Date(r.at).toISOString(),\n kind: 'blood-pressure',\n systolic: r.systolic,\n diastolic: r.diastolic,\n ...(r.pulse !== undefined ? { pulse: r.pulse } : {}),\n device: r.deviceName,\n });\n } else if (r.kind === 'glucose') {\n readingsOut.push({\n id: r.id,\n at: new Date(r.at).toISOString(),\n kind: 'glucose',\n glucoseMgDl: r.mgdl,\n ...(r.meal ? { meal: r.meal } : {}),\n device: r.deviceName,\n });\n }\n }\n if (readingsOut.length) day.readings = readingsOut.sort((a, b) => a.at.localeCompare(b.at));\n\n const workouts: HealthWorkout[] = list\n .filter((r): r is HeartRateSession => r.kind === 'heart-rate')\n .sort((a, b) => a.at - b.at)\n .map((s) => {\n const w: HealthWorkout = {\n id: s.id,\n start: new Date(s.at).toISOString(),\n end: new Date(s.end).toISOString(),\n type: s.workoutType,\n durationMin: round1((s.end - s.at) / 60_000),\n avgHr: s.avgHr,\n maxHr: s.maxHr,\n };\n if (opts.maxHr && s.samples.length) {\n w.zoneMinutes = zoneMinutes(s.samples, { start: s.at, end: s.end }, opts.maxHr);\n } else if (s.zoneMinutes) w.zoneMinutes = s.zoneMinutes;\n return w;\n });\n // Device-recorded workouts (jump rope, treadmill): same HealthWorkout shape, no HR samples.\n for (const s of list.filter((r): r is WorkoutReading => r.kind === 'workout').sort((a, b) => a.at - b.at)) {\n const w: HealthWorkout = {\n id: s.id,\n start: new Date(s.at).toISOString(),\n end: new Date(s.end).toISOString(),\n type: s.workoutType,\n durationMin: round1(s.durationMin),\n ...(s.calories !== undefined ? { calories: s.calories } : {}),\n ...(s.distanceMeters !== undefined ? { distanceMeters: s.distanceMeters } : {}),\n ...(s.avgHr !== undefined ? { avgHr: s.avgHr } : {}),\n ...(s.maxHr !== undefined ? { maxHr: s.maxHr } : {}),\n };\n workouts.push(w);\n }\n if (workouts.length) day.workouts = workouts.sort((a, b) => a.start.localeCompare(b.start));\n\n const clean = sanitizeDay(day, dropped);\n if (hasData(clean)) days.push({ ...clean, syncedAt: opts.syncedAt });\n }\n return { days, dropped };\n}\n\n/** One line for a reading, as the person reads it (\"82.4 kg, body fat 23.1%\"). */\nexport function describeReading(r: DeviceReading, units: 'metric' | 'imperial' = 'metric'): string {\n const kg = (v: number) => (units === 'imperial' ? `${round1(v / 0.45359237)} lb` : `${round1(v)} kg`);\n switch (r.kind) {\n case 'body': {\n const parts: string[] = [];\n if (r.weightKg !== undefined) parts.push(kg(r.weightKg));\n if (r.bodyFatPct !== undefined) parts.push(`body fat ${round1(r.bodyFatPct)}%`);\n if (r.bmi !== undefined) parts.push(`BMI ${round1(r.bmi)}`);\n return parts.join(', ') || 'A measurement with no weight';\n }\n case 'blood-pressure':\n return `${Math.round(r.systolic)}/${Math.round(r.diastolic)} mmHg${r.pulse ? `, pulse ${Math.round(r.pulse)}` : ''}`;\n case 'temperature':\n return units === 'imperial' ? `${round1((r.celsius * 9) / 5 + 32)} °F` : `${round1(r.celsius)} °C`;\n case 'spo2':\n return `Blood oxygen ${Math.round(r.spo2)}%${r.pulse ? `, pulse ${Math.round(r.pulse)}` : ''}`;\n case 'glucose':\n return `${Math.round(r.mgdl)} mg/dL${r.meal ? `, ${r.meal.replace('-', ' ')}` : ''}`;\n case 'heart-rate': {\n const minutes = Math.round((r.end - r.at) / 60_000);\n return `${minutes} min, average ${Math.round(r.avgHr)} bpm, max ${Math.round(r.maxHr)}`;\n }\n case 'workout': {\n const parts: string[] = [`${Math.round(r.durationMin)} min`];\n if (r.jumps !== undefined) parts.unshift(`${r.jumps} jumps`);\n if (r.distanceMeters !== undefined) parts.push(`${round1(r.distanceMeters / 1000)} km`);\n if (r.calories !== undefined) parts.push(`${Math.round(r.calories)} kcal`);\n return parts.join(', ');\n }\n case 'body-measurement': {\n const part = r.bodyPart.replace(/_/g, ' ');\n return units === 'imperial' ? `${part} ${round1(r.cm / 2.54)} in` : `${part} ${round1(r.cm)} cm`;\n }\n default:\n return '';\n }\n}\n\n/**\n * A session's samples are only needed until they are uploaded and saved to\n * the health store; after that the zones are kept and the samples let go, so\n * the phone's store stays small.\n */\nexport function compactSession(s: HeartRateSession, maxHr: number | undefined): HeartRateSession {\n if (!s.samples.length) return s;\n const zones = maxHr ? zoneMinutes(s.samples, { start: s.at, end: s.end }, maxHr) : s.zoneMinutes;\n return { ...s, samples: [], ...(zones ? { zoneMinutes: zones } : {}) };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {deviceKind}from'./catalog.js';import {describeBleError}from'./link.js';import {thinSamples,readingId}from'./readings.js';import'./brands/frames.js';import'./brands/uuids.js';import'./gatt/uuids.js';import {detectBrand}from'./brands/detect.js';import {startDriver}from'./drivers.js';
|
|
1
|
+
import {deviceKind}from'./catalog.js';import {describeBleError}from'./link.js';import {thinSamples,readingId}from'./readings.js';import'./brands/frames.js';import'./brands/uuids.js';import'./gatt/uuids.js';import {detectBrand}from'./brands/detect.js';import {startDriver}from'./drivers.js';var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -24,26 +24,6 @@ function ageFrom(birthDate, now) {
|
|
|
24
24
|
const t = Date.parse(`${birthDate}T00:00:00Z`);
|
|
25
25
|
return Number.isFinite(t) ? Math.floor((now - t) / (365.25 * 864e5)) : void 0;
|
|
26
26
|
}
|
|
27
|
-
function enrichWithComposition(reading, facts) {
|
|
28
|
-
var _a, _b, _c;
|
|
29
|
-
if (reading.kind !== "body" || reading.weightKg === void 0 || reading.bodyFatPct === void 0) {
|
|
30
|
-
return reading;
|
|
31
|
-
}
|
|
32
|
-
if (!facts.heightCm || facts.age === void 0) return reading;
|
|
33
|
-
const composition = computeBodyComposition({
|
|
34
|
-
weightKg: reading.weightKg,
|
|
35
|
-
bodyFatPct: reading.bodyFatPct,
|
|
36
|
-
heightCm: facts.heightCm,
|
|
37
|
-
age: facts.age,
|
|
38
|
-
sex: (_a = facts.sex) != null ? _a : "unspecified",
|
|
39
|
-
impedanceOhm: reading.impedanceOhm
|
|
40
|
-
});
|
|
41
|
-
return __spreadProps(__spreadValues({}, reading), {
|
|
42
|
-
bmi: (_b = reading.bmi) != null ? _b : composition.bmi,
|
|
43
|
-
leanMassKg: (_c = reading.leanMassKg) != null ? _c : composition.leanMassKg,
|
|
44
|
-
composition
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
27
|
class DeviceSession {
|
|
48
28
|
constructor(deps) {
|
|
49
29
|
this.deps = deps;
|
|
@@ -207,7 +187,7 @@ class DeviceSession {
|
|
|
207
187
|
} : void 0,
|
|
208
188
|
scaleUser: paired == null ? void 0 : paired.scaleUser,
|
|
209
189
|
saveScaleUser: (user) => store.saveScaleUser(link.id, user),
|
|
210
|
-
onReading: (r) => void this.keep([
|
|
190
|
+
onReading: (r) => void this.keep([r]),
|
|
211
191
|
onLive: (v) => this.onLive(v),
|
|
212
192
|
onNotice: (m) => this.set({
|
|
213
193
|
notices: [...this.snapshot.notices, m]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sources":["../../../src/features/devices/session.ts"],"sourcesContent":["/**\n * One \"take a reading\" from start to end, for the screen: is Bluetooth on and\n * allowed, find the device (or the one already paired), connect, run its\n * driver, keep what it measures, and end cleanly when it goes to sleep (a\n * scale switches off seconds after a weighing; that is the normal end, not an\n * error).\n *\n * Heart-rate straps and continuous oximeters stream: the person starts and\n * stops a session (heart rate) or saves the value they see (oxygen).\n *\n * Plain class with injected transport and store, like the other stores: the\n * screen subscribes with useSyncExternalStore, tests drive it with fakes.\n */\nimport type { TimedValue } from '../health/model';\nimport { deviceKind, type DeviceKindId } from './catalog';\nimport { describeBleError, type BleTransport, type ConnectedLink, type FoundDevice, type RadioState } from './link';\nimport { detectBrand } from './brands';\nimport type { DeviceStore } from './deviceStore';\nimport { startDriver, type DriverHandle, type LiveValue, type PersonFacts } from './drivers';\nimport { computeBodyComposition } from './bodyComposition';\nimport { readingId, thinSamples, type DeviceReading, type HeartRateSession } from './readings';\n\nexport type SessionState =\n | { step: 'starting' }\n | { step: 'unavailable'; reason: string }\n | { step: 'radio'; radio: Exclude<RadioState, 'ready'> }\n | { step: 'scanning'; found: FoundDevice[]; hint?: string }\n | { step: 'connecting'; device: FoundDevice }\n | { step: 'connected'; device: { id: string; name: string } }\n | { step: 'ended'; device: { id: string; name: string } }\n | { step: 'error'; message: string };\n\nexport interface SessionSnapshot {\n state: SessionState;\n kind: DeviceKindId;\n /** What this session measured, newest first. */\n readings: DeviceReading[];\n live?: LiveValue;\n recording?: { startedAt: number; workoutType: string; avgHr?: number; maxHr?: number };\n notices: string[];\n}\n\nexport interface SessionDeps {\n transport: BleTransport | null;\n store: Pick<DeviceStore, 'pair' | 'addReadings' | 'saveScaleUser' | 'person' | 'getSnapshot'>;\n kind: DeviceKindId;\n /** Reconnect to this paired device instead of offering a list. */\n deviceId?: string;\n now?: () => number;\n}\n\n/** Scanning this long without finding anything: tell the person how to wake it. */\nexport const SCAN_HINT_MS = 20_000;\n\nfunction ageFrom(birthDate: string | undefined, now: number): number | undefined {\n if (!birthDate) return undefined;\n const t = Date.parse(`${birthDate}T00:00:00Z`);\n return Number.isFinite(t) ? Math.floor((now - t) / (365.25 * 86_400_000)) : undefined;\n}\n\n/**\n * Fill in the full body composition for a body reading once the scale has given\n * weight and body fat and the person's height/age/sex are known. Other readings\n * pass through unchanged.\n */\nfunction enrichWithComposition(reading: DeviceReading, facts: PersonFacts): DeviceReading {\n if (reading.kind !== 'body' || reading.weightKg === undefined || reading.bodyFatPct === undefined) {\n return reading;\n }\n if (!facts.heightCm || facts.age === undefined) return reading;\n const composition = computeBodyComposition({\n weightKg: reading.weightKg,\n bodyFatPct: reading.bodyFatPct,\n heightCm: facts.heightCm,\n age: facts.age,\n sex: facts.sex ?? 'unspecified',\n impedanceOhm: reading.impedanceOhm,\n });\n return {\n ...reading,\n bmi: reading.bmi ?? composition.bmi,\n leanMassKg: reading.leanMassKg ?? composition.leanMassKg,\n composition,\n };\n}\n\nexport class DeviceSession {\n private snapshot: SessionSnapshot;\n\n private listeners = new Set<() => void>();\n\n private stopScan: (() => void) | null = null;\n\n private link: ConnectedLink | null = null;\n\n private driver: DriverHandle | null = null;\n\n private hintTimer: ReturnType<typeof setTimeout> | null = null;\n\n private hr: { samples: TimedValue[]; sum: number; count: number; max: number } | null = null;\n\n private closed = false;\n\n constructor(private readonly deps: SessionDeps) {\n this.snapshot = { state: { step: 'starting' }, kind: deps.kind, readings: [], notices: [] };\n }\n\n subscribe = (listener: () => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n getSnapshot = (): SessionSnapshot => this.snapshot;\n\n private now(): number {\n return this.deps.now ? this.deps.now() : Date.now();\n }\n\n private set(patch: Partial<SessionSnapshot>) {\n if (this.closed) return;\n this.snapshot = { ...this.snapshot, ...patch };\n this.listeners.forEach((l) => l());\n }\n\n async start(): Promise<void> {\n const { transport } = this.deps;\n if (!transport) {\n this.set({\n state: { step: 'unavailable', reason: 'Bluetooth devices need the latest version of the Yantra app.' },\n });\n return;\n }\n if (!(await transport.requestPermissions())) {\n this.set({ state: { step: 'radio', radio: 'unauthorized' } });\n return;\n }\n const radio = await transport.radio();\n if (radio !== 'ready' && radio !== 'unknown') {\n this.set({ state: { step: 'radio', radio } });\n return;\n }\n this.scan();\n }\n\n /** Back to looking for the device (after the radio came on, or to measure again). */\n scan(): void {\n const { transport } = this.deps;\n if (!transport || this.closed) return;\n this.stopScan?.();\n this.set({ state: { step: 'scanning', found: [] } });\n this.hintTimer = setTimeout(() => {\n const s = this.snapshot.state;\n if (s.step === 'scanning' && !s.found.length) {\n this.set({ state: { ...s, hint: deviceKind(this.deps.kind).steps[0] } });\n }\n }, SCAN_HINT_MS);\n const kind = this.deps.kind;\n this.stopScan = transport.scan(\n {\n services: deviceKind(kind).services,\n // Brand devices do not advertise a standard service: recognise this kind of them.\n match: (adv) => {\n const brand = detectBrand(adv);\n return brand && brand.kind === kind ? brand : undefined;\n },\n },\n (found) => {\n const s = this.snapshot.state;\n if (s.step !== 'scanning') return;\n if (this.deps.deviceId && found.id === this.deps.deviceId) {\n void this.pick(found);\n return;\n }\n if (this.deps.deviceId) return;\n this.set({\n state: {\n ...s,\n hint: undefined,\n found: [...s.found, found].sort((a, b) => (b.rssi ?? -999) - (a.rssi ?? -999)),\n },\n });\n },\n (message) => this.set({ state: { step: 'error', message } }),\n );\n }\n\n async pick(found: FoundDevice): Promise<void> {\n const { transport, store } = this.deps;\n if (!transport) return;\n this.clearScan();\n this.set({ state: { step: 'connecting', device: found } });\n try {\n const link = await transport.connect(found.id, found.name, () => this.onDisconnect());\n this.link = link;\n const paired = store.getSnapshot().devices.find((d) => d.id === link.id);\n const person = await store.person();\n const facts: PersonFacts = {\n age: ageFrom(person?.birthDate, this.now()),\n sex: person?.sex,\n heightCm: person?.heightCm,\n birthDate: person?.birthDate,\n weightKg: paired?.lastWeightKg,\n };\n this.driver = await startDriver(this.deps.kind, link, {\n now: () => this.now(),\n person: facts,\n identity: found.protocol\n ? {\n protocol: found.protocol,\n mac: found.mac,\n deviceType: found.deviceType,\n model: found.model,\n kind: found.kind,\n }\n : undefined,\n scaleUser: paired?.scaleUser,\n saveScaleUser: (user) => store.saveScaleUser(link.id, user),\n onReading: (r) => void this.keep([enrichWithComposition(r, facts)]),\n onLive: (v) => this.onLive(v),\n onNotice: (m) => this.set({ notices: [...this.snapshot.notices, m] }),\n });\n await store.pair({\n id: link.id,\n name: link.name,\n kind: this.deps.kind,\n ...(found.protocol ? { protocol: found.protocol } : {}),\n });\n this.set({ state: { step: 'connected', device: { id: link.id, name: link.name } } });\n } catch (err) {\n await this.link?.close();\n this.link = null;\n this.set({ state: { step: 'error', message: describeErrorOrOwn(err) } });\n }\n }\n\n private async keep(readings: DeviceReading[]): Promise<void> {\n const fresh = await this.deps.store.addReadings(readings);\n if (fresh.length) this.set({ readings: [...fresh.reverse(), ...this.snapshot.readings] });\n }\n\n private onLive(v: LiveValue) {\n this.set({ live: { ...this.snapshot.live, ...v } });\n if (this.hr && v.bpm) {\n const t = this.now();\n this.hr.samples.push({ t, value: v.bpm });\n this.hr.sum += v.bpm;\n this.hr.count += 1;\n this.hr.max = Math.max(this.hr.max, v.bpm);\n const rec = this.snapshot.recording;\n if (rec)\n this.set({ recording: { ...rec, avgHr: Math.round(this.hr.sum / this.hr.count), maxHr: this.hr.max } });\n }\n }\n\n /** Heart rate: start recording a session of the given kind (run, walk, cycle, strength ...). */\n startRecording(workoutType: string): void {\n this.hr = { samples: [], sum: 0, count: 0, max: 0 };\n this.set({ recording: { startedAt: this.now(), workoutType } });\n }\n\n /** Heart rate: end the session and keep it. Nothing is kept for a session with no heart rate. */\n async stopRecording(): Promise<HeartRateSession | null> {\n const rec = this.snapshot.recording;\n const hr = this.hr;\n this.hr = null;\n this.set({ recording: undefined });\n const device = this.link;\n if (!rec || !hr || !hr.count || !device) return null;\n const end = this.now();\n const session: HeartRateSession = {\n kind: 'heart-rate',\n id: readingId(device.id, 'heart-rate', rec.startedAt),\n at: rec.startedAt,\n end,\n deviceId: device.id,\n deviceName: device.name,\n workoutType: rec.workoutType,\n avgHr: Math.round(hr.sum / hr.count),\n maxHr: hr.max,\n samples: thinSamples(hr.samples),\n };\n await this.keep([session]);\n return session;\n }\n\n /** Continuous oximeter: keep the value on screen as a reading. */\n async saveLive(): Promise<void> {\n const live = this.snapshot.live;\n const device = this.link;\n if (!device || live?.spo2 === undefined) return;\n const at = this.now();\n await this.keep([\n {\n kind: 'spo2',\n id: readingId(device.id, 'spo2', at, live.spo2),\n at,\n deviceId: device.id,\n deviceName: device.name,\n spo2: live.spo2,\n ...(live.pulse !== undefined ? { pulse: live.pulse } : {}),\n },\n ]);\n }\n\n private onDisconnect() {\n this.driver?.stop();\n this.driver = null;\n const link = this.link;\n this.link = null;\n if (this.hr) void this.stopRecording();\n const s = this.snapshot.state;\n if (s.step === 'connected' && link) {\n // A scale or cuff switches off after measuring: the normal end.\n this.set({ state: { step: 'ended', device: { id: link.id, name: link.name } }, live: undefined });\n }\n }\n\n private clearScan() {\n this.stopScan?.();\n this.stopScan = null;\n if (this.hintTimer) clearTimeout(this.hintTimer);\n this.hintTimer = null;\n }\n\n /** Leave: finish what was being assembled, stop scanning, disconnect. */\n async close(): Promise<void> {\n if (this.hr) await this.stopRecording();\n this.clearScan();\n this.driver?.stop();\n this.driver = null;\n const link = this.link;\n this.link = null;\n this.closed = true;\n await link?.close();\n }\n}\n\nfunction describeErrorOrOwn(err: unknown): string {\n // The drivers' own messages are already in plain words (\"does not send weight the standard way\").\n if (err instanceof Error && /standard way|does not know how/.test(err.message)) return err.message;\n return describeBleError(err);\n}\n"],"names":["_a"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session.js","sources":["../../../src/features/devices/session.ts"],"sourcesContent":["/**\n * One \"take a reading\" from start to end, for the screen: is Bluetooth on and\n * allowed, find the device (or the one already paired), connect, run its\n * driver, keep what it measures, and end cleanly when it goes to sleep (a\n * scale switches off seconds after a weighing; that is the normal end, not an\n * error).\n *\n * Heart-rate straps and continuous oximeters stream: the person starts and\n * stops a session (heart rate) or saves the value they see (oxygen).\n *\n * Plain class with injected transport and store, like the other stores: the\n * screen subscribes with useSyncExternalStore, tests drive it with fakes.\n */\nimport type { TimedValue } from '../health/model';\nimport { deviceKind, type DeviceKindId } from './catalog';\nimport { describeBleError, type BleTransport, type ConnectedLink, type FoundDevice, type RadioState } from './link';\nimport { detectBrand } from './brands';\nimport type { DeviceStore } from './deviceStore';\nimport { startDriver, type DriverHandle, type LiveValue, type PersonFacts } from './drivers';\nimport { readingId, thinSamples, type DeviceReading, type HeartRateSession } from './readings';\n\nexport type SessionState =\n | { step: 'starting' }\n | { step: 'unavailable'; reason: string }\n | { step: 'radio'; radio: Exclude<RadioState, 'ready'> }\n | { step: 'scanning'; found: FoundDevice[]; hint?: string }\n | { step: 'connecting'; device: FoundDevice }\n | { step: 'connected'; device: { id: string; name: string } }\n | { step: 'ended'; device: { id: string; name: string } }\n | { step: 'error'; message: string };\n\nexport interface SessionSnapshot {\n state: SessionState;\n kind: DeviceKindId;\n /** What this session measured, newest first. */\n readings: DeviceReading[];\n live?: LiveValue;\n recording?: { startedAt: number; workoutType: string; avgHr?: number; maxHr?: number };\n notices: string[];\n}\n\nexport interface SessionDeps {\n transport: BleTransport | null;\n store: Pick<DeviceStore, 'pair' | 'addReadings' | 'saveScaleUser' | 'person' | 'getSnapshot'>;\n kind: DeviceKindId;\n /** Reconnect to this paired device instead of offering a list. */\n deviceId?: string;\n now?: () => number;\n}\n\n/** Scanning this long without finding anything: tell the person how to wake it. */\nexport const SCAN_HINT_MS = 20_000;\n\nfunction ageFrom(birthDate: string | undefined, now: number): number | undefined {\n if (!birthDate) return undefined;\n const t = Date.parse(`${birthDate}T00:00:00Z`);\n return Number.isFinite(t) ? Math.floor((now - t) / (365.25 * 86_400_000)) : undefined;\n}\n\nexport class DeviceSession {\n private snapshot: SessionSnapshot;\n\n private listeners = new Set<() => void>();\n\n private stopScan: (() => void) | null = null;\n\n private link: ConnectedLink | null = null;\n\n private driver: DriverHandle | null = null;\n\n private hintTimer: ReturnType<typeof setTimeout> | null = null;\n\n private hr: { samples: TimedValue[]; sum: number; count: number; max: number } | null = null;\n\n private closed = false;\n\n constructor(private readonly deps: SessionDeps) {\n this.snapshot = { state: { step: 'starting' }, kind: deps.kind, readings: [], notices: [] };\n }\n\n subscribe = (listener: () => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n getSnapshot = (): SessionSnapshot => this.snapshot;\n\n private now(): number {\n return this.deps.now ? this.deps.now() : Date.now();\n }\n\n private set(patch: Partial<SessionSnapshot>) {\n if (this.closed) return;\n this.snapshot = { ...this.snapshot, ...patch };\n this.listeners.forEach((l) => l());\n }\n\n async start(): Promise<void> {\n const { transport } = this.deps;\n if (!transport) {\n this.set({\n state: { step: 'unavailable', reason: 'Bluetooth devices need the latest version of the Yantra app.' },\n });\n return;\n }\n if (!(await transport.requestPermissions())) {\n this.set({ state: { step: 'radio', radio: 'unauthorized' } });\n return;\n }\n const radio = await transport.radio();\n if (radio !== 'ready' && radio !== 'unknown') {\n this.set({ state: { step: 'radio', radio } });\n return;\n }\n this.scan();\n }\n\n /** Back to looking for the device (after the radio came on, or to measure again). */\n scan(): void {\n const { transport } = this.deps;\n if (!transport || this.closed) return;\n this.stopScan?.();\n this.set({ state: { step: 'scanning', found: [] } });\n this.hintTimer = setTimeout(() => {\n const s = this.snapshot.state;\n if (s.step === 'scanning' && !s.found.length) {\n this.set({ state: { ...s, hint: deviceKind(this.deps.kind).steps[0] } });\n }\n }, SCAN_HINT_MS);\n const kind = this.deps.kind;\n this.stopScan = transport.scan(\n {\n services: deviceKind(kind).services,\n // Brand devices do not advertise a standard service: recognise this kind of them.\n match: (adv) => {\n const brand = detectBrand(adv);\n return brand && brand.kind === kind ? brand : undefined;\n },\n },\n (found) => {\n const s = this.snapshot.state;\n if (s.step !== 'scanning') return;\n if (this.deps.deviceId && found.id === this.deps.deviceId) {\n void this.pick(found);\n return;\n }\n if (this.deps.deviceId) return;\n this.set({\n state: {\n ...s,\n hint: undefined,\n found: [...s.found, found].sort((a, b) => (b.rssi ?? -999) - (a.rssi ?? -999)),\n },\n });\n },\n (message) => this.set({ state: { step: 'error', message } }),\n );\n }\n\n async pick(found: FoundDevice): Promise<void> {\n const { transport, store } = this.deps;\n if (!transport) return;\n this.clearScan();\n this.set({ state: { step: 'connecting', device: found } });\n try {\n const link = await transport.connect(found.id, found.name, () => this.onDisconnect());\n this.link = link;\n const paired = store.getSnapshot().devices.find((d) => d.id === link.id);\n const person = await store.person();\n const facts: PersonFacts = {\n age: ageFrom(person?.birthDate, this.now()),\n sex: person?.sex,\n heightCm: person?.heightCm,\n birthDate: person?.birthDate,\n weightKg: paired?.lastWeightKg,\n };\n this.driver = await startDriver(this.deps.kind, link, {\n now: () => this.now(),\n person: facts,\n identity: found.protocol\n ? {\n protocol: found.protocol,\n mac: found.mac,\n deviceType: found.deviceType,\n model: found.model,\n kind: found.kind,\n }\n : undefined,\n scaleUser: paired?.scaleUser,\n saveScaleUser: (user) => store.saveScaleUser(link.id, user),\n onReading: (r) => void this.keep([r]),\n onLive: (v) => this.onLive(v),\n onNotice: (m) => this.set({ notices: [...this.snapshot.notices, m] }),\n });\n await store.pair({\n id: link.id,\n name: link.name,\n kind: this.deps.kind,\n ...(found.protocol ? { protocol: found.protocol } : {}),\n });\n this.set({ state: { step: 'connected', device: { id: link.id, name: link.name } } });\n } catch (err) {\n await this.link?.close();\n this.link = null;\n this.set({ state: { step: 'error', message: describeErrorOrOwn(err) } });\n }\n }\n\n private async keep(readings: DeviceReading[]): Promise<void> {\n const fresh = await this.deps.store.addReadings(readings);\n if (fresh.length) this.set({ readings: [...fresh.reverse(), ...this.snapshot.readings] });\n }\n\n private onLive(v: LiveValue) {\n this.set({ live: { ...this.snapshot.live, ...v } });\n if (this.hr && v.bpm) {\n const t = this.now();\n this.hr.samples.push({ t, value: v.bpm });\n this.hr.sum += v.bpm;\n this.hr.count += 1;\n this.hr.max = Math.max(this.hr.max, v.bpm);\n const rec = this.snapshot.recording;\n if (rec)\n this.set({ recording: { ...rec, avgHr: Math.round(this.hr.sum / this.hr.count), maxHr: this.hr.max } });\n }\n }\n\n /** Heart rate: start recording a session of the given kind (run, walk, cycle, strength ...). */\n startRecording(workoutType: string): void {\n this.hr = { samples: [], sum: 0, count: 0, max: 0 };\n this.set({ recording: { startedAt: this.now(), workoutType } });\n }\n\n /** Heart rate: end the session and keep it. Nothing is kept for a session with no heart rate. */\n async stopRecording(): Promise<HeartRateSession | null> {\n const rec = this.snapshot.recording;\n const hr = this.hr;\n this.hr = null;\n this.set({ recording: undefined });\n const device = this.link;\n if (!rec || !hr || !hr.count || !device) return null;\n const end = this.now();\n const session: HeartRateSession = {\n kind: 'heart-rate',\n id: readingId(device.id, 'heart-rate', rec.startedAt),\n at: rec.startedAt,\n end,\n deviceId: device.id,\n deviceName: device.name,\n workoutType: rec.workoutType,\n avgHr: Math.round(hr.sum / hr.count),\n maxHr: hr.max,\n samples: thinSamples(hr.samples),\n };\n await this.keep([session]);\n return session;\n }\n\n /** Continuous oximeter: keep the value on screen as a reading. */\n async saveLive(): Promise<void> {\n const live = this.snapshot.live;\n const device = this.link;\n if (!device || live?.spo2 === undefined) return;\n const at = this.now();\n await this.keep([\n {\n kind: 'spo2',\n id: readingId(device.id, 'spo2', at, live.spo2),\n at,\n deviceId: device.id,\n deviceName: device.name,\n spo2: live.spo2,\n ...(live.pulse !== undefined ? { pulse: live.pulse } : {}),\n },\n ]);\n }\n\n private onDisconnect() {\n this.driver?.stop();\n this.driver = null;\n const link = this.link;\n this.link = null;\n if (this.hr) void this.stopRecording();\n const s = this.snapshot.state;\n if (s.step === 'connected' && link) {\n // A scale or cuff switches off after measuring: the normal end.\n this.set({ state: { step: 'ended', device: { id: link.id, name: link.name } }, live: undefined });\n }\n }\n\n private clearScan() {\n this.stopScan?.();\n this.stopScan = null;\n if (this.hintTimer) clearTimeout(this.hintTimer);\n this.hintTimer = null;\n }\n\n /** Leave: finish what was being assembled, stop scanning, disconnect. */\n async close(): Promise<void> {\n if (this.hr) await this.stopRecording();\n this.clearScan();\n this.driver?.stop();\n this.driver = null;\n const link = this.link;\n this.link = null;\n this.closed = true;\n await link?.close();\n }\n}\n\nfunction describeErrorOrOwn(err: unknown): string {\n // The drivers' own messages are already in plain words (\"does not send weight the standard way\").\n if (err instanceof Error && /standard way|does not know how/.test(err.message)) return err.message;\n return describeBleError(err);\n}\n"],"names":["_a"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {jsxs,jsx,Fragment}from'react/jsx-runtime';import React__default,{useState,useMemo,useCallback,useEffect,useRef}from'react';import {BackHandler,StyleSheet,View,Pressable,ActivityIndicator,ScrollView,Linking,Alert,Animated,Easing,Platform}from'react-native';import {Ionicons}from'@expo/vector-icons';import {Text}from'@admin-layout/gluestack-ui-mobile';import {useNavigation,useRoute,CommonActions}from'@react-navigation/native';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {mobileColors,mobileTokens}from'../../theme/mobileTokens.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {deviceKind,DEVICE_KINDS}from'../../features/devices/catalog.js';import {useDevices,useDeviceSession,platformWriter,deviceStore}from'../../features/devices/devices.js';import {describeReading}from'../../features/devices/readings.js';import {
|
|
1
|
+
import {jsxs,jsx,Fragment}from'react/jsx-runtime';import React__default,{useState,useMemo,useCallback,useEffect,useRef}from'react';import {BackHandler,StyleSheet,View,Pressable,ActivityIndicator,ScrollView,Linking,Alert,Animated,Easing,Platform}from'react-native';import {Ionicons}from'@expo/vector-icons';import {Text}from'@admin-layout/gluestack-ui-mobile';import {useNavigation,useRoute,CommonActions}from'@react-navigation/native';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {mobileColors,mobileTokens}from'../../theme/mobileTokens.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {deviceKind,DEVICE_KINDS}from'../../features/devices/catalog.js';import {useDevices,useDeviceSession,platformWriter,deviceStore}from'../../features/devices/devices.js';import {describeReading}from'../../features/devices/readings.js';import {useHealthSync}from'../../features/health/healthSync.js';var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
3
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
4
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -305,53 +305,6 @@ const styles = StyleSheet.create({
|
|
|
305
305
|
fontSize: 14,
|
|
306
306
|
marginTop: 2
|
|
307
307
|
},
|
|
308
|
-
measureBox: {
|
|
309
|
-
alignItems: "center",
|
|
310
|
-
paddingVertical: 24,
|
|
311
|
-
gap: 6
|
|
312
|
-
},
|
|
313
|
-
measureRing: {
|
|
314
|
-
position: "absolute",
|
|
315
|
-
top: 24,
|
|
316
|
-
width: 176,
|
|
317
|
-
height: 176,
|
|
318
|
-
borderRadius: 88,
|
|
319
|
-
borderWidth: 2
|
|
320
|
-
},
|
|
321
|
-
measureCore: {
|
|
322
|
-
width: 176,
|
|
323
|
-
height: 176,
|
|
324
|
-
borderRadius: 88,
|
|
325
|
-
alignItems: "center",
|
|
326
|
-
justifyContent: "center",
|
|
327
|
-
marginBottom: 12
|
|
328
|
-
},
|
|
329
|
-
measureWeight: {
|
|
330
|
-
fontSize: 44,
|
|
331
|
-
fontWeight: "700"
|
|
332
|
-
},
|
|
333
|
-
measureUnit: {
|
|
334
|
-
fontSize: 18,
|
|
335
|
-
fontWeight: "600"
|
|
336
|
-
},
|
|
337
|
-
compositionGrid: {
|
|
338
|
-
flexDirection: "row",
|
|
339
|
-
flexWrap: "wrap",
|
|
340
|
-
marginTop: 10,
|
|
341
|
-
rowGap: 10
|
|
342
|
-
},
|
|
343
|
-
compositionItem: {
|
|
344
|
-
width: "33.33%",
|
|
345
|
-
paddingRight: 8
|
|
346
|
-
},
|
|
347
|
-
compositionLabel: {
|
|
348
|
-
fontSize: 12
|
|
349
|
-
},
|
|
350
|
-
compositionValue: {
|
|
351
|
-
fontSize: 15,
|
|
352
|
-
fontWeight: "600",
|
|
353
|
-
marginTop: 1
|
|
354
|
-
},
|
|
355
308
|
savedLine: {
|
|
356
309
|
flexDirection: "row",
|
|
357
310
|
alignItems: "center",
|
|
@@ -614,15 +567,7 @@ function ReadingsCard({
|
|
|
614
567
|
}], children: whenLabel(r.at, now) }),
|
|
615
568
|
r.kind === "blood-pressure" && ((_a = r.problems) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx(Text, { style: [styles.readingNote, {
|
|
616
569
|
color: colors.warningText
|
|
617
|
-
}], children: r.problems.join(" ") }) : null
|
|
618
|
-
r.kind === "body" && r.composition ? /* @__PURE__ */ jsx(View, { style: styles.compositionGrid, children: compositionRows(r.composition, units).map((m) => /* @__PURE__ */ jsxs(View, { style: styles.compositionItem, children: [
|
|
619
|
-
/* @__PURE__ */ jsx(Text, { style: [styles.compositionLabel, {
|
|
620
|
-
color: colors.textMuted
|
|
621
|
-
}], children: m.label }),
|
|
622
|
-
/* @__PURE__ */ jsx(Text, { style: [styles.compositionValue, {
|
|
623
|
-
color: colors.text
|
|
624
|
-
}], children: m.value })
|
|
625
|
-
] }, m.label)) }) : null
|
|
570
|
+
}], children: r.problems.join(" ") }) : null
|
|
626
571
|
] })
|
|
627
572
|
] }, r.id);
|
|
628
573
|
}) })
|
|
@@ -827,151 +772,10 @@ function PickKind({
|
|
|
827
772
|
] }, k.id)) })
|
|
828
773
|
] });
|
|
829
774
|
}
|
|
830
|
-
function formatWeight(kg, units) {
|
|
831
|
-
if (kg === void 0) return "--";
|
|
832
|
-
const v = units === "imperial" ? kg / 0.45359237 : kg;
|
|
833
|
-
return (Math.round(v * 10) / 10).toFixed(1);
|
|
834
|
-
}
|
|
835
|
-
function ScaleMeasuring({
|
|
836
|
-
colors,
|
|
837
|
-
live,
|
|
838
|
-
units
|
|
839
|
-
}) {
|
|
840
|
-
const pulse = useRef(new Animated.Value(0)).current;
|
|
841
|
-
useEffect(() => {
|
|
842
|
-
const loop = Animated.loop(Animated.timing(pulse, {
|
|
843
|
-
toValue: 1,
|
|
844
|
-
duration: 1400,
|
|
845
|
-
easing: Easing.out(Easing.ease),
|
|
846
|
-
useNativeDriver: true
|
|
847
|
-
}));
|
|
848
|
-
loop.start();
|
|
849
|
-
return () => loop.stop();
|
|
850
|
-
}, [pulse]);
|
|
851
|
-
const ringScale = pulse.interpolate({
|
|
852
|
-
inputRange: [0, 1],
|
|
853
|
-
outputRange: [0.9, 1.5]
|
|
854
|
-
});
|
|
855
|
-
const ringOpacity = pulse.interpolate({
|
|
856
|
-
inputRange: [0, 1],
|
|
857
|
-
outputRange: [0.5, 0]
|
|
858
|
-
});
|
|
859
|
-
const unitLabel = units === "imperial" ? "lb" : "kg";
|
|
860
|
-
return /* @__PURE__ */ jsxs(View, { style: styles.measureBox, children: [
|
|
861
|
-
/* @__PURE__ */ jsx(Animated.View, { style: [styles.measureRing, {
|
|
862
|
-
borderColor: colors.primary,
|
|
863
|
-
opacity: ringOpacity,
|
|
864
|
-
transform: [{
|
|
865
|
-
scale: ringScale
|
|
866
|
-
}]
|
|
867
|
-
}], accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants" }),
|
|
868
|
-
/* @__PURE__ */ jsx(View, { style: [styles.measureCore, {
|
|
869
|
-
backgroundColor: colors.primarySoft
|
|
870
|
-
}], children: /* @__PURE__ */ jsxs(Text, { style: [styles.measureWeight, {
|
|
871
|
-
color: colors.text
|
|
872
|
-
}], accessibilityLabel: `${formatWeight(live.weightKg, units)} ${unitLabel}`, children: [
|
|
873
|
-
formatWeight(live.weightKg, units),
|
|
874
|
-
/* @__PURE__ */ jsxs(Text, { style: [styles.measureUnit, {
|
|
875
|
-
color: colors.textMuted
|
|
876
|
-
}], children: [
|
|
877
|
-
" ",
|
|
878
|
-
unitLabel
|
|
879
|
-
] })
|
|
880
|
-
] }) }),
|
|
881
|
-
/* @__PURE__ */ jsx(Text, { style: [styles.statusTitle, {
|
|
882
|
-
color: colors.text
|
|
883
|
-
}], children: "Measuring" }),
|
|
884
|
-
/* @__PURE__ */ jsx(Text, { style: [styles.statusBody, {
|
|
885
|
-
color: colors.textMuted
|
|
886
|
-
}], children: "Stand still, barefoot, until it settles." })
|
|
887
|
-
] });
|
|
888
|
-
}
|
|
889
|
-
function BrandLive({
|
|
890
|
-
kind,
|
|
891
|
-
colors,
|
|
892
|
-
live,
|
|
893
|
-
units
|
|
894
|
-
}) {
|
|
895
|
-
var _a, _b, _c;
|
|
896
|
-
const items = [];
|
|
897
|
-
const round1 = (n) => Math.round(n * 10) / 10;
|
|
898
|
-
if (kind === "kitchen-scale") items.push({
|
|
899
|
-
label: "Weight",
|
|
900
|
-
value: `${Math.round((_a = live.grams) != null ? _a : 0)} g`
|
|
901
|
-
});
|
|
902
|
-
if (kind === "tape") {
|
|
903
|
-
const cm = (_b = live.lengthCm) != null ? _b : 0;
|
|
904
|
-
items.push({
|
|
905
|
-
label: live.bodyPart ? live.bodyPart.replace(/_/g, " ") : "Length",
|
|
906
|
-
value: units === "imperial" ? `${round1(cm / 2.54)} in` : `${round1(cm)} cm`
|
|
907
|
-
});
|
|
908
|
-
}
|
|
909
|
-
if (kind === "jump-rope") {
|
|
910
|
-
items.push({
|
|
911
|
-
label: "Jumps",
|
|
912
|
-
value: String((_c = live.jumps) != null ? _c : 0)
|
|
913
|
-
});
|
|
914
|
-
if (live.elapsedS !== void 0) items.push({
|
|
915
|
-
label: "Time",
|
|
916
|
-
value: clockOf(live.elapsedS)
|
|
917
|
-
});
|
|
918
|
-
}
|
|
919
|
-
if (kind === "treadmill") {
|
|
920
|
-
if (live.speedKmh !== void 0) items.push({
|
|
921
|
-
label: "Speed",
|
|
922
|
-
value: `${round1(live.speedKmh)} km/h`
|
|
923
|
-
});
|
|
924
|
-
if (live.distanceM !== void 0) items.push({
|
|
925
|
-
label: "Distance",
|
|
926
|
-
value: `${round1(live.distanceM / 1e3)} km`
|
|
927
|
-
});
|
|
928
|
-
if (live.kcal !== void 0) items.push({
|
|
929
|
-
label: "Calories",
|
|
930
|
-
value: `${Math.round(live.kcal)} kcal`
|
|
931
|
-
});
|
|
932
|
-
if (live.elapsedS !== void 0) items.push({
|
|
933
|
-
label: "Time",
|
|
934
|
-
value: clockOf(live.elapsedS)
|
|
935
|
-
});
|
|
936
|
-
}
|
|
937
|
-
if (kind === "ring") {
|
|
938
|
-
if (live.bpm !== void 0) items.push({
|
|
939
|
-
label: "Heart rate",
|
|
940
|
-
value: `${live.bpm} bpm`
|
|
941
|
-
});
|
|
942
|
-
if (live.spo2 !== void 0) items.push({
|
|
943
|
-
label: "Blood oxygen",
|
|
944
|
-
value: `${live.spo2}%`
|
|
945
|
-
});
|
|
946
|
-
if (live.skinTempC !== void 0) items.push({
|
|
947
|
-
label: "Skin temp",
|
|
948
|
-
value: `${round1(live.skinTempC)} \xB0C`
|
|
949
|
-
});
|
|
950
|
-
if (live.steps !== void 0) items.push({
|
|
951
|
-
label: "Steps",
|
|
952
|
-
value: String(live.steps)
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
if (live.battery !== void 0) items.push({
|
|
956
|
-
label: "Battery",
|
|
957
|
-
value: `${live.battery}%`
|
|
958
|
-
});
|
|
959
|
-
return /* @__PURE__ */ jsx(View, { style: [styles.card, styles.livePanel, {
|
|
960
|
-
backgroundColor: colors.surface
|
|
961
|
-
}], children: /* @__PURE__ */ jsx(View, { style: styles.compositionGrid, children: items.map((m) => /* @__PURE__ */ jsxs(View, { style: styles.compositionItem, children: [
|
|
962
|
-
/* @__PURE__ */ jsx(Text, { style: [styles.compositionLabel, {
|
|
963
|
-
color: colors.textMuted
|
|
964
|
-
}], children: m.label }),
|
|
965
|
-
/* @__PURE__ */ jsx(Text, { style: [styles.compositionValue, {
|
|
966
|
-
color: colors.text
|
|
967
|
-
}], children: m.value })
|
|
968
|
-
] }, m.label)) }) });
|
|
969
|
-
}
|
|
970
775
|
function LivePanel({
|
|
971
776
|
kind,
|
|
972
777
|
colors,
|
|
973
778
|
live,
|
|
974
|
-
units,
|
|
975
779
|
recording,
|
|
976
780
|
connected,
|
|
977
781
|
onStart,
|
|
@@ -980,12 +784,6 @@ function LivePanel({
|
|
|
980
784
|
}) {
|
|
981
785
|
var _a, _b, _c, _d, _e;
|
|
982
786
|
const [type, setType] = useState("run");
|
|
983
|
-
if (kind === "scale") {
|
|
984
|
-
return /* @__PURE__ */ jsx(ScaleMeasuring, { colors, live, units });
|
|
985
|
-
}
|
|
986
|
-
if (kind === "kitchen-scale" || kind === "tape" || kind === "jump-rope" || kind === "treadmill" || kind === "ring") {
|
|
987
|
-
return /* @__PURE__ */ jsx(BrandLive, { kind, colors, live, units });
|
|
988
|
-
}
|
|
989
787
|
const [, tick] = useState(0);
|
|
990
788
|
useEffect(() => {
|
|
991
789
|
if (!recording) return void 0;
|
|
@@ -1145,7 +943,7 @@ function Measure({
|
|
|
1145
943
|
"."
|
|
1146
944
|
] })
|
|
1147
945
|
] }) : null,
|
|
1148
|
-
(state.step === "connected" || state.step === "ended") && live ? /* @__PURE__ */ jsx(LivePanel, { kind, colors, live,
|
|
946
|
+
(state.step === "connected" || state.step === "ended") && live ? /* @__PURE__ */ jsx(LivePanel, { kind, colors, live, recording, connected: state.step === "connected", onStart: (type) => session == null ? void 0 : session.startRecording(type), onStop: () => {
|
|
1149
947
|
void (session == null ? void 0 : session.stopRecording());
|
|
1150
948
|
}, onSave: () => {
|
|
1151
949
|
void (session == null ? void 0 : session.saveLive());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/screens/Devices/index.tsx"],"sourcesContent":["/**\n * Devices: the Bluetooth health devices the person paired, and pairing a new\n * one. One route with its own small stack (home -> pick a kind -> measure, or\n * home -> a device -> measure), so the flow never leaves the screen:\n *\n * - home: the paired devices with their last reading, and \"Add a device\";\n * - pick: which kind of device (scale, blood pressure, heart rate ...);\n * - measure: how to wake it, the devices found nearby, connecting, waiting for\n * a measurement (or live heart rate / oxygen), and what it measured;\n * - device: its readings, take another, forget it.\n *\n * Only devices that speak the Bluetooth SIG health profiles pair here. A brand\n * scale with its own app (RENPHO, Withings ...) keeps that app; it writes to\n * Apple Health / Health Connect and Yantra reads it there, which the home says.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n ActivityIndicator,\n Alert,\n Animated,\n BackHandler,\n Easing,\n Linking,\n Platform,\n Pressable,\n ScrollView,\n StyleSheet,\n View,\n} from 'react-native';\nimport { Ionicons } from '@expo/vector-icons';\nimport { Text } from '@admin-layout/gluestack-ui-mobile';\nimport {\n CommonActions,\n useNavigation,\n useRoute,\n type NavigationProp,\n type ParamListBase,\n type RouteProp,\n} from '@react-navigation/native';\nimport { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { mobileColors, mobileTokens } from '../../theme/mobileTokens';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\nimport { DEVICE_KINDS, deviceKind, type DeviceKindId } from '../../features/devices/catalog';\nimport { deviceStore, platformWriter, useDeviceSession, useDevices } from '../../features/devices/devices';\nimport { describeReading, type DeviceReading } from '../../features/devices/readings';\nimport { compositionRows } from '../../features/devices/bodyComposition';\nimport type { PairedDevice } from '../../features/devices/deviceStore';\nimport type { FoundDevice, RadioState } from '../../features/devices/link';\nimport type { LiveValue } from '../../features/devices/drivers';\nimport { useHealthSync } from '../../features/health/healthSync';\n\ntype Colors = ReturnType<typeof mobileColors>;\ntype Glyph = keyof typeof Ionicons.glyphMap;\n/** `add`: open straight on \"Which device\" (the Fitness page's Add a device). */\ntype DevicesParams = { orgName?: string; add?: boolean } | undefined;\ntype Step =\n | { name: 'home' }\n | { name: 'pick' }\n | { name: 'measure'; kind: DeviceKindId; deviceId?: string }\n | { name: 'device'; id: string };\n\nconst IS_IOS = Platform.OS === 'ios';\n/** The app's surfaces are white on a white page in light mode; an edge keeps each card readable as one. */\nconst CARD_EDGE = 'rgba(148,163,184,0.3)';\nconst STORE_NAME = IS_IOS ? 'Apple Health' : 'Health Connect';\nconst WORKOUT_TYPES: Array<{ id: string; label: string }> = [\n { id: 'run', label: 'Run' },\n { id: 'walk', label: 'Walk' },\n { id: 'cycle', label: 'Ride' },\n { id: 'strength', label: 'Strength' },\n { id: 'hiit', label: 'HIIT' },\n { id: 'other', label: 'Other' },\n];\n\nconst styles = StyleSheet.create({\n safe: { flex: 1 },\n header: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingBottom: 8, minHeight: 52 },\n backCircle: {\n width: 40,\n height: 40,\n borderRadius: 20,\n alignItems: 'center',\n justifyContent: 'center',\n ...mobileTokens.shadow.card,\n },\n headerTitle: { flex: 1, textAlign: 'center', fontSize: 17, fontWeight: '600', marginHorizontal: 8 },\n headerSpacer: { width: 40, height: 40 },\n pressed: { opacity: 0.72 },\n loading: { marginTop: 48 },\n scroll: { paddingHorizontal: 16, paddingBottom: 40 },\n hero: { alignItems: 'center', paddingTop: 8, paddingBottom: 16, gap: 10 },\n heroIcon: { width: 64, height: 64, borderRadius: 32, alignItems: 'center', justifyContent: 'center' },\n heroTitle: { fontSize: 20, fontWeight: '700', textAlign: 'center' },\n heroBody: { fontSize: 15, lineHeight: 21, textAlign: 'center', paddingHorizontal: 8 },\n card: { borderRadius: 16, overflow: 'hidden', borderWidth: 1, borderColor: CARD_EDGE },\n secondaryCard: { marginTop: 20 },\n sectionTitle: {\n fontSize: 13,\n fontWeight: '600',\n letterSpacing: 0.4,\n marginTop: 24,\n marginBottom: 8,\n marginLeft: 16,\n },\n row: { flexDirection: 'row', alignItems: 'center', minHeight: 52, paddingHorizontal: 16, gap: 12 },\n rowLabelWide: { flex: 1, fontSize: 16 },\n rowLine: { height: StyleSheet.hairlineWidth, marginLeft: 16 },\n deviceRow: { flexDirection: 'row', alignItems: 'center', minHeight: 64, paddingHorizontal: 16, gap: 12 },\n deviceText: { flex: 1, minWidth: 0 },\n deviceName: { fontSize: 16, fontWeight: '600' },\n deviceMeta: { fontSize: 14, marginTop: 2 },\n kindIcon: { alignItems: 'center', justifyContent: 'center' },\n question: { fontSize: 22, fontWeight: '700', textAlign: 'center', marginTop: 8, marginBottom: 20, lineHeight: 28 },\n kindList: { gap: 10 },\n kindCard: {\n flexDirection: 'row',\n alignItems: 'center',\n borderRadius: 16,\n padding: 14,\n gap: 14,\n borderWidth: 1,\n borderColor: CARD_EDGE,\n },\n kindTitle: { fontSize: 16, fontWeight: '600' },\n center: { alignItems: 'center', paddingTop: 24, gap: 12 },\n statusTitle: { fontSize: 19, fontWeight: '700', textAlign: 'center', marginTop: 4 },\n statusBody: { fontSize: 15, lineHeight: 21, textAlign: 'center', paddingHorizontal: 8 },\n guidance: { marginTop: 16, paddingVertical: 8 },\n guidanceRow: { flexDirection: 'row', alignItems: 'flex-start', paddingHorizontal: 16, paddingVertical: 8, gap: 12 },\n stepDot: { width: 24, height: 24, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginTop: 1 },\n stepNumber: { fontSize: 13, fontWeight: '700' },\n guidanceText: { flex: 1, fontSize: 15, lineHeight: 22 },\n pulseBox: {\n alignSelf: 'center',\n width: 120,\n height: 120,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: 16,\n },\n pulseRing: { position: 'absolute', width: 64, height: 64, borderRadius: 32 },\n pulseCore: { width: 64, height: 64, borderRadius: 32, alignItems: 'center', justifyContent: 'center' },\n signal: { flexDirection: 'row', alignItems: 'flex-end', gap: 2, height: 16 },\n signalBar: { width: 4, borderRadius: 1 },\n livePanel: { alignItems: 'center', padding: 20, marginTop: 16, gap: 12 },\n liveValue: { fontSize: 56, fontWeight: '700', fontVariant: ['tabular-nums'] },\n liveUnit: { fontSize: 18, fontWeight: '500' },\n liveMeta: { fontSize: 15, fontVariant: ['tabular-nums'] },\n chips: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'center', gap: 8 },\n chip: { borderWidth: 1, borderRadius: 999, paddingHorizontal: 14, paddingVertical: 8 },\n chipLabel: { fontSize: 14, fontWeight: '600' },\n readingRow: { paddingHorizontal: 16, paddingVertical: 12, gap: 2 },\n readingValue: { fontSize: 16, fontWeight: '600' },\n readingWhen: { fontSize: 14 },\n readingNote: { fontSize: 14, marginTop: 2 },\n measureBox: { alignItems: 'center', paddingVertical: 24, gap: 6 },\n measureRing: { position: 'absolute', top: 24, width: 176, height: 176, borderRadius: 88, borderWidth: 2 },\n measureCore: {\n width: 176,\n height: 176,\n borderRadius: 88,\n alignItems: 'center',\n justifyContent: 'center',\n marginBottom: 12,\n },\n measureWeight: { fontSize: 44, fontWeight: '700' },\n measureUnit: { fontSize: 18, fontWeight: '600' },\n compositionGrid: { flexDirection: 'row', flexWrap: 'wrap', marginTop: 10, rowGap: 10 },\n compositionItem: { width: '33.33%', paddingRight: 8 },\n compositionLabel: { fontSize: 12 },\n compositionValue: { fontSize: 15, fontWeight: '600', marginTop: 1 },\n savedLine: { flexDirection: 'row', alignItems: 'center', gap: 8, marginTop: 12, marginHorizontal: 4 },\n savedBlock: { marginTop: 12, gap: 10 },\n savedText: { flex: 1, fontSize: 14, lineHeight: 20 },\n notice: { flexDirection: 'row', borderRadius: 14, padding: 12, marginTop: 12, gap: 8 },\n noticeIcon: { marginTop: 1 },\n noticeText: { flex: 1, fontSize: 14, lineHeight: 20 },\n actions: { marginTop: 20, gap: 10, alignItems: 'stretch' },\n actionHint: { fontSize: 15, lineHeight: 21, textAlign: 'center' },\n primary: {\n backgroundColor: mobileTokens.color.primary,\n borderRadius: 14,\n minHeight: 50,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: 18,\n alignSelf: 'stretch',\n },\n primaryLabel: { color: '#fff', fontSize: 16, fontWeight: '600' },\n secondary: {\n borderRadius: 14,\n minHeight: 48,\n alignItems: 'center',\n justifyContent: 'center',\n borderWidth: 1,\n paddingHorizontal: 18,\n },\n secondaryLabel: { fontSize: 16, fontWeight: '600' },\n footnote: { fontSize: 13, lineHeight: 18, marginTop: 16, marginHorizontal: 16 },\n linkRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n marginTop: 10,\n marginHorizontal: 16,\n alignSelf: 'flex-start',\n },\n link: { fontSize: 14, fontWeight: '600' },\n});\n\nfunction stepTitle(step: Step, paired: PairedDevice[]): string {\n switch (step.name) {\n case 'pick':\n return 'Add a device';\n case 'measure':\n return deviceKind(step.kind).title;\n case 'device':\n return paired.find((d) => d.id === step.id)?.name ?? 'Device';\n default:\n return 'Devices';\n }\n}\n\n/** What to say when the radio is not ready to scan. */\nfunction radioCopy(radio: RadioState): { title: string; body: string } {\n if (radio === 'off') return { title: 'Turn on Bluetooth', body: 'Yantra finds your device over Bluetooth.' };\n if (radio === 'unauthorized') {\n return {\n title: 'Allow Bluetooth for Yantra',\n body: 'Yantra needs Bluetooth to find and read your device. Turn it on for Yantra in Settings.',\n };\n }\n return { title: 'This phone has no Bluetooth Yantra can use', body: '' };\n}\n\n/** Bars for the signal strength of a device found nearby. */\nfunction signalBars(rssi: number | undefined): number {\n if (rssi === undefined) return 1;\n if (rssi > -60) return 3;\n if (rssi > -80) return 2;\n return 1;\n}\n\nfunction whenLabel(at: number, now: number): string {\n const d = new Date(at);\n const time = d.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });\n const startOf = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const days = Math.round((startOf(new Date(now)) - startOf(d)) / 86_400_000);\n if (days === 0) return `Today, ${time}`;\n if (days === 1) return `Yesterday, ${time}`;\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\n/** \"Today, 7:31 AM\" wraps as one piece, never with \"AM\" alone on the next line. */\nfunction keepTogether(text: string): string {\n return text.replace(/\\s/g, '\\u00a0');\n}\n\nfunction clockOf(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${String(s).padStart(2, '0')}`;\n}\n\n// ------------------------------------------------------------------ Pieces\n\nfunction KindIcon({ kind, colors, large }: { kind: DeviceKindId; colors: Colors; large?: boolean }) {\n const size = large ? 48 : 36;\n return (\n <View\n style={[\n styles.kindIcon,\n { width: size, height: size, borderRadius: size / 2, backgroundColor: colors.primarySoft },\n ]}\n >\n <Ionicons name={deviceKind(kind).icon as Glyph} size={large ? 24 : 18} color={colors.primary} />\n </View>\n );\n}\n\n/** The Bluetooth mark with a ring that breathes while scanning. */\nfunction BluetoothPulse({ colors, active, connected }: { colors: Colors; active: boolean; connected?: boolean }) {\n const pulse = useRef(new Animated.Value(0)).current;\n useEffect(() => {\n if (!active) return undefined;\n const loop = Animated.loop(\n Animated.timing(pulse, {\n toValue: 1,\n duration: 1600,\n easing: Easing.out(Easing.ease),\n useNativeDriver: true,\n }),\n );\n loop.start();\n return () => loop.stop();\n }, [active, pulse]);\n const scale = pulse.interpolate({ inputRange: [0, 1], outputRange: [1, 1.9] });\n const opacity = pulse.interpolate({ inputRange: [0, 1], outputRange: [0.45, 0] });\n return (\n <View style={styles.pulseBox} accessibilityElementsHidden importantForAccessibility=\"no-hide-descendants\">\n {active ? (\n <Animated.View\n style={[styles.pulseRing, { backgroundColor: colors.primary, opacity, transform: [{ scale }] }]}\n />\n ) : null}\n <View style={[styles.pulseCore, { backgroundColor: connected ? colors.successText : colors.primary }]}>\n <Ionicons name={connected ? 'checkmark' : 'bluetooth'} size={28} color=\"#fff\" />\n </View>\n </View>\n );\n}\n\nfunction Notice({\n colors,\n tone,\n icon,\n text,\n}: {\n colors: Colors;\n tone: 'warning' | 'danger';\n icon: Glyph;\n text: string;\n}) {\n const bg = tone === 'danger' ? colors.dangerSoft : colors.warningSoft;\n const fg = tone === 'danger' ? colors.dangerText : colors.warningText;\n return (\n <View style={[styles.notice, { backgroundColor: bg }]} accessibilityRole=\"alert\">\n <Ionicons name={icon} size={18} color={fg} style={styles.noticeIcon} />\n <Text style={[styles.noticeText, { color: fg }]}>{text}</Text>\n </View>\n );\n}\n\nfunction PrimaryButton({ label, onPress }: { label: string; onPress: () => void }) {\n return (\n <Pressable\n onPress={onPress}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n style={({ pressed }) => [styles.primary, pressed && styles.pressed]}\n >\n <Text style={styles.primaryLabel}>{label}</Text>\n </Pressable>\n );\n}\n\nfunction SecondaryButton({ label, onPress, colors }: { label: string; onPress: () => void; colors: Colors }) {\n return (\n <Pressable\n onPress={onPress}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n style={({ pressed }) => [\n styles.secondary,\n { borderColor: colors.border, backgroundColor: colors.surface },\n pressed && styles.pressed,\n ]}\n >\n <Text style={[styles.secondaryLabel, { color: colors.text }]}>{label}</Text>\n </Pressable>\n );\n}\n\nfunction ReadingsCard({\n title,\n readings,\n colors,\n units,\n now,\n}: {\n title: string;\n readings: DeviceReading[];\n colors: Colors;\n units: 'metric' | 'imperial';\n now: number;\n}) {\n return (\n <>\n <Text style={[styles.sectionTitle, { color: colors.textMuted }]}>{title}</Text>\n <View style={[styles.card, { backgroundColor: colors.surface }]}>\n {readings.map((r, i) => (\n <React.Fragment key={r.id}>\n {i > 0 ? <View style={[styles.rowLine, { backgroundColor: colors.border }]} /> : null}\n <View style={styles.readingRow}>\n <Text style={[styles.readingValue, { color: colors.text }]}>\n {describeReading(r, units)}\n </Text>\n <Text style={[styles.readingWhen, { color: colors.textMuted }]}>\n {whenLabel(r.at, now)}\n </Text>\n {r.kind === 'blood-pressure' && r.problems?.length ? (\n <Text style={[styles.readingNote, { color: colors.warningText }]}>\n {r.problems.join(' ')}\n </Text>\n ) : null}\n {r.kind === 'body' && r.composition ? (\n <View style={styles.compositionGrid}>\n {compositionRows(r.composition, units).map((m) => (\n <View key={m.label} style={styles.compositionItem}>\n <Text style={[styles.compositionLabel, { color: colors.textMuted }]}>\n {m.label}\n </Text>\n <Text style={[styles.compositionValue, { color: colors.text }]}>\n {m.value}\n </Text>\n </View>\n ))}\n </View>\n ) : null}\n </View>\n </React.Fragment>\n ))}\n </View>\n </>\n );\n}\n\n/** Where the readings went, and how to have them saved to the health store too. */\nfunction SavedLine({ colors, onHealth }: { colors: Colors; onHealth: () => void }) {\n const health = useHealthSync();\n const [asked, setAsked] = useState<boolean | null>(null);\n useEffect(() => {\n let live = true;\n void platformWriter().then(async (w) => {\n const a = w ? await w.asked().catch(() => true) : true;\n if (live) setAsked(a);\n });\n return () => {\n live = false;\n };\n }, [health.sync.connected]);\n const allowSaving = async () => {\n const w = await platformWriter();\n if (!w) return;\n await w.requestAccess().catch(() => undefined);\n setAsked(true);\n void deviceStore.flush();\n };\n if (!health.sync.connected) {\n return (\n <Pressable\n onPress={onHealth}\n accessibilityRole=\"link\"\n style={({ pressed }) => [styles.savedLine, pressed && styles.pressed]}\n >\n <Ionicons name=\"checkmark-circle\" size={18} color={colors.successText} />\n <Text style={[styles.savedText, { color: colors.textMuted }]}>\n Saved for your coach. <Text style={{ color: colors.primary }}>Connect {STORE_NAME}</Text> to keep it\n there too.\n </Text>\n </Pressable>\n );\n }\n if (asked === false) {\n return (\n <View style={styles.savedBlock}>\n <Text style={[styles.savedText, { color: colors.textMuted }]}>Saved for your coach.</Text>\n <SecondaryButton\n label={`Also save to ${STORE_NAME}`}\n colors={colors}\n onPress={() => {\n void allowSaving();\n }}\n />\n </View>\n );\n }\n return (\n <View style={styles.savedLine}>\n <Ionicons name=\"checkmark-circle\" size={18} color={colors.successText} />\n <Text style={[styles.savedText, { color: colors.textMuted }]}>\n Saved for your coach and to {STORE_NAME}.\n </Text>\n </View>\n );\n}\n\nfunction FoundRow({\n found,\n first,\n colors,\n onPress,\n}: {\n found: FoundDevice;\n first: boolean;\n colors: Colors;\n onPress: () => void;\n}) {\n const bars = signalBars(found.rssi);\n return (\n <>\n {!first ? <View style={[styles.rowLine, { backgroundColor: colors.border }]} /> : null}\n <Pressable\n onPress={onPress}\n accessibilityRole=\"button\"\n accessibilityLabel={`Connect ${found.name}`}\n style={({ pressed }) => [styles.deviceRow, pressed && { backgroundColor: colors.surfaceMuted }]}\n >\n {found.kind ? (\n <KindIcon kind={found.kind} colors={colors} />\n ) : (\n <Ionicons name=\"bluetooth\" size={22} color={colors.primary} />\n )}\n <Text style={[styles.deviceName, styles.deviceText, { color: colors.text }]} numberOfLines={1}>\n {found.name}\n </Text>\n <View style={styles.signal} accessibilityLabel={`Signal ${bars} of 3`}>\n {[1, 2, 3].map((b) => (\n <View\n key={b}\n style={[\n styles.signalBar,\n { height: 4 + b * 4, backgroundColor: b <= bars ? colors.primary : colors.border },\n ]}\n />\n ))}\n </View>\n </Pressable>\n </>\n );\n}\n\n// ------------------------------------------------------------------- Home\n\nfunction Home({\n colors,\n isDark,\n units,\n onAdd,\n onOpen,\n onHealth,\n}: {\n colors: Colors;\n isDark: boolean;\n units: 'metric' | 'imperial';\n onAdd: () => void;\n onOpen: (id: string) => void;\n onHealth: () => void;\n}) {\n const devices = useDevices();\n const now = Date.now();\n if (!devices.loaded) return <ActivityIndicator style={styles.loading} color={colors.primary} />;\n const latestOf = (d: PairedDevice) =>\n devices.readings\n .filter((r) => r.deviceId === d.id)\n .reduce<DeviceReading | undefined>((a, b) => (!a || b.at > a.at ? b : a), undefined);\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n {devices.devices.length ? (\n <>\n <Text style={[styles.sectionTitle, { color: colors.textMuted }]}>MY DEVICES</Text>\n <View style={[styles.card, { backgroundColor: colors.surface }]}>\n {devices.devices.map((d, i) => {\n const latest = latestOf(d);\n return (\n <React.Fragment key={d.id}>\n {i > 0 ? (\n <View style={[styles.rowLine, { backgroundColor: colors.border }]} />\n ) : null}\n <Pressable\n onPress={() => onOpen(d.id)}\n accessibilityRole=\"button\"\n accessibilityLabel={d.name}\n style={({ pressed }) => [\n styles.deviceRow,\n pressed && { backgroundColor: colors.surfaceMuted },\n ]}\n >\n <KindIcon kind={d.kind} colors={colors} />\n <View style={styles.deviceText}>\n <Text style={[styles.deviceName, { color: colors.text }]} numberOfLines={1}>\n {d.name}\n </Text>\n <Text\n style={[styles.deviceMeta, { color: colors.textMuted }]}\n numberOfLines={2}\n >\n {latest\n ? `${describeReading(latest, units)} · ${keepTogether(whenLabel(latest.at, now))}`\n : 'No readings yet'}\n </Text>\n </View>\n <Ionicons\n name=\"chevron-forward\"\n size={16}\n color={isDark ? '#64748b' : '#c4c4c4'}\n />\n </Pressable>\n </React.Fragment>\n );\n })}\n </View>\n </>\n ) : (\n <View style={styles.hero}>\n <View style={[styles.heroIcon, { backgroundColor: colors.primarySoft }]}>\n <Ionicons name=\"bluetooth\" size={30} color={colors.primary} />\n </View>\n <Text style={[styles.heroTitle, { color: colors.text }]}>Connect a device</Text>\n <Text style={[styles.heroBody, { color: colors.textMuted }]}>\n Pair a scale, blood-pressure monitor, heart-rate strap, pulse oximeter, thermometer or glucose\n meter. Each reading goes to your coach, and to {STORE_NAME} when you connected it.\n </Text>\n </View>\n )}\n {devices.lastError && devices.pendingDates.length ? (\n <Notice\n colors={colors}\n tone=\"warning\"\n icon=\"cloud-offline-outline\"\n text={`Readings are kept on this phone and sent when Yantra can reach your coach. ${devices.lastError}`}\n />\n ) : null}\n <View style={styles.actions}>\n <PrimaryButton label=\"Add a device\" onPress={onAdd} />\n </View>\n <Text style={[styles.footnote, { color: colors.textMuted }]}>\n Devices that use the Bluetooth health standards pair here. For a brand scale with its own app, such as\n RENPHO or Withings, turn on its {STORE_NAME} sync; Yantra reads it there.\n </Text>\n <Pressable\n onPress={onHealth}\n accessibilityRole=\"link\"\n style={({ pressed }) => [styles.linkRow, pressed && styles.pressed]}\n >\n <Text style={[styles.link, { color: colors.primary }]}>{STORE_NAME} settings</Text>\n <Ionicons name=\"chevron-forward\" size={14} color={colors.primary} />\n </Pressable>\n </ScrollView>\n );\n}\n\n// --------------------------------------------------------------- Pick kind\n\nfunction PickKind({\n colors,\n isDark,\n onPick,\n}: {\n colors: Colors;\n isDark: boolean;\n onPick: (kind: DeviceKindId) => void;\n}) {\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n <Text style={[styles.question, { color: colors.text }]}>Which device do you want to connect?</Text>\n <View style={styles.kindList}>\n {DEVICE_KINDS.map((k) => (\n <Pressable\n key={k.id}\n onPress={() => onPick(k.id)}\n accessibilityRole=\"button\"\n accessibilityLabel={k.title}\n style={({ pressed }) => [\n styles.kindCard,\n { backgroundColor: colors.surface },\n pressed && { backgroundColor: colors.surfaceMuted },\n ]}\n >\n <KindIcon kind={k.id} colors={colors} large />\n <View style={styles.deviceText}>\n <Text style={[styles.kindTitle, { color: colors.text }]}>{k.title}</Text>\n <Text style={[styles.deviceMeta, { color: colors.textMuted }]}>{k.subtitle}</Text>\n </View>\n <Ionicons name=\"chevron-forward\" size={16} color={isDark ? '#64748b' : '#c4c4c4'} />\n </Pressable>\n ))}\n </View>\n </ScrollView>\n );\n}\n\n// ----------------------------------------------------------------- Measure\n\n/** kg to the person's units, as a string with one decimal. */\nfunction formatWeight(kg: number | undefined, units: 'metric' | 'imperial'): string {\n if (kg === undefined) return '--';\n const v = units === 'imperial' ? kg / 0.45359237 : kg;\n return (Math.round(v * 10) / 10).toFixed(1);\n}\n\n/**\n * The scale's live weighing: the number rises as the person settles onto the\n * scale, inside a soft pulsing ring. An original Yantra design, not a copy of\n * any scale maker's screen.\n */\nfunction ScaleMeasuring({ colors, live, units }: { colors: Colors; live: LiveValue; units: 'metric' | 'imperial' }) {\n const pulse = useRef(new Animated.Value(0)).current;\n useEffect(() => {\n const loop = Animated.loop(\n Animated.timing(pulse, {\n toValue: 1,\n duration: 1400,\n easing: Easing.out(Easing.ease),\n useNativeDriver: true,\n }),\n );\n loop.start();\n return () => loop.stop();\n }, [pulse]);\n const ringScale = pulse.interpolate({ inputRange: [0, 1], outputRange: [0.9, 1.5] });\n const ringOpacity = pulse.interpolate({ inputRange: [0, 1], outputRange: [0.5, 0] });\n const unitLabel = units === 'imperial' ? 'lb' : 'kg';\n return (\n <View style={styles.measureBox}>\n <Animated.View\n style={[\n styles.measureRing,\n { borderColor: colors.primary, opacity: ringOpacity, transform: [{ scale: ringScale }] },\n ]}\n accessibilityElementsHidden\n importantForAccessibility=\"no-hide-descendants\"\n />\n <View style={[styles.measureCore, { backgroundColor: colors.primarySoft }]}>\n <Text style={[styles.measureWeight, { color: colors.text }]} accessibilityLabel={`${formatWeight(live.weightKg, units)} ${unitLabel}`}>\n {formatWeight(live.weightKg, units)}\n <Text style={[styles.measureUnit, { color: colors.textMuted }]}> {unitLabel}</Text>\n </Text>\n </View>\n <Text style={[styles.statusTitle, { color: colors.text }]}>Measuring</Text>\n <Text style={[styles.statusBody, { color: colors.textMuted }]}>\n Stand still, barefoot, until it settles.\n </Text>\n </View>\n );\n}\n\n/** A plain live readout for the other brand devices (kitchen scale, tape, rope, treadmill, ring). */\nfunction BrandLive({\n kind,\n colors,\n live,\n units,\n}: {\n kind: DeviceKindId;\n colors: Colors;\n live: LiveValue;\n units: 'metric' | 'imperial';\n}) {\n const items: Array<{ label: string; value: string }> = [];\n const round1 = (n: number) => Math.round(n * 10) / 10;\n if (kind === 'kitchen-scale') items.push({ label: 'Weight', value: `${Math.round(live.grams ?? 0)} g` });\n if (kind === 'tape') {\n const cm = live.lengthCm ?? 0;\n items.push({\n label: live.bodyPart ? live.bodyPart.replace(/_/g, ' ') : 'Length',\n value: units === 'imperial' ? `${round1(cm / 2.54)} in` : `${round1(cm)} cm`,\n });\n }\n if (kind === 'jump-rope') {\n items.push({ label: 'Jumps', value: String(live.jumps ?? 0) });\n if (live.elapsedS !== undefined) items.push({ label: 'Time', value: clockOf(live.elapsedS) });\n }\n if (kind === 'treadmill') {\n if (live.speedKmh !== undefined) items.push({ label: 'Speed', value: `${round1(live.speedKmh)} km/h` });\n if (live.distanceM !== undefined) items.push({ label: 'Distance', value: `${round1(live.distanceM / 1000)} km` });\n if (live.kcal !== undefined) items.push({ label: 'Calories', value: `${Math.round(live.kcal)} kcal` });\n if (live.elapsedS !== undefined) items.push({ label: 'Time', value: clockOf(live.elapsedS) });\n }\n if (kind === 'ring') {\n if (live.bpm !== undefined) items.push({ label: 'Heart rate', value: `${live.bpm} bpm` });\n if (live.spo2 !== undefined) items.push({ label: 'Blood oxygen', value: `${live.spo2}%` });\n if (live.skinTempC !== undefined) items.push({ label: 'Skin temp', value: `${round1(live.skinTempC)} °C` });\n if (live.steps !== undefined) items.push({ label: 'Steps', value: String(live.steps) });\n }\n if (live.battery !== undefined) items.push({ label: 'Battery', value: `${live.battery}%` });\n return (\n <View style={[styles.card, styles.livePanel, { backgroundColor: colors.surface }]}>\n <View style={styles.compositionGrid}>\n {items.map((m) => (\n <View key={m.label} style={styles.compositionItem}>\n <Text style={[styles.compositionLabel, { color: colors.textMuted }]}>{m.label}</Text>\n <Text style={[styles.compositionValue, { color: colors.text }]}>{m.value}</Text>\n </View>\n ))}\n </View>\n </View>\n );\n}\n\nfunction LivePanel({\n kind,\n colors,\n live,\n units,\n recording,\n connected,\n onStart,\n onStop,\n onSave,\n}: {\n kind: DeviceKindId;\n colors: Colors;\n live: LiveValue;\n units: 'metric' | 'imperial';\n recording?: { startedAt: number; workoutType: string; avgHr?: number; maxHr?: number };\n connected: boolean;\n onStart: (type: string) => void;\n onStop: () => void;\n onSave: () => void;\n}) {\n const [type, setType] = useState('run');\n if (kind === 'scale') {\n return <ScaleMeasuring colors={colors} live={live} units={units} />;\n }\n if (kind === 'kitchen-scale' || kind === 'tape' || kind === 'jump-rope' || kind === 'treadmill' || kind === 'ring') {\n return <BrandLive kind={kind} colors={colors} live={live} units={units} />;\n }\n const [, tick] = useState(0);\n useEffect(() => {\n if (!recording) return undefined;\n const t = setInterval(() => tick((n) => n + 1), 1000);\n return () => clearInterval(t);\n }, [recording]);\n if (kind === 'heart-rate') {\n const elapsed = recording ? Math.max(0, Math.floor((Date.now() - recording.startedAt) / 1000)) : 0;\n return (\n <View style={[styles.card, styles.livePanel, { backgroundColor: colors.surface }]}>\n <Text\n style={[styles.liveValue, { color: colors.text }]}\n accessibilityLabel={`Heart rate ${live.bpm ?? 0} beats per minute`}\n >\n {live.bpm ?? '--'}\n <Text style={[styles.liveUnit, { color: colors.textMuted }]}> bpm</Text>\n </Text>\n {recording ? (\n <>\n <Text style={[styles.liveMeta, { color: colors.textMuted }]}>\n {clockOf(elapsed)} · average {recording.avgHr ?? '--'} · max {recording.maxHr ?? '--'}\n </Text>\n <PrimaryButton label=\"Stop and save\" onPress={onStop} />\n </>\n ) : null}\n {!recording && connected ? (\n <>\n <View style={styles.chips}>\n {WORKOUT_TYPES.map((w) => (\n <Pressable\n key={w.id}\n onPress={() => setType(w.id)}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: type === w.id }}\n style={[\n styles.chip,\n { borderColor: type === w.id ? colors.primary : colors.border },\n type === w.id && { backgroundColor: colors.primarySoft },\n ]}\n >\n <Text\n style={[\n styles.chipLabel,\n { color: type === w.id ? colors.primary : colors.text },\n ]}\n >\n {w.label}\n </Text>\n </Pressable>\n ))}\n </View>\n <PrimaryButton label=\"Start session\" onPress={() => onStart(type)} />\n </>\n ) : null}\n </View>\n );\n }\n return (\n <View style={[styles.card, styles.livePanel, { backgroundColor: colors.surface }]}>\n <Text style={[styles.liveValue, { color: colors.text }]}>\n {live.spo2 ?? '--'}\n <Text style={[styles.liveUnit, { color: colors.textMuted }]}>%</Text>\n </Text>\n <Text style={[styles.liveMeta, { color: colors.textMuted }]}>\n Blood oxygen{live.pulse ? ` · pulse ${live.pulse}` : ''}\n </Text>\n {connected ? <PrimaryButton label=\"Save this reading\" onPress={onSave} /> : null}\n </View>\n );\n}\n\nfunction Measure({\n kind,\n deviceId,\n colors,\n units,\n onDone,\n onHealth,\n}: {\n kind: DeviceKindId;\n deviceId?: string;\n colors: Colors;\n units: 'metric' | 'imperial';\n onDone: () => void;\n onHealth: () => void;\n}) {\n const { snapshot, session } = useDeviceSession(kind, deviceId);\n const { state, readings, live, recording, notices } = snapshot;\n const info = deviceKind(kind);\n const now = Date.now();\n const retry = () => {\n void session?.start();\n };\n\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n {state.step === 'starting' ? <ActivityIndicator style={styles.loading} color={colors.primary} /> : null}\n\n {state.step === 'unavailable' ? (\n <Notice colors={colors} tone=\"warning\" icon=\"information-circle\" text={state.reason} />\n ) : null}\n\n {state.step === 'radio' ? (\n <View style={styles.center}>\n <BluetoothPulse colors={colors} active={false} />\n <Text style={[styles.statusTitle, { color: colors.text }]}>{radioCopy(state.radio).title}</Text>\n <Text style={[styles.statusBody, { color: colors.textMuted }]}>{radioCopy(state.radio).body}</Text>\n {state.radio === 'unauthorized' ? (\n <PrimaryButton\n label=\"Open Settings\"\n onPress={() => {\n void Linking.openSettings();\n }}\n />\n ) : null}\n {state.radio === 'off' ? <PrimaryButton label=\"Try again\" onPress={retry} /> : null}\n </View>\n ) : null}\n\n {state.step === 'scanning' ? (\n <>\n <BluetoothPulse colors={colors} active />\n <Text style={[styles.statusTitle, { color: colors.text }]}>\n {deviceId ? 'Looking for your device' : 'Looking for devices nearby'}\n </Text>\n <View style={[styles.card, styles.guidance, { backgroundColor: colors.surface }]}>\n {info.steps.map((line, i) => (\n <View key={line} style={styles.guidanceRow}>\n <View style={[styles.stepDot, { backgroundColor: colors.primarySoft }]}>\n <Text style={[styles.stepNumber, { color: colors.primary }]}>{i + 1}</Text>\n </View>\n <Text style={[styles.guidanceText, { color: colors.text }]}>{line}</Text>\n </View>\n ))}\n </View>\n {state.hint ? (\n <Notice\n colors={colors}\n tone=\"warning\"\n icon=\"information-circle\"\n text={`Nothing yet. ${state.hint} Keep it close to the phone.`}\n />\n ) : null}\n {state.found.length ? (\n <>\n <Text style={[styles.sectionTitle, { color: colors.textMuted }]}>NEARBY</Text>\n <View style={[styles.card, { backgroundColor: colors.surface }]}>\n {state.found.map((f, i) => (\n <FoundRow\n key={f.id}\n found={f}\n first={i === 0}\n colors={colors}\n onPress={() => {\n void session?.pick(f);\n }}\n />\n ))}\n </View>\n </>\n ) : null}\n </>\n ) : null}\n\n {state.step === 'connecting' ? (\n <View style={styles.center}>\n <ActivityIndicator color={colors.primary} size=\"large\" />\n <Text style={[styles.statusTitle, { color: colors.text }]}>Connecting to {state.device.name}</Text>\n <Text style={[styles.statusBody, { color: colors.textMuted }]}>\n If your phone asks to pair, tap Pair.\n </Text>\n </View>\n ) : null}\n\n {state.step === 'connected' && !readings.length && !live ? (\n <View style={styles.center}>\n <BluetoothPulse colors={colors} active connected />\n <Text style={[styles.statusTitle, { color: colors.text }]}>{info.waitingFor}</Text>\n <Text style={[styles.statusBody, { color: colors.textMuted }]}>\n Connected to {state.device.name}.\n </Text>\n </View>\n ) : null}\n\n {(state.step === 'connected' || state.step === 'ended') && live ? (\n <LivePanel\n kind={kind}\n colors={colors}\n live={live}\n units={units}\n recording={recording}\n connected={state.step === 'connected'}\n onStart={(type) => session?.startRecording(type)}\n onStop={() => {\n void session?.stopRecording();\n }}\n onSave={() => {\n void session?.saveLive();\n }}\n />\n ) : null}\n\n {notices.map((n) => (\n <Notice key={n} colors={colors} tone=\"warning\" icon=\"information-circle\" text={n} />\n ))}\n\n {readings.length ? (\n <ReadingsCard title=\"JUST MEASURED\" readings={readings} colors={colors} units={units} now={now} />\n ) : null}\n {readings.length ? <SavedLine colors={colors} onHealth={onHealth} /> : null}\n\n {state.step === 'ended' ? (\n <View style={styles.actions}>\n {!readings.length ? (\n <Text style={[styles.actionHint, { color: colors.textMuted }]}>\n The device went to sleep before it sent a measurement.\n </Text>\n ) : null}\n <PrimaryButton label=\"Done\" onPress={onDone} />\n <SecondaryButton label=\"Measure again\" colors={colors} onPress={() => session?.scan()} />\n </View>\n ) : null}\n\n {state.step === 'connected' && readings.length ? (\n <View style={styles.actions}>\n <PrimaryButton label=\"Done\" onPress={onDone} />\n </View>\n ) : null}\n\n {state.step === 'error' ? (\n <View style={styles.center}>\n <Ionicons name=\"alert-circle\" size={40} color={colors.dangerText} />\n <Text style={[styles.statusTitle, { color: colors.text }]}>{state.message}</Text>\n <PrimaryButton label=\"Try again\" onPress={retry} />\n </View>\n ) : null}\n </ScrollView>\n );\n}\n\n// ------------------------------------------------------------ Device detail\n\nfunction DeviceDetail({\n id,\n colors,\n units,\n onMeasure,\n onForgot,\n}: {\n id: string;\n colors: Colors;\n units: 'metric' | 'imperial';\n onMeasure: (kind: DeviceKindId) => void;\n onForgot: () => void;\n}) {\n const devices = useDevices();\n const device = devices.devices.find((d) => d.id === id);\n const readings = useMemo(\n () =>\n devices.readings\n .filter((r) => r.deviceId === id)\n .sort((a, b) => b.at - a.at)\n .slice(0, 20),\n [devices.readings, id],\n );\n if (!device) return null;\n const forget = () =>\n Alert.alert(`Forget ${device.name}?`, 'Its readings stay in Yantra. To use it again, pair it again.', [\n { text: 'Cancel', style: 'cancel' },\n {\n text: 'Forget',\n style: 'destructive',\n onPress: () => {\n void deviceStore.forget(id).then(onForgot);\n },\n },\n ]);\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n <View style={styles.hero}>\n <KindIcon kind={device.kind} colors={colors} large />\n <Text style={[styles.heroTitle, { color: colors.text }]}>{device.name}</Text>\n <Text style={[styles.heroBody, { color: colors.textMuted }]}>\n {deviceKind(device.kind).title}\n {device.scaleUser ? ` · user ${device.scaleUser.userIndex} on this scale` : ''}\n </Text>\n </View>\n <View style={styles.actions}>\n <PrimaryButton\n label={device.kind === 'heart-rate' ? 'Start a session' : 'Take a reading'}\n onPress={() => onMeasure(device.kind)}\n />\n </View>\n {readings.length ? (\n <ReadingsCard title=\"READINGS\" readings={readings} colors={colors} units={units} now={Date.now()} />\n ) : (\n <Text style={[styles.footnote, { color: colors.textMuted }]}>No readings from this device yet.</Text>\n )}\n <View style={[styles.card, styles.secondaryCard, { backgroundColor: colors.surface }]}>\n <Pressable\n onPress={forget}\n accessibilityRole=\"button\"\n style={({ pressed }) => [styles.row, pressed && { backgroundColor: colors.surfaceMuted }]}\n >\n <Text style={[styles.rowLabelWide, { color: colors.dangerText }]}>Forget this device</Text>\n </Pressable>\n </View>\n </ScrollView>\n );\n}\n\nexport default function DevicesScreen() {\n const navigation = useNavigation<NavigationProp<ParamListBase>>();\n const route = useRoute<RouteProp<Record<string, DevicesParams>, string>>();\n const { isDark } = useAppTheme();\n const colors = mobileColors(isDark);\n const insets = useSafeAreaInsets();\n const devices = useDevices();\n const [stack, setStack] = useState<Step[]>(() =>\n route?.params?.add ? [{ name: 'home' }, { name: 'pick' }] : [{ name: 'home' }],\n );\n const step = stack[stack.length - 1];\n const units = devices.person?.units ?? 'metric';\n\n const orgName = useMemo(() => {\n const raw = (route?.params?.orgName as string | undefined) ?? '';\n return typeof raw === 'string' && raw.trim() ? raw.trim() : null;\n }, [route?.params?.orgName]);\n\n const push = useCallback((next: Step) => setStack((s) => [...s, next]), []);\n const pop = useCallback(() => {\n if (stack.length > 1) {\n setStack((s) => s.slice(0, -1));\n return true;\n }\n if (navigation?.canGoBack?.()) {\n navigation.goBack();\n return true;\n }\n navigation?.dispatch?.(\n CommonActions.navigate({ name: 'MainStack.Account', params: orgName ? { orgName } : undefined }),\n );\n return true;\n }, [stack.length, navigation, orgName]);\n\n useEffect(() => {\n const sub = BackHandler.addEventListener('hardwareBackPress', pop);\n return () => sub.remove();\n }, [pop]);\n\n const openHealth = useCallback(() => {\n navigation?.navigate?.('MainStack.Health', orgName ? { orgName } : undefined);\n }, [navigation, orgName]);\n\n const title = stepTitle(step, devices.devices);\n\n return (\n <SafeAreaView edges={['top', 'left', 'right']} style={[styles.safe, { backgroundColor: colors.bg }]}>\n <View style={[styles.header, { paddingTop: insets.top > 0 ? 4 : 10 }]}>\n <Pressable\n onPress={pop}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Go back\"\n style={({ pressed }) => [\n styles.backCircle,\n { backgroundColor: colors.surface },\n pressed && styles.pressed,\n ]}\n >\n <Ionicons name=\"chevron-back\" size={22} color={colors.text} />\n </Pressable>\n <Text style={[styles.headerTitle, { color: colors.text }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={styles.headerSpacer} />\n </View>\n {step.name === 'home' ? (\n <Home\n colors={colors}\n isDark={isDark}\n units={units}\n onAdd={() => push({ name: 'pick' })}\n onOpen={(id) => push({ name: 'device', id })}\n onHealth={openHealth}\n />\n ) : null}\n {step.name === 'pick' ? (\n <PickKind colors={colors} isDark={isDark} onPick={(kind) => push({ name: 'measure', kind })} />\n ) : null}\n {step.name === 'measure' ? (\n <Measure\n key={`${step.kind}:${step.deviceId ?? ''}`}\n kind={step.kind}\n deviceId={step.deviceId}\n colors={colors}\n units={units}\n onDone={() => setStack([{ name: 'home' }])}\n onHealth={openHealth}\n />\n ) : null}\n {step.name === 'device' ? (\n <DeviceDetail\n id={step.id}\n colors={colors}\n units={units}\n onMeasure={(kind) => push({ name: 'measure', kind, deviceId: step.id })}\n onForgot={() => setStack([{ name: 'home' }])}\n />\n ) : null}\n </SafeAreaView>\n );\n}\n"],"names":["React","_a","_b"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/screens/Devices/index.tsx"],"sourcesContent":["/**\n * Devices: the Bluetooth health devices the person paired, and pairing a new\n * one. One route with its own small stack (home -> pick a kind -> measure, or\n * home -> a device -> measure), so the flow never leaves the screen:\n *\n * - home: the paired devices with their last reading, and \"Add a device\";\n * - pick: which kind of device (scale, blood pressure, heart rate ...);\n * - measure: how to wake it, the devices found nearby, connecting, waiting for\n * a measurement (or live heart rate / oxygen), and what it measured;\n * - device: its readings, take another, forget it.\n *\n * Only devices that speak the Bluetooth SIG health profiles pair here. A brand\n * scale with its own app (RENPHO, Withings ...) keeps that app; it writes to\n * Apple Health / Health Connect and Yantra reads it there, which the home says.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n ActivityIndicator,\n Alert,\n Animated,\n BackHandler,\n Easing,\n Linking,\n Platform,\n Pressable,\n ScrollView,\n StyleSheet,\n View,\n} from 'react-native';\nimport { Ionicons } from '@expo/vector-icons';\nimport { Text } from '@admin-layout/gluestack-ui-mobile';\nimport {\n CommonActions,\n useNavigation,\n useRoute,\n type NavigationProp,\n type ParamListBase,\n type RouteProp,\n} from '@react-navigation/native';\nimport { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { mobileColors, mobileTokens } from '../../theme/mobileTokens';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\nimport { DEVICE_KINDS, deviceKind, type DeviceKindId } from '../../features/devices/catalog';\nimport { deviceStore, platformWriter, useDeviceSession, useDevices } from '../../features/devices/devices';\nimport { describeReading, type DeviceReading } from '../../features/devices/readings';\nimport type { PairedDevice } from '../../features/devices/deviceStore';\nimport type { FoundDevice, RadioState } from '../../features/devices/link';\nimport { useHealthSync } from '../../features/health/healthSync';\n\ntype Colors = ReturnType<typeof mobileColors>;\ntype Glyph = keyof typeof Ionicons.glyphMap;\n/** `add`: open straight on \"Which device\" (the Fitness page's Add a device). */\ntype DevicesParams = { orgName?: string; add?: boolean } | undefined;\ntype Step =\n | { name: 'home' }\n | { name: 'pick' }\n | { name: 'measure'; kind: DeviceKindId; deviceId?: string }\n | { name: 'device'; id: string };\n\nconst IS_IOS = Platform.OS === 'ios';\n/** The app's surfaces are white on a white page in light mode; an edge keeps each card readable as one. */\nconst CARD_EDGE = 'rgba(148,163,184,0.3)';\nconst STORE_NAME = IS_IOS ? 'Apple Health' : 'Health Connect';\nconst WORKOUT_TYPES: Array<{ id: string; label: string }> = [\n { id: 'run', label: 'Run' },\n { id: 'walk', label: 'Walk' },\n { id: 'cycle', label: 'Ride' },\n { id: 'strength', label: 'Strength' },\n { id: 'hiit', label: 'HIIT' },\n { id: 'other', label: 'Other' },\n];\n\nconst styles = StyleSheet.create({\n safe: { flex: 1 },\n header: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingBottom: 8, minHeight: 52 },\n backCircle: {\n width: 40,\n height: 40,\n borderRadius: 20,\n alignItems: 'center',\n justifyContent: 'center',\n ...mobileTokens.shadow.card,\n },\n headerTitle: { flex: 1, textAlign: 'center', fontSize: 17, fontWeight: '600', marginHorizontal: 8 },\n headerSpacer: { width: 40, height: 40 },\n pressed: { opacity: 0.72 },\n loading: { marginTop: 48 },\n scroll: { paddingHorizontal: 16, paddingBottom: 40 },\n hero: { alignItems: 'center', paddingTop: 8, paddingBottom: 16, gap: 10 },\n heroIcon: { width: 64, height: 64, borderRadius: 32, alignItems: 'center', justifyContent: 'center' },\n heroTitle: { fontSize: 20, fontWeight: '700', textAlign: 'center' },\n heroBody: { fontSize: 15, lineHeight: 21, textAlign: 'center', paddingHorizontal: 8 },\n card: { borderRadius: 16, overflow: 'hidden', borderWidth: 1, borderColor: CARD_EDGE },\n secondaryCard: { marginTop: 20 },\n sectionTitle: {\n fontSize: 13,\n fontWeight: '600',\n letterSpacing: 0.4,\n marginTop: 24,\n marginBottom: 8,\n marginLeft: 16,\n },\n row: { flexDirection: 'row', alignItems: 'center', minHeight: 52, paddingHorizontal: 16, gap: 12 },\n rowLabelWide: { flex: 1, fontSize: 16 },\n rowLine: { height: StyleSheet.hairlineWidth, marginLeft: 16 },\n deviceRow: { flexDirection: 'row', alignItems: 'center', minHeight: 64, paddingHorizontal: 16, gap: 12 },\n deviceText: { flex: 1, minWidth: 0 },\n deviceName: { fontSize: 16, fontWeight: '600' },\n deviceMeta: { fontSize: 14, marginTop: 2 },\n kindIcon: { alignItems: 'center', justifyContent: 'center' },\n question: { fontSize: 22, fontWeight: '700', textAlign: 'center', marginTop: 8, marginBottom: 20, lineHeight: 28 },\n kindList: { gap: 10 },\n kindCard: {\n flexDirection: 'row',\n alignItems: 'center',\n borderRadius: 16,\n padding: 14,\n gap: 14,\n borderWidth: 1,\n borderColor: CARD_EDGE,\n },\n kindTitle: { fontSize: 16, fontWeight: '600' },\n center: { alignItems: 'center', paddingTop: 24, gap: 12 },\n statusTitle: { fontSize: 19, fontWeight: '700', textAlign: 'center', marginTop: 4 },\n statusBody: { fontSize: 15, lineHeight: 21, textAlign: 'center', paddingHorizontal: 8 },\n guidance: { marginTop: 16, paddingVertical: 8 },\n guidanceRow: { flexDirection: 'row', alignItems: 'flex-start', paddingHorizontal: 16, paddingVertical: 8, gap: 12 },\n stepDot: { width: 24, height: 24, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginTop: 1 },\n stepNumber: { fontSize: 13, fontWeight: '700' },\n guidanceText: { flex: 1, fontSize: 15, lineHeight: 22 },\n pulseBox: {\n alignSelf: 'center',\n width: 120,\n height: 120,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: 16,\n },\n pulseRing: { position: 'absolute', width: 64, height: 64, borderRadius: 32 },\n pulseCore: { width: 64, height: 64, borderRadius: 32, alignItems: 'center', justifyContent: 'center' },\n signal: { flexDirection: 'row', alignItems: 'flex-end', gap: 2, height: 16 },\n signalBar: { width: 4, borderRadius: 1 },\n livePanel: { alignItems: 'center', padding: 20, marginTop: 16, gap: 12 },\n liveValue: { fontSize: 56, fontWeight: '700', fontVariant: ['tabular-nums'] },\n liveUnit: { fontSize: 18, fontWeight: '500' },\n liveMeta: { fontSize: 15, fontVariant: ['tabular-nums'] },\n chips: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'center', gap: 8 },\n chip: { borderWidth: 1, borderRadius: 999, paddingHorizontal: 14, paddingVertical: 8 },\n chipLabel: { fontSize: 14, fontWeight: '600' },\n readingRow: { paddingHorizontal: 16, paddingVertical: 12, gap: 2 },\n readingValue: { fontSize: 16, fontWeight: '600' },\n readingWhen: { fontSize: 14 },\n readingNote: { fontSize: 14, marginTop: 2 },\n savedLine: { flexDirection: 'row', alignItems: 'center', gap: 8, marginTop: 12, marginHorizontal: 4 },\n savedBlock: { marginTop: 12, gap: 10 },\n savedText: { flex: 1, fontSize: 14, lineHeight: 20 },\n notice: { flexDirection: 'row', borderRadius: 14, padding: 12, marginTop: 12, gap: 8 },\n noticeIcon: { marginTop: 1 },\n noticeText: { flex: 1, fontSize: 14, lineHeight: 20 },\n actions: { marginTop: 20, gap: 10, alignItems: 'stretch' },\n actionHint: { fontSize: 15, lineHeight: 21, textAlign: 'center' },\n primary: {\n backgroundColor: mobileTokens.color.primary,\n borderRadius: 14,\n minHeight: 50,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: 18,\n alignSelf: 'stretch',\n },\n primaryLabel: { color: '#fff', fontSize: 16, fontWeight: '600' },\n secondary: {\n borderRadius: 14,\n minHeight: 48,\n alignItems: 'center',\n justifyContent: 'center',\n borderWidth: 1,\n paddingHorizontal: 18,\n },\n secondaryLabel: { fontSize: 16, fontWeight: '600' },\n footnote: { fontSize: 13, lineHeight: 18, marginTop: 16, marginHorizontal: 16 },\n linkRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n marginTop: 10,\n marginHorizontal: 16,\n alignSelf: 'flex-start',\n },\n link: { fontSize: 14, fontWeight: '600' },\n});\n\nfunction stepTitle(step: Step, paired: PairedDevice[]): string {\n switch (step.name) {\n case 'pick':\n return 'Add a device';\n case 'measure':\n return deviceKind(step.kind).title;\n case 'device':\n return paired.find((d) => d.id === step.id)?.name ?? 'Device';\n default:\n return 'Devices';\n }\n}\n\n/** What to say when the radio is not ready to scan. */\nfunction radioCopy(radio: RadioState): { title: string; body: string } {\n if (radio === 'off') return { title: 'Turn on Bluetooth', body: 'Yantra finds your device over Bluetooth.' };\n if (radio === 'unauthorized') {\n return {\n title: 'Allow Bluetooth for Yantra',\n body: 'Yantra needs Bluetooth to find and read your device. Turn it on for Yantra in Settings.',\n };\n }\n return { title: 'This phone has no Bluetooth Yantra can use', body: '' };\n}\n\n/** Bars for the signal strength of a device found nearby. */\nfunction signalBars(rssi: number | undefined): number {\n if (rssi === undefined) return 1;\n if (rssi > -60) return 3;\n if (rssi > -80) return 2;\n return 1;\n}\n\nfunction whenLabel(at: number, now: number): string {\n const d = new Date(at);\n const time = d.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });\n const startOf = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();\n const days = Math.round((startOf(new Date(now)) - startOf(d)) / 86_400_000);\n if (days === 0) return `Today, ${time}`;\n if (days === 1) return `Yesterday, ${time}`;\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\n/** \"Today, 7:31 AM\" wraps as one piece, never with \"AM\" alone on the next line. */\nfunction keepTogether(text: string): string {\n return text.replace(/\\s/g, '\\u00a0');\n}\n\nfunction clockOf(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${String(s).padStart(2, '0')}`;\n}\n\n// ------------------------------------------------------------------ Pieces\n\nfunction KindIcon({ kind, colors, large }: { kind: DeviceKindId; colors: Colors; large?: boolean }) {\n const size = large ? 48 : 36;\n return (\n <View\n style={[\n styles.kindIcon,\n { width: size, height: size, borderRadius: size / 2, backgroundColor: colors.primarySoft },\n ]}\n >\n <Ionicons name={deviceKind(kind).icon as Glyph} size={large ? 24 : 18} color={colors.primary} />\n </View>\n );\n}\n\n/** The Bluetooth mark with a ring that breathes while scanning. */\nfunction BluetoothPulse({ colors, active, connected }: { colors: Colors; active: boolean; connected?: boolean }) {\n const pulse = useRef(new Animated.Value(0)).current;\n useEffect(() => {\n if (!active) return undefined;\n const loop = Animated.loop(\n Animated.timing(pulse, {\n toValue: 1,\n duration: 1600,\n easing: Easing.out(Easing.ease),\n useNativeDriver: true,\n }),\n );\n loop.start();\n return () => loop.stop();\n }, [active, pulse]);\n const scale = pulse.interpolate({ inputRange: [0, 1], outputRange: [1, 1.9] });\n const opacity = pulse.interpolate({ inputRange: [0, 1], outputRange: [0.45, 0] });\n return (\n <View style={styles.pulseBox} accessibilityElementsHidden importantForAccessibility=\"no-hide-descendants\">\n {active ? (\n <Animated.View\n style={[styles.pulseRing, { backgroundColor: colors.primary, opacity, transform: [{ scale }] }]}\n />\n ) : null}\n <View style={[styles.pulseCore, { backgroundColor: connected ? colors.successText : colors.primary }]}>\n <Ionicons name={connected ? 'checkmark' : 'bluetooth'} size={28} color=\"#fff\" />\n </View>\n </View>\n );\n}\n\nfunction Notice({\n colors,\n tone,\n icon,\n text,\n}: {\n colors: Colors;\n tone: 'warning' | 'danger';\n icon: Glyph;\n text: string;\n}) {\n const bg = tone === 'danger' ? colors.dangerSoft : colors.warningSoft;\n const fg = tone === 'danger' ? colors.dangerText : colors.warningText;\n return (\n <View style={[styles.notice, { backgroundColor: bg }]} accessibilityRole=\"alert\">\n <Ionicons name={icon} size={18} color={fg} style={styles.noticeIcon} />\n <Text style={[styles.noticeText, { color: fg }]}>{text}</Text>\n </View>\n );\n}\n\nfunction PrimaryButton({ label, onPress }: { label: string; onPress: () => void }) {\n return (\n <Pressable\n onPress={onPress}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n style={({ pressed }) => [styles.primary, pressed && styles.pressed]}\n >\n <Text style={styles.primaryLabel}>{label}</Text>\n </Pressable>\n );\n}\n\nfunction SecondaryButton({ label, onPress, colors }: { label: string; onPress: () => void; colors: Colors }) {\n return (\n <Pressable\n onPress={onPress}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n style={({ pressed }) => [\n styles.secondary,\n { borderColor: colors.border, backgroundColor: colors.surface },\n pressed && styles.pressed,\n ]}\n >\n <Text style={[styles.secondaryLabel, { color: colors.text }]}>{label}</Text>\n </Pressable>\n );\n}\n\nfunction ReadingsCard({\n title,\n readings,\n colors,\n units,\n now,\n}: {\n title: string;\n readings: DeviceReading[];\n colors: Colors;\n units: 'metric' | 'imperial';\n now: number;\n}) {\n return (\n <>\n <Text style={[styles.sectionTitle, { color: colors.textMuted }]}>{title}</Text>\n <View style={[styles.card, { backgroundColor: colors.surface }]}>\n {readings.map((r, i) => (\n <React.Fragment key={r.id}>\n {i > 0 ? <View style={[styles.rowLine, { backgroundColor: colors.border }]} /> : null}\n <View style={styles.readingRow}>\n <Text style={[styles.readingValue, { color: colors.text }]}>\n {describeReading(r, units)}\n </Text>\n <Text style={[styles.readingWhen, { color: colors.textMuted }]}>\n {whenLabel(r.at, now)}\n </Text>\n {r.kind === 'blood-pressure' && r.problems?.length ? (\n <Text style={[styles.readingNote, { color: colors.warningText }]}>\n {r.problems.join(' ')}\n </Text>\n ) : null}\n </View>\n </React.Fragment>\n ))}\n </View>\n </>\n );\n}\n\n/** Where the readings went, and how to have them saved to the health store too. */\nfunction SavedLine({ colors, onHealth }: { colors: Colors; onHealth: () => void }) {\n const health = useHealthSync();\n const [asked, setAsked] = useState<boolean | null>(null);\n useEffect(() => {\n let live = true;\n void platformWriter().then(async (w) => {\n const a = w ? await w.asked().catch(() => true) : true;\n if (live) setAsked(a);\n });\n return () => {\n live = false;\n };\n }, [health.sync.connected]);\n const allowSaving = async () => {\n const w = await platformWriter();\n if (!w) return;\n await w.requestAccess().catch(() => undefined);\n setAsked(true);\n void deviceStore.flush();\n };\n if (!health.sync.connected) {\n return (\n <Pressable\n onPress={onHealth}\n accessibilityRole=\"link\"\n style={({ pressed }) => [styles.savedLine, pressed && styles.pressed]}\n >\n <Ionicons name=\"checkmark-circle\" size={18} color={colors.successText} />\n <Text style={[styles.savedText, { color: colors.textMuted }]}>\n Saved for your coach. <Text style={{ color: colors.primary }}>Connect {STORE_NAME}</Text> to keep it\n there too.\n </Text>\n </Pressable>\n );\n }\n if (asked === false) {\n return (\n <View style={styles.savedBlock}>\n <Text style={[styles.savedText, { color: colors.textMuted }]}>Saved for your coach.</Text>\n <SecondaryButton\n label={`Also save to ${STORE_NAME}`}\n colors={colors}\n onPress={() => {\n void allowSaving();\n }}\n />\n </View>\n );\n }\n return (\n <View style={styles.savedLine}>\n <Ionicons name=\"checkmark-circle\" size={18} color={colors.successText} />\n <Text style={[styles.savedText, { color: colors.textMuted }]}>\n Saved for your coach and to {STORE_NAME}.\n </Text>\n </View>\n );\n}\n\nfunction FoundRow({\n found,\n first,\n colors,\n onPress,\n}: {\n found: FoundDevice;\n first: boolean;\n colors: Colors;\n onPress: () => void;\n}) {\n const bars = signalBars(found.rssi);\n return (\n <>\n {!first ? <View style={[styles.rowLine, { backgroundColor: colors.border }]} /> : null}\n <Pressable\n onPress={onPress}\n accessibilityRole=\"button\"\n accessibilityLabel={`Connect ${found.name}`}\n style={({ pressed }) => [styles.deviceRow, pressed && { backgroundColor: colors.surfaceMuted }]}\n >\n {found.kind ? (\n <KindIcon kind={found.kind} colors={colors} />\n ) : (\n <Ionicons name=\"bluetooth\" size={22} color={colors.primary} />\n )}\n <Text style={[styles.deviceName, styles.deviceText, { color: colors.text }]} numberOfLines={1}>\n {found.name}\n </Text>\n <View style={styles.signal} accessibilityLabel={`Signal ${bars} of 3`}>\n {[1, 2, 3].map((b) => (\n <View\n key={b}\n style={[\n styles.signalBar,\n { height: 4 + b * 4, backgroundColor: b <= bars ? colors.primary : colors.border },\n ]}\n />\n ))}\n </View>\n </Pressable>\n </>\n );\n}\n\n// ------------------------------------------------------------------- Home\n\nfunction Home({\n colors,\n isDark,\n units,\n onAdd,\n onOpen,\n onHealth,\n}: {\n colors: Colors;\n isDark: boolean;\n units: 'metric' | 'imperial';\n onAdd: () => void;\n onOpen: (id: string) => void;\n onHealth: () => void;\n}) {\n const devices = useDevices();\n const now = Date.now();\n if (!devices.loaded) return <ActivityIndicator style={styles.loading} color={colors.primary} />;\n const latestOf = (d: PairedDevice) =>\n devices.readings\n .filter((r) => r.deviceId === d.id)\n .reduce<DeviceReading | undefined>((a, b) => (!a || b.at > a.at ? b : a), undefined);\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n {devices.devices.length ? (\n <>\n <Text style={[styles.sectionTitle, { color: colors.textMuted }]}>MY DEVICES</Text>\n <View style={[styles.card, { backgroundColor: colors.surface }]}>\n {devices.devices.map((d, i) => {\n const latest = latestOf(d);\n return (\n <React.Fragment key={d.id}>\n {i > 0 ? (\n <View style={[styles.rowLine, { backgroundColor: colors.border }]} />\n ) : null}\n <Pressable\n onPress={() => onOpen(d.id)}\n accessibilityRole=\"button\"\n accessibilityLabel={d.name}\n style={({ pressed }) => [\n styles.deviceRow,\n pressed && { backgroundColor: colors.surfaceMuted },\n ]}\n >\n <KindIcon kind={d.kind} colors={colors} />\n <View style={styles.deviceText}>\n <Text style={[styles.deviceName, { color: colors.text }]} numberOfLines={1}>\n {d.name}\n </Text>\n <Text\n style={[styles.deviceMeta, { color: colors.textMuted }]}\n numberOfLines={2}\n >\n {latest\n ? `${describeReading(latest, units)} · ${keepTogether(whenLabel(latest.at, now))}`\n : 'No readings yet'}\n </Text>\n </View>\n <Ionicons\n name=\"chevron-forward\"\n size={16}\n color={isDark ? '#64748b' : '#c4c4c4'}\n />\n </Pressable>\n </React.Fragment>\n );\n })}\n </View>\n </>\n ) : (\n <View style={styles.hero}>\n <View style={[styles.heroIcon, { backgroundColor: colors.primarySoft }]}>\n <Ionicons name=\"bluetooth\" size={30} color={colors.primary} />\n </View>\n <Text style={[styles.heroTitle, { color: colors.text }]}>Connect a device</Text>\n <Text style={[styles.heroBody, { color: colors.textMuted }]}>\n Pair a scale, blood-pressure monitor, heart-rate strap, pulse oximeter, thermometer or glucose\n meter. Each reading goes to your coach, and to {STORE_NAME} when you connected it.\n </Text>\n </View>\n )}\n {devices.lastError && devices.pendingDates.length ? (\n <Notice\n colors={colors}\n tone=\"warning\"\n icon=\"cloud-offline-outline\"\n text={`Readings are kept on this phone and sent when Yantra can reach your coach. ${devices.lastError}`}\n />\n ) : null}\n <View style={styles.actions}>\n <PrimaryButton label=\"Add a device\" onPress={onAdd} />\n </View>\n <Text style={[styles.footnote, { color: colors.textMuted }]}>\n Devices that use the Bluetooth health standards pair here. For a brand scale with its own app, such as\n RENPHO or Withings, turn on its {STORE_NAME} sync; Yantra reads it there.\n </Text>\n <Pressable\n onPress={onHealth}\n accessibilityRole=\"link\"\n style={({ pressed }) => [styles.linkRow, pressed && styles.pressed]}\n >\n <Text style={[styles.link, { color: colors.primary }]}>{STORE_NAME} settings</Text>\n <Ionicons name=\"chevron-forward\" size={14} color={colors.primary} />\n </Pressable>\n </ScrollView>\n );\n}\n\n// --------------------------------------------------------------- Pick kind\n\nfunction PickKind({\n colors,\n isDark,\n onPick,\n}: {\n colors: Colors;\n isDark: boolean;\n onPick: (kind: DeviceKindId) => void;\n}) {\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n <Text style={[styles.question, { color: colors.text }]}>Which device do you want to connect?</Text>\n <View style={styles.kindList}>\n {DEVICE_KINDS.map((k) => (\n <Pressable\n key={k.id}\n onPress={() => onPick(k.id)}\n accessibilityRole=\"button\"\n accessibilityLabel={k.title}\n style={({ pressed }) => [\n styles.kindCard,\n { backgroundColor: colors.surface },\n pressed && { backgroundColor: colors.surfaceMuted },\n ]}\n >\n <KindIcon kind={k.id} colors={colors} large />\n <View style={styles.deviceText}>\n <Text style={[styles.kindTitle, { color: colors.text }]}>{k.title}</Text>\n <Text style={[styles.deviceMeta, { color: colors.textMuted }]}>{k.subtitle}</Text>\n </View>\n <Ionicons name=\"chevron-forward\" size={16} color={isDark ? '#64748b' : '#c4c4c4'} />\n </Pressable>\n ))}\n </View>\n </ScrollView>\n );\n}\n\n// ----------------------------------------------------------------- Measure\n\nfunction LivePanel({\n kind,\n colors,\n live,\n recording,\n connected,\n onStart,\n onStop,\n onSave,\n}: {\n kind: DeviceKindId;\n colors: Colors;\n live: { bpm?: number; spo2?: number; pulse?: number };\n recording?: { startedAt: number; workoutType: string; avgHr?: number; maxHr?: number };\n connected: boolean;\n onStart: (type: string) => void;\n onStop: () => void;\n onSave: () => void;\n}) {\n const [type, setType] = useState('run');\n const [, tick] = useState(0);\n useEffect(() => {\n if (!recording) return undefined;\n const t = setInterval(() => tick((n) => n + 1), 1000);\n return () => clearInterval(t);\n }, [recording]);\n if (kind === 'heart-rate') {\n const elapsed = recording ? Math.max(0, Math.floor((Date.now() - recording.startedAt) / 1000)) : 0;\n return (\n <View style={[styles.card, styles.livePanel, { backgroundColor: colors.surface }]}>\n <Text\n style={[styles.liveValue, { color: colors.text }]}\n accessibilityLabel={`Heart rate ${live.bpm ?? 0} beats per minute`}\n >\n {live.bpm ?? '--'}\n <Text style={[styles.liveUnit, { color: colors.textMuted }]}> bpm</Text>\n </Text>\n {recording ? (\n <>\n <Text style={[styles.liveMeta, { color: colors.textMuted }]}>\n {clockOf(elapsed)} · average {recording.avgHr ?? '--'} · max {recording.maxHr ?? '--'}\n </Text>\n <PrimaryButton label=\"Stop and save\" onPress={onStop} />\n </>\n ) : null}\n {!recording && connected ? (\n <>\n <View style={styles.chips}>\n {WORKOUT_TYPES.map((w) => (\n <Pressable\n key={w.id}\n onPress={() => setType(w.id)}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: type === w.id }}\n style={[\n styles.chip,\n { borderColor: type === w.id ? colors.primary : colors.border },\n type === w.id && { backgroundColor: colors.primarySoft },\n ]}\n >\n <Text\n style={[\n styles.chipLabel,\n { color: type === w.id ? colors.primary : colors.text },\n ]}\n >\n {w.label}\n </Text>\n </Pressable>\n ))}\n </View>\n <PrimaryButton label=\"Start session\" onPress={() => onStart(type)} />\n </>\n ) : null}\n </View>\n );\n }\n return (\n <View style={[styles.card, styles.livePanel, { backgroundColor: colors.surface }]}>\n <Text style={[styles.liveValue, { color: colors.text }]}>\n {live.spo2 ?? '--'}\n <Text style={[styles.liveUnit, { color: colors.textMuted }]}>%</Text>\n </Text>\n <Text style={[styles.liveMeta, { color: colors.textMuted }]}>\n Blood oxygen{live.pulse ? ` · pulse ${live.pulse}` : ''}\n </Text>\n {connected ? <PrimaryButton label=\"Save this reading\" onPress={onSave} /> : null}\n </View>\n );\n}\n\nfunction Measure({\n kind,\n deviceId,\n colors,\n units,\n onDone,\n onHealth,\n}: {\n kind: DeviceKindId;\n deviceId?: string;\n colors: Colors;\n units: 'metric' | 'imperial';\n onDone: () => void;\n onHealth: () => void;\n}) {\n const { snapshot, session } = useDeviceSession(kind, deviceId);\n const { state, readings, live, recording, notices } = snapshot;\n const info = deviceKind(kind);\n const now = Date.now();\n const retry = () => {\n void session?.start();\n };\n\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n {state.step === 'starting' ? <ActivityIndicator style={styles.loading} color={colors.primary} /> : null}\n\n {state.step === 'unavailable' ? (\n <Notice colors={colors} tone=\"warning\" icon=\"information-circle\" text={state.reason} />\n ) : null}\n\n {state.step === 'radio' ? (\n <View style={styles.center}>\n <BluetoothPulse colors={colors} active={false} />\n <Text style={[styles.statusTitle, { color: colors.text }]}>{radioCopy(state.radio).title}</Text>\n <Text style={[styles.statusBody, { color: colors.textMuted }]}>{radioCopy(state.radio).body}</Text>\n {state.radio === 'unauthorized' ? (\n <PrimaryButton\n label=\"Open Settings\"\n onPress={() => {\n void Linking.openSettings();\n }}\n />\n ) : null}\n {state.radio === 'off' ? <PrimaryButton label=\"Try again\" onPress={retry} /> : null}\n </View>\n ) : null}\n\n {state.step === 'scanning' ? (\n <>\n <BluetoothPulse colors={colors} active />\n <Text style={[styles.statusTitle, { color: colors.text }]}>\n {deviceId ? 'Looking for your device' : 'Looking for devices nearby'}\n </Text>\n <View style={[styles.card, styles.guidance, { backgroundColor: colors.surface }]}>\n {info.steps.map((line, i) => (\n <View key={line} style={styles.guidanceRow}>\n <View style={[styles.stepDot, { backgroundColor: colors.primarySoft }]}>\n <Text style={[styles.stepNumber, { color: colors.primary }]}>{i + 1}</Text>\n </View>\n <Text style={[styles.guidanceText, { color: colors.text }]}>{line}</Text>\n </View>\n ))}\n </View>\n {state.hint ? (\n <Notice\n colors={colors}\n tone=\"warning\"\n icon=\"information-circle\"\n text={`Nothing yet. ${state.hint} Keep it close to the phone.`}\n />\n ) : null}\n {state.found.length ? (\n <>\n <Text style={[styles.sectionTitle, { color: colors.textMuted }]}>NEARBY</Text>\n <View style={[styles.card, { backgroundColor: colors.surface }]}>\n {state.found.map((f, i) => (\n <FoundRow\n key={f.id}\n found={f}\n first={i === 0}\n colors={colors}\n onPress={() => {\n void session?.pick(f);\n }}\n />\n ))}\n </View>\n </>\n ) : null}\n </>\n ) : null}\n\n {state.step === 'connecting' ? (\n <View style={styles.center}>\n <ActivityIndicator color={colors.primary} size=\"large\" />\n <Text style={[styles.statusTitle, { color: colors.text }]}>Connecting to {state.device.name}</Text>\n <Text style={[styles.statusBody, { color: colors.textMuted }]}>\n If your phone asks to pair, tap Pair.\n </Text>\n </View>\n ) : null}\n\n {state.step === 'connected' && !readings.length && !live ? (\n <View style={styles.center}>\n <BluetoothPulse colors={colors} active connected />\n <Text style={[styles.statusTitle, { color: colors.text }]}>{info.waitingFor}</Text>\n <Text style={[styles.statusBody, { color: colors.textMuted }]}>\n Connected to {state.device.name}.\n </Text>\n </View>\n ) : null}\n\n {(state.step === 'connected' || state.step === 'ended') && live ? (\n <LivePanel\n kind={kind}\n colors={colors}\n live={live}\n recording={recording}\n connected={state.step === 'connected'}\n onStart={(type) => session?.startRecording(type)}\n onStop={() => {\n void session?.stopRecording();\n }}\n onSave={() => {\n void session?.saveLive();\n }}\n />\n ) : null}\n\n {notices.map((n) => (\n <Notice key={n} colors={colors} tone=\"warning\" icon=\"information-circle\" text={n} />\n ))}\n\n {readings.length ? (\n <ReadingsCard title=\"JUST MEASURED\" readings={readings} colors={colors} units={units} now={now} />\n ) : null}\n {readings.length ? <SavedLine colors={colors} onHealth={onHealth} /> : null}\n\n {state.step === 'ended' ? (\n <View style={styles.actions}>\n {!readings.length ? (\n <Text style={[styles.actionHint, { color: colors.textMuted }]}>\n The device went to sleep before it sent a measurement.\n </Text>\n ) : null}\n <PrimaryButton label=\"Done\" onPress={onDone} />\n <SecondaryButton label=\"Measure again\" colors={colors} onPress={() => session?.scan()} />\n </View>\n ) : null}\n\n {state.step === 'connected' && readings.length ? (\n <View style={styles.actions}>\n <PrimaryButton label=\"Done\" onPress={onDone} />\n </View>\n ) : null}\n\n {state.step === 'error' ? (\n <View style={styles.center}>\n <Ionicons name=\"alert-circle\" size={40} color={colors.dangerText} />\n <Text style={[styles.statusTitle, { color: colors.text }]}>{state.message}</Text>\n <PrimaryButton label=\"Try again\" onPress={retry} />\n </View>\n ) : null}\n </ScrollView>\n );\n}\n\n// ------------------------------------------------------------ Device detail\n\nfunction DeviceDetail({\n id,\n colors,\n units,\n onMeasure,\n onForgot,\n}: {\n id: string;\n colors: Colors;\n units: 'metric' | 'imperial';\n onMeasure: (kind: DeviceKindId) => void;\n onForgot: () => void;\n}) {\n const devices = useDevices();\n const device = devices.devices.find((d) => d.id === id);\n const readings = useMemo(\n () =>\n devices.readings\n .filter((r) => r.deviceId === id)\n .sort((a, b) => b.at - a.at)\n .slice(0, 20),\n [devices.readings, id],\n );\n if (!device) return null;\n const forget = () =>\n Alert.alert(`Forget ${device.name}?`, 'Its readings stay in Yantra. To use it again, pair it again.', [\n { text: 'Cancel', style: 'cancel' },\n {\n text: 'Forget',\n style: 'destructive',\n onPress: () => {\n void deviceStore.forget(id).then(onForgot);\n },\n },\n ]);\n return (\n <ScrollView contentContainerStyle={styles.scroll}>\n <View style={styles.hero}>\n <KindIcon kind={device.kind} colors={colors} large />\n <Text style={[styles.heroTitle, { color: colors.text }]}>{device.name}</Text>\n <Text style={[styles.heroBody, { color: colors.textMuted }]}>\n {deviceKind(device.kind).title}\n {device.scaleUser ? ` · user ${device.scaleUser.userIndex} on this scale` : ''}\n </Text>\n </View>\n <View style={styles.actions}>\n <PrimaryButton\n label={device.kind === 'heart-rate' ? 'Start a session' : 'Take a reading'}\n onPress={() => onMeasure(device.kind)}\n />\n </View>\n {readings.length ? (\n <ReadingsCard title=\"READINGS\" readings={readings} colors={colors} units={units} now={Date.now()} />\n ) : (\n <Text style={[styles.footnote, { color: colors.textMuted }]}>No readings from this device yet.</Text>\n )}\n <View style={[styles.card, styles.secondaryCard, { backgroundColor: colors.surface }]}>\n <Pressable\n onPress={forget}\n accessibilityRole=\"button\"\n style={({ pressed }) => [styles.row, pressed && { backgroundColor: colors.surfaceMuted }]}\n >\n <Text style={[styles.rowLabelWide, { color: colors.dangerText }]}>Forget this device</Text>\n </Pressable>\n </View>\n </ScrollView>\n );\n}\n\nexport default function DevicesScreen() {\n const navigation = useNavigation<NavigationProp<ParamListBase>>();\n const route = useRoute<RouteProp<Record<string, DevicesParams>, string>>();\n const { isDark } = useAppTheme();\n const colors = mobileColors(isDark);\n const insets = useSafeAreaInsets();\n const devices = useDevices();\n const [stack, setStack] = useState<Step[]>(() =>\n route?.params?.add ? [{ name: 'home' }, { name: 'pick' }] : [{ name: 'home' }],\n );\n const step = stack[stack.length - 1];\n const units = devices.person?.units ?? 'metric';\n\n const orgName = useMemo(() => {\n const raw = (route?.params?.orgName as string | undefined) ?? '';\n return typeof raw === 'string' && raw.trim() ? raw.trim() : null;\n }, [route?.params?.orgName]);\n\n const push = useCallback((next: Step) => setStack((s) => [...s, next]), []);\n const pop = useCallback(() => {\n if (stack.length > 1) {\n setStack((s) => s.slice(0, -1));\n return true;\n }\n if (navigation?.canGoBack?.()) {\n navigation.goBack();\n return true;\n }\n navigation?.dispatch?.(\n CommonActions.navigate({ name: 'MainStack.Account', params: orgName ? { orgName } : undefined }),\n );\n return true;\n }, [stack.length, navigation, orgName]);\n\n useEffect(() => {\n const sub = BackHandler.addEventListener('hardwareBackPress', pop);\n return () => sub.remove();\n }, [pop]);\n\n const openHealth = useCallback(() => {\n navigation?.navigate?.('MainStack.Health', orgName ? { orgName } : undefined);\n }, [navigation, orgName]);\n\n const title = stepTitle(step, devices.devices);\n\n return (\n <SafeAreaView edges={['top', 'left', 'right']} style={[styles.safe, { backgroundColor: colors.bg }]}>\n <View style={[styles.header, { paddingTop: insets.top > 0 ? 4 : 10 }]}>\n <Pressable\n onPress={pop}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Go back\"\n style={({ pressed }) => [\n styles.backCircle,\n { backgroundColor: colors.surface },\n pressed && styles.pressed,\n ]}\n >\n <Ionicons name=\"chevron-back\" size={22} color={colors.text} />\n </Pressable>\n <Text style={[styles.headerTitle, { color: colors.text }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={styles.headerSpacer} />\n </View>\n {step.name === 'home' ? (\n <Home\n colors={colors}\n isDark={isDark}\n units={units}\n onAdd={() => push({ name: 'pick' })}\n onOpen={(id) => push({ name: 'device', id })}\n onHealth={openHealth}\n />\n ) : null}\n {step.name === 'pick' ? (\n <PickKind colors={colors} isDark={isDark} onPick={(kind) => push({ name: 'measure', kind })} />\n ) : null}\n {step.name === 'measure' ? (\n <Measure\n key={`${step.kind}:${step.deviceId ?? ''}`}\n kind={step.kind}\n deviceId={step.deviceId}\n colors={colors}\n units={units}\n onDone={() => setStack([{ name: 'home' }])}\n onHealth={openHealth}\n />\n ) : null}\n {step.name === 'device' ? (\n <DeviceDetail\n id={step.id}\n colors={colors}\n units={units}\n onMeasure={(kind) => push({ name: 'measure', kind, deviceId: step.id })}\n onForgot={() => setStack([{ name: 'home' }])}\n />\n ) : null}\n </SafeAreaView>\n );\n}\n"],"names":["React","_a","_b"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminide-stack/yantra-mobile",
|
|
3
|
-
"version": "12.0.
|
|
3
|
+
"version": "12.0.141-alpha.1",
|
|
4
4
|
"description": "Sample core for higher packages to depend on",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "CDMBase LLC",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"uuid": "^9.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"common": "12.0.
|
|
30
|
+
"common": "12.0.141-alpha.1",
|
|
31
31
|
"libphonenumber-js": "^1.13.3"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@messenger-box/platform-mobile": "*",
|
|
46
46
|
"@react-native-async-storage/async-storage": "*",
|
|
47
47
|
"@react-navigation/native": "*",
|
|
48
|
-
"common": "12.0.139",
|
|
48
|
+
"common": "12.0.139-alpha.0",
|
|
49
49
|
"expo-background-task": "*",
|
|
50
50
|
"expo-constants": "*",
|
|
51
51
|
"expo-secure-store": "*",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"typescript": {
|
|
68
68
|
"definition": "lib/index.d.ts"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "230ff8e3720371c702b4da3ca70fd788b3a7d8e7"
|
|
71
71
|
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
const WATER_FRACTION_OF_FFM = 0.72;
|
|
2
|
-
const BONE_FRACTION_OF_FFM = 0.0497;
|
|
3
|
-
const round1 = (n) => Math.round(n * 10) / 10;
|
|
4
|
-
const round2 = (n) => Math.round(n * 100) / 100;
|
|
5
|
-
function computeBodyComposition(input) {
|
|
6
|
-
const {
|
|
7
|
-
weightKg,
|
|
8
|
-
bodyFatPct,
|
|
9
|
-
heightCm,
|
|
10
|
-
age
|
|
11
|
-
} = input;
|
|
12
|
-
const male = input.sex === "male";
|
|
13
|
-
const heightM = heightCm / 100;
|
|
14
|
-
const bmi = heightM > 0 ? weightKg / (heightM * heightM) : 0;
|
|
15
|
-
const fat = Math.max(0, Math.min(75, bodyFatPct)) / 100;
|
|
16
|
-
const fatMassKg = weightKg * fat;
|
|
17
|
-
const leanMassKg = weightKg - fatMassKg;
|
|
18
|
-
const boneMassKg = leanMassKg * BONE_FRACTION_OF_FFM;
|
|
19
|
-
const muscleMassKg = leanMassKg - boneMassKg;
|
|
20
|
-
const bodyWaterKg = leanMassKg * WATER_FRACTION_OF_FFM;
|
|
21
|
-
const proteinKg = Math.max(0, leanMassKg - bodyWaterKg - boneMassKg);
|
|
22
|
-
let skeletalMuscleMassKg;
|
|
23
|
-
if (input.impedanceOhm && input.impedanceOhm > 0) {
|
|
24
|
-
const sexTerm = male ? 3.825 : 0;
|
|
25
|
-
skeletalMuscleMassKg = 0.401 * (heightCm * heightCm) / input.impedanceOhm + sexTerm - 0.071 * age + 5.102;
|
|
26
|
-
skeletalMuscleMassKg = Math.max(0, Math.min(muscleMassKg, skeletalMuscleMassKg));
|
|
27
|
-
} else {
|
|
28
|
-
skeletalMuscleMassKg = muscleMassKg * (male ? 0.68 : 0.62);
|
|
29
|
-
}
|
|
30
|
-
const bmr = Math.round(370 + 21.6 * leanMassKg);
|
|
31
|
-
const metabolicAge = estimateMetabolicAge(bmr, heightCm, male, age);
|
|
32
|
-
const visceralFat = Math.max(1, Math.min(59, Math.round(fatMassKg * (male ? 1 : 0.85) / 2.2 + age / 12 - 3)));
|
|
33
|
-
const subcutaneousFatPct = Math.max(0, bodyFatPct - visceralFat * 0.33);
|
|
34
|
-
const pct = (kg) => weightKg > 0 ? kg / weightKg * 100 : 0;
|
|
35
|
-
return {
|
|
36
|
-
bmi: round1(bmi),
|
|
37
|
-
fatMassKg: round2(fatMassKg),
|
|
38
|
-
leanMassKg: round2(leanMassKg),
|
|
39
|
-
muscleMassKg: round2(muscleMassKg),
|
|
40
|
-
musclePct: round1(pct(muscleMassKg)),
|
|
41
|
-
skeletalMuscleMassKg: round2(skeletalMuscleMassKg),
|
|
42
|
-
skeletalMusclePct: round1(pct(skeletalMuscleMassKg)),
|
|
43
|
-
boneMassKg: round2(boneMassKg),
|
|
44
|
-
bonePct: round1(pct(boneMassKg)),
|
|
45
|
-
bodyWaterKg: round2(bodyWaterKg),
|
|
46
|
-
bodyWaterPct: round1(pct(bodyWaterKg)),
|
|
47
|
-
proteinKg: round2(proteinKg),
|
|
48
|
-
proteinPct: round1(pct(proteinKg)),
|
|
49
|
-
bmr,
|
|
50
|
-
metabolicAge,
|
|
51
|
-
visceralFat,
|
|
52
|
-
subcutaneousFatPct: round1(subcutaneousFatPct)
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function compositionRows(c, units = "metric") {
|
|
56
|
-
const kg = (v) => units === "imperial" ? `${Math.round(v / 0.45359237 * 10) / 10} lb` : `${v} kg`;
|
|
57
|
-
const pct = (v) => `${v}%`;
|
|
58
|
-
return [{
|
|
59
|
-
label: "BMI",
|
|
60
|
-
value: String(c.bmi)
|
|
61
|
-
}, {
|
|
62
|
-
label: "Fat mass",
|
|
63
|
-
value: kg(c.fatMassKg)
|
|
64
|
-
}, {
|
|
65
|
-
label: "Fat-free mass",
|
|
66
|
-
value: kg(c.leanMassKg)
|
|
67
|
-
}, {
|
|
68
|
-
label: "Muscle mass",
|
|
69
|
-
value: kg(c.muscleMassKg)
|
|
70
|
-
}, {
|
|
71
|
-
label: "Muscle",
|
|
72
|
-
value: pct(c.musclePct)
|
|
73
|
-
}, {
|
|
74
|
-
label: "Skeletal muscle",
|
|
75
|
-
value: kg(c.skeletalMuscleMassKg)
|
|
76
|
-
}, {
|
|
77
|
-
label: "Bone mass",
|
|
78
|
-
value: kg(c.boneMassKg)
|
|
79
|
-
}, {
|
|
80
|
-
label: "Body water",
|
|
81
|
-
value: pct(c.bodyWaterPct)
|
|
82
|
-
}, {
|
|
83
|
-
label: "Protein",
|
|
84
|
-
value: pct(c.proteinPct)
|
|
85
|
-
}, {
|
|
86
|
-
label: "BMR",
|
|
87
|
-
value: `${c.bmr} kcal`
|
|
88
|
-
}, {
|
|
89
|
-
label: "Metabolic age",
|
|
90
|
-
value: `${c.metabolicAge} yrs`
|
|
91
|
-
}, {
|
|
92
|
-
label: "Visceral fat",
|
|
93
|
-
value: String(c.visceralFat)
|
|
94
|
-
}, {
|
|
95
|
-
label: "Subcutaneous fat",
|
|
96
|
-
value: pct(c.subcutaneousFatPct)
|
|
97
|
-
}];
|
|
98
|
-
}
|
|
99
|
-
function estimateMetabolicAge(bmr, heightCm, male, age) {
|
|
100
|
-
const ffmAt = (a) => {
|
|
101
|
-
const base = male ? 0.407 * heightCm - 15 : 0.357 * heightCm - 13;
|
|
102
|
-
const decline = a > 25 ? (a - 25) * 0.1 : 0;
|
|
103
|
-
return Math.max(20, base - decline);
|
|
104
|
-
};
|
|
105
|
-
const bmrAt = (a) => 370 + 21.6 * ffmAt(a);
|
|
106
|
-
let best = age;
|
|
107
|
-
let bestDiff = Infinity;
|
|
108
|
-
for (let a = 18; a <= 80; a++) {
|
|
109
|
-
const diff = Math.abs(bmrAt(a) - bmr);
|
|
110
|
-
if (diff < bestDiff) {
|
|
111
|
-
bestDiff = diff;
|
|
112
|
-
best = a;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return best;
|
|
116
|
-
}export{compositionRows,computeBodyComposition};//# sourceMappingURL=bodyComposition.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bodyComposition.js","sources":["../../../src/features/devices/bodyComposition.ts"],"sourcesContent":["/**\n * Full body composition from a scale reading, using established published\n * formulas (not any vendor's proprietary coefficients).\n *\n * A body-fat scale measures weight and bioelectrical impedance and, from the\n * person's height/age/sex, estimates body-fat percentage. Everything else a\n * scale app shows (fat-free mass, muscle, bone, body water, protein, BMR,\n * metabolic age, visceral/subcutaneous fat) is derived from weight and body\n * fat with standard equations:\n *\n * - Fat mass / fat-free mass: definitional.\n * - Total body water: FFM is ~72% water (the standard hydration constant).\n * - Bone mineral: a small, roughly fixed fraction of fat-free mass.\n * - Muscle mass = fat-free mass minus bone mineral; protein is the dry\n * non-mineral remainder.\n * - BMR: Katch-McArdle (370 + 21.6 x FFM), which depends only on lean mass.\n * - Skeletal muscle: Janssen's impedance equation when impedance is known.\n *\n * These reproduce a RENPHO/QN scale's derived numbers closely because the scale\n * uses the same public science; the only vendor-specific step is the body-fat\n * estimate, which the device sends directly, so Yantra does not recompute it.\n */\n\nexport interface BodyCompositionInput {\n weightKg: number;\n bodyFatPct: number;\n heightCm: number;\n age: number;\n sex: 'male' | 'female' | 'unspecified';\n /** Whole-body impedance in ohms, when the scale reported it (for skeletal muscle). */\n impedanceOhm?: number;\n}\n\nexport interface BodyComposition {\n bmi: number;\n fatMassKg: number;\n /** Fat-free (lean) mass. */\n leanMassKg: number;\n muscleMassKg: number;\n musclePct: number;\n skeletalMuscleMassKg: number;\n skeletalMusclePct: number;\n boneMassKg: number;\n bonePct: number;\n bodyWaterKg: number;\n bodyWaterPct: number;\n proteinKg: number;\n proteinPct: number;\n /** Basal metabolic rate, kcal/day. */\n bmr: number;\n metabolicAge: number;\n /** Visceral fat rating (unitless, like the scale's 1-59 scale). */\n visceralFat: number;\n subcutaneousFatPct: number;\n}\n\n/** Fraction of fat-free mass that is water (standard hydration constant). */\nconst WATER_FRACTION_OF_FFM = 0.72;\n/** Fraction of fat-free mass that is bone mineral. */\nconst BONE_FRACTION_OF_FFM = 0.0497;\n\nconst round1 = (n: number) => Math.round(n * 10) / 10;\nconst round2 = (n: number) => Math.round(n * 100) / 100;\n\nexport function computeBodyComposition(input: BodyCompositionInput): BodyComposition {\n const { weightKg, bodyFatPct, heightCm, age } = input;\n const male = input.sex === 'male';\n const heightM = heightCm / 100;\n\n const bmi = heightM > 0 ? weightKg / (heightM * heightM) : 0;\n const fat = Math.max(0, Math.min(75, bodyFatPct)) / 100;\n const fatMassKg = weightKg * fat;\n const leanMassKg = weightKg - fatMassKg;\n\n const boneMassKg = leanMassKg * BONE_FRACTION_OF_FFM;\n const muscleMassKg = leanMassKg - boneMassKg;\n const bodyWaterKg = leanMassKg * WATER_FRACTION_OF_FFM;\n const proteinKg = Math.max(0, leanMassKg - bodyWaterKg - boneMassKg);\n\n // Skeletal muscle: Janssen (2000) when impedance is known, else a fraction of muscle.\n let skeletalMuscleMassKg: number;\n if (input.impedanceOhm && input.impedanceOhm > 0) {\n const sexTerm = male ? 3.825 : 0;\n skeletalMuscleMassKg =\n (0.401 * (heightCm * heightCm)) / input.impedanceOhm + sexTerm - 0.071 * age + 5.102;\n skeletalMuscleMassKg = Math.max(0, Math.min(muscleMassKg, skeletalMuscleMassKg));\n } else {\n skeletalMuscleMassKg = muscleMassKg * (male ? 0.68 : 0.62);\n }\n\n // Katch-McArdle: basal metabolic rate from lean mass.\n const bmr = Math.round(370 + 21.6 * leanMassKg);\n\n // Metabolic age: how old the person's BMR looks against the BMR a lean,\n // average person of their height would have at each age. Clamped to 18-80.\n const metabolicAge = estimateMetabolicAge(bmr, heightCm, male, age);\n\n // Visceral fat rating: rises with body-fat mass and age; a standard-style\n // index (not a clinical measure), clamped to the usual 1-59 range.\n const visceralFat = Math.max(\n 1,\n Math.min(59, Math.round((fatMassKg * (male ? 1.0 : 0.85)) / 2.2 + age / 12 - 3)),\n );\n // Subcutaneous fat is the body fat that is not visceral.\n const subcutaneousFatPct = Math.max(0, bodyFatPct - visceralFat * 0.33);\n\n const pct = (kg: number) => (weightKg > 0 ? (kg / weightKg) * 100 : 0);\n return {\n bmi: round1(bmi),\n fatMassKg: round2(fatMassKg),\n leanMassKg: round2(leanMassKg),\n muscleMassKg: round2(muscleMassKg),\n musclePct: round1(pct(muscleMassKg)),\n skeletalMuscleMassKg: round2(skeletalMuscleMassKg),\n skeletalMusclePct: round1(pct(skeletalMuscleMassKg)),\n boneMassKg: round2(boneMassKg),\n bonePct: round1(pct(boneMassKg)),\n bodyWaterKg: round2(bodyWaterKg),\n bodyWaterPct: round1(pct(bodyWaterKg)),\n proteinKg: round2(proteinKg),\n proteinPct: round1(pct(proteinKg)),\n bmr,\n metabolicAge,\n visceralFat,\n subcutaneousFatPct: round1(subcutaneousFatPct),\n };\n}\n\n/** The composition as labelled rows for a details view, in the person's units. */\nexport function compositionRows(\n c: BodyComposition,\n units: 'metric' | 'imperial' = 'metric',\n): Array<{ label: string; value: string }> {\n const kg = (v: number) =>\n units === 'imperial' ? `${Math.round((v / 0.45359237) * 10) / 10} lb` : `${v} kg`;\n const pct = (v: number) => `${v}%`;\n return [\n { label: 'BMI', value: String(c.bmi) },\n { label: 'Fat mass', value: kg(c.fatMassKg) },\n { label: 'Fat-free mass', value: kg(c.leanMassKg) },\n { label: 'Muscle mass', value: kg(c.muscleMassKg) },\n { label: 'Muscle', value: pct(c.musclePct) },\n { label: 'Skeletal muscle', value: kg(c.skeletalMuscleMassKg) },\n { label: 'Bone mass', value: kg(c.boneMassKg) },\n { label: 'Body water', value: pct(c.bodyWaterPct) },\n { label: 'Protein', value: pct(c.proteinPct) },\n { label: 'BMR', value: `${c.bmr} kcal` },\n { label: 'Metabolic age', value: `${c.metabolicAge} yrs` },\n { label: 'Visceral fat', value: String(c.visceralFat) },\n { label: 'Subcutaneous fat', value: pct(c.subcutaneousFatPct) },\n ];\n}\n\n/** Compare the person's BMR to the typical BMR by age for their height and sex. */\nfunction estimateMetabolicAge(bmr: number, heightCm: number, male: boolean, age: number): number {\n // Typical fat-free mass by age (slow decline past 25), then its Katch-McArdle BMR.\n const ffmAt = (a: number) => {\n const base = male ? 0.407 * heightCm - 15 : 0.357 * heightCm - 13;\n const decline = a > 25 ? (a - 25) * 0.1 : 0;\n return Math.max(20, base - decline);\n };\n const bmrAt = (a: number) => 370 + 21.6 * ffmAt(a);\n let best = age;\n let bestDiff = Infinity;\n for (let a = 18; a <= 80; a++) {\n const diff = Math.abs(bmrAt(a) - bmr);\n if (diff < bestDiff) {\n bestDiff = diff;\n best = a;\n }\n }\n return best;\n}\n"],"names":[],"mappings":"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"}
|