From d245563940922408d2c348f533bccae4429f3cea Mon Sep 17 00:00:00 2001 From: Navan Chauhan Date: Sat, 10 Feb 2024 01:54:53 -0700 Subject: display steps --- iCUrHealth.xcodeproj/project.pbxproj | 53 +++++++- .../xcshareddata/swiftpm/Package.resolved | 14 ++ iCUrHealth/ContentView.swift | 148 +++++++++++++-------- 3 files changed, 161 insertions(+), 54 deletions(-) create mode 100644 iCUrHealth.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/iCUrHealth.xcodeproj/project.pbxproj b/iCUrHealth.xcodeproj/project.pbxproj index c7d30d5..eab4ec3 100644 --- a/iCUrHealth.xcodeproj/project.pbxproj +++ b/iCUrHealth.xcodeproj/project.pbxproj @@ -11,6 +11,9 @@ 3E54FF0E2B772F1C00260FCB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E54FF0D2B772F1C00260FCB /* ContentView.swift */; }; 3E54FF102B772F1E00260FCB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3E54FF0F2B772F1E00260FCB /* Assets.xcassets */; }; 3E54FF142B772F1E00260FCB /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3E54FF132B772F1E00260FCB /* Preview Assets.xcassets */; }; + 3E54FF1C2B7765C200260FCB /* CareKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3E54FF1B2B7765C200260FCB /* CareKit */; }; + 3E54FF1E2B7765C200260FCB /* CareKitStore in Frameworks */ = {isa = PBXBuildFile; productRef = 3E54FF1D2B7765C200260FCB /* CareKitStore */; }; + 3E54FF202B7765C200260FCB /* CareKitUI in Frameworks */ = {isa = PBXBuildFile; productRef = 3E54FF1F2B7765C200260FCB /* CareKitUI */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -27,6 +30,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 3E54FF1E2B7765C200260FCB /* CareKitStore in Frameworks */, + 3E54FF1C2B7765C200260FCB /* CareKit in Frameworks */, + 3E54FF202B7765C200260FCB /* CareKitUI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -85,6 +91,11 @@ dependencies = ( ); name = iCUrHealth; + packageProductDependencies = ( + 3E54FF1B2B7765C200260FCB /* CareKit */, + 3E54FF1D2B7765C200260FCB /* CareKitStore */, + 3E54FF1F2B7765C200260FCB /* CareKitUI */, + ); productName = iCUrHealth; productReference = 3E54FF082B772F1C00260FCB /* iCUrHealth.app */; productType = "com.apple.product-type.application"; @@ -113,6 +124,9 @@ Base, ); mainGroup = 3E54FEFF2B772F1C00260FCB; + packageReferences = ( + 3E54FF1A2B7765C200260FCB /* XCRemoteSwiftPackageReference "CareKit" */, + ); productRefGroup = 3E54FF092B772F1C00260FCB /* Products */; projectDirPath = ""; projectRoot = ""; @@ -274,6 +288,8 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHealthClinicalHealthRecordsShareUsageDescription = "Used to analyze and provide strats"; + INFOPLIST_KEY_NSHealthShareUsageDescription = "Used to analyze health data to provide stats"; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; @@ -292,7 +308,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.navanchauhan.iCUrHealth; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -312,6 +329,8 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHealthClinicalHealthRecordsShareUsageDescription = "Used to analyze and provide strats"; + INFOPLIST_KEY_NSHealthShareUsageDescription = "Used to analyze health data to provide stats"; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; @@ -330,7 +349,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.navanchauhan.iCUrHealth; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -359,6 +379,35 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 3E54FF1A2B7765C200260FCB /* XCRemoteSwiftPackageReference "CareKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/carekit-apple/CareKit"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.0.2; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 3E54FF1B2B7765C200260FCB /* CareKit */ = { + isa = XCSwiftPackageProductDependency; + package = 3E54FF1A2B7765C200260FCB /* XCRemoteSwiftPackageReference "CareKit" */; + productName = CareKit; + }; + 3E54FF1D2B7765C200260FCB /* CareKitStore */ = { + isa = XCSwiftPackageProductDependency; + package = 3E54FF1A2B7765C200260FCB /* XCRemoteSwiftPackageReference "CareKit" */; + productName = CareKitStore; + }; + 3E54FF1F2B7765C200260FCB /* CareKitUI */ = { + isa = XCSwiftPackageProductDependency; + package = 3E54FF1A2B7765C200260FCB /* XCRemoteSwiftPackageReference "CareKit" */; + productName = CareKitUI; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 3E54FF002B772F1C00260FCB /* Project object */; } diff --git a/iCUrHealth.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iCUrHealth.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..973296d --- /dev/null +++ b/iCUrHealth.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "carekit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/carekit-apple/CareKit", + "state" : { + "revision" : "9d4233253faf39e5dcd52e6cb4a0498ac4ca4a1f", + "version" : "2.0.2" + } + } + ], + "version" : 2 +} diff --git a/iCUrHealth/ContentView.swift b/iCUrHealth/ContentView.swift index cc8ea87..200e14c 100644 --- a/iCUrHealth/ContentView.swift +++ b/iCUrHealth/ContentView.swift @@ -8,6 +8,14 @@ import SwiftUI import HealthKit import HealthKitUI +import Charts + +struct chartData: Identifiable { + + let dateInterval: Date + let data: Double + var id: TimeInterval { dateInterval.timeIntervalSince1970 } +} let allTypes: Set = [ HKQuantityType.workoutType(), @@ -20,72 +28,108 @@ let allTypes: Set = [ HKCategoryType(.sleepAnalysis) ] -func stepCount(healthStore: HKHealthStore) async throws { - let stepType = HKQuantityType(.stepCount) - let descriptor = HKSampleQueryDescriptor(predicates:[.quantitySample(type: stepType)], sortDescriptors: [SortDescriptor(\.endDate, order: .reverse)], limit: 10) - let descriptor = HKSampleQuery( - - let results = try await descriptor.result(for: healthStore) - - for result in results { - print(result) - } -} - struct ContentView: View { @State var authenticated = false @State var trigger = false let healthStore = HKHealthStore() + @State private var data: [chartData] = [] + var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Button(action: { - trigger.toggle() - }) { - Text("Force Permissions") - } - Button(action: { - if HKHealthStore.isHealthDataAvailable() { - print("YES!") + NavigationView { + VStack { + HStack { + Text("Steps") + Chart(data) { + BarMark(x: .value("Date", $0.dateInterval), + y: .value("Count", $0.data) + ) + + } + }.frame(maxHeight: 100) + Button(action: { Task { - try await stepCount(healthStore: healthStore) + try await fetchStepCountData() } - - - } else { - print("NOOOO!") + }) + { + Text("Exp Function") } - }) { - Text("Test Healthkit stuff") - }.disabled(!authenticated) - + Spacer() .onAppear() { - - // Check that Health data is available on the device. - if HKHealthStore.isHealthDataAvailable() { - // Modifying the trigger initiates the health data - // access request. - trigger.toggle() - } - } + if HKHealthStore.isHealthDataAvailable() { + trigger.toggle() + } + } .healthDataAccessRequest(store: healthStore, - readTypes: allTypes, - trigger: trigger) { result in - switch result { - - case .success(_): - authenticated = true - case .failure(let error): - // Handle the error here. - fatalError("*** An error occurred while requesting authentication: \(error) ***") - } + readTypes: allTypes, + trigger: trigger) { result in + switch result { + + case .success(_): + authenticated = true + Task { + try await fetchStepCountData() } + case .failure(let error): + // Handle the error here. + fatalError("*** An error occurred while requesting authentication: \(error) ***") + } + } + } + .padding() + .navigationTitle("iCUrHealth") + } + } + + private func fetchStepCountData() async throws { + let calendar = Calendar(identifier: .gregorian) + let today = calendar.startOfDay(for: Date()) + + + guard let endDate = calendar.date(byAdding: .day, value: 1, to: today) else { + fatalError("*** Unable to calculate the end time ***") + } + + + guard let startDate = calendar.date(byAdding: .day, value: -29, to: endDate) else { + fatalError("*** Unable to calculate the start time ***") + } + + + let thisWeek = HKQuery.predicateForSamples(withStart: startDate, end: endDate) + + + // Create the query descriptor. + let stepType = HKQuantityType(.stepCount) + let stepsThisWeek = HKSamplePredicate.quantitySample(type: stepType, predicate:thisWeek) + let everyDay = DateComponents(day:1) + + + let sumOfStepsQuery = HKStatisticsCollectionQueryDescriptor( + predicate: stepsThisWeek, + options: .cumulativeSum, + anchorDate: endDate, + intervalComponents: everyDay) + + + let stepCounts = try await sumOfStepsQuery.result(for: self.healthStore) + + var dailyData: [chartData] = [] + + stepCounts.enumerateStatistics(from: startDate, to: endDate) { stats, _ in + if let quantity = stats.sumQuantity() { + //print(quantity, stats.startDate) + dailyData.append( + chartData(dateInterval: stats.startDate, data: quantity.doubleValue(for: HKUnit.count())) + ) + } else { + } + } - .padding() + + data = dailyData } } -- cgit v1.2.3