diff --git a/.firebaserc b/.firebaserc index 39b8d8b5..5d910ff7 100644 --- a/.firebaserc +++ b/.firebaserc @@ -2,4 +2,4 @@ "projects": { "default": "cs342-2023-paws" } -} +} diff --git a/.firebaserc.license b/.firebaserc.license index 9137ea9d..c310108a 100644 --- a/.firebaserc.license +++ b/.firebaserc.license @@ -1,6 +1,5 @@ +This source file is part of the PAWS application based on the Stanford Spezi Template Application project -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University +SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) SPDX-License-Identifier: MIT diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 77c2e811..00000000 --- a/.gitattributes +++ /dev/null @@ -1,7 +0,0 @@ -# -# This source file is part of the CS342 2023 PAWS Team Application project -# -# SPDX-FileCopyrightText: 2023 Stanford University -# -# SPDX-License-Identifier: MIT -# diff --git a/.github/workflows/beta-deployment.yml b/.github/workflows/beta-deployment.yml index 7b8e00cb..b5afb88a 100644 --- a/.github/workflows/beta-deployment.yml +++ b/.github/workflows/beta-deployment.yml @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # @@ -18,12 +18,27 @@ jobs: buildandtest: name: Build and Test uses: ./.github/workflows/build-and-test.yml + permissions: + contents: read + secrets: inherit iosapptestflightdeployment: name: iOS App TestFlight Deployment needs: buildandtest uses: CS342/.github/.github/workflows/xcodebuild-or-fastlane.yml@v2 - secrets: inherit + permissions: + contents: read with: - artifactname: PAWS.xcresult - fastlanelane: beta + googleserviceinfoplistpath: 'PAWS/Supporting Files/GoogleService-Info.plist' setupsigning: true + fastlanelane: beta + secrets: inherit + deployfirebase: + name: Deploy Firebase Project + needs: iosapptestflightdeployment + uses: StanfordBDHG/.github/.github/workflows/firebase-deploy.yml@v2 + permissions: + contents: read + with: + arguments: '--debug' + secrets: + GOOGLE_APPLICATION_CREDENTIALS_BASE64: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_BASE64 }} diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f05987ff..4e80132c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # @@ -17,20 +17,35 @@ jobs: reuse_action: name: REUSE Compliance Check uses: StanfordBDHG/.github/.github/workflows/reuse.yml@v2 + permissions: + contents: read swiftlint: name: SwiftLint uses: StanfordBDHG/.github/.github/workflows/swiftlint.yml@v2 + permissions: + contents: read + markdownlinkcheck: + name: Markdown Link Check + uses: StanfordBDHG/.github/.github/workflows/markdown-link-check.yml@v2 + permissions: + contents: read buildandtest: name: Build and Test uses: CS342/.github/.github/workflows/xcodebuild-or-fastlane.yml@v2 + permissions: + contents: read with: - codeql: true artifactname: PAWS.xcresult + runsonlabels: '["macOS", "self-hosted"]' setupfirebaseemulator: true customcommand: "firebase emulators:exec 'fastlane test'" uploadcoveragereport: name: Upload Coverage Report needs: buildandtest uses: StanfordBDHG/.github/.github/workflows/create-and-upload-coverage-report.yml@v2 + permissions: + contents: read with: coveragereports: PAWS.xcresult + secrets: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/monthly-markdown-link-check.yml.yml b/.github/workflows/monthly-markdown-link-check.yml.yml new file mode 100644 index 00000000..9b749c97 --- /dev/null +++ b/.github/workflows/monthly-markdown-link-check.yml.yml @@ -0,0 +1,21 @@ +# +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project +# +# SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) +# +# SPDX-License-Identifier: MIT +# + +name: Monthly Markdown Link Check + +on: + # Runs at midnight on the first of every month + schedule: + - cron: "0 0 1 * *" + +jobs: + markdown_link_check: + name: Markdown Link Check + uses: StanfordBDHG/.github/.github/workflows/markdown-link-check.yml@v2 + permissions: + contents: read diff --git a/.gitignore b/.gitignore index 24f2a14b..176cbf40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # @@ -9,11 +9,11 @@ # Swift Package Manager *.xcodeproj .swiftpm -.build/ +.derivedData +.build +.docs !PAWS.xcodeproj -project.xcworkspace/ - # IDE related folders .idea @@ -32,7 +32,6 @@ report.junit report.html PAWS.xcresult - # Logs logs *.log @@ -43,4 +42,7 @@ firebase-debug.log* firebase-debug.*.log* # Firebase cache -.firebase/ \ No newline at end of file +.firebase/ + +# Swift Package List +PAWS/package-list.json diff --git a/.swiftlint.yml b/.swiftlint.yml index 87c022c1..3aae2ae7 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,11 +1,11 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # # SPDX-License-Identifier: MIT # - + # The whitelist_rules configuration also includes rules that are enabled by default to provide a good overview of all rules. only_rules: # All Images that provide context should have an accessibility label. Purely decorative images can be hidden from accessibility. @@ -379,6 +379,7 @@ deployment_target: # Availability checks or attributes shouldn’t be using olde excluded: # paths to ignore during linting. Takes precedence over `included`. - .build - .swiftpm + - .codeql - .derivedData closure_body_length: # Closure bodies should not span too many lines. diff --git a/CITATION.cff b/CITATION.cff index 4967af21..41211df1 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # @@ -18,5 +18,4 @@ authors: - family-names: "Aalami" given-names: "Oliver" orcid: "https://orcid.org/0000-0002-7799-2429" -title: "CS342 2023 PAWS Team Application" -url: "https://github.com/CS342/2023-PAWS" +title: "PAWS" diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c5a43f76..a5943558 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,6 +1,6 @@ -CS342 2023 PAWS Team Application Contributors +PAWS Contributors ================================= * [Paul Schmiedmayer](https://github.com/PSchmiedmayer) +* [Andreas Bauer](https://github.com/Supereg) +* [Philipp Zagar](https://github.com/philippzagar) +* [Nikolai Madlener](https://github.com/NikolaiMadlener) +* [Caitlin Kunchur](https://github.com/ckunchur) +* [Shriya Reddy](https://github.com/reddyrose) +* [Riya Karumanchi](https://github.com/riyakaru) +* [Vishnu Ravi](https://github.com/vishnuravi) +* [Ananya Vasireddy](https://github.com/ananya-vasireddy) +* [Abhinav Agarwal](https://github.com/abhinav30219) +* [Raghav Samavedam](https://github.com/RSamavedam) +* [Aydin Zahedivash](http://github.com/aydinzahedi) +* [Scott Randolph Ceresnak](https://med.stanford.edu/profiles/scott-ceresnak) +* [Oliver Aalami](http://github.com/aalami5) \ No newline at end of file diff --git a/Gemfile b/Gemfile index 2e284a7f..39505584 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # diff --git a/Gemfile.lock b/Gemfile.lock index 0a30d2bc..8f90740b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,27 +1,27 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.5) + CFPropertyList (3.0.6) rexml - addressable (2.8.1) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.699.0) - aws-sdk-core (3.169.0) + aws-partitions (1.809.0) + aws-sdk-core (3.181.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.62.0) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-kms (1.71.0) + aws-sdk-core (~> 3, >= 3.177.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.118.0) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-s3 (1.133.0) + aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.2) + aws-sigv4 (~> 1.6) + aws-sigv4 (1.6.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -30,13 +30,13 @@ GEM commander (4.6.0) highline (~> 2.0.0) declarative (0.0.20) - digest-crc (0.6.4) + digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.97.2) + excon (0.100.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -65,8 +65,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.6) - fastlane (2.211.0) + fastimage (2.2.7) + fastlane (2.214.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -90,7 +90,7 @@ GEM json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) - multipart-post (~> 2.0.0) + multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) @@ -106,9 +106,9 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.32.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-core (0.9.5) + google-apis-androidpublisher_v3 (0.48.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.1) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -117,10 +117,10 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.16.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-playcustomapp_v1 (0.12.0) - google-apis-core (>= 0.9.1, < 2.a) + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) google-apis-storage_v1 (0.19.0) google-apis-core (>= 0.9.0, < 2.a) google-cloud-core (1.6.0) @@ -128,7 +128,7 @@ GEM google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.3.0) + google-cloud-errors (1.3.1) google-cloud-storage (1.44.0) addressable (~> 2.8) digest-crc (~> 0.4) @@ -137,7 +137,7 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.3.0) + googleauth (1.7.0) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -150,25 +150,25 @@ GEM httpclient (2.8.3) jmespath (1.6.2) json (2.6.3) - jwt (2.6.0) + jwt (2.7.1) memoist (0.16.2) mini_magick (4.12.0) - mini_mime (1.1.2) + mini_mime (1.1.5) multi_json (1.15.0) - multipart-post (2.0.0) + multipart-post (2.3.0) nanaimo (0.3.0) naturally (2.2.1) optparse (0.1.1) os (1.1.4) - plist (3.6.0) - public_suffix (5.0.1) + plist (3.7.0) + public_suffix (5.0.3) rake (13.0.6) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.2.6) rouge (2.0.7) ruby2_keywords (0.0.5) rubyzip (2.3.2) @@ -178,7 +178,7 @@ GEM faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.8) + simctl (1.6.10) CFPropertyList naturally terminal-notifier (2.0.0) @@ -194,7 +194,7 @@ GEM unf_ext unf_ext (0.0.8.2) unicode-display_width (1.8.0) - webrick (1.7.0) + webrick (1.8.1) word_wrap (1.0.0) xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) @@ -209,6 +209,7 @@ GEM xcpretty (~> 0.2, >= 0.0.7) PLATFORMS + arm64-darwin-22 universal-darwin-21 x86_64-darwin-20 @@ -216,4 +217,4 @@ DEPENDENCIES fastlane BUNDLED WITH - 2.3.23 + 2.4.10 diff --git a/Gemfile.lock.license b/Gemfile.lock.license index 9137ea9d..4f324d88 100644 --- a/Gemfile.lock.license +++ b/Gemfile.lock.license @@ -1,5 +1,5 @@ -This source file is part of the CS342 2023 PAWS Team Application project +This source file is part of the PAWS application based on the Stanford Spezi Template Application project SPDX-FileCopyrightText: 2023 Stanford University diff --git a/PAWS.xcodeproj/project.pbxproj b/PAWS.xcodeproj/project.pbxproj index a878c5b8..05b081f6 100644 --- a/PAWS.xcodeproj/project.pbxproj +++ b/PAWS.xcodeproj/project.pbxproj @@ -7,37 +7,72 @@ objects = { /* Begin PBXBuildFile section */ - 2F36AD24299D93E200B1077C /* NotificationsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F36AD23299D93E200B1077C /* NotificationsTests.swift */; }; - 2F36AD27299D989F00B1077C /* XCTestExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = 2F36AD26299D989F00B1077C /* XCTestExtensions */; }; - 2F49B7762980407C00BCB272 /* CardinalKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B7752980407B00BCB272 /* CardinalKit */; }; - 2F49B7782980407C00BCB272 /* FHIR in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B7772980407C00BCB272 /* FHIR */; }; - 2F49B77A2980407C00BCB272 /* HealthKitDataSource in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B7792980407C00BCB272 /* HealthKitDataSource */; }; - 2F49B77E2980407C00BCB272 /* Scheduler in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B77D2980407C00BCB272 /* Scheduler */; }; - 2F49B7802980418400BCB272 /* Onboarding in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B77F2980418400BCB272 /* Onboarding */; }; - 2F49B7822980419C00BCB272 /* Questionnaires in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B7812980419C00BCB272 /* Questionnaires */; }; - 2F49B784298041F300BCB272 /* Contact in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B783298041F300BCB272 /* Contact */; }; - 2F4E237E2989A2FE0013F3D9 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4E237D2989A2FE0013F3D9 /* OnboardingTests.swift */; }; - 2F4E23812989C5930013F3D9 /* XCTHealthKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2F4E23802989C5930013F3D9 /* XCTHealthKit */; }; - 2F4E23832989D51F0013F3D9 /* PAWSAppTestingSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4E23822989D51F0013F3D9 /* PAWSAppTestingSetup.swift */; }; - 2F4E23872989DB360013F3D9 /* ContactsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4E23862989DB360013F3D9 /* ContactsTests.swift */; }; - 2F59B93D298C628800C5107F /* PAWSContacts in Frameworks */ = {isa = PBXBuildFile; productRef = 2F59B93C298C628800C5107F /* PAWSContacts */; }; - 2F59B93F298C628800C5107F /* PAWSMockDataStorageProvider in Frameworks */ = {isa = PBXBuildFile; productRef = 2F59B93E298C628800C5107F /* PAWSMockDataStorageProvider */; }; - 2F59B941298C628800C5107F /* PAWSOnboardingFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 2F59B940298C628800C5107F /* PAWSOnboardingFlow */; }; - 2F59B945298C628800C5107F /* PAWSSharedContext in Frameworks */ = {isa = PBXBuildFile; productRef = 2F59B944298C628800C5107F /* PAWSSharedContext */; }; - 2F5E32BD297E05EA003432F8 /* PAWSAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5E32BC297E05EA003432F8 /* PAWSAppDelegate.swift */; }; - 2F9056D3299E1B9C003D3802 /* FHIRToFirestoreAdapter in Frameworks */ = {isa = PBXBuildFile; productRef = 2F9056D2299E1B9C003D3802 /* FHIRToFirestoreAdapter */; }; - 2F9056D5299E1B9C003D3802 /* FirestoreDataStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 2F9056D4299E1B9C003D3802 /* FirestoreDataStorage */; }; - 2F9056D7299E1B9C003D3802 /* FirestoreStoragePrefixUserIdAdapter in Frameworks */ = {isa = PBXBuildFile; productRef = 2F9056D6299E1B9C003D3802 /* FirestoreStoragePrefixUserIdAdapter */; }; - 2F9056DB299E1C97003D3802 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F9056D9299E1C97003D3802 /* GoogleService-Info.plist */; }; - 2F9F4D8329B7FFAE00ABE259 /* CardinalKitHealthKitToFHIRAdapter in Frameworks */ = {isa = PBXBuildFile; productRef = 2F9F4D8229B7FFAE00ABE259 /* CardinalKitHealthKitToFHIRAdapter */; }; - 2FABBC5929A8975900DF3BBC /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 2FABBC5829A8975900DF3BBC /* FirebaseFirestore */; }; - 2FABBC5B29A8975900DF3BBC /* FirebaseFirestoreSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 2FABBC5A29A8975900DF3BBC /* FirebaseFirestoreSwift */; }; - 2FC9759F2978E39600BA99FE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2FC9759E2978E39600BA99FE /* Localizable.strings */; }; - 3637947E2992F3B000B3C006 /* PAWSLandingScreen in Frameworks */ = {isa = PBXBuildFile; productRef = 3637947D2992F3B000B3C006 /* PAWSLandingScreen */; }; - 36379481299308AA00B3C006 /* PAWSNotificationScreen in Frameworks */ = {isa = PBXBuildFile; productRef = 36379480299308AA00B3C006 /* PAWSNotificationScreen */; }; + 2F3D4ABC2A4E7C290068FB2F /* SpeziScheduler in Frameworks */ = {isa = PBXBuildFile; productRef = 2F3D4ABB2A4E7C290068FB2F /* SpeziScheduler */; }; + 2F49B7762980407C00BCB272 /* Spezi in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B7752980407B00BCB272 /* Spezi */; }; + 2F4E237E2989A2FE0013F3D9 /* LaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4E237D2989A2FE0013F3D9 /* LaunchTests.swift */; }; + 2F4E23832989D51F0013F3D9 /* PAWSTestingSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4E23822989D51F0013F3D9 /* PAWSTestingSetup.swift */; }; + 2F4FC8D729EE69D300BFFE26 /* MockUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F4FC8D629EE69D300BFFE26 /* MockUpload.swift */; }; + 2F5E32BD297E05EA003432F8 /* PAWSDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5E32BC297E05EA003432F8 /* PAWSDelegate.swift */; }; + 2F6025CB29BBE70F0045459E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2F6025CA29BBE70F0045459E /* GoogleService-Info.plist */; }; + 2F65B44E2A3B8B0600A36932 /* NotificationPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F65B44D2A3B8B0600A36932 /* NotificationPermissions.swift */; }; + 2FA0BFED2ACC977500E0EF83 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 2FA0BFEC2ACC977500E0EF83 /* Localizable.xcstrings */; }; + 2FB099AF2A875DF100B20952 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 2FB099AE2A875DF100B20952 /* FirebaseAuth */; }; + 2FB099B12A875DF100B20952 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 2FB099B02A875DF100B20952 /* FirebaseFirestore */; }; + 2FB099B32A875DF100B20952 /* FirebaseFirestoreSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 2FB099B22A875DF100B20952 /* FirebaseFirestoreSwift */; }; + 2FB099B62A875E2B00B20952 /* HealthKitOnFHIR in Frameworks */ = {isa = PBXBuildFile; productRef = 2FB099B52A875E2B00B20952 /* HealthKitOnFHIR */; }; + 2FBD738C2A3BD150004228E7 /* SpeziScheduler in Frameworks */ = {isa = PBXBuildFile; productRef = 2FBD738B2A3BD150004228E7 /* SpeziScheduler */; }; + 2FC3439229EE634B002D773C /* ConsentDocument.md in Resources */ = {isa = PBXBuildFile; fileRef = 2FE5DC2C29EDD78E004B9AB4 /* ConsentDocument.md */; }; + 2FC975A82978F11A00BA99FE /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC975A72978F11A00BA99FE /* Home.swift */; }; + 2FCC1DBE2B6A1C9000C686BE /* ECGRecordingsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCC1DBD2B6A1C9000C686BE /* ECGRecordingsList.swift */; }; + 2FCC1DC12B6A1D4C00C686BE /* ECGModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCC1DC02B6A1D4C00C686BE /* ECGModule.swift */; }; + 2FCC1DC52B6A1F0600C686BE /* ECGRecording.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCC1DC42B6A1F0600C686BE /* ECGRecording.swift */; }; + 2FCC1DC92B6A258A00C686BE /* PAWSScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCC1DC82B6A258A00C686BE /* PAWSScheduler.swift */; }; + 2FCC1DCB2B6A2B2700C686BE /* Date+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FCC1DCA2B6A2B2700C686BE /* Date+RawRepresentable.swift */; }; + 2FE5DC2629EDD38A004B9AB4 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC2529EDD38A004B9AB4 /* Contacts.swift */; }; + 2FE5DC3529EDD7CA004B9AB4 /* Consent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC2F29EDD7CA004B9AB4 /* Consent.swift */; }; + 2FE5DC3629EDD7CA004B9AB4 /* HealthKitPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3029EDD7CA004B9AB4 /* HealthKitPermissions.swift */; }; + 2FE5DC3729EDD7CA004B9AB4 /* OnboardingFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3129EDD7CA004B9AB4 /* OnboardingFlow.swift */; }; + 2FE5DC3829EDD7CA004B9AB4 /* InterestingModules.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3229EDD7CA004B9AB4 /* InterestingModules.swift */; }; + 2FE5DC3A29EDD7CA004B9AB4 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3429EDD7CA004B9AB4 /* Welcome.swift */; }; + 2FE5DC4029EDD7EE004B9AB4 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3E29EDD7ED004B9AB4 /* FeatureFlags.swift */; }; + 2FE5DC4129EDD7EE004B9AB4 /* StorageKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3F29EDD7EE004B9AB4 /* StorageKeys.swift */; }; + 2FE5DC4529EDD7F2004B9AB4 /* Binding+Negate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4229EDD7F2004B9AB4 /* Binding+Negate.swift */; }; + 2FE5DC4629EDD7F2004B9AB4 /* Bundle+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4329EDD7F2004B9AB4 /* Bundle+Image.swift */; }; + 2FE5DC4729EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4429EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift */; }; + 2FE5DC5129EDD7FA004B9AB4 /* PAWSTaskContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4B29EDD7FA004B9AB4 /* PAWSTaskContext.swift */; }; + 2FE5DC6429EDD883004B9AB4 /* SpeziAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC6329EDD883004B9AB4 /* SpeziAccount */; }; + 2FE5DC6729EDD894004B9AB4 /* SpeziContact in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC6629EDD894004B9AB4 /* SpeziContact */; }; + 2FE5DC7229EDD8D3004B9AB4 /* SpeziHealthKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC7129EDD8D3004B9AB4 /* SpeziHealthKit */; }; + 2FE5DC7529EDD8E6004B9AB4 /* SpeziFirebaseAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC7429EDD8E6004B9AB4 /* SpeziFirebaseAccount */; }; + 2FE5DC7729EDD8E6004B9AB4 /* SpeziFirebaseConfiguration in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC7629EDD8E6004B9AB4 /* SpeziFirebaseConfiguration */; }; + 2FE5DC7929EDD8E6004B9AB4 /* SpeziFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC7829EDD8E6004B9AB4 /* SpeziFirestore */; }; + 2FE5DC8A29EDD972004B9AB4 /* SpeziLocalStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC8929EDD972004B9AB4 /* SpeziLocalStorage */; }; + 2FE5DC8C29EDD972004B9AB4 /* SpeziSecureStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC8B29EDD972004B9AB4 /* SpeziSecureStorage */; }; + 2FE5DC8F29EDD980004B9AB4 /* SpeziViews in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC8E29EDD980004B9AB4 /* SpeziViews */; }; + 2FE5DC9929EDD9D9004B9AB4 /* XCTestExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC9829EDD9D9004B9AB4 /* XCTestExtensions */; }; + 2FE5DC9C29EDD9EF004B9AB4 /* XCTHealthKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC9B29EDD9EF004B9AB4 /* XCTHealthKit */; }; + 2FE5DCB129EE6107004B9AB4 /* AccountOnboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DCAC29EE6107004B9AB4 /* AccountOnboarding.swift */; }; + 2FF53D8B2A8725DE00042B76 /* SpeziMockWebService in Frameworks */ = {isa = PBXBuildFile; productRef = 2FF53D8A2A8725DE00042B76 /* SpeziMockWebService */; }; + 2FF53D8D2A8729D600042B76 /* PAWSStandard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FF53D8C2A8729D600042B76 /* PAWSStandard.swift */; }; + 2FFD22F62B59ABE2005DD268 /* PAWSCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFD22F52B59ABE2005DD268 /* PAWSCard.swift */; }; + 2FFD22FC2B59AED8005DD268 /* FAQ.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFD22FB2B59AED8005DD268 /* FAQ.swift */; }; + 2FFD22FF2B59B158005DD268 /* StudyDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFD22FE2B59B158005DD268 /* StudyDescription.swift */; }; + 2FFD23022B59B22C005DD268 /* StudyInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FFD23012B59B22C005DD268 /* StudyInformation.swift */; }; + 5661551D2AB8384200209B80 /* SwiftPackageList in Frameworks */ = {isa = PBXBuildFile; productRef = 5661551C2AB8384200209B80 /* SwiftPackageList */; }; + 566155292AB8447C00209B80 /* Package+LicenseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566155282AB8447C00209B80 /* Package+LicenseType.swift */; }; + 5661552E2AB854C000209B80 /* PackageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5661552D2AB854C000209B80 /* PackageHelper.swift */; }; + 5680DD392AB8983D004E6D4A /* PackageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5680DD382AB8983D004E6D4A /* PackageCell.swift */; }; + 56F6F2A02AB441930022FE5A /* ContributionsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56F6F29F2AB441930022FE5A /* ContributionsList.swift */; }; 653A2551283387FE005D4D48 /* PAWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653A2550283387FE005D4D48 /* PAWS.swift */; }; 653A255528338800005D4D48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 653A255428338800005D4D48 /* Assets.xcassets */; }; 653A256228338800005D4D48 /* PAWSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653A256128338800005D4D48 /* PAWSTests.swift */; }; + 9733CFC62A8066DE001B7ABC /* SpeziOnboarding in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC8029EDD91D004B9AB4 /* SpeziOnboarding */; }; + 9739A0C62AD7B5730084BEA5 /* FirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 9739A0C52AD7B5730084BEA5 /* FirebaseStorage */; }; + 97D73D6A2AD860AD00B47FA0 /* SpeziFirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 97D73D692AD860AD00B47FA0 /* SpeziFirebaseStorage */; }; + A9720E432ABB68CC00872D23 /* AccountSetupHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9720E422ABB68CC00872D23 /* AccountSetupHeader.swift */; }; + A9D83F962B083794000D0C78 /* SpeziFirebaseAccountStorage in Frameworks */ = {isa = PBXBuildFile; productRef = A9D83F952B083794000D0C78 /* SpeziFirebaseAccountStorage */; }; + A9DFE8A92ABE551400428242 /* AccountButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DFE8A82ABE551400428242 /* AccountButton.swift */; }; + A9FE7AD02AA39BAB0077B045 /* AccountSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FE7ACF2AA39BAB0077B045 /* AccountSheet.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -46,28 +81,56 @@ containerPortal = 653A2545283387FE005D4D48 /* Project object */; proxyType = 1; remoteGlobalIDString = 653A254C283387FE005D4D48; - remoteInfo = Blance; + remoteInfo = PAWS; }; 653A256828338800005D4D48 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 653A2545283387FE005D4D48 /* Project object */; proxyType = 1; remoteGlobalIDString = 653A254C283387FE005D4D48; - remoteInfo = Blance; + remoteInfo = PAWS; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 2F36AD23299D93E200B1077C /* NotificationsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTests.swift; sourceTree = ""; }; - 2F49B77329803E8F00BCB272 /* PAWSModules */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PAWSModules; sourceTree = ""; }; - 2F4E237D2989A2FE0013F3D9 /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; - 2F4E23822989D51F0013F3D9 /* PAWSAppTestingSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWSAppTestingSetup.swift; sourceTree = ""; }; - 2F4E23862989DB360013F3D9 /* ContactsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsTests.swift; sourceTree = ""; }; - 2F5E32BC297E05EA003432F8 /* PAWSAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWSAppDelegate.swift; sourceTree = ""; }; - 2F9056D9299E1C97003D3802 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 2F4E237D2989A2FE0013F3D9 /* LaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchTests.swift; sourceTree = ""; }; + 2F4E23822989D51F0013F3D9 /* PAWSTestingSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWSTestingSetup.swift; sourceTree = ""; }; + 2F4FC8D629EE69D300BFFE26 /* MockUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUpload.swift; sourceTree = ""; }; + 2F5E32BC297E05EA003432F8 /* PAWSDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWSDelegate.swift; sourceTree = ""; }; + 2F6025CA29BBE70F0045459E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 2F65B44D2A3B8B0600A36932 /* NotificationPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissions.swift; sourceTree = ""; }; + 2FA0BFEC2ACC977500E0EF83 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; 2FAEC07F297F583900C11C42 /* PAWS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PAWS.entitlements; sourceTree = ""; }; 2FC94CD4298B0A1D009C8209 /* PAWS.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PAWS.xctestplan; sourceTree = ""; }; - 2FC9759E2978E39600BA99FE /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; + 2FC975A72978F11A00BA99FE /* Home.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Home.swift; sourceTree = ""; }; + 2FCC1DBD2B6A1C9000C686BE /* ECGRecordingsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ECGRecordingsList.swift; sourceTree = ""; }; + 2FCC1DC02B6A1D4C00C686BE /* ECGModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ECGModule.swift; sourceTree = ""; }; + 2FCC1DC42B6A1F0600C686BE /* ECGRecording.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ECGRecording.swift; sourceTree = ""; }; + 2FCC1DC82B6A258A00C686BE /* PAWSScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWSScheduler.swift; sourceTree = ""; }; + 2FCC1DCA2B6A2B2700C686BE /* Date+RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+RawRepresentable.swift"; sourceTree = ""; }; + 2FE5DC2529EDD38A004B9AB4 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = ""; }; + 2FE5DC2C29EDD78E004B9AB4 /* ConsentDocument.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ConsentDocument.md; sourceTree = ""; }; + 2FE5DC2F29EDD7CA004B9AB4 /* Consent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Consent.swift; sourceTree = ""; }; + 2FE5DC3029EDD7CA004B9AB4 /* HealthKitPermissions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HealthKitPermissions.swift; sourceTree = ""; }; + 2FE5DC3129EDD7CA004B9AB4 /* OnboardingFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingFlow.swift; sourceTree = ""; }; + 2FE5DC3229EDD7CA004B9AB4 /* InterestingModules.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterestingModules.swift; sourceTree = ""; }; + 2FE5DC3429EDD7CA004B9AB4 /* Welcome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Welcome.swift; sourceTree = ""; }; + 2FE5DC3E29EDD7ED004B9AB4 /* FeatureFlags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = ""; }; + 2FE5DC3F29EDD7EE004B9AB4 /* StorageKeys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageKeys.swift; sourceTree = ""; }; + 2FE5DC4229EDD7F2004B9AB4 /* Binding+Negate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Binding+Negate.swift"; sourceTree = ""; }; + 2FE5DC4329EDD7F2004B9AB4 /* Bundle+Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bundle+Image.swift"; sourceTree = ""; }; + 2FE5DC4429EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CodableArray+RawRepresentable.swift"; sourceTree = ""; }; + 2FE5DC4B29EDD7FA004B9AB4 /* PAWSTaskContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PAWSTaskContext.swift; sourceTree = ""; }; + 2FE5DCAC29EE6107004B9AB4 /* AccountOnboarding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountOnboarding.swift; sourceTree = ""; }; + 2FF53D8C2A8729D600042B76 /* PAWSStandard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PAWSStandard.swift; sourceTree = ""; }; + 2FFD22F52B59ABE2005DD268 /* PAWSCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWSCard.swift; sourceTree = ""; }; + 2FFD22FB2B59AED8005DD268 /* FAQ.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQ.swift; sourceTree = ""; }; + 2FFD22FE2B59B158005DD268 /* StudyDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyDescription.swift; sourceTree = ""; }; + 2FFD23012B59B22C005DD268 /* StudyInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyInformation.swift; sourceTree = ""; }; + 566155282AB8447C00209B80 /* Package+LicenseType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Package+LicenseType.swift"; sourceTree = ""; }; + 5661552D2AB854C000209B80 /* PackageHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageHelper.swift; sourceTree = ""; }; + 5680DD382AB8983D004E6D4A /* PackageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageCell.swift; sourceTree = ""; }; + 56F6F29F2AB441930022FE5A /* ContributionsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContributionsList.swift; sourceTree = ""; }; 653A254D283387FE005D4D48 /* PAWS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PAWS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 653A2550283387FE005D4D48 /* PAWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWS.swift; sourceTree = ""; }; 653A255428338800005D4D48 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -75,6 +138,9 @@ 653A256128338800005D4D48 /* PAWSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PAWSTests.swift; sourceTree = ""; }; 653A256728338800005D4D48 /* PAWSUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PAWSUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 653A258928339462005D4D48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A9720E422ABB68CC00872D23 /* AccountSetupHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSetupHeader.swift; sourceTree = ""; }; + A9DFE8A82ABE551400428242 /* AccountButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountButton.swift; sourceTree = ""; }; + A9FE7ACF2AA39BAB0077B045 /* AccountSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSheet.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -82,25 +148,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 36379481299308AA00B3C006 /* PAWSNotificationScreen in Frameworks */, - 2F59B941298C628800C5107F /* PAWSOnboardingFlow in Frameworks */, - 2F9F4D8329B7FFAE00ABE259 /* CardinalKitHealthKitToFHIRAdapter in Frameworks */, - 2F49B7822980419C00BCB272 /* Questionnaires in Frameworks */, - 2F49B77E2980407C00BCB272 /* Scheduler in Frameworks */, - 2F9056D3299E1B9C003D3802 /* FHIRToFirestoreAdapter in Frameworks */, - 2FABBC5B29A8975900DF3BBC /* FirebaseFirestoreSwift in Frameworks */, - 2FABBC5929A8975900DF3BBC /* FirebaseFirestore in Frameworks */, - 3637947E2992F3B000B3C006 /* PAWSLandingScreen in Frameworks */, - 2F9056D5299E1B9C003D3802 /* FirestoreDataStorage in Frameworks */, - 2F59B93F298C628800C5107F /* PAWSMockDataStorageProvider in Frameworks */, - 2F49B77A2980407C00BCB272 /* HealthKitDataSource in Frameworks */, - 2F59B945298C628800C5107F /* PAWSSharedContext in Frameworks */, - 2F49B784298041F300BCB272 /* Contact in Frameworks */, - 2F9056D7299E1B9C003D3802 /* FirestoreStoragePrefixUserIdAdapter in Frameworks */, - 2F49B7782980407C00BCB272 /* FHIR in Frameworks */, - 2F49B7802980418400BCB272 /* Onboarding in Frameworks */, - 2F49B7762980407C00BCB272 /* CardinalKit in Frameworks */, - 2F59B93D298C628800C5107F /* PAWSContacts in Frameworks */, + 9733CFC62A8066DE001B7ABC /* SpeziOnboarding in Frameworks */, + 2FE5DC6429EDD883004B9AB4 /* SpeziAccount in Frameworks */, + 2FB099AF2A875DF100B20952 /* FirebaseAuth in Frameworks */, + 97D73D6A2AD860AD00B47FA0 /* SpeziFirebaseStorage in Frameworks */, + 2FE5DC6729EDD894004B9AB4 /* SpeziContact in Frameworks */, + 2FB099B32A875DF100B20952 /* FirebaseFirestoreSwift in Frameworks */, + 5661551D2AB8384200209B80 /* SwiftPackageList in Frameworks */, + 2FB099B12A875DF100B20952 /* FirebaseFirestore in Frameworks */, + A9D83F962B083794000D0C78 /* SpeziFirebaseAccountStorage in Frameworks */, + 2FB099B62A875E2B00B20952 /* HealthKitOnFHIR in Frameworks */, + 2FE5DC8A29EDD972004B9AB4 /* SpeziLocalStorage in Frameworks */, + 2FE5DC8C29EDD972004B9AB4 /* SpeziSecureStorage in Frameworks */, + 2FE5DC7529EDD8E6004B9AB4 /* SpeziFirebaseAccount in Frameworks */, + 9739A0C62AD7B5730084BEA5 /* FirebaseStorage in Frameworks */, + 2FF53D8B2A8725DE00042B76 /* SpeziMockWebService in Frameworks */, + 2FE5DC7229EDD8D3004B9AB4 /* SpeziHealthKit in Frameworks */, + 2F49B7762980407C00BCB272 /* Spezi in Frameworks */, + 2FE5DC8F29EDD980004B9AB4 /* SpeziViews in Frameworks */, + 2F3D4ABC2A4E7C290068FB2F /* SpeziScheduler in Frameworks */, + 2FBD738C2A3BD150004228E7 /* SpeziScheduler in Frameworks */, + 2FE5DC7929EDD8E6004B9AB4 /* SpeziFirestore in Frameworks */, + 2FE5DC7729EDD8E6004B9AB4 /* SpeziFirebaseConfiguration in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -115,31 +184,129 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2F4E23812989C5930013F3D9 /* XCTHealthKit in Frameworks */, - 2F36AD27299D989F00B1077C /* XCTestExtensions in Frameworks */, + 2FE5DC9929EDD9D9004B9AB4 /* XCTestExtensions in Frameworks */, + 2FE5DC9C29EDD9EF004B9AB4 /* XCTHealthKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2F4FC8D529EE69BE00BFFE26 /* MockUpload */ = { + isa = PBXGroup; + children = ( + 2F4FC8D629EE69D300BFFE26 /* MockUpload.swift */, + ); + path = MockUpload; + sourceTree = ""; + }; 2FC9759D2978E30800BA99FE /* Supporting Files */ = { isa = PBXGroup; children = ( 2FAEC07F297F583900C11C42 /* PAWS.entitlements */, 653A258928339462005D4D48 /* Info.plist */, - 2F9056D9299E1C97003D3802 /* GoogleService-Info.plist */, - 653A255428338800005D4D48 /* Assets.xcassets */, - 2FC9759E2978E39600BA99FE /* Localizable.strings */, + 2F6025CA29BBE70F0045459E /* GoogleService-Info.plist */, ); path = "Supporting Files"; sourceTree = ""; }; + 2FCC1DBC2B6A1C7400C686BE /* ECGRecordings */ = { + isa = PBXGroup; + children = ( + 2FCC1DBD2B6A1C9000C686BE /* ECGRecordingsList.swift */, + 2FCC1DC42B6A1F0600C686BE /* ECGRecording.swift */, + 2FCC1DC02B6A1D4C00C686BE /* ECGModule.swift */, + ); + path = ECGRecordings; + sourceTree = ""; + }; + 2FE5DC2729EDD38D004B9AB4 /* Contacts */ = { + isa = PBXGroup; + children = ( + 2FE5DC2529EDD38A004B9AB4 /* Contacts.swift */, + ); + path = Contacts; + sourceTree = ""; + }; + 2FE5DC2829EDD398004B9AB4 /* Onboarding */ = { + isa = PBXGroup; + children = ( + 2FE5DC3129EDD7CA004B9AB4 /* OnboardingFlow.swift */, + 2FE5DC3429EDD7CA004B9AB4 /* Welcome.swift */, + 2FE5DC3229EDD7CA004B9AB4 /* InterestingModules.swift */, + 2FE5DCAC29EE6107004B9AB4 /* AccountOnboarding.swift */, + 2FE5DC2F29EDD7CA004B9AB4 /* Consent.swift */, + 2FE5DC3029EDD7CA004B9AB4 /* HealthKitPermissions.swift */, + 2F65B44D2A3B8B0600A36932 /* NotificationPermissions.swift */, + ); + path = Onboarding; + sourceTree = ""; + }; + 2FE5DC2D29EDD792004B9AB4 /* Resources */ = { + isa = PBXGroup; + children = ( + 653A255428338800005D4D48 /* Assets.xcassets */, + 2FA0BFEC2ACC977500E0EF83 /* Localizable.xcstrings */, + 2FE5DC2C29EDD78E004B9AB4 /* ConsentDocument.md */, + ); + path = Resources; + sourceTree = ""; + }; + 2FE5DC3B29EDD7D0004B9AB4 /* Reminders */ = { + isa = PBXGroup; + children = ( + 2FE5DC4B29EDD7FA004B9AB4 /* PAWSTaskContext.swift */, + 2FCC1DC82B6A258A00C686BE /* PAWSScheduler.swift */, + ); + path = Reminders; + sourceTree = ""; + }; + 2FE5DC3C29EDD7DA004B9AB4 /* SharedContext */ = { + isa = PBXGroup; + children = ( + 2FE5DC3E29EDD7ED004B9AB4 /* FeatureFlags.swift */, + 2FE5DC3F29EDD7EE004B9AB4 /* StorageKeys.swift */, + 2FFD22F52B59ABE2005DD268 /* PAWSCard.swift */, + ); + path = SharedContext; + sourceTree = ""; + }; + 2FE5DC3D29EDD7E4004B9AB4 /* Helper */ = { + isa = PBXGroup; + children = ( + 2FE5DC4229EDD7F2004B9AB4 /* Binding+Negate.swift */, + 2FCC1DCA2B6A2B2700C686BE /* Date+RawRepresentable.swift */, + 2FE5DC4329EDD7F2004B9AB4 /* Bundle+Image.swift */, + 2FE5DC4429EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift */, + ); + path = Helper; + sourceTree = ""; + }; + 2FFD22F82B59AECC005DD268 /* Study Information */ = { + isa = PBXGroup; + children = ( + 2FFD22FB2B59AED8005DD268 /* FAQ.swift */, + 2FFD22FE2B59B158005DD268 /* StudyDescription.swift */, + 2FFD23012B59B22C005DD268 /* StudyInformation.swift */, + ); + path = "Study Information"; + sourceTree = ""; + }; + 56F6F29E2AB441640022FE5A /* Contributions */ = { + isa = PBXGroup; + children = ( + 56F6F29F2AB441930022FE5A /* ContributionsList.swift */, + 5680DD382AB8983D004E6D4A /* PackageCell.swift */, + 566155282AB8447C00209B80 /* Package+LicenseType.swift */, + 5661552D2AB854C000209B80 /* PackageHelper.swift */, + ); + path = Contributions; + sourceTree = ""; + }; 653A2544283387FE005D4D48 = { isa = PBXGroup; children = ( 2FC94CD4298B0A1D009C8209 /* PAWS.xctestplan */, - 2F49B77329803E8F00BCB272 /* PAWSModules */, 653A254F283387FE005D4D48 /* PAWS */, 653A256028338800005D4D48 /* PAWSTests */, 653A256A28338800005D4D48 /* PAWSUITests */, @@ -162,8 +329,21 @@ isa = PBXGroup; children = ( 653A2550283387FE005D4D48 /* PAWS.swift */, - 2F5E32BC297E05EA003432F8 /* PAWSAppDelegate.swift */, - 2F4E23822989D51F0013F3D9 /* PAWSAppTestingSetup.swift */, + 2F5E32BC297E05EA003432F8 /* PAWSDelegate.swift */, + 2FF53D8C2A8729D600042B76 /* PAWSStandard.swift */, + 2F4E23822989D51F0013F3D9 /* PAWSTestingSetup.swift */, + 2FC975A72978F11A00BA99FE /* Home.swift */, + A9720E412ABB68B300872D23 /* Account */, + 2FE5DC2829EDD398004B9AB4 /* Onboarding */, + 2FCC1DBC2B6A1C7400C686BE /* ECGRecordings */, + 2FE5DC3B29EDD7D0004B9AB4 /* Reminders */, + 2FFD22F82B59AECC005DD268 /* Study Information */, + 2FE5DC2729EDD38D004B9AB4 /* Contacts */, + 56F6F29E2AB441640022FE5A /* Contributions */, + 2F4FC8D529EE69BE00BFFE26 /* MockUpload */, + 2FE5DC3C29EDD7DA004B9AB4 /* SharedContext */, + 2FE5DC3D29EDD7E4004B9AB4 /* Helper */, + 2FE5DC2D29EDD792004B9AB4 /* Resources */, 2FC9759D2978E30800BA99FE /* Supporting Files */, ); path = PAWS; @@ -180,9 +360,7 @@ 653A256A28338800005D4D48 /* PAWSUITests */ = { isa = PBXGroup; children = ( - 2F4E237D2989A2FE0013F3D9 /* OnboardingTests.swift */, - 2F4E23862989DB360013F3D9 /* ContactsTests.swift */, - 2F36AD23299D93E200B1077C /* NotificationsTests.swift */, + 2F4E237D2989A2FE0013F3D9 /* LaunchTests.swift */, ); path = PAWSUITests; sourceTree = ""; @@ -194,6 +372,16 @@ name = Frameworks; sourceTree = ""; }; + A9720E412ABB68B300872D23 /* Account */ = { + isa = PBXGroup; + children = ( + A9FE7ACF2AA39BAB0077B045 /* AccountSheet.swift */, + A9720E422ABB68CC00872D23 /* AccountSetupHeader.swift */, + A9DFE8A82ABE551400428242 /* AccountButton.swift */, + ); + path = Account; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -204,35 +392,39 @@ 653A2549283387FE005D4D48 /* Sources */, 653A254A283387FE005D4D48 /* Frameworks */, 653A254B283387FE005D4D48 /* Resources */, - 2FDB275429AEB6DC0084C7DF /* ShellScript */, ); buildRules = ( ); dependencies = ( + 2FCC1DD02B6A2CF000C686BE /* PBXTargetDependency */, + 566155222AB83CF200209B80 /* PBXTargetDependency */, ); name = PAWS; packageProductDependencies = ( - 2F49B7752980407B00BCB272 /* CardinalKit */, - 2F49B7772980407C00BCB272 /* FHIR */, - 2F49B7792980407C00BCB272 /* HealthKitDataSource */, - 2F49B77D2980407C00BCB272 /* Scheduler */, - 2F49B77F2980418400BCB272 /* Onboarding */, - 2F49B7812980419C00BCB272 /* Questionnaires */, - 2F49B783298041F300BCB272 /* Contact */, - 2F59B93C298C628800C5107F /* PAWSContacts */, - 2F59B93E298C628800C5107F /* PAWSMockDataStorageProvider */, - 2F59B940298C628800C5107F /* PAWSOnboardingFlow */, - 2F59B944298C628800C5107F /* PAWSSharedContext */, - 3637947D2992F3B000B3C006 /* PAWSLandingScreen */, - 36379480299308AA00B3C006 /* PAWSNotificationScreen */, - 2F9056D2299E1B9C003D3802 /* FHIRToFirestoreAdapter */, - 2F9056D4299E1B9C003D3802 /* FirestoreDataStorage */, - 2F9056D6299E1B9C003D3802 /* FirestoreStoragePrefixUserIdAdapter */, - 2FABBC5829A8975900DF3BBC /* FirebaseFirestore */, - 2FABBC5A29A8975900DF3BBC /* FirebaseFirestoreSwift */, - 2F9F4D8229B7FFAE00ABE259 /* CardinalKitHealthKitToFHIRAdapter */, + 2F49B7752980407B00BCB272 /* Spezi */, + 2FE5DC6329EDD883004B9AB4 /* SpeziAccount */, + 2FE5DC6629EDD894004B9AB4 /* SpeziContact */, + 2FE5DC7129EDD8D3004B9AB4 /* SpeziHealthKit */, + 2FE5DC7429EDD8E6004B9AB4 /* SpeziFirebaseAccount */, + 2FE5DC7629EDD8E6004B9AB4 /* SpeziFirebaseConfiguration */, + 2FE5DC7829EDD8E6004B9AB4 /* SpeziFirestore */, + 2FE5DC8929EDD972004B9AB4 /* SpeziLocalStorage */, + 2FE5DC8B29EDD972004B9AB4 /* SpeziSecureStorage */, + 2FE5DC8E29EDD980004B9AB4 /* SpeziViews */, + 2FBD738B2A3BD150004228E7 /* SpeziScheduler */, + 2F3D4ABB2A4E7C290068FB2F /* SpeziScheduler */, + 2FE5DC8029EDD91D004B9AB4 /* SpeziOnboarding */, + 2FF53D8A2A8725DE00042B76 /* SpeziMockWebService */, + 2FB099AE2A875DF100B20952 /* FirebaseAuth */, + 2FB099B02A875DF100B20952 /* FirebaseFirestore */, + 2FB099B22A875DF100B20952 /* FirebaseFirestoreSwift */, + 2FB099B52A875E2B00B20952 /* HealthKitOnFHIR */, + 5661551C2AB8384200209B80 /* SwiftPackageList */, + 9739A0C52AD7B5730084BEA5 /* FirebaseStorage */, + 97D73D692AD860AD00B47FA0 /* SpeziFirebaseStorage */, + A9D83F952B083794000D0C78 /* SpeziFirebaseAccountStorage */, ); - productName = TemplateApplication; + productName = PAWS; productReference = 653A254D283387FE005D4D48 /* PAWS.app */; productType = "com.apple.product-type.application"; }; @@ -250,7 +442,7 @@ 653A255F28338800005D4D48 /* PBXTargetDependency */, ); name = PAWSTests; - productName = TemplateApplicationTests; + productName = PAWSTests; productReference = 653A255D28338800005D4D48 /* PAWSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; @@ -269,10 +461,10 @@ ); name = PAWSUITests; packageProductDependencies = ( - 2F4E23802989C5930013F3D9 /* XCTHealthKit */, - 2F36AD26299D989F00B1077C /* XCTestExtensions */, + 2FE5DC9829EDD9D9004B9AB4 /* XCTestExtensions */, + 2FE5DC9B29EDD9EF004B9AB4 /* XCTHealthKit */, ); - productName = TemplateApplicationUITests; + productName = PAWSUITests; productReference = 653A256728338800005D4D48 /* PAWSUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; @@ -284,7 +476,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1340; - LastUpgradeCheck = 1340; + LastUpgradeCheck = 1520; TargetAttributes = { 653A254C283387FE005D4D48 = { CreatedOnToolsVersion = 13.4; @@ -309,11 +501,22 @@ ); mainGroup = 653A2544283387FE005D4D48; packageReferences = ( - 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */, - 2F4E237F2989C5930013F3D9 /* XCRemoteSwiftPackageReference "XCTHealthKit" */, - 2F36AD25299D989F00B1077C /* XCRemoteSwiftPackageReference "XCTestExtensions" */, - 2FABBC5729A8975900DF3BBC /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, - 2F9F4D8129B7FFAE00ABE259 /* XCRemoteSwiftPackageReference "CardinalKitHealthKitToFHIRAdapter" */, + 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "Spezi" */, + 2FE5DC6229EDD883004B9AB4 /* XCRemoteSwiftPackageReference "SpeziAccount" */, + 2FE5DC6529EDD894004B9AB4 /* XCRemoteSwiftPackageReference "SpeziContact" */, + 2FE5DC7029EDD8D3004B9AB4 /* XCRemoteSwiftPackageReference "SpeziHealthKit" */, + 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */, + 2FE5DC8829EDD972004B9AB4 /* XCRemoteSwiftPackageReference "SpeziStorage" */, + 2FE5DC8D29EDD980004B9AB4 /* XCRemoteSwiftPackageReference "SpeziViews" */, + 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + 2FE5DC9729EDD9D9004B9AB4 /* XCRemoteSwiftPackageReference "XCTestExtensions" */, + 2FE5DC9A29EDD9EF004B9AB4 /* XCRemoteSwiftPackageReference "XCTHealthKit" */, + 2F3D4ABA2A4E7C290068FB2F /* XCRemoteSwiftPackageReference "SpeziScheduler" */, + 97F466E62A76BBEE005DC9B4 /* XCRemoteSwiftPackageReference "SpeziOnboarding" */, + 2FE750CA2A87240100723EAE /* XCRemoteSwiftPackageReference "SpeziMockWebService" */, + 2FB099B42A875E2B00B20952 /* XCRemoteSwiftPackageReference "HealthKitOnFHIR" */, + 5661551B2AB8384200209B80 /* XCRemoteSwiftPackageReference "swift-package-list" */, + 2FCC1DCE2B6A2CE000C686BE /* XCRemoteSwiftPackageReference "SwiftLint" */, ); productRefGroup = 653A254E283387FE005D4D48 /* Products */; projectDirPath = ""; @@ -331,9 +534,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2F9056DB299E1C97003D3802 /* GoogleService-Info.plist in Resources */, + 2FC3439229EE634B002D773C /* ConsentDocument.md in Resources */, 653A255528338800005D4D48 /* Assets.xcassets in Resources */, - 2FC9759F2978E39600BA99FE /* Localizable.strings in Resources */, + 2FA0BFED2ACC977500E0EF83 /* Localizable.xcstrings in Resources */, + 2F6025CB29BBE70F0045459E /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -353,35 +557,47 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 2FDB275429AEB6DC0084C7DF /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [ \"${CONFIGURATION}\" = \"Debug\" ]; then\n export PATH=\"$PATH:/opt/homebrew/bin\"\n if which swiftlint > /dev/null; then\n swiftlint\n else\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\n fi\nfi\n"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 653A2549283387FE005D4D48 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2F4E23832989D51F0013F3D9 /* PAWSAppTestingSetup.swift in Sources */, - 2F5E32BD297E05EA003432F8 /* PAWSAppDelegate.swift in Sources */, + 2FE5DC4129EDD7EE004B9AB4 /* StorageKeys.swift in Sources */, + 2FE5DCB129EE6107004B9AB4 /* AccountOnboarding.swift in Sources */, + 2F4FC8D729EE69D300BFFE26 /* MockUpload.swift in Sources */, + 2FE5DC3A29EDD7CA004B9AB4 /* Welcome.swift in Sources */, + 2FE5DC3829EDD7CA004B9AB4 /* InterestingModules.swift in Sources */, + 2FE5DC3529EDD7CA004B9AB4 /* Consent.swift in Sources */, + 2FE5DC4529EDD7F2004B9AB4 /* Binding+Negate.swift in Sources */, + 2FFD23022B59B22C005DD268 /* StudyInformation.swift in Sources */, + 2FCC1DBE2B6A1C9000C686BE /* ECGRecordingsList.swift in Sources */, + 2FCC1DCB2B6A2B2700C686BE /* Date+RawRepresentable.swift in Sources */, + 2FCC1DC12B6A1D4C00C686BE /* ECGModule.swift in Sources */, + 2FC975A82978F11A00BA99FE /* Home.swift in Sources */, + A9DFE8A92ABE551400428242 /* AccountButton.swift in Sources */, + 2FE5DC3729EDD7CA004B9AB4 /* OnboardingFlow.swift in Sources */, + 2FF53D8D2A8729D600042B76 /* PAWSStandard.swift in Sources */, + 2FE5DC4729EDD7F2004B9AB4 /* CodableArray+RawRepresentable.swift in Sources */, + A9720E432ABB68CC00872D23 /* AccountSetupHeader.swift in Sources */, + 2FE5DC4029EDD7EE004B9AB4 /* FeatureFlags.swift in Sources */, + 2FE5DC4629EDD7F2004B9AB4 /* Bundle+Image.swift in Sources */, + 2FFD22FC2B59AED8005DD268 /* FAQ.swift in Sources */, + 2F4E23832989D51F0013F3D9 /* PAWSTestingSetup.swift in Sources */, + 2FE5DC5129EDD7FA004B9AB4 /* PAWSTaskContext.swift in Sources */, + 2FCC1DC92B6A258A00C686BE /* PAWSScheduler.swift in Sources */, + 56F6F2A02AB441930022FE5A /* ContributionsList.swift in Sources */, + 566155292AB8447C00209B80 /* Package+LicenseType.swift in Sources */, + 2FFD22FF2B59B158005DD268 /* StudyDescription.swift in Sources */, + 5680DD392AB8983D004E6D4A /* PackageCell.swift in Sources */, + 2FCC1DC52B6A1F0600C686BE /* ECGRecording.swift in Sources */, + 2F5E32BD297E05EA003432F8 /* PAWSDelegate.swift in Sources */, + A9FE7AD02AA39BAB0077B045 /* AccountSheet.swift in Sources */, 653A2551283387FE005D4D48 /* PAWS.swift in Sources */, + 2FFD22F62B59ABE2005DD268 /* PAWSCard.swift in Sources */, + 2FE5DC3629EDD7CA004B9AB4 /* HealthKitPermissions.swift in Sources */, + 2F65B44E2A3B8B0600A36932 /* NotificationPermissions.swift in Sources */, + 5661552E2AB854C000209B80 /* PackageHelper.swift in Sources */, + 2FE5DC2629EDD38A004B9AB4 /* Contacts.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -397,15 +613,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2F4E23872989DB360013F3D9 /* ContactsTests.swift in Sources */, - 2F36AD24299D93E200B1077C /* NotificationsTests.swift in Sources */, - 2F4E237E2989A2FE0013F3D9 /* OnboardingTests.swift in Sources */, + 2F4E237E2989A2FE0013F3D9 /* LaunchTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 2FCC1DD02B6A2CF000C686BE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 2FCC1DCF2B6A2CF000C686BE /* SwiftLintPlugin */; + }; + 566155222AB83CF200209B80 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 566155212AB83CF200209B80 /* SwiftPackageListJSONPlugin */; + }; 653A255F28338800005D4D48 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 653A254C283387FE005D4D48 /* PAWS */; @@ -419,10 +641,11 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 2F82DB262A80C04F0029346E /* Test */ = { + 2FEE10302998C89C000822E1 /* Test */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; @@ -455,6 +678,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -469,17 +693,18 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = TEST; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Test; }; - 2F82DB272A80C04F0029346E /* Test */ = { + 2FEE10312998C89C000822E1 /* Test */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -493,21 +718,20 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "PAWS/Supporting Files/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = PAWS; INFOPLIST_KEY_NSCameraUsageDescription = "This message should never appear. Please adjust this when you start using camera information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; - INFOPLIST_KEY_NSHealthShareUsageDescription = "The PAWS Application uses the heart rate information to extract ECG data and provide it to the researchers. "; - INFOPLIST_KEY_NSHealthUpdateUsageDescription = "The PAWS Application uses the heart rate information to extract ECG data and provide it to the researchers. "; + INFOPLIST_KEY_NSHealthShareUsageDescription = "The PAWS uses the step count to demonstrate Spezi's integration with HealthKit."; + INFOPLIST_KEY_NSHealthUpdateUsageDescription = "The PAWS uses the step count to demonstrate Spezi's integration with HealthKit."; INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "This message should never appear. Please adjust this when you start using location information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This message should never appear. Please adjust this when you start using location information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSMicrophoneUsageDescription = "This message should never appear. Please adjust this when you start using microphone information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSMotionUsageDescription = "This message should never appear. Please adjust this when you start using motion information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "This message should never appear. Please adjust this when you start using speecg information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UIPAWSlicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIPAWSlicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; - INFOPLIST_KEY_UITemplateApplicationlicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UITemplateApplicationlicationSupportsIndirectInputEvents = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -519,13 +743,14 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = YES; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = YES; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; name = Test; }; - 2F82DB282A80C04F0029346E /* Test */ = { + 2FEE10322998C89C000822E1 /* Test */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; @@ -534,18 +759,18 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.paws.tests; PRODUCT_NAME = "$(TARGET_NAME)"; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = NO; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PAWS.app/PAWS"; }; name = Test; }; - 2F82DB292A80C04F0029346E /* Test */ = { + 2FEE10332998C89C000822E1 /* Test */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; @@ -553,11 +778,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.paws.uitests; + PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.pawsuitests; PRODUCT_NAME = "$(TARGET_NAME)"; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = NO; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = PAWS; @@ -568,6 +793,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; @@ -600,6 +826,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -614,7 +841,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -628,6 +856,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; @@ -660,6 +889,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -668,7 +898,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -692,21 +923,20 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "PAWS/Supporting Files/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = PAWS; INFOPLIST_KEY_NSCameraUsageDescription = "This message should never appear. Please adjust this when you start using camera information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; - INFOPLIST_KEY_NSHealthShareUsageDescription = "The PAWS Application uses the heart rate information to extract ECG data and provide it to the researchers. "; - INFOPLIST_KEY_NSHealthUpdateUsageDescription = "The PAWS Application uses the heart rate information to extract ECG data and provide it to the researchers. "; + INFOPLIST_KEY_NSHealthShareUsageDescription = "The PAWS uses the step count to demonstrate Spezi's integration with HealthKit."; + INFOPLIST_KEY_NSHealthUpdateUsageDescription = "The PAWS uses the step count to demonstrate Spezi's integration with HealthKit."; INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "This message should never appear. Please adjust this when you start using location information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This message should never appear. Please adjust this when you start using location information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSMicrophoneUsageDescription = "This message should never appear. Please adjust this when you start using microphone information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSMotionUsageDescription = "This message should never appear. Please adjust this when you start using motion information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "This message should never appear. Please adjust this when you start using speecg information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UIPAWSlicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIPAWSlicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; - INFOPLIST_KEY_UITemplateApplicationlicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UITemplateApplicationlicationSupportsIndirectInputEvents = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -718,7 +948,8 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = YES; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = YES; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; @@ -730,6 +961,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "PAWS/Supporting Files/PAWS.entitlements"; + CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; @@ -739,21 +971,20 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "PAWS/Supporting Files/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = PAWS; INFOPLIST_KEY_NSCameraUsageDescription = "This message should never appear. Please adjust this when you start using camera information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; - INFOPLIST_KEY_NSHealthShareUsageDescription = "The PAWS Application uses the heart rate information to extract ECG data and provide it to the researchers. "; - INFOPLIST_KEY_NSHealthUpdateUsageDescription = "The PAWS Application uses the heart rate information to extract ECG data and provide it to the researchers. "; + INFOPLIST_KEY_NSHealthShareUsageDescription = "The PAWS uses the step count to demonstrate Spezi's integration with HealthKit."; + INFOPLIST_KEY_NSHealthUpdateUsageDescription = "The PAWS uses the step count to demonstrate Spezi's integration with HealthKit."; INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "This message should never appear. Please adjust this when you start using location information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This message should never appear. Please adjust this when you start using location information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSMicrophoneUsageDescription = "This message should never appear. Please adjust this when you start using microphone information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSMotionUsageDescription = "This message should never appear. Please adjust this when you start using motion information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "This message should never appear. Please adjust this when you start using speecg information. We have to put this in here as ResearchKit has the possibility to use it and not putting it here returns an error on AppStore Connect."; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UIPAWSlicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIPAWSlicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; - INFOPLIST_KEY_UITemplateApplicationlicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UITemplateApplicationlicationSupportsIndirectInputEvents = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -766,7 +997,8 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = YES; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = YES; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; @@ -781,11 +1013,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.paws.tests; PRODUCT_NAME = "$(TARGET_NAME)"; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = NO; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PAWS.app/PAWS"; @@ -801,11 +1033,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.paws.tests; PRODUCT_NAME = "$(TARGET_NAME)"; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = NO; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PAWS.app/PAWS"; @@ -820,11 +1052,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.paws.uitests; + PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.pawsuitests; PRODUCT_NAME = "$(TARGET_NAME)"; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = NO; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = PAWS; @@ -839,11 +1071,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.paws.uitests; + PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.cs342.2023.pawsuitests; PRODUCT_NAME = "$(TARGET_NAME)"; - "SWIFT_ELicenseRef-TemplateApplication_LOC_STRINGS" = NO; + "SWIFT_ELicenseRef-PAWS_LOC_STRINGS" = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = PAWS; @@ -857,7 +1089,7 @@ isa = XCConfigurationList; buildConfigurations = ( 653A256F28338800005D4D48 /* Debug */, - 2F82DB262A80C04F0029346E /* Test */, + 2FEE10302998C89C000822E1 /* Test */, 653A257028338800005D4D48 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -867,7 +1099,7 @@ isa = XCConfigurationList; buildConfigurations = ( 653A257228338800005D4D48 /* Debug */, - 2F82DB272A80C04F0029346E /* Test */, + 2FEE10312998C89C000822E1 /* Test */, 653A257328338800005D4D48 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -877,7 +1109,7 @@ isa = XCConfigurationList; buildConfigurations = ( 653A257528338800005D4D48 /* Debug */, - 2F82DB282A80C04F0029346E /* Test */, + 2FEE10322998C89C000822E1 /* Test */, 653A257628338800005D4D48 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -887,7 +1119,7 @@ isa = XCConfigurationList; buildConfigurations = ( 653A257828338800005D4D48 /* Debug */, - 2F82DB292A80C04F0029346E /* Test */, + 2FEE10332998C89C000822E1 /* Test */, 653A257928338800005D4D48 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -896,147 +1128,265 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 2F36AD25299D989F00B1077C /* XCRemoteSwiftPackageReference "XCTestExtensions" */ = { + 2F3D4ABA2A4E7C290068FB2F /* XCRemoteSwiftPackageReference "SpeziScheduler" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/StanfordBDHG/XCTestExtensions"; + repositoryURL = "https://github.com/StanfordSpezi/SpeziScheduler.git"; requirement = { kind = upToNextMinorVersion; - minimumVersion = 0.4.6; + minimumVersion = 0.8.0; }; }; - 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */ = { + 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "Spezi" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/StanfordBDHG/CardinalKit"; + repositoryURL = "https://github.com/StanfordSpezi/Spezi"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.1.0; + }; + }; + 2FB099B42A875E2B00B20952 /* XCRemoteSwiftPackageReference "HealthKitOnFHIR" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordBDHG/HealthKitOnFHIR.git"; requirement = { kind = upToNextMinorVersion; - minimumVersion = 0.3.5; + minimumVersion = 0.2.4; }; }; - 2F4E237F2989C5930013F3D9 /* XCRemoteSwiftPackageReference "XCTHealthKit" */ = { + 2FCC1DCE2B6A2CE000C686BE /* XCRemoteSwiftPackageReference "SwiftLint" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/StanfordBDHG/XCTHealthKit"; + repositoryURL = "https://github.com/realm/SwiftLint.git"; requirement = { kind = upToNextMinorVersion; - minimumVersion = 0.3.5; + minimumVersion = 0.54.0; + }; + }; + 2FE5DC6229EDD883004B9AB4 /* XCRemoteSwiftPackageReference "SpeziAccount" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziAccount.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.1.0; }; }; - 2F9F4D8129B7FFAE00ABE259 /* XCRemoteSwiftPackageReference "CardinalKitHealthKitToFHIRAdapter" */ = { + 2FE5DC6529EDD894004B9AB4 /* XCRemoteSwiftPackageReference "SpeziContact" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/StanfordBDHG/CardinalKitHealthKitToFHIRAdapter"; + repositoryURL = "https://github.com/StanfordSpezi/SpeziContact.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 2FE5DC7029EDD8D3004B9AB4 /* XCRemoteSwiftPackageReference "SpeziHealthKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziHealthKit.git"; requirement = { kind = upToNextMinorVersion; - minimumVersion = 0.1.1; + minimumVersion = 0.5.0; }; }; - 2FABBC5729A8975900DF3BBC /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziFirebase.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 2FE5DC8829EDD972004B9AB4 /* XCRemoteSwiftPackageReference "SpeziStorage" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziStorage.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 2FE5DC8D29EDD980004B9AB4 /* XCRemoteSwiftPackageReference "SpeziViews" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziViews.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 10.5.0; + minimumVersion = 10.17.0; + }; + }; + 2FE5DC9729EDD9D9004B9AB4 /* XCRemoteSwiftPackageReference "XCTestExtensions" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordBDHG/XCTestExtensions.git"; + requirement = { + kind = upToNextMinorVersion; + minimumVersion = 0.4.7; + }; + }; + 2FE5DC9A29EDD9EF004B9AB4 /* XCRemoteSwiftPackageReference "XCTHealthKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordBDHG/XCTHealthKit.git"; + requirement = { + kind = upToNextMinorVersion; + minimumVersion = 0.3.5; + }; + }; + 2FE750CA2A87240100723EAE /* XCRemoteSwiftPackageReference "SpeziMockWebService" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziMockWebService.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5661551B2AB8384200209B80 /* XCRemoteSwiftPackageReference "swift-package-list" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/FelixHerrmann/swift-package-list"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.0.10; + }; + }; + 97F466E62A76BBEE005DC9B4 /* XCRemoteSwiftPackageReference "SpeziOnboarding" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziOnboarding"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 2F36AD26299D989F00B1077C /* XCTestExtensions */ = { + 2F3D4ABB2A4E7C290068FB2F /* SpeziScheduler */ = { isa = XCSwiftPackageProductDependency; - package = 2F36AD25299D989F00B1077C /* XCRemoteSwiftPackageReference "XCTestExtensions" */; - productName = XCTestExtensions; + package = 2F3D4ABA2A4E7C290068FB2F /* XCRemoteSwiftPackageReference "SpeziScheduler" */; + productName = SpeziScheduler; }; - 2F49B7752980407B00BCB272 /* CardinalKit */ = { + 2F49B7752980407B00BCB272 /* Spezi */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = CardinalKit; + package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "Spezi" */; + productName = Spezi; }; - 2F49B7772980407C00BCB272 /* FHIR */ = { + 2FB099AE2A875DF100B20952 /* FirebaseAuth */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = FHIR; + package = 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAuth; }; - 2F49B7792980407C00BCB272 /* HealthKitDataSource */ = { + 2FB099B02A875DF100B20952 /* FirebaseFirestore */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = HealthKitDataSource; + package = 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestore; }; - 2F49B77D2980407C00BCB272 /* Scheduler */ = { + 2FB099B22A875DF100B20952 /* FirebaseFirestoreSwift */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = Scheduler; + package = 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestoreSwift; }; - 2F49B77F2980418400BCB272 /* Onboarding */ = { + 2FB099B52A875E2B00B20952 /* HealthKitOnFHIR */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = Onboarding; + package = 2FB099B42A875E2B00B20952 /* XCRemoteSwiftPackageReference "HealthKitOnFHIR" */; + productName = HealthKitOnFHIR; }; - 2F49B7812980419C00BCB272 /* Questionnaires */ = { + 2FBD738B2A3BD150004228E7 /* SpeziScheduler */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = Questionnaires; + productName = SpeziScheduler; }; - 2F49B783298041F300BCB272 /* Contact */ = { + 2FCC1DCF2B6A2CF000C686BE /* SwiftLintPlugin */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = Contact; + package = 2FCC1DCE2B6A2CE000C686BE /* XCRemoteSwiftPackageReference "SwiftLint" */; + productName = "plugin:SwiftLintPlugin"; }; - 2F4E23802989C5930013F3D9 /* XCTHealthKit */ = { + 2FE5DC6329EDD883004B9AB4 /* SpeziAccount */ = { isa = XCSwiftPackageProductDependency; - package = 2F4E237F2989C5930013F3D9 /* XCRemoteSwiftPackageReference "XCTHealthKit" */; - productName = XCTHealthKit; + package = 2FE5DC6229EDD883004B9AB4 /* XCRemoteSwiftPackageReference "SpeziAccount" */; + productName = SpeziAccount; }; - 2F59B93C298C628800C5107F /* PAWSContacts */ = { + 2FE5DC6629EDD894004B9AB4 /* SpeziContact */ = { isa = XCSwiftPackageProductDependency; - productName = PAWSContacts; + package = 2FE5DC6529EDD894004B9AB4 /* XCRemoteSwiftPackageReference "SpeziContact" */; + productName = SpeziContact; }; - 2F59B93E298C628800C5107F /* PAWSMockDataStorageProvider */ = { + 2FE5DC7129EDD8D3004B9AB4 /* SpeziHealthKit */ = { isa = XCSwiftPackageProductDependency; - productName = PAWSMockDataStorageProvider; + package = 2FE5DC7029EDD8D3004B9AB4 /* XCRemoteSwiftPackageReference "SpeziHealthKit" */; + productName = SpeziHealthKit; }; - 2F59B940298C628800C5107F /* PAWSOnboardingFlow */ = { + 2FE5DC7429EDD8E6004B9AB4 /* SpeziFirebaseAccount */ = { isa = XCSwiftPackageProductDependency; - productName = PAWSOnboardingFlow; + package = 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */; + productName = SpeziFirebaseAccount; }; - 2F59B944298C628800C5107F /* PAWSSharedContext */ = { + 2FE5DC7629EDD8E6004B9AB4 /* SpeziFirebaseConfiguration */ = { isa = XCSwiftPackageProductDependency; - productName = PAWSSharedContext; + package = 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */; + productName = SpeziFirebaseConfiguration; }; - 2F9056D2299E1B9C003D3802 /* FHIRToFirestoreAdapter */ = { + 2FE5DC7829EDD8E6004B9AB4 /* SpeziFirestore */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = FHIRToFirestoreAdapter; + package = 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */; + productName = SpeziFirestore; }; - 2F9056D4299E1B9C003D3802 /* FirestoreDataStorage */ = { + 2FE5DC8029EDD91D004B9AB4 /* SpeziOnboarding */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = FirestoreDataStorage; + package = 97F466E62A76BBEE005DC9B4 /* XCRemoteSwiftPackageReference "SpeziOnboarding" */; + productName = SpeziOnboarding; }; - 2F9056D6299E1B9C003D3802 /* FirestoreStoragePrefixUserIdAdapter */ = { + 2FE5DC8929EDD972004B9AB4 /* SpeziLocalStorage */ = { isa = XCSwiftPackageProductDependency; - package = 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "CardinalKit" */; - productName = FirestoreStoragePrefixUserIdAdapter; + package = 2FE5DC8829EDD972004B9AB4 /* XCRemoteSwiftPackageReference "SpeziStorage" */; + productName = SpeziLocalStorage; }; - 2F9F4D8229B7FFAE00ABE259 /* CardinalKitHealthKitToFHIRAdapter */ = { + 2FE5DC8B29EDD972004B9AB4 /* SpeziSecureStorage */ = { isa = XCSwiftPackageProductDependency; - package = 2F9F4D8129B7FFAE00ABE259 /* XCRemoteSwiftPackageReference "CardinalKitHealthKitToFHIRAdapter" */; - productName = CardinalKitHealthKitToFHIRAdapter; + package = 2FE5DC8829EDD972004B9AB4 /* XCRemoteSwiftPackageReference "SpeziStorage" */; + productName = SpeziSecureStorage; }; - 2FABBC5829A8975900DF3BBC /* FirebaseFirestore */ = { + 2FE5DC8E29EDD980004B9AB4 /* SpeziViews */ = { isa = XCSwiftPackageProductDependency; - package = 2FABBC5729A8975900DF3BBC /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseFirestore; + package = 2FE5DC8D29EDD980004B9AB4 /* XCRemoteSwiftPackageReference "SpeziViews" */; + productName = SpeziViews; }; - 2FABBC5A29A8975900DF3BBC /* FirebaseFirestoreSwift */ = { + 2FE5DC9829EDD9D9004B9AB4 /* XCTestExtensions */ = { isa = XCSwiftPackageProductDependency; - package = 2FABBC5729A8975900DF3BBC /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseFirestoreSwift; + package = 2FE5DC9729EDD9D9004B9AB4 /* XCRemoteSwiftPackageReference "XCTestExtensions" */; + productName = XCTestExtensions; + }; + 2FE5DC9B29EDD9EF004B9AB4 /* XCTHealthKit */ = { + isa = XCSwiftPackageProductDependency; + package = 2FE5DC9A29EDD9EF004B9AB4 /* XCRemoteSwiftPackageReference "XCTHealthKit" */; + productName = XCTHealthKit; + }; + 2FF53D8A2A8725DE00042B76 /* SpeziMockWebService */ = { + isa = XCSwiftPackageProductDependency; + package = 2FE750CA2A87240100723EAE /* XCRemoteSwiftPackageReference "SpeziMockWebService" */; + productName = SpeziMockWebService; + }; + 5661551C2AB8384200209B80 /* SwiftPackageList */ = { + isa = XCSwiftPackageProductDependency; + package = 5661551B2AB8384200209B80 /* XCRemoteSwiftPackageReference "swift-package-list" */; + productName = SwiftPackageList; + }; + 566155212AB83CF200209B80 /* SwiftPackageListJSONPlugin */ = { + isa = XCSwiftPackageProductDependency; + package = 5661551B2AB8384200209B80 /* XCRemoteSwiftPackageReference "swift-package-list" */; + productName = "plugin:SwiftPackageListJSONPlugin"; + }; + 9739A0C52AD7B5730084BEA5 /* FirebaseStorage */ = { + isa = XCSwiftPackageProductDependency; + package = 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseStorage; }; - 3637947D2992F3B000B3C006 /* PAWSLandingScreen */ = { + 97D73D692AD860AD00B47FA0 /* SpeziFirebaseStorage */ = { isa = XCSwiftPackageProductDependency; - productName = PAWSLandingScreen; + package = 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */; + productName = SpeziFirebaseStorage; }; - 36379480299308AA00B3C006 /* PAWSNotificationScreen */ = { + A9D83F952B083794000D0C78 /* SpeziFirebaseAccountStorage */ = { isa = XCSwiftPackageProductDependency; - productName = PAWSNotificationScreen; + package = 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */; + productName = SpeziFirebaseAccountStorage; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/PAWS.xcodeproj/project.pbxproj.license b/PAWS.xcodeproj/project.pbxproj.license index 9137ea9d..4f324d88 100644 --- a/PAWS.xcodeproj/project.pbxproj.license +++ b/PAWS.xcodeproj/project.pbxproj.license @@ -1,5 +1,5 @@ -This source file is part of the CS342 2023 PAWS Team Application project +This source file is part of the PAWS application based on the Stanford Spezi Template Application project SPDX-FileCopyrightText: 2023 Stanford University diff --git a/PAWS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/PAWS.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/PAWS.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/PAWS.xcodeproj/project.xcworkspace/contents.xcworkspacedata.license b/PAWS.xcodeproj/project.xcworkspace/contents.xcworkspacedata.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS.xcodeproj/project.xcworkspace/contents.xcworkspacedata.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/PAWS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist.license b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..b21a4c1c --- /dev/null +++ b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,365 @@ +{ + "pins" : [ + { + "identity" : "abseil-cpp-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/abseil-cpp-binary.git", + "state" : { + "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c", + "version" : "1.2022062300.0" + } + }, + { + "identity" : "app-check", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/app-check.git", + "state" : { + "revision" : "5746b2d35c91c50581590ed97abe4c06b5037274", + "version" : "10.18.0" + } + }, + { + "identity" : "collectionconcurrencykit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git", + "state" : { + "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", + "version" : "0.2.0" + } + }, + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", + "state" : { + "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", + "version" : "1.8.1" + } + }, + { + "identity" : "fhirmodels", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/FHIRModels", + "state" : { + "revision" : "861afd5816a98d38f86220eab2f812d76cad84a0", + "version" : "0.5.0" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk.git", + "state" : { + "revision" : "c60c958e707c50a9cf8bcb7cfd7d51c566d726c5", + "version" : "10.19.1" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "6b332152355c372ace9966d8ee76ed191f97025e", + "version" : "10.17.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "a732a4b47f59e4f725a2ea10f0c77e93a7131117", + "version" : "9.3.0" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "bc27fad73504f3d4af235de451f02ee22586ebd3", + "version" : "7.12.1" + } + }, + { + "identity" : "grpc-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/grpc-binary.git", + "state" : { + "revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98", + "version" : "1.49.1" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "115f75e43851774934d695449a4836123c3246e1", + "version" : "3.2.0" + } + }, + { + "identity" : "healthkitonfhir", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordBDHG/HealthKitOnFHIR.git", + "state" : { + "revision" : "825e96007d83ed83f81ee49eb3ebab29d7b7ba2f", + "version" : "0.2.5" + } + }, + { + "identity" : "interop-ios-for-google-sdks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "state" : { + "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648", + "version" : "100.0.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "9d108e9112aa1d65ce508facf804674546116d9c", + "version" : "1.22.3" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692", + "version" : "2.30909.0" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e", + "version" : "2.3.1" + } + }, + { + "identity" : "sourcekitten", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/SourceKitten.git", + "state" : { + "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", + "version" : "0.34.1" + } + }, + { + "identity" : "spezi", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/Spezi", + "state" : { + "revision" : "c4bf0e99de40acfdd2baf0fa02769f06a4c3f0eb", + "version" : "1.1.0" + } + }, + { + "identity" : "speziaccount", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziAccount.git", + "state" : { + "revision" : "714f01ae1e67bf9c1c0e7c07624380f9bea772b7", + "version" : "1.1.0" + } + }, + { + "identity" : "spezicontact", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziContact.git", + "state" : { + "revision" : "494b776f8c98d771e4a609a1fb706097dba4c030", + "version" : "1.0.0" + } + }, + { + "identity" : "spezifirebase", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziFirebase.git", + "state" : { + "revision" : "ca1edf678ec59e76c9869ee3448e6e165d9c2789", + "version" : "1.0.0" + } + }, + { + "identity" : "spezifoundation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziFoundation.git", + "state" : { + "revision" : "683c66f922a4cfe0882c4a86a43854f613b48541", + "version" : "1.0.0" + } + }, + { + "identity" : "spezihealthkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziHealthKit.git", + "state" : { + "revision" : "d882734a4ed31fce1bffd7b9977e2669080f21de", + "version" : "0.5.0" + } + }, + { + "identity" : "spezimockwebservice", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziMockWebService.git", + "state" : { + "revision" : "b18067d3499e630bbd995ef05a296ef8fdd42528", + "version" : "1.0.0" + } + }, + { + "identity" : "spezionboarding", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziOnboarding", + "state" : { + "revision" : "ae7b18a18453557cd95c7adeb8f75846f48c343c", + "version" : "1.0.0" + } + }, + { + "identity" : "spezischeduler", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziScheduler.git", + "state" : { + "revision" : "adf793cb47dc199f8ae88f5c719f4d3ba06a4c4e", + "version" : "0.8.0" + } + }, + { + "identity" : "spezistorage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziStorage.git", + "state" : { + "revision" : "eaed2220375c35400aa69d1f96a8d32b7e66b1c7", + "version" : "1.0.0" + } + }, + { + "identity" : "speziviews", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziViews.git", + "state" : { + "revision" : "0137e69d156bf4001a8d6bf5661c9a37b2bbd0aa", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser", + "state" : { + "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", + "version" : "1.2.3" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "d029d9d39c87bed85b1c50adee7c41795261a192", + "version" : "1.0.6" + } + }, + { + "identity" : "swift-package-list", + "kind" : "remoteSourceControl", + "location" : "https://github.com/FelixHerrmann/swift-package-list", + "state" : { + "revision" : "412180a72b9a1f8262213c16459e3533b0385ea5", + "version" : "3.1.0" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8", + "version" : "1.25.2" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", + "version" : "509.0.2" + } + }, + { + "identity" : "swiftlint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/SwiftLint.git", + "state" : { + "revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee", + "version" : "0.54.0" + } + }, + { + "identity" : "swiftytexttable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/scottrhoyt/SwiftyTextTable.git", + "state" : { + "revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", + "version" : "0.9.0" + } + }, + { + "identity" : "swxmlhash", + "kind" : "remoteSourceControl", + "location" : "https://github.com/drmohundro/SWXMLHash.git", + "state" : { + "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", + "version" : "7.0.2" + } + }, + { + "identity" : "xctestextensions", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordBDHG/XCTestExtensions", + "state" : { + "revision" : "388a6d6a5be48eff5d98a2c45e0b50f30ed21dc3", + "version" : "0.4.7" + } + }, + { + "identity" : "xcthealthkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordBDHG/XCTHealthKit", + "state" : { + "revision" : "6e9344a2d632b801d94fe3bbd1d891817e032103", + "version" : "0.3.5" + } + }, + { + "identity" : "xctruntimeassertions", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordBDHG/XCTRuntimeAssertions", + "state" : { + "revision" : "bb2a287c2544aa846e53670d1ece35e5949567be", + "version" : "1.0.0" + } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3", + "version" : "5.0.6" + } + } + ], + "version" : 2 +} diff --git a/PAWS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved.license b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS.xcodeproj/xcshareddata/xcschemes/PAWS.xcscheme b/PAWS.xcodeproj/xcshareddata/xcschemes/PAWS.xcscheme index 81291d56..dc7a2bb2 100644 --- a/PAWS.xcodeproj/xcshareddata/xcschemes/PAWS.xcscheme +++ b/PAWS.xcodeproj/xcshareddata/xcschemes/PAWS.xcscheme @@ -1,95 +1,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + ) { + self._isPresented = isPresented + } +} + + +#if DEBUG +#Preview(traits: .sizeThatFitsLayout) { + AccountButton(isPresented: .constant(false)) +} +#endif diff --git a/PAWS/Account/AccountSetupHeader.swift b/PAWS/Account/AccountSetupHeader.swift new file mode 100644 index 00000000..08a10cf3 --- /dev/null +++ b/PAWS/Account/AccountSetupHeader.swift @@ -0,0 +1,43 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziAccount +import SwiftUI + + +struct AccountSetupHeader: View { + @Environment(Account.self) private var account + @Environment(\._accountSetupState) private var setupState + + + var body: some View { + VStack { + Text("ACCOUNT_TITLE") + .font(.largeTitle) + .bold() + .padding(.bottom) + .padding(.top, 30) + Text("ACCOUNT_SUBTITLE") + .padding(.bottom, 8) + if account.signedIn, case .generic = setupState { + Text("ACCOUNT_SIGNED_IN_DESCRIPTION") + } else { + Text("ACCOUNT_SETUP_DESCRIPTION") + } + } + .multilineTextAlignment(.center) + } +} + + +#if DEBUG +#Preview { + AccountSetupHeader() + .environment(Account()) +} +#endif diff --git a/PAWS/Account/AccountSheet.swift b/PAWS/Account/AccountSheet.swift new file mode 100644 index 00000000..b0691693 --- /dev/null +++ b/PAWS/Account/AccountSheet.swift @@ -0,0 +1,91 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziAccount +import SwiftUI + + +struct AccountSheet: View { + @Environment(\.dismiss) var dismiss + + @Environment(Account.self) private var account + @Environment(\.accountRequired) var accountRequired + + @State var isInSetup = false + @State var overviewIsEditing = false + + + var body: some View { + NavigationStack { + ZStack { + if account.signedIn && !isInSetup { + AccountOverview(isEditing: $overviewIsEditing) { + NavigationLink { + ContributionsList() + } label: { + Text("LICENSE_INFO_TITLE") + } + } + .onDisappear { + overviewIsEditing = false + } + .toolbar { + if !overviewIsEditing { + closeButton + } + } + } else { + AccountSetup { _ in + dismiss() // we just signed in, dismiss the account setup sheet + } header: { + AccountSetupHeader() + } + .onAppear { + isInSetup = true + } + .toolbar { + if !accountRequired { + closeButton + } + } + } + } + } + } + + var closeButton: some ToolbarContent { + ToolbarItem(placement: .cancellationAction) { + Button("CLOSE") { + dismiss() + } + } + } +} + + +#if DEBUG +#Preview("AccountSheet") { + let details = AccountDetails.Builder() + .set(\.userId, value: "lelandstanford@stanford.edu") + .set(\.name, value: PersonNameComponents(givenName: "Leland", familyName: "Stanford")) + + return AccountSheet() + .previewWith { + AccountConfiguration(building: details, active: MockUserIdPasswordAccountService()) + } +} + +#Preview("AccountSheet SignIn") { + AccountSheet() + .previewWith { + AccountConfiguration { + MockUserIdPasswordAccountService() + } + } +} +#endif diff --git a/PAWS/Contacts/Contacts.swift b/PAWS/Contacts/Contacts.swift new file mode 100644 index 00000000..00149bc5 --- /dev/null +++ b/PAWS/Contacts/Contacts.swift @@ -0,0 +1,107 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import Foundation +import SpeziContact +import SwiftUI + + +/// Displays the contacts for the PAWS. +struct Contacts: View { + let contacts = [ + Contact( + name: PersonNameComponents( + givenName: "Scott", + familyName: "Ceresnak" + ), + image: Image("ScottSquarePhoto"), // swiftlint:disable:this accessibility_label_for_image + title: "Professor of Pediatrics (Cardiology)", + description: String(localized: "SCOTT_CERESNAK_BIO"), + organization: "Stanford University", + address: { + let address = CNMutablePostalAddress() + address.country = "USA" + address.state = "CA" + address.postalCode = "94304" + address.city = "Palo Alto" + address.street = "725 Welch Rd" + return address + }(), + contactOptions: [ + .email(addresses: ["ceresnak@stanford.edu"]), + ContactOption( + image: Image(systemName: "safari.fill"), // swiftlint:disable:this accessibility_label_for_image + title: "Website", + action: { + if let url = URL(string: "https://profiles.stanford.edu/intranet/scott-ceresnak?tab=bio") { + UIApplication.shared.open(url) + } + } + ) + ] + ), + Contact( + name: PersonNameComponents( + givenName: "Aydin", + familyName: "Zahedivash" + ), + image: Image("AydinSquarePhoto"), // swiftlint:disable:this accessibility_label_for_image + title: "Pediatric Stanford Cardiology Fellow", + description: String(localized: "AYDIN_ZAHEDIVASH_BIO"), + organization: "Stanford University", + address: { + let address = CNMutablePostalAddress() + address.country = "USA" + address.state = "CA" + address.postalCode = "94304" + address.city = "Palo Alto" + address.street = "725 Welch Rd" + return address + }(), + contactOptions: [ + .email(addresses: ["aydinz@stanford.edu"]), + ContactOption( + image: Image(systemName: "safari.fill"), // swiftlint:disable:this accessibility_label_for_image + title: "Website", + action: { + if let url = URL(string: "https://profiles.stanford.edu/intranet/scott-ceresnak?tab=bio") { + UIApplication.shared.open(url) + } + } + ) + ] + ) + ] + + @Binding var presentingAccount: Bool + + + var body: some View { + NavigationStack { + ContactsList(contacts: contacts) + .navigationTitle(String(localized: "CONTACTS_NAVIGATION_TITLE")) + .toolbar { + if AccountButton.shouldDisplay { + AccountButton(isPresented: $presentingAccount) + } + } + } + } + + + init(presentingAccount: Binding) { + self._presentingAccount = presentingAccount + } +} + + +#if DEBUG +#Preview { + Contacts(presentingAccount: .constant(false)) +} +#endif diff --git a/PAWS/Contributions/ContributionsList.swift b/PAWS/Contributions/ContributionsList.swift new file mode 100644 index 00000000..409989bc --- /dev/null +++ b/PAWS/Contributions/ContributionsList.swift @@ -0,0 +1,53 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SwiftPackageList +import SwiftUI + + +struct ContributionsList: View { + var packages: [Package] = PackageHelper.getPackageList() + + var body: some View { + List { + Section(footer: Text("PROJECT_LICENSE_DESCRIPTION")) { + Text("CONTRIBUTIONS_LIST_DESCRIPTION") + } + Section( + header: Text("CONTRIBUTIONS_LIST_HEADER"), + footer: Text("CONTRIBUTIONS_LIST_FOOTER") + ) { + ForEach(packages.sorted(by: { $0.name < $1.name }), id: \.name) { package in + PackageCell(package: package) + } + } + } + .navigationTitle("LICENSE_INFO_TITLE") + .navigationBarTitleDisplayMode(.inline) + } +} + + +#if DEBUG +#Preview { + let mockPackages = [ + Package( + name: "MockPackage", + version: "1.0", + branch: nil, + revision: "0", + // We use a force unwrap in the preview as we can not recover from an error here + // and the code will never end up in a production environment. + // swiftlint:disable:next force_unwrapping + repositoryURL: URL(string: "github.com")!, + license: "MIT License" + ) + ] + return ContributionsList(packages: mockPackages) +} +#endif diff --git a/PAWS/Contributions/Package+LicenseType.swift b/PAWS/Contributions/Package+LicenseType.swift new file mode 100644 index 00000000..302dac67 --- /dev/null +++ b/PAWS/Contributions/Package+LicenseType.swift @@ -0,0 +1,104 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import Foundation +import SwiftPackageList + + +// This section of code is based on the SwiftPackageList package: +// - Original code: https://github.com/FelixHerrmann/swift-package-list/issues/43 +enum LicenseType { + case mit + case apachev2 + case gplv2 + case gplv3 + case bsd2 + case bsd3 + case bsd4 + case zlib + + /// SPDX-License-Identifier for the UI + var spdxIdentifier: String { + switch self { + case .mit: return "MIT" + case .apachev2: return "Apache-2.0" + case .gplv2: return "GPL-2.0" + case .gplv3: return "GPL-3.0" + case .bsd2: return "BSD-2-Clause" + case .bsd3: return "BSD-3-Clause" + case .bsd4: return "BSD-4-Clause" + case .zlib: return "Zlib" + } + } + + /// Initializer that scans the license document for common licenses and versions + init?(license: String) { + let license = license + .replacingOccurrences(of: "\\s+|\\n", with: " ", options: .regularExpression) + + if license.contains(mitText) { + self = .mit + } else if license.contains(apacheText) && license.contains("Version 2.0") { + self = .apachev2 + } else if license.contains(gnuText) && license.contains("Version 2") { + self = .gplv2 + } else if license.contains(gnuText) && license.contains("Version 3") { + self = .gplv3 + } else if license.contains(bsdFourClauseText) { + self = .bsd4 + } else if license.range(of: bsdThreeClausePattern, options: .regularExpression) != nil { + self = .bsd3 + } else if license.contains(bsdTwoClauseText) { + self = .bsd2 + } else if license.range(of: zlibPattern, options: .regularExpression) != nil { + self = .zlib + } else { + return nil + } + } +} + + +// Constants representing typical text and regular expression patterns often found in license files. +// They are used for matching and identifying different types of licenses within text documents. +private let mitText = "MIT License" +private let apacheText = "Apache License" +private let gnuText = "GNU GENERAL PUBLIC LICENSE" +private let bsdTwoClauseText = + """ + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met + """ +private let bsdThreeClausePattern = + """ + Neither the name of (.+) nor the names of (.+) may be used to endorse or promote products derived from this software \ + without specific prior written permission + """ +private let bsdFourClauseText = + """ + All advertising materials mentioning features or use of this software must display the following acknowledgement: \ + this product includes software developed by + """ +private let zlibPattern = + """ + The origin of this software must not be misrepresented; you must not claim that you wrote the original software. \ + If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.(.*) \ + Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.(.*) \ + This notice may not be removed or altered from any source distribution. + """ + + +extension Package { + /// Generates the `LicenseType` from a license document of `String` + func getLicenseType(license: String?) -> LicenseType? { + if let license = license { + let licenseType = LicenseType(license: license) + return licenseType + } + return nil + } +} diff --git a/PAWS/Contributions/PackageCell.swift b/PAWS/Contributions/PackageCell.swift new file mode 100644 index 00000000..da60b26f --- /dev/null +++ b/PAWS/Contributions/PackageCell.swift @@ -0,0 +1,73 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SwiftPackageList +import SwiftUI + + +struct PackageCell: View { + let package: Package + + var body: some View { + HStack { + VStack(alignment: .leading, spacing: 4) { + Text(package.name).font(.headline) + HStack { + Text(getPackageDetails(package: package)) + .font(.caption) + if let licenseType = package.getLicenseType(license: package.license) { + Text(licenseType.spdxIdentifier) + .font(.caption) + .fontWeight(.semibold) + .padding(2) + .background(Color(.systemGray5)) + .cornerRadius(4) + } + } + } + Spacer() + Button(action: { + UIApplication.shared.open(package.repositoryURL) + }) { + Image(systemName: "safari.fill") + .imageScale(.large) + }.buttonStyle(PlainButtonStyle()) + .foregroundColor(.blue) + .accessibilityLabel(Text("Repository Link")) + } + } + + func getPackageDetails(package: Package) -> String { + if let branch = package.branch { + return "Branch: \(branch)" + } else if let version = package.version { + return "Version: \(version)" + } else { + return "Revision: \(package.revision)" + } + } +} + + +#if DEBUG +#Preview(traits: .sizeThatFitsLayout) { + let mockPackage = Package( + name: "MockPackage", + version: "1.0", + branch: nil, + revision: "0", + // We use a force unwrap in the preview as we can not recover from an error here + // and the code will never end up in a production environment. + // swiftlint:disable:next force_unwrapping + repositoryURL: URL(string: "github.com")!, + license: "MIT License" + ) + + return PackageCell(package: mockPackage) +} +#endif diff --git a/PAWS/Contributions/PackageHelper.swift b/PAWS/Contributions/PackageHelper.swift new file mode 100644 index 00000000..6558a442 --- /dev/null +++ b/PAWS/Contributions/PackageHelper.swift @@ -0,0 +1,26 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import Foundation +import SwiftPackageList + + +enum PackageHelper { + /// Helper function that calls the corresponding API of `SwiftPackageList`to fetch the list of packages + static func getPackageList() -> [Package] { + do { + let packages = try packageList() + return packages + } catch PackageListError.noPackageList { + print("There is no package-list file") + } catch { + print(error) + } + return [] + } +} diff --git a/PAWS/ECGRecordings/ECGModule.swift b/PAWS/ECGRecordings/ECGModule.swift new file mode 100644 index 00000000..49b5e144 --- /dev/null +++ b/PAWS/ECGRecordings/ECGModule.swift @@ -0,0 +1,20 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import HealthKit +import Spezi + + +@Observable +class ECGModule: Module, DefaultInitializable, EnvironmentAccessible { + var hkElectrocardiograms: [HKElectrocardiogram] = [] + + + /// Creates an instance of a ``MockWebService``. + required init() { } +} diff --git a/PAWS/ECGRecordings/ECGRecording.swift b/PAWS/ECGRecordings/ECGRecording.swift new file mode 100644 index 00000000..b1156b86 --- /dev/null +++ b/PAWS/ECGRecordings/ECGRecording.swift @@ -0,0 +1,42 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import HealthKit +import SwiftUI + + +struct ECGRecording: View { + let hkElectrocardiogram: HKElectrocardiogram + @State var symptoms: HKElectrocardiogram.Symptoms = [:] + + + var body: some View { + PAWSCard { + HStack { + Text("EEG Recording") + .font(.title) + Text(hkElectrocardiogram.endDate.formatted()) + .font(.subheadline) + .foregroundStyle(.secondary) + Divider() + if symptoms.isEmpty { + Text("Recorded no symptoms") + } else { + Text("Recorded \(symptoms.count) symptoms.") + } + } + } + .task { + guard let symptoms = try? await hkElectrocardiogram.symptoms(from: HKHealthStore()) else { + return + } + + self.symptoms = symptoms + } + } +} diff --git a/PAWS/ECGRecordings/ECGRecordingsList.swift b/PAWS/ECGRecordings/ECGRecordingsList.swift new file mode 100644 index 00000000..491acf6a --- /dev/null +++ b/PAWS/ECGRecordings/ECGRecordingsList.swift @@ -0,0 +1,56 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SwiftUI + + +struct ECGRecordingsList: View { + @Environment(ECGModule.self) var ecgModule + @Binding var presentingAccount: Bool + + + var body: some View { + NavigationStack { + GeometryReader { geometry in + ScrollView { + if ecgModule.hkElectrocardiograms.isEmpty { + ContentUnavailableView { + Label("No Recordings", systemImage: "waveform.path.ecg") + } description: { + Text("New ECG Recordings will be displayed here.") + } + .frame(minHeight: geometry.size.height) + } + ForEach(ecgModule.hkElectrocardiograms) { hkElectrocardiogram in + ECGRecording(hkElectrocardiogram: hkElectrocardiogram) + } + } + .scrollBounceBehavior(.basedOnSize) + } + .toolbar { + if AccountButton.shouldDisplay { + AccountButton(isPresented: $presentingAccount) + } + } + .navigationTitle(String(localized: "ECG Recordings")) + } + } + + + init(presentingAccount: Binding) { + self._presentingAccount = presentingAccount + } +} + + +#Preview { + ECGRecordingsList(presentingAccount: .constant(false)) + .previewWith { + ECGModule() + } +} diff --git a/PAWSModules/Sources/PAWSSharedContext/Binding+Negate.swift b/PAWS/Helper/Binding+Negate.swift similarity index 63% rename from PAWSModules/Sources/PAWSSharedContext/Binding+Negate.swift rename to PAWS/Helper/Binding+Negate.swift index 484bad68..63e5dbd0 100644 --- a/PAWSModules/Sources/PAWSSharedContext/Binding+Negate.swift +++ b/PAWS/Helper/Binding+Negate.swift @@ -1,5 +1,5 @@ // -// This source file is part of the CS342 2023 PAWS Team Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // @@ -11,7 +11,7 @@ import SwiftUI extension Binding where Value == Bool { /// Negates a `Binding`. - public prefix static func ! (value: Binding) -> Binding { + prefix static func ! (value: Binding) -> Binding { Binding( get: { !value.wrappedValue }, set: { value.wrappedValue = !$0 } diff --git a/PAWSModules/Sources/PAWSSharedContext/Bundle+Image.swift b/PAWS/Helper/Bundle+Image.swift similarity index 82% rename from PAWSModules/Sources/PAWSSharedContext/Bundle+Image.swift rename to PAWS/Helper/Bundle+Image.swift index 431b155e..448cebc4 100644 --- a/PAWSModules/Sources/PAWSSharedContext/Bundle+Image.swift +++ b/PAWS/Helper/Bundle+Image.swift @@ -1,5 +1,5 @@ // -// This source file is part of the Stanford CardinalKit PAWS Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // @@ -15,7 +15,7 @@ extension Foundation.Bundle { /// - name: The name of the image. /// - fileExtension: The file extension of the image. /// - Returns: Returns the `UIImage` loaded from the `Bundle` instance. - public func image(withName name: String, fileExtension: String) -> UIImage { + func image(withName name: String, fileExtension: String) -> UIImage { guard let resourceURL = self.url(forResource: name, withExtension: fileExtension) else { fatalError("Could not find the file \"\(name).\(fileExtension)\" in the bundle.") } diff --git a/PAWSModules/Sources/PAWSSharedContext/CodableArray+RawRepresentable.swift b/PAWS/Helper/CodableArray+RawRepresentable.swift similarity index 85% rename from PAWSModules/Sources/PAWSSharedContext/CodableArray+RawRepresentable.swift rename to PAWS/Helper/CodableArray+RawRepresentable.swift index fd9fa003..154f19ca 100644 --- a/PAWSModules/Sources/PAWSSharedContext/CodableArray+RawRepresentable.swift +++ b/PAWS/Helper/CodableArray+RawRepresentable.swift @@ -1,5 +1,5 @@ // -// This source file is part of the CS342 2023 PAWS Team Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // diff --git a/PAWS/Helper/Date+RawRepresentable.swift b/PAWS/Helper/Date+RawRepresentable.swift new file mode 100644 index 00000000..761b54b2 --- /dev/null +++ b/PAWS/Helper/Date+RawRepresentable.swift @@ -0,0 +1,20 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +extension Date: RawRepresentable { + public var rawValue: String { + self.timeIntervalSinceReferenceDate.description + } + + public init?(rawValue: String) { + self = Date(timeIntervalSinceReferenceDate: Double(rawValue) ?? 0.0) + } +} diff --git a/PAWS/Home.swift b/PAWS/Home.swift new file mode 100644 index 00000000..954a5b4e --- /dev/null +++ b/PAWS/Home.swift @@ -0,0 +1,92 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziAccount +import SpeziMockWebService +import SwiftUI + + +struct HomeView: View { + enum Tabs: String { + case schedule + case contact + case studyInformation + case mockUpload + } + + static var accountEnabled: Bool { + !FeatureFlags.disableFirebase && !FeatureFlags.skipOnboarding + } + + + @AppStorage(StorageKeys.homeTabSelection) private var selectedTab = Tabs.schedule + @State private var presentingAccount = false + + + var body: some View { + TabView(selection: $selectedTab) { + ECGRecordingsList(presentingAccount: $presentingAccount) + .tag(Tabs.schedule) + .tabItem { + Label("ECG Recordings", systemImage: "waveform.path.ecg") + } + StudyInformation(presentingAccount: $presentingAccount) + .tag(Tabs.studyInformation) + .tabItem { + Label("Infos", systemImage: "i.circle") + } + Contacts(presentingAccount: $presentingAccount) + .tag(Tabs.contact) + .tabItem { + Label("Contacts", systemImage: "person.fill") + } + if FeatureFlags.disableFirebase { + MockUpload(presentingAccount: $presentingAccount) + .tag(Tabs.mockUpload) + .tabItem { + Label("Mock Web Service", systemImage: "server.rack") + } + } + } + .sheet(isPresented: $presentingAccount) { + AccountSheet() + } + .accountRequired(Self.accountEnabled) { + AccountSheet() + } + .verifyRequiredAccountDetails(Self.accountEnabled) + } +} + + +#if DEBUG +#Preview { + let details = AccountDetails.Builder() + .set(\.userId, value: "lelandstanford@stanford.edu") + .set(\.name, value: PersonNameComponents(givenName: "Leland", familyName: "Stanford")) + + return HomeView() + .previewWith(standard: PAWSStandard()) { + PAWSScheduler() + MockWebService() + AccountConfiguration(building: details, active: MockUserIdPasswordAccountService()) + } +} + +#Preview { + CommandLine.arguments.append("--disableFirebase") // make sure the MockWebService is displayed + return HomeView() + .previewWith(standard: PAWSStandard()) { + PAWSScheduler() + MockWebService() + AccountConfiguration { + MockUserIdPasswordAccountService() + } + } +} +#endif diff --git a/PAWS/MockUpload/MockUpload.swift b/PAWS/MockUpload/MockUpload.swift new file mode 100644 index 00000000..6ecad118 --- /dev/null +++ b/PAWS/MockUpload/MockUpload.swift @@ -0,0 +1,41 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziMockWebService +import SwiftUI + + +struct MockUpload: View { + @Binding var presentingAccount: Bool + + var body: some View { + NavigationStack { + RequestList() + .toolbar { + if AccountButton.shouldDisplay { + AccountButton(isPresented: $presentingAccount) + } + } + } + } + + + init(presentingAccount: Binding) { + self._presentingAccount = presentingAccount + } +} + + +#if DEBUG +#Preview { + MockUpload(presentingAccount: .constant(false)) + .previewWith { + MockWebService() + } +} +#endif diff --git a/PAWS/Onboarding/AccountOnboarding.swift b/PAWS/Onboarding/AccountOnboarding.swift new file mode 100644 index 00000000..eec7441d --- /dev/null +++ b/PAWS/Onboarding/AccountOnboarding.swift @@ -0,0 +1,64 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziAccount +import SpeziOnboarding +import SwiftUI + + +struct AccountOnboarding: View { + @Environment(Account.self) private var account + @Environment(OnboardingNavigationPath.self) private var onboardingNavigationPath + + + var body: some View { + AccountSetup { _ in + Task { + // Placing the nextStep() call inside this task will ensure that the sheet dismiss animation is + // played till the end before we navigate to the next step. + onboardingNavigationPath.nextStep() + } + } header: { + AccountSetupHeader() + } continue: { + OnboardingActionsView( + "ACCOUNT_NEXT", + action: { + onboardingNavigationPath.nextStep() + } + ) + } + } +} + + +#if DEBUG +#Preview("Account Onboarding SignIn") { + OnboardingStack { + AccountOnboarding() + } + .previewWith { + AccountConfiguration { + MockUserIdPasswordAccountService() + } + } +} + +#Preview("Account Onboarding") { + let details = AccountDetails.Builder() + .set(\.userId, value: "lelandstanford@stanford.edu") + .set(\.name, value: PersonNameComponents(givenName: "Leland", familyName: "Stanford")) + + return OnboardingStack { + AccountOnboarding() + } + .previewWith { + AccountConfiguration(building: details, active: MockUserIdPasswordAccountService()) + } +} +#endif diff --git a/PAWS/Onboarding/Consent.swift b/PAWS/Onboarding/Consent.swift new file mode 100644 index 00000000..2e7e7524 --- /dev/null +++ b/PAWS/Onboarding/Consent.swift @@ -0,0 +1,51 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziOnboarding +import SwiftUI + + +/// - Note: The `OnboardingConsentView` exports the signed consent form as PDF to the Spezi `Standard`, necessitating the conformance of the `Standard` to the `OnboardingConstraint`. +struct Consent: View { + @Environment(OnboardingNavigationPath.self) private var onboardingNavigationPath + @AppStorage(StorageKeys.healthKitStartDate) var healthKitStartDate: Date? + + + private var consentDocument: Data { + guard let path = Bundle.main.url(forResource: "ConsentDocument", withExtension: "md"), + let data = try? Data(contentsOf: path) else { + return Data(String(localized: "CONSENT_LOADING_ERROR").utf8) + } + return data + } + + + var body: some View { + OnboardingConsentView( + markdown: { + consentDocument + }, + action: { + healthKitStartDate = Date.now + onboardingNavigationPath.nextStep() + } + ) + } +} + + +#if DEBUG +#Preview { + OnboardingStack { + Consent() + } + .previewWith(standard: PAWSStandard()) { + OnboardingDataSource() + } +} +#endif diff --git a/PAWS/Onboarding/HealthKitPermissions.swift b/PAWS/Onboarding/HealthKitPermissions.swift new file mode 100644 index 00000000..94212932 --- /dev/null +++ b/PAWS/Onboarding/HealthKitPermissions.swift @@ -0,0 +1,77 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziHealthKit +import SpeziOnboarding +import SwiftUI + + +struct HealthKitPermissions: View { + @Environment(HealthKit.self) private var healthKitDataSource + @Environment(OnboardingNavigationPath.self) private var onboardingNavigationPath + + @State private var healthKitProcessing = false + + + var body: some View { + OnboardingView( + contentView: { + VStack { + OnboardingTitleView( + title: "HEALTHKIT_PERMISSIONS_TITLE", + subtitle: "HEALTHKIT_PERMISSIONS_SUBTITLE" + ) + Spacer() + Image(systemName: "heart.text.square.fill") + .font(.system(size: 150)) + .foregroundColor(.accentColor) + .accessibilityHidden(true) + Text("HEALTHKIT_PERMISSIONS_DESCRIPTION") + .multilineTextAlignment(.center) + .padding(.vertical, 16) + Spacer() + } + }, actionView: { + OnboardingActionsView( + "HEALTHKIT_PERMISSIONS_BUTTON", + action: { + do { + healthKitProcessing = true + // HealthKit is not available in the preview simulator. + if ProcessInfo.processInfo.isPreviewSimulator { + try await _Concurrency.Task.sleep(for: .seconds(5)) + } else { + try await healthKitDataSource.askForAuthorization() + } + } catch { + print("Could not request HealthKit permissions.") + } + healthKitProcessing = false + + onboardingNavigationPath.nextStep() + } + ) + } + ) + .navigationBarBackButtonHidden(healthKitProcessing) + // Small fix as otherwise "Login" or "Sign up" is still shown in the nav bar + .navigationTitle(Text(verbatim: "")) + } +} + + +#if DEBUG +#Preview { + OnboardingStack { + HealthKitPermissions() + } + .previewWith(standard: PAWSStandard()) { + HealthKit() + } +} +#endif diff --git a/PAWS/Onboarding/InterestingModules.swift b/PAWS/Onboarding/InterestingModules.swift new file mode 100644 index 00000000..08d5d703 --- /dev/null +++ b/PAWS/Onboarding/InterestingModules.swift @@ -0,0 +1,50 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziOnboarding +import SwiftUI + + +struct InterestingModules: View { + @Environment(OnboardingNavigationPath.self) private var onboardingNavigationPath + + + var body: some View { + SequentialOnboardingView( + title: "INTERESTING_MODULES_TITLE", + subtitle: "INTERESTING_MODULES_SUBTITLE", + content: [ + SequentialOnboardingView.Content( + title: "INTERESTING_MODULES_AREA1_TITLE", + description: "INTERESTING_MODULES_AREA1_DESCRIPTION" + ), + SequentialOnboardingView.Content( + title: "INTERESTING_MODULES_AREA2_TITLE", + description: "INTERESTING_MODULES_AREA2_DESCRIPTION" + ), + SequentialOnboardingView.Content( + title: "INTERESTING_MODULES_AREA3_TITLE", + description: "INTERESTING_MODULES_AREA3_DESCRIPTION" + ) + ], + actionText: "INTERESTING_MODULES_BUTTON", + action: { + onboardingNavigationPath.nextStep() + } + ) + } +} + + +#if DEBUG +#Preview { + OnboardingStack { + InterestingModules() + } +} +#endif diff --git a/PAWS/Onboarding/NotificationPermissions.swift b/PAWS/Onboarding/NotificationPermissions.swift new file mode 100644 index 00000000..bc9d4e5d --- /dev/null +++ b/PAWS/Onboarding/NotificationPermissions.swift @@ -0,0 +1,87 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziOnboarding +import SpeziScheduler +import SwiftUI + + +struct NotificationPermissions: View { + @Environment(PAWSScheduler.self) private var scheduler + @Environment(OnboardingNavigationPath.self) private var onboardingNavigationPath + + @State private var notificationProcessing = false + @State private var selectedTime = Calendar.current.date(bySettingHour: 19, minute: 0, second: 0, of: .now) ?? .now + + + var body: some View { + OnboardingView( + contentView: { + VStack { + Image(systemName: "pawprint.circle.fill") + .resizable() + .scaledToFill() + .frame(width: 40, height: 40) + .foregroundStyle(Color.accentColor) + .offset(y: 20) + .accessibilityHidden(true) + OnboardingTitleView( + title: "NOTIFICATIONS_TITLE", + subtitle: "NOTIFICATIONS_SUBTITLE" + ) + DatePicker("Select a time", selection: $selectedTime, displayedComponents: .hourAndMinute) + Image("NotificationImage") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 275, height: 275) + .padding(.vertical) + .accessibilityHidden(true) + } + }, actionView: { + OnboardingActionsView( + "NOTIFICATION_PERMISSIONS_BUTTON", + action: { + do { + notificationProcessing = true + + let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: selectedTime) + try await scheduler.scheduleReminders(time: dateComponents) + + // Notification Authorization is not available in the preview simulator. + if ProcessInfo.processInfo.isPreviewSimulator { + try await _Concurrency.Task.sleep(for: .seconds(5)) + } else { + try await scheduler.requestLocalNotificationAuthorization() + } + } catch { + print("Could not request notification permissions.") + } + notificationProcessing = false + + onboardingNavigationPath.nextStep() + } + ) + } + ) + .navigationBarBackButtonHidden(notificationProcessing) + // Small fix as otherwise "Login" or "Sign up" is still shown in the nav bar + .navigationTitle(Text(verbatim: "")) + } +} + + +#if DEBUG +#Preview { + OnboardingStack { + NotificationPermissions() + } + .previewWith { + PAWSScheduler() + } +} +#endif diff --git a/PAWS/Onboarding/OnboardingFlow.swift b/PAWS/Onboarding/OnboardingFlow.swift new file mode 100644 index 00000000..e0221f0e --- /dev/null +++ b/PAWS/Onboarding/OnboardingFlow.swift @@ -0,0 +1,79 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziAccount +import SpeziFirebaseAccount +import SpeziHealthKit +import SpeziOnboarding +import SwiftUI + + +/// Displays an multi-step onboarding flow for the PAWS. +struct OnboardingFlow: View { + @Environment(HealthKit.self) private var healthKitDataSource + @Environment(PAWSScheduler.self) private var scheduler + + @AppStorage(StorageKeys.onboardingFlowComplete) private var completedOnboardingFlow = false + + @State private var localNotificationAuthorization = false + + + private var healthKitAuthorization: Bool { + // As HealthKit not available in preview simulator + if ProcessInfo.processInfo.isPreviewSimulator { + return false + } + + return healthKitDataSource.authorized + } + + + var body: some View { + OnboardingStack(onboardingFlowComplete: $completedOnboardingFlow) { + Welcome() + InterestingModules() + + if !FeatureFlags.disableFirebase { + AccountOnboarding() + } + + #if !(targetEnvironment(simulator) && (arch(i386) || arch(x86_64))) + Consent() + #endif + + if HKHealthStore.isHealthDataAvailable() && !healthKitAuthorization { + HealthKitPermissions() + } + + if !localNotificationAuthorization { + NotificationPermissions() + } + } + .task { + localNotificationAuthorization = await scheduler.localNotificationAuthorization + } + .interactiveDismissDisabled(!completedOnboardingFlow) + } +} + + +#if DEBUG +#Preview { + OnboardingFlow() + .environment(Account(MockUserIdPasswordAccountService())) + .previewWith(standard: PAWSStandard()) { + OnboardingDataSource() + HealthKit() + AccountConfiguration { + MockUserIdPasswordAccountService() + } + + PAWSScheduler() + } +} +#endif diff --git a/PAWS/Onboarding/Welcome.swift b/PAWS/Onboarding/Welcome.swift new file mode 100644 index 00000000..1d410725 --- /dev/null +++ b/PAWS/Onboarding/Welcome.swift @@ -0,0 +1,63 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziOnboarding +import SwiftUI + + +struct Welcome: View { + @Environment(OnboardingNavigationPath.self) private var onboardingNavigationPath + + + var body: some View { + OnboardingView( + title: "WELCOME_TITLE", + subtitle: "WELCOME_SUBTITLE", + areas: [ + OnboardingInformationView.Content( + icon: { + Image(systemName: "apps.iphone") + .accessibilityHidden(true) + }, + title: "WELCOME_AREA1_TITLE", + description: "WELCOME_AREA1_DESCRIPTION" + ), + OnboardingInformationView.Content( + icon: { + Image(systemName: "shippingbox.fill") + .accessibilityHidden(true) + }, + title: "WELCOME_AREA2_TITLE", + description: "WELCOME_AREA2_DESCRIPTION" + ), + OnboardingInformationView.Content( + icon: { + Image(systemName: "list.bullet.clipboard.fill") + .accessibilityHidden(true) + }, + title: "WELCOME_AREA3_TITLE", + description: "WELCOME_AREA3_DESCRIPTION" + ) + ], + actionText: "WELCOME_BUTTON", + action: { + onboardingNavigationPath.nextStep() + } + ) + .padding(.top, 24) + } +} + + +#if DEBUG +#Preview { + OnboardingStack { + Welcome() + } +} +#endif diff --git a/PAWS/PAWS.swift b/PAWS/PAWS.swift index 706b2a19..4c26c317 100644 --- a/PAWS/PAWS.swift +++ b/PAWS/PAWS.swift @@ -1,48 +1,36 @@ // -// This source file is part of the CS342 2023 PAWS Team Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // // SPDX-License-Identifier: MIT // -import CardinalKit -import PAWSLandingScreen -import PAWSMockDataStorageProvider -import PAWSOnboardingFlow -import PAWSSharedContext +import Spezi +import SpeziFirebaseAccount import SwiftUI + @main struct PAWS: App { - @UIApplicationDelegateAdaptor(PAWSAppDelegate.self) var appDelegate + @UIApplicationDelegateAdaptor(PAWSDelegate.self) var appDelegate @AppStorage(StorageKeys.onboardingFlowComplete) var completedOnboardingFlow = false - @State var pressedStart = false - - var isSheetPresented: Binding { - Binding( - get: { - !completedOnboardingFlow && pressedStart - }, set: { _ in } - ) - } var body: some Scene { WindowGroup { - Group { + ZStack { if completedOnboardingFlow { HomeView() } else { - LandingScreen(pressedStart: $pressedStart) + EmptyView() } } - .sheet(isPresented: isSheetPresented) { + .sheet(isPresented: !$completedOnboardingFlow) { OnboardingFlow() - .interactiveDismissDisabled(true) } .testingSetup() - .cardinalKit(appDelegate) + .spezi(appDelegate) } } } diff --git a/PAWS/PAWSAppDelegate.swift b/PAWS/PAWSAppDelegate.swift deleted file mode 100644 index b0ea2a2e..00000000 --- a/PAWS/PAWSAppDelegate.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import CardinalKit -import FHIR -import FHIRToFirestoreAdapter -import FirebaseAccount -import class FirebaseFirestore.FirestoreSettings -import CardinalKitHealthKitToFHIRAdapter -import FirestoreDataStorage -import FirestoreStoragePrefixUserIdAdapter -import HealthKit -import HealthKitDataSource -import PAWSMockDataStorageProvider -import PAWSSharedContext -import Questionnaires -import Scheduler -import SwiftUI - - -class PAWSAppDelegate: CardinalKitAppDelegate { - override var configuration: Configuration { - Configuration(standard: FHIR()) { - if !FeatureFlags.disableFirebase { - if FeatureFlags.useFirebaseEmulator { - FirebaseAccountConfiguration(emulatorSettings: (host: "localhost", port: 9099)) - } else { - FirebaseAccountConfiguration() - } - firestore - } - if HKHealthStore.isHealthDataAvailable() { - healthKit - } - QuestionnaireDataSource() - MockDataStorageProvider() - } - } - - - private var firestore: Firestore { - let settings = FirestoreSettings() - if FeatureFlags.useFirebaseEmulator { - settings.host = "localhost:8080" - settings.isPersistenceEnabled = false - settings.isSSLEnabled = false - } - - return Firestore( - adapter: { - FHIRToFirestoreAdapter() - FirestoreStoragePrefixUserIdAdapter() - }, - settings: settings - ) - } - - - private var healthKit: HealthKit { - HealthKit { - CollectSample( - HKQuantityType.electrocardiogramType(), - deliverySetting: .background(.afterAuthorizationAndApplicationWillLaunch) - ) - CollectSamples(Set(HKElectrocardiogram.correlatedSymptomTypes)) - } adapter: { - HealthKitToFHIRAdapter() - } - } -} diff --git a/PAWS/PAWSDelegate.swift b/PAWS/PAWSDelegate.swift new file mode 100644 index 00000000..7966a1b9 --- /dev/null +++ b/PAWS/PAWSDelegate.swift @@ -0,0 +1,97 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import Spezi +import SpeziAccount +import SpeziFirebaseAccount +import SpeziFirebaseStorage +import SpeziFirestore +import SpeziHealthKit +import SpeziMockWebService +import SpeziOnboarding +import SpeziScheduler +import SwiftUI + + +class PAWSDelegate: SpeziAppDelegate { + override var configuration: Configuration { + Configuration(standard: PAWSStandard()) { + if !FeatureFlags.disableFirebase { + AccountConfiguration(configuration: [ + .requires(\.userId), + .requires(\.name), + .requires(\.dateOfBirth), + .collects(\.genderIdentity) + ]) + + if FeatureFlags.useFirebaseEmulator { + FirebaseAccountConfiguration( + authenticationMethods: [.emailAndPassword, .signInWithApple], + emulatorSettings: (host: "localhost", port: 9099) + ) + } else { + FirebaseAccountConfiguration(authenticationMethods: [.emailAndPassword, .signInWithApple]) + } + firestore + if FeatureFlags.useFirebaseEmulator { + FirebaseStorageConfiguration(emulatorSettings: (host: "localhost", port: 9199)) + } else { + FirebaseStorageConfiguration() + } + } else { + MockWebService() + } + + if HKHealthStore.isHealthDataAvailable() { + healthKit + } + + PAWSScheduler() + OnboardingDataSource() + } + } + + + private var firestore: Firestore { + let settings = FirestoreSettings() + if FeatureFlags.useFirebaseEmulator { + settings.host = "localhost:8080" + settings.cacheSettings = MemoryCacheSettings() + settings.isSSLEnabled = false + } + + return Firestore( + settings: settings + ) + } + + + private var healthKit: HealthKit { + @AppStorage(StorageKeys.healthKitStartDate) var healthKitStartDate: Date = .now + + // Collection starts at the time the user consents and lasts for 1 month. + let sharedPredicate = HKQuery.predicateForSamples( + withStart: healthKitStartDate, + end: Calendar.current.date(byAdding: DateComponents(month: 1), to: healthKitStartDate), + options: .strictEndDate + ) + + return HealthKit { + CollectSample( + HKQuantityType.electrocardiogramType(), + predicate: sharedPredicate, + deliverySetting: .background(saveAnchor: false) + ) + CollectSamples( + Set(HKElectrocardiogram.correlatedSymptomTypes), + predicate: sharedPredicate, + deliverySetting: .background(saveAnchor: false) + ) + } + } +} diff --git a/PAWS/PAWSStandard.swift b/PAWS/PAWSStandard.swift new file mode 100644 index 00000000..51a5c347 --- /dev/null +++ b/PAWS/PAWSStandard.swift @@ -0,0 +1,190 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import FirebaseFirestore +import FirebaseStorage +import HealthKitOnFHIR +import OSLog +import PDFKit +import Spezi +import SpeziAccount +import SpeziFirebaseAccountStorage +import SpeziFirestore +import SpeziHealthKit +import SpeziMockWebService +import SpeziOnboarding +import SwiftUI + + +actor PAWSStandard: Standard, EnvironmentAccessible, HealthKitConstraint, OnboardingConstraint, AccountStorageConstraint { + enum PAWSStandardError: Error { + case userNotAuthenticatedYet + } + + private static var userCollection: CollectionReference { + Firestore.firestore().collection("users") + } + + @Dependency var mockWebService: MockWebService? + @Dependency var accountStorage: FirestoreAccountStorage? + @Dependency var ecgStorage: ECGModule + + @AccountReference var account: Account + + private let logger = Logger(subsystem: "PAWS", category: "Standard") + + + private var userDocumentReference: DocumentReference { + get async throws { + guard let details = await account.details else { + throw PAWSStandardError.userNotAuthenticatedYet + } + + return Self.userCollection.document(details.accountId) + } + } + + private var userBucketReference: StorageReference { + get async throws { + guard let details = await account.details else { + throw PAWSStandardError.userNotAuthenticatedYet + } + + return Storage.storage().reference().child("users/\(details.accountId)") + } + } + + + init() { + if !FeatureFlags.disableFirebase { + _accountStorage = Dependency(wrappedValue: FirestoreAccountStorage(storeIn: PAWSStandard.userCollection)) + } + } + + + func add(sample: HKSample) async { + if let hkElectrocardiogram = sample as? HKElectrocardiogram { + ecgStorage.hkElectrocardiograms.append(hkElectrocardiogram) + } + + if let mockWebService { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + let jsonRepresentation = (try? String(data: encoder.encode(sample.resource), encoding: .utf8)) ?? "" + try? await mockWebService.upload(path: "healthkit/\(sample.uuid.uuidString)", body: jsonRepresentation) + return + } + + do { + try await healthKitDocument(id: sample.id).setData(from: sample.resource) + } catch { + logger.error("Could not store HealthKit sample: \(error)") + } + } + + func remove(sample: HKDeletedObject) async { + ecgStorage.hkElectrocardiograms.removeAll(where: { $0.id == sample.uuid }) + + if let mockWebService { + try? await mockWebService.remove(path: "healthkit/\(sample.uuid.uuidString)") + return + } + + do { + try await healthKitDocument(id: sample.uuid).delete() + } catch { + logger.error("Could not remove HealthKit sample: \(error)") + } + } + + + private func healthKitDocument(id uuid: UUID) async throws -> DocumentReference { + try await userDocumentReference + .collection("HealthKit") // Add all HealthKit sources in a /HealthKit collection. + .document(uuid.uuidString) // Set the document identifier to the UUID of the document. + } + + func deletedAccount() async throws { + // delete all user associated data + do { + try await userDocumentReference.delete() + } catch { + logger.error("Could not delete user document: \(error)") + } + } + + /// Stores the given consent form in the user's document directory with a unique timestamped filename. + /// + /// - Parameter consent: The consent form's data to be stored as a `PDFDocument`. + func store(consent: PDFDocument) async { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd_HHmmss" + let dateString = formatter.string(from: Date()) + + guard !FeatureFlags.disableFirebase else { + guard let basePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { + logger.error("Could not create path for writing consent form to user document directory.") + return + } + + let filePath = basePath.appending(path: "consentForm_\(dateString).pdf") + consent.write(to: filePath) + + return + } + + do { + guard let consentData = consent.dataRepresentation() else { + logger.error("Could not store consent form.") + return + } + + let metadata = StorageMetadata() + metadata.contentType = "application/pdf" + _ = try await userBucketReference.child("consent/\(dateString).pdf").putDataAsync(consentData, metadata: metadata) + } catch { + logger.error("Could not store consent form: \(error)") + } + } + + + func create(_ identifier: AdditionalRecordId, _ details: SignupDetails) async throws { + guard let accountStorage else { + preconditionFailure("Account Storage was requested although not enabled in current configuration.") + } + try await accountStorage.create(identifier, details) + } + + func load(_ identifier: AdditionalRecordId, _ keys: [any AccountKey.Type]) async throws -> PartialAccountDetails { + guard let accountStorage else { + preconditionFailure("Account Storage was requested although not enabled in current configuration.") + } + return try await accountStorage.load(identifier, keys) + } + + func modify(_ identifier: AdditionalRecordId, _ modifications: AccountModifications) async throws { + guard let accountStorage else { + preconditionFailure("Account Storage was requested although not enabled in current configuration.") + } + try await accountStorage.modify(identifier, modifications) + } + + func clear(_ identifier: AdditionalRecordId) async { + guard let accountStorage else { + preconditionFailure("Account Storage was requested although not enabled in current configuration.") + } + await accountStorage.clear(identifier) + } + + func delete(_ identifier: AdditionalRecordId) async throws { + guard let accountStorage else { + preconditionFailure("Account Storage was requested although not enabled in current configuration.") + } + try await accountStorage.delete(identifier) + } +} diff --git a/PAWS/PAWSAppTestingSetup.swift b/PAWS/PAWSTestingSetup.swift similarity index 75% rename from PAWS/PAWSAppTestingSetup.swift rename to PAWS/PAWSTestingSetup.swift index 43df0098..4495236f 100644 --- a/PAWS/PAWSAppTestingSetup.swift +++ b/PAWS/PAWSTestingSetup.swift @@ -1,16 +1,15 @@ // -// This source file is part of the CS342 2023 PAWS Team Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // // SPDX-License-Identifier: MIT // -import PAWSSharedContext import SwiftUI -private struct PAWSTestingSetup: ViewModifier { +private struct PAWSAppTestingSetup: ViewModifier { @AppStorage(StorageKeys.onboardingFlowComplete) var completedOnboardingFlow = false @@ -30,6 +29,6 @@ private struct PAWSTestingSetup: ViewModifier { extension View { func testingSetup() -> some View { - self.modifier(PAWSTestingSetup()) + self.modifier(PAWSAppTestingSetup()) } } diff --git a/PAWS/Reminders/PAWSScheduler.swift b/PAWS/Reminders/PAWSScheduler.swift new file mode 100644 index 00000000..aaa8bc97 --- /dev/null +++ b/PAWS/Reminders/PAWSScheduler.swift @@ -0,0 +1,37 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import Foundation +import SpeziScheduler + + +/// A `Scheduler` using the ``PAWSTaskContext`` to schedule and manage tasks and events in the +/// PAWS. +typealias PAWSScheduler = Scheduler + + +extension PAWSScheduler { + func scheduleReminders(time: DateComponents) async throws { + // We discard all other date components: + let dateComponents = DateComponents(hour: time.hour, minute: time.minute) + + await schedule( + task: Task( + title: String(localized: "Friendly reminder to record your ECG!"), + description: String(localized: "Thank you for participating in the PAWS study!"), + schedule: Schedule( + start: Calendar.current.startOfDay(for: .now), + repetition: .matching(dateComponents), + end: .numberOfEvents(7) + ), + notifications: true, + context: PAWSTaskContext.reminder + ) + ) + } +} diff --git a/PAWS/Reminders/PAWSTaskContext.swift b/PAWS/Reminders/PAWSTaskContext.swift new file mode 100644 index 00000000..b92560bf --- /dev/null +++ b/PAWS/Reminders/PAWSTaskContext.swift @@ -0,0 +1,16 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +/// The context attached to each task in the PAWS app. +enum PAWSTaskContext: Codable { + /// Reminder Notificaiton to do a ECG recording + case reminder +} diff --git a/PAWS/Resources/Assets.xcassets/AccentColor.colorset/Contents.json b/PAWS/Resources/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..63ed2ec7 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.349", + "green" : "0.330", + "red" : "0.850" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PAWS/Resources/Assets.xcassets/AccentColor.colorset/Contents.json.license b/PAWS/Resources/Assets.xcassets/AccentColor.colorset/Contents.json.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/AccentColor.colorset/Contents.json.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json b/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json rename to PAWS/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json.license b/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/paws-logo.png b/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/paws-logo.png similarity index 100% rename from PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/paws-logo.png rename to PAWS/Resources/Assets.xcassets/AppIcon.appiconset/paws-logo.png diff --git a/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/paws-logo.png.license b/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/paws-logo.png.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/AppIcon.appiconset/paws-logo.png.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png b/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png similarity index 100% rename from PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png rename to PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png diff --git a/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png.license b/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json b/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json similarity index 65% rename from PAWS/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json rename to PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json index eb878970..20ccc4dc 100644 --- a/PAWS/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json @@ -1,6 +1,7 @@ { - "colors" : [ + "images" : [ { + "filename" : "AydinSquarePhoto.png", "idiom" : "universal" } ], diff --git a/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json.license b/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/Contents.json b/PAWS/Resources/Assets.xcassets/Contents.json similarity index 100% rename from PAWS/Supporting Files/Assets.xcassets/Contents.json rename to PAWS/Resources/Assets.xcassets/Contents.json diff --git a/PAWS/Resources/Assets.xcassets/Contents.json.license b/PAWS/Resources/Assets.xcassets/Contents.json.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/Contents.json.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/Contents.json b/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/Contents.json new file mode 100644 index 00000000..2bd22f78 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "NotificationImage.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/Contents.json.license b/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/Contents.json.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/Contents.json.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/NotificationImage.png b/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/NotificationImage.png similarity index 100% rename from PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/NotificationImage.png rename to PAWS/Resources/Assets.xcassets/NotificationImage.imageset/NotificationImage.png diff --git a/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/NotificationImage.png.license b/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/NotificationImage.png.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/NotificationImage.imageset/NotificationImage.png.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json b/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json new file mode 100644 index 00000000..553b2510 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "ScottSquarePhoto.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json.license b/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png b/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png similarity index 100% rename from PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png rename to PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png diff --git a/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png.license b/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/ConsentDocument.md b/PAWS/Resources/ConsentDocument.md similarity index 100% rename from PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/ConsentDocument.md rename to PAWS/Resources/ConsentDocument.md diff --git a/PAWS/Resources/ConsentDocument.md.license b/PAWS/Resources/ConsentDocument.md.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/ConsentDocument.md.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Resources/Localizable.xcstrings b/PAWS/Resources/Localizable.xcstrings new file mode 100644 index 00000000..3a13a556 --- /dev/null +++ b/PAWS/Resources/Localizable.xcstrings @@ -0,0 +1,719 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "ACCOUNT_NEXT" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Next" + } + } + } + }, + "ACCOUNT_SETUP_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You may login to your existing account. Or create a new one if you don't have one already." + } + } + } + }, + "ACCOUNT_SIGNED_IN_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You are successfully signed in with the following account:" + } + } + } + }, + "ACCOUNT_SUBTITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign up for a new account or sign in to an existing account" + } + } + } + }, + "ACCOUNT_TITLE" : { + "comment" : "MARK: Account", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your PAWS Account" + } + } + } + }, + "ANSWER_1" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Don’t be concerned, simply start another ECG recording on the Apple Watch as soon as you can." + } + } + } + }, + "ANSWER_2" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The PAWS app will store your ECG file directly on your iPhone and upload it to the research database when you have access to the internet again." + } + } + } + }, + "ANSWER_3" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The research team will review your Apple Watch ECG data periodically but will not use it in place of traditional diagnostic methods to change the course of your care plan." + } + } + } + }, + "ANSWER_4" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you are experiencing symptoms that require immediate attention, please call 9-1-1. Neither the PAWS app nor the Apple Watch will call the emergency services for you." + } + } + } + }, + "ANSWER_5" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You will not get sick or hurt because of anything in this study. We will be studying your health information and all of your information will be kept secure." + } + } + } + }, + "ANSWER_6" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing good will directly happen to you but, by participating in this study, you will help us understand if the Apple Watch can be used to monitor heart problems in other kids. We hope that someday we can just give an Apple Watch to kids needing to have their heart tested." + } + } + } + }, + "ANSWER_7" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Only the researchers in charge of the study will know that you are in it. No one else will know, and your information will be kept secure." + } + } + } + }, + "ANSWER_8" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you have any questions about the study or any problems to do with the study you can contact the Protocol Director Dr. Scott Ceresnak. You can call him at (650)-723-7913.\n\nIf you have questions about the study but want to talk to someone else who is not a part of the study, you can call the Stanford Institutional Review Board (IRB) at (650)-723-5244 or toll free at 1-866-680-2906." + } + } + } + }, + "ANSWER_9" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you do not want to participate in the study, just tell the researchers or your parents. You don’t need to be a part of the study and you won’t get in trouble if you decide if you don’t want to. Your doctor will still treat you the same even if you don’t participate." + } + } + } + }, + "AYDIN_ZAHEDIVASH_BIO" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dr. Zahedivash is a resident physician in the Stanford Department of Pediatrics and will serve as a chief resident during the 2023-2024 academic year. His academic interests focus on the development and translation of innovative technologies and services to address diagnostic and health equity challenges. During his educational career as an engineer and budding physician, he has co-invented a series of computational techniques and devices. Previous inventions include diagnostic deep-learning algorithms to detect unstable coronary artery plaque on intravascular imaging and a surgical probe for intraoperative margin detection during cancer resection. He is passionate about using his medical, technical, and business backgrounds to develop digital health solutions and equitable technology translation strategies for children." + } + } + } + }, + "CLOSE" : { + "comment" : "MARK: General", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close" + } + } + } + }, + "CONSENT_LOADING_ERROR" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please include a markdown based document named \"ConsentDocument\" in your module Bundle." + } + } + } + }, + "Contacts" : { + + }, + "CONTACTS_NAVIGATION_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contacts" + } + } + } + }, + "CONTRIBUTIONS_LIST_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The following list contains all Swift Package dependencies of the PAWS Application." + } + } + } + }, + "CONTRIBUTIONS_LIST_FOOTER" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please refer to the individual repository links for packages without license labels." + } + } + } + }, + "CONTRIBUTIONS_LIST_HEADER" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Packages" + } + } + } + }, + "ECG Recordings" : { + + }, + "EEG Recording" : { + + }, + "FAQ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "FAQ" + } + } + } + }, + "Friendly reminder to record your ECG!" : { + + }, + "HEALTHKIT_PERMISSIONS_BUTTON" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Health Data Access" + } + } + } + }, + "HEALTHKIT_PERMISSIONS_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On the next page you will be asked to grant access to the heart data from your Health app." + } + } + } + }, + "HEALTHKIT_PERMISSIONS_SUBTITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAWS requires access to your Health app data to collect ECG information including date of recording, average bpm,\nreported symptoms, and any detected abnormalities." + } + } + } + }, + "HEALTHKIT_PERMISSIONS_TITLE" : { + "comment" : "MARK: HealthKit", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "HealthKit Access" + } + } + } + }, + "Infos" : { + + }, + "INTERESTING_MODULES_AREA1_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create an account so researchers can identify you as a patient" + } + } + } + }, + "INTERESTING_MODULES_AREA1_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create an account" + } + } + } + }, + "INTERESTING_MODULES_AREA2_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Give researchers consent to use your health data as part of the PAWS study" + } + } + } + }, + "INTERESTING_MODULES_AREA2_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Consent" + } + } + } + }, + "INTERESTING_MODULES_AREA3_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Allow the PAWS app to access the health data recorded on your Apple Watch and iPhone" + } + } + } + }, + "INTERESTING_MODULES_AREA3_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grant access to health data" + } + } + } + }, + "INTERESTING_MODULES_BUTTON" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Next" + } + } + } + }, + "INTERESTING_MODULES_SUBTITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You'll need to complete a few more steps\nto get started..." + } + } + } + }, + "INTERESTING_MODULES_TITLE" : { + "comment" : "MARK: Interesting Modules", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Interesting Modules" + } + } + } + }, + "LICENSE_INFO_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "License Information" + } + } + } + }, + "Mock Web Service" : { + + }, + "New ECG Recordings will be displayed here." : { + + }, + "No Recordings" : { + + }, + "NOTIFICATION_PERMISSIONS_BUTTON" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Allow Notifications" + } + } + } + }, + "NOTIFICATION_PERMISSIONS_DESCRIPTION" : { + "extractionState" : "stale", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Do you want to receive friendly reminders for the first week of the PAWS study? Choose your preferred time of day to receive notifications below and click allow." + } + } + } + }, + "NOTIFICATION_PERMISSIONS_SUBTITLE" : { + "extractionState" : "stale", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAWS Study Reminder" + } + } + } + }, + "NOTIFICATION_PERMISSIONS_TITLE" : { + "comment" : "MARK: Notifications", + "extractionState" : "stale", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notifications" + } + } + } + }, + "NOTIFICATIONS_SUBTITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Do you want to receive friendly reminders for the first week of the PAWS study? Choose your preferred time of day to receive notifications below and click allow." + } + } + } + }, + "NOTIFICATIONS_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAWS Reminders" + } + } + } + }, + "PROJECT_LICENSE_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This project is licensed under the MIT License." + } + } + } + }, + "QUESTION_1" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "1. After pressing the event button on the Zio Patch, what do I do if I don’t get a successful recording on my Apple Watch?" + } + } + } + }, + "QUESTION_2" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. What happens if I don’t have internet access when I record the Apple Watch ECG?" + } + } + } + }, + "QUESTION_3" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "3. Will the research team use my Apple Watch ECG data to provide care or change my treatment plan?" + } + } + } + }, + "QUESTION_4" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "4. If I am experiencing symptoms that need immediate medical attention, will the PAWS app or Apple Watch call 9-1-1 for me?" + } + } + } + }, + "QUESTION_5" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "5. Can anything bad happen to me by participating in this study?" + } + } + } + }, + "QUESTION_6" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "6. Can anything good happen to me by participating in this study?" + } + } + } + }, + "QUESTION_7" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "7. Will anyone know I am in the study?" + } + } + } + }, + "QUESTION_8" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "8. Who can I talk to about the study?" + } + } + } + }, + "QUESTION_9" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "9. What if I do not want to be in the study?" + } + } + } + }, + "Recorded %lld symptoms." : { + + }, + "Recorded no symptoms" : { + + }, + "Repository Link" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Repository Link" + } + } + } + }, + "SCOTT_CERESNAK_BIO" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dr. Ceresnak is a Professor of Pediatrics at Stanford University in the Division of Pediatric Cardiology. He is Director of the Pediatric Electrophysiology and Arrhythmia Program at Lucile Packard Children’s Hospital. His primary clinical and research interests involve the care of children and adults with congenital heart disease, with special attention to patients with arrhythmia disorders and inherited arrhythmia syndromes. He has special research interest and experience in advancing technological growth with the goal of creating improved diagnostic and therapeutic options for children with arrhythmia disorders." + } + } + } + }, + "Select a time" : { + + }, + "Study Information" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Study Information" + } + } + } + }, + "STUDY_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This study will explore how the Apple Watch® can work as a heart monitor for kids. As a part of the study, you will wear the Apple Watch for as long as 6 months, and any time you feel like your heart is beating fast or differently, you will record an ECG on the watch using the instructions below. Other than the fact that you are using an Apple Watch, there is no difference between being a part of the study and everything else about seeing your doctor.\n\nAny time that you feel symptoms that feel like an arrhythmia (i.e., palpitations, skipped beats, fast heart rate):\n\n1. First, press the event button on your Zio® Patch Monitor.\n2. Second, initiate a recording on the Apple Watch by following these steps:\n • Open the ECG App.\n • Hold your finger to the Digital Crown for 30 seconds.\n • Follow the on-screen prompts on the Apple Watch." + } + } + } + }, + "Thank you for participating in the PAWS study!" : { + + }, + "WELCOME_AREA1_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You'll be able to see your patient information and a summary of the ECG recordings uploaded from your Apple Watch." + } + } + } + }, + "WELCOME_AREA1_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your ECG Recordings" + } + } + } + }, + "WELCOME_AREA2_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Check if an ECG recording from your Apple Watch was successfully uploaded to the research server. " + } + } + } + }, + "WELCOME_AREA2_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Study Status" + } + } + } + }, + "WELCOME_AREA3_DESCRIPTION" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Learn more about the PAWS study and contact the lead researchers if you have any questions or concerns." + } + } + } + }, + "WELCOME_AREA3_TITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Study Information" + } + } + } + }, + "WELCOME_BUTTON" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Learn More" + } + } + } + }, + "WELCOME_SUBTITLE" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "We are excited to have you join the Pediatric Apple Watch Study (PAWS) to improve diagnosis of arrhythmias in patients like you!" + } + } + } + }, + "WELCOME_TITLE" : { + "comment" : "MARK: Welcome", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Welcome to PAWS!" + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/PAWS/Resources/Localizable.xcstrings.license b/PAWS/Resources/Localizable.xcstrings.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/Localizable.xcstrings.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWS/Resources/SocialSupportQuestionnaire.json.license b/PAWS/Resources/SocialSupportQuestionnaire.json.license new file mode 100644 index 00000000..4f324d88 --- /dev/null +++ b/PAWS/Resources/SocialSupportQuestionnaire.json.license @@ -0,0 +1,6 @@ + +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2023 Stanford University + +SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSSharedContext/FeatureFlags.swift b/PAWS/SharedContext/FeatureFlags.swift similarity index 60% rename from PAWSModules/Sources/PAWSSharedContext/FeatureFlags.swift rename to PAWS/SharedContext/FeatureFlags.swift index 68fe73c9..9d8e0b4e 100644 --- a/PAWSModules/Sources/PAWSSharedContext/FeatureFlags.swift +++ b/PAWS/SharedContext/FeatureFlags.swift @@ -1,24 +1,24 @@ // -// This source file is part of the CS342 2023 PAWS Team Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // // SPDX-License-Identifier: MIT // -/// A collection of feature flags for the PAWS app. -public enum FeatureFlags { +/// A collection of feature flags for the PAWS. +enum FeatureFlags { /// Skips the onboarding flow to enable easier development of features in the application and to allow UI tests to skip the onboarding flow. - public static let skipOnboarding = CommandLine.arguments.contains("--skipOnboarding") + static let skipOnboarding = CommandLine.arguments.contains("--skipOnboarding") /// Always show the onboarding when the application is launched. Makes it easy to modify and test the onboarding flow without the need to manually remove the application or reset the simulator. - public static let showOnboarding = CommandLine.arguments.contains("--showOnboarding") + static let showOnboarding = CommandLine.arguments.contains("--showOnboarding") /// Disables the Firebase interactions, including the login/sign-up step and the Firebase Firestore upload. - public static let disableFirebase = CommandLine.arguments.contains("--disableFirebase") + static let disableFirebase = CommandLine.arguments.contains("--disableFirebase") #if targetEnvironment(simulator) /// Defines if the application should connect to the local firebase emulator. Always set to true when using the iOS simulator. - public static let useFirebaseEmulator = true + static let useFirebaseEmulator = true #else /// Defines if the application should connect to the local firebase emulator. Always set to true when using the iOS simulator. - public static let useFirebaseEmulator = CommandLine.arguments.contains("--useFirebaseEmulator") + static let useFirebaseEmulator = CommandLine.arguments.contains("--useFirebaseEmulator") #endif } diff --git a/PAWS/SharedContext/PAWSCard.swift b/PAWS/SharedContext/PAWSCard.swift new file mode 100644 index 00000000..77bbcf24 --- /dev/null +++ b/PAWS/SharedContext/PAWSCard.swift @@ -0,0 +1,52 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SwiftUI + + +struct PAWSCard: View { + private let content: Content + + + var body: some View { + Group { + content + } + .cornerRadius(5) + .padding(3) + .background( + ZStack { + RoundedRectangle(cornerRadius: 5) + .stroke( + LinearGradient( + colors: [.red, .pink, .yellow], + startPoint: .leading, + endPoint: .trailing + ), + lineWidth: 4 + ) + .shadow(radius: 5) + RoundedRectangle(cornerRadius: 5) + .foregroundStyle(.background) + } + ) + .padding(.horizontal) + } + + + init(@ViewBuilder content: () -> Content) { + self.content = content() + } +} + + +#Preview { + PAWSCard { + Text(verbatim: "This is an example content ...") + } +} diff --git a/PAWS/SharedContext/StorageKeys.swift b/PAWS/SharedContext/StorageKeys.swift new file mode 100644 index 00000000..6758e0d6 --- /dev/null +++ b/PAWS/SharedContext/StorageKeys.swift @@ -0,0 +1,26 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +/// Constants shared across the Spezi Teamplate Application to access storage information including the `AppStorage` and `SceneStorage` +enum StorageKeys { + // MARK: - Onboarding + /// A `Bool` flag indicating of the onboarding was completed. + static let onboardingFlowComplete = "onboardingFlow.complete" + /// A `Step` flag indicating the current step in the onboarding process. + static let onboardingFlowStep = "onboardingFlow.step" + + + // MARK: - Home + /// The currently selected home tab. + static let homeTabSelection = "home.tabselection" + + + // MARK: - HealthKit + /// Start date of the HealthKit data collection + static let healthKitStartDate = "healthkit.startdate" +} diff --git a/PAWS/Study Information/FAQ.swift b/PAWS/Study Information/FAQ.swift new file mode 100644 index 00000000..aa58d6e9 --- /dev/null +++ b/PAWS/Study Information/FAQ.swift @@ -0,0 +1,74 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SwiftUI + + +struct FAQ: View { + private struct Question: Identifiable { + let question: LocalizedStringResource + let answer: LocalizedStringResource + + + var id: String { + question.localizedString() + } + } + + + private static var questions: [Question] = { + (1...9).map { index in + Question( + question: "QUESTION_\(index)".localized(), + answer: "ANSWER_\(index)".localized() + ) + } + }() + + + var body: some View { + HStack { + Text("FAQ") + .font(.title.bold()) + Spacer() + } + .padding(.horizontal) + .padding(.top, 24) + .padding(.bottom, 8) + ForEach(Self.questions) { question in + PAWSCard { + VStack(alignment: .leading) { + HStack { + Text(question.question) + .font(.title3.bold()) + .multilineTextAlignment(.leading) + .padding(.bottom, 4) + Spacer() + } + HStack { + Text(question.answer) + .multilineTextAlignment(.leading) + Spacer() + } + } + .padding() + .frame(maxWidth: .infinity) + } + .padding(.vertical, 8) + } + } +} + + +#Preview { + NavigationStack { + ScrollView { + FAQ() + } + } +} diff --git a/PAWS/Study Information/StudyDescription.swift b/PAWS/Study Information/StudyDescription.swift new file mode 100644 index 00000000..30cb0a4a --- /dev/null +++ b/PAWS/Study Information/StudyDescription.swift @@ -0,0 +1,33 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SwiftUI + +struct StudyDescription: View { + var body: some View { + PAWSCard { + VStack(alignment: .leading) { + HStack { + Text("STUDY_DESCRIPTION") + .multilineTextAlignment(.leading) + Spacer() + } + } + .padding() + .frame(maxWidth: .infinity) + } + .padding(.vertical, 8) + } +} + + +#Preview { + NavigationStack { + StudyDescription() + } +} diff --git a/PAWS/Study Information/StudyInformation.swift b/PAWS/Study Information/StudyInformation.swift new file mode 100644 index 00000000..240cd95c --- /dev/null +++ b/PAWS/Study Information/StudyInformation.swift @@ -0,0 +1,41 @@ +// +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SwiftUI + + +struct StudyInformation: View { + @Binding var presentingAccount: Bool + + + var body: some View { + NavigationStack { + ScrollView { + VStack(spacing: 0) { + StudyDescription() + FAQ() + } + } + .toolbar { + if AccountButton.shouldDisplay { + AccountButton(isPresented: $presentingAccount) + } + } + .navigationTitle(String(localized: "Study Information")) + } + } + + + init(presentingAccount: Binding) { + self._presentingAccount = presentingAccount + } +} + +#Preview { + StudyInformation(presentingAccount: .constant(false)) +} diff --git a/PAWS/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json.license b/PAWS/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json.license b/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/paws-logo.png.license b/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/paws-logo.png.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/AppIcon.appiconset/paws-logo.png.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png.license b/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/AydinSquarePhoto.png.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json b/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json deleted file mode 100644 index 2df9cc96..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "AydinSquarePhoto.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json.license b/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/AydinSquarePhoto.imageset/Contents.json.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/Contents.json.license b/PAWS/Supporting Files/Assets.xcassets/Contents.json.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/Contents.json.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/Contents.json b/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/Contents.json deleted file mode 100644 index bc46caed..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "NotificationImage.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/Contents.json.license b/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/Contents.json.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/Contents.json.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/NotificationImage.png.license b/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/NotificationImage.png.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/NotificationImage.imageset/NotificationImage.png.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json b/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json deleted file mode 100644 index d2705d74..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "ScottSquarePhoto.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json.license b/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json.license deleted file mode 100644 index 358a2369..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/Contents.json.license +++ /dev/null @@ -1,7 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT - diff --git a/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png.license b/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png.license deleted file mode 100644 index 358a2369..00000000 --- a/PAWS/Supporting Files/Assets.xcassets/ScottSquarePhoto.imageset/ScottSquarePhoto.png.license +++ /dev/null @@ -1,7 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT - diff --git a/PAWS/Supporting Files/GoogleService-Info.plist b/PAWS/Supporting Files/GoogleService-Info.plist index 62410148..5a975050 100644 --- a/PAWS/Supporting Files/GoogleService-Info.plist +++ b/PAWS/Supporting Files/GoogleService-Info.plist @@ -3,13 +3,13 @@ CLIENT_ID - 750636343858-kev1gbnfovu771ri9hqlh33kuh6reqcg.apps.googleusercontent.com + CLIENT_ID REVERSED_CLIENT_ID - com.googleusercontent.apps.750636343858-kev1gbnfovu771ri9hqlh33kuh6reqcg + REVERSED_CLIENT_ID API_KEY - AIzaSyAkafWtgHHisoqURUyyYDW9Oj3gBSUaefQ + API_KEY GCM_SENDER_ID - 750636343858 + GCM_SENDER_ID PLIST_VERSION 1 BUNDLE_ID @@ -17,18 +17,18 @@ PROJECT_ID cs342-2023-paws STORAGE_BUCKET - cs342-2023-paws.appspot.com + STORAGE_BUCKET IS_ADS_ENABLED - + IS_ANALYTICS_ENABLED - + IS_APPINVITE_ENABLED - + IS_GCM_ENABLED - + IS_SIGNIN_ENABLED - + GOOGLE_APP_ID - 1:750636343858:ios:2d29a3cdbe7e71868e122b + 1:123456789012:ios:1234567890123456789012 - \ No newline at end of file + diff --git a/PAWS/Supporting Files/GoogleService-Info.plist.license b/PAWS/Supporting Files/GoogleService-Info.plist.license index 9137ea9d..c310108a 100644 --- a/PAWS/Supporting Files/GoogleService-Info.plist.license +++ b/PAWS/Supporting Files/GoogleService-Info.plist.license @@ -1,6 +1,5 @@ +This source file is part of the PAWS application based on the Stanford Spezi Template Application project -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University +SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) SPDX-License-Identifier: MIT diff --git a/PAWS/Supporting Files/Info.plist b/PAWS/Supporting Files/Info.plist index 24f5161d..5dc3321f 100644 --- a/PAWS/Supporting Files/Info.plist +++ b/PAWS/Supporting Files/Info.plist @@ -2,14 +2,8 @@ - INIntentsSupported - - Intent - ITSAppUsesNonExemptEncryption - NSUserNotificationsUsageDescription - Reminders to record ECG UIApplicationSceneManifest UIApplicationSupportsMultipleScenes @@ -17,5 +11,7 @@ UISceneConfigurations + CFBundleAllowMixedLocalizations + diff --git a/PAWS/Supporting Files/Info.plist.license b/PAWS/Supporting Files/Info.plist.license index 9137ea9d..4f324d88 100644 --- a/PAWS/Supporting Files/Info.plist.license +++ b/PAWS/Supporting Files/Info.plist.license @@ -1,5 +1,5 @@ -This source file is part of the CS342 2023 PAWS Team Application project +This source file is part of the PAWS application based on the Stanford Spezi Template Application project SPDX-FileCopyrightText: 2023 Stanford University diff --git a/PAWS/Supporting Files/Localizable.strings b/PAWS/Supporting Files/Localizable.strings deleted file mode 100644 index 98ad3022..00000000 --- a/PAWS/Supporting Files/Localizable.strings +++ /dev/null @@ -1,22 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - - -// MARK: - Notifications -"NOTIFICATIONS_TAB_TITLE" = "Notifications"; - -// MARK: - Contacts -"CONTACTS_TAB_TITLE" = "Contacts"; - - -// MARK: - Mock Upload Data Storage Provider -"MOCK_UPLOAD_TAB_TITLE" = "Reports"; - - -// MARK: - Schedule -"SCHEDULE_TAB_TITLE" = "Schedule"; diff --git a/PAWS/Supporting Files/PAWS.entitlements b/PAWS/Supporting Files/PAWS.entitlements index dab226cc..c541ce6f 100644 --- a/PAWS/Supporting Files/PAWS.entitlements +++ b/PAWS/Supporting Files/PAWS.entitlements @@ -2,6 +2,10 @@ + com.apple.developer.applesignin + + Default + com.apple.developer.healthkit com.apple.developer.healthkit.access diff --git a/PAWS/Supporting Files/PAWS.entitlements.license b/PAWS/Supporting Files/PAWS.entitlements.license index 9137ea9d..4f324d88 100644 --- a/PAWS/Supporting Files/PAWS.entitlements.license +++ b/PAWS/Supporting Files/PAWS.entitlements.license @@ -1,5 +1,5 @@ -This source file is part of the CS342 2023 PAWS Team Application project +This source file is part of the PAWS application based on the Stanford Spezi Template Application project SPDX-FileCopyrightText: 2023 Stanford University diff --git a/PAWSModules/Package.swift b/PAWSModules/Package.swift deleted file mode 100644 index b4358d9f..00000000 --- a/PAWSModules/Package.swift +++ /dev/null @@ -1,84 +0,0 @@ -// swift-tools-version: 5.7 - -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import PackageDescription - - -let package = Package( - name: "PAWSModules", - defaultLocalization: "en", - platforms: [ - .iOS(.v16) - ], - products: [ - .library(name: "PAWSContacts", targets: ["PAWSContacts"]), - .library(name: "PAWSMockDataStorageProvider", targets: ["PAWSMockDataStorageProvider"]), - .library(name: "PAWSOnboardingFlow", targets: ["PAWSOnboardingFlow"]), - .library(name: "PAWSSharedContext", targets: ["PAWSSharedContext"]), - .library(name: "PAWSLandingScreen", targets: ["PAWSLandingScreen"]), - .library(name: "PAWSNotificationScreen", targets: ["PAWSNotificationScreen"]) - ], - dependencies: [ - .package(url: "https://github.com/StanfordBDHG/CardinalKit.git", .upToNextMinor(from: "0.3.5")), - .package(url: "https://github.com/firebase/firebase-ios-sdk.git", from: "10.5.0"), - .package(url: "https://github.com/apple/FHIRModels.git", .upToNextMajor(from: "0.4.0")) - ], - targets: [ - .target( - name: "PAWSContacts", - dependencies: [ - .target(name: "PAWSSharedContext"), - .product(name: "Contact", package: "CardinalKit") - ], - resources: [ - .process("Resources") - ] - ), - .target( - name: "PAWSMockDataStorageProvider", - dependencies: [ - .target(name: "PAWSSharedContext"), - .product(name: "CardinalKit", package: "CardinalKit"), - .product(name: "FHIR", package: "CardinalKit"), - .product(name: "FirebaseAccount", package: "CardinalKit"), - .product(name: "FirestoreDataStorage", package: "firebase-ios-sdk"), - .product(name: "FirebaseFirestore", package: "firebase-ios-sdk"), - .product(name: "FirebaseFirestoreSwift", package: "firebase-ios-sdk"), - .product(name: "FirebaseAuth", package: "firebase-ios-sdk"), - .product(name: "ModelsR4", package: "fhirmodels") - ], - resources: [ - .process("Resources") - ] - ), - .target( - name: "PAWSOnboardingFlow", - dependencies: [ - .target(name: "PAWSSharedContext"), - .product(name: "FHIR", package: "CardinalKit"), - .product(name: "FirebaseAccount", package: "CardinalKit"), - .product(name: "HealthKitDataSource", package: "CardinalKit"), - .product(name: "Onboarding", package: "CardinalKit") - ], - resources: [ - .process("Resources") - ] - ), - .target( - name: "PAWSSharedContext" - ), - .target( - name: "PAWSLandingScreen" - ), - .target( - name: "PAWSNotificationScreen" - ) - ] -) diff --git a/PAWSModules/Sources/PAWSContacts/Contacts.swift b/PAWSModules/Sources/PAWSContacts/Contacts.swift deleted file mode 100644 index 0b9a8ac5..00000000 --- a/PAWSModules/Sources/PAWSContacts/Contacts.swift +++ /dev/null @@ -1,463 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Contact -import Foundation -import SwiftUI - -struct Question1234View: View { - var body: some View { - VStack(spacing: 1) { - Text("FAQ") - .font(.custom("Gill Sans", fixedSize: 28)) - } - VStack(spacing: 1) { - Text("1. After pressing the event button on the Zio Patch, what do I do if I don’t get a successful recording on my Apple Watch?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question1) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - - VStack(spacing: 1) { - Text("2. What happens if I don’t have internet access when I record the Apple Watch ECG?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question2) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - - VStack(spacing: 1) { - Text("3. Will the research team use my Apple Watch ECG data to provide care or change my treatment plan?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question3) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - - VStack(spacing: 1) { - Text("4. If I am experiencing symptoms that need immediate medical attention, will the PAWS app or Apple Watch call 9-1-1 for me?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question4) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - } - - private var question1: String { - guard let question1Path = Bundle.module.path(forResource: "Question1", ofType: "md"), - let question1 = try? String(contentsOfFile: question1Path) else { - return "" - } - - return question1 - } - - private var question2: String { - guard let question2Path = Bundle.module.path(forResource: "Question2", ofType: "md"), - let question2 = try? String(contentsOfFile: question2Path) else { - return "" - } - - return question2 - } - - private var question3: String { - guard let question3Path = Bundle.module.path(forResource: "Question3", ofType: "md"), - let question3 = try? String(contentsOfFile: question3Path) else { - return "" - } - - return question3 - } - - private var question4: String { - guard let question4Path = Bundle.module.path(forResource: "Question4", ofType: "md"), - let question4 = try? String(contentsOfFile: question4Path) else { - return "" - } - - return question4 - } -} - -struct Question56789View: View { - var body: some View { - VStack(spacing: 1) { - Text("5. Can anything bad happen to me by participating in this study?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question5) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - - VStack(spacing: 1) { - Text("6. Can anything good happen to me by participating in this study?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question6) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - - VStack(spacing: 1) { - Text("7. Will anyone know I am in the study?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question7) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - - VStack(spacing: 1) { - Text("8. Who can I talk to about the study?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question8) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - - VStack(spacing: 1) { - Text("9. What if I do not want to be in the study?") - .font(.custom("Gill Sans SemiBold", fixedSize: 19)) - .padding() - Text(question9) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - } - .padding(.vertical, 20) - .padding(.horizontal, 10) - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - } - - private var question5: String { - guard let question5Path = Bundle.module.path(forResource: "Question5", ofType: "md"), - let question5 = try? String(contentsOfFile: question5Path) else { - return "" - } - - return question5 - } - - private var question6: String { - guard let question6Path = Bundle.module.path(forResource: "Question6", ofType: "md"), - let question6 = try? String(contentsOfFile: question6Path) else { - return "" - } - - return question6 - } - - private var question7: String { - guard let question7Path = Bundle.module.path(forResource: "Question7", ofType: "md"), - let question7 = try? String(contentsOfFile: question7Path) else { - return "" - } - - return question7 - } - - private var question8: String { - guard let question8Path = Bundle.module.path(forResource: "Question8", ofType: "md"), - let question8 = try? String(contentsOfFile: question8Path) else { - return "" - } - - return question8 - } - - private var question9: String { - guard let question9Path = Bundle.module.path(forResource: "Question9", ofType: "md"), - let question9 = try? String(contentsOfFile: question9Path) else { - return "" - } - - return question9 - } -} - -public struct Contacts: View { - let contacts = [ - Contact( - name: PersonNameComponents( - givenName: "Scott", - familyName: "Ceresnak" - ), - image: Image(decorative: "ScottSquarePhoto"), - title: "Professor of Pediatrics (Cardiology)", - description: String(localized: "SCOTT_CERESNAK_BIO", bundle: .module), - organization: "Stanford University", - address: { - let address = CNMutablePostalAddress() - address.country = "USA" - address.state = "CA" - address.postalCode = "94304" - address.city = "Palo Alto" - address.street = "725 Welch Rd" - return address - }(), - contactOptions: [ - .email(addresses: ["ceresnak@stanford.edu"]), - ContactOption( - image: Image(systemName: "safari.fill"), - title: "Website", - action: { - if let url = URL(string: "https://profiles.stanford.edu/intranet/scott-ceresnak?tab=bio") { - UIApplication.shared.open(url) - } - } - ) - ] - ), - Contact( - name: PersonNameComponents( - givenName: "Aydin", - familyName: "Zahedivash" - ), - image: Image(decorative: "AydinSquarePhoto"), - title: "Pediatric Stanford Cardiology Fellow", - description: String(localized: "AYDIN_ZAHEDIVASH_BIO", bundle: .module), - organization: "Stanford University", - address: { - let address = CNMutablePostalAddress() - address.country = "USA" - address.state = "CA" - address.postalCode = "94304" - address.city = "Palo Alto" - address.street = "725 Welch Rd" - return address - }(), - contactOptions: [ - .email(addresses: ["aydinz@stanford.edu"]), - ContactOption( - image: Image(systemName: "safari.fill"), - title: "Website", - action: { - if let url = URL(string: "https://profiles.stanford.edu/intranet/scott-ceresnak?tab=bio") { - UIApplication.shared.open(url) - } - } - ) - ] - ) - ] - - - public var body: some View { - NavigationStack { - ScrollView(.vertical) { - DescriptionView() - .padding(.vertical, 12) - Question1234View() - .padding(.vertical, 12) - Question56789View() - .padding(.vertical, 12) - Text("CONTACTS") - .font(.custom("Gill Sans", fixedSize: 28)) - ForEach(contacts, id: \.name) { contact in - ContactView(contact: contact) - .padding() - .padding() - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ), width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 6) - } - .padding(.vertical, 6) - } - .background(Color(.systemGroupedBackground)) - .navigationTitle(String(localized: "CONTACTS_NAVIGATION_TITLE", bundle: .module)) - } - } - - public init() {} -} - - -struct Contacts_Previews: PreviewProvider { - static var previews: some View { - Contacts() - } -} diff --git a/PAWSModules/Sources/PAWSContacts/Description.swift b/PAWSModules/Sources/PAWSContacts/Description.swift deleted file mode 100644 index 4baf0cb5..00000000 --- a/PAWSModules/Sources/PAWSContacts/Description.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - -struct DescriptionView: View { - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ) - - var body: some View { - VStack(spacing: 1) { - Text("DESCRIPTION") - .font(.custom("Gill Sans", fixedSize: 28)) - .padding() - Text(description) - .font(.custom("GillSans", fixedSize: 18)) - .padding() - .padding() - .background { - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(backgroundGradient, width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - .padding(.horizontal) - .padding(.vertical, 2) - } - } - - private var description: String { - guard let descriptionPath = Bundle.module.path(forResource: "StudyDescription", ofType: "md"), - let description = try? String(contentsOfFile: descriptionPath) else { - return "" - } - - return description - } -} - -struct DescriptionView_Previews: PreviewProvider { - static var previews: some View { - DescriptionView() - } -} diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question1.md b/PAWSModules/Sources/PAWSContacts/Resources/Question1.md deleted file mode 100644 index cec0d483..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question1.md +++ /dev/null @@ -1 +0,0 @@ -Don’t be concerned, simply start another ECG recording on the Apple Watch as soon as you can. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question1.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question1.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question1.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question2.md b/PAWSModules/Sources/PAWSContacts/Resources/Question2.md deleted file mode 100644 index 508d01ae..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question2.md +++ /dev/null @@ -1 +0,0 @@ -The PAWS app will store your ECG file directly on your iPhone and upload it to the research database when you have access to the internet again. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question2.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question2.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question2.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question3.md b/PAWSModules/Sources/PAWSContacts/Resources/Question3.md deleted file mode 100644 index 70d9b201..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question3.md +++ /dev/null @@ -1 +0,0 @@ -The research team will review your Apple Watch ECG data periodically but will not use it in place of traditional diagnostic methods to change the course of your care plan. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question3.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question3.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question3.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question4.md b/PAWSModules/Sources/PAWSContacts/Resources/Question4.md deleted file mode 100644 index b73ad2bf..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question4.md +++ /dev/null @@ -1 +0,0 @@ -If you are experiencing symptoms that require immediate attention, please call 9-1-1. Neither the PAWS app nor the Apple Watch will call the emergency services for you. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question4.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question4.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question4.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question5.md b/PAWSModules/Sources/PAWSContacts/Resources/Question5.md deleted file mode 100644 index 6a4a0edd..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question5.md +++ /dev/null @@ -1 +0,0 @@ -You will not get sick or hurt because of anything in this study. We will be studying your health information and all of your information will be kept secure. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question5.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question5.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question5.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question6.md b/PAWSModules/Sources/PAWSContacts/Resources/Question6.md deleted file mode 100644 index 4e4284d1..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question6.md +++ /dev/null @@ -1 +0,0 @@ -Nothing good will directly happen to you but, by participating in this study, you will help us understand if the Apple Watch can be used to monitor heart problems in other kids. We hope that someday we can just give an Apple Watch to kids needing to have their heart tested. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question6.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question6.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question6.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question7.md b/PAWSModules/Sources/PAWSContacts/Resources/Question7.md deleted file mode 100644 index a14056ab..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question7.md +++ /dev/null @@ -1 +0,0 @@ -Only the researchers in charge of the study will know that you are in it. No one else will know, and your information will be kept secure. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question7.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question7.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question7.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question8.md b/PAWSModules/Sources/PAWSContacts/Resources/Question8.md deleted file mode 100644 index 56e06fde..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question8.md +++ /dev/null @@ -1,4 +0,0 @@ -If you have any questions about the study or any problems to do with the study you can contact the Protocol Director Dr. Scott Ceresnak. You can call him at (650)-723-7913. - - -If you have questions about the study but want to talk to someone else who is not a part of the study, you can call the Stanford Institutional Review Board (IRB) at (650)-723-5244 or toll free at 1-866-680-2906. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question8.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question8.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question8.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question9.md b/PAWSModules/Sources/PAWSContacts/Resources/Question9.md deleted file mode 100644 index 7a179c99..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question9.md +++ /dev/null @@ -1 +0,0 @@ -If you do not want to participate in the study, just tell the researchers or your parents. You don’t need to be a part of the study and you won’t get in trouble if you decide if you don’t want to. Your doctor will still treat you the same even if you don’t participate. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/Question9.md.license b/PAWSModules/Sources/PAWSContacts/Resources/Question9.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/Question9.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/StudyDescription.md b/PAWSModules/Sources/PAWSContacts/Resources/StudyDescription.md deleted file mode 100644 index 763f98ee..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/StudyDescription.md +++ /dev/null @@ -1,9 +0,0 @@ -This study will explore how the Apple Watch® can work as a heart monitor for kids. As a part of the study, you will wear the Apple Watch for as long as 6 months, and any time you feel like your heart is beating fast or differently, you will record an ECG on the watch using the instructions below. Other than the fact that you are using an Apple Watch, there is no difference between being a part of the study and everything else about seeing your doctor. - -Any time that you feel symptoms that feel like an arrhythmia (i.e., palpitations, skipped beats, fast heart rate): - -1. First, press the event button on your Zio® Patch Monitor. -2. Second, initiate a recording on the Apple Watch by following these steps: - • Open the ECG App. - • Hold your finger to the Digital Crown for 30 seconds. - • Follow the on-screen prompts on the Apple Watch. diff --git a/PAWSModules/Sources/PAWSContacts/Resources/StudyDescription.md.license b/PAWSModules/Sources/PAWSContacts/Resources/StudyDescription.md.license deleted file mode 100644 index 7a306f20..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/StudyDescription.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSContacts/Resources/en.lproj/Localizable.strings b/PAWSModules/Sources/PAWSContacts/Resources/en.lproj/Localizable.strings deleted file mode 100644 index 0a2645a3..00000000 --- a/PAWSModules/Sources/PAWSContacts/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,12 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -// MARK: - Contacts -"CONTACTS_NAVIGATION_TITLE" = "Study Information"; -"SCOTT_CERESNAK_BIO" = "Dr. Ceresnak is a Professor of Pediatrics at Stanford University in the Division of Pediatric Cardiology. He is Director of the Pediatric Electrophysiology and Arrhythmia Program at Lucile Packard Children’s Hospital. His primary clinical and research interests involve the care of children and adults with congenital heart disease, with special attention to patients with arrhythmia disorders and inherited arrhythmia syndromes. He has special research interest and experience in advancing technological growth with the goal of creating improved diagnostic and therapeutic options for children with arrhythmia disorders."; -"AYDIN_ZAHEDIVASH_BIO" = "Dr. Zahedivash is a resident physician in the Stanford Department of Pediatrics and will serve as a chief resident during the 2023-2024 academic year. His academic interests focus on the development and translation of innovative technologies and services to address diagnostic and health equity challenges. During his educational career as an engineer and budding physician, he has co-invented a series of computational techniques and devices. Previous inventions include diagnostic deep-learning algorithms to detect unstable coronary artery plaque on intravascular imaging and a surgical probe for intraoperative margin detection during cancer resection. He is passionate about using his medical, technical, and business backgrounds to develop digital health solutions and equitable technology translation strategies for children."; diff --git a/PAWSModules/Sources/PAWSLandingScreen/Bundle+Image.swift b/PAWSModules/Sources/PAWSLandingScreen/Bundle+Image.swift deleted file mode 100644 index 2b20a775..00000000 --- a/PAWSModules/Sources/PAWSLandingScreen/Bundle+Image.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// This source file is part of the CS342 2023 Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -extension Bundle { - /// Loads an image from the `Bundle` and returns the content as a SwiftUI `Image`. - /// - Parameter name: The name of the image file. - /// - Returns: SwiftUI `Image` instance loaded from the `Bundle`. - public func image(fromFileNamed name: String, type: String = "jpeg") -> Image { - guard let imagePath = self.path(forResource: name, ofType: type), - let image = UIImage(contentsOfFile: imagePath) else { - return Image(systemName: "person.fill") - } - - return Image(uiImage: image) - } -} diff --git a/PAWSModules/Sources/PAWSLandingScreen/LandingScreen.swift b/PAWSModules/Sources/PAWSLandingScreen/LandingScreen.swift deleted file mode 100644 index 8d83667a..00000000 --- a/PAWSModules/Sources/PAWSLandingScreen/LandingScreen.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -public struct LandingScreen: View { - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .orange, .yellow], - startPoint: .leading, - endPoint: .trailing - ) - @Binding private var launchStatus: Bool - - - public var body: some View { - VStack { - backgroundGradient - .mask( - VStack { - Image(systemName: "pawprint.circle.fill") - .resizable() - .scaledToFill() - .frame(width: 200, height: 200) - .foregroundColor(.red) - Text("PAWS") - .font(.custom("GillSans-Bold", fixedSize: 30)) - Text("The Pediatric Apple Watch Study") - .font(.custom("GillSans", fixedSize: 15)) - .offset(y: 50) - } - ) - Button( - action: { - launchStatus = true - }, label: { - Text("Tap to get started") - .fontWeight(.bold) - .padding() - .foregroundColor(Color.red) - .border(backgroundGradient, width: 3) - .cornerRadius(5) - .offset(y: -30) - } - ) - } - } - - - public init(pressedStart: Binding) { - self._launchStatus = pressedStart - } -} - - -struct LandingScreen_Previews: PreviewProvider { - @State private static var pressedStart = false - - static var previews: some View { - LandingScreen(pressedStart: $pressedStart) - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/AboutStudy.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/AboutStudy.swift deleted file mode 100644 index 83aac34d..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/AboutStudy.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -struct AboutStudy: View { - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .orange], - startPoint: .leading, - endPoint: .trailing - ) - - - var body: some View { - VStack(alignment: .leading, spacing: 8) { - VStack { - Image(systemName: "pawprint.circle.fill") - .resizable() - // .aspectRatio(contentMode: .fit) - .scaledToFill() - .frame(width: 115, height: 75) - .foregroundColor(.red) - .padding([.top], 20) - // .offset(x: 8) - // .offset(x:80, y:-5) - } - .frame(maxWidth: .infinity, alignment: .center) - .padding([.top, .leading, .trailing, .bottom], 20) - VStack(alignment: .leading, spacing: 8) { - Text("Contribute to Health Research") - .font(.headline) - .fontWeight(.bold) - .frame(maxWidth: .infinity, alignment: .center) - - Text("Find out how you're helping the Stanford Pediatric Apple Watch Study (PAWS).") - .font(.subheadline) - .frame(maxWidth: .infinity, alignment: .leading) - .padding([.top, .bottom, .leading, .trailing], 10) - // .offset(y:-10) - } - .offset(y: 10) - .frame(maxWidth: .infinity, alignment: .center) - .padding([.top], 1) - .padding([.bottom], 20) - AboutStudyNav().padding([.leading, .trailing], 10) - } - .frame(maxWidth: .infinity) - .overlay( - RoundedRectangle(cornerRadius: 10).strokeBorder(.gray, lineWidth: 1) - ) - } -} - - -struct AboutStudy_Previews: PreviewProvider { - static var previews: some View { - AboutStudy() - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/AboutStudyNav.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/AboutStudyNav.swift deleted file mode 100644 index 1672b5ef..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/AboutStudyNav.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import PAWSSharedContext -import SwiftUI - - -struct AboutStudyNav: View { - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .orange], - startPoint: .leading, - endPoint: .trailing - ) - - @AppStorage(StorageKeys.homeTabSelection) var selectedTab = Tabs.home - - var body: some View { - Button( - action: { - selectedTab = Tabs.contact - }, label: { - Text("Learn More ") - .fontWeight(.bold) - .padding() - .foregroundColor(Color.white) - .frame(maxWidth: .infinity, alignment: .center) - .background(backgroundGradient) - .cornerRadius(10) - .padding(.bottom, 10) - } - ) - } -} - -struct AboutStudyNav_Previews: PreviewProvider { - static var previews: some View { - AboutStudyNav() - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/Bundle+ECGTracing.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/Bundle+ECGTracing.swift deleted file mode 100644 index 600a2d01..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/Bundle+ECGTracing.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Foundation -import ModelsR4 - -extension Foundation.Bundle { - func ecgTracing(withName name: String) -> Observation { - guard let resourceURL = self.url(forResource: name, withExtension: "json") else { - print(self.bundleURL) - fatalError("Could not find the ecgTracing \"\(name).json\" in Bundle.") - } - - do { - let resourceData = try Data(contentsOf: resourceURL) - return try JSONDecoder().decode(Observation.self, from: resourceData) - } catch { - fatalError("Could not decode the FHIR ECG data named \"\(name).json\": \(error)") - } - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/Home.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/Home.swift deleted file mode 100644 index f0595f73..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/Home.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import PAWSContacts -import PAWSNotificationScreen -import PAWSSharedContext -import SwiftUI - - -enum Tabs: String { - case home - case contact - case mockUpload -} - -public struct HomeView: View { - @AppStorage(StorageKeys.homeTabSelection) var selectedTab = Tabs.home - - public var body: some View { - TabView(selection: $selectedTab) { - HomeScreen() - .tag(Tabs.home) - .tabItem { - Label("Home", systemImage: "house.fill") - } - MockUploadList() - .tag(Tabs.mockUpload) - .tabItem { - Label("Reports", systemImage: "heart.text.square.fill") - } - Contacts() - .tag(Tabs.contact) - .tabItem { - Label("Study Information", systemImage: "doc.text.fill") - } - } - } - public init() {} -} - - -struct MainView_Previews: PreviewProvider { - static var previews: some View { - HomeView() - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/HomeScreen.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/HomeScreen.swift deleted file mode 100644 index 8d386903..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/HomeScreen.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Account -import class FHIR.FHIR -import FirebaseAccount -import Foundation -import SwiftUI -import Views - - -public struct HomeScreen: View { - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .orange, .yellow], - startPoint: .leading, - endPoint: .trailing - ) - - @EnvironmentObject var account: Account - @EnvironmentObject var firebaseAccountConfiguration: FirebaseAccountConfiguration - @EnvironmentObject var mockDataStorageProvider: MockDataStorageProvider - - - public var body: some View { - let name = firebaseAccountConfiguration.user?.displayName ?? "Name Needed" - - ScrollView(.vertical) { - VStack(alignment: .leading) { - HStack(alignment: .top) { - VStack(alignment: .leading) { - Text("Hello,") - .padding([.top], 10) - .font(.title) - .fontWeight(.bold) - Text(firstName(fullName: name).capitalized) - .font(.title2) - .fontWeight(.bold) - .padding([.top], 0) - .padding([.bottom], 10) - } - .padding() - Image(systemName: "pawprint.circle.fill") - .resizable() - .scaledToFill() - .frame(width: 60, height: 60) - .foregroundColor(.black) - .padding([.top], 20) - .padding([.leading], 190) - } - .frame(maxWidth: .infinity, alignment: .leading) - .padding([.top, .leading, .trailing], 10) - Divider().frame(maxWidth: .infinity) - recording - aboutstudy - }.frame(maxHeight: .infinity, alignment: .top) - } - } - @ViewBuilder var recording: some View { - if mockDataStorageProvider.mockUploads.isEmpty { - VStack(spacing: 32) { - Text("No Recordings Uploaded") - .multilineTextAlignment(.center) - .fontWeight(.bold) - } - .frame(maxWidth: .infinity) - .padding(32) - } else { - VStack(alignment: .leading) { - Text("Latest Recording") - .font(.title3) - .fontWeight(.bold) - .padding([.top], 10) - .padding(.leading, 10) - .foregroundColor(.gray) - let uploadList = mockDataStorageProvider.mockUploads - let latest = uploadList[0] - LatestRecording(mockUpload: latest) - } - .padding([.top, .leading, .trailing], 10) - .frame(maxWidth: .infinity, alignment: .topLeading) - } - } - @ViewBuilder var aboutstudy: some View { - VStack(alignment: .leading) { - Text("About The Study") - .font(.title3) - .fontWeight(.bold) - .padding([.top], 10) - .padding(.leading, 10) - .foregroundColor(.gray) - AboutStudy() - } - .padding([.top, .leading, .trailing], 10) - .frame(maxWidth: .infinity, alignment: .topLeading) - } - - public init() {} - - func firstName(fullName: String) -> String { - var names = fullName.components(separatedBy: " ") - let first = names.removeFirst() - return first + "!" - } -} - - -struct HomeScreen_Previews: PreviewProvider { - static var previews: some View { - HomeScreen() - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/LatestRecording.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/LatestRecording.swift deleted file mode 100644 index ecc162c7..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/LatestRecording.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -// swiftlint:disable all - -import FirebaseAuth -import FirebaseCore -import FirebaseFirestore -import FirestoreDataStorage -import Foundation -import SwiftUI - - -struct LatestRecording: View { - let mockUpload: MockUpload - @State var status: MockUpload.UploadStatus? - - private let backgroundGradient = LinearGradient( - colors: [.white], - startPoint: .leading, - endPoint: .trailing - ) - - var body: some View { - let date = "\(format(mockUpload.date))" - let time = date.range(of: "at")!.lowerBound - VStack(alignment: .leading, spacing: 8) { - HStack(alignment: .top, spacing: 8) { - Text("ECG Recording") - .font(.headline) - .frame(maxWidth: .infinity, alignment: .leading) - .padding([.top, .bottom, .leading, .trailing], 10) - .fontWeight(.bold) - Text(date[date.index(time, offsetBy: 2)...]) - .font(.subheadline) - .frame(maxWidth: .infinity, alignment: .trailing) - .padding([.top, .bottom, .leading, .trailing], 10) - - } - Text(date[.. String { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .long - dateFormatter.timeStyle = .long - return dateFormatter.string(from: date) - } - - private func checkStatus() { - let user = Auth.auth().currentUser - let uid = user?.uid ?? "" - let id = mockUpload.identifier - - let dbs = Firestore.firestore() - let uploadRef = dbs.collection("users").document(uid).collection("Observation").document(id) - - uploadRef.getDocument { document, _ in - if let document = document, document.exists { - self.status = .success - } else { - self.status = .failure - } - } - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/LazyText.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/LazyText.swift deleted file mode 100644 index 88b9ba58..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/LazyText.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import FHIR -import SwiftUI - - -struct LazyText: View { - private let text: String - @State private var lines: [(linenumber: Int, text: String)] = [] - - - var body: some View { - LazyVStack(alignment: .leading) { - ForEach(lines, id: \.linenumber) { line in - Text(line.text) - .multilineTextAlignment(.leading) - } - } - .onAppear { - var lineNumber = 0 - text.enumerateLines { line, _ in - lines.append((lineNumber, line)) - lineNumber += 1 - } - } - } - - - init(text: String) { - self.text = text - } -} - - -struct LazyText_Previews: PreviewProvider { - static let mappingJSONString = { - let observation = Bundle.module.ecgTracing(withName: "ECGObservation") - let jsonEncoder = JSONEncoder() - jsonEncoder.outputFormatting = [.prettyPrinted, .sortedKeys] - let jsonData = (try? jsonEncoder.encode(observation)) ?? Data() - return String(data: jsonData, encoding: .utf8) ?? "" - }() - static var previews: some View { - ScrollView { - LazyText(text: mappingJSONString) - } - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockDataStorageProvider.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/MockDataStorageProvider.swift deleted file mode 100644 index 091269f4..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockDataStorageProvider.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import CardinalKit -import FHIR -import FirebaseAuth -import FirebaseCore -import FirebaseFirestore -import FirestoreDataStorage -import Foundation -import HealthKitUI - -/// A data storage provider that collects all uploads and displays them in a user interface using the ``MockUploadList``. -public actor MockDataStorageProvider: DataStorageProvider, ObservableObjectProvider, ObservableObject { - public typealias ComponentStandard = FHIR - - - let encoder: JSONEncoder = { - let encoder = JSONEncoder() - encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] - return encoder - }() - @MainActor @Published private (set) var mockUploads: [MockUpload] = [] - - - public init() { } - - - public func process(_ element: DataChange) async throws { - switch element { - case let .addition(element): - let data = try encoder.encode(element) - let json = String(decoding: data, as: UTF8.self) - print(json) - - // let tracing = try JSONDecoder().decode(HKElectrocardiogramMapping.self, from: data) - // print(tracing) - // Bundle.module.ecgTracing(withName: json) - // let symptoms = tracing.symptomsStatus.codings.description - let symptoms = getSymptoms(tracing: json) - - _Concurrency.Task { @MainActor in - mockUploads.insert( - MockUpload( - id: element.id.description, - type: .add, - path: ResourceProxy(with: element).resourceType.description, - body: json, - symptoms: symptoms - ), - at: 0 - ) - } - case let .removal(removalContext): - _Concurrency.Task { @MainActor in - mockUploads.insert( - MockUpload( - id: removalContext.id.description, - type: .delete, - path: removalContext.resourceType.rawValue - ), - at: 0 - ) - } - } - } - - private func getSymptoms(tracing: String) -> String { - var symptoms = "" - - if tracing.contains("Fatigue") { - symptoms += "Fatigue; " - } - if tracing.contains("Dizziness") { - symptoms += "Dizziness; " - } - if tracing.contains("Rapid") { - symptoms += "Rapid, pounding or fluttering heartbeat; " - } - if tracing.contains("Skipped") { - symptoms += "Skipped heartbeat; " - } - if tracing.contains("Shortness") { - symptoms += "Shortness of breath; " - } - if tracing.contains("Chest tightness or pain") { - symptoms += "Chest tightness or pain; " - } - if tracing.contains("Fainting") { - symptoms += "Fainting; " - } - if tracing.contains("Other") { - symptoms += "Other; " - } - - return symptoms - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUpload.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUpload.swift deleted file mode 100644 index 41af6aee..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUpload.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import FirebaseAuth -import FirebaseCore -import FirebaseFirestore -import FirestoreDataStorage -import Foundation - - -struct MockUpload: Identifiable, Hashable { - enum UploadType { - case add - case delete - } - - enum UploadStatus { - case success - case failure - } - - let identifier: String - let date = Date() - let type: UploadType - let path: String - let body: String? - var symptoms: String? - - var id: String { - "\(type): \(path)/\(identifier) at \(date.debugDescription)" - } - - - init(id: String, type: UploadType, path: String, body: String? = nil, symptoms: String? = "") { - self.identifier = id - self.type = type - self.path = path - self.body = body - self.symptoms = symptoms - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadDetailView.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadDetailView.swift deleted file mode 100644 index 58a17191..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadDetailView.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -struct MockUploadDetailView: View { - let mockUpload: MockUpload - - - var body: some View { - List { - Section(String(localized: "MOCK_UPLOAD_DETAIL_HEADER", bundle: .module)) { - MockUploadHeader(mockUpload: mockUpload) - } - Section(String(localized: "MOCK_UPLOAD_DETAIL_BODY", bundle: .module)) { - LazyText(text: mockUpload.body ?? "") - } - } - .listStyle(.insetGrouped) - .navigationBarTitleDisplayMode(.inline) - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadHeader.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadHeader.swift deleted file mode 100644 index d901f123..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadHeader.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -// swiftlint:disable all - -import FirebaseAuth -import FirebaseCore -import FirebaseFirestore -import FirestoreDataStorage -import SwiftUI - -struct MockUploadHeader: View { - let mockUpload: MockUpload - @State var status: MockUpload.UploadStatus? - - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ) - - var body: some View { - let date = "\(format(mockUpload.date))" - let time = date.range(of: "at")!.lowerBound - //let symptomNum = seperateSymptoms(allSymptoms: mockUpload.symptoms ?? "").count - - ZStack{ - RoundedRectangle(cornerRadius: 10) - .foregroundColor(Color(.systemBackground)) - .frame(width: 360) - .shadow(radius: 5) - .opacity(0.9) - .border(backgroundGradient, width: 2) - .cornerRadius(10) - .shadow(radius: 10) - VStack(alignment: .leading, spacing: 4) { - Text(date[.. String { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .long - dateFormatter.timeStyle = .long - return dateFormatter.string(from: date) - } - - private func checkStatus() { - let user = Auth.auth().currentUser - let uid = user?.uid ?? "" - let id = mockUpload.identifier - - let dbs = Firestore.firestore() - let uploadRef = dbs.collection("users").document(uid).collection("Observation").document(id) - - uploadRef.getDocument { document, _ in - if let document = document, document.exists { - self.status = .success - } else { - self.status = .failure - } - } - } - - private func seperateSymptoms(allSymptoms: String) -> [String] { - var symptoms = allSymptoms.components(separatedBy: "; ") - symptoms.removeLast() - return symptoms - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadList-filter.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadList-filter.swift deleted file mode 100644 index c54384a1..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadList-filter.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -/// Displays the recoded uploads collected by the ``MockDataStorageProvider``. -public struct MockUploadListFilter: View { - @EnvironmentObject var mockDataStorageProvider: MockDataStorageProvider - let button1: some View = - Text("Past week") - .fontWeight(.bold) - .font(.system(size: 8)) - .padding() - .background(Color.purple) - .cornerRadius(10) - .foregroundColor(.white) - .padding(5) - - public var body: some View { - VStack(alignment: .leading) { - Text(String(localized: "MOCK_UPLOAD_LIST_TITLE", bundle: .module)) - .font(.title) - .fontWeight(.bold) - .padding([.top, .bottom], 20) - HStack(spacing: 3) { - button1 - .frame(maxWidth: .infinity) - button1 - .frame(maxWidth: .infinity) - button1 - .frame(maxWidth: .infinity) - } - - Group { - if mockDataStorageProvider.mockUploads.isEmpty { - VStack(spacing: 32) { - Image(systemName: "pawprint.circle") - .font(.system(size: 100)) - .opacity(0.2) - Text(String(localized: "MOCK_UPLOAD_LIST_PLACEHOLDER", bundle: .module)) - .multilineTextAlignment(.center) - } - .padding(32) - } else { - List(mockDataStorageProvider.mockUploads) { mockUpload in - MockUploadHeader(mockUpload: mockUpload) - } - } - } - } - } - - - public init() {} - - - private func format(_ date: Date) -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .long - dateFormatter.timeStyle = .long - return dateFormatter.string(from: date) - } -} - - -struct MockUploadsListFilter_Previews: PreviewProvider { - static var previews: some View { - MockUploadListFilter() - .environmentObject(MockDataStorageProvider()) - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadList.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadList.swift deleted file mode 100644 index 0aeb4796..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/MockUploadList.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -/// Displays the recoded uploads collected by the ``MockDataStorageProvider``. -public struct MockUploadList: View { - @EnvironmentObject var mockDataStorageProvider: MockDataStorageProvider - - public var body: some View { - ZStack { - Color.white - .ignoresSafeArea() - // VStack(alignment: .leading) { - // Text("Notifications") - // .font(.largeTitle) - // .fontWeight(.bold) - // .padding([.top, .leading, .bottom], 20) - // .offset(y: -150) - NavigationStack { - Group { - if mockDataStorageProvider.mockUploads.isEmpty { - VStack(spacing: 32) { - Image(systemName: "pawprint.circle") - .font(.system(size: 100)) - .opacity(0.2) - Text(String(localized: "MOCK_UPLOAD_LIST_PLACEHOLDER", bundle: .module)) - .multilineTextAlignment(.center) - .fontWeight(.bold) - } - .padding(32) - } else { - List(mockDataStorageProvider.mockUploads) { mockUpload in - MockUploadHeader(mockUpload: mockUpload) - } - } - } - .navigationTitle(String(localized: "MOCK_UPLOAD_LIST_TITLE", bundle: .module)) - } - } - } - - public init() {} - - - private func format(_ date: Date) -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .long - dateFormatter.timeStyle = .long - return dateFormatter.string(from: date) - } -} - - -struct MockUploadsList_Previews: PreviewProvider { - static var previews: some View { - MockUploadList() - .environmentObject(MockDataStorageProvider()) - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/RecordingsNav.swift b/PAWSModules/Sources/PAWSMockDataStorageProvider/RecordingsNav.swift deleted file mode 100644 index f93273c8..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/RecordingsNav.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import PAWSSharedContext -import SwiftUI - - -struct RecordingsNav: View { - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .orange], - startPoint: .leading, - endPoint: .trailing - ) - - @AppStorage(StorageKeys.homeTabSelection) var selectedTab = Tabs.home - - var body: some View { - Button( - action: { - selectedTab = Tabs.mockUpload - }, label: { - Text("View More Recordings ") - .fontWeight(.bold) - .padding() - .foregroundColor(Color.white) - .frame(maxWidth: .infinity, alignment: .center) - .background(backgroundGradient) - .cornerRadius(10) - .padding(.bottom, 10) - } - ) - } -} - -struct RecordingsNav_Previews: PreviewProvider { - static var previews: some View { - RecordingsNav() - } -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/ECGObservation.json b/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/ECGObservation.json deleted file mode 100644 index f18fb46e..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/ECGObservation.json +++ /dev/null @@ -1,165 +0,0 @@ -{ - "category" : [ - { - "coding" : [ - { - "code" : "procedure", - "display" : "Procedure", - "system" : "http://terminology.hl7.org/CodeSystem/observation-category" - } - ] - } - ], - "code" : { - "coding" : [ - { - "code" : "HKElectrocardiogram", - "display" : "Electrocardiogram", - "system" : "http://developer.apple.com/documentation/healthkit" - }, - { - "code" : "131329", - "display" : "MDC_ECG_ELEC_POTL_I", - "system" : "urn:oid:2.16.840.1.113883.6.24" - } - ] - }, - "component" : [ - { - "code" : { - "coding" : [ - { - "code" : "HKElectrocardiogram.NumberOfVoltageMeasurements", - "display" : "Electrocardiogram Number of Voltage Measurements", - "system" : "http://developer.apple.com/documentation/healthkit" - } - ] - }, - "valueQuantity" : { - "unit" : "measurements", - "value" : 22112 - } - }, - { - "code" : { - "coding" : [ - { - "code" : "HKElectrocardiogram.SamplingFrequency", - "display" : "Sampling Frequency", - "system" : "http://developer.apple.com/documentation/healthkit" - } - ] - }, - "valueQuantity" : { - "code" : "hertz", - "system" : "http://unitsofmeasure.org", - "unit" : "hertz", - "value" : 512 - } - }, - { - "code" : { - "coding" : [ - { - "code" : "HKElectrocardiogram.Classification", - "display" : "Electrocardiogram Classification", - "system" : "http://developer.apple.com/documentation/healthkit" - } - ] - }, - "valueString" : "sinusRhythm" - }, - { - "code" : { - "coding" : [ - { - "code" : "8867-4", - "display" : "Heart rate", - "system" : "http://loinc.org" - }, - { - "code" : "HKQuantityTypeIdentifierHeartRate", - "display" : "Heart Rate", - "system" : "http://developer.apple.com/documentation/healthkit" - } - ] - }, - "valueQuantity" : { - "code" : "/min", - "system" : "http://unitsofmeasure.org", - "unit" : "beats/minute", - "value" : 140 - } - }, - { - "code" : { - "coding" : [ - { - "code" : "HKElectrocardiogram.SymptomsStatus", - "display" : "Electrocardiogram Symptoms Status", - "system" : "http://developer.apple.com/documentation/healthkit" - } - ] - }, - "valueString" : "present" - }, - { - "code" : { - "coding" : [ - { - "code" : "HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat", - "display" : "Rapid Pounding Or Fluttering Heartbeat", - "system" : "http://developer.apple.com/documentation/healthkit" - } - ] - }, - "valueString" : "unspecified" - }, - { - "code" : { - "coding" : [ - { - "code" : "HKCategoryTypeIdentifierFatigue", - "display" : "Fatigue", - "system" : "http://developer.apple.com/documentation/healthkit" - } - ] - }, - "valueString" : "unspecified" - }, - { - "code" : { - "coding" : [ - { - "code" : "131329", - "display" : "MDC_ECG_ELEC_POTL_I", - "system" : "urn:oid:2.16.840.1.113883.6.24" - } - ] - }, - "valueSampledData" : { - "data" : "-122.59088134765625 -262.6523132324219 -398.10791015625 -517.7991333007812 ....", - "dimensions" : 1, - "origin" : { - "code" : "uV", - "system" : "http://unitsofmeasure.org", - "unit" : "uV", - "value" : 0 - }, - "period" : 0.00195303667126447232 - } - } - ], - "effectivePeriod" : { - "end" : "2022-12-20T01:41:00-08:00", - "start" : "2022-12-20T01:41:43.1875-08:00" - }, - "identifier" : [ - { - "id" : "E3E98DA2-7124-4567-93CB-0B52647EA332" - } - ], - "issued" : "2022-12-20T19:14:52.072656035-08:00", - "resourceType" : "Observation", - "status" : "final" -} diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/ECGObservation.json.license b/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/ECGObservation.json.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/ECGObservation.json.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/en.lproj/Localizable.strings b/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/en.lproj/Localizable.strings deleted file mode 100644 index 07ef31cd..00000000 --- a/PAWSModules/Sources/PAWSMockDataStorageProvider/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,13 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -// MARK: - Mock Upload Data Storage Provider -"MOCK_UPLOAD_LIST_PLACEHOLDER" = "No recordings have been uploaded yet."; -"MOCK_UPLOAD_LIST_TITLE" = "Reports"; -"MOCK_UPLOAD_DETAIL_HEADER" = "Upload Header"; -"MOCK_UPLOAD_DETAIL_BODY" = "Upload Details"; diff --git a/PAWSModules/Sources/PAWSNotificationScreen/Notification.swift b/PAWSModules/Sources/PAWSNotificationScreen/Notification.swift deleted file mode 100644 index f12baefb..00000000 --- a/PAWSModules/Sources/PAWSNotificationScreen/Notification.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -struct Notification: View { - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .yellow], - startPoint: .leading, - endPoint: .trailing - ) - - - var body: some View { - VStack(alignment: .leading) { - Text("February 8th, 2023") - .font(.title3) - .fontWeight(.bold) - .foregroundColor(.gray) - VStack(alignment: .leading) { - VStack(alignment: .leading, spacing: 8) { - Text("ECG Recording") - .font(.headline) - .padding([.leading, .trailing, .top], 20) - .fontWeight(.bold) - - Text("12:30 PM") - .font(.subheadline) - .padding([.leading, .trailing], 20) - } - - Divider() - HStack { - Text("Recording successfully uploaded") - .font(.callout) - .padding() - Image(systemName: "checkmark.circle.fill") - .foregroundColor(.green) - } - } - .frame(width: 320) - .opacity(0.9) - .border(backgroundGradient, width: 5) - .cornerRadius(10) - .shadow(radius: 10) - } - } -} - - -struct Notification_Previews: PreviewProvider { - static var previews: some View { - Notification() - } -} diff --git a/PAWSModules/Sources/PAWSNotificationScreen/NotificationScreen.swift b/PAWSModules/Sources/PAWSNotificationScreen/NotificationScreen.swift deleted file mode 100644 index 310a8802..00000000 --- a/PAWSModules/Sources/PAWSNotificationScreen/NotificationScreen.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SwiftUI - - -public struct NotificationScreen: View { - public var body: some View { - ScrollView(.vertical) { - VStack(alignment: .leading) { - Text("Notifications") - .font(.title) - .fontWeight(.bold) - .padding([.top, .bottom], 20) - Notification() - Notification() - Notification() - Notification() - } - } - } - - - public init() {} -} - - -struct NotificationScreen_Previews: PreviewProvider { - static var previews: some View { - NotificationScreen() - } -} diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/AccountSetup.swift b/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/AccountSetup.swift deleted file mode 100644 index b07c76dd..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/AccountSetup.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// This source file is part of the Stanford CardinalKit PAWS Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Account -import class FHIR.FHIR -import FirebaseAccount -import FirebaseAuth -import FirebaseFirestore -import Onboarding -import SwiftUI - - -struct AccountSetup: View { - @Binding private var onboardingSteps: [OnboardingFlow.Step] - @EnvironmentObject var account: Account - private let backgroundGradient = LinearGradient( - colors: [.red, .pink, .orange, .yellow], - startPoint: .leading, - endPoint: .trailing - ) - - var body: some View { - OnboardingView( - contentView: { - VStack { - OnboardingTitleView( - title: "ACCOUNT_TITLE".moduleLocalized, - subtitle: "ACCOUNT_SUBTITLE".moduleLocalized - ) - Spacer(minLength: 0) - accountImage - accountDescription - Spacer(minLength: 0) - } - }, actionView: { - actionView - } - ) - .onReceive(account.objectWillChange) { - if account.signedIn { - onboardingSteps.append(.healthKitPermissions) - - if let user = Auth.auth().currentUser { - let uid = user.uid - let name = user.displayName?.components(separatedBy: " ") - let firstName = name?[0] ?? "" - let lastName = name?[1] ?? "" - let data: [String: Any] = ["firstName": firstName, "id": uid, "lastName": lastName] - Firestore.firestore().collection("users").document(uid).setData(data) { err in - if let err = err { - print("Error updating document: \(err)") - } - } - } - // Unfortunately, SwiftUI currently animates changes in the navigation path that do not change - // the current top view. Therefore we need to do the following async procedure to remove the - // `.login` and `.signUp` steps while disabling the animations before and re-enabling them - // after the elements have been changed. - Task { @MainActor in - try? await Task.sleep(for: .seconds(1.0)) - UIView.setAnimationsEnabled(false) - onboardingSteps.removeAll(where: { $0 == .login || $0 == .signUp }) - try? await Task.sleep(for: .seconds(1.0)) - UIView.setAnimationsEnabled(true) - } - } - } - } - - @ViewBuilder private var accountImage: some View { - Group { - if account.signedIn { - backgroundGradient - .mask( - Image(systemName: "pawprint.circle.fill") - ) - } else { - backgroundGradient - .mask( - VStack { - Image(systemName: "pawprint.circle") - } - ) - } - } - .font(.system(size: 150)) - .foregroundColor(.accentColor) - } - - @ViewBuilder private var accountDescription: some View { - VStack { - Group { - if account.signedIn { - Text("ACCOUNT_SIGNED_IN_DESCRIPTION", bundle: .module) - } else { - Text("ACCOUNT_SETUP_DESCRIPTION", bundle: .module) - } - } - .multilineTextAlignment(.center) - .padding(.vertical, 16) - if account.signedIn { - UserView() - .padding() - } - } - } - - @ViewBuilder private var actionView: some View { - if account.signedIn { - OnboardingActionsView( - "ACCOUNT_NEXT".moduleLocalized, - action: { - onboardingSteps.append(.healthKitPermissions) - } - ) - } else { - OnboardingActionsView( - primaryText: "ACCOUNT_SIGN_UP".moduleLocalized, - primaryAction: { - onboardingSteps.append(.signUp) - }, - secondaryText: "ACCOUNT_LOGIN".moduleLocalized, - secondaryAction: { - onboardingSteps.append(.login) - } - ) - } - } - - - init(onboardingSteps: Binding<[OnboardingFlow.Step]>) { - self._onboardingSteps = onboardingSteps - } -} - - -#if DEBUG -struct AccountSetup_Previews: PreviewProvider { - @State private static var path: [OnboardingFlow.Step] = [] - - - static var previews: some View { - AccountSetup(onboardingSteps: $path) - .environmentObject(Account(accountServices: [])) - .environmentObject(FirebaseAccountConfiguration(emulatorSettings: (host: "localhost", port: 9099))) - } -} -#endif diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/IconView.swift b/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/IconView.swift deleted file mode 100644 index 2216d8d0..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/IconView.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// This source file is part of the Stanford CardinalKit PAWS Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import PAWSSharedContext -import SwiftUI - - -struct IconView: View { - let size: Double - - - var body: some View { - Image(uiImage: Bundle.module.image(withName: "AppIcon", fileExtension: "png")) - .resizable() - .scaledToFill() - .accessibilityLabel(Text("App Icon")) - .frame(width: size, height: size) - .clipShape(RoundedRectangle(cornerRadius: size / 5)) - .shadow(color: Color(.systemGray4), radius: 4, x: 0, y: 4) - .padding(.bottom) - } - - - init(size: Double = 150) { - self.size = size - } -} - - -#if DEBUG -struct IconView_Previews: PreviewProvider { - static var previews: some View { - ZStack { - Color(.secondarySystemBackground) - IconView(size: 100) - } - } -} -#endif diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/PAWSLogin.swift b/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/PAWSLogin.swift deleted file mode 100644 index 39a711e8..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/PAWSLogin.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// This source file is part of the Stanford CardinalKit PAWS Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Account -import Onboarding -import SwiftUI - - -struct PAWSLogin: View { - var body: some View { - Login { - IconView() - .padding(.top, 32) - Text("LOGIN_SUBTITLE", bundle: .module) - .multilineTextAlignment(.center) - .padding() - .padding() - Spacer(minLength: 0) - } - .navigationBarTitleDisplayMode(.large) - } -} - - -#if DEBUG -struct PAWSLogin_Previews: PreviewProvider { - static var previews: some View { - PAWSLogin() - .environmentObject(Account(accountServices: [])) - } -} -#endif diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/PAWSSignUp.swift b/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/PAWSSignUp.swift deleted file mode 100644 index 914a7c93..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/PAWSSignUp.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// This source file is part of the Stanford CardinalKit PAWS Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Account -import Onboarding -import SwiftUI - - -struct PAWSSignUp: View { - var body: some View { - SignUp { - IconView() - .padding(.top, 32) - Text("SIGN_UP_SUBTITLE", bundle: .module) - .multilineTextAlignment(.center) - .padding() - Spacer(minLength: 0) - } - .navigationBarTitleDisplayMode(.large) - } -} - - -#if DEBUG -struct PAWSSignUp_Previews: PreviewProvider { - static var previews: some View { - PAWSSignUp() - .environmentObject(Account(accountServices: [])) - } -} -#endif diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/UserView.swift b/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/UserView.swift deleted file mode 100644 index 89abc2e7..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/AccountSetup/UserView.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// This source file is part of the Stanford CardinalKit PAWS Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Account -import class FHIR.FHIR -import FirebaseAccount -import Foundation -import SwiftUI -import Views - - -struct UserView: View { - @EnvironmentObject var account: Account - @EnvironmentObject var firebaseAccountConfiguration: FirebaseAccountConfiguration - - var body: some View { - userInformation - .padding() - .background( - RoundedRectangle(cornerRadius: 8) - .fill(Color(.systemBackground)) - .shadow(color: .gray, radius: 2) - ) - } - - - @ViewBuilder private var userInformation: some View { - HStack(spacing: 16) { - if account.signedIn, - let user = firebaseAccountConfiguration.user, - let displayName = user.displayName, - let name = try? PersonNameComponents(displayName) { - UserProfileView(name: name) - .frame(height: 30) - VStack(alignment: .leading, spacing: 4) { - Text(name.formatted(.name(style: .medium))) - if let email = user.email { - Text(email) - } - } - Spacer() - } else { - Spacer() - VStack(spacing: 16) { - ProgressView() - Text("USER_VIEW_LOADING", bundle: .module) - .multilineTextAlignment(.center) - } - Spacer() - } - } - } -} - - -#if DEBUG -struct SwiftUIView_Previews: PreviewProvider { - static var previews: some View { - UserView() - .padding() - .environmentObject(FirebaseAccountConfiguration(emulatorSettings: (host: "localhost", port: 9099))) - } -} -#endif diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/Consent.swift b/PAWSModules/Sources/PAWSOnboardingFlow/Consent.swift deleted file mode 100644 index 38aa36ac..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/Consent.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Onboarding -import PAWSSharedContext -import SwiftUI - - -struct Consent: View { - @Binding private var onboardingSteps: [OnboardingFlow.Step] - - - private var consentDocument: Data { - guard let path = Bundle.module.url(forResource: "ConsentDocument", withExtension: "md"), - let data = try? Data(contentsOf: path) else { - return Data("CONSENT_LOADING_ERROR".moduleLocalized.utf8) - } - return data - } - - var body: some View { - VStack { - Image(systemName: "pawprint.circle.fill") - .resizable() - .scaledToFill() - .frame(width: 80, height: 80) - .foregroundColor(.red) - .offset(y: 10) - ConsentView( - header: { - OnboardingTitleView( - title: "CONSENT_TITLE".moduleLocalized, - subtitle: "CONSENT_SUBTITLE".moduleLocalized - ) - }, - - asyncMarkdown: { - consentDocument - }, - action: { - if !FeatureFlags.disableFirebase { - onboardingSteps.append(.accountSetup) - } else { - onboardingSteps.append(.healthKitPermissions) - } - } - ) - .offset(y: -20) - } - } - - - init(onboardingSteps: Binding<[OnboardingFlow.Step]>) { - self._onboardingSteps = onboardingSteps - } -} - - -struct Consent_Previews: PreviewProvider { - @State private static var path: [OnboardingFlow.Step] = [] - - - static var previews: some View { - Consent(onboardingSteps: $path) - } -} diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/HealthKitPermissions.swift b/PAWSModules/Sources/PAWSOnboardingFlow/HealthKitPermissions.swift deleted file mode 100644 index 192e170c..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/HealthKitPermissions.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import FHIR -import HealthKitDataSource -import Onboarding -import PAWSSharedContext -import SwiftUI - - -struct HealthKitPermissions: View { - @EnvironmentObject var healthKitDataSource: HealthKit - @Binding var onboardingSteps: [OnboardingFlow.Step] - - - var body: some View { - OnboardingView( - contentView: { - VStack { - Image(systemName: "pawprint.circle.fill") - .resizable() - .scaledToFill() - .frame(width: 40, height: 40) - .foregroundColor(.red) - .offset(y: 20) - OnboardingTitleView( - title: "HEALTHKIT_PERMISSIONS_TITLE".moduleLocalized, - subtitle: "HEALTHKIT_PERMISSIONS_SUBTITLE".moduleLocalized - ) - Spacer() - Image(systemName: "heart.text.square.fill") - .font(.system(size: 150)) - .foregroundColor(.accentColor) - Text("HEALTHKIT_PERMISSIONS_DESCRIPTION", bundle: .module) - .multilineTextAlignment(.center) - .padding(.vertical, 16) - Spacer() - } - }, actionView: { - OnboardingActionsView( - "HEALTHKIT_PERMISSIONS_BUTTON".moduleLocalized, - action: { - do { - try await healthKitDataSource.askForAuthorization() - } catch { - print("Could not request HealthKit permissions.") - } - onboardingSteps.append(.notificationSetup) - } - ) - } - ) - } -} - - -struct HealthKitPermissions_Previews: PreviewProvider { - @State private static var path: [OnboardingFlow.Step] = [] - - - static var previews: some View { - HealthKitPermissions(onboardingSteps: $path) - } -} diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/InterestingModules.swift b/PAWSModules/Sources/PAWSOnboardingFlow/InterestingModules.swift deleted file mode 100644 index 00165057..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/InterestingModules.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Onboarding -import SwiftUI - - -struct InterestingModules: View { - @Binding private var onboardingSteps: [OnboardingFlow.Step] - - - var body: some View { - VStack { - Image(systemName: "pawprint.circle.fill") - .resizable() - .scaledToFill() - .frame(width: 40, height: 40) - .foregroundColor(.red) - .offset(y: 20) - SequentialOnboardingView( - title: "INTERESTING_MODULES_TITLE".moduleLocalized, - subtitle: "INTERESTING_MODULES_SUBTITLE".moduleLocalized, - content: [ - .init( - title: "INTERESTING_MODULES_AREA1_TITLE".moduleLocalized, - description: "INTERESTING_MODULES_AREA1_DESCRIPTION".moduleLocalized - ), - .init( - title: "INTERESTING_MODULES_AREA2_TITLE".moduleLocalized, - description: "INTERESTING_MODULES_AREA2_DESCRIPTION".moduleLocalized - ), - .init( - title: "INTERESTING_MODULES_AREA3_TITLE".moduleLocalized, - description: "INTERESTING_MODULES_AREA3_DESCRIPTION".moduleLocalized - ) - ], - actionText: "INTERESTING_MODULES_BUTTON".moduleLocalized, - action: { - #if targetEnvironment(simulator) && (arch(i386) || arch(x86_64)) - print("PKCanvas view-related views are currently skipped on Intel-based iOS simulators due to a metal bug on the simulator.") - onboardingSteps.append(.accountSetup) - #else - onboardingSteps.append(.consent) - #endif - } - ) - } - } - - - init(onboardingSteps: Binding<[OnboardingFlow.Step]>) { - self._onboardingSteps = onboardingSteps - } -} - - -struct ThingsToKnow_Previews: PreviewProvider { - @State private static var path: [OnboardingFlow.Step] = [] - - - static var previews: some View { - InterestingModules(onboardingSteps: $path) - } -} diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/NotificationSetup.swift b/PAWSModules/Sources/PAWSOnboardingFlow/NotificationSetup.swift deleted file mode 100644 index 9d159402..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/NotificationSetup.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -// swiftlint:disable all - -import Onboarding -import PAWSSharedContext -import SwiftUI - -struct NotificationSetup: View { - @Binding var onboardingSteps: [OnboardingFlow.Step] - @AppStorage(StorageKeys.onboardingFlowComplete) var completedOnboardingFlow = false - @State private var date = Date() - @State private var selectedTime = Calendar.current.date(bySettingHour: 19, minute: 0, second: 0, of: Date())! - - var body: some View { - OnboardingView( - contentView: { - VStack { - Image(systemName: "pawprint.circle.fill") - .resizable() - .scaledToFill() - .frame(width: 40, height: 40) - .foregroundColor(.red) - .offset(y: 20) - OnboardingTitleView( - title: "NOTIFICATION_SETUP_TITLE".moduleLocalized, - subtitle: "NOTIFICATION_SETUP_SUBTITLE".moduleLocalized - ) - DatePicker("Select a time", selection: $selectedTime, displayedComponents: .hourAndMinute) - Image("NotificationImage") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 275, height: 275) - .padding(.vertical) - - } - }, actionView: { - OnboardingActionsView( - "ALLOW_NOTIFICATIONS_BUTTON".moduleLocalized, - action: { - notificationTrigger() - completedOnboardingFlow = true - } - ) - } - ) - } - - func notificationTrigger() { - let center = UNUserNotificationCenter.current() - center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in - if let error { - print("Error scheduling notification: \(error)") - } else { - let content = UNMutableNotificationContent() - content.title = "Friendly reminder to record your ECG!" - content.body = "Thank you for participating in the PAWS study!" - - // Configure the recurring date. - - let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: selectedTime) - - for index in 0...6 { - let scheduleDate = Date.now.addingTimeInterval(86400 * Double(index)) - guard let notificationDate = Calendar.current.nextDate(after: scheduleDate, matching: dateComponents, matchingPolicy: .nextTime) else { - continue - } - - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: notificationDate.timeIntervalSince(.now), repeats: false) - - - // Create the request - let uuidString = UUID().uuidString - let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger) - - // Schedule the request with the system. - let notificationCenter = UNUserNotificationCenter.current() - notificationCenter.add(request) { (error) in - if error != nil { - // Handle any errors. - } - } - } - } - } - } - -} diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/OnboardingFlow.swift b/PAWSModules/Sources/PAWSOnboardingFlow/OnboardingFlow.swift deleted file mode 100644 index c6aa9085..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/OnboardingFlow.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import PAWSSharedContext -import SwiftUI - - -/// Displays an multi-step onboarding flow for the CS342 2023 PAWS Team Application. -public struct OnboardingFlow: View { - enum Step: String, Codable { - case interestingModules - case consent - case accountSetup - case login - case signUp - case healthKitPermissions - case notificationSetup - } - - - @SceneStorage(StorageKeys.onboardingFlowStep) private var onboardingSteps: [Step] = [] - - - public var body: some View { - VStack { - NavigationStack(path: $onboardingSteps) { - Image(systemName: "pawprint.circle.fill") - .resizable() - .scaledToFill() - .frame(width: 40, height: 40) - .foregroundColor(.red) - .offset(y: 20) - Welcome(onboardingSteps: $onboardingSteps) - .navigationDestination(for: Step.self) { onboardingStep in - switch onboardingStep { - case .interestingModules: - InterestingModules(onboardingSteps: $onboardingSteps) - case .accountSetup: - AccountSetup(onboardingSteps: $onboardingSteps) - case .login: - PAWSLogin() - case .signUp: - PAWSSignUp() - case .consent: - Consent(onboardingSteps: $onboardingSteps) - case .healthKitPermissions: - HealthKitPermissions( onboardingSteps: $onboardingSteps) - case .notificationSetup: - NotificationSetup( onboardingSteps: $onboardingSteps) - } - } - .navigationBarTitleDisplayMode(.inline) - } - } - } - - - public init() {} -} - - -struct OnboardingFlow_Previews: PreviewProvider { - static var previews: some View { - OnboardingFlow() - } -} diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/AppIcon.png b/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/AppIcon.png deleted file mode 100644 index b2123dd1..00000000 Binary files a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/AppIcon.png and /dev/null differ diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/AppIcon.png.license b/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/AppIcon.png.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/AppIcon.png.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/ConsentDocument.md.license b/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/ConsentDocument.md.license deleted file mode 100644 index 9137ea9d..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/ConsentDocument.md.license +++ /dev/null @@ -1,6 +0,0 @@ - -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University - -SPDX-License-Identifier: MIT diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/Localizable.strings b/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/Localizable.strings deleted file mode 100644 index b54998d7..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,83 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -// MARK: - Onboarding - -// MARK: Welcome -"WELCOME_TITLE" = "Welcome to PAWS!"; -"WELCOME_SUBTITLE" = "We are excited to have you join the Pediatric Apple Watch Study (PAWS) to improve diagnosis of arrhythmias in patients like you! - -On this page, we'll walk through the app's main features. Next, you'll complete important onboarding information to confirm your participation in the study."; - -"WELCOME_AREA1_TITLE" = "Home Page"; -"WELCOME_AREA1_DESCRIPTION" = "On this page you'll be able to see your patient information and a summary of the ECG recordings uploaded from your Apple Watch "; - -"WELCOME_AREA2_TITLE" = "Reports"; -"WELCOME_AREA2_DESCRIPTION" = "On this page you'll be able to check if an ECG recording from your Apple Watch was successfully uploaded to the research server. "; - -"WELCOME_AREA3_TITLE" = "Study Information"; -"WELCOME_AREA3_DESCRIPTION" = "Learn more about the PAWS study and contact the lead researchers if you have any questions or concerns"; - -"WELCOME_BUTTON" = "Begin onboarding"; - -// MARK: Interesting Modules -"INTERESTING_MODULES_TITLE" = "PAWS Onboarding"; -"INTERESTING_MODULES_SUBTITLE" = "You'll need to complete a few more steps -to get started..."; - -"INTERESTING_MODULES_AREA1_TITLE" = "Create an account"; -"INTERESTING_MODULES_AREA1_DESCRIPTION" = "Create an account so researchers can identify you as a patient"; - -"INTERESTING_MODULES_AREA2_TITLE" = "Consent"; -"INTERESTING_MODULES_AREA2_DESCRIPTION" = "Give researchers consent to use your health data as part of the PAWS study"; - -"INTERESTING_MODULES_AREA3_TITLE" = "Grant access to health data "; -"INTERESTING_MODULES_AREA3_DESCRIPTION" = "Allow the PAWS app to access the health data recorded on your Apple Watch and iPhone"; - - - -"INTERESTING_MODULES_BUTTON" = "Next"; - - -// MARK: Consent -"CONSENT_TITLE" = "Consent Page"; -"CONSENT_SUBTITLE" = ""; - -"CONSENT_LOADING_ERROR" = "Please include a markdown based document named \"ConsentDocument\" in your module Bundle."; - - -// MARK: Account -"ACCOUNT_TITLE" = "Your PAWS Account"; -"ACCOUNT_SUBTITLE" = "Sign up for a new account or sign in to an existing account"; -"ACCOUNT_SETUP_DESCRIPTION" = "Select an option below"; -"ACCOUNT_SIGNED_IN_DESCRIPTION" = "You are successfully signed in with the following account:"; -"ACCOUNT_NEXT" = "Next"; -"ACCOUNT_SIGN_UP" = "Sign Up"; -"ACCOUNT_LOGIN" = "Login"; - -"USER_VIEW_LOADING" = "Loading user information ..."; - -"LOGIN_TITLE" = "Login"; -"LOGIN_SUBTITLE" = "Login to you existing PAWS account with a valid email and password."; - -"SIGN_UP_TITLE" = "Sign Up"; -"SIGN_UP_SUBTITLE" = "Sign up for a new PAWS account using a valid email and password"; - - -// MARK: HealthKit -"HEALTHKIT_PERMISSIONS_TITLE" = "Health Data Access"; -"HEALTHKIT_PERMISSIONS_SUBTITLE" = "PAWS requires access to your Health app data to collect ECG information including date of recording, average bpm, -reported symptoms, and any detected abnormalities. "; -"HEALTHKIT_PERMISSIONS_DESCRIPTION" = "On the next page you will be asked to grant access to the heart data from your Health app."; -"HEALTHKIT_PERMISSIONS_BUTTON" = "Grant Access"; - -// MARK: NOTIFICATIONS VIEW -"ALLOW_NOTIFICATIONS_BUTTON" = "Allow Notifications"; -"NOTIFICATION_SETUP_TITLE" = "Notifications"; -"NOTIFICATION_SETUP_SUBTITLE" = "Want to receive friendly reminders for the first week of the PAWS study? Choose your preferred time of day to receive notifications below and click allow."; - diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/String+ModuleLocalized.swift b/PAWSModules/Sources/PAWSOnboardingFlow/String+ModuleLocalized.swift deleted file mode 100644 index 08c953ed..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/String+ModuleLocalized.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -extension String { - var moduleLocalized: String { - String(localized: LocalizationValue(self), bundle: .module) - } -} diff --git a/PAWSModules/Sources/PAWSOnboardingFlow/Welcome.swift b/PAWSModules/Sources/PAWSOnboardingFlow/Welcome.swift deleted file mode 100644 index b1c5a623..00000000 --- a/PAWSModules/Sources/PAWSOnboardingFlow/Welcome.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Onboarding -import SwiftUI - - -struct Welcome: View { - @Binding private var onboardingSteps: [OnboardingFlow.Step] - - - var body: some View { - OnboardingView( - title: "WELCOME_TITLE".moduleLocalized, - subtitle: "WELCOME_SUBTITLE".moduleLocalized, - areas: [ - .init( - icon: Image(systemName: "house.fill"), - title: "WELCOME_AREA1_TITLE".moduleLocalized, - description: "WELCOME_AREA1_DESCRIPTION".moduleLocalized - ), - .init( - icon: Image(systemName: "bell.badge"), - title: "WELCOME_AREA2_TITLE".moduleLocalized, - description: "WELCOME_AREA2_DESCRIPTION".moduleLocalized - ), - .init( - icon: Image(systemName: "list.bullet.clipboard.fill"), - title: "WELCOME_AREA3_TITLE".moduleLocalized, - description: "WELCOME_AREA3_DESCRIPTION".moduleLocalized - ) - ], - actionText: "WELCOME_BUTTON".moduleLocalized, - action: { - onboardingSteps.append(.interestingModules) - } - ) - } - - - init(onboardingSteps: Binding<[OnboardingFlow.Step]>) { - self._onboardingSteps = onboardingSteps - } -} - - -struct Welcome_Previews: PreviewProvider { - @State private static var path: [OnboardingFlow.Step] = [] - - - static var previews: some View { - Welcome(onboardingSteps: $path) - } -} diff --git a/PAWSModules/Sources/PAWSSharedContext/StorageKeys.swift b/PAWSModules/Sources/PAWSSharedContext/StorageKeys.swift deleted file mode 100644 index 1ce9eb77..00000000 --- a/PAWSModules/Sources/PAWSSharedContext/StorageKeys.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -/// Constants shared across the CardinalKit Teamplate Application to access storage information including the `AppStorage` and `SceneStorage` -public enum StorageKeys { - // MARK: - Onboarding - /// A `Bool` flag indicating of the onboarding was completed. - public static let onboardingFlowComplete = "onboardingFlow.complete" - /// A `Step` flag indicating the current step in the onboarding process. - public static let onboardingFlowStep = "onboardingFlow.step" - - - // MARK: - Home - /// The currently selected home tab. - public static let homeTabSelection = "home.tabselection" -} diff --git a/PAWSTests/PAWSTests.swift b/PAWSTests/PAWSTests.swift index c889a557..4322299c 100644 --- a/PAWSTests/PAWSTests.swift +++ b/PAWSTests/PAWSTests.swift @@ -1,5 +1,5 @@ // -// This source file is part of the CS342 2023 PAWS Team Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // diff --git a/PAWSUITests/ContactsTests.swift b/PAWSUITests/LaunchTests.swift similarity index 55% rename from PAWSUITests/ContactsTests.swift rename to PAWSUITests/LaunchTests.swift index 791734a9..70b4ee8c 100644 --- a/PAWSUITests/ContactsTests.swift +++ b/PAWSUITests/LaunchTests.swift @@ -1,5 +1,5 @@ // -// This source file is part of the CS342 2023 PAWS Team Application project +// This source file is part of the PAWS application based on the Stanford Spezi Template Application project // // SPDX-FileCopyrightText: 2023 Stanford University // @@ -9,7 +9,7 @@ import XCTest -class StudyInformationTests: XCTestCase { +class LaunchTests: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() @@ -21,10 +21,8 @@ class StudyInformationTests: XCTestCase { } - func testStudyInformation() throws { + func testApplicationLaunch() throws { let app = XCUIApplication() - - XCTAssertTrue(app.tabBars["Tab Bar"].buttons["Study Information"].waitForExistence(timeout: 2)) - app.tabBars["Tab Bar"].buttons["Study Information"].tap() + XCTAssertEqual(app.state, .runningForeground) } } diff --git a/PAWSUITests/NotificationsTests.swift b/PAWSUITests/NotificationsTests.swift deleted file mode 100644 index 70fe1e13..00000000 --- a/PAWSUITests/NotificationsTests.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import XCTest - - -class NotificationsTests: XCTestCase { - override func setUpWithError() throws { - try super.setUpWithError() - - continueAfterFailure = false - - let app = XCUIApplication() - app.launchArguments = ["--skipOnboarding"] - app.launch() - } - - - func testNotifications() throws { - let app = XCUIApplication() - - XCTAssertTrue(app.tabBars["Tab Bar"].buttons["Reports"].waitForExistence(timeout: 2)) - app.tabBars["Tab Bar"].buttons["Reports"].tap() - - app.swipeUp(velocity: .fast) - } -} diff --git a/PAWSUITests/OnboardingTests.swift b/PAWSUITests/OnboardingTests.swift deleted file mode 100644 index 1b4c2edd..00000000 --- a/PAWSUITests/OnboardingTests.swift +++ /dev/null @@ -1,164 +0,0 @@ -// -// This source file is part of the CS342 2023 PAWS Team Application project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import XCTest -import XCTestExtensions -import XCTHealthKit - - -class OnboardingTests: XCTestCase { - override func setUpWithError() throws { - try super.setUpWithError() - - try disablePasswordAutofill() - - continueAfterFailure = false - - let app = XCUIApplication() - app.launchArguments = ["--showOnboarding"] - app.deleteAndLaunch(withSpringboardAppName: "PAWS") - } - - - func testOnboardingFlow() throws { - let app = XCUIApplication() - - try app.navigateOnboardingFlow(assertThatHealthKitConsentIsShown: true) - - XCTAssertTrue(app.tabBars["Tab Bar"].waitForExistence(timeout: 2)) - XCTAssertTrue(app.tabBars["Tab Bar"].isHittable) - } -} - - -extension XCUIApplication { - func conductOnboardingIfNeeded() throws { - if buttons["Tap to get started"].waitForExistence(timeout: 2) { - try navigateOnboardingFlow(assertThatHealthKitConsentIsShown: false) - } - } - - func navigateOnboardingFlow(assertThatHealthKitConsentIsShown: Bool = true) throws { - try navigateOnboardingGetStarted() - try navigateOnboardingFlowWelcome() - try navigateOnboardingFlowInterestingModules() - if staticTexts["Consent Page"].waitForExistence(timeout: 2) { - try navigateOnboardingFlowConsent() - } - try navigateOnboardingAccount() - try healthKitPermissions() - try notificationPermissions() - } - - private func navigateOnboardingGetStarted() throws { - XCTAssertTrue(buttons["Tap to get started"].waitForExistence(timeout: 2)) - buttons["Tap to get started"].tap() - } - - private func navigateOnboardingFlowWelcome() throws { - XCTAssertTrue(staticTexts["Welcome to PAWS!"].waitForExistence(timeout: 2)) - - swipeUp() - - XCTAssertTrue(buttons["Begin onboarding"].waitForExistence(timeout: 2)) - buttons["Begin onboarding"].tap() - } - - private func navigateOnboardingFlowInterestingModules() throws { - XCTAssertTrue(staticTexts["PAWS Onboarding"].waitForExistence(timeout: 2)) - - for _ in 1..<3 { - XCTAssertTrue(buttons["Next"].waitForExistence(timeout: 2)) - buttons["Next"].tap() - } - - XCTAssertTrue(buttons["Next"].waitForExistence(timeout: 2)) - buttons["Next"].tap() - } - - private func navigateOnboardingFlowConsent() throws { - XCTAssertTrue(staticTexts["Consent Page"].waitForExistence(timeout: 2)) - - swipeUp(velocity: .fast) - - XCTAssertTrue(staticTexts["First Name"].waitForExistence(timeout: 2)) - try textFields["Enter your first name ..."].enter(value: "Leland") - - XCTAssertTrue(staticTexts["Last Name"].waitForExistence(timeout: 2)) - try textFields["Enter your last name ..."].enter(value: "Stanford") - swipeUp() - - XCTAssertTrue(staticTexts["Leland Stanford"].waitForExistence(timeout: 2)) - staticTexts["Leland Stanford"].firstMatch.swipeUp() - - XCTAssertTrue(buttons["I Consent"].waitForExistence(timeout: 2)) - buttons["I Consent"].tap() - } - - private func navigateOnboardingAccount() throws { - XCTAssertTrue(staticTexts["Your PAWS Account"].waitForExistence(timeout: 2)) - - guard !buttons["Next"].waitForExistence(timeout: 5) else { - buttons["Next"].tap() - return - } - - XCTAssertTrue(buttons["Sign Up"].waitForExistence(timeout: 2)) - buttons["Sign Up"].tap() - - XCTAssertTrue(navigationBars.staticTexts["Sign Up"].waitForExistence(timeout: 2)) - XCTAssertTrue(images["App Icon"].waitForExistence(timeout: 2)) - XCTAssertTrue(buttons["Email and Password"].waitForExistence(timeout: 2)) - - buttons["Email and Password"].tap() - - try textFields["Enter your email ..."].enter(value: "leland@stanford.edu") - swipeUp() - - try secureTextFields["Enter your password ..."].enter(value: "StanfordRocks") - swipeUp() - try secureTextFields["Repeat your password ..."].enter(value: "StanfordRocks") - swipeUp() - - try textFields["Enter your first name ..."].enter(value: "Leland") - staticTexts["Repeat\nPassword"].swipeUp() - - try textFields["Enter your last name ..."].enter(value: "Stanford") - staticTexts["Repeat\nPassword"].swipeUp() - - XCTAssertTrue(collectionViews.buttons["Sign Up"].waitForExistence(timeout: 2)) - collectionViews.buttons["Sign Up"].tap() - - sleep(5) - } - - private func healthKitPermissions() throws { - XCTAssertTrue(buttons["Grant Access"].waitForExistence(timeout: 2)) - buttons["Grant Access"].tap() - - try handleHealthKitAuthorization() - } - - private func notificationPermissions() throws { - XCTAssertTrue(staticTexts["Notifications"].waitForExistence(timeout: 5)) - - swipeUp() - - XCTAssertTrue(buttons["Allow Notifications"].waitForExistence(timeout: 2)) - buttons["Allow Notifications"].tap() - - - let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") - let alertAllowButton = springboard.buttons["Allow"] - if alertAllowButton.waitForExistence(timeout: 5) { - alertAllowButton.tap() - } else { - print("Did not observe the notification permissions alert. Permissions might have already been provided.") - } - } -} diff --git a/README.md b/README.md index 4de5285f..320d4422 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# CS342 2023 PAWS Team Application +# PAWS -This repository contains the CS342 2023 PAWS Team Application. +This repository contains the PAWS. +The PAWS is using the [Spezi](https://github.com/StanfordSpezi/Spezi) ecosystem and builds on top of the [Stanford Spezi Template Application](https://github.com/StanfordSpezi/SpeziTemplateApplication). -It demonstrates using the [CardinalKit](https://github.com/StanfordBDHG/CardinalKit) framework template and builds on top of the [StanfordBDHG Template Application](https://github.com/StanfordBDHG/PAWS) and [StanfordBDHG CardinalKit Template Application](https://github.com/StanfordBDHG/CardinalKitPAWS). +> [!NOTE]  +> Do you want to learn more about the Stanford Spezi Template Application and how to use, extend, and modify this application? Check out the [Stanford Spezi Template Application documentation](https://stanfordspezi.github.io/SpeziTemplateApplication) -## Application Structure +## PAWS Features -The application uses a modularized structure enabled by using the Swift Package Manager. +*Provide a comprehensive description of your application, including figures showing the application. You can learn more on how to structure a README in the [Stanford Spezi Documentation Guide](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/documentation-guide)* -The application uses the CardinalKit `FHIR` standard to provide a shared repository for data exchanged between different modules using the `FHIR` standard. -You can learn more about the CardinalKit standards-based software architecture in the [CardinalKit documentation](https://github.com/StanfordBDHG/CardinalKit). +## Contributing -## Build and Run the Application +*Ensure that you add an adequate contribution section to this README.* -You can build and run the application using [Xcode](https://developer.apple.com/xcode/) by opening up the **PAWS.xcodeproj**. -The application provides a [Firebase Firestore](https://firebase.google.com/docs/firestore)-based data upload and [Firebase Authentication](https://firebase.google.com/docs/auth) login & sign-up. -It is required to have the [Firebase Emulator Suite](https://firebase.google.com/docs/emulator-suite) to be up and running to use these features to build and test the application locally. Please follow the [installation instructions](https://firebase.google.com/docs/emulator-suite/install_and_configure). +## License -You do not have to make any modifications to the Firebase configuration, login into the `firebase` CLI using your Google account, or create a project in firebase to run, build, and test the application! - -Startup the [Firebase Emulator Suite](https://firebase.google.com/docs/emulator-suite) using -``` -$ firebase emulators:start --only auth,firestore -``` - -After the emulators have started up, you can run the application in your simulator to build, test, and run the application. - -The application includes the following feature flags that can be configured in the [scheme editor in Xcode](https://help.apple.com/xcode/mac/11.4/index.html?localePath=en.lproj#/dev0bee46f46) and selecting the **PAWS** scheme, the **Run** configuration, and to switch to the **Arguments** tab to add, enable, disable, or remove the following arguments passed on launch: -- ``--skipOnboarding``: Skips the onboarding flow to enable easier development of features in the application and to allow UI tests to skip the onboarding flow. -- ``--showOnboarding``: Always show the onboarding when the application is launched. Makes it easy to modify and test the onboarding flow without the need to manually remove the application or reset the simulator. -- ``--disableFirebase``: Disables the Firebase interactions, including the login/sign-up step and the Firebase Firestore upload. -- ``--useFirebaseEmulator``: Defines if the application should connect to the local firebase emulator. Always set to true when using the iOS simulator. - - -## Continous Delivery Workflows - -The application includes continuous integration (CI) and continuous delivery (CD) setup. -- Automatically build and test the application on every pull request before deploying it. -- An automated setup to deploy the application to TestFlight every time there is a new commit on the repository's main branch. -- Ensure a coherent code style by checking the conformance to the SwiftLint rules defined in `.swiftlint.yml` on every pull request and commit. -- Ensure conformance to the [REUSE Spacification]() to property license the application and all related code. - -Please refer to the [StanfordBDHG Template Application](https://github.com/StanfordBDHG/PAWS) and the [ContinousDelivery Example by Paul Schmiedmayer](https://github.com/PSchmiedmayer/ContinousDelivery) for more background about the CI and CD setup for the CardinalKit Template Application. - - -## Contributors & License - -This project is based on [ContinousDelivery Example by Paul Schmiedmayer](https://github.com/PSchmiedmayer/ContinousDelivery), [StanfordBDHG Template Application](https://github.com/StanfordBDHG/PAWS), and the [StanfordBDHG CardinalKit Template Application](https://github.com/StanfordBDHG/CardinalKitPAWS) provided using the MIT license. -You can find a list of contributors in the `CONTRIBUTORS.md` file. - -The CS342 2023 PAWS Team Application is licensed under the MIT license. +This project is licensed under the MIT License. See [Licenses](LICENSES) for more information. diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..c971049f --- /dev/null +++ b/codecov.yml @@ -0,0 +1,40 @@ +# +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project +# +# SPDX-FileCopyrightText: 2023 Stanford University +# +# SPDX-License-Identifier: MIT +# + +codecov: + branch: main + require_ci_to_pass: true +comment: + behavior: default + layout: reach,diff,flags,files,footer + require_changes: false +coverage: + precision: 2 + range: + - 70.0 + - 90.0 + round: up + status: + patch: + default: + target: auto + threshold: 5.0 + project: + default: + target: auto + threshold: 5.0 +ignore: +- ^PAWSUITests.* +- ^PAWSTests.* +parsers: + gcov: + branch_detection: + conditional: true + loop: true + macro: false + method: false diff --git a/fastlane/.gitignore b/fastlane/.gitignore index 2ed5baae..f7cdaa40 100644 --- a/fastlane/.gitignore +++ b/fastlane/.gitignore @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # diff --git a/fastlane/Appfile b/fastlane/Appfile index 8ed7f70f..1acbe6c3 100644 --- a/fastlane/Appfile +++ b/fastlane/Appfile @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 42547fac..8a6591c3 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -1,5 +1,5 @@ # -# This source file is part of the CS342 2023 PAWS Team Application project +# This source file is part of the PAWS application based on the Stanford Spezi Template Application project # # SPDX-FileCopyrightText: 2023 Stanford University # @@ -17,17 +17,41 @@ platform :ios do desc "Build and test" lane :test do run_tests( - code_coverage: true, + skip_build: true, derived_data_path: ".derivedData", + code_coverage: true, + devices: ["iPhone 15 Pro"], + force_quit_simulator: true, + reset_simulator: true, + prelaunch_simulator: false, + concurrent_workers: 1, + max_concurrent_simulators: 1, result_bundle: true, - output_directory: "." + output_directory: ".", + xcargs: "-skipPackagePluginValidation -skipMacroValidation" + ) + end + + desc "CodeQL" + lane :codeql do + build_app( + skip_archive: true, + skip_codesigning: true, + derived_data_path: ".derivedData", + xcargs: "-skipPackagePluginValidation -skipMacroValidation" ) end desc "Build app" lane :build do build_app( - derived_data_path: ".derivedData" + derived_data_path: ".derivedData", + xcargs: "-skipPackagePluginValidation", + export_options: { + provisioningProfiles: { + "edu.stanford.cs342.2023.paws" => "CS342 2023 PAWS Team Application" + } + } ) end @@ -44,16 +68,17 @@ platform :ios do desc "Publish a beta release to internal TestFlight testers" lane :beta do signin - increment_build_number({ - build_number: latest_testflight_build_number + 1, - xcodeproj: "PAWS.xcodeproj" - }) + increment_build_number( + { + build_number: latest_testflight_build_number + 1 + } + ) build commit = last_git_commit upload_to_testflight( distribute_external: true, groups: [ - "CS342 2023" + "External Testers" ], submit_beta_review: true, notify_external_testers: true, diff --git a/fastlane/Gymfile b/fastlane/Gymfile deleted file mode 100644 index 928c1c10..00000000 --- a/fastlane/Gymfile +++ /dev/null @@ -1,25 +0,0 @@ -# -# This source file is part of the CS342 2023 PAWS Team Application project -# -# SPDX-FileCopyrightText: 2023 Stanford University -# -# SPDX-License-Identifier: MIT -# - -# For more information about this configuration visit -# https://docs.fastlane.tools/actions/gym/#gymfile - -# In general, you can use the options available -# fastlane gym --help - -scheme("PAWS") - -project("PAWS.xcodeproj") - -export_options( - { - provisioningProfiles: { - "edu.stanford.cs342.2023.paws" => "CS342 2023 PAWS Team Application" - } - } -) \ No newline at end of file diff --git a/fastlane/README.md b/fastlane/README.md index c13a4f42..140582f7 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -23,6 +23,14 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do Build and test +### ios codeql + +```sh +[bundle exec] fastlane ios codeql +``` + +CodeQL + ### ios build ```sh diff --git a/fastlane/README.md.license b/fastlane/README.md.license index 9137ea9d..4f324d88 100644 --- a/fastlane/README.md.license +++ b/fastlane/README.md.license @@ -1,5 +1,5 @@ -This source file is part of the CS342 2023 PAWS Team Application project +This source file is part of the PAWS application based on the Stanford Spezi Template Application project SPDX-FileCopyrightText: 2023 Stanford University diff --git a/fastlane/Scanfile b/fastlane/Scanfile deleted file mode 100644 index e93c505a..00000000 --- a/fastlane/Scanfile +++ /dev/null @@ -1,18 +0,0 @@ -# -# This source file is part of the CS342 2023 PAWS Team Application project -# -# SPDX-FileCopyrightText: 2023 Stanford University -# -# SPDX-License-Identifier: MIT -# - -# For more information about this configuration visit -# https://docs.fastlane.tools/actions/scan/#scanfile - -# In general, you can use the options available -# fastlane scan --help - -project("PAWS.xcodeproj") -scheme("PAWS") -devices(["iPhone 14 Pro"]) -skip_build(true) diff --git a/firebase.json b/firebase.json index 74e41027..0b85064f 100644 --- a/firebase.json +++ b/firebase.json @@ -2,6 +2,9 @@ "firestore": { "rules": "firestore.rules" }, + "storage": { + "rules": "firebasestorage.rules" + }, "emulators": { "auth": { "port": 9099 @@ -13,6 +16,9 @@ "enabled": true, "port": 4000 }, + "storage": { + "port": 9199 + }, "singleProjectMode": true } -} +} \ No newline at end of file diff --git a/firebase.json.license b/firebase.json.license index 9137ea9d..c310108a 100644 --- a/firebase.json.license +++ b/firebase.json.license @@ -1,6 +1,5 @@ +This source file is part of the PAWS application based on the Stanford Spezi Template Application project -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University +SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) SPDX-License-Identifier: MIT diff --git a/firebasestorage.rules b/firebasestorage.rules new file mode 100644 index 00000000..18a3bd29 --- /dev/null +++ b/firebasestorage.rules @@ -0,0 +1,12 @@ +rules_version = '2'; +service firebase.storage { + match /b/{bucket}/o { + match /users/{userId}/{allPaths=**} { + allow read, write: if request.auth != null && request.auth.uid == userId; + } + + match /{allPaths=**} { + allow read, write: if false; + } + } +} diff --git a/firebasestorage.rules.license b/firebasestorage.rules.license new file mode 100644 index 00000000..c310108a --- /dev/null +++ b/firebasestorage.rules.license @@ -0,0 +1,5 @@ +This source file is part of the PAWS application based on the Stanford Spezi Template Application project + +SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) + +SPDX-License-Identifier: MIT diff --git a/firestore.rules b/firestore.rules index 6b4d87de..5a233b0d 100644 --- a/firestore.rules +++ b/firestore.rules @@ -1,8 +1,9 @@ +rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // Allow only authenticated content owners access match /users/{userId}/{documents=**} { - allow read, write: if request.auth != null && request.auth.uid == userId + allow read, write: if request.auth != null && request.auth.uid == userId; } } } diff --git a/firestore.rules.license b/firestore.rules.license index 9137ea9d..c310108a 100644 --- a/firestore.rules.license +++ b/firestore.rules.license @@ -1,6 +1,5 @@ +This source file is part of the PAWS application based on the Stanford Spezi Template Application project -This source file is part of the CS342 2023 PAWS Team Application project - -SPDX-FileCopyrightText: 2023 Stanford University +SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) SPDX-License-Identifier: MIT