├── .gitignore ├── .gitmodules ├── LICENSE.txt ├── README.md ├── Recover Final ├── Recover.xcodeproj │ └── project.pbxproj └── Recover │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── CareFeedViewController.swift │ ├── Info.plist │ ├── InsightsViewController.swift │ ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json │ ├── Recover.entitlements │ ├── Supporting Files │ ├── Consent.swift │ ├── Launch Screen.storyboard │ ├── Logging.swift │ ├── OCKAnyEvent+Answer.swift │ ├── SceneDelegate.swift │ └── Tasks.swift │ └── Surveys.swift ├── Recover Part 1 ├── Recover.xcodeproj │ └── project.pbxproj └── Recover │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── CareFeedViewController.swift │ ├── Info.plist │ ├── InsightsViewController.swift │ ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json │ ├── Recover.entitlements │ ├── Supporting Files │ ├── Consent.swift │ ├── Launch Screen.storyboard │ ├── Logging.swift │ ├── OCKAnyEvent+Answer.swift │ ├── SceneDelegate.swift │ └── Tasks.swift │ └── Surveys.swift ├── Recover Part 2 ├── Recover.xcodeproj │ └── project.pbxproj └── Recover │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── CareFeedViewController.swift │ ├── Info.plist │ ├── InsightsViewController.swift │ ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json │ ├── Recover.entitlements │ ├── Supporting Files │ ├── Consent.swift │ ├── Launch Screen.storyboard │ ├── Logging.swift │ ├── OCKAnyEvent+Answer.swift │ ├── SceneDelegate.swift │ └── Tasks.swift │ └── Surveys.swift └── Recover Part 3 ├── Recover.xcodeproj └── project.pbxproj └── Recover ├── AppDelegate.swift ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── CareFeedViewController.swift ├── Info.plist ├── InsightsViewController.swift ├── Preview Content └── Preview Assets.xcassets │ └── Contents.json ├── Recover.entitlements ├── Supporting Files ├── Consent.swift ├── Launch Screen.storyboard ├── Logging.swift ├── OCKAnyEvent+Answer.swift ├── SceneDelegate.swift └── Tasks.swift └── Surveys.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Xcode 4 | build/* 5 | */build/* 6 | */**/build/* 7 | *.mode1 8 | *.pbxuser 9 | *.perspective 10 | !default.perspectivev3 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | **/*.xcodeproj/project.xcworkspace/* 19 | **/*.playground/playground.xcworkspace/* 20 | xcuserdata 21 | profile 22 | *.moved-aside 23 | Distribution/ 24 | 25 | # Generated files 26 | VersionX-revision.h 27 | 28 | # build products 29 | build/ 30 | *.[oa] 31 | 32 | # version control files 33 | .hg 34 | .svn 35 | CVS 36 | 37 | # automatic backup files 38 | *~.nib 39 | *.swp 40 | *~ 41 | *(Autosaved).rtfd/ 42 | Backup[ ]of[ ]*.pages/ 43 | Backup[ ]of[ ]*.key/ 44 | Backup[ ]of[ ]*.numbers/ 45 | 46 | # Cocopods 47 | Pods/ 48 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ResearchKit"] 2 | path = ResearchKit 3 | url = https://github.com/ResearchKit/ResearchKit 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2021 Apple Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Recover 2 | 3 | Recover is a sample study app built using Apple's ResearchKit and CareKit frameworks. Be sure to watch the accompanying WWDC videos. 4 | - [Build a research and care app, part 1: Setup onboarding](https://developer.apple.com/wwdc21/10068) 5 | - [Build a research and care app, part 2: Schedule tasks](https://developer.apple.com/wwdc21/10069) 6 | - [Build a research and care app, part 3: Visualize progress](https://developer.apple.com/wwdc21/10282) 7 | 8 | # Minimum Requirements 9 | 10 | - iOS 13.0 11 | - Xcode 12.0 12 | 13 | # Setup 14 | 15 | 1. Download the repository and the required submodules: 16 | 17 | ```bash 18 | git clone --recurse-submodule https://github.com/carekit-apple/WWDC21-RecoverApp.git 19 | ``` 20 | 21 | 2. Choose the target named `Recover` and run the app. 22 | 23 | # Files 24 | 25 | - `AppDelegate.swift`: Contains logic that sets up the CareKit store. 26 | 27 | - `Surveys.swift`: Defines ResearchKit tasks such as surveys and onboarding. 28 | 29 | - `CareFeedViewController.swift`: Contains logic that fetches and displays tasks from the CareKit store. 30 | 31 | - `InsightsViewController.swift` Contains logic that sets up the 3D model and charts for visualizing progress. 32 | 33 | # 3D Model 34 | 35 | By default, the "Insights" tab in the app displays a 3D model of a toy robot. To view the toy robot, download [this](https://developer.apple.com/augmented-reality/quick-look/models/vintagerobot2k/toy_robot_vintage.usdz) file and drag it into your project in Xcode. Alternatively, you can provide custom built models or use 3rd party solutions. In order to display the knee model shown in the demo, you can install the SDK provided by - [BioDigital](https://developer.biodigital.com/docs/ios-sdk/apple-research-kit). 36 | -------------------------------------------------------------------------------- /Recover Final/Recover.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 03105DFF2616906400805B3A /* Tasks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03105DFE2616906400805B3A /* Tasks.swift */; }; 11 | 033F70502628E7F80034C876 /* OCKAnyEvent+Answer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033F704F2628E7F80034C876 /* OCKAnyEvent+Answer.swift */; }; 12 | 0353057B2617AA5200216742 /* InsightsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0353057A2617AA5200216742 /* InsightsViewController.swift */; }; 13 | 03543EC92612777600FB2C37 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03543EC82612777600FB2C37 /* Logging.swift */; }; 14 | 03543ECB2612A64F00FB2C37 /* Surveys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03543ECA2612A64F00FB2C37 /* Surveys.swift */; }; 15 | 03DC29E52641BE7F00DC5FC6 /* Consent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DC29E42641BE7F00DC5FC6 /* Consent.swift */; }; 16 | 51415DC8260B877100A76FC5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51415DC7260B877100A76FC5 /* AppDelegate.swift */; }; 17 | 51415DCA260B877100A76FC5 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51415DC9260B877100A76FC5 /* SceneDelegate.swift */; }; 18 | 51415DCC260B877100A76FC5 /* CareFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51415DCB260B877100A76FC5 /* CareFeedViewController.swift */; }; 19 | 51415DCE260B877300A76FC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51415DCD260B877300A76FC5 /* Assets.xcassets */; }; 20 | 51415DD1260B877300A76FC5 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51415DD0260B877300A76FC5 /* Preview Assets.xcassets */; }; 21 | 51415DE0260B8AD500A76FC5 /* CareKit in Frameworks */ = {isa = PBXBuildFile; productRef = 51415DDF260B8AD500A76FC5 /* CareKit */; }; 22 | 51415DE2260B8AD500A76FC5 /* CareKitStore in Frameworks */ = {isa = PBXBuildFile; productRef = 51415DE1260B8AD500A76FC5 /* CareKitStore */; }; 23 | 51415DE4260B8AD500A76FC5 /* CareKitUI in Frameworks */ = {isa = PBXBuildFile; productRef = 51415DE3260B8AD500A76FC5 /* CareKitUI */; }; 24 | 514C86C0260B92F10086AECB /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 514C86BF260B92F10086AECB /* Launch Screen.storyboard */; }; 25 | 518F2A01261FC1CF00A9674E /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 518F2A00261FC1CF00A9674E /* HealthKit.framework */; }; 26 | 5192FB43265DC85100F75887 /* ResearchKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5192FB40265DC7AA00F75887 /* ResearchKit.framework */; }; 27 | 5192FB44265DC85100F75887 /* ResearchKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5192FB40265DC7AA00F75887 /* ResearchKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXContainerItemProxy section */ 31 | 5192FB3F265DC7AA00F75887 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 5192FB39265DC7A900F75887 /* ResearchKit.xcodeproj */; 34 | proxyType = 2; 35 | remoteGlobalIDString = B183A5951A8535D100C76870; 36 | remoteInfo = ResearchKit; 37 | }; 38 | 5192FB41265DC7AA00F75887 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = 5192FB39265DC7A900F75887 /* ResearchKit.xcodeproj */; 41 | proxyType = 2; 42 | remoteGlobalIDString = 86CC8E9A1AC09332001CCD89; 43 | remoteInfo = ResearchKitTests; 44 | }; 45 | /* End PBXContainerItemProxy section */ 46 | 47 | /* Begin PBXCopyFilesBuildPhase section */ 48 | 032E79B32655C2EF004807F9 /* Embed Frameworks */ = { 49 | isa = PBXCopyFilesBuildPhase; 50 | buildActionMask = 2147483647; 51 | dstPath = ""; 52 | dstSubfolderSpec = 10; 53 | files = ( 54 | 5192FB44265DC85100F75887 /* ResearchKit.framework in Embed Frameworks */, 55 | ); 56 | name = "Embed Frameworks"; 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXCopyFilesBuildPhase section */ 60 | 61 | /* Begin PBXFileReference section */ 62 | 03105DFE2616906400805B3A /* Tasks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tasks.swift; sourceTree = ""; }; 63 | 033F704F2628E7F80034C876 /* OCKAnyEvent+Answer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OCKAnyEvent+Answer.swift"; sourceTree = ""; }; 64 | 0353057A2617AA5200216742 /* InsightsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsightsViewController.swift; sourceTree = ""; }; 65 | 03543EC82612777600FB2C37 /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; 66 | 03543ECA2612A64F00FB2C37 /* Surveys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Surveys.swift; sourceTree = ""; }; 67 | 03B9AD3F262E2FA9009C4320 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 68 | 03DC29E42641BE7F00DC5FC6 /* Consent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Consent.swift; sourceTree = ""; }; 69 | 51415DC4260B877100A76FC5 /* Recover.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Recover.app; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | 51415DC7260B877100A76FC5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 71 | 51415DC9260B877100A76FC5 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 72 | 51415DCB260B877100A76FC5 /* CareFeedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CareFeedViewController.swift; sourceTree = ""; }; 73 | 51415DCD260B877300A76FC5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 74 | 51415DD0260B877300A76FC5 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 75 | 51415DD5260B877300A76FC5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | 514C86BF260B92F10086AECB /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; 77 | 518F29FF261FC1CF00A9674E /* Recover.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Recover.entitlements; sourceTree = ""; }; 78 | 518F2A00261FC1CF00A9674E /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; 79 | 5192FB39265DC7A900F75887 /* ResearchKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ResearchKit.xcodeproj; path = ../ResearchKit/ResearchKit.xcodeproj; sourceTree = ""; }; 80 | /* End PBXFileReference section */ 81 | 82 | /* Begin PBXFrameworksBuildPhase section */ 83 | 51415DC1260B877100A76FC5 /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | 51415DE0260B8AD500A76FC5 /* CareKit in Frameworks */, 88 | 51415DE4260B8AD500A76FC5 /* CareKitUI in Frameworks */, 89 | 518F2A01261FC1CF00A9674E /* HealthKit.framework in Frameworks */, 90 | 51415DE2260B8AD500A76FC5 /* CareKitStore in Frameworks */, 91 | 5192FB43265DC85100F75887 /* ResearchKit.framework in Frameworks */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXFrameworksBuildPhase section */ 96 | 97 | /* Begin PBXGroup section */ 98 | 03543EC426126CA100FB2C37 /* Frameworks */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 518F2A00261FC1CF00A9674E /* HealthKit.framework */, 102 | ); 103 | name = Frameworks; 104 | sourceTree = ""; 105 | }; 106 | 03F0BE5B2661A1AE005B5D5F /* Supporting Files */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 514C86BF260B92F10086AECB /* Launch Screen.storyboard */, 110 | 51415DC9260B877100A76FC5 /* SceneDelegate.swift */, 111 | 03543EC82612777600FB2C37 /* Logging.swift */, 112 | 03105DFE2616906400805B3A /* Tasks.swift */, 113 | 03DC29E42641BE7F00DC5FC6 /* Consent.swift */, 114 | 033F704F2628E7F80034C876 /* OCKAnyEvent+Answer.swift */, 115 | ); 116 | path = "Supporting Files"; 117 | sourceTree = ""; 118 | }; 119 | 51415DBB260B877100A76FC5 = { 120 | isa = PBXGroup; 121 | children = ( 122 | 5192FB39265DC7A900F75887 /* ResearchKit.xcodeproj */, 123 | 03B9AD3F262E2FA9009C4320 /* README.md */, 124 | 51415DC6260B877100A76FC5 /* Recover */, 125 | 51415DC5260B877100A76FC5 /* Products */, 126 | 03543EC426126CA100FB2C37 /* Frameworks */, 127 | ); 128 | sourceTree = ""; 129 | }; 130 | 51415DC5260B877100A76FC5 /* Products */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 51415DC4260B877100A76FC5 /* Recover.app */, 134 | ); 135 | name = Products; 136 | sourceTree = ""; 137 | }; 138 | 51415DC6260B877100A76FC5 /* Recover */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 51415DC7260B877100A76FC5 /* AppDelegate.swift */, 142 | 51415DCB260B877100A76FC5 /* CareFeedViewController.swift */, 143 | 0353057A2617AA5200216742 /* InsightsViewController.swift */, 144 | 03543ECA2612A64F00FB2C37 /* Surveys.swift */, 145 | 51415DCD260B877300A76FC5 /* Assets.xcassets */, 146 | 51415DD5260B877300A76FC5 /* Info.plist */, 147 | 518F29FF261FC1CF00A9674E /* Recover.entitlements */, 148 | 03F0BE5B2661A1AE005B5D5F /* Supporting Files */, 149 | 51415DCF260B877300A76FC5 /* Preview Content */, 150 | ); 151 | path = Recover; 152 | sourceTree = ""; 153 | }; 154 | 51415DCF260B877300A76FC5 /* Preview Content */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 51415DD0260B877300A76FC5 /* Preview Assets.xcassets */, 158 | ); 159 | path = "Preview Content"; 160 | sourceTree = ""; 161 | }; 162 | 5192FB3A265DC7A900F75887 /* Products */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 5192FB40265DC7AA00F75887 /* ResearchKit.framework */, 166 | 5192FB42265DC7AA00F75887 /* ResearchKitTests.xctest */, 167 | ); 168 | name = Products; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 51415DC3260B877100A76FC5 /* Recover */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 51415DD8260B877300A76FC5 /* Build configuration list for PBXNativeTarget "Recover" */; 177 | buildPhases = ( 178 | 51415DC0260B877100A76FC5 /* Sources */, 179 | 51415DC1260B877100A76FC5 /* Frameworks */, 180 | 51415DC2260B877100A76FC5 /* Resources */, 181 | 032E79B32655C2EF004807F9 /* Embed Frameworks */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | ); 187 | name = Recover; 188 | packageProductDependencies = ( 189 | 51415DDF260B8AD500A76FC5 /* CareKit */, 190 | 51415DE1260B8AD500A76FC5 /* CareKitStore */, 191 | 51415DE3260B8AD500A76FC5 /* CareKitUI */, 192 | ); 193 | productName = Recover; 194 | productReference = 51415DC4260B877100A76FC5 /* Recover.app */; 195 | productType = "com.apple.product-type.application"; 196 | }; 197 | /* End PBXNativeTarget section */ 198 | 199 | /* Begin PBXProject section */ 200 | 51415DBC260B877100A76FC5 /* Project object */ = { 201 | isa = PBXProject; 202 | attributes = { 203 | LastSwiftUpdateCheck = 1300; 204 | LastUpgradeCheck = 1300; 205 | TargetAttributes = { 206 | 51415DC3260B877100A76FC5 = { 207 | CreatedOnToolsVersion = 13.0; 208 | }; 209 | }; 210 | }; 211 | buildConfigurationList = 51415DBF260B877100A76FC5 /* Build configuration list for PBXProject "Recover" */; 212 | compatibilityVersion = "Xcode 9.3"; 213 | developmentRegion = en; 214 | hasScannedForEncodings = 0; 215 | knownRegions = ( 216 | en, 217 | Base, 218 | ); 219 | mainGroup = 51415DBB260B877100A76FC5; 220 | packageReferences = ( 221 | 51415DDC260B8AD500A76FC5 /* XCRemoteSwiftPackageReference "CareKit" */, 222 | ); 223 | productRefGroup = 51415DC5260B877100A76FC5 /* Products */; 224 | projectDirPath = ""; 225 | projectReferences = ( 226 | { 227 | ProductGroup = 5192FB3A265DC7A900F75887 /* Products */; 228 | ProjectRef = 5192FB39265DC7A900F75887 /* ResearchKit.xcodeproj */; 229 | }, 230 | ); 231 | projectRoot = ""; 232 | targets = ( 233 | 51415DC3260B877100A76FC5 /* Recover */, 234 | ); 235 | }; 236 | /* End PBXProject section */ 237 | 238 | /* Begin PBXReferenceProxy section */ 239 | 5192FB40265DC7AA00F75887 /* ResearchKit.framework */ = { 240 | isa = PBXReferenceProxy; 241 | fileType = wrapper.framework; 242 | path = ResearchKit.framework; 243 | remoteRef = 5192FB3F265DC7AA00F75887 /* PBXContainerItemProxy */; 244 | sourceTree = BUILT_PRODUCTS_DIR; 245 | }; 246 | 5192FB42265DC7AA00F75887 /* ResearchKitTests.xctest */ = { 247 | isa = PBXReferenceProxy; 248 | fileType = wrapper.cfbundle; 249 | path = ResearchKitTests.xctest; 250 | remoteRef = 5192FB41265DC7AA00F75887 /* PBXContainerItemProxy */; 251 | sourceTree = BUILT_PRODUCTS_DIR; 252 | }; 253 | /* End PBXReferenceProxy section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | 51415DC2260B877100A76FC5 /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 514C86C0260B92F10086AECB /* Launch Screen.storyboard in Resources */, 261 | 51415DD1260B877300A76FC5 /* Preview Assets.xcassets in Resources */, 262 | 51415DCE260B877300A76FC5 /* Assets.xcassets in Resources */, 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | /* End PBXResourcesBuildPhase section */ 267 | 268 | /* Begin PBXSourcesBuildPhase section */ 269 | 51415DC0260B877100A76FC5 /* Sources */ = { 270 | isa = PBXSourcesBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | 03105DFF2616906400805B3A /* Tasks.swift in Sources */, 274 | 51415DC8260B877100A76FC5 /* AppDelegate.swift in Sources */, 275 | 03543ECB2612A64F00FB2C37 /* Surveys.swift in Sources */, 276 | 03543EC92612777600FB2C37 /* Logging.swift in Sources */, 277 | 033F70502628E7F80034C876 /* OCKAnyEvent+Answer.swift in Sources */, 278 | 51415DCA260B877100A76FC5 /* SceneDelegate.swift in Sources */, 279 | 51415DCC260B877100A76FC5 /* CareFeedViewController.swift in Sources */, 280 | 03DC29E52641BE7F00DC5FC6 /* Consent.swift in Sources */, 281 | 0353057B2617AA5200216742 /* InsightsViewController.swift in Sources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | /* End PBXSourcesBuildPhase section */ 286 | 287 | /* Begin XCBuildConfiguration section */ 288 | 51415DD6260B877300A76FC5 /* Debug */ = { 289 | isa = XCBuildConfiguration; 290 | buildSettings = { 291 | ALWAYS_SEARCH_USER_PATHS = NO; 292 | CLANG_ANALYZER_NONNULL = YES; 293 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 294 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 295 | CLANG_CXX_LIBRARY = "libc++"; 296 | CLANG_ENABLE_MODULES = YES; 297 | CLANG_ENABLE_OBJC_ARC = YES; 298 | CLANG_ENABLE_OBJC_WEAK = YES; 299 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 300 | CLANG_WARN_BOOL_CONVERSION = YES; 301 | CLANG_WARN_COMMA = YES; 302 | CLANG_WARN_CONSTANT_CONVERSION = YES; 303 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 304 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 305 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 306 | CLANG_WARN_EMPTY_BODY = YES; 307 | CLANG_WARN_ENUM_CONVERSION = YES; 308 | CLANG_WARN_INFINITE_RECURSION = YES; 309 | CLANG_WARN_INT_CONVERSION = YES; 310 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 311 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 312 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 313 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 314 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 315 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 316 | CLANG_WARN_STRICT_PROTOTYPES = YES; 317 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 318 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 319 | CLANG_WARN_UNREACHABLE_CODE = YES; 320 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 321 | COPY_PHASE_STRIP = NO; 322 | DEBUG_INFORMATION_FORMAT = dwarf; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | ENABLE_TESTABILITY = YES; 325 | GCC_C_LANGUAGE_STANDARD = gnu11; 326 | GCC_DYNAMIC_NO_PIC = NO; 327 | GCC_NO_COMMON_BLOCKS = YES; 328 | GCC_OPTIMIZATION_LEVEL = 0; 329 | GCC_PREPROCESSOR_DEFINITIONS = ( 330 | "DEBUG=1", 331 | "$(inherited)", 332 | ); 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 340 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 341 | MTL_FAST_MATH = YES; 342 | ONLY_ACTIVE_ARCH = YES; 343 | SDKROOT = iphoneos; 344 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 345 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 346 | }; 347 | name = Debug; 348 | }; 349 | 51415DD7260B877300A76FC5 /* Release */ = { 350 | isa = XCBuildConfiguration; 351 | buildSettings = { 352 | ALWAYS_SEARCH_USER_PATHS = NO; 353 | CLANG_ANALYZER_NONNULL = YES; 354 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 355 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 356 | CLANG_CXX_LIBRARY = "libc++"; 357 | CLANG_ENABLE_MODULES = YES; 358 | CLANG_ENABLE_OBJC_ARC = YES; 359 | CLANG_ENABLE_OBJC_WEAK = YES; 360 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 361 | CLANG_WARN_BOOL_CONVERSION = YES; 362 | CLANG_WARN_COMMA = YES; 363 | CLANG_WARN_CONSTANT_CONVERSION = YES; 364 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 365 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 366 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 367 | CLANG_WARN_EMPTY_BODY = YES; 368 | CLANG_WARN_ENUM_CONVERSION = YES; 369 | CLANG_WARN_INFINITE_RECURSION = YES; 370 | CLANG_WARN_INT_CONVERSION = YES; 371 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 372 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 373 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 374 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 375 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 376 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 377 | CLANG_WARN_STRICT_PROTOTYPES = YES; 378 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 379 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 380 | CLANG_WARN_UNREACHABLE_CODE = YES; 381 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 382 | COPY_PHASE_STRIP = NO; 383 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 384 | ENABLE_NS_ASSERTIONS = NO; 385 | ENABLE_STRICT_OBJC_MSGSEND = YES; 386 | GCC_C_LANGUAGE_STANDARD = gnu11; 387 | GCC_NO_COMMON_BLOCKS = YES; 388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 390 | GCC_WARN_UNDECLARED_SELECTOR = YES; 391 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 392 | GCC_WARN_UNUSED_FUNCTION = YES; 393 | GCC_WARN_UNUSED_VARIABLE = YES; 394 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 395 | MTL_ENABLE_DEBUG_INFO = NO; 396 | MTL_FAST_MATH = YES; 397 | SDKROOT = iphoneos; 398 | SWIFT_COMPILATION_MODE = wholemodule; 399 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 400 | VALIDATE_PRODUCT = YES; 401 | }; 402 | name = Release; 403 | }; 404 | 51415DD9260B877300A76FC5 /* Debug */ = { 405 | isa = XCBuildConfiguration; 406 | buildSettings = { 407 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 408 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 409 | CODE_SIGN_ENTITLEMENTS = Recover/Recover.entitlements; 410 | CODE_SIGN_IDENTITY = "Apple Development"; 411 | CODE_SIGN_STYLE = Automatic; 412 | CURRENT_PROJECT_VERSION = 1; 413 | DEVELOPMENT_ASSET_PATHS = "\"Recover/Preview Content\""; 414 | DEVELOPMENT_TEAM = ""; 415 | ENABLE_PREVIEWS = YES; 416 | GENERATE_INFOPLIST_FILE = YES; 417 | INFOPLIST_FILE = Recover/Info.plist; 418 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 419 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 420 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 421 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 422 | IPHONEOS_DEPLOYMENT_TARGET = 14.1; 423 | LD_RUNPATH_SEARCH_PATHS = ( 424 | "$(inherited)", 425 | "@executable_path/Frameworks", 426 | ); 427 | MARKETING_VERSION = 1.0; 428 | PRODUCT_BUNDLE_IDENTIFIER = com.apple.wwdc.Recover; 429 | PRODUCT_NAME = "$(TARGET_NAME)"; 430 | PROVISIONING_PROFILE_SPECIFIER = ""; 431 | SWIFT_VERSION = 5.0; 432 | TARGETED_DEVICE_FAMILY = 1; 433 | }; 434 | name = Debug; 435 | }; 436 | 51415DDA260B877300A76FC5 /* Release */ = { 437 | isa = XCBuildConfiguration; 438 | buildSettings = { 439 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 440 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 441 | CODE_SIGN_ENTITLEMENTS = Recover/Recover.entitlements; 442 | CODE_SIGN_IDENTITY = "Apple Development"; 443 | CODE_SIGN_STYLE = Automatic; 444 | CURRENT_PROJECT_VERSION = 1; 445 | DEVELOPMENT_ASSET_PATHS = "\"Recover/Preview Content\""; 446 | DEVELOPMENT_TEAM = ""; 447 | ENABLE_PREVIEWS = YES; 448 | GENERATE_INFOPLIST_FILE = YES; 449 | INFOPLIST_FILE = Recover/Info.plist; 450 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 451 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 452 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 453 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 454 | IPHONEOS_DEPLOYMENT_TARGET = 14.1; 455 | LD_RUNPATH_SEARCH_PATHS = ( 456 | "$(inherited)", 457 | "@executable_path/Frameworks", 458 | ); 459 | MARKETING_VERSION = 1.0; 460 | PRODUCT_BUNDLE_IDENTIFIER = com.apple.wwdc.Recover; 461 | PRODUCT_NAME = "$(TARGET_NAME)"; 462 | PROVISIONING_PROFILE_SPECIFIER = ""; 463 | SWIFT_VERSION = 5.0; 464 | TARGETED_DEVICE_FAMILY = 1; 465 | }; 466 | name = Release; 467 | }; 468 | /* End XCBuildConfiguration section */ 469 | 470 | /* Begin XCConfigurationList section */ 471 | 51415DBF260B877100A76FC5 /* Build configuration list for PBXProject "Recover" */ = { 472 | isa = XCConfigurationList; 473 | buildConfigurations = ( 474 | 51415DD6260B877300A76FC5 /* Debug */, 475 | 51415DD7260B877300A76FC5 /* Release */, 476 | ); 477 | defaultConfigurationIsVisible = 0; 478 | defaultConfigurationName = Release; 479 | }; 480 | 51415DD8260B877300A76FC5 /* Build configuration list for PBXNativeTarget "Recover" */ = { 481 | isa = XCConfigurationList; 482 | buildConfigurations = ( 483 | 51415DD9260B877300A76FC5 /* Debug */, 484 | 51415DDA260B877300A76FC5 /* Release */, 485 | ); 486 | defaultConfigurationIsVisible = 0; 487 | defaultConfigurationName = Release; 488 | }; 489 | /* End XCConfigurationList section */ 490 | 491 | /* Begin XCRemoteSwiftPackageReference section */ 492 | 51415DDC260B8AD500A76FC5 /* XCRemoteSwiftPackageReference "CareKit" */ = { 493 | isa = XCRemoteSwiftPackageReference; 494 | repositoryURL = "https://github.com/carekit-apple/CareKit.git"; 495 | requirement = { 496 | branch = main; 497 | kind = branch; 498 | }; 499 | }; 500 | /* End XCRemoteSwiftPackageReference section */ 501 | 502 | /* Begin XCSwiftPackageProductDependency section */ 503 | 51415DDF260B8AD500A76FC5 /* CareKit */ = { 504 | isa = XCSwiftPackageProductDependency; 505 | package = 51415DDC260B8AD500A76FC5 /* XCRemoteSwiftPackageReference "CareKit" */; 506 | productName = CareKit; 507 | }; 508 | 51415DE1260B8AD500A76FC5 /* CareKitStore */ = { 509 | isa = XCSwiftPackageProductDependency; 510 | package = 51415DDC260B8AD500A76FC5 /* XCRemoteSwiftPackageReference "CareKit" */; 511 | productName = CareKitStore; 512 | }; 513 | 51415DE3260B8AD500A76FC5 /* CareKitUI */ = { 514 | isa = XCSwiftPackageProductDependency; 515 | package = 51415DDC260B8AD500A76FC5 /* XCRemoteSwiftPackageReference "CareKit" */; 516 | productName = CareKitUI; 517 | }; 518 | /* End XCSwiftPackageProductDependency section */ 519 | }; 520 | rootObject = 51415DBC260B877100A76FC5 /* Project object */; 521 | } 522 | -------------------------------------------------------------------------------- /Recover Final/Recover/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import UIKit 33 | import os.log 34 | 35 | @main 36 | class AppDelegate: UIResponder, UIApplicationDelegate { 37 | 38 | let storeManager = OCKSynchronizedStoreManager( 39 | wrapping: OCKStore( 40 | name: "com.apple.wwdc.carekitstore", 41 | type: .inMemory 42 | ) 43 | ) 44 | 45 | func application( 46 | _ application: UIApplication, 47 | didFinishLaunchingWithOptions 48 | launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 49 | 50 | seedTasks() 51 | 52 | return true 53 | } 54 | 55 | // MARK: UISceneSession Life Cycle 56 | 57 | func application( 58 | _ application: UIApplication, 59 | configurationForConnecting connectingSceneSession: UISceneSession, 60 | options: UIScene.ConnectionOptions) -> UISceneConfiguration { 61 | 62 | UISceneConfiguration( 63 | name: "Default Configuration", 64 | sessionRole: connectingSceneSession.role 65 | ) 66 | } 67 | 68 | // MARK: Seeding the Store 69 | 70 | private func seedTasks() { 71 | 72 | let onboardSchedule = OCKSchedule.dailyAtTime( 73 | hour: 0, minutes: 0, 74 | start: Date(), end: nil, 75 | text: "Task Due!", 76 | duration: .allDay 77 | ) 78 | 79 | var onboardTask = OCKTask( 80 | id: TaskIDs.onboarding, 81 | title: "Onboard", 82 | carePlanUUID: nil, 83 | schedule: onboardSchedule 84 | ) 85 | onboardTask.instructions = "You'll need to agree to some terms and conditions before we get started!" 86 | onboardTask.impactsAdherence = false 87 | 88 | let checkInSchedule = OCKSchedule.dailyAtTime( 89 | hour: 8, minutes: 0, 90 | start: Date(), end: nil, 91 | text: nil 92 | ) 93 | 94 | let checkInTask = OCKTask( 95 | id: TaskIDs.checkIn, 96 | title: "Check In", 97 | carePlanUUID: nil, 98 | schedule: checkInSchedule 99 | ) 100 | 101 | let thisMorning = Calendar.current.startOfDay(for: Date()) 102 | 103 | let nextWeek = Calendar.current.date( 104 | byAdding: .weekOfYear, 105 | value: 1, 106 | to: Date() 107 | )! 108 | 109 | let nextMonth = Calendar.current.date( 110 | byAdding: .month, 111 | value: 1, 112 | to: thisMorning 113 | ) 114 | 115 | let dailyElement = OCKScheduleElement( 116 | start: thisMorning, 117 | end: nextWeek, 118 | interval: DateComponents(day: 1), 119 | text: nil, 120 | targetValues: [], 121 | duration: .allDay 122 | ) 123 | 124 | let weeklyElement = OCKScheduleElement( 125 | start: nextWeek, 126 | end: nextMonth, 127 | interval: DateComponents(weekOfYear: 1), 128 | text: nil, 129 | targetValues: [], 130 | duration: .allDay 131 | ) 132 | 133 | let rangeOfMotionCheckSchedule = OCKSchedule( 134 | composing: [dailyElement, weeklyElement] 135 | ) 136 | 137 | let rangeOfMotionCheckTask = OCKTask( 138 | id: TaskIDs.rangeOfMotionCheck, 139 | title: "Range Of Motion", 140 | carePlanUUID: nil, 141 | schedule: rangeOfMotionCheckSchedule 142 | ) 143 | 144 | storeManager.store.addAnyTasks( 145 | [onboardTask, checkInTask, rangeOfMotionCheckTask], 146 | callbackQueue: .main) { result in 147 | 148 | switch result { 149 | 150 | case let .success(tasks): 151 | Logger.store.info("Seeded \(tasks.count) tasks") 152 | 153 | case let .failure(error): 154 | Logger.store.warning("Failed to seed tasks: \(error as NSError)") 155 | } 156 | } 157 | } 158 | } 159 | 160 | -------------------------------------------------------------------------------- /Recover Final/Recover/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Recover Final/Recover/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Recover Final/Recover/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Final/Recover/CareFeedViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import CareKitUI 33 | import ResearchKit 34 | import UIKit 35 | import os.log 36 | 37 | final class CareFeedViewController: OCKDailyPageViewController, 38 | OCKSurveyTaskViewControllerDelegate { 39 | 40 | override func dailyPageViewController( 41 | _ dailyPageViewController: OCKDailyPageViewController, 42 | prepare listViewController: OCKListViewController, 43 | for date: Date) { 44 | 45 | checkIfOnboardingIsComplete { isOnboarded in 46 | 47 | guard isOnboarded else { 48 | 49 | let onboardCard = OCKSurveyTaskViewController( 50 | taskID: TaskIDs.onboarding, 51 | eventQuery: OCKEventQuery(for: date), 52 | storeManager: self.storeManager, 53 | survey: Surveys.onboardingSurvey(), 54 | extractOutcome: { _ in [OCKOutcomeValue(Date())] } 55 | ) 56 | 57 | onboardCard.surveyDelegate = self 58 | 59 | listViewController.appendViewController( 60 | onboardCard, 61 | animated: false 62 | ) 63 | 64 | return 65 | } 66 | 67 | let isFuture = Calendar.current.compare( 68 | date, 69 | to: Date(), 70 | toGranularity: .day) == .orderedDescending 71 | 72 | self.fetchTasks(on: date) { tasks in 73 | tasks.compactMap { 74 | 75 | let card = self.taskViewController(for: $0, on: date) 76 | card?.view.isUserInteractionEnabled = !isFuture 77 | card?.view.alpha = isFuture ? 0.4 : 1.0 78 | 79 | return card 80 | 81 | }.forEach { 82 | listViewController.appendViewController($0, animated: false) 83 | } 84 | } 85 | } 86 | } 87 | 88 | private func checkIfOnboardingIsComplete(_ completion: @escaping (Bool) -> Void) { 89 | 90 | var query = OCKOutcomeQuery() 91 | query.taskIDs = [TaskIDs.onboarding] 92 | 93 | storeManager.store.fetchAnyOutcomes( 94 | query: query, 95 | callbackQueue: .main) { result in 96 | 97 | switch result { 98 | 99 | case .failure: 100 | Logger.feed.error("Failed to fetch onboarding outcomes!") 101 | completion(false) 102 | 103 | case let .success(outcomes): 104 | completion(!outcomes.isEmpty) 105 | } 106 | } 107 | } 108 | 109 | private func fetchTasks( 110 | on date: Date, 111 | completion: @escaping([OCKAnyTask]) -> Void) { 112 | 113 | var query = OCKTaskQuery(for: date) 114 | query.excludesTasksWithNoEvents = true 115 | 116 | storeManager.store.fetchAnyTasks( 117 | query: query, 118 | callbackQueue: .main) { result in 119 | 120 | switch result { 121 | 122 | case .failure: 123 | Logger.feed.error("Failed to fetch tasks for date \(date)") 124 | completion([]) 125 | 126 | case let .success(tasks): 127 | completion(tasks) 128 | } 129 | } 130 | } 131 | 132 | private func taskViewController( 133 | for task: OCKAnyTask, 134 | on date: Date) -> UIViewController? { 135 | 136 | switch task.id { 137 | 138 | case TaskIDs.checkIn: 139 | 140 | let survey = OCKSurveyTaskViewController( 141 | task: task, 142 | eventQuery: OCKEventQuery(for: date), 143 | storeManager: storeManager, 144 | survey: Surveys.checkInSurvey(), 145 | viewSynchronizer: SurveyViewSynchronizer(), 146 | extractOutcome: Surveys.extractAnswersFromCheckInSurvey 147 | ) 148 | survey.surveyDelegate = self 149 | 150 | return survey 151 | 152 | case TaskIDs.rangeOfMotionCheck: 153 | let survey = OCKSurveyTaskViewController( 154 | task: task, 155 | eventQuery: OCKEventQuery(for: date), 156 | storeManager: storeManager, 157 | survey: Surveys.rangeOfMotionCheck(), 158 | extractOutcome: Surveys.extractRangeOfMotionOutcome 159 | ) 160 | survey.surveyDelegate = self 161 | 162 | return survey 163 | 164 | default: 165 | return nil 166 | } 167 | } 168 | 169 | // MARK: SurveyTaskViewControllerDelegate 170 | 171 | func surveyTask( 172 | viewController: OCKSurveyTaskViewController, 173 | for task: OCKAnyTask, 174 | didFinish result: Result) { 175 | 176 | if case let .success(reason) = result, reason == .completed { 177 | reload() 178 | } 179 | } 180 | 181 | func surveyTask( 182 | viewController: OCKSurveyTaskViewController, 183 | shouldAllowDeletingOutcomeForEvent event: OCKAnyEvent) -> Bool { 184 | 185 | event.scheduleEvent.start >= Calendar.current.startOfDay(for: Date()) 186 | } 187 | } 188 | 189 | final class SurveyViewSynchronizer: OCKSurveyTaskViewSynchronizer { 190 | 191 | override func updateView( 192 | _ view: OCKInstructionsTaskView, 193 | context: OCKSynchronizationContext) { 194 | 195 | super.updateView(view, context: context) 196 | 197 | if let event = context.viewModel.first?.first, event.outcome != nil { 198 | view.instructionsLabel.isHidden = false 199 | 200 | let pain = event.answer(kind: Surveys.checkInPainItemIdentifier) 201 | let sleep = event.answer(kind: Surveys.checkInSleepItemIdentifier) 202 | 203 | view.instructionsLabel.text = """ 204 | Pain: \(Int(pain)) 205 | Sleep: \(Int(sleep)) hours 206 | """ 207 | } else { 208 | view.instructionsLabel.isHidden = true 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Recover Final/Recover/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSExceptionDomains 8 | 9 | localhost 10 | 11 | NSTemporaryExceptionAllowsInsecureHTTPLoads 12 | 13 | 14 | 15 | NSAllowsLocalNetworking 16 | 17 | 18 | NSMotionUsageDescription 19 | Recover would like to record device motion to assess your range of motion 20 | NSHealthShareUsageDescription 21 | Recover reads your HealthKit data during certain tasks. 22 | NSHealthUpdateUsageDescription 23 | Recover updates your HealthKit data during certain tasks. 24 | UIApplicationSceneManifest 25 | 26 | UIApplicationSupportsMultipleScenes 27 | 28 | UISceneConfigurations 29 | 30 | UIWindowSceneSessionRoleApplication 31 | 32 | 33 | UISceneConfigurationName 34 | Default Configuration 35 | UISceneDelegateClassName 36 | $(PRODUCT_MODULE_NAME).SceneDelegate 37 | 38 | 39 | 40 | 41 | UILaunchStoryboardName 42 | Launch Screen 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Final/Recover/InsightsViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import UIKit 31 | import CareKit 32 | import CareKitUI 33 | import ResearchKit 34 | 35 | final class InsightsViewController: 36 | OCKListViewController, 37 | OCKFeaturedContentViewDelegate, 38 | ORKTaskViewControllerDelegate { 39 | 40 | let storeManager: OCKSynchronizedStoreManager 41 | 42 | init(storeManager: OCKSynchronizedStoreManager) { 43 | self.storeManager = storeManager 44 | super.init(nibName: nil, bundle: nil) 45 | } 46 | 47 | required init?(coder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | navigationController?.navigationBar.prefersLargeTitles = true 55 | 56 | // A spacer view. 57 | appendView(UIView(), animated: false) 58 | 59 | let kneeModelView = OCKFeaturedContentView(imageOverlayStyle: .dark) 60 | kneeModelView.delegate = self 61 | kneeModelView.label.text = "About the meniscus" 62 | kneeModelView.label.textColor = .systemBackground 63 | kneeModelView.imageView.image = UIImage(named: "knee") 64 | appendView(kneeModelView, animated: true) 65 | 66 | let painSeries = OCKDataSeriesConfiguration( 67 | taskID: TaskIDs.checkIn, 68 | legendTitle: "Pain (1-10)", 69 | gradientStartColor: #colorLiteral(red: 1, green: 0.462745098, blue: 0.368627451, alpha: 1), 70 | gradientEndColor: #colorLiteral(red: 1, green: 0.462745098, blue: 0.368627451, alpha: 1), 71 | markerSize: 10, 72 | eventAggregator: .custom({ events in 73 | events 74 | .first? 75 | .answer(kind: Surveys.checkInPainItemIdentifier) 76 | ?? 0 77 | }) 78 | ) 79 | 80 | let sleepSeries = OCKDataSeriesConfiguration( 81 | taskID: TaskIDs.checkIn, 82 | legendTitle: "Sleep (hours)", 83 | gradientStartColor: UIColor.systemBlue, 84 | gradientEndColor: UIColor.systemBlue, 85 | markerSize: 10, 86 | eventAggregator: .custom({ events in 87 | events 88 | .first? 89 | .answer(kind: Surveys.checkInSleepItemIdentifier) 90 | ?? 0 91 | }) 92 | ) 93 | 94 | let barChart = OCKCartesianChartViewController( 95 | plotType: .bar, 96 | selectedDate: Date(), 97 | configurations: [painSeries, sleepSeries], 98 | storeManager: storeManager 99 | ) 100 | 101 | appendViewController(barChart, animated: false) 102 | 103 | let rangeSeries = OCKDataSeriesConfiguration( 104 | taskID: TaskIDs.rangeOfMotionCheck, 105 | legendTitle: "Range of Motion (degrees)", 106 | gradientStartColor: view.tintColor, 107 | gradientEndColor: view.tintColor, 108 | markerSize: 3, 109 | eventAggregator: .custom({ events in 110 | events 111 | .first? 112 | .answer(kind: #keyPath(ORKRangeOfMotionResult.range)) 113 | ?? 0 114 | }) 115 | ) 116 | 117 | let scatterChart = OCKCartesianChartViewController( 118 | plotType: .scatter, 119 | selectedDate: Date(), 120 | configurations: [rangeSeries], 121 | storeManager: storeManager 122 | ) 123 | 124 | appendViewController(scatterChart, animated: false) 125 | 126 | // A spacer view. 127 | appendView(UIView(), animated: false) 128 | } 129 | 130 | // MARK: OCKFeaturedContentViewDelegate 131 | 132 | func didTapView(_ view: OCKFeaturedContentView) { 133 | 134 | let humanModelTask = Surveys.kneeModel() 135 | 136 | let taskViewController = ORKTaskViewController( 137 | task: humanModelTask, 138 | taskRun: nil 139 | ) 140 | 141 | taskViewController.delegate = self 142 | 143 | present(taskViewController, animated: true, completion: nil) 144 | } 145 | 146 | // MARK: ORKTaskViewControllerDelegate 147 | 148 | func taskViewController( 149 | _ taskViewController: ORKTaskViewController, 150 | didFinishWith reason: ORKTaskViewControllerFinishReason, 151 | error: Error?) { 152 | 153 | taskViewController.dismiss(animated: true, completion: nil) 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Recover Final/Recover/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Final/Recover/Recover.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.healthkit 6 | 7 | com.apple.developer.healthkit.access 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Recover Final/Recover/Supporting Files/Consent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | let informedConsentHTML = """ 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 45 | 46 |

Informed Consent

47 |

Study Expectations

48 |
    49 |
  • You will be asked to complete various study tasks such as surveys.
  • 50 |
  • The study will send you notifications to remind you to complete these study tasks.
  • 51 |
  • You will be asked to share various health data types to support the study goals.
  • 52 |
  • The study is expected to last 4 years.
  • 53 |
  • The study may reach out to you for future research opportunities.
  • 54 |
  • Your information will be kept private and secure.
  • 55 |
  • You can withdraw from the study at any time.
  • 56 |
57 |

Eligibility Requirements

58 |
    59 |
  • Must be 18 years or older.
  • 60 |
  • Must be able to read and understand English.
  • 61 |
  • Must be the only user of the device on which you are participating in the study.
  • 62 |
  • Must be able to sign your own consent form.
  • 63 |
64 |

By signing below, I acknowledge that I have read this consent carefully, that I understand all of its terms, and that I enter into this study voluntarily. I understand that my information will only be used and disclosed for the purposes described in the consent and I can withdraw from the study at any time.

65 |

Please sign using your finger below.

66 | 67 | 68 | """ 69 | -------------------------------------------------------------------------------- /Recover Final/Recover/Supporting Files/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Final/Recover/Supporting Files/Logging.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | import os.log 32 | 33 | extension Logger { 34 | 35 | private static let subsystem = Bundle.main.bundleIdentifier! 36 | 37 | static let store = Logger(subsystem: subsystem, category: "Store") 38 | 39 | static let survey = Logger(subsystem: subsystem, category: "Surveys") 40 | 41 | static let feed = Logger(subsystem: subsystem, category: "Feed") 42 | } 43 | -------------------------------------------------------------------------------- /Recover Final/Recover/Supporting Files/OCKAnyEvent+Answer.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | 32 | extension OCKAnyEvent { 33 | 34 | func answer(kind: String) -> Double { 35 | let values = outcome?.values ?? [] 36 | let match = values.first(where: { $0.kind == kind }) 37 | return match?.doubleValue ?? 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Recover Final/Recover/Supporting Files/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import UIKit 32 | 33 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 34 | 35 | var storeManager: OCKSynchronizedStoreManager { 36 | let delegate = UIApplication.shared.delegate as! AppDelegate 37 | return delegate.storeManager 38 | } 39 | 40 | var window: UIWindow? 41 | 42 | func scene( 43 | _ scene: UIScene, 44 | willConnectTo session: UISceneSession, 45 | options connectionOptions: UIScene.ConnectionOptions) { 46 | 47 | let appDelegate = UIApplication.shared.delegate as! AppDelegate 48 | 49 | let feed = CareFeedViewController(storeManager: appDelegate.storeManager) 50 | feed.title = "Care Feed" 51 | feed.tabBarItem = UITabBarItem( 52 | title: "Care Feed", 53 | image: UIImage(systemName: "heart.fill"), 54 | tag: 0 55 | ) 56 | 57 | let insights = InsightsViewController(storeManager: appDelegate.storeManager) 58 | insights.title = "Insights" 59 | insights.tabBarItem = UITabBarItem( 60 | title: "Insights", 61 | image: UIImage(systemName: "waveform.path.ecg.rectangle.fill"), 62 | tag: 1 63 | ) 64 | 65 | let root = UITabBarController() 66 | let feedTab = UINavigationController(rootViewController: feed) 67 | let insightsTab = UINavigationController(rootViewController: insights) 68 | root.setViewControllers([feedTab, insightsTab], animated: false) 69 | 70 | window = UIWindow(windowScene: scene as! UIWindowScene) 71 | window?.rootViewController = root 72 | window?.makeKeyAndVisible() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Recover Final/Recover/Supporting Files/Tasks.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | struct TaskIDs { 33 | 34 | static let onboarding = "onboarding" 35 | 36 | static let checkIn = "checkin" 37 | 38 | static let rangeOfMotionCheck = "rangeOfMotionCheck" 39 | 40 | private init() {} 41 | } 42 | -------------------------------------------------------------------------------- /Recover Final/Recover/Surveys.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | import ResearchKit 32 | 33 | struct Surveys { 34 | 35 | private init() {} 36 | 37 | // MARK: Onboarding 38 | 39 | static func onboardingSurvey() -> ORKTask { 40 | 41 | // The Welcome Instruction step. 42 | let welcomeInstructionStep = ORKInstructionStep( 43 | identifier: "onboarding.welcome" 44 | ) 45 | 46 | welcomeInstructionStep.title = "Welcome!" 47 | welcomeInstructionStep.detailText = "Thank you for joining our study. Tap Next to learn more before signing up." 48 | welcomeInstructionStep.image = UIImage(named: "welcome-image") 49 | welcomeInstructionStep.imageContentMode = .scaleAspectFill 50 | 51 | // The Informed Consent Instruction step. 52 | let studyOverviewInstructionStep = ORKInstructionStep( 53 | identifier: "onboarding.overview" 54 | ) 55 | 56 | studyOverviewInstructionStep.title = "Before You Join" 57 | studyOverviewInstructionStep.iconImage = UIImage(systemName: "checkmark.seal.fill") 58 | 59 | let heartBodyItem = ORKBodyItem( 60 | text: "The study will ask you to share some of your health data.", 61 | detailText: nil, 62 | image: UIImage(systemName: "heart.fill"), 63 | learnMoreItem: nil, 64 | bodyItemStyle: .image 65 | ) 66 | 67 | let completeTasksBodyItem = ORKBodyItem( 68 | text: "You will be asked to complete various tasks over the duration of the study.", 69 | detailText: nil, 70 | image: UIImage(systemName: "checkmark.circle.fill"), 71 | learnMoreItem: nil, 72 | bodyItemStyle: .image 73 | ) 74 | 75 | let signatureBodyItem = ORKBodyItem( 76 | text: "Before joining, we will ask you to sign an informed consent document.", 77 | detailText: nil, 78 | image: UIImage(systemName: "signature"), 79 | learnMoreItem: nil, 80 | bodyItemStyle: .image 81 | ) 82 | 83 | let secureDataBodyItem = ORKBodyItem( 84 | text: "Your data is kept private and secure.", 85 | detailText: nil, 86 | image: UIImage(systemName: "lock.fill"), 87 | learnMoreItem: nil, 88 | bodyItemStyle: .image 89 | ) 90 | 91 | studyOverviewInstructionStep.bodyItems = [ 92 | heartBodyItem, 93 | completeTasksBodyItem, 94 | signatureBodyItem, 95 | secureDataBodyItem 96 | ] 97 | 98 | // The Signature step (using WebView). 99 | let webViewStep = ORKWebViewStep( 100 | identifier: "onboarding.signatureCapture", 101 | html: informedConsentHTML 102 | ) 103 | 104 | webViewStep.showSignatureAfterContent = true 105 | 106 | // The Request Permissions step. 107 | let healthKitTypesToWrite: Set = [ 108 | HKObjectType.quantityType(forIdentifier: .bodyMassIndex)!, 109 | HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!, 110 | HKObjectType.workoutType() 111 | ] 112 | 113 | let healthKitTypesToRead: Set = [ 114 | HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!, 115 | HKObjectType.workoutType(), 116 | HKObjectType.quantityType(forIdentifier: .appleStandTime)!, 117 | HKObjectType.quantityType(forIdentifier: .appleExerciseTime)! 118 | ] 119 | 120 | let healthKitPermissionType = ORKHealthKitPermissionType( 121 | sampleTypesToWrite: healthKitTypesToWrite, 122 | objectTypesToRead: healthKitTypesToRead 123 | ) 124 | 125 | let notificationsPermissionType = ORKNotificationPermissionType( 126 | authorizationOptions: [.alert, .badge, .sound] 127 | ) 128 | 129 | let motionPermissionType = ORKMotionActivityPermissionType() 130 | 131 | let requestPermissionsStep = ORKRequestPermissionsStep( 132 | identifier: "onboarding.requestPermissionsStep", 133 | permissionTypes: [ 134 | healthKitPermissionType, 135 | notificationsPermissionType, 136 | motionPermissionType 137 | ] 138 | ) 139 | 140 | requestPermissionsStep.title = "Health Data Request" 141 | requestPermissionsStep.text = "Please review the health data types below and enable sharing to contribute to the study." 142 | 143 | // Completion Step 144 | let completionStep = ORKCompletionStep( 145 | identifier: "onboarding.completionStep" 146 | ) 147 | 148 | completionStep.title = "Enrollment Complete" 149 | completionStep.text = "Thank you for enrolling in this study. Your participation will contribute to meaningful research!" 150 | 151 | let surveyTask = ORKOrderedTask( 152 | identifier: "onboard", 153 | steps: [ 154 | welcomeInstructionStep, 155 | studyOverviewInstructionStep, 156 | webViewStep, 157 | requestPermissionsStep, 158 | completionStep 159 | ] 160 | ) 161 | 162 | return surveyTask 163 | } 164 | 165 | // MARK: Check-in Survey 166 | 167 | static let checkInIdentifier = "checkin" 168 | static let checkInFormIdentifier = "checkin.form" 169 | static let checkInPainItemIdentifier = "checkin.form.pain" 170 | static let checkInSleepItemIdentifier = "checkin.form.sleep" 171 | 172 | static func checkInSurvey() -> ORKTask { 173 | 174 | let painAnswerFormat = ORKAnswerFormat.scale( 175 | withMaximumValue: 10, 176 | minimumValue: 1, 177 | defaultValue: 0, 178 | step: 1, 179 | vertical: false, 180 | maximumValueDescription: "Very painful", 181 | minimumValueDescription: "No pain" 182 | ) 183 | 184 | let sleepAnswerFormat = ORKAnswerFormat.scale( 185 | withMaximumValue: 12, 186 | minimumValue: 0, 187 | defaultValue: 0, 188 | step: 1, 189 | vertical: false, 190 | maximumValueDescription: nil, 191 | minimumValueDescription: nil 192 | ) 193 | 194 | let painItem = ORKFormItem( 195 | identifier: checkInPainItemIdentifier, 196 | text: "How would you rate your pain?", 197 | answerFormat: painAnswerFormat 198 | ) 199 | painItem.isOptional = false 200 | 201 | let sleepItem = ORKFormItem( 202 | identifier: checkInSleepItemIdentifier, 203 | text: "How many hours of sleep did you get last night?", 204 | answerFormat: sleepAnswerFormat 205 | ) 206 | sleepItem.isOptional = false 207 | 208 | let formStep = ORKFormStep( 209 | identifier: checkInFormIdentifier, 210 | title: "Check In", 211 | text: "Please answer the following questions." 212 | ) 213 | formStep.formItems = [painItem, sleepItem] 214 | formStep.isOptional = false 215 | 216 | let surveyTask = ORKOrderedTask( 217 | identifier: checkInIdentifier, 218 | steps: [formStep] 219 | ) 220 | 221 | return surveyTask 222 | } 223 | 224 | static func extractAnswersFromCheckInSurvey( 225 | _ result: ORKTaskResult) -> [OCKOutcomeValue]? { 226 | 227 | guard 228 | let response = result.results? 229 | .compactMap({ $0 as? ORKStepResult }) 230 | .first(where: { $0.identifier == checkInFormIdentifier }), 231 | 232 | let scaleResults = response 233 | .results?.compactMap({ $0 as? ORKScaleQuestionResult }), 234 | 235 | let painAnswer = scaleResults 236 | .first(where: { $0.identifier == checkInPainItemIdentifier })? 237 | .scaleAnswer, 238 | 239 | let sleepAnswer = scaleResults 240 | .first(where: { $0.identifier == checkInSleepItemIdentifier })? 241 | .scaleAnswer 242 | else { 243 | assertionFailure("Failed to extract answers from check in survey!") 244 | return nil 245 | } 246 | 247 | var painValue = OCKOutcomeValue(Double(truncating: painAnswer)) 248 | painValue.kind = checkInPainItemIdentifier 249 | 250 | var sleepValue = OCKOutcomeValue(Double(truncating: sleepAnswer)) 251 | sleepValue.kind = checkInSleepItemIdentifier 252 | 253 | return [painValue, sleepValue] 254 | } 255 | 256 | // MARK: Range of Motion. 257 | 258 | static func rangeOfMotionCheck() -> ORKTask { 259 | 260 | let rangeOfMotionOrderedTask = ORKOrderedTask.kneeRangeOfMotionTask( 261 | withIdentifier: "rangeOfMotionTask", 262 | limbOption: .left, 263 | intendedUseDescription: nil, 264 | options: [.excludeConclusion] 265 | ) 266 | 267 | let completionStep = ORKCompletionStep(identifier: "rom.completion") 268 | completionStep.title = "All done!" 269 | completionStep.detailText = "We know the road to recovery can be tough. Keep up the good work!" 270 | 271 | rangeOfMotionOrderedTask.appendSteps([completionStep]) 272 | 273 | return rangeOfMotionOrderedTask 274 | } 275 | 276 | static func extractRangeOfMotionOutcome( 277 | _ result: ORKTaskResult) -> [OCKOutcomeValue]? { 278 | 279 | guard let motionResult = result.results? 280 | .compactMap({ $0 as? ORKStepResult }) 281 | .compactMap({ $0.results }) 282 | .flatMap({ $0 }) 283 | .compactMap({ $0 as? ORKRangeOfMotionResult }) 284 | .first else { 285 | 286 | assertionFailure("Failed to parse range of motion result") 287 | return nil 288 | } 289 | 290 | var range = OCKOutcomeValue(motionResult.range) 291 | range.kind = #keyPath(ORKRangeOfMotionResult.range) 292 | 293 | return [range] 294 | } 295 | 296 | // MARK: 3D Knee Model 297 | 298 | static func kneeModel() -> ORKTask { 299 | 300 | let instructionStep = ORKInstructionStep( 301 | identifier: "insights.instructionStep" 302 | ) 303 | instructionStep.title = "Your Injury Visualized" 304 | instructionStep.detailText = "A 3D model will be presented to give you better insights on your specific injury." 305 | instructionStep.iconImage = UIImage(systemName: "bandage") 306 | 307 | let modelManager = ORKUSDZModelManager(usdzFileName: "toy_robot_vintage") 308 | 309 | let kneeModelStep = ORK3DModelStep( 310 | identifier: "insights.kneeModel", 311 | modelManager: modelManager 312 | ) 313 | 314 | let kneeModelTask = ORKOrderedTask( 315 | identifier: "insights", 316 | steps: [instructionStep, kneeModelStep] 317 | ) 318 | 319 | return kneeModelTask 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import UIKit 33 | import os.log 34 | 35 | @main 36 | class AppDelegate: UIResponder, UIApplicationDelegate { 37 | 38 | let storeManager = OCKSynchronizedStoreManager( 39 | wrapping: OCKStore( 40 | name: "com.apple.wwdc.carekitstore", 41 | type: .inMemory 42 | ) 43 | ) 44 | 45 | func application( 46 | _ application: UIApplication, 47 | didFinishLaunchingWithOptions 48 | launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 49 | 50 | seedTasks() 51 | 52 | return true 53 | } 54 | 55 | // MARK: UISceneSession Life Cycle 56 | 57 | func application( 58 | _ application: UIApplication, 59 | configurationForConnecting connectingSceneSession: UISceneSession, 60 | options: UIScene.ConnectionOptions) -> UISceneConfiguration { 61 | 62 | UISceneConfiguration( 63 | name: "Default Configuration", 64 | sessionRole: connectingSceneSession.role 65 | ) 66 | } 67 | 68 | // MARK: Seeding the Store 69 | 70 | private func seedTasks() { 71 | 72 | // 1.1 Persist an onboarding task 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/CareFeedViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import CareKitUI 33 | import ResearchKit 34 | import UIKit 35 | import os.log 36 | 37 | final class CareFeedViewController: OCKDailyPageViewController, 38 | OCKSurveyTaskViewControllerDelegate { 39 | 40 | override func dailyPageViewController( 41 | _ dailyPageViewController: OCKDailyPageViewController, 42 | prepare listViewController: OCKListViewController, 43 | for date: Date) { 44 | 45 | // 1.3 Check if onboarding is complete. 46 | 47 | // 1.5 If isn't, show an onboarding card. 48 | } 49 | 50 | // 1.2 Define a method that checks if onboarding is complete 51 | 52 | // 1.6 Refresh the content when onboarding completes 53 | } 54 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSExceptionDomains 8 | 9 | localhost 10 | 11 | NSTemporaryExceptionAllowsInsecureHTTPLoads 12 | 13 | 14 | 15 | NSAllowsLocalNetworking 16 | 17 | 18 | NSMotionUsageDescription 19 | Recover would like to record device motion to assess your range of motion 20 | NSHealthShareUsageDescription 21 | Recover reads your HealthKit data during certain tasks. 22 | NSHealthUpdateUsageDescription 23 | Recover updates your HealthKit data during certain tasks. 24 | UIApplicationSceneManifest 25 | 26 | UIApplicationSupportsMultipleScenes 27 | 28 | UISceneConfigurations 29 | 30 | UIWindowSceneSessionRoleApplication 31 | 32 | 33 | UISceneConfigurationName 34 | Default Configuration 35 | UISceneDelegateClassName 36 | $(PRODUCT_MODULE_NAME).SceneDelegate 37 | 38 | 39 | 40 | 41 | UILaunchStoryboardName 42 | Launch Screen 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/InsightsViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import UIKit 31 | import CareKit 32 | import CareKitUI 33 | import ResearchKit 34 | 35 | final class InsightsViewController: 36 | OCKListViewController, 37 | OCKFeaturedContentViewDelegate, 38 | ORKTaskViewControllerDelegate { 39 | 40 | let storeManager: OCKSynchronizedStoreManager 41 | 42 | init(storeManager: OCKSynchronizedStoreManager) { 43 | self.storeManager = storeManager 44 | super.init(nibName: nil, bundle: nil) 45 | } 46 | 47 | required init?(coder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | navigationController?.navigationBar.prefersLargeTitles = true 55 | 56 | // A spacer view. 57 | appendView(UIView(), animated: false) 58 | } 59 | 60 | // MARK: OCKFeaturedContentViewDelegate 61 | 62 | func didTapView(_ view: OCKFeaturedContentView) { 63 | 64 | } 65 | 66 | // MARK: ORKTaskViewControllerDelegate 67 | 68 | func taskViewController( 69 | _ taskViewController: ORKTaskViewController, 70 | didFinishWith reason: ORKTaskViewControllerFinishReason, 71 | error: Error?) { 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Recover.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.healthkit 6 | 7 | com.apple.developer.healthkit.access 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Supporting Files/Consent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | let informedConsentHTML = """ 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 45 | 46 |

Informed Consent

47 |

Study Expectations

48 |
    49 |
  • You will be asked to complete various study tasks such as surveys.
  • 50 |
  • The study will send you notifications to remind you to complete these study tasks.
  • 51 |
  • You will be asked to share various health data types to support the study goals.
  • 52 |
  • The study is expected to last 4 years.
  • 53 |
  • The study may reach out to you for future research opportunities.
  • 54 |
  • Your information will be kept private and secure.
  • 55 |
  • You can withdraw from the study at any time.
  • 56 |
57 |

Eligibility Requirements

58 |
    59 |
  • Must be 18 years or older.
  • 60 |
  • Must be able to read and understand English.
  • 61 |
  • Must be the only user of the device on which you are participating in the study.
  • 62 |
  • Must be able to sign your own consent form.
  • 63 |
64 |

By signing below, I acknowledge that I have read this consent carefully, that I understand all of its terms, and that I enter into this study voluntarily. I understand that my information will only be used and disclosed for the purposes described in the consent and I can withdraw from the study at any time.

65 |

Please sign using your finger below.

66 | 67 | 68 | """ 69 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Supporting Files/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Supporting Files/Logging.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | import os.log 32 | 33 | extension Logger { 34 | 35 | private static let subsystem = Bundle.main.bundleIdentifier! 36 | 37 | static let store = Logger(subsystem: subsystem, category: "Store") 38 | 39 | static let survey = Logger(subsystem: subsystem, category: "Surveys") 40 | 41 | static let feed = Logger(subsystem: subsystem, category: "Feed") 42 | } 43 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Supporting Files/OCKAnyEvent+Answer.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | 32 | extension OCKAnyEvent { 33 | 34 | func answer(kind: String) -> Double { 35 | let values = outcome?.values ?? [] 36 | let match = values.first(where: { $0.kind == kind }) 37 | return match?.doubleValue ?? 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Supporting Files/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import UIKit 32 | 33 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 34 | 35 | var storeManager: OCKSynchronizedStoreManager { 36 | let delegate = UIApplication.shared.delegate as! AppDelegate 37 | return delegate.storeManager 38 | } 39 | 40 | var window: UIWindow? 41 | 42 | func scene( 43 | _ scene: UIScene, 44 | willConnectTo session: UISceneSession, 45 | options connectionOptions: UIScene.ConnectionOptions) { 46 | 47 | let appDelegate = UIApplication.shared.delegate as! AppDelegate 48 | 49 | let feed = CareFeedViewController(storeManager: appDelegate.storeManager) 50 | feed.title = "Care Feed" 51 | feed.tabBarItem = UITabBarItem( 52 | title: "Care Feed", 53 | image: UIImage(systemName: "heart.fill"), 54 | tag: 0 55 | ) 56 | 57 | let insights = InsightsViewController(storeManager: appDelegate.storeManager) 58 | insights.title = "Insights" 59 | insights.tabBarItem = UITabBarItem( 60 | title: "Insights", 61 | image: UIImage(systemName: "waveform.path.ecg.rectangle.fill"), 62 | tag: 1 63 | ) 64 | 65 | let root = UITabBarController() 66 | let feedTab = UINavigationController(rootViewController: feed) 67 | let insightsTab = UINavigationController(rootViewController: insights) 68 | root.setViewControllers([feedTab, insightsTab], animated: false) 69 | 70 | window = UIWindow(windowScene: scene as! UIWindowScene) 71 | window?.rootViewController = root 72 | window?.makeKeyAndVisible() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Supporting Files/Tasks.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | struct TaskIDs { 33 | 34 | static let onboarding = "onboarding" 35 | 36 | static let checkIn = "checkin" 37 | 38 | static let rangeOfMotionCheck = "rangeOfMotionCheck" 39 | 40 | private init() {} 41 | } 42 | -------------------------------------------------------------------------------- /Recover Part 1/Recover/Surveys.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | import ResearchKit 32 | 33 | struct Surveys { 34 | 35 | private init() {} 36 | 37 | // MARK: Onboarding 38 | 39 | // 1.4 Construct an ORKTask for onboarding 40 | } 41 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import UIKit 33 | import os.log 34 | 35 | @main 36 | class AppDelegate: UIResponder, UIApplicationDelegate { 37 | 38 | let storeManager = OCKSynchronizedStoreManager( 39 | wrapping: OCKStore( 40 | name: "com.apple.wwdc.carekitstore", 41 | type: .inMemory 42 | ) 43 | ) 44 | 45 | func application( 46 | _ application: UIApplication, 47 | didFinishLaunchingWithOptions 48 | launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 49 | 50 | seedTasks() 51 | 52 | return true 53 | } 54 | 55 | // MARK: UISceneSession Life Cycle 56 | 57 | func application( 58 | _ application: UIApplication, 59 | configurationForConnecting connectingSceneSession: UISceneSession, 60 | options: UIScene.ConnectionOptions) -> UISceneConfiguration { 61 | 62 | UISceneConfiguration( 63 | name: "Default Configuration", 64 | sessionRole: connectingSceneSession.role 65 | ) 66 | } 67 | 68 | // MARK: Seeding the Store 69 | 70 | private func seedTasks() { 71 | 72 | let onboardSchedule = OCKSchedule.dailyAtTime( 73 | hour: 0, minutes: 0, 74 | start: Date(), end: nil, 75 | text: "Task Due!", 76 | duration: .allDay 77 | ) 78 | 79 | var onboardTask = OCKTask( 80 | id: TaskIDs.onboarding, 81 | title: "Onboard", 82 | carePlanUUID: nil, 83 | schedule: onboardSchedule 84 | ) 85 | onboardTask.instructions = "You'll need to agree to some terms and conditions before we get started!" 86 | onboardTask.impactsAdherence = false 87 | 88 | // 2.1 Add a check-in task 89 | 90 | // 2.6 Add a range of motion task 91 | 92 | storeManager.store.addAnyTasks( 93 | [onboardTask], 94 | callbackQueue: .main) { result in 95 | 96 | switch result { 97 | 98 | case let .success(tasks): 99 | Logger.store.info("Seeded \(tasks.count) tasks") 100 | 101 | case let .failure(error): 102 | Logger.store.warning("Failed to seed tasks: \(error as NSError)") 103 | } 104 | } 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/CareFeedViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import CareKitUI 33 | import ResearchKit 34 | import UIKit 35 | import os.log 36 | 37 | final class CareFeedViewController: OCKDailyPageViewController, 38 | OCKSurveyTaskViewControllerDelegate { 39 | 40 | override func dailyPageViewController( 41 | _ dailyPageViewController: OCKDailyPageViewController, 42 | prepare listViewController: OCKListViewController, 43 | for date: Date) { 44 | 45 | checkIfOnboardingIsComplete { isOnboarded in 46 | 47 | guard isOnboarded else { 48 | 49 | let onboardCard = OCKSurveyTaskViewController( 50 | taskID: TaskIDs.onboarding, 51 | eventQuery: OCKEventQuery(for: date), 52 | storeManager: self.storeManager, 53 | survey: Surveys.onboardingSurvey(), 54 | extractOutcome: { _ in [OCKOutcomeValue(Date())] } 55 | ) 56 | 57 | onboardCard.surveyDelegate = self 58 | 59 | listViewController.appendViewController( 60 | onboardCard, 61 | animated: false 62 | ) 63 | 64 | return 65 | } 66 | 67 | // 2.2 Query and display a card for each task. 68 | } 69 | } 70 | 71 | private func checkIfOnboardingIsComplete(_ completion: @escaping (Bool) -> Void) { 72 | 73 | var query = OCKOutcomeQuery() 74 | query.taskIDs = [TaskIDs.onboarding] 75 | 76 | storeManager.store.fetchAnyOutcomes( 77 | query: query, 78 | callbackQueue: .main) { result in 79 | 80 | switch result { 81 | 82 | case .failure: 83 | Logger.feed.error("Failed to fetch onboarding outcomes!") 84 | completion(false) 85 | 86 | case let .success(outcomes): 87 | completion(!outcomes.isEmpty) 88 | } 89 | } 90 | } 91 | 92 | // 2.3 Query all the tasks to be displayed on a given date 93 | 94 | // 2.4 Create a card for a given task 95 | 96 | // MARK: SurveyTaskViewControllerDelegate 97 | 98 | func surveyTask( 99 | viewController: OCKSurveyTaskViewController, 100 | for task: OCKAnyTask, 101 | didFinish result: Result) { 102 | 103 | if case let .success(reason) = result, reason == .completed { 104 | reload() 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSExceptionDomains 8 | 9 | localhost 10 | 11 | NSTemporaryExceptionAllowsInsecureHTTPLoads 12 | 13 | 14 | 15 | NSAllowsLocalNetworking 16 | 17 | 18 | NSMotionUsageDescription 19 | Recover would like to record device motion to assess your range of motion 20 | NSHealthShareUsageDescription 21 | Recover reads your HealthKit data during certain tasks. 22 | NSHealthUpdateUsageDescription 23 | Recover updates your HealthKit data during certain tasks. 24 | UIApplicationSceneManifest 25 | 26 | UIApplicationSupportsMultipleScenes 27 | 28 | UISceneConfigurations 29 | 30 | UIWindowSceneSessionRoleApplication 31 | 32 | 33 | UISceneConfigurationName 34 | Default Configuration 35 | UISceneDelegateClassName 36 | $(PRODUCT_MODULE_NAME).SceneDelegate 37 | 38 | 39 | 40 | 41 | UILaunchStoryboardName 42 | Launch Screen 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/InsightsViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import UIKit 31 | import CareKit 32 | import CareKitUI 33 | import ResearchKit 34 | 35 | final class InsightsViewController: 36 | OCKListViewController, 37 | OCKFeaturedContentViewDelegate, 38 | ORKTaskViewControllerDelegate { 39 | 40 | let storeManager: OCKSynchronizedStoreManager 41 | 42 | init(storeManager: OCKSynchronizedStoreManager) { 43 | self.storeManager = storeManager 44 | super.init(nibName: nil, bundle: nil) 45 | } 46 | 47 | required init?(coder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | navigationController?.navigationBar.prefersLargeTitles = true 55 | 56 | // A spacer view. 57 | appendView(UIView(), animated: false) 58 | } 59 | 60 | // MARK: OCKFeaturedContentViewDelegate 61 | 62 | func didTapView(_ view: OCKFeaturedContentView) { 63 | 64 | } 65 | 66 | // MARK: ORKTaskViewControllerDelegate 67 | 68 | func taskViewController( 69 | _ taskViewController: ORKTaskViewController, 70 | didFinishWith reason: ORKTaskViewControllerFinishReason, 71 | error: Error?) { 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Recover.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.healthkit 6 | 7 | com.apple.developer.healthkit.access 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Supporting Files/Consent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | let informedConsentHTML = """ 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 45 | 46 |

Informed Consent

47 |

Study Expectations

48 |
    49 |
  • You will be asked to complete various study tasks such as surveys.
  • 50 |
  • The study will send you notifications to remind you to complete these study tasks.
  • 51 |
  • You will be asked to share various health data types to support the study goals.
  • 52 |
  • The study is expected to last 4 years.
  • 53 |
  • The study may reach out to you for future research opportunities.
  • 54 |
  • Your information will be kept private and secure.
  • 55 |
  • You can withdraw from the study at any time.
  • 56 |
57 |

Eligibility Requirements

58 |
    59 |
  • Must be 18 years or older.
  • 60 |
  • Must be able to read and understand English.
  • 61 |
  • Must be the only user of the device on which you are participating in the study.
  • 62 |
  • Must be able to sign your own consent form.
  • 63 |
64 |

By signing below, I acknowledge that I have read this consent carefully, that I understand all of its terms, and that I enter into this study voluntarily. I understand that my information will only be used and disclosed for the purposes described in the consent and I can withdraw from the study at any time.

65 |

Please sign using your finger below.

66 | 67 | 68 | """ 69 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Supporting Files/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Supporting Files/Logging.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | import os.log 32 | 33 | extension Logger { 34 | 35 | private static let subsystem = Bundle.main.bundleIdentifier! 36 | 37 | static let store = Logger(subsystem: subsystem, category: "Store") 38 | 39 | static let survey = Logger(subsystem: subsystem, category: "Surveys") 40 | 41 | static let feed = Logger(subsystem: subsystem, category: "Feed") 42 | } 43 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Supporting Files/OCKAnyEvent+Answer.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | 32 | extension OCKAnyEvent { 33 | 34 | func answer(kind: String) -> Double { 35 | let values = outcome?.values ?? [] 36 | let match = values.first(where: { $0.kind == kind }) 37 | return match?.doubleValue ?? 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Supporting Files/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import UIKit 32 | 33 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 34 | 35 | var storeManager: OCKSynchronizedStoreManager { 36 | let delegate = UIApplication.shared.delegate as! AppDelegate 37 | return delegate.storeManager 38 | } 39 | 40 | var window: UIWindow? 41 | 42 | func scene( 43 | _ scene: UIScene, 44 | willConnectTo session: UISceneSession, 45 | options connectionOptions: UIScene.ConnectionOptions) { 46 | 47 | let appDelegate = UIApplication.shared.delegate as! AppDelegate 48 | 49 | let feed = CareFeedViewController(storeManager: appDelegate.storeManager) 50 | feed.title = "Care Feed" 51 | feed.tabBarItem = UITabBarItem( 52 | title: "Care Feed", 53 | image: UIImage(systemName: "heart.fill"), 54 | tag: 0 55 | ) 56 | 57 | let insights = InsightsViewController(storeManager: appDelegate.storeManager) 58 | insights.title = "Insights" 59 | insights.tabBarItem = UITabBarItem( 60 | title: "Insights", 61 | image: UIImage(systemName: "waveform.path.ecg.rectangle.fill"), 62 | tag: 1 63 | ) 64 | 65 | let root = UITabBarController() 66 | let feedTab = UINavigationController(rootViewController: feed) 67 | let insightsTab = UINavigationController(rootViewController: insights) 68 | root.setViewControllers([feedTab, insightsTab], animated: false) 69 | 70 | window = UIWindow(windowScene: scene as! UIWindowScene) 71 | window?.rootViewController = root 72 | window?.makeKeyAndVisible() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Supporting Files/Tasks.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | struct TaskIDs { 33 | 34 | static let onboarding = "onboarding" 35 | 36 | static let checkIn = "checkin" 37 | 38 | static let rangeOfMotionCheck = "rangeOfMotionCheck" 39 | 40 | private init() {} 41 | } 42 | -------------------------------------------------------------------------------- /Recover Part 2/Recover/Surveys.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | import ResearchKit 32 | 33 | struct Surveys { 34 | 35 | private init() {} 36 | 37 | // MARK: Onboarding 38 | 39 | static func onboardingSurvey() -> ORKTask { 40 | 41 | // The Welcome Instruction step. 42 | let welcomeInstructionStep = ORKInstructionStep( 43 | identifier: "onboarding.welcome" 44 | ) 45 | 46 | welcomeInstructionStep.title = "Welcome!" 47 | welcomeInstructionStep.detailText = "Thank you for joining our study. Tap Next to learn more before signing up." 48 | welcomeInstructionStep.image = UIImage(named: "welcome-image") 49 | welcomeInstructionStep.imageContentMode = .scaleAspectFill 50 | 51 | // The Informed Consent Instruction step. 52 | let studyOverviewInstructionStep = ORKInstructionStep( 53 | identifier: "onboarding.overview" 54 | ) 55 | 56 | studyOverviewInstructionStep.title = "Before You Join" 57 | studyOverviewInstructionStep.iconImage = UIImage(systemName: "checkmark.seal.fill") 58 | 59 | let heartBodyItem = ORKBodyItem( 60 | text: "The study will ask you to share some of your health data.", 61 | detailText: nil, 62 | image: UIImage(systemName: "heart.fill"), 63 | learnMoreItem: nil, 64 | bodyItemStyle: .image 65 | ) 66 | 67 | let completeTasksBodyItem = ORKBodyItem( 68 | text: "You will be asked to complete various tasks over the duration of the study.", 69 | detailText: nil, 70 | image: UIImage(systemName: "checkmark.circle.fill"), 71 | learnMoreItem: nil, 72 | bodyItemStyle: .image 73 | ) 74 | 75 | let signatureBodyItem = ORKBodyItem( 76 | text: "Before joining, we will ask you to sign an informed consent document.", 77 | detailText: nil, 78 | image: UIImage(systemName: "signature"), 79 | learnMoreItem: nil, 80 | bodyItemStyle: .image 81 | ) 82 | 83 | let secureDataBodyItem = ORKBodyItem( 84 | text: "Your data is kept private and secure.", 85 | detailText: nil, 86 | image: UIImage(systemName: "lock.fill"), 87 | learnMoreItem: nil, 88 | bodyItemStyle: .image 89 | ) 90 | 91 | studyOverviewInstructionStep.bodyItems = [ 92 | heartBodyItem, 93 | completeTasksBodyItem, 94 | signatureBodyItem, 95 | secureDataBodyItem 96 | ] 97 | 98 | // The Signature step (using WebView). 99 | let webViewStep = ORKWebViewStep( 100 | identifier: "onboarding.signatureCapture", 101 | html: informedConsentHTML 102 | ) 103 | 104 | webViewStep.showSignatureAfterContent = true 105 | 106 | // The Request Permissions step. 107 | let healthKitTypesToWrite: Set = [ 108 | HKObjectType.quantityType(forIdentifier: .bodyMassIndex)!, 109 | HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!, 110 | HKObjectType.workoutType() 111 | ] 112 | 113 | let healthKitTypesToRead: Set = [ 114 | HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!, 115 | HKObjectType.workoutType(), 116 | HKObjectType.quantityType(forIdentifier: .appleStandTime)!, 117 | HKObjectType.quantityType(forIdentifier: .appleExerciseTime)! 118 | ] 119 | 120 | let healthKitPermissionType = ORKHealthKitPermissionType( 121 | sampleTypesToWrite: healthKitTypesToWrite, 122 | objectTypesToRead: healthKitTypesToRead 123 | ) 124 | 125 | let notificationsPermissionType = ORKNotificationPermissionType( 126 | authorizationOptions: [.alert, .badge, .sound] 127 | ) 128 | 129 | let motionPermissionType = ORKMotionActivityPermissionType() 130 | 131 | let requestPermissionsStep = ORKRequestPermissionsStep( 132 | identifier: "onboarding.requestPermissionsStep", 133 | permissionTypes: [ 134 | healthKitPermissionType, 135 | notificationsPermissionType, 136 | motionPermissionType 137 | ] 138 | ) 139 | 140 | requestPermissionsStep.title = "Health Data Request" 141 | requestPermissionsStep.text = "Please review the health data types below and enable sharing to contribute to the study." 142 | 143 | // Completion Step 144 | let completionStep = ORKCompletionStep( 145 | identifier: "onboarding.completionStep" 146 | ) 147 | 148 | completionStep.title = "Enrollment Complete" 149 | completionStep.text = "Thank you for enrolling in this study. Your participation will contribute to meaningful research!" 150 | 151 | let surveyTask = ORKOrderedTask( 152 | identifier: "onboard", 153 | steps: [ 154 | welcomeInstructionStep, 155 | studyOverviewInstructionStep, 156 | webViewStep, 157 | requestPermissionsStep, 158 | completionStep 159 | ] 160 | ) 161 | 162 | return surveyTask 163 | } 164 | 165 | // MARK: 2.5 Check In Survey 166 | 167 | // MARK: 2.7 Range of Motion 168 | } 169 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import UIKit 33 | import os.log 34 | 35 | @main 36 | class AppDelegate: UIResponder, UIApplicationDelegate { 37 | 38 | let storeManager = OCKSynchronizedStoreManager( 39 | wrapping: OCKStore( 40 | name: "com.apple.wwdc.carekitstore", 41 | type: .inMemory 42 | ) 43 | ) 44 | 45 | func application( 46 | _ application: UIApplication, 47 | didFinishLaunchingWithOptions 48 | launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 49 | 50 | seedTasks() 51 | 52 | return true 53 | } 54 | 55 | // MARK: UISceneSession Life Cycle 56 | 57 | func application( 58 | _ application: UIApplication, 59 | configurationForConnecting connectingSceneSession: UISceneSession, 60 | options: UIScene.ConnectionOptions) -> UISceneConfiguration { 61 | 62 | UISceneConfiguration( 63 | name: "Default Configuration", 64 | sessionRole: connectingSceneSession.role 65 | ) 66 | } 67 | 68 | // MARK: Seeding the Store 69 | 70 | private func seedTasks() { 71 | 72 | let onboardSchedule = OCKSchedule.dailyAtTime( 73 | hour: 0, minutes: 0, 74 | start: Date(), end: nil, 75 | text: "Task Due!", 76 | duration: .allDay 77 | ) 78 | 79 | var onboardTask = OCKTask( 80 | id: TaskIDs.onboarding, 81 | title: "Onboard", 82 | carePlanUUID: nil, 83 | schedule: onboardSchedule 84 | ) 85 | onboardTask.instructions = "You'll need to agree to some terms and conditions before we get started!" 86 | onboardTask.impactsAdherence = false 87 | 88 | let checkInSchedule = OCKSchedule.dailyAtTime( 89 | hour: 8, minutes: 0, 90 | start: Date(), end: nil, 91 | text: nil 92 | ) 93 | 94 | let checkInTask = OCKTask( 95 | id: TaskIDs.checkIn, 96 | title: "Check In", 97 | carePlanUUID: nil, 98 | schedule: checkInSchedule 99 | ) 100 | 101 | let thisMorning = Calendar.current.startOfDay(for: Date()) 102 | 103 | let nextWeek = Calendar.current.date( 104 | byAdding: .weekOfYear, 105 | value: 1, 106 | to: Date() 107 | )! 108 | 109 | let nextMonth = Calendar.current.date( 110 | byAdding: .month, 111 | value: 1, 112 | to: thisMorning 113 | ) 114 | 115 | let dailyElement = OCKScheduleElement( 116 | start: thisMorning, 117 | end: nextWeek, 118 | interval: DateComponents(day: 1), 119 | text: nil, 120 | targetValues: [], 121 | duration: .allDay 122 | ) 123 | 124 | let weeklyElement = OCKScheduleElement( 125 | start: nextWeek, 126 | end: nextMonth, 127 | interval: DateComponents(weekOfYear: 1), 128 | text: nil, 129 | targetValues: [], 130 | duration: .allDay 131 | ) 132 | 133 | let rangeOfMotionCheckSchedule = OCKSchedule( 134 | composing: [dailyElement, weeklyElement] 135 | ) 136 | 137 | let rangeOfMotionCheckTask = OCKTask( 138 | id: TaskIDs.rangeOfMotionCheck, 139 | title: "Range Of Motion", 140 | carePlanUUID: nil, 141 | schedule: rangeOfMotionCheckSchedule 142 | ) 143 | 144 | storeManager.store.addAnyTasks( 145 | [onboardTask, checkInTask, rangeOfMotionCheckTask], 146 | callbackQueue: .main) { result in 147 | 148 | switch result { 149 | 150 | case let .success(tasks): 151 | Logger.store.info("Seeded \(tasks.count) tasks") 152 | 153 | case let .failure(error): 154 | Logger.store.warning("Failed to seed tasks: \(error as NSError)") 155 | } 156 | } 157 | } 158 | } 159 | 160 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/CareFeedViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import CareKitStore 32 | import CareKitUI 33 | import ResearchKit 34 | import UIKit 35 | import os.log 36 | 37 | final class CareFeedViewController: OCKDailyPageViewController, 38 | OCKSurveyTaskViewControllerDelegate { 39 | 40 | override func dailyPageViewController( 41 | _ dailyPageViewController: OCKDailyPageViewController, 42 | prepare listViewController: OCKListViewController, 43 | for date: Date) { 44 | 45 | checkIfOnboardingIsComplete { isOnboarded in 46 | 47 | guard isOnboarded else { 48 | 49 | let onboardCard = OCKSurveyTaskViewController( 50 | taskID: TaskIDs.onboarding, 51 | eventQuery: OCKEventQuery(for: date), 52 | storeManager: self.storeManager, 53 | survey: Surveys.onboardingSurvey(), 54 | extractOutcome: { _ in [OCKOutcomeValue(Date())] } 55 | ) 56 | 57 | onboardCard.surveyDelegate = self 58 | 59 | listViewController.appendViewController( 60 | onboardCard, 61 | animated: false 62 | ) 63 | 64 | return 65 | } 66 | 67 | // 3.3 Disable interaction for future events 68 | 69 | self.fetchTasks(on: date) { tasks in 70 | tasks.compactMap { 71 | self.taskViewController(for: $0, on: date) 72 | }.forEach { 73 | listViewController.appendViewController($0, animated: false) 74 | } 75 | } 76 | } 77 | } 78 | 79 | private func checkIfOnboardingIsComplete(_ completion: @escaping (Bool) -> Void) { 80 | 81 | var query = OCKOutcomeQuery() 82 | query.taskIDs = [TaskIDs.onboarding] 83 | 84 | storeManager.store.fetchAnyOutcomes( 85 | query: query, 86 | callbackQueue: .main) { result in 87 | 88 | switch result { 89 | 90 | case .failure: 91 | Logger.feed.error("Failed to fetch onboarding outcomes!") 92 | completion(false) 93 | 94 | case let .success(outcomes): 95 | completion(!outcomes.isEmpty) 96 | } 97 | } 98 | } 99 | 100 | private func fetchTasks( 101 | on date: Date, 102 | completion: @escaping([OCKAnyTask]) -> Void) { 103 | 104 | var query = OCKTaskQuery(for: date) 105 | query.excludesTasksWithNoEvents = true 106 | 107 | storeManager.store.fetchAnyTasks( 108 | query: query, 109 | callbackQueue: .main) { result in 110 | 111 | switch result { 112 | 113 | case .failure: 114 | Logger.feed.error("Failed to fetch tasks for date \(date)") 115 | completion([]) 116 | 117 | case let .success(tasks): 118 | completion(tasks) 119 | } 120 | } 121 | } 122 | 123 | private func taskViewController( 124 | for task: OCKAnyTask, 125 | on date: Date) -> UIViewController? { 126 | 127 | switch task.id { 128 | 129 | case TaskIDs.checkIn: 130 | 131 | let survey = OCKSurveyTaskViewController( 132 | task: task, 133 | eventQuery: OCKEventQuery(for: date), 134 | storeManager: storeManager, 135 | survey: Surveys.checkInSurvey(), 136 | extractOutcome: Surveys.extractAnswersFromCheckInSurvey 137 | ) 138 | 139 | return survey 140 | 141 | case TaskIDs.rangeOfMotionCheck: 142 | let survey = OCKSurveyTaskViewController( 143 | task: task, 144 | eventQuery: OCKEventQuery(for: date), 145 | storeManager: storeManager, 146 | survey: Surveys.rangeOfMotionCheck(), 147 | extractOutcome: Surveys.extractRangeOfMotionOutcome 148 | ) 149 | 150 | return survey 151 | 152 | default: 153 | return nil 154 | } 155 | } 156 | 157 | // MARK: SurveyTaskViewControllerDelegate 158 | 159 | func surveyTask( 160 | viewController: OCKSurveyTaskViewController, 161 | for task: OCKAnyTask, 162 | didFinish result: Result) { 163 | 164 | if case let .success(reason) = result, reason == .completed { 165 | reload() 166 | } 167 | } 168 | 169 | // 3.2 Disallow deleting past outcomes 170 | 171 | } 172 | 173 | 174 | // MARK: 3.1 Custom View Synchronizer 175 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSExceptionDomains 8 | 9 | localhost 10 | 11 | NSTemporaryExceptionAllowsInsecureHTTPLoads 12 | 13 | 14 | 15 | NSAllowsLocalNetworking 16 | 17 | 18 | NSMotionUsageDescription 19 | Recover would like to record device motion to assess your range of motion 20 | NSHealthShareUsageDescription 21 | Recover reads your HealthKit data during certain tasks. 22 | NSHealthUpdateUsageDescription 23 | Recover updates your HealthKit data during certain tasks. 24 | UIApplicationSceneManifest 25 | 26 | UIApplicationSupportsMultipleScenes 27 | 28 | UISceneConfigurations 29 | 30 | UIWindowSceneSessionRoleApplication 31 | 32 | 33 | UISceneConfigurationName 34 | Default Configuration 35 | UISceneDelegateClassName 36 | $(PRODUCT_MODULE_NAME).SceneDelegate 37 | 38 | 39 | 40 | 41 | UILaunchStoryboardName 42 | Launch Screen 43 | UISupportedInterfaceOrientations 44 | 45 | UIInterfaceOrientationPortrait 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/InsightsViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import UIKit 31 | import CareKit 32 | import CareKitUI 33 | import ResearchKit 34 | 35 | final class InsightsViewController: 36 | OCKListViewController, 37 | OCKFeaturedContentViewDelegate, 38 | ORKTaskViewControllerDelegate { 39 | 40 | let storeManager: OCKSynchronizedStoreManager 41 | 42 | init(storeManager: OCKSynchronizedStoreManager) { 43 | self.storeManager = storeManager 44 | super.init(nibName: nil, bundle: nil) 45 | } 46 | 47 | required init?(coder: NSCoder) { 48 | fatalError("init(coder:) has not been implemented") 49 | } 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | navigationController?.navigationBar.prefersLargeTitles = true 55 | 56 | // A spacer view. 57 | appendView(UIView(), animated: false) 58 | 59 | // MARK: 3.6 Featured Content 60 | 61 | // MARK: 3.4 Pain and Sleep Bar Chart 62 | 63 | // MARK: 3.5 Range of Motion Scatter Plot 64 | } 65 | 66 | // MARK: OCKFeaturedContentViewDelegate 67 | 68 | func didTapView(_ view: OCKFeaturedContentView) { 69 | // 3.7 Present the knee model 70 | } 71 | 72 | // MARK: ORKTaskViewControllerDelegate 73 | 74 | func taskViewController( 75 | _ taskViewController: ORKTaskViewController, 76 | didFinishWith reason: ORKTaskViewControllerFinishReason, 77 | error: Error?) { 78 | 79 | // 3.8 Dismiss the knee model 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Recover.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.healthkit 6 | 7 | com.apple.developer.healthkit.access 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Supporting Files/Consent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | let informedConsentHTML = """ 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 45 | 46 |

Informed Consent

47 |

Study Expectations

48 |
    49 |
  • You will be asked to complete various study tasks such as surveys.
  • 50 |
  • The study will send you notifications to remind you to complete these study tasks.
  • 51 |
  • You will be asked to share various health data types to support the study goals.
  • 52 |
  • The study is expected to last 4 years.
  • 53 |
  • The study may reach out to you for future research opportunities.
  • 54 |
  • Your information will be kept private and secure.
  • 55 |
  • You can withdraw from the study at any time.
  • 56 |
57 |

Eligibility Requirements

58 |
    59 |
  • Must be 18 years or older.
  • 60 |
  • Must be able to read and understand English.
  • 61 |
  • Must be the only user of the device on which you are participating in the study.
  • 62 |
  • Must be able to sign your own consent form.
  • 63 |
64 |

By signing below, I acknowledge that I have read this consent carefully, that I understand all of its terms, and that I enter into this study voluntarily. I understand that my information will only be used and disclosed for the purposes described in the consent and I can withdraw from the study at any time.

65 |

Please sign using your finger below.

66 | 67 | 68 | """ 69 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Supporting Files/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Supporting Files/Logging.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | import os.log 32 | 33 | extension Logger { 34 | 35 | private static let subsystem = Bundle.main.bundleIdentifier! 36 | 37 | static let store = Logger(subsystem: subsystem, category: "Store") 38 | 39 | static let survey = Logger(subsystem: subsystem, category: "Surveys") 40 | 41 | static let feed = Logger(subsystem: subsystem, category: "Feed") 42 | } 43 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Supporting Files/OCKAnyEvent+Answer.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | 32 | extension OCKAnyEvent { 33 | 34 | func answer(kind: String) -> Double { 35 | let values = outcome?.values ?? [] 36 | let match = values.first(where: { $0.kind == kind }) 37 | return match?.doubleValue ?? 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Supporting Files/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKit 31 | import UIKit 32 | 33 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 34 | 35 | var storeManager: OCKSynchronizedStoreManager { 36 | let delegate = UIApplication.shared.delegate as! AppDelegate 37 | return delegate.storeManager 38 | } 39 | 40 | var window: UIWindow? 41 | 42 | func scene( 43 | _ scene: UIScene, 44 | willConnectTo session: UISceneSession, 45 | options connectionOptions: UIScene.ConnectionOptions) { 46 | 47 | let appDelegate = UIApplication.shared.delegate as! AppDelegate 48 | 49 | let feed = CareFeedViewController(storeManager: appDelegate.storeManager) 50 | feed.title = "Care Feed" 51 | feed.tabBarItem = UITabBarItem( 52 | title: "Care Feed", 53 | image: UIImage(systemName: "heart.fill"), 54 | tag: 0 55 | ) 56 | 57 | let insights = InsightsViewController(storeManager: appDelegate.storeManager) 58 | insights.title = "Insights" 59 | insights.tabBarItem = UITabBarItem( 60 | title: "Insights", 61 | image: UIImage(systemName: "waveform.path.ecg.rectangle.fill"), 62 | tag: 1 63 | ) 64 | 65 | let root = UITabBarController() 66 | let feedTab = UINavigationController(rootViewController: feed) 67 | let insightsTab = UINavigationController(rootViewController: insights) 68 | root.setViewControllers([feedTab, insightsTab], animated: false) 69 | 70 | window = UIWindow(windowScene: scene as! UIWindowScene) 71 | window?.rootViewController = root 72 | window?.makeKeyAndVisible() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Supporting Files/Tasks.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import Foundation 31 | 32 | struct TaskIDs { 33 | 34 | static let onboarding = "onboarding" 35 | 36 | static let checkIn = "checkin" 37 | 38 | static let rangeOfMotionCheck = "rangeOfMotionCheck" 39 | 40 | private init() {} 41 | } 42 | -------------------------------------------------------------------------------- /Recover Part 3/Recover/Surveys.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 Apple Inc. All rights reserved. 3 | 4 | Apple permits redistribution and use in source and binary forms, with or without 5 | modification, providing that you adhere to the following conditions: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions, and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions, and the following disclaimer in the documentation and 12 | other distributed materials. 13 | 14 | 3. You may not use the name of the copyright holders nor the names of any contributors 15 | to endorse or promote products that derive from this software without specific prior 16 | written permission. Apple does not grant license to the trademarks of the copyright 17 | holders even if this software includes such marks. 18 | 19 | THE COPYRIGHT HOLDERS AND CONTRIBUTORS PROVIDE THIS SOFTWARE "AS IS”, AND DISCLAIM ANY 20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) WHATEVER THE CAUSE AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF YOU 27 | ADVISE THEM OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | import CareKitStore 31 | import ResearchKit 32 | 33 | struct Surveys { 34 | 35 | private init() {} 36 | 37 | // MARK: Onboarding 38 | 39 | static func onboardingSurvey() -> ORKTask { 40 | 41 | // The Welcome Instruction step. 42 | let welcomeInstructionStep = ORKInstructionStep( 43 | identifier: "onboarding.welcome" 44 | ) 45 | 46 | welcomeInstructionStep.title = "Welcome!" 47 | welcomeInstructionStep.detailText = "Thank you for joining our study. Tap Next to learn more before signing up." 48 | welcomeInstructionStep.image = UIImage(named: "welcome-image") 49 | welcomeInstructionStep.imageContentMode = .scaleAspectFill 50 | 51 | // The Informed Consent Instruction step. 52 | let studyOverviewInstructionStep = ORKInstructionStep( 53 | identifier: "onboarding.overview" 54 | ) 55 | 56 | studyOverviewInstructionStep.title = "Before You Join" 57 | studyOverviewInstructionStep.iconImage = UIImage(systemName: "checkmark.seal.fill") 58 | 59 | let heartBodyItem = ORKBodyItem( 60 | text: "The study will ask you to share some of your health data.", 61 | detailText: nil, 62 | image: UIImage(systemName: "heart.fill"), 63 | learnMoreItem: nil, 64 | bodyItemStyle: .image 65 | ) 66 | 67 | let completeTasksBodyItem = ORKBodyItem( 68 | text: "You will be asked to complete various tasks over the duration of the study.", 69 | detailText: nil, 70 | image: UIImage(systemName: "checkmark.circle.fill"), 71 | learnMoreItem: nil, 72 | bodyItemStyle: .image 73 | ) 74 | 75 | let signatureBodyItem = ORKBodyItem( 76 | text: "Before joining, we will ask you to sign an informed consent document.", 77 | detailText: nil, 78 | image: UIImage(systemName: "signature"), 79 | learnMoreItem: nil, 80 | bodyItemStyle: .image 81 | ) 82 | 83 | let secureDataBodyItem = ORKBodyItem( 84 | text: "Your data is kept private and secure.", 85 | detailText: nil, 86 | image: UIImage(systemName: "lock.fill"), 87 | learnMoreItem: nil, 88 | bodyItemStyle: .image 89 | ) 90 | 91 | studyOverviewInstructionStep.bodyItems = [ 92 | heartBodyItem, 93 | completeTasksBodyItem, 94 | signatureBodyItem, 95 | secureDataBodyItem 96 | ] 97 | 98 | // The Signature step (using WebView). 99 | let webViewStep = ORKWebViewStep( 100 | identifier: "onboarding.signatureCapture", 101 | html: informedConsentHTML 102 | ) 103 | 104 | webViewStep.showSignatureAfterContent = true 105 | 106 | // The Request Permissions step. 107 | let healthKitTypesToWrite: Set = [ 108 | HKObjectType.quantityType(forIdentifier: .bodyMassIndex)!, 109 | HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!, 110 | HKObjectType.workoutType() 111 | ] 112 | 113 | let healthKitTypesToRead: Set = [ 114 | HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!, 115 | HKObjectType.workoutType(), 116 | HKObjectType.quantityType(forIdentifier: .appleStandTime)!, 117 | HKObjectType.quantityType(forIdentifier: .appleExerciseTime)! 118 | ] 119 | 120 | let healthKitPermissionType = ORKHealthKitPermissionType( 121 | sampleTypesToWrite: healthKitTypesToWrite, 122 | objectTypesToRead: healthKitTypesToRead 123 | ) 124 | 125 | let notificationsPermissionType = ORKNotificationPermissionType( 126 | authorizationOptions: [.alert, .badge, .sound] 127 | ) 128 | 129 | let motionPermissionType = ORKMotionActivityPermissionType() 130 | 131 | let requestPermissionsStep = ORKRequestPermissionsStep( 132 | identifier: "onboarding.requestPermissionsStep", 133 | permissionTypes: [ 134 | healthKitPermissionType, 135 | notificationsPermissionType, 136 | motionPermissionType 137 | ] 138 | ) 139 | 140 | requestPermissionsStep.title = "Health Data Request" 141 | requestPermissionsStep.text = "Please review the health data types below and enable sharing to contribute to the study." 142 | 143 | // Completion Step 144 | let completionStep = ORKCompletionStep( 145 | identifier: "onboarding.completionStep" 146 | ) 147 | 148 | completionStep.title = "Enrollment Complete" 149 | completionStep.text = "Thank you for enrolling in this study. Your participation will contribute to meaningful research!" 150 | 151 | let surveyTask = ORKOrderedTask( 152 | identifier: "onboard", 153 | steps: [ 154 | welcomeInstructionStep, 155 | studyOverviewInstructionStep, 156 | webViewStep, 157 | requestPermissionsStep, 158 | completionStep 159 | ] 160 | ) 161 | 162 | return surveyTask 163 | } 164 | 165 | // MARK: Check-in Survey 166 | 167 | static let checkInIdentifier = "checkin" 168 | static let checkInFormIdentifier = "checkin.form" 169 | static let checkInPainItemIdentifier = "checkin.form.pain" 170 | static let checkInSleepItemIdentifier = "checkin.form.sleep" 171 | 172 | static func checkInSurvey() -> ORKTask { 173 | 174 | let painAnswerFormat = ORKAnswerFormat.scale( 175 | withMaximumValue: 10, 176 | minimumValue: 1, 177 | defaultValue: 0, 178 | step: 1, 179 | vertical: false, 180 | maximumValueDescription: "Very painful", 181 | minimumValueDescription: "No pain" 182 | ) 183 | 184 | let painItem = ORKFormItem( 185 | identifier: checkInPainItemIdentifier, 186 | text: "How would you rate your pain?", 187 | answerFormat: painAnswerFormat 188 | ) 189 | painItem.isOptional = false 190 | 191 | let sleepAnswerFormat = ORKAnswerFormat.scale( 192 | withMaximumValue: 12, 193 | minimumValue: 0, 194 | defaultValue: 0, 195 | step: 1, 196 | vertical: false, 197 | maximumValueDescription: nil, 198 | minimumValueDescription: nil 199 | ) 200 | 201 | let sleepItem = ORKFormItem( 202 | identifier: checkInSleepItemIdentifier, 203 | text: "How many hours of sleep did you get last night?", 204 | answerFormat: sleepAnswerFormat 205 | ) 206 | sleepItem.isOptional = false 207 | 208 | let formStep = ORKFormStep( 209 | identifier: checkInFormIdentifier, 210 | title: "Check In", 211 | text: "Please answer the following questions." 212 | ) 213 | formStep.formItems = [painItem, sleepItem] 214 | formStep.isOptional = false 215 | 216 | let surveyTask = ORKOrderedTask( 217 | identifier: checkInIdentifier, 218 | steps: [formStep] 219 | ) 220 | 221 | return surveyTask 222 | } 223 | 224 | static func extractAnswersFromCheckInSurvey( 225 | _ result: ORKTaskResult) -> [OCKOutcomeValue]? { 226 | 227 | guard 228 | let response = result.results? 229 | .compactMap({ $0 as? ORKStepResult }) 230 | .first(where: { $0.identifier == checkInFormIdentifier }), 231 | 232 | let scaleResults = response 233 | .results?.compactMap({ $0 as? ORKScaleQuestionResult }), 234 | 235 | let painAnswer = scaleResults 236 | .first(where: { $0.identifier == checkInPainItemIdentifier })? 237 | .scaleAnswer, 238 | 239 | let sleepAnswer = scaleResults 240 | .first(where: { $0.identifier == checkInSleepItemIdentifier })? 241 | .scaleAnswer 242 | else { 243 | assertionFailure("Failed to extract answers from check in survey!") 244 | return nil 245 | } 246 | 247 | var painValue = OCKOutcomeValue(Double(truncating: painAnswer)) 248 | painValue.kind = checkInPainItemIdentifier 249 | 250 | var sleepValue = OCKOutcomeValue(Double(truncating: sleepAnswer)) 251 | sleepValue.kind = checkInSleepItemIdentifier 252 | 253 | return [painValue, sleepValue] 254 | } 255 | 256 | // MARK: Range of Motion. 257 | 258 | static func rangeOfMotionCheck() -> ORKTask { 259 | 260 | let rangeOfMotionOrderedTask = ORKOrderedTask.kneeRangeOfMotionTask( 261 | withIdentifier: "rangeOfMotionTask", 262 | limbOption: .left, 263 | intendedUseDescription: nil, 264 | options: [.excludeConclusion] 265 | ) 266 | 267 | let completionStep = ORKCompletionStep(identifier: "rom.completion") 268 | completionStep.title = "All done!" 269 | completionStep.detailText = "We know the road to recovery can be tough. Keep up the good work!" 270 | 271 | rangeOfMotionOrderedTask.appendSteps([completionStep]) 272 | 273 | return rangeOfMotionOrderedTask 274 | } 275 | 276 | static func extractRangeOfMotionOutcome( 277 | _ result: ORKTaskResult) -> [OCKOutcomeValue]? { 278 | 279 | guard let motionResult = result.results? 280 | .compactMap({ $0 as? ORKStepResult }) 281 | .compactMap({ $0.results }) 282 | .flatMap({ $0 }) 283 | .compactMap({ $0 as? ORKRangeOfMotionResult }) 284 | .first else { 285 | 286 | assertionFailure("Failed to parse range of motion result") 287 | return nil 288 | } 289 | 290 | var range = OCKOutcomeValue(motionResult.range) 291 | range.kind = #keyPath(ORKRangeOfMotionResult.range) 292 | 293 | return [range] 294 | } 295 | 296 | // MARK: 3.9 Knee Model Task 297 | } 298 | --------------------------------------------------------------------------------