glp-companion/lib/core/platform/health_gateway.dart

88 lines
3.1 KiB
Dart

import 'health_gateway_fallback.dart'
if (dart.library.io) 'health_gateway_mobile.dart' as impl;
/// Native health ecosystem backing the current device.
///
/// Kept in `core` (not the health_sync feature) so the platform layer never
/// imports feature code; the biometric controller maps this to the domain's
/// `BiometricSource` enum.
enum NativeHealthPlatform {
/// Apple HealthKit (iOS).
appleHealth,
/// Google Health Connect (Android).
healthConnect,
}
/// Scalar sample returned by the health gateway.
///
/// Pure value type: [unit] is a display string (`lb`, `kcal`) — unit
/// normalization (kg → lb, joules → kcal) happens inside the gateway so
/// consumers only ever deal in pounds and Calories.
class HealthMetric {
const HealthMetric({
required this.timestamp,
required this.value,
required this.unit,
});
/// When the sample was recorded.
final DateTime timestamp;
/// Normalized magnitude (pounds for weight, kilocalories for energy).
final double value;
/// Unit of [value] for display (e.g. `lb`, `kcal`).
final String unit;
}
/// Cross-platform boundary over the OS health ecosystems (architecture rule
/// 2/3: platform-specific packages never leak past this interface).
///
/// * **Android / iOS:** implemented by `health_gateway_mobile.dart`, which
/// wraps the `health` package (Health Connect / HealthKit).
/// * **Windows / macOS / Web:** implemented by `health_gateway_fallback.dart`,
/// a manual-entry mode that never touches platform channels; consumers read
/// the drift-backed cache through `IHealthSyncRepository` instead.
abstract class IHealthGateway {
/// Whether this device can read/write native health data. `false` on
/// Web/Windows/macOS, which signals the UI to offer manual entry.
bool get supportsNativeHealth;
/// Ecosystem backing [supportsNativeHealth], or `null` in fallback mode.
NativeHealthPlatform? get nativePlatform;
/// Requests read permission for weight and active energy; returns whether
/// access was granted. Always `false` in fallback mode.
Future<bool> requestPermissions();
/// Weight samples in pounds for `[start, end)`, newest first.
///
/// Returns an empty list (never throws) in fallback mode or when the OS
/// denies access.
Future<List<HealthMetric>> fetchWeightHistory({
required DateTime start,
required DateTime end,
});
/// Active energy burned (kcal) samples for `[start, end)`, newest first.
///
/// Returns an empty list (never throws) in fallback mode or when the OS
/// denies access.
Future<List<HealthMetric>> fetchActiveEnergyBurned({
required DateTime start,
required DateTime end,
});
/// Writes a weight measurement back to the native store; returns whether
/// the platform accepted it (always `false` in fallback mode).
Future<bool> writeWeight({
required double weightLbs,
required DateTime timestamp,
});
}
/// Platform-appropriate factory: native `health`-backed gateway on
/// Android/iOS, manual-entry fallback on Web/Windows/macOS.
IHealthGateway createHealthGateway() => impl.makeHealthGateway();