fitness_app/FitnessApp/Managers/HealthManager.swift
Matt Bruce 0c5e3dae74 added healthkit
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2024-12-21 10:31:16 -06:00

123 lines
4.4 KiB
Swift

//
// HealthManager.swift
// FitnessApp
//
// Created by Matt Bruce on 12/20/24.
//
import Foundation
import HealthKit
extension Date {
static var startOfDay: Date {
let calendar = Calendar.current
return calendar.startOfDay(for: Date())
}
}
class HealthManager {
static let shared = HealthManager()
let healthStore = HKHealthStore()
private init () {
Task {
do {
try await requestHealthKitAccess()
} catch {
}
}
}
func requestHealthKitAccess() async throws {
let calories = HKQuantityType(.activeEnergyBurned)
let exercise = HKQuantityType(.appleExerciseTime)
let stand = HKCategoryType(.appleStandHour)
let healthTypes: Set = [calories, exercise, stand]
try await healthStore.requestAuthorization(toShare: [], read: healthTypes)
}
func fetchTodayCaloriesBurned(completion: @escaping(Result<Double, Error>) -> Void) {
guard HKHealthStore.isHealthDataAvailable() else {
completion(.failure(NSError(domain: "HealthManager", code: -2, userInfo: [NSLocalizedDescriptionKey: "Health data unavailable"])))
return
}
let calories = HKQuantityType(.activeEnergyBurned)
let predicate = HKQuery.predicateForSamples(withStart: .startOfDay, end: Date())
let query = HKStatisticsQuery(quantityType: calories, quantitySamplePredicate: predicate) { _, results, error in
if let error = error {
completion(.failure(error))
return
}
if let quantity = results?.sumQuantity() {
let caloriesBurned = quantity.doubleValue(for: .kilocalorie())
completion(.success(caloriesBurned))
} else {
completion(.failure(NSError(domain: "HealthManager", code: -3, userInfo: [NSLocalizedDescriptionKey: "No data found for today's calories"])))
}
}
healthStore.execute(query)
}
func fetchTodayExerciseTime(completion: @escaping(Result<Double, Error>) -> Void) {
guard HKHealthStore.isHealthDataAvailable() else {
completion(.failure(NSError(domain: "HealthManager", code: -2, userInfo: [NSLocalizedDescriptionKey: "Health data unavailable"])))
return
}
let exercise = HKQuantityType(.appleExerciseTime)
let predicate = HKQuery.predicateForSamples(withStart: .startOfDay, end: Date())
let query = HKStatisticsQuery(quantityType: exercise, quantitySamplePredicate: predicate) { _, results, error in
if let error = error {
completion(.failure(error))
return
}
if let quantity = results?.sumQuantity() {
let exerciseTime = quantity.doubleValue(for: .minute())
completion(.success(exerciseTime))
} else {
completion(.failure(NSError(domain: "HealthManager", code: -3, userInfo: [NSLocalizedDescriptionKey: "No exercise time data found for today."])))
}
}
healthStore.execute(query)
}
func fetchTodayStandHours(completion: @escaping(Result<Double, Error>) -> Void) {
guard HKHealthStore.isHealthDataAvailable() else {
completion(.failure(NSError(domain: "HealthManager", code: -2, userInfo: [NSLocalizedDescriptionKey: "Health data unavailable"])))
return
}
let stand = HKCategoryType(.appleStandHour)
let predicate = HKQuery.predicateForSamples(withStart: .startOfDay, end: Date())
let query = HKSampleQuery(sampleType: stand, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { _, results, error in
if let error = error {
completion(.failure(error))
return
}
guard let samples = results as? [HKCategorySample], !samples.isEmpty else {
completion(.failure(NSError(domain: "HealthManager", code: -3, userInfo: [NSLocalizedDescriptionKey: "No stand data found for today."])))
return
}
// Count stand hours
let standHours = samples.filter { $0.value == HKCategoryValueAppleStandHour.stood.rawValue }.count
completion(.success(Double(standHours)))
}
healthStore.execute(query)
}
}