diff --git a/TemplateApplication.xcodeproj/project.pbxproj b/TemplateApplication.xcodeproj/project.pbxproj index f1f79a30..7f88aa7a 100644 --- a/TemplateApplication.xcodeproj/project.pbxproj +++ b/TemplateApplication.xcodeproj/project.pbxproj @@ -3,11 +3,10 @@ archiveVersion = 1; classes = { }; - objectVersion = 55; + objectVersion = 63; objects = { /* Begin PBXBuildFile section */ - 27FA29902A388E9B009CAC45 /* ModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27FA298F2A388E9B009CAC45 /* ModalView.swift */; }; 2F1AC9DF2B4E840E00C24973 /* TemplateApplication.docc in Sources */ = {isa = PBXBuildFile; fileRef = 2F1AC9DE2B4E840E00C24973 /* TemplateApplication.docc */; }; 2F3D4ABC2A4E7C290068FB2F /* SpeziScheduler in Frameworks */ = {isa = PBXBuildFile; productRef = 2F3D4ABB2A4E7C290068FB2F /* SpeziScheduler */; }; 2F49B7762980407C00BCB272 /* Spezi in Frameworks */ = {isa = PBXBuildFile; productRef = 2F49B7752980407B00BCB272 /* Spezi */; }; @@ -25,7 +24,7 @@ 2FC3439029EE6346002D773C /* SocialSupportQuestionnaire.json in Resources */ = {isa = PBXBuildFile; fileRef = 2FE5DC5529EDD811004B9AB4 /* SocialSupportQuestionnaire.json */; }; 2FC3439129EE6349002D773C /* AppIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 2FE5DC2A29EDD78D004B9AB4 /* AppIcon.png */; }; 2FC3439229EE634B002D773C /* ConsentDocument.md in Resources */ = {isa = PBXBuildFile; fileRef = 2FE5DC2C29EDD78E004B9AB4 /* ConsentDocument.md */; }; - 2FC975A82978F11A00BA99FE /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC975A72978F11A00BA99FE /* Home.swift */; }; + 2FC975A82978F11A00BA99FE /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FC975A72978F11A00BA99FE /* HomeView.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 */; }; @@ -35,9 +34,6 @@ 2FE5DC4029EDD7EE004B9AB4 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3E29EDD7ED004B9AB4 /* FeatureFlags.swift */; }; 2FE5DC4129EDD7EE004B9AB4 /* StorageKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC3F29EDD7EE004B9AB4 /* StorageKeys.swift */; }; 2FE5DC4E29EDD7FA004B9AB4 /* ScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4829EDD7FA004B9AB4 /* ScheduleView.swift */; }; - 2FE5DC4F29EDD7FA004B9AB4 /* EventContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4929EDD7FA004B9AB4 /* EventContext.swift */; }; - 2FE5DC5029EDD7FA004B9AB4 /* EventContextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4A29EDD7FA004B9AB4 /* EventContextView.swift */; }; - 2FE5DC5129EDD7FA004B9AB4 /* TemplateApplicationTaskContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4B29EDD7FA004B9AB4 /* TemplateApplicationTaskContext.swift */; }; 2FE5DC5229EDD7FA004B9AB4 /* TemplateApplicationScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4C29EDD7FA004B9AB4 /* TemplateApplicationScheduler.swift */; }; 2FE5DC5329EDD7FA004B9AB4 /* Bundle+Questionnaire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE5DC4D29EDD7FA004B9AB4 /* Bundle+Questionnaire.swift */; }; 2FE5DC6429EDD883004B9AB4 /* SpeziAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC6329EDD883004B9AB4 /* SpeziAccount */; }; @@ -64,8 +60,12 @@ 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 */; }; - A92E4DF02BAA001100AC8DE8 /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = A92E4DEF2BAA001100AC8DE8 /* OrderedCollections */; }; + A94DDFFD2CBD1190004930BD /* SpeziNotifications in Frameworks */ = {isa = PBXBuildFile; productRef = A94DDFFC2CBD1190004930BD /* SpeziNotifications */; }; A9720E432ABB68CC00872D23 /* AccountSetupHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9720E422ABB68CC00872D23 /* AccountSetupHeader.swift */; }; + A98FF2B12CD131F500DFC949 /* EventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98FF2B02CD131F500DFC949 /* EventView.swift */; }; + A994264E2CD25EB3002F8BD5 /* XCTSpeziAccount in Frameworks */ = {isa = PBXBuildFile; productRef = A994264D2CD25EB3002F8BD5 /* XCTSpeziAccount */; }; + A9947BF02CC131ED0068AA8A /* SpeziSchedulerUI in Frameworks */ = {isa = PBXBuildFile; productRef = A9947BEF2CC131ED0068AA8A /* SpeziSchedulerUI */; }; + A9947BF42CC142BD0068AA8A /* XCTSpeziNotifications in Frameworks */ = {isa = PBXBuildFile; productRef = A9947BF32CC142BD0068AA8A /* XCTSpeziNotifications */; }; A9A3DCC82C75CBBD00FC9B69 /* FirebaseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A3DCC72C75CB9A00FC9B69 /* FirebaseConfiguration.swift */; }; A9D83F962B083794000D0C78 /* SpeziFirebaseAccountStorage in Frameworks */ = {isa = PBXBuildFile; productRef = A9D83F952B083794000D0C78 /* SpeziFirebaseAccountStorage */; }; A9DFE8A92ABE551400428242 /* AccountButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DFE8A82ABE551400428242 /* AccountButton.swift */; }; @@ -90,7 +90,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 27FA298F2A388E9B009CAC45 /* ModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalView.swift; sourceTree = ""; }; 2F1AC9DE2B4E840E00C24973 /* TemplateApplication.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = TemplateApplication.docc; sourceTree = ""; }; 2F4E237D2989A2FE0013F3D9 /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; 2F4E23822989D51F0013F3D9 /* TemplateApplicationTestingSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateApplicationTestingSetup.swift; sourceTree = ""; }; @@ -101,7 +100,7 @@ 2FA0BFEC2ACC977500E0EF83 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; 2FAEC07F297F583900C11C42 /* TemplateApplication.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TemplateApplication.entitlements; sourceTree = ""; }; 2FC94CD4298B0A1D009C8209 /* TemplateApplication.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = TemplateApplication.xctestplan; sourceTree = ""; }; - 2FC975A72978F11A00BA99FE /* Home.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Home.swift; sourceTree = ""; }; + 2FC975A72978F11A00BA99FE /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 2FE5DC2529EDD38A004B9AB4 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = ""; }; 2FE5DC2A29EDD78D004B9AB4 /* AppIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AppIcon.png; sourceTree = ""; }; 2FE5DC2C29EDD78E004B9AB4 /* ConsentDocument.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ConsentDocument.md; sourceTree = ""; }; @@ -113,9 +112,6 @@ 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 = ""; }; 2FE5DC4829EDD7FA004B9AB4 /* ScheduleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduleView.swift; sourceTree = ""; }; - 2FE5DC4929EDD7FA004B9AB4 /* EventContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventContext.swift; sourceTree = ""; }; - 2FE5DC4A29EDD7FA004B9AB4 /* EventContextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventContextView.swift; sourceTree = ""; }; - 2FE5DC4B29EDD7FA004B9AB4 /* TemplateApplicationTaskContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateApplicationTaskContext.swift; sourceTree = ""; }; 2FE5DC4C29EDD7FA004B9AB4 /* TemplateApplicationScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateApplicationScheduler.swift; sourceTree = ""; }; 2FE5DC4D29EDD7FA004B9AB4 /* Bundle+Questionnaire.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bundle+Questionnaire.swift"; sourceTree = ""; }; 2FE5DC5529EDD811004B9AB4 /* SocialSupportQuestionnaire.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = SocialSupportQuestionnaire.json; sourceTree = ""; }; @@ -131,6 +127,7 @@ 653A256B28338800005D4D48 /* SchedulerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchedulerTests.swift; sourceTree = ""; }; 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 = ""; }; + A98FF2B02CD131F500DFC949 /* EventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventView.swift; sourceTree = ""; }; A9A3DCC72C75CB9A00FC9B69 /* FirebaseConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseConfiguration.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 = ""; }; @@ -143,11 +140,13 @@ files = ( 9733CFC62A8066DE001B7ABC /* SpeziOnboarding in Frameworks */, 2FE5DC6429EDD883004B9AB4 /* SpeziAccount in Frameworks */, + A9947BF02CC131ED0068AA8A /* SpeziSchedulerUI in Frameworks */, 2FB099AF2A875DF100B20952 /* FirebaseAuth in Frameworks */, 97D73D6A2AD860AD00B47FA0 /* SpeziFirebaseStorage in Frameworks */, 2FE5DC6729EDD894004B9AB4 /* SpeziContact in Frameworks */, 2FE5DC8429EDD934004B9AB4 /* SpeziQuestionnaire in Frameworks */, 2FB099B12A875DF100B20952 /* FirebaseFirestore in Frameworks */, + A94DDFFD2CBD1190004930BD /* SpeziNotifications in Frameworks */, A9D83F962B083794000D0C78 /* SpeziFirebaseAccountStorage in Frameworks */, 2FB099B62A875E2B00B20952 /* HealthKitOnFHIR in Frameworks */, 56E7083B2BB06F6F00B08F0A /* SwiftPackageList in Frameworks */, @@ -155,7 +154,6 @@ 2FE5DC8A29EDD972004B9AB4 /* SpeziLocalStorage in Frameworks */, 2FE5DC8C29EDD972004B9AB4 /* SpeziSecureStorage in Frameworks */, 2FE5DC7529EDD8E6004B9AB4 /* SpeziFirebaseAccount in Frameworks */, - A92E4DF02BAA001100AC8DE8 /* OrderedCollections in Frameworks */, 9739A0C62AD7B5730084BEA5 /* FirebaseStorage in Frameworks */, 2FE5DC7229EDD8D3004B9AB4 /* SpeziHealthKit in Frameworks */, 2F49B7762980407C00BCB272 /* Spezi in Frameworks */, @@ -180,6 +178,8 @@ files = ( 2FE5DC9929EDD9D9004B9AB4 /* XCTestExtensions in Frameworks */, 2FE5DC9C29EDD9EF004B9AB4 /* XCTHealthKit in Frameworks */, + A994264E2CD25EB3002F8BD5 /* XCTSpeziAccount in Frameworks */, + A9947BF42CC142BD0068AA8A /* XCTSpeziNotifications in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -235,12 +235,9 @@ isa = PBXGroup; children = ( 2FE5DC4D29EDD7FA004B9AB4 /* Bundle+Questionnaire.swift */, - 2FE5DC4929EDD7FA004B9AB4 /* EventContext.swift */, - 2FE5DC4A29EDD7FA004B9AB4 /* EventContextView.swift */, 2FE5DC4829EDD7FA004B9AB4 /* ScheduleView.swift */, + A98FF2B02CD131F500DFC949 /* EventView.swift */, 2FE5DC4C29EDD7FA004B9AB4 /* TemplateApplicationScheduler.swift */, - 2FE5DC4B29EDD7FA004B9AB4 /* TemplateApplicationTaskContext.swift */, - 27FA298F2A388E9B009CAC45 /* ModalView.swift */, ); path = Schedule; sourceTree = ""; @@ -279,7 +276,7 @@ 653A254F283387FE005D4D48 /* TemplateApplication */ = { isa = PBXGroup; children = ( - 2FC975A72978F11A00BA99FE /* Home.swift */, + 2FC975A72978F11A00BA99FE /* HomeView.swift */, 653A2550283387FE005D4D48 /* TemplateApplication.swift */, 2F5E32BC297E05EA003432F8 /* TemplateApplicationDelegate.swift */, 2FF53D8C2A8729D600042B76 /* TemplateApplicationStandard.swift */, @@ -379,9 +376,10 @@ 9739A0C52AD7B5730084BEA5 /* FirebaseStorage */, 97D73D692AD860AD00B47FA0 /* SpeziFirebaseStorage */, A9D83F952B083794000D0C78 /* SpeziFirebaseAccountStorage */, - A92E4DEF2BAA001100AC8DE8 /* OrderedCollections */, 56E708342BB06B7100B08F0A /* SpeziLicense */, 56E7083A2BB06F6F00B08F0A /* SwiftPackageList */, + A94DDFFC2CBD1190004930BD /* SpeziNotifications */, + A9947BEF2CC131ED0068AA8A /* SpeziSchedulerUI */, ); productName = TemplateApplication; productReference = 653A254D283387FE005D4D48 /* TemplateApplication.app */; @@ -424,6 +422,8 @@ packageProductDependencies = ( 2FE5DC9829EDD9D9004B9AB4 /* XCTestExtensions */, 2FE5DC9B29EDD9EF004B9AB4 /* XCTHealthKit */, + A9947BF32CC142BD0068AA8A /* XCTSpeziNotifications */, + A994264D2CD25EB3002F8BD5 /* XCTSpeziAccount */, ); productName = TemplateApplicationUITests; productReference = 653A256728338800005D4D48 /* TemplateApplicationUITests.xctest */; @@ -437,7 +437,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1340; - LastUpgradeCheck = 1520; + LastUpgradeCheck = 1600; TargetAttributes = { 653A254C283387FE005D4D48 = { CreatedOnToolsVersion = 13.4; @@ -453,7 +453,7 @@ }; }; buildConfigurationList = 653A2548283387FE005D4D48 /* Build configuration list for PBXProject "TemplateApplication" */; - compatibilityVersion = "Xcode 13.0"; + compatibilityVersion = "Xcode 15.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -477,9 +477,10 @@ 97F466E62A76BBEE005DC9B4 /* XCRemoteSwiftPackageReference "SpeziOnboarding" */, 2FB099B42A875E2B00B20952 /* XCRemoteSwiftPackageReference "HealthKitOnFHIR" */, 5661551B2AB8384200209B80 /* XCRemoteSwiftPackageReference "swift-package-list" */, - A92E4DEE2BAA001100AC8DE8 /* XCRemoteSwiftPackageReference "swift-collections" */, 56E708332BB06B7100B08F0A /* XCRemoteSwiftPackageReference "SpeziLicense" */, 2F66D20D2BB723180010D555 /* XCRemoteSwiftPackageReference "SwiftLint" */, + A945FCD32C9C6BFA00B9EBC7 /* XCRemoteSwiftPackageReference "ResearchKitOnFHIR" */, + A94DDFFB2CBD1190004930BD /* XCRemoteSwiftPackageReference "SpeziNotifications" */, ); productRefGroup = 653A254E283387FE005D4D48 /* Products */; projectDirPath = ""; @@ -532,7 +533,7 @@ 2FE5DC3A29EDD7CA004B9AB4 /* Welcome.swift in Sources */, 2FE5DC3829EDD7CA004B9AB4 /* InterestingModules.swift in Sources */, 2FE5DC3529EDD7CA004B9AB4 /* Consent.swift in Sources */, - 2FC975A82978F11A00BA99FE /* Home.swift in Sources */, + 2FC975A82978F11A00BA99FE /* HomeView.swift in Sources */, 2FE5DC4E29EDD7FA004B9AB4 /* ScheduleView.swift in Sources */, A9DFE8A92ABE551400428242 /* AccountButton.swift in Sources */, A9A3DCC82C75CBBD00FC9B69 /* FirebaseConfiguration.swift in Sources */, @@ -541,18 +542,15 @@ 2FF53D8D2A8729D600042B76 /* TemplateApplicationStandard.swift in Sources */, A9720E432ABB68CC00872D23 /* AccountSetupHeader.swift in Sources */, 2FE5DC4029EDD7EE004B9AB4 /* FeatureFlags.swift in Sources */, - 2FE5DC4F29EDD7FA004B9AB4 /* EventContext.swift in Sources */, - 2FE5DC5029EDD7FA004B9AB4 /* EventContextView.swift in Sources */, 2F4E23832989D51F0013F3D9 /* TemplateApplicationTestingSetup.swift in Sources */, + A98FF2B12CD131F500DFC949 /* EventView.swift in Sources */, 2FE5DC5329EDD7FA004B9AB4 /* Bundle+Questionnaire.swift in Sources */, - 2FE5DC5129EDD7FA004B9AB4 /* TemplateApplicationTaskContext.swift in Sources */, 2F5E32BD297E05EA003432F8 /* TemplateApplicationDelegate.swift in Sources */, 2FE5DC5229EDD7FA004B9AB4 /* TemplateApplicationScheduler.swift in Sources */, A9FE7AD02AA39BAB0077B045 /* AccountSheet.swift in Sources */, 653A2551283387FE005D4D48 /* TemplateApplication.swift in Sources */, 2FE5DC3629EDD7CA004B9AB4 /* HealthKitPermissions.swift in Sources */, 2F65B44E2A3B8B0600A36932 /* NotificationPermissions.swift in Sources */, - 27FA29902A388E9B009CAC45 /* ModalView.swift in Sources */, 2FE5DC2629EDD38A004B9AB4 /* Contacts.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -700,6 +698,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UITemplateApplicationlicationSceneManifest_Generation = YES; INFOPLIST_KEY_UITemplateApplicationlicationSupportsIndirectInputEvents = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -720,12 +719,12 @@ 2FEE10322998C89C000822E1 /* Test */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.spezi.templateapplication.tests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -738,11 +737,11 @@ 2FEE10332998C89C000822E1 /* Test */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.spezi.templateapplicationuitests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -903,6 +902,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UITemplateApplicationlicationSceneManifest_Generation = YES; INFOPLIST_KEY_UITemplateApplicationlicationSupportsIndirectInputEvents = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -949,6 +949,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UITemplateApplicationlicationSceneManifest_Generation = YES; INFOPLIST_KEY_UITemplateApplicationlicationSupportsIndirectInputEvents = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -970,12 +971,12 @@ 653A257528338800005D4D48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.spezi.templateapplication.tests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -988,12 +989,12 @@ 653A257628338800005D4D48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.spezi.templateapplication.tests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1006,11 +1007,11 @@ 653A257828338800005D4D48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.spezi.templateapplicationuitests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1023,11 +1024,11 @@ 653A257928338800005D4D48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 637867499T; GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.spezi.templateapplicationuitests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1087,16 +1088,16 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/StanfordSpezi/SpeziScheduler.git"; requirement = { - kind = upToNextMinorVersion; - minimumVersion = 0.8.3; + kind = upToNextMajorVersion; + minimumVersion = 1.1.0; }; }; 2F49B7742980407B00BCB272 /* XCRemoteSwiftPackageReference "Spezi" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/StanfordSpezi/Spezi"; + repositoryURL = "https://github.com/StanfordSpezi/Spezi.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.7.1; + minimumVersion = 1.8.0; }; }; 2F66D20D2BB723180010D555 /* XCRemoteSwiftPackageReference "SwiftLint" */ = { @@ -1104,7 +1105,7 @@ repositoryURL = "https://github.com/realm/SwiftLint.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 0.55.0; + minimumVersion = 0.56.0; }; }; 2FB099B42A875E2B00B20952 /* XCRemoteSwiftPackageReference "HealthKitOnFHIR" */ = { @@ -1120,7 +1121,7 @@ repositoryURL = "https://github.com/StanfordSpezi/SpeziAccount.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "2.0.0-beta.7"; + minimumVersion = 2.0.1; }; }; 2FE5DC6529EDD894004B9AB4 /* XCRemoteSwiftPackageReference "SpeziContact" */ = { @@ -1144,7 +1145,7 @@ repositoryURL = "https://github.com/StanfordSpezi/SpeziFirebase.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "2.0.0-beta.3"; + minimumVersion = 2.0.0; }; }; 2FE5DC8229EDD934004B9AB4 /* XCRemoteSwiftPackageReference "SpeziQuestionnaire" */ = { @@ -1152,7 +1153,7 @@ repositoryURL = "https://github.com/StanfordSpezi/SpeziQuestionnaire.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.2.0; + minimumVersion = 1.2.3; }; }; 2FE5DC8829EDD972004B9AB4 /* XCRemoteSwiftPackageReference "SpeziStorage" */ = { @@ -1160,7 +1161,7 @@ repositoryURL = "https://github.com/StanfordSpezi/SpeziStorage.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.1.2; + minimumVersion = 1.2.1; }; }; 2FE5DC8D29EDD980004B9AB4 /* XCRemoteSwiftPackageReference "SpeziViews" */ = { @@ -1168,7 +1169,7 @@ repositoryURL = "https://github.com/StanfordSpezi/SpeziViews.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.6.0; + minimumVersion = 1.7.0; }; }; 2FE5DC9029EDD9C3004B9AB4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { @@ -1205,7 +1206,7 @@ }; 56E708332BB06B7100B08F0A /* XCRemoteSwiftPackageReference "SpeziLicense" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/StanfordSpezi/SpeziLicense"; + repositoryURL = "https://github.com/StanfordSpezi/SpeziLicense.git"; requirement = { kind = upToNextMinorVersion; minimumVersion = 0.1.1; @@ -1213,18 +1214,26 @@ }; 97F466E62A76BBEE005DC9B4 /* XCRemoteSwiftPackageReference "SpeziOnboarding" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/StanfordSpezi/SpeziOnboarding"; + repositoryURL = "https://github.com/StanfordSpezi/SpeziOnboarding.git"; requirement = { kind = upToNextMajorVersion; minimumVersion = 1.2.1; }; }; - A92E4DEE2BAA001100AC8DE8 /* XCRemoteSwiftPackageReference "swift-collections" */ = { + A945FCD32C9C6BFA00B9EBC7 /* XCRemoteSwiftPackageReference "ResearchKitOnFHIR" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/apple/swift-collections.git"; + repositoryURL = "https://github.com/StanfordBDHG/ResearchKitOnFHIR.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.1.0; + minimumVersion = 2.0.2; + }; + }; + A94DDFFB2CBD1190004930BD /* XCRemoteSwiftPackageReference "SpeziNotifications" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/StanfordSpezi/SpeziNotifications.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.2; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -1349,10 +1358,25 @@ package = 2FE5DC7329EDD8E6004B9AB4 /* XCRemoteSwiftPackageReference "SpeziFirebase" */; productName = SpeziFirebaseStorage; }; - A92E4DEF2BAA001100AC8DE8 /* OrderedCollections */ = { + A94DDFFC2CBD1190004930BD /* SpeziNotifications */ = { + isa = XCSwiftPackageProductDependency; + package = A94DDFFB2CBD1190004930BD /* XCRemoteSwiftPackageReference "SpeziNotifications" */; + productName = SpeziNotifications; + }; + A994264D2CD25EB3002F8BD5 /* XCTSpeziAccount */ = { + isa = XCSwiftPackageProductDependency; + package = 2FE5DC6229EDD883004B9AB4 /* XCRemoteSwiftPackageReference "SpeziAccount" */; + productName = XCTSpeziAccount; + }; + A9947BEF2CC131ED0068AA8A /* SpeziSchedulerUI */ = { + isa = XCSwiftPackageProductDependency; + package = 2F3D4ABA2A4E7C290068FB2F /* XCRemoteSwiftPackageReference "SpeziScheduler" */; + productName = SpeziSchedulerUI; + }; + A9947BF32CC142BD0068AA8A /* XCTSpeziNotifications */ = { isa = XCSwiftPackageProductDependency; - package = A92E4DEE2BAA001100AC8DE8 /* XCRemoteSwiftPackageReference "swift-collections" */; - productName = OrderedCollections; + package = A94DDFFB2CBD1190004930BD /* XCRemoteSwiftPackageReference "SpeziNotifications" */; + productName = XCTSpeziNotifications; }; A9D83F952B083794000D0C78 /* SpeziFirebaseAccountStorage */ = { isa = XCSwiftPackageProductDependency; diff --git a/TemplateApplication.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/TemplateApplication.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e39c222a..50342014 100644 --- a/TemplateApplication.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/TemplateApplication.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "7791f7520d86b9b987dab37c9b90dab7fe5795363615aa359655357df18d38c1", + "originHash" : "db91c54ac80b4652c5d1b19cb32a4d0a53d2e435c933b5bd074867152f598a36", "pins" : [ { "identity" : "abseil-cpp-binary", @@ -13,7 +13,7 @@ { "identity" : "antlr4", "kind" : "remoteSourceControl", - "location" : "https://github.com/antlr/antlr4", + "location" : "https://github.com/antlr/antlr4.git", "state" : { "revision" : "cc82115a4e7f53d71d9d905caa2c2dfa4da58899", "version" : "4.13.2" @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/app-check.git", "state" : { - "revision" : "21fe1af9be463a359aaf8d96789ef73fc3760d09", - "version" : "11.0.1" + "revision" : "87dd288fc792bf9751e522e171a47df5b783b0b8", + "version" : "11.1.0" } }, { @@ -60,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/firebase/firebase-ios-sdk.git", "state" : { - "revision" : "9118aca998dbe2ceac45d64b21a91c6376928df7", - "version" : "11.1.0" + "revision" : "f909f901bfba9e27e4e9da83242a4915d6dd64bb", + "version" : "11.3.0" } }, { @@ -69,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleAppMeasurement.git", "state" : { - "revision" : "07a2f57d147d2bf368a0d2dcb5579ff082d9e44f", - "version" : "11.1.0" + "revision" : "93406fd21b85e66e2d6dbf50b472161fd75c3f1f", + "version" : "11.3.0" } }, { @@ -114,8 +114,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordBDHG/HealthKitOnFHIR.git", "state" : { - "revision" : "c24e316311ff9813cb1fe32cd8820bcca6e5e7f2", - "version" : "0.2.10" + "revision" : "87a9257e6fa37407f3437e4a0bf21dd09a4ea7c5", + "version" : "0.2.11" } }, { @@ -166,10 +166,10 @@ { "identity" : "researchkitonfhir", "kind" : "remoteSourceControl", - "location" : "https://github.com/StanfordBDHG/ResearchKitOnFHIR", + "location" : "https://github.com/StanfordBDHG/ResearchKitOnFHIR.git", "state" : { - "revision" : "23dda93dc652b5c2753b5cbf989faf8185fd17f1", - "version" : "2.0.1" + "revision" : "d8d8b0d01599ad8a5a8397d10a99073728e6ae9b", + "version" : "2.0.2" } }, { @@ -184,10 +184,10 @@ { "identity" : "spezi", "kind" : "remoteSourceControl", - "location" : "https://github.com/StanfordSpezi/Spezi", + "location" : "https://github.com/StanfordSpezi/Spezi.git", "state" : { - "revision" : "d5c8eec55255fd753367422c49db1ec16610c48b", - "version" : "1.7.4" + "revision" : "4513a697572e8e1faea1e0ee52e6fad4b8d3dd8d", + "version" : "1.8.0" } }, { @@ -195,8 +195,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordSpezi/SpeziAccount.git", "state" : { - "revision" : "7e78ee9e7e4df2071a18ac0fc722671ac1dcfac4", - "version" : "2.0.0-beta.7" + "revision" : "7ffb73de1c874c78029b620f74d6411bdf65f3fc", + "version" : "2.0.1" } }, { @@ -213,17 +213,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordSpezi/SpeziFirebase.git", "state" : { - "revision" : "d0cb58fc43c99e632446b43c5cb56943f8339bf2", - "version" : "2.0.0-beta.3" + "revision" : "7c6829624884f6f1d700e0316b2580b39d3b0c5f", + "version" : "2.0.0" } }, { "identity" : "spezifoundation", "kind" : "remoteSourceControl", - "location" : "https://github.com/StanfordSpezi/SpeziFoundation", + "location" : "https://github.com/StanfordSpezi/SpeziFoundation.git", "state" : { - "revision" : "17bd0e03e69e0cc722d4cd28148d04443f4e2aba", - "version" : "2.0.0-beta.2" + "revision" : "5b4ad1b343154b52a68c33a6bfe02d9cb07cb9dc", + "version" : "2.0.0" } }, { @@ -238,16 +238,25 @@ { "identity" : "spezilicense", "kind" : "remoteSourceControl", - "location" : "https://github.com/StanfordSpezi/SpeziLicense", + "location" : "https://github.com/StanfordSpezi/SpeziLicense.git", "state" : { "revision" : "2249ce615a624a072834e31e7906b779ba82b824", "version" : "0.1.1" } }, + { + "identity" : "spezinotifications", + "kind" : "remoteSourceControl", + "location" : "https://github.com/StanfordSpezi/SpeziNotifications", + "state" : { + "revision" : "7f24fce6b969d0f1a7bcc0e228af1c01e55fb59f", + "version" : "1.0.2" + } + }, { "identity" : "spezionboarding", "kind" : "remoteSourceControl", - "location" : "https://github.com/StanfordSpezi/SpeziOnboarding", + "location" : "https://github.com/StanfordSpezi/SpeziOnboarding.git", "state" : { "revision" : "a3d7bc15e6803b2205eb8dca010a48b1a40215be", "version" : "1.2.2" @@ -267,8 +276,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordSpezi/SpeziScheduler.git", "state" : { - "revision" : "896eb442eb2941f9b2f7721c3ac871373934142a", - "version" : "0.8.3" + "revision" : "a4923dcdcc46d7edf0a7bf7ea9d9531d40abe147", + "version" : "1.1.0" } }, { @@ -276,8 +285,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordSpezi/SpeziStorage.git", "state" : { - "revision" : "60962375bbce7cc0599bc3da4ebda08231922371", - "version" : "1.2.0" + "revision" : "0f4a54430e51f82d29da63a7ce5f61bad7dfb9cd", + "version" : "1.2.1" } }, { @@ -285,14 +294,23 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordSpezi/SpeziViews.git", "state" : { - "revision" : "427f4f3a7acb0e00ea11c4c3ca7b60e36d2557a0", - "version" : "1.6.0" + "revision" : "f87514406bb57ae67d0040eec5454fff55104143", + "version" : "1.7.0" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms.git", + "state" : { + "revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42", + "version" : "1.2.0" } }, { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-argument-parser", + "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { "revision" : "41982a3656a71c768319979febd796c6fd111d5c", "version" : "1.5.0" @@ -312,8 +330,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "9bf03ff58ce34478e66aaee630e491823326fd06", - "version" : "1.1.3" + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics.git", + "state" : { + "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", + "version" : "1.0.2" } }, { @@ -321,8 +348,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/FelixHerrmann/swift-package-list", "state" : { - "revision" : "01f2e9860c122dd8c3ae2a7e642b85bbb053efe3", - "version" : "4.2.0" + "revision" : "e84b63c88f0797d769732440fe0786c5a2c634d8", + "version" : "4.4.0" } }, { @@ -330,17 +357,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "edb6ed4919f7756157fe02f2552b7e3850a538e5", - "version" : "1.28.1" + "revision" : "ebc7251dd5b37f627c93698e4374084d98409633", + "version" : "1.28.2" } }, { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", + "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82", - "version" : "510.0.3" + "revision" : "515f79b522918f83483068d99c68daeb5116342d", + "version" : "600.0.0-prerelease-2024-08-14" } }, { @@ -348,8 +375,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/realm/SwiftLint.git", "state" : { - "revision" : "b515723b16eba33f15c4677ee65f3fef2ce8c255", - "version" : "0.55.1" + "revision" : "168fb98ed1f3e343d703ecceaf518b6cf565207b", + "version" : "0.57.0" } }, { @@ -375,8 +402,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/StanfordBDHG/XCTestExtensions.git", "state" : { - "revision" : "aad6c161a09d658f30c7170deb4a61e8916a4a4c", - "version" : "1.0.0" + "revision" : "5379d70249cae926927105bfb6686770f03ee5b9", + "version" : "1.1.0" } }, { @@ -391,7 +418,7 @@ { "identity" : "xctruntimeassertions", "kind" : "remoteSourceControl", - "location" : "https://github.com/StanfordBDHG/XCTRuntimeAssertions", + "location" : "https://github.com/StanfordBDHG/XCTRuntimeAssertions.git", "state" : { "revision" : "f560ec8410af032dd485ca9386e8c2b5d3e1a1f8", "version" : "1.1.3" diff --git a/TemplateApplication.xcodeproj/xcshareddata/xcschemes/TemplateApplication.xcscheme b/TemplateApplication.xcodeproj/xcshareddata/xcschemes/TemplateApplication.xcscheme index e92311a8..0a585a00 100644 --- a/TemplateApplication.xcodeproj/xcshareddata/xcschemes/TemplateApplication.xcscheme +++ b/TemplateApplication.xcodeproj/xcshareddata/xcschemes/TemplateApplication.xcscheme @@ -1,6 +1,6 @@ - - - var id: Event.ID { - event.id - } - - - static func < (lhs: EventContext, rhs: EventContext) -> Bool { - lhs.event.scheduledAt < rhs.event.scheduledAt - } -} diff --git a/TemplateApplication/Schedule/EventContextView.swift b/TemplateApplication/Schedule/EventContextView.swift deleted file mode 100644 index efcbc963..00000000 --- a/TemplateApplication/Schedule/EventContextView.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// This source file is part of the Stanford Spezi Template Application open-source project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SpeziScheduler -import SwiftUI - - -struct EventContextView: View { - let eventContext: EventContext - - - var body: some View { - HStack { - VStack(alignment: .leading) { - HStack { - if eventContext.event.complete { - Image(systemName: "checkmark.circle.fill") - .foregroundColor(.accentColor) - .font(.system(size: 30)) - .accessibilityHidden(true) - } - VStack(alignment: .leading, spacing: 8) { - Text(verbatim: eventContext.task.title) - .font(.headline) - .accessibilityLabel( - eventContext.event.complete - ? "COMPLETED_TASK_LABEL \(eventContext.task.title)" - : "TASK_LABEL \(eventContext.task.title)" - ) - Text(verbatim: format(eventDate: eventContext.event.scheduledAt)) - .font(.subheadline) - } - } - Divider() - Text(eventContext.task.description) - .font(.callout) - if !eventContext.event.complete { - Text(eventContext.task.context.actionType) - .frame(maxWidth: .infinity, minHeight: 50) - .foregroundColor(.white) - .background(Color.accentColor) - .clipShape(RoundedRectangle(cornerRadius: 8)) - .padding(.top, 8) - } - } - } - .disabled(eventContext.event.complete) - .contentShape(Rectangle()) - } - - - private func format(eventDate: Date) -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - return dateFormatter.string(from: eventDate) - } -} - - -#if DEBUG -#Preview(traits: .sizeThatFitsLayout) { - let task = TemplateApplicationScheduler.socialSupportTask - - return EventContextView( - eventContext: EventContext( - // 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 - event: task.events(from: .now.addingTimeInterval(-60 * 60 * 24)).first!, - task: task - ) - ) - .padding() -} -#endif diff --git a/TemplateApplication/Schedule/EventView.swift b/TemplateApplication/Schedule/EventView.swift new file mode 100644 index 00000000..33b98d8a --- /dev/null +++ b/TemplateApplication/Schedule/EventView.swift @@ -0,0 +1,52 @@ +// +// This source file is part of the Stanford Spezi Template Application open-source project +// +// SPDX-FileCopyrightText: 2023 Stanford University +// +// SPDX-License-Identifier: MIT +// + +import SpeziQuestionnaire +import SpeziScheduler +import SpeziSchedulerUI +import SwiftUI + + +struct EventView: View { + private let event: Event + + @Environment(TemplateApplicationStandard.self) private var standard + @Environment(\.dismiss) private var dismiss + + var body: some View { + if let questionnaire = event.task.questionnaire { + QuestionnaireView(questionnaire: questionnaire) { result in + dismiss() + + guard case let .completed(response) = result else { + return // user cancelled the task + } + + event.complete() + await standard.add(response: response) + } + } else { + NavigationStack { + ContentUnavailableView( + "Unsupported Event", + systemImage: "list.bullet.clipboard", + description: Text("This type of event is currently unsupported. Please contact the developer of this app.") + ) + .toolbar { + Button("Close") { + dismiss() + } + } + } + } + } + + init(_ event: Event) { + self.event = event + } +} diff --git a/TemplateApplication/Schedule/ModalView.swift b/TemplateApplication/Schedule/ModalView.swift deleted file mode 100644 index ba683315..00000000 --- a/TemplateApplication/Schedule/ModalView.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// This source file is part of the Stanford Spezi Template Application open-source project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import SpeziViews -import SwiftUI - - -struct ModalView: View { - @Environment(\.dismiss) private var dismiss - - let text: String - let buttonText: String - let onClose: () async -> Void - - - var body: some View { - VStack { - Spacer() - Text(text) - .padding() - Spacer() - AsyncButton { - self.dismiss() - await self.onClose() - } label: { - Text(buttonText) - .frame(maxWidth: .infinity, minHeight: 38) - } - .padding() - .buttonStyle(.borderedProminent) - } - } -} - - -#if DEBUG -#Preview { - ModalView(text: "Preview Modal", buttonText: "Close") { - print("Preview Modal closed.") - } -} -#endif diff --git a/TemplateApplication/Schedule/ScheduleView.swift b/TemplateApplication/Schedule/ScheduleView.swift index 9413cac4..3afce88d 100644 --- a/TemplateApplication/Schedule/ScheduleView.swift +++ b/TemplateApplication/Schedule/ScheduleView.swift @@ -6,65 +6,42 @@ // SPDX-License-Identifier: MIT // -import OrderedCollections @_spi(TestingSupport) import SpeziAccount -import SpeziQuestionnaire import SpeziScheduler +import SpeziSchedulerUI +import SpeziViews import SwiftUI struct ScheduleView: View { - @Environment(TemplateApplicationStandard.self) private var standard - @Environment(TemplateApplicationScheduler.self) private var scheduler @Environment(Account.self) private var account: Account? + @Environment(TemplateApplicationScheduler.self) private var scheduler: TemplateApplicationScheduler - @State private var presentedContext: EventContext? + @State private var presentedEvent: Event? @Binding private var presentingAccount: Bool - - - @MainActor private var eventContextsByDate: OrderedDictionary { - let eventContexts = scheduler.tasks.flatMap { task in - task - .events( - from: Calendar.current.startOfDay(for: .now), - to: .numberOfEventsOrEndDate(100, .now) - ) - .map { event in - EventContext(event: event, task: task) - } - } - .sorted() - - return OrderedDictionary(grouping: eventContexts) { eventContext in - Calendar.current.startOfDay(for: eventContext.event.scheduledAt) - } - } var body: some View { + @Bindable var scheduler = scheduler + NavigationStack { - let eventContextsByDate = eventContextsByDate - List(eventContextsByDate.keys, id: \.timeIntervalSinceNow) { startOfDay in - Section(format(startOfDay: startOfDay)) { - ForEach(eventContextsByDate[startOfDay] ?? [], id: \.event) { eventContext in - EventContextView(eventContext: eventContext) - .onTapGesture { - if !eventContext.event.complete { - presentedContext = eventContext - } - } + TodayList { event in + InstructionsTile(event) { + EventActionButton(event: event, "Start Questionnaire") { + presentedEvent = event } } } - .sheet(item: $presentedContext) { presentedContext in - destination(withContext: presentedContext) + .navigationTitle("Schedule") + .viewStateAlert(state: $scheduler.viewState) + .sheet(item: $presentedEvent) { event in + EventView(event) } .toolbar { if account != nil { AccountButton(isPresented: $presentingAccount) } } - .navigationTitle("SCHEDULE_LIST_TITLE") } } @@ -72,46 +49,16 @@ struct ScheduleView: View { init(presentingAccount: Binding) { self._presentingAccount = presentingAccount } - - - @MainActor - private func destination(withContext eventContext: EventContext) -> some View { - @ViewBuilder var destination: some View { - switch eventContext.task.context { - case let .questionnaire(questionnaire): - QuestionnaireView(questionnaire: questionnaire) { result in - presentedContext = nil - - guard case let .completed(response) = result else { - return // user cancelled the task - } - - eventContext.event.complete(true) - await standard.add(response: response) - } - case let .test(string): - ModalView(text: string, buttonText: String(localized: "CLOSE")) { - eventContext.event.complete(true) - } - } - } - return destination - } - - - private func format(startOfDay: Date) -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .long - dateFormatter.timeStyle = .none - return dateFormatter.string(from: startOfDay) - } } #if DEBUG #Preview("ScheduleView") { - ScheduleView(presentingAccount: .constant(false)) + @Previewable @State var presentingAccount = false + + ScheduleView(presentingAccount: $presentingAccount) .previewWith(standard: TemplateApplicationStandard()) { + Scheduler() TemplateApplicationScheduler() AccountConfiguration(service: InMemoryAccountService()) } diff --git a/TemplateApplication/Schedule/TemplateApplicationScheduler.swift b/TemplateApplication/Schedule/TemplateApplicationScheduler.swift index aa6626f1..2d7e3c7f 100644 --- a/TemplateApplication/Schedule/TemplateApplicationScheduler.swift +++ b/TemplateApplication/Schedule/TemplateApplicationScheduler.swift @@ -7,43 +7,46 @@ // import Foundation +import Spezi import SpeziScheduler +import SpeziViews +import class ModelsR4.Questionnaire +import class ModelsR4.QuestionnaireResponse -/// A `Scheduler` using the ``TemplateApplicationTaskContext`` to schedule and manage tasks and events in the -/// Spezi Template Application. -typealias TemplateApplicationScheduler = Scheduler +@Observable +final class TemplateApplicationScheduler: Module, DefaultInitializable, EnvironmentAccessible { + @Dependency(Scheduler.self) @ObservationIgnored private var scheduler + @MainActor var viewState: ViewState = .idle -extension TemplateApplicationScheduler { - static var socialSupportTask: SpeziScheduler.Task { - let dateComponents: DateComponents - if FeatureFlags.testSchedule { - // Adds a task at the current time for UI testing if the `--testSchedule` feature flag is set - dateComponents = DateComponents( - hour: Calendar.current.component(.hour, from: .now), - minute: Calendar.current.component(.minute, from: .now) - ) - } else { - // For the normal app usage, we schedule the task for every day at 8:00 AM - dateComponents = DateComponents(hour: 8, minute: 0) + init() {} + + /// Add or update the current list of task upon app startup. + func configure() { + do { + try scheduler.createOrUpdateTask( + id: "social-support-questionnaire", + title: "Social Support Questionnaire", + instructions: "Please fill out the Social Support Questionnaire every day.", + category: .questionnaire, + schedule: .daily(hour: 8, minute: 0, startingAt: .today) + ) { context in + context.questionnaire = Bundle.main.questionnaire(withName: "SocialSupportQuestionnaire") + } + } catch { + viewState = .error(AnyLocalizedError(error: error, defaultErrorDescription: "Failed to create or update scheduled tasks.")) } - - return Task( - title: String(localized: "TASK_SOCIAL_SUPPORT_QUESTIONNAIRE_TITLE"), - description: String(localized: "TASK_SOCIAL_SUPPORT_QUESTIONNAIRE_DESCRIPTION"), - schedule: Schedule( - start: Calendar.current.startOfDay(for: Date()), - repetition: .matching(dateComponents), - end: .numberOfEvents(365) - ), - notifications: true, - context: TemplateApplicationTaskContext.questionnaire(Bundle.main.questionnaire(withName: "SocialSupportQuestionnaire")) - ) } +} - /// Creates a default instance of the ``TemplateApplicationScheduler`` by scheduling the tasks listed below. - convenience init() { - self.init(tasks: [Self.socialSupportTask]) - } + +extension Task.Context { + @Property(coding: .json) var questionnaire: Questionnaire? +} + + +extension Outcome { + // periphery:ignore - demonstration of how to store additional context within an outcome + @Property(coding: .json) var questionnaireResponse: QuestionnaireResponse? } diff --git a/TemplateApplication/Schedule/TemplateApplicationTaskContext.swift b/TemplateApplication/Schedule/TemplateApplicationTaskContext.swift deleted file mode 100644 index d7cccb0f..00000000 --- a/TemplateApplication/Schedule/TemplateApplicationTaskContext.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// This source file is part of the Stanford Spezi Template Application open-source project -// -// SPDX-FileCopyrightText: 2023 Stanford University -// -// SPDX-License-Identifier: MIT -// - -import Foundation -import ModelsR4 - - -/// The context attached to each task in the Spezi Template Application. -/// -/// We currently only support `Questionnaire`s, more cases can be added in the future. -@MainActor -enum TemplateApplicationTaskContext: Codable, Identifiable { - /// The task should display a `Questionnaire`. - case questionnaire(Questionnaire) - /// The task is used for UI testing. - case test(String) - - - nonisolated var id: FHIRPrimitive? { - switch self { - case let .questionnaire(questionnaire): - return questionnaire.id - case .test: - return FHIRPrimitive(FHIRString(UUID().uuidString)) - } - } - - var actionType: LocalizedStringResource { - switch self { - case .questionnaire: - return LocalizedStringResource("TASK_CONTEXT_ACTION_QUESTIONNAIRE") - case .test: - return LocalizedStringResource("TASK_CONTEXT_ACTION_TEST") - } - } -} diff --git a/TemplateApplication/SharedContext/FeatureFlags.swift b/TemplateApplication/SharedContext/FeatureFlags.swift index 8829f6bc..5d5e34b7 100644 --- a/TemplateApplication/SharedContext/FeatureFlags.swift +++ b/TemplateApplication/SharedContext/FeatureFlags.swift @@ -21,8 +21,6 @@ enum FeatureFlags { /// Defines if the application should connect to the local firebase emulator. Always set to true when using the iOS simulator. static let useFirebaseEmulator = CommandLine.arguments.contains("--useFirebaseEmulator") #endif - /// Adds a test task to the schedule at the current time - static let testSchedule = CommandLine.arguments.contains("--testSchedule") /// Automatically sign in into a test account upon app launch. /// /// Requires ``disableFirebase`` to be `false`. diff --git a/TemplateApplication/SharedContext/StorageKeys.swift b/TemplateApplication/SharedContext/StorageKeys.swift index 1c0f1e87..18119a57 100644 --- a/TemplateApplication/SharedContext/StorageKeys.swift +++ b/TemplateApplication/SharedContext/StorageKeys.swift @@ -15,4 +15,6 @@ enum StorageKeys { // MARK: - Home /// The currently selected home tab. static let homeTabSelection = "home.tabselection" + /// The TabView customization on iPadOS + static let tabViewCustomization = "home.tab-view-customization" } diff --git a/TemplateApplication/Supporting Files/Info.plist b/TemplateApplication/Supporting Files/Info.plist index 549ff286..d9963b1b 100644 --- a/TemplateApplication/Supporting Files/Info.plist +++ b/TemplateApplication/Supporting Files/Info.plist @@ -2,10 +2,10 @@ - FirebaseAppDelegateProxyEnabled - CFBundleAllowMixedLocalizations + FirebaseAppDelegateProxyEnabled + ITSAppUsesNonExemptEncryption UIApplicationSceneManifest @@ -15,5 +15,9 @@ UISceneConfigurations + UIBackgroundModes + + fetch + diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Create.md b/TemplateApplication/Supporting Files/TemplateApplication.docc/Create.md index 7e94f316..b65b4008 100644 --- a/TemplateApplication/Supporting Files/TemplateApplication.docc/Create.md +++ b/TemplateApplication/Supporting Files/TemplateApplication.docc/Create.md @@ -43,7 +43,7 @@ The following example shows renaming the application to "My Spezi App": $ sh Scripts/create.sh --name "My Spezi App" --bundleIdentifier "edu.stanford.spezi.myapp" ``` -## 3. Setup the Continous Integration and Delivery Setup +## 3. Setup the Continuous Integration and Delivery Setup Continuous integration (CI) and continuous delivery (CD) are essential to automatically test and deploy your application at any time. Each Spezi Template Application-based Spezi app already has the necessary infrastructure in place; the Spezi Template Application includes continuous integration (CI) and continuous delivery (CD) setup: diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Modify.md b/TemplateApplication/Supporting Files/TemplateApplication.docc/Modify.md index 987480e6..13086252 100644 --- a/TemplateApplication/Supporting Files/TemplateApplication.docc/Modify.md +++ b/TemplateApplication/Supporting Files/TemplateApplication.docc/Modify.md @@ -61,7 +61,7 @@ It uses the [**Spezi Scheduler**](https://github.com/StanfordSpezi/SpeziSchedule @Row(numberOfColumns: 4) { @Column(size: 1) { @Image(source: "Schedule", alt: "A screen displaying the Scheduler UI.") { - The elements that are displayed as part of a schedule are defined in the ``TemplateApplicationTaskContext`` and displayed using the ``EventContextView`` and logic in the ``ScheduleView``. + The elements that are displayed as part of the schedule are defined in the ``TemplateApplicationScheduler`` and displayed using the ``ScheduleView`` and ``EventView``. } } @Column(size: 1) { diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account.png index a607eebf..9a163391 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account~dark.png index 36d9519a..6e6f70b4 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Account~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login.png index 4c240db4..c9d4be1f 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login~dark.png index e24cfe1b..3787ddd2 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/Login~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount.png index 5d14995d..e5cd48f1 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount~dark.png index 7b8b784e..bfabe334 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Account/NewAccount~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts.png index ae7581f4..4414122f 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts~dark.png index a1ebd711..df73de84 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/Contacts~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License.png index d0b1854a..f26f0b08 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License~dark.png index c1b8f783..1959c2bf 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Context/License~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire.png index d0be49dc..a6f2fd0b 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire~dark.png index db8dfe22..7f886e9c 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Questionnaire~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule.png index 39fa9b9a..44985e54 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete.png index 53407017..ffc182c1 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete~dark.png index 4a81661d..f861ec6c 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/ScheduleComplete~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule~dark.png b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule~dark.png index ba1e6690..283f1324 100644 Binary files a/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule~dark.png and b/TemplateApplication/Supporting Files/TemplateApplication.docc/Resources/Schedule/Schedule~dark.png differ diff --git a/TemplateApplication/Supporting Files/TemplateApplication.entitlements b/TemplateApplication/Supporting Files/TemplateApplication.entitlements index c541ce6f..803b90f4 100644 --- a/TemplateApplication/Supporting Files/TemplateApplication.entitlements +++ b/TemplateApplication/Supporting Files/TemplateApplication.entitlements @@ -12,5 +12,7 @@ com.apple.developer.healthkit.background-delivery + com.apple.developer.usernotifications.time-sensitive + diff --git a/TemplateApplication/TemplateApplicationDelegate.swift b/TemplateApplication/TemplateApplicationDelegate.swift index 631c5d3c..a66f4917 100644 --- a/TemplateApplication/TemplateApplicationDelegate.swift +++ b/TemplateApplication/TemplateApplicationDelegate.swift @@ -15,6 +15,7 @@ import SpeziFirebaseAccountStorage import SpeziFirebaseStorage import SpeziFirestore import SpeziHealthKit +import SpeziNotifications import SpeziOnboarding import SpeziScheduler import SwiftUI @@ -50,7 +51,10 @@ class TemplateApplicationDelegate: SpeziAppDelegate { } TemplateApplicationScheduler() + Scheduler() OnboardingDataSource() + + Notifications() } } diff --git a/TemplateApplication/TemplateApplicationStandard.swift b/TemplateApplication/TemplateApplicationStandard.swift index 4262d896..5f2e785b 100644 --- a/TemplateApplication/TemplateApplicationStandard.swift +++ b/TemplateApplication/TemplateApplicationStandard.swift @@ -59,13 +59,14 @@ actor TemplateApplicationStandard: Standard, logger.error("Could not remove HealthKit sample: \(error)") } } - - func add(response: ModelsR4.QuestionnaireResponse) async { + + // periphery:ignore:parameters isolation + func add(response: ModelsR4.QuestionnaireResponse, isolation: isolated (any Actor)? = #isolation) async { let id = response.identifier?.value?.value?.string ?? UUID().uuidString if FeatureFlags.disableFirebase { let jsonRepresentation = (try? String(data: JSONEncoder().encode(response), encoding: .utf8)) ?? "" - logger.debug("Received questionnaire response: \(jsonRepresentation)") + await logger.debug("Received questionnaire response: \(jsonRepresentation)") return } @@ -75,7 +76,7 @@ actor TemplateApplicationStandard: Standard, .document(id) // Set the document identifier to the id of the response. .setData(from: response) } catch { - logger.error("Could not store questionnaire response: \(error)") + await logger.error("Could not store questionnaire response: \(error)") } } diff --git a/TemplateApplicationUITests/OnboardingTests.swift b/TemplateApplicationUITests/OnboardingTests.swift index 438c5100..cb1a414f 100644 --- a/TemplateApplicationUITests/OnboardingTests.swift +++ b/TemplateApplicationUITests/OnboardingTests.swift @@ -9,6 +9,8 @@ import XCTest import XCTestExtensions import XCTHealthKit +import XCTSpeziAccount +import XCTSpeziNotifications class OnboardingTests: XCTestCase { @@ -101,16 +103,10 @@ extension XCUIApplication { XCTAssertTrue(buttons["Signup"].exists) buttons["Signup"].tap() + XCTAssertTrue(staticTexts["Create a new Account"].waitForExistence(timeout: 2)) - XCTAssertTrue(collectionViews.textFields["E-Mail Address"].exists) - try collectionViews.textFields["E-Mail Address"].enter(value: email) - XCTAssertTrue(collectionViews.secureTextFields["Password"].exists) - try collectionViews.secureTextFields["Password"].enter(value: "StanfordRocks") - XCTAssertTrue(collectionViews.textFields["enter first name"].exists) - try textFields["enter first name"].enter(value: "Leland") - XCTAssertTrue(collectionViews.textFields["enter last name"].exists) - try textFields["enter last name"].enter(value: "Stanford") + try fillSignupForm(email: email, password: "StanfordRocks", name: PersonNameComponents(givenName: "Leland", familyName: "Stanford")) XCTAssertTrue(collectionViews.buttons["Signup"].exists) collectionViews.buttons["Signup"].tap() @@ -156,12 +152,8 @@ extension XCUIApplication { XCTAssertTrue(buttons["Allow Notifications"].exists) buttons["Allow Notifications"].tap() - - let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") - let alertAllowButton = springboard.buttons["Allow"] - if alertAllowButton.waitForExistence(timeout: 5) { - alertAllowButton.tap() - } + + confirmNotificationAuthorization(action: .allow) } fileprivate func assertOnboardingComplete() { @@ -189,8 +181,7 @@ extension XCUIApplication { XCTAssertTrue(navigationBars.buttons["Edit"].waitForExistence(timeout: 2)) navigationBars.buttons["Edit"].tap() - usleep(500_00) - XCTAssertFalse(navigationBars.buttons["Close"].exists) + XCTAssertTrue(navigationBars.buttons["Close"].waitForNonExistence(timeout: 0.5)) XCTAssertTrue(buttons["Delete Account"].waitForExistence(timeout: 2)) buttons["Delete Account"].tap() @@ -207,12 +198,7 @@ extension XCUIApplication { sleep(2) - // Login - try textFields["E-Mail Address"].enter(value: email) - try secureTextFields["Password"].enter(value: "StanfordRocks") - - XCTAssertTrue(buttons["Login"].waitForExistence(timeout: 0.5)) - buttons["Login"].tap() + try login(email: email, password: "StanfordRocks") XCTAssertTrue(alerts["Invalid Credentials"].waitForExistence(timeout: 2.0)) } diff --git a/TemplateApplicationUITests/SchedulerTests.swift b/TemplateApplicationUITests/SchedulerTests.swift index fef49bbe..8f7043e6 100644 --- a/TemplateApplicationUITests/SchedulerTests.swift +++ b/TemplateApplicationUITests/SchedulerTests.swift @@ -16,7 +16,7 @@ class SchedulerTests: XCTestCase { continueAfterFailure = false let app = XCUIApplication() - app.launchArguments = ["--skipOnboarding", "--testSchedule"] + app.launchArguments = ["--skipOnboarding"] app.deleteAndLaunch(withSpringboardAppName: "TemplateApplication") } @@ -30,9 +30,43 @@ class SchedulerTests: XCTestCase { XCTAssertTrue(app.tabBars["Tab Bar"].buttons["Schedule"].exists) app.tabBars["Tab Bar"].buttons["Schedule"].tap() - XCTAssertTrue(app.staticTexts["Start Questionnaire"].waitForExistence(timeout: 2)) - app.staticTexts["Start Questionnaire"].tap() + XCTAssertTrue(app.buttons["Start Questionnaire"].waitForExistence(timeout: 2)) + app.buttons["Start Questionnaire"].tap() XCTAssertTrue(app.staticTexts["Social Support"].waitForExistence(timeout: 2)) + XCTAssertTrue(app.navigationBars.buttons["Cancel"].exists) + + XCTAssertTrue(app.staticTexts["None of the time"].exists) + let noButton = app.staticTexts["None of the time"] + + let nextButton = app.buttons["Next"] + + for _ in 1...4 { + XCTAssertFalse(nextButton.isEnabled) + noButton.tap() + XCTAssertTrue(nextButton.isEnabled) + nextButton.tap() + usleep(500_000) + } + + XCTAssert(app.staticTexts["What is your age?"].waitForExistence(timeout: 0.5)) + XCTAssert(app.textFields["Tap to answer"].exists) + try app.textFields["Tap to answer"].enter(value: "25") + + XCTAssert(nextButton.isEnabled) + nextButton.tap() + + XCTAssert(app.staticTexts["What is your preferred contact method?"].waitForExistence(timeout: 0.5)) + XCTAssert(app.staticTexts["E-mail"].exists) + app.staticTexts["E-mail"].tap() + + XCTAssert(nextButton.isEnabled) + nextButton.tap() + + XCTAssert(app.staticTexts["Thank you for taking the survey!"].waitForExistence(timeout: 0.5)) + XCTAssert(app.buttons["Done"].exists) + app.buttons["Done"].tap() + + XCTAssert(app.staticTexts["Completed"].waitForExistence(timeout: 0.5)) } } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index bb38b7fe..f6f7ae37 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -20,7 +20,7 @@ platform :ios do skip_build: true, derived_data_path: ".derivedData", code_coverage: true, - devices: ["iPhone 15 Pro"], + devices: ["iPhone 16 Pro"], disable_slide_to_type: false, concurrent_workers: 1, max_concurrent_simulators: 1,