From 1b98e585cf95e4cb98648c7952286275546ca958 Mon Sep 17 00:00:00 2001 From: aakritil <67278558+aakritil@users.noreply.github.com> Date: Sat, 17 Feb 2024 21:12:04 -0800 Subject: [PATCH] Aakriti updates --- .../CardinalKit.xcodeproj/project.pbxproj | 22 +++- CardinalKit-Example/CardinalKit/.DS_Store | Bin 6148 -> 8196 bytes .../Onboarding/OnboardingViewController.swift | 6 +- .../CKHealthDataStepViewController.swift | 6 +- .../Tasks/Model/LocalTaskItem.swift | 96 +++++++-------- .../Components/Tasks/Model/TaskSamples.swift | 6 +- .../Components/Tasks/TasksUIView.swift | 112 +++++++++++++++++- .../Tasks/Views/CoffeePieChartView.swift | 6 +- .../Tasks/Views/DataCollectionView.swift | 65 +++++++++- .../Tasks/Views/HotlineUIView.swift | 28 ++++- .../Tasks/Views/LocalTaskListItemView.swift | 6 +- .../Supporting Files/CKConfiguration.plist | 42 ++----- .../Supporting Files/GoogleService-Info.plist | 34 ++++++ .../CardinalKit/Supporting Files/Info.plist | 4 +- CardinalKit.podspec | 4 +- .../Networking/CKNetworkManager.swift | 2 + 16 files changed, 323 insertions(+), 116 deletions(-) create mode 100644 CardinalKit-Example/CardinalKit/Supporting Files/GoogleService-Info.plist diff --git a/CardinalKit-Example/CardinalKit.xcodeproj/project.pbxproj b/CardinalKit-Example/CardinalKit.xcodeproj/project.pbxproj index 12fd0044..ab88c319 100644 --- a/CardinalKit-Example/CardinalKit.xcodeproj/project.pbxproj +++ b/CardinalKit-Example/CardinalKit.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 270CDC0A28A65A0100F2F053 /* CKFHIRTaskViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 270CDC0928A65A0100F2F053 /* CKFHIRTaskViewController.swift */; }; 270CDC0C28A65AD300F2F053 /* CKUploadFHIRTaskViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 270CDC0B28A65AD300F2F053 /* CKUploadFHIRTaskViewControllerDelegate.swift */; }; 275A6AC5296A684800DA4943 /* OnboardingPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 275A6AC4296A684800DA4943 /* OnboardingPageView.swift */; }; - 276399A129021BB5004DE158 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 276399A029021BB4004DE158 /* GoogleService-Info.plist */; }; 27653A13272A2E7700D74E83 /* LocalTaskListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27653A12272A2E7700D74E83 /* LocalTaskListItemView.swift */; }; 27663F2A29574F1500A34080 /* CardinalKit_ExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27663F2929574F1500A34080 /* CardinalKit_ExampleTests.swift */; }; 2777DADD2969F76300F2ECD4 /* CKSignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777DADC2969F76300F2ECD4 /* CKSignInView.swift */; }; @@ -34,6 +33,10 @@ 2FFFA2CD29024EFD009D289D /* Questionnaire+ValueSets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFFA2C529024EFD009D289D /* Questionnaire+ValueSets.swift */; }; 2FFFA2CE29024EFD009D289D /* FHIRExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFFA2C729024EFD009D289D /* FHIRExtensions.swift */; }; 2FFFA2D229025241009D289D /* ORKESerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E0A4386244A4A0400656518 /* ORKESerialization.m */; }; + 5822BF4E2B81738A00F94625 /* HotlineUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5822BF4D2B81738A00F94625 /* HotlineUIView.swift */; }; + 5822BF4F2B81755200F94625 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5822BF4C2B8172F800F94625 /* GoogleService-Info.plist */; }; + 5822BF502B81755300F94625 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5822BF4C2B8172F800F94625 /* GoogleService-Info.plist */; }; + 5822BF522B817BBB00F94625 /* DataCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5822BF512B817BBB00F94625 /* DataCollectionView.swift */; }; 6333443D2AAE1E56006DC7A7 /* ResearchKit in Frameworks */ = {isa = PBXBuildFile; productRef = 6333443C2AAE1E56006DC7A7 /* ResearchKit */; }; 6372202D2AAE390C00367157 /* CKSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6372202C2AAE390C00367157 /* CKSessionTests.swift */; }; 8E0A43AC244A4A0400656518 /* CKStudyUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E0A4382244A4A0400656518 /* CKStudyUser.swift */; }; @@ -130,7 +133,6 @@ 270CDC0928A65A0100F2F053 /* CKFHIRTaskViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CKFHIRTaskViewController.swift; sourceTree = ""; }; 270CDC0B28A65AD300F2F053 /* CKUploadFHIRTaskViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CKUploadFHIRTaskViewControllerDelegate.swift; sourceTree = ""; }; 275A6AC4296A684800DA4943 /* OnboardingPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPageView.swift; sourceTree = ""; }; - 276399A029021BB4004DE158 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 27653A12272A2E7700D74E83 /* LocalTaskListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalTaskListItemView.swift; sourceTree = ""; }; 27663F2729574F1500A34080 /* CardinalKit ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CardinalKit ExampleTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 27663F2929574F1500A34080 /* CardinalKit_ExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardinalKit_ExampleTests.swift; sourceTree = ""; }; @@ -155,6 +157,9 @@ 2FFFA2C529024EFD009D289D /* Questionnaire+ValueSets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Questionnaire+ValueSets.swift"; sourceTree = ""; }; 2FFFA2C729024EFD009D289D /* FHIRExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FHIRExtensions.swift; sourceTree = ""; }; 41DC264876E45FE5A3FD8701 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; + 5822BF4C2B8172F800F94625 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 5822BF4D2B81738A00F94625 /* HotlineUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotlineUIView.swift; sourceTree = ""; }; + 5822BF512B817BBB00F94625 /* DataCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataCollectionView.swift; sourceTree = ""; }; 5B3D62399A6AD2DDCE5BC6B8 /* Pods-CardinalKit_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CardinalKit_Example.debug.xcconfig"; path = "Target Support Files/Pods-CardinalKit_Example/Pods-CardinalKit_Example.debug.xcconfig"; sourceTree = ""; }; 607FACD01AFB9204008FA782 /* CardinalKit Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "CardinalKit Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 62AA5CD1C2188D392530510F /* CardinalKit.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = CardinalKit.podspec; path = ../CardinalKit.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; @@ -377,13 +382,13 @@ 8E0A4383244A4A0400656518 /* Supporting Files */ = { isa = PBXGroup; children = ( + 5822BF4C2B8172F800F94625 /* GoogleService-Info.plist */, 8E0A4388244A4A0400656518 /* Assets.xcassets */, 8E0A4389244A4A0400656518 /* LaunchScreen.storyboard */, 8E0A4384244A4A0400656518 /* Constants.swift */, 8E0A4378244A4A0300656518 /* CardinalKit_Example-Bridging-Header.h */, - 276399A029021BB4004DE158 /* GoogleService-Info.plist */, - 8E0A43C9244A4C6500656518 /* Info.plist */, E2F1FD7724D62064006C39DF /* CKConfiguration.plist */, + 8E0A43C9244A4C6500656518 /* Info.plist */, 27A9F0372AC9F0400084D2B8 /* FeatureFlags.swift */, ); path = "Supporting Files"; @@ -453,6 +458,8 @@ 8E7FFFBA25DE37FF002982B4 /* CoffeePieChartView.swift */, 27653A12272A2E7700D74E83 /* LocalTaskListItemView.swift */, 8E6E1E27253538CC0024B8DF /* CloudTaskListItemView.swift */, + 5822BF4D2B81738A00F94625 /* HotlineUIView.swift */, + 5822BF512B817BBB00F94625 /* DataCollectionView.swift */, ); path = Views; sourceTree = ""; @@ -680,6 +687,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5822BF502B81755300F94625 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -688,8 +696,8 @@ buildActionMask = 2147483647; files = ( 8E0A43AF244A4A0400656518 /* Assets.xcassets in Resources */, + 5822BF4F2B81755200F94625 /* GoogleService-Info.plist in Resources */, 8E0A43B0244A4A0400656518 /* LaunchScreen.storyboard in Resources */, - 276399A129021BB5004DE158 /* GoogleService-Info.plist in Resources */, E2F1FD7824D62064006C39DF /* CKConfiguration.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -866,6 +874,7 @@ 8EA664B025941A4D00B6A45A /* SurveyItemViewController.swift in Sources */, 27797418296289F2006D6DE5 /* CKInstructionSteps.swift in Sources */, 8E9CDEBA2591843200C8A228 /* CKConfig.swift in Sources */, + 5822BF522B817BBB00F94625 /* DataCollectionView.swift in Sources */, 2F94C5F22536543600DF8866 /* SceneDelegate+CardinalKit.swift in Sources */, 8E9CDFAE2592B79900C8A228 /* Metrics.swift in Sources */, 27653A13272A2E7700D74E83 /* LocalTaskListItemView.swift in Sources */, @@ -887,6 +896,7 @@ 8E6E1E24253537580024B8DF /* MainUIView.swift in Sources */, 8E6E1E182535263F0024B8DF /* CKTaskViewController.swift in Sources */, 8E9CDF142591B73900C8A228 /* CKHealthRecordsManager.swift in Sources */, + 5822BF4E2B81738A00F94625 /* HotlineUIView.swift in Sources */, 8EA664B42594387900B6A45A /* Errors.swift in Sources */, 275A6AC5296A684800DA4943 /* OnboardingPageView.swift in Sources */, 8E6E1E1225351F830024B8DF /* DocumentPreviewViewController.swift in Sources */, @@ -1133,7 +1143,7 @@ ); MARKETING_VERSION = 2.2.0; MODULE_NAME = ExampleApp; - PRODUCT_BUNDLE_IDENTIFIER = ahjfhomvdtujn; + PRODUCT_BUNDLE_IDENTIFIER = com.safesip; PRODUCT_NAME = "CardinalKit Example"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "CardinalKit/Supporting Files/CardinalKit_Example-Bridging-Header.h"; diff --git a/CardinalKit-Example/CardinalKit/.DS_Store b/CardinalKit-Example/CardinalKit/.DS_Store index 721d3012e639f6297ef0b86b4910e6c3f5a93243..c46bac1538ecd8fe9aa4f7743174e868870af901 100644 GIT binary patch delta 117 zcmZoMXmOBWU|?W$DortDU;r^WfEYvza8E20o2aMA$g?qEH}hr%jz7$c**Q2SHn1@A zZ02Ek!pxacoSc)CpP$1x`3$?!W^JCw%v=)OK%K52&6@=|zB5ne7xA3z&%?pN2r-vo Jb3D%+W&pEi87}|; delta 105 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{Mvv5r;6q~50$jH4hU^g=(_hue}C(M&&Mff)V rW9Q@$WCkh$0s(Fy;R;f{vG6kX{BRh&dpm88*lB%wYxqq0 ORKTaskViewController { let config = CKPropertyReader(file: "CKConfiguration") @@ -132,6 +134,8 @@ struct OnboardingViewController: UIViewControllerRepresentable { /// Create a navigation rule for the sign in screen that will show /// the email/password sign up workflow if the user chose it, /// otherwise skips forward to the passcode entry screen. + /// + let resultSelector = ORKResultSelector(resultIdentifier: "SignInButtons") let booleanAnswerType = ORKResultPredicate.predicateForBooleanQuestionResult( with: resultSelector, diff --git a/CardinalKit-Example/CardinalKit/Components/Onboarding/Steps/CKHealthDataStepViewController.swift b/CardinalKit-Example/CardinalKit/Components/Onboarding/Steps/CKHealthDataStepViewController.swift index 5606eee9..12301739 100755 --- a/CardinalKit-Example/CardinalKit/Components/Onboarding/Steps/CKHealthDataStepViewController.swift +++ b/CardinalKit-Example/CardinalKit/Components/Onboarding/Steps/CKHealthDataStepViewController.swift @@ -19,11 +19,9 @@ class CKHealthDataStep: ORKInstructionStep { let config = CKConfig.shared - title = config.read(query: "Health Permissions Title") ?? "Permission to read Activity Data" + title = config.read(query: "Health Permissions Title") ?? "Permission to read Acceleration Data" text = config.read(query: "Health Permissions Text") ?? """ - Use this text to provide an explanation to your app participants about what activity data \ - you intend to read from the Health app and why. This sample will read step count, distance, \ - heart rate, and flights climbed data. + We will use this data to predict negative health outcomes related to alcohol! """ } diff --git a/CardinalKit-Example/CardinalKit/Components/Tasks/Model/LocalTaskItem.swift b/CardinalKit-Example/CardinalKit/Components/Tasks/Model/LocalTaskItem.swift index f950da5a..a29e4364 100755 --- a/CardinalKit-Example/CardinalKit/Components/Tasks/Model/LocalTaskItem.swift +++ b/CardinalKit-Example/CardinalKit/Components/Tasks/Model/LocalTaskItem.swift @@ -15,13 +15,13 @@ enum LocalTaskItem: Int { * STEP (1) APPEND TABLE ITEMS HERE, * Give each item a recognizable name! */ - case sampleResearchKitSurvey, - sampleResearchKitActiveTask, + case alchoholHotlines, +// sampleResearchKitActiveTask, sampleFHIRSurvey, - sampleFunCoffeeSurvey, - sampleFunCoffeeResult, - sampleCoreMotionAppleWatch, - sampleLearnItem + sampleFunCoffeeSurvey +// sampleFunCoffeeResult, +// sampleCoreMotionAppleWatch, +// sampleLearnItem /* * STEP (2) for each item, what should its @@ -29,20 +29,20 @@ enum LocalTaskItem: Int { */ var title: String { switch self { - case .sampleResearchKitSurvey: - return "Survey (ResearchKit)" + case .alchoholHotlines: + return "Hotlines" case .sampleFHIRSurvey: return "Survey (FHIR)" - case .sampleResearchKitActiveTask: - return "Active Task (ResearchKit)" - case .sampleCoreMotionAppleWatch: - return "Sensors Demo" +// case .sampleResearchKitActiveTask: +// return "Active Task (ResearchKit)" +// case .sampleCoreMotionAppleWatch: +// return "Sensors Demo" case .sampleFunCoffeeSurvey: - return "Coffee Survey" - case .sampleFunCoffeeResult: - return "Coffee Results" - case .sampleLearnItem: - return "About CardinalKit" + return "Alcohol Survey" +// case .sampleFunCoffeeResult: +// return "Survey Results" +// case .sampleLearnItem: +// return "About CardinalKit" } } @@ -51,20 +51,20 @@ enum LocalTaskItem: Int { */ var subtitle: String { switch self { - case .sampleResearchKitSurvey: - return "Sample questions and forms." + case .alchoholHotlines: + return "Important Hotlines!" case .sampleFHIRSurvey: return "Sample questions and forms." - case .sampleResearchKitActiveTask: - return "Sample sensor/data collection activities." - case .sampleCoreMotionAppleWatch: - return "CoreMotion & Cloud Storage" +// case .sampleResearchKitActiveTask: +// return "Sample sensor/data collection activities." +// case .sampleCoreMotionAppleWatch: +// return "CoreMotion & Cloud Storage" case .sampleFunCoffeeSurvey: - return "How do you like your coffee?" - case .sampleFunCoffeeResult: - return "ResearchKit Charts" - case .sampleLearnItem: - return "Visit cardinalkit.org" + return "How do you like your alcohol?" +// case .sampleFunCoffeeResult: +// return "ResearchKit Charts" +// case .sampleLearnItem: +// return "Visit cardinalkit.org" } } @@ -75,18 +75,18 @@ enum LocalTaskItem: Int { */ var image: UIImage? { switch self { - case .sampleResearchKitActiveTask: - return getImage(named: "ActivityIcon") + case .alchoholHotlines: + return getImage(named: "DataIcon") case .sampleFHIRSurvey: return getImage(named: "SurveyIcon") case .sampleFunCoffeeSurvey: return getImage(named: "CoffeeIcon") - case .sampleFunCoffeeResult: - return getImage(named: "DataIcon") - case .sampleCoreMotionAppleWatch: - return getImage(named: "WatchIcon") - case .sampleLearnItem: - return getImage(named: "CKLogoIcon") +// case .sampleFunCoffeeResult: +// return getImage(named: "DataIcon") +// case .sampleCoreMotionAppleWatch: +// return getImage(named: "WatchIcon") +// case .sampleLearnItem: +// return getImage(named: "CKLogoIcon") default: return getImage(named: "SurveyIcon") } @@ -97,12 +97,11 @@ enum LocalTaskItem: Int { */ var section: String { switch self { - case .sampleResearchKitSurvey, .sampleFHIRSurvey, .sampleResearchKitActiveTask: - return "Current Tasks" - case .sampleFunCoffeeSurvey, .sampleFunCoffeeResult: - return "Your Interests" - case .sampleLearnItem, .sampleCoreMotionAppleWatch: - return "Learn" + case .alchoholHotlines, .sampleFunCoffeeSurvey: + return "Important Information" + case .sampleFHIRSurvey: + return "Your Current Stat" + } } @@ -112,20 +111,13 @@ enum LocalTaskItem: Int { */ var action: some View { switch self { - case .sampleResearchKitSurvey: - return AnyView(CKTaskViewController(tasks: TaskSamples.sampleSurveyTask)) + case .alchoholHotlines: + return AnyView(HotlineUIView()) case .sampleFHIRSurvey: return AnyView(CKFHIRTaskViewController(tasks: TaskSamples.sampleFHIRTask)) - case .sampleResearchKitActiveTask: - return AnyView(CKTaskViewController(tasks: TaskSamples.sampleWalkingTask)) - case .sampleCoreMotionAppleWatch: - return AnyView(SensorsDemoUIView()) + case .sampleFunCoffeeSurvey: return AnyView(CKTaskViewController(tasks: TaskSamples.sampleCoffeeTask)) - case .sampleFunCoffeeResult: - return AnyView(CoffeeUIView()) - case .sampleLearnItem: - return AnyView(LearnUIView()) } } diff --git a/CardinalKit-Example/CardinalKit/Components/Tasks/Model/TaskSamples.swift b/CardinalKit-Example/CardinalKit/Components/Tasks/Model/TaskSamples.swift index 9ca2a8e2..a1599318 100755 --- a/CardinalKit-Example/CardinalKit/Components/Tasks/Model/TaskSamples.swift +++ b/CardinalKit-Example/CardinalKit/Components/Tasks/Model/TaskSamples.swift @@ -58,9 +58,9 @@ enum TaskSamples { minimumValueDescription: "None 😴" ) let coffeeScaleQuestionStep = ORKQuestionStep( - identifier: "CoffeeScaleQuestionStep", - title: "Coffee Intake", - question: "How many cups of coffee do you drink per day?", + identifier: "AlcoholScaleQuestionStep", + title: "Alcohol Intake", + question: "How many cups of alcohol do you drink per day?", answer: coffeeScaleAnswerFormat ) diff --git a/CardinalKit-Example/CardinalKit/Components/Tasks/TasksUIView.swift b/CardinalKit-Example/CardinalKit/Components/Tasks/TasksUIView.swift index ab5f903d..5b489c0b 100644 --- a/CardinalKit-Example/CardinalKit/Components/Tasks/TasksUIView.swift +++ b/CardinalKit-Example/CardinalKit/Components/Tasks/TasksUIView.swift @@ -7,6 +7,14 @@ // import ResearchKit import SwiftUI +import CardinalKit +import CareKit +import CareKitFHIR +import CareKitStore +import HealthKit +import UIKit + + struct TasksUIView: View { var date = "" @@ -64,6 +72,90 @@ struct TasksUIView: View { } } + let motionManager = CMMotionManager() + + func startAccelerometerUpdates() { + if motionManager.isAccelerometerAvailable { + motionManager.accelerometerUpdateInterval = 0.1 + motionManager.startAccelerometerUpdates(to: .main) { (data, error) in + guard let accelerometerData = data else { return } + + let dataDictionary: [String: Any] = [ + "x": accelerometerData.acceleration.x, + "y": accelerometerData.acceleration.y, + "z": accelerometerData.acceleration.z, + "timestamp": Date().timeIntervalSince1970 + ] + + guard let authCollection = CKStudyUser.shared.authCollection else { + return + } + + let route = "\(authCollection)\(Constants.dataBucketFHIRQuestionnaireResponse)/\(Date().timeIntervalSince1970)" + + + + CKApp.sendData(route: route, data: dataDictionary, params: nil) { success, error in + if success { + print("Accelerometer data uploaded successfully!") + } else { + print("Error uploading accelerometer data:", error?.localizedDescription ?? "Unknown error") + } + } + } + } else { + print("Accelerometer is not available") + } + } + + + struct AIModelResponse: Codable { + let userId: Int + let id: Int + let title: String + let completed: Bool + } + + @State private var apiResponse: AIModelResponse? + + + func callAPI() { + guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1") else { + print("Invalid URL") + return + } + + let task = URLSession.shared.dataTask(with: url) { data, response, error in + if let error = error { + print("Error: \(error)") + return + } + + guard let httpResponse = response as? HTTPURLResponse, + (200...299).contains(httpResponse.statusCode) else { + print("Invalid response") + return + } + + if let data = data { + do { + let apiResponse = try JSONDecoder().decode(AIModelResponse.self, from: data) + print("API Response: \(apiResponse)") + + DispatchQueue.main.async { + self.apiResponse = apiResponse // Update the state on the main thread + } + } catch { + print("Error decoding JSON: \(error)") + } + } + } + + task.resume() + } + let timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect() + + var body: some View { VStack { Text(config.read(query: "Study Title") ?? "CardinalKit") @@ -72,8 +164,18 @@ struct TasksUIView: View { .padding(.top, 10) Text(config.read(query: "Team Name") ?? "Stanford Byers Center for Bidoesign") .font(.system(size: 15, weight: .light)) + Text(date).font(.system(size: 18, weight: .regular)).padding() - + Button(action: { + startAccelerometerUpdates() + }) { + Text("Start Accelerometer Updates") + .padding() + .foregroundColor(.white) + .background(Color.blue) + .cornerRadius(10) + } + .padding() if useCloudSurveys { List { ForEach(listItemsSections, id: \.self) { key in @@ -99,13 +201,21 @@ struct TasksUIView: View { } }.listStyle(GroupedListStyle()) } + Text(apiResponse != nil ? "API Response: \(apiResponse!.completed.description)" : "No response yet") } .onAppear(perform: { self.useCloudSurveys = config.readBool(query: "Use Cloud Surveys") ?? false if self.useCloudSurveys { getRemoteItems() } + }) + .onReceive(timer) { _ in + print("Timer ticked!") + // Call the function at each timer tick + self.callAPI() + } + } } diff --git a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/CoffeePieChartView.swift b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/CoffeePieChartView.swift index 581f5a71..7e91028f 100644 --- a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/CoffeePieChartView.swift +++ b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/CoffeePieChartView.swift @@ -22,9 +22,9 @@ struct CoffeePieChartView: UIViewRepresentable { let chartView = ORKPieChartView() chartView.tintColor = tintColor chartView.showsTitleAboveChart = true - chartView.title = "Do you drink coffee?" - chartView.text = "How many cups per day?" - chartView.noDataText = "Take the coffee survey and come back!" + chartView.title = "Do you drink alcohol?" + chartView.text = "How many drinks per day?" + chartView.noDataText = "Take the alcohol survey and come back!" CoffeeChartDataSource.fetchData { result in let dataSource = CoffeeChartDataSource(countPerAnswer: result) diff --git a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/DataCollectionView.swift b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/DataCollectionView.swift index e9755917..e493a250 100644 --- a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/DataCollectionView.swift +++ b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/DataCollectionView.swift @@ -6,14 +6,73 @@ // Copyright © 2024 CardinalKit. All rights reserved. // +import Firebase import SwiftUI +import CoreMotion +import Foundation -struct DataCollectionView: View { +import CardinalKit +import CareKit +import CareKitFHIR +import CareKitStore +import HealthKit + + +struct AccelerometerDataUploaderView: View { + let motionManager = CMMotionManager() + let identifier = "1" + + var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + VStack { + Button(action: { + startAccelerometerUpdates() + }) { + Text("Start Accelerometer Updates") + .padding() + .foregroundColor(.white) + .background(Color.blue) + .cornerRadius(10) + } + .padding() + } + } + + func startAccelerometerUpdates() { + if motionManager.isAccelerometerAvailable { + motionManager.accelerometerUpdateInterval = 0.1 + motionManager.startAccelerometerUpdates(to: .main) { (data, error) in + guard let accelerometerData = data else { return } + + let dataDictionary: [String: Any] = [ + "x": accelerometerData.acceleration.x, + "y": accelerometerData.acceleration.y, + "z": accelerometerData.acceleration.z, + "timestamp": Date().timeIntervalSince1970 + ] + + guard let authCollection = CKStudyUser.shared.authCollection else { + return + } + + let route = "\(authCollection)\(Constants.dataBucketFHIRQuestionnaireResponse)/\(Date().timeIntervalSince1970)" + + + + CKApp.sendData(route: route, data: dataDictionary, params: nil) { success, error in + if success { + print("Accelerometer data uploaded successfully!") + } else { + print("Error uploading accelerometer data:", error?.localizedDescription ?? "Unknown error") + } + } + } + } else { + print("Accelerometer is not available") + } } } #Preview { - DataCollectionView() + AccelerometerDataUploaderView() } diff --git a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/HotlineUIView.swift b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/HotlineUIView.swift index f9553bd5..19bbaa5a 100644 --- a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/HotlineUIView.swift +++ b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/HotlineUIView.swift @@ -8,12 +8,38 @@ import SwiftUI +struct Hotline: Identifiable { + var id = UUID() + var name: String + var phoneNumber: String +} + struct HotlineUIView: View { + let hotlines = [ + Hotline(name: "National Drug and Alcohol Treatment Referral Routing Service (SAMHSA)", phoneNumber: "1-800-662-HELP (1-800-662-4357)"), + Hotline(name: "Alcoholics Anonymous (AA) Hotline", phoneNumber: "(212) 870-3400"), + Hotline(name: "National Council on Alcoholism and Drug Dependence (NCADD) Hopeline", phoneNumber: "1-800-NCA-CALL (1-800-622-2255)"), + Hotline(name: "Al-Anon Family Groups Helpline", phoneNumber: "1-888-4AL-ANON (1-888-425-2666)"), + Hotline(name: "National Suicide Prevention Lifeline", phoneNumber: "1-800-273-TALK (1-800-273-8255)") + ] + var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + NavigationView { + List(hotlines) { hotline in + VStack(alignment: .leading) { + Text(hotline.name) + .font(.headline) + Text(hotline.phoneNumber) + .font(.subheadline) + .foregroundColor(.gray) + } + } + .navigationBarTitle("Alcohol Hotlines") + } } } + #Preview { HotlineUIView() } diff --git a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/LocalTaskListItemView.swift b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/LocalTaskListItemView.swift index 93007663..fcff1ef4 100644 --- a/CardinalKit-Example/CardinalKit/Components/Tasks/Views/LocalTaskListItemView.swift +++ b/CardinalKit-Example/CardinalKit/Components/Tasks/Views/LocalTaskListItemView.swift @@ -51,8 +51,4 @@ struct LocalTaskListItemView: View { } } -struct LocalTaskListItemView_Previews: PreviewProvider { - static var previews: some View { - LocalTaskListItemView(item: .sampleCoreMotionAppleWatch) - } -} + diff --git a/CardinalKit-Example/CardinalKit/Supporting Files/CKConfiguration.plist b/CardinalKit-Example/CardinalKit/Supporting Files/CKConfiguration.plist index 65e4273b..78156897 100644 --- a/CardinalKit-Example/CardinalKit/Supporting Files/CKConfiguration.plist +++ b/CardinalKit-Example/CardinalKit/Supporting Files/CKConfiguration.plist @@ -5,15 +5,15 @@ AppId 415789243347763 Study Title - CardinalKit + SafeSip Team Name - Stanford Byers Center for Biodesign + Treehacks <3 Email - contact@domain.com + aakritil@stanford.edu Phone - 123-456-7890 + 704-293-0705 Copyright - Made at Stanford with ❤️ + Website https://cardinalkit.org Tint Color @@ -35,15 +35,13 @@ Completion Step Text This step concludes the onboarding and consent process of the CardinalKit framework. Next up, you will see main app functionality. Health Permissions Title - Permission to read Activity Data 🏃🏽‍♀️ + Permission to read Accelerometer Data Health Permissions Text - Use this text to provide an explanation to your app participants about what activity data you intend to read from the Health app and why. This sample will read step count, distance, heart rate, and flights climbed data. + We use this data to predict negative health outcomes related to alcohol. Health Records Enabled - Permissions Text - Use this text to provide an explanation to your app participants about what electronic health records (EHR) you intend to collect from the Health app and why. This sample will read all available records (for which permission is granted). Permissions Title Permission to read Health Records 🏥 @@ -52,7 +50,7 @@ Sign In With Google Sign In With Email - + Withdrawal Instruction Title Are you sure you want to withdraw? Withdrawal Instruction Text @@ -171,30 +169,6 @@ Contacts - - givenName - Oliver - familyName - Aalami - title - Vascular Surgeon - role - Dr. Aalami is the director of the CardinalKit project. - email - aalami@stanford.edu - phone - 111-111-1111 - text - 111-111-1111 - street - 318 Campus Drive - city - Stanford - state - CA - postalCode - 94305 - givenName Johnny diff --git a/CardinalKit-Example/CardinalKit/Supporting Files/GoogleService-Info.plist b/CardinalKit-Example/CardinalKit/Supporting Files/GoogleService-Info.plist new file mode 100644 index 00000000..b61be568 --- /dev/null +++ b/CardinalKit-Example/CardinalKit/Supporting Files/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 281223930916-s9ttij3nlc18ce546aquaht9drfi96tu.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.281223930916-s9ttij3nlc18ce546aquaht9drfi96tu + API_KEY + AIzaSyABVT50tb7Gkreht7ua5kY1v4OPH7LW2ko + GCM_SENDER_ID + 281223930916 + PLIST_VERSION + 1 + BUNDLE_ID + com.safesip + PROJECT_ID + guardian-dcf69 + STORAGE_BUCKET + guardian-dcf69.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:281223930916:ios:2ad5808ef5e5b20d7824b1 + + \ No newline at end of file diff --git a/CardinalKit-Example/CardinalKit/Supporting Files/Info.plist b/CardinalKit-Example/CardinalKit/Supporting Files/Info.plist index af674036..7d662eb6 100755 --- a/CardinalKit-Example/CardinalKit/Supporting Files/Info.plist +++ b/CardinalKit-Example/CardinalKit/Supporting Files/Info.plist @@ -25,9 +25,10 @@ Editor CFBundleURLSchemes - com.googleusercontent.apps.949411969311-25li9prr4lnl9njusscqv5rq586j3un4 + com.googleusercontent.apps.281223930916-s9ttij3nlc18ce546aquaht9drfi96tu + CFBundleVersion 6 @@ -103,6 +104,7 @@ LaunchScreen UIRequiredDeviceCapabilities + accelerometer armv7 UIStatusBarStyle diff --git a/CardinalKit.podspec b/CardinalKit.podspec index 821980cd..27e14831 100755 --- a/CardinalKit.podspec +++ b/CardinalKit.podspec @@ -7,8 +7,8 @@ # Pod::Spec.new do |s| - s.name = 'CardinalKit' - s.version = '2.2.0' + s.name = 'SafeSip' + s.version = '1.1.0' s.summary = 'https://cardinalkit.org/' s.description = 'CardinalKit empowers the digital health community to rapidly prototype and build modern, interoperable, scalable digital health solutions on a variety of platforms.' diff --git a/CardinalKit/Source/Components/Networking/CKNetworkManager.swift b/CardinalKit/Source/Components/Networking/CKNetworkManager.swift index c89ee035..ebc54d43 100644 --- a/CardinalKit/Source/Components/Networking/CKNetworkManager.swift +++ b/CardinalKit/Source/Components/Networking/CKNetworkManager.swift @@ -10,6 +10,8 @@ import FirebaseAuth import FirebaseFirestore import FirebaseStorage + + public protocol CKAPIRouteDelegate { func getAPIRoute(type: PackageType) -> String? func getWhitelistDomains() -> [String]