From d9e366eb816616bd97f5c0c5e1476f563fe89d0f Mon Sep 17 00:00:00 2001 From: Paul Schmiedmayer Date: Tue, 23 May 2023 00:07:29 -0500 Subject: [PATCH 1/2] Add option to pass in a custom predicate for HealthKit data collection --- .../CollectSample/CollectSamples.swift | 12 +++++++++++- Sources/SpeziHealthKit/HealthKit.swift | 13 +++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Sources/SpeziHealthKit/CollectSample/CollectSamples.swift b/Sources/SpeziHealthKit/CollectSample/CollectSamples.swift index c9be574..1f679b6 100644 --- a/Sources/SpeziHealthKit/CollectSample/CollectSamples.swift +++ b/Sources/SpeziHealthKit/CollectSample/CollectSamples.swift @@ -13,14 +13,23 @@ import Spezi /// Collects `HKSampleType`s in the ``HealthKit`` component. public struct CollectSamples: HealthKitDataSourceDescription { public let sampleTypes: Set + let predicate: NSPredicate? let deliverySetting: HealthKitDeliverySetting /// - Parameters: /// - sampleType: The set of `HKSampleType`s that should be collected + /// - predicate: A custom predicate that should be passed to the HealthKit query. + /// The default predicate collects all samples that have been collected from the first time that the user + /// provided the application authorization to collect the samples. /// - deliverySetting: The ``HealthKitDeliverySetting`` that should be used to collect the sample type. `.manual` is the default argument used. - public init(_ sampleTypes: Set, deliverySetting: HealthKitDeliverySetting = .manual()) { + public init( + _ sampleTypes: Set, + predicate: NSPredicate? = nil, + deliverySetting: HealthKitDeliverySetting = .manual() + ) { self.sampleTypes = sampleTypes + self.predicate = predicate self.deliverySetting = deliverySetting } @@ -35,6 +44,7 @@ public struct CollectSamples: HealthKitDataSourceDescription { healthStore: healthStore, standard: standard, sampleType: sampleType, + predicate: predicate, deliverySetting: deliverySetting, adapter: adapter ) diff --git a/Sources/SpeziHealthKit/HealthKit.swift b/Sources/SpeziHealthKit/HealthKit.swift index 4d2453c..cee4f01 100644 --- a/Sources/SpeziHealthKit/HealthKit.swift +++ b/Sources/SpeziHealthKit/HealthKit.swift @@ -98,21 +98,22 @@ public final class HealthKit: Module { /// Displays the user interface to ask for authorization for all HealthKit data defined by the ``HealthKitDataSourceDescription``s. /// /// Call this function when you want to start HealthKit data collection. - public func askForAuthorization() async throws { - var sampleTypes: Set = [] + /// - Parameter objectTypes: Additional `HKObjectType` instances that should be authorized. + public func askForAuthorization(_ objectTypes: Set = []) async throws { + var objectTypes: Set = [] for healthKitDataSourceDescription in healthKitDataSourceDescriptions { - sampleTypes = sampleTypes.union(healthKitDataSourceDescription.sampleTypes) + objectTypes = objectTypes.union(healthKitDataSourceDescription.sampleTypes) } let requestedSampleTypes = Set(UserDefaults.standard.stringArray(forKey: UserDefaults.Keys.healthKitRequestedSampleTypes) ?? []) - guard !Set(sampleTypes.map { $0.identifier }).isSubset(of: requestedSampleTypes) else { + guard !Set(objectTypes.map { $0.identifier }).isSubset(of: requestedSampleTypes) else { return } - try await healthStore.requestAuthorization(toShare: [], read: sampleTypes) + try await healthStore.requestAuthorization(toShare: [], read: objectTypes) - UserDefaults.standard.set(sampleTypes.map { $0.identifier }, forKey: UserDefaults.Keys.healthKitRequestedSampleTypes) + UserDefaults.standard.set(objectTypes.map { $0.identifier }, forKey: UserDefaults.Keys.healthKitRequestedSampleTypes) for healthKitComponent in healthKitComponents { healthKitComponent.askedForAuthorization() From 4aa7f0278f688463e8a4f1d00ec20b5bdc635326 Mon Sep 17 00:00:00 2001 From: Paul Schmiedmayer Date: Tue, 23 May 2023 00:12:36 -0500 Subject: [PATCH 2/2] Add predicate to CollecSample --- .../CollectSample/CollectSample.swift | 11 +++++++++-- Sources/SpeziHealthKit/HealthKit.swift | 13 ++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Sources/SpeziHealthKit/CollectSample/CollectSample.swift b/Sources/SpeziHealthKit/CollectSample/CollectSample.swift index 39e794d..8dccf96 100644 --- a/Sources/SpeziHealthKit/CollectSample/CollectSample.swift +++ b/Sources/SpeziHealthKit/CollectSample/CollectSample.swift @@ -22,9 +22,16 @@ public struct CollectSample: HealthKitDataSourceDescription { /// - Parameters: /// - sampleType: The `HKSampleType` that should be collected + /// - predicate: A custom predicate that should be passed to the HealthKit query. + /// The default predicate collects all samples that have been collected from the first time that the user + /// provided the application authorization to collect the samples. /// - deliverySetting: The ``HealthKitDeliverySetting`` that should be used to collect the sample type. `.manual` is the default argument used. - public init(_ sampleType: S, deliverySetting: HealthKitDeliverySetting = .manual()) { - self.collectSamples = CollectSamples([sampleType], deliverySetting: deliverySetting) + public init( + _ sampleType: S, + predicate: NSPredicate? = nil, + deliverySetting: HealthKitDeliverySetting = .manual() + ) { + self.collectSamples = CollectSamples([sampleType], predicate: predicate, deliverySetting: deliverySetting) } diff --git a/Sources/SpeziHealthKit/HealthKit.swift b/Sources/SpeziHealthKit/HealthKit.swift index cee4f01..4d2453c 100644 --- a/Sources/SpeziHealthKit/HealthKit.swift +++ b/Sources/SpeziHealthKit/HealthKit.swift @@ -98,22 +98,21 @@ public final class HealthKit: Module { /// Displays the user interface to ask for authorization for all HealthKit data defined by the ``HealthKitDataSourceDescription``s. /// /// Call this function when you want to start HealthKit data collection. - /// - Parameter objectTypes: Additional `HKObjectType` instances that should be authorized. - public func askForAuthorization(_ objectTypes: Set = []) async throws { - var objectTypes: Set = [] + public func askForAuthorization() async throws { + var sampleTypes: Set = [] for healthKitDataSourceDescription in healthKitDataSourceDescriptions { - objectTypes = objectTypes.union(healthKitDataSourceDescription.sampleTypes) + sampleTypes = sampleTypes.union(healthKitDataSourceDescription.sampleTypes) } let requestedSampleTypes = Set(UserDefaults.standard.stringArray(forKey: UserDefaults.Keys.healthKitRequestedSampleTypes) ?? []) - guard !Set(objectTypes.map { $0.identifier }).isSubset(of: requestedSampleTypes) else { + guard !Set(sampleTypes.map { $0.identifier }).isSubset(of: requestedSampleTypes) else { return } - try await healthStore.requestAuthorization(toShare: [], read: objectTypes) + try await healthStore.requestAuthorization(toShare: [], read: sampleTypes) - UserDefaults.standard.set(objectTypes.map { $0.identifier }, forKey: UserDefaults.Keys.healthKitRequestedSampleTypes) + UserDefaults.standard.set(sampleTypes.map { $0.identifier }, forKey: UserDefaults.Keys.healthKitRequestedSampleTypes) for healthKitComponent in healthKitComponents { healthKitComponent.askedForAuthorization()