diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 404d73baf..f18b9da96 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -6,21 +6,22 @@ on: pull_request: branches: [ main ] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true -jobs: - +jobs: test: - - runs-on: macos-11 - + runs-on: macos-12 strategy: matrix: - destination: ['platform=iOS\ Simulator,OS=15.0,name=iPhone\ 11\ Pro\ Max'] - scheme: ['CareKit\ iOS', 'CareKitStore\ iOS', 'CareKitUI\ iOS', 'CareKitFHIR'] - + destination: ['platform=iOS\ Simulator,OS=16.2,name=iPhone\ 14\ Pro\ Max', 'platform=watchOS\ Simulator,OS=9.1,name=Apple\ Watch\ Series\ 5\ \(40mm\)'] + scheme: ['CareKit', 'CareKitStore', 'CareKitUI', 'CareKitFHIR'] steps: - uses: actions/checkout@v2 - name: Set Xcode Version - run: sudo xcode-select -s /Applications/Xcode_13.0.app + run: sudo xcode-select -s /Applications/Xcode_14.2.app + - name: Use multiple cores + run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1 - name: Build run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -verbose -workspace CKWorkspace.xcworkspace -scheme ${{ matrix.scheme }} -destination ${{ matrix.destination }} build test | xcpretty diff --git a/.gitignore b/.gitignore index 052dbb4ab..2d24cc563 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # # Xcode build/ +IDEWorkspaceChecks.plist *.pbxuser !default.pbxuser *.mode1v3 @@ -24,6 +25,7 @@ DerivedData # SPM .build/ +.swiftpm/ # DocC -.docc-build \ No newline at end of file +.docc-build diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 000000000..9a410b55c --- /dev/null +++ b/.spi.yml @@ -0,0 +1,11 @@ +version: 1 +builder: + configs: + - documentation_targets: ["CareKit", "CareKitUI", "CareKitStore", "CareKitFHIR"] + platform: ios + - platform: ios + scheme: "CareKit" + - platform: watchos + scheme: "CareKit" + - platform: macos + scheme: "CareKit" diff --git a/CKWorkspace.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CKWorkspace.xcworkspace/xcshareddata/swiftpm/Package.resolved index dfb60b1d5..bf455053b 100644 --- a/CKWorkspace.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CKWorkspace.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-async-algorithms", "state" : { - "revision" : "aed5422380244498344a036b8d94e27f370d9a22", - "version" : "0.0.4" + "revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a", + "version" : "0.1.0" } }, { diff --git a/CareKit/CareKit.xcodeproj/project.pbxproj b/CareKit/CareKit.xcodeproj/project.pbxproj index dea1f9094..8e797f8b5 100644 --- a/CareKit/CareKit.xcodeproj/project.pbxproj +++ b/CareKit/CareKit.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ @@ -883,8 +883,9 @@ 8605A5B11C4F04EC00DD65FF /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1020; - LastUpgradeCheck = 1420; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = carekit.org; TargetAttributes = { 5196C7F8226F8F8F00F1C2A2 = { @@ -936,7 +937,6 @@ }; /* End PBXResourcesBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 5196C7F5226F8F8F00F1C2A2 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -1107,6 +1107,7 @@ 5196C801226F8F8F00F1C2A2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -1120,7 +1121,7 @@ DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = CareKitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1130,16 +1131,19 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = Apple.CareKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos"; + SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; }; name = Debug; }; 5196C802226F8F8F00F1C2A2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -1153,7 +1157,7 @@ DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = CareKitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1162,8 +1166,10 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = Apple.CareKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos"; + SUPPORTS_MACCATALYST = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; }; name = Release; }; @@ -1231,7 +1237,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = "$(VERSION_NUMBER)"; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -1245,7 +1251,7 @@ TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 2.1; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -1307,7 +1313,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = "$(VERSION_NUMBER)"; MTL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = NO; @@ -1321,6 +1327,7 @@ VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -1338,16 +1345,19 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = CareKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = org.carekit.CareKit; PRODUCT_NAME = "$(PROJECT_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1362,7 +1372,7 @@ "SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*]" = DEBUG; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; TARGETED_DEVICE_FAMILY = "1,2,4"; - WATCHOS_DEPLOYMENT_TARGET = 6.0; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -1380,16 +1390,19 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = CareKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = org.carekit.CareKit; PRODUCT_NAME = "$(PROJECT_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1403,7 +1416,7 @@ SUPPORTS_UIKITFORMAC = NO; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; TARGETED_DEVICE_FAMILY = "1,2,4"; - WATCHOS_DEPLOYMENT_TARGET = 6.0; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; diff --git a/CareKit/CareKit.xcodeproj/xcshareddata/xcschemes/CareKit.xcscheme b/CareKit/CareKit.xcodeproj/xcshareddata/xcschemes/CareKit.xcscheme index ed17cc4f1..2452baaac 100644 --- a/CareKit/CareKit.xcodeproj/xcshareddata/xcschemes/CareKit.xcscheme +++ b/CareKit/CareKit.xcodeproj/xcshareddata/xcschemes/CareKit.xcscheme @@ -1,6 +1,6 @@ OCKAnyOutcome { return try await withCheckedThrowingContinuation { continuation in toggleBooleanOutcome(for: event, completion: continuation.resume) diff --git a/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequest.swift b/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequest.swift index 1128bf883..6543fe571 100644 --- a/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequest.swift +++ b/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequest.swift @@ -55,7 +55,7 @@ import SwiftUI /// You can inject the store through the environment like this: /// /// ContentView() -/// .environment(\.careKitStore, store) +/// .environment(\.careStore, store) /// /// See the `OCKAnyStoreProtocol` and the `OCKStore` for more information about /// creating a CareKit store. @@ -74,7 +74,6 @@ import SwiftUI /// ``` /// /// If you prefer to update the query date at a very specific time interval, see [`TimelineView`](https://www.google.com/search?client=safari&rls=en&q=timelineview&ie=UTF-8&oe=UTF-8&safari_group=3). -@available(iOS 14, watchOS 7, *) @propertyWrapper public struct CareStoreFetchRequest: DynamicProperty { @@ -132,7 +131,6 @@ public struct CareStoreFetchRequest: DynamicProperty { // MARK: - Fetching Store Entities -@available(iOS 14, watchOS 7, *) public extension CareStoreFetchRequest where Result == OCKAnyTask, Query == OCKTaskQuery @@ -155,7 +153,6 @@ public extension CareStoreFetchRequest where } } -@available(iOS 14, watchOS 7, *) public extension CareStoreFetchRequest where Result == OCKAnyEvent, Query == OCKEventQuery @@ -178,7 +175,6 @@ public extension CareStoreFetchRequest where } } -@available(iOS 14, watchOS 7, *) public extension CareStoreFetchRequest where Result == OCKAnyOutcome, Query == OCKOutcomeQuery @@ -201,7 +197,6 @@ public extension CareStoreFetchRequest where } } -@available(iOS 14, watchOS 7, *) public extension CareStoreFetchRequest where Result == OCKAnyContact, Query == OCKContactQuery @@ -224,7 +219,6 @@ public extension CareStoreFetchRequest where } } -@available(iOS 14, watchOS 7, *) public extension CareStoreFetchRequest where Result == OCKAnyPatient, Query == OCKPatientQuery @@ -247,7 +241,6 @@ public extension CareStoreFetchRequest where } } -@available(iOS 14, watchOS 7, *) public extension CareStoreFetchRequest where Result == OCKAnyCarePlan, Query == OCKCarePlanQuery @@ -270,7 +263,6 @@ public extension CareStoreFetchRequest where } } -@available(iOS 14, watchOS 7, *) private extension CareStoreFetchRequest where Query: Equatable { init( diff --git a/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequestController.swift b/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequestController.swift index e7e2ecd5c..0c63d598f 100644 --- a/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequestController.swift +++ b/CareKit/CareKit/Shared/Synchronization/CareStoreFetchRequestController.swift @@ -39,7 +39,6 @@ import SwiftUI /// /// - The result is generic, and is computed based on the provided `Result`. /// Going the generic route allows us to create a single controller for all of the entity types in the CareKit store. -@available(iOS 14, watchOS 7, *) final class CareStoreFetchRequestController: ObservableObject { typealias ComputeResults = ( @@ -92,6 +91,10 @@ final class CareStoreFetchRequestController: ObservableObject { ) } + deinit { + cancelStreamingTask() + } + /// Update the current query that is either pending or streaming. If the query is pending /// make sure to call `streamResults(store:)` explicitly to begin the streaming process. func update(query: Query) { @@ -195,7 +198,6 @@ final class CareStoreFetchRequestController: ObservableObject { } } -@available(iOS 14, watchOS 7, *) private extension CareStoreFetchRequestController { /// The status of a data stream from the CareKit store. @@ -217,7 +219,6 @@ private extension CareStoreFetchRequestController { // duplicate queries. We could avoid this indirection by making the // original generic conform to Equatable, but that locks us into that // conformance in the public API. -@available(iOS 14, watchOS 7, *) extension CareStoreFetchRequestController where Query: Equatable { convenience init( diff --git a/CareKit/CareKit/Shared/Synchronization/CareStoreFetchedResult+Extension.swift b/CareKit/CareKit/Shared/Synchronization/CareStoreFetchedResult+Extension.swift index d7c4ca959..e7b1532f8 100644 --- a/CareKit/CareKit/Shared/Synchronization/CareStoreFetchedResult+Extension.swift +++ b/CareKit/CareKit/Shared/Synchronization/CareStoreFetchedResult+Extension.swift @@ -33,8 +33,6 @@ import Foundation extension CareStoreFetchedResult where Result == OCKAnyEvent { - @available(iOS 15, *) - @available(watchOS 8, *) func toggleBooleanOutcome() async throws -> OCKAnyOutcome { try await store.toggleBooleanOutcome(for: result) } diff --git a/CareKit/CareKit/iOS/Calendar/Paging/OCKWeekCalendarPageViewController.swift b/CareKit/CareKit/iOS/Calendar/Paging/OCKWeekCalendarPageViewController.swift index e7b69b3f3..27145ecd5 100644 --- a/CareKit/CareKit/iOS/Calendar/Paging/OCKWeekCalendarPageViewController.swift +++ b/CareKit/CareKit/iOS/Calendar/Paging/OCKWeekCalendarPageViewController.swift @@ -83,7 +83,8 @@ UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelega /// The initial date displayed when the view controller is loaded. private let startingDate = Date() - private let store: OCKAnyStoreProtocol + /// The store the view controller uses for synchronization. + public let store: OCKAnyStoreProtocol // MARK: - Life Cycle diff --git a/CareKit/CareKit/iOS/Contact/View Controllers/OCKContactViewResponder.swift b/CareKit/CareKit/iOS/Contact/View Controllers/OCKContactViewResponder.swift index 9e8c15814..5fa07ef52 100644 --- a/CareKit/CareKit/iOS/Contact/View Controllers/OCKContactViewResponder.swift +++ b/CareKit/CareKit/iOS/Contact/View Controllers/OCKContactViewResponder.swift @@ -159,6 +159,16 @@ final class OCKContactViewResponder: NSObject, action: #selector(dismissViewController) ) + /* + TODO: Remove in the future. Explicitly setting the tint color here to support + current developers that have a SwiftUI lifecycle app and wrap this view + controller in a `UIViewControllerRepresentable` implementation...Tint color + is not propagated...etc. + */ + let tintColor = contactViewController.determineTintColor(from: contactView) + contactViewController.view.tintColor = tintColor + contactViewController.navigationItem.rightBarButtonItem?.tintColor = tintColor + let navigationController = UINavigationController(rootViewController: contactViewController) presenter?.present(navigationController, animated: true) } diff --git a/CareKit/CareKit/iOS/Extensions/UIViewController+Extensions.swift b/CareKit/CareKit/iOS/Extensions/UIViewController+Extensions.swift index 6521c2afb..c2ffa5107 100644 --- a/CareKit/CareKit/iOS/Extensions/UIViewController+Extensions.swift +++ b/CareKit/CareKit/iOS/Extensions/UIViewController+Extensions.swift @@ -50,5 +50,9 @@ internal extension UIViewController { stackView.insertArrangedSubview(view, at: index, animated: animated) didMove(toParent: containerViewController) } + + func determineTintColor(from view: UIView) -> UIColor { + self.view.window?.tintColor ?? view.tintColor + } } #endif diff --git a/CareKit/CareKit/iOS/Higher Order/ViewController/OCKDailyPageViewController.swift b/CareKit/CareKit/iOS/Higher Order/ViewController/OCKDailyPageViewController.swift index d5a7414f9..2c35534a2 100644 --- a/CareKit/CareKit/iOS/Higher Order/ViewController/OCKDailyPageViewController.swift +++ b/CareKit/CareKit/iOS/Higher Order/ViewController/OCKDailyPageViewController.swift @@ -77,11 +77,12 @@ UIPageViewControllerDataSource, UIPageViewControllerDelegate { return weekCalendarPageViewController.selectedDate } - /// The store manager the view controller uses for synchronization + /// The store manager the view controller uses for synchronization. @available(*, unavailable, renamed: "store") public var storeManager: OCKSynchronizedStoreManager! - let store: OCKAnyStoreProtocol + /// The store the view controller uses for synchronization. + public let store: OCKAnyStoreProtocol /// Page view managing ListViewControllers. private let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) diff --git a/CareKit/CareKit/iOS/Task/View Controllers/OCKSurveyTaskViewController.swift b/CareKit/CareKit/iOS/Task/View Controllers/OCKSurveyTaskViewController.swift index d5063447b..2b36b5c1b 100644 --- a/CareKit/CareKit/iOS/Task/View Controllers/OCKSurveyTaskViewController.swift +++ b/CareKit/CareKit/iOS/Task/View Controllers/OCKSurveyTaskViewController.swift @@ -133,65 +133,81 @@ open class OCKSurveyTaskViewController: OCKTaskViewController=5.8.0) + await fulfillment(of: [didUpdate], timeout: 2) + #else wait(for: [didUpdate], timeout: 2) + #endif } } diff --git a/CareKitFHIR/CareKitFHIR.xcodeproj/project.pbxproj b/CareKitFHIR/CareKitFHIR.xcodeproj/project.pbxproj index 4a9818f74..629e26ec9 100644 --- a/CareKitFHIR/CareKitFHIR.xcodeproj/project.pbxproj +++ b/CareKitFHIR/CareKitFHIR.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ @@ -26,7 +26,6 @@ 03C85E73233D7215002C5901 /* CareKitFHIRTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03C85E72233D7215002C5901 /* CareKitFHIRTests.swift */; }; 03C85E76233D721F002C5901 /* R4PatientConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03C85E75233D721F002C5901 /* R4PatientConverterTests.swift */; }; 03E5929123736D0D00B6E9DE /* DSTU2TaskConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E5929023736D0D00B6E9DE /* DSTU2TaskConverterTests.swift */; }; - 51266327291B1E0500C1D7DE /* Project-Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 51266326291B1E0500C1D7DE /* Project-Shared.xcconfig */; }; 51373774299E051E000AA8E1 /* ModelsDSTU2 in Frameworks */ = {isa = PBXBuildFile; productRef = 51373773299E051E000AA8E1 /* ModelsDSTU2 */; }; 51373776299E051E000AA8E1 /* ModelsR4 in Frameworks */ = {isa = PBXBuildFile; productRef = 51373775299E051E000AA8E1 /* ModelsR4 */; }; E746B33A2378F55600278A95 /* OCKDSTU2ScheduleCoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = E746B3392378F55600278A95 /* OCKDSTU2ScheduleCoder.swift */; }; @@ -269,8 +268,9 @@ 0396EF2D233D187800C28FC0 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1100; - LastUpgradeCheck = 1200; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = Apple; TargetAttributes = { 0396EF35233D187800C28FC0 = { @@ -310,7 +310,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 51266327291B1E0500C1D7DE /* Project-Shared.xcconfig in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -323,7 +322,6 @@ }; /* End PBXResourcesBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 0396EF32233D187800C28FC0 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -376,7 +374,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51266326291B1E0500C1D7DE /* Project-Shared.xcconfig */; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -425,16 +425,19 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = "$(VERSION_NUMBER)"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos"; + SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -442,7 +445,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51266326291B1E0500C1D7DE /* Project-Shared.xcconfig */; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -485,16 +490,19 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = "$(VERSION_NUMBER)"; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - SDKROOT = iphoneos; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos"; + SUPPORTS_MACCATALYST = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -502,13 +510,16 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51266326291B1E0500C1D7DE /* Project-Shared.xcconfig */; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = CareKitFHIR/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -517,14 +528,21 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = org.carekit.CareKitFHIR; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; RUN_DOCUMENTATION_COMPILER = YES; + SDKROOT = auto; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -532,13 +550,16 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51266326291B1E0500C1D7DE /* Project-Shared.xcconfig */; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = CareKitFHIR/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -547,19 +568,27 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = org.carekit.CareKitFHIR; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; RUN_DOCUMENTATION_COMPILER = YES; + SDKROOT = auto; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; 0396EF4E233D187800C28FC0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; @@ -572,15 +601,21 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.Apple.com.CareKitFHIRTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; 0396EF4F233D187800C28FC0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; @@ -593,8 +628,13 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.Apple.com.CareKitFHIRTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/CareKitFHIR/CareKitFHIR.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata rename to CareKitFHIR/CareKitFHIR.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/CareKitFHIR/CareKitFHIR.xcodeproj/xcshareddata/xcschemes/CareKitFHIR.xcscheme b/CareKitFHIR/CareKitFHIR.xcodeproj/xcshareddata/xcschemes/CareKitFHIR.xcscheme index 26ee78f41..94cf42b89 100644 --- a/CareKitFHIR/CareKitFHIR.xcodeproj/xcshareddata/xcschemes/CareKitFHIR.xcscheme +++ b/CareKitFHIR/CareKitFHIR.xcodeproj/xcshareddata/xcschemes/CareKitFHIR.xcscheme @@ -1,6 +1,6 @@ SampleChanges, updateCumulativeSumOfSamples: @escaping UpdateCumulativeSumOfSamples ) -> AsyncFlatMapSequence, [[OCKHealthKitPassthroughStore.Task]]>, [PartialEvent]>, [OCKHealthKitPassthroughStore.Event]>, AsyncThrowingExclusiveReductionsSequence, SampleChanges>, [OCKHealthKitPassthroughStore.Event]> + AsyncThrowingMapSequence, [[OCKHealthKitPassthroughStore.Task]]>, [PartialEvent]>, [OCKHealthKitPassthroughStore.Event]>, AsyncThrowingExclusiveReductionsSequence, SampleChanges>, [OCKHealthKitPassthroughStore.Event]> > where SampleChanges.Element == SampleChange { diff --git a/CareKitStore/CareKitStore/Logging/Logger+Init.swift b/CareKitStore/CareKitStore/Logging/Logger+Init.swift index 2ce2b5ec2..81d3b7287 100644 --- a/CareKitStore/CareKitStore/Logging/Logger+Init.swift +++ b/CareKitStore/CareKitStore/Logging/Logger+Init.swift @@ -31,7 +31,6 @@ import Foundation import os.log -@available(iOS 14, watchOS 7, *) extension Logger { static var store: Logger? { diff --git a/CareKitStore/CareKitStore/StoreCoordinator/OCKStoreCoordinator.swift b/CareKitStore/CareKitStore/StoreCoordinator/OCKStoreCoordinator.swift index ee0cc08c8..08d33afa9 100644 --- a/CareKitStore/CareKitStore/StoreCoordinator/OCKStoreCoordinator.swift +++ b/CareKitStore/CareKitStore/StoreCoordinator/OCKStoreCoordinator.swift @@ -208,7 +208,7 @@ open class OCKStoreCoordinator: OCKAnyStoreProtocol { // a single combined result is sent through the stream. // Create a stream that outputs a single empty result - let initialResults: AsyncLazySequence<[[T]]> = [[]].async + let initialResults: AsyncSyncSequence<[[T]]> = [[]].async let wrappedInitialResults = CareStoreQueryResults(wrapping: initialResults) let combinedResults = sequences.reduce(wrappedInitialResults) { partiallyCombinedResults, nextResults in @@ -315,7 +315,7 @@ open class OCKStoreCoordinator: OCKAnyStoreProtocol { open func taskStore(_ store: OCKAnyReadOnlyTaskStore, shouldHandleWritingTask task: OCKAnyTask) -> Bool { #if os(iOS) - if #available(iOS 15, *) { + if #available(iOS 15, watchOS 8, *) { // HealthKit stores should only respond to HealthKit tasks if store is OCKHealthKitPassthroughStore && !(task is OCKHealthKitTask) { return false } @@ -349,7 +349,7 @@ open class OCKStoreCoordinator: OCKAnyStoreProtocol { open func outcomeStore(_ store: OCKAnyReadOnlyOutcomeStore, shouldHandleWritingOutcome outcome: OCKAnyOutcome) -> Bool { #if os(iOS) - if #available(iOS 15, *) { + if #available(iOS 15, watchOS 8, *) { // Only the HK passthrough store should handle HK outcomes if outcome is OCKHealthKitOutcome || store is OCKHealthKitPassthroughStore { return store is OCKHealthKitPassthroughStore && outcome is OCKHealthKitOutcome diff --git a/CareKitStore/CareKitStore/Structs/OCKScheduleElement.swift b/CareKitStore/CareKitStore/Structs/OCKScheduleElement.swift index ac955d971..855a2469d 100644 --- a/CareKitStore/CareKitStore/Structs/OCKScheduleElement.swift +++ b/CareKitStore/CareKitStore/Structs/OCKScheduleElement.swift @@ -88,7 +88,7 @@ public struct OCKScheduleElement: Codable, Equatable { } } - private let calendar: Calendar + private static var calendar: Calendar { .current } /// An text about the time this element represents. /// e.g. before breakfast on Tuesdays, 5PM every day, etc. @@ -132,18 +132,15 @@ public struct OCKScheduleElement: Codable, Equatable { public init(start: Date, end: Date?, interval: DateComponents, text: String? = nil, targetValues: [OCKOutcomeValue] = [], duration: Duration = .hours(1)) { - let calendar = Calendar.current - precondition(end == nil || start < end!, "Start date must be before the end date!") - precondition(interval.movesForwardInTime(calendar: calendar), "Interval must not progress backwards in time!") + precondition(interval.movesForwardInTime(calendar: Self.calendar), "Interval must not progress backwards in time!") - self.start = duration == .allDay ? calendar.startOfDay(for: start) : start + self.start = duration == .allDay ? Self.calendar.startOfDay(for: start) : start self.end = end self.interval = interval self.text = text self.duration = duration self.targetValues = targetValues - self.calendar = calendar } /// Compute the Nth event of this schedule. @@ -165,8 +162,8 @@ public struct OCKScheduleElement: Codable, Equatable { /// - Returns: a new instance of with all event times offset by the given value. public func offset(by dateComponents: DateComponents) -> OCKScheduleElement { - let newStart = calendar.date(byAdding: dateComponents, to: start)! - let newEnd = end == nil ? nil : calendar.date(byAdding: dateComponents, to: end!)! + let newStart = Self.calendar.date(byAdding: dateComponents, to: start)! + let newEnd = end == nil ? nil : Self.calendar.date(byAdding: dateComponents, to: end!)! return OCKScheduleElement(start: newStart, end: newEnd, interval: interval, text: text, targetValues: targetValues, duration: duration) } @@ -272,7 +269,7 @@ public struct OCKScheduleElement: Codable, Equatable { events.append(event) // Create a new event for the next iteration - let start = calendar.date(byAdding: interval, to: event.start)! + let start = Self.calendar.date(byAdding: interval, to: event.start)! nextEvent = computeEvent( on: start, @@ -295,8 +292,8 @@ public struct OCKScheduleElement: Codable, Equatable { switch duration { case .allDay: - start = calendar.startOfDay(for: date) - end = calendar.date(byAdding: DateComponents(day: 1, second: -1), to: start)! + start = Self.calendar.startOfDay(for: date) + end = Self.calendar.date(byAdding: DateComponents(day: 1, second: -1), to: start)! case let .seconds(seconds): start = date @@ -332,8 +329,8 @@ public struct OCKScheduleElement: Codable, Equatable { case .allDay: // Subtract a second from the limit to ensure an exclusive end date - let adjustedLimit = calendar.date(byAdding: .second, value: -1, to: limit)! - let occursOnSameDayAsLimit = calendar.isDate(eventStart, inSameDayAs: adjustedLimit) + let adjustedLimit = Self.calendar.date(byAdding: .second, value: -1, to: limit)! + let occursOnSameDayAsLimit = Self.calendar.isDate(eventStart, inSameDayAs: adjustedLimit) return occursBeforeLimit || occursOnSameDayAsLimit } diff --git a/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Events.swift b/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Events.swift index 5c77dc77d..0f08f114b 100644 --- a/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Events.swift +++ b/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Events.swift @@ -37,7 +37,7 @@ import XCTest // Note, we test the event stream and not the outcome stream because the outcome stream // calls into the event stream. Testing the outcome stream is unnecessary. - +@available(iOS 15, watchOS 8, *) class TestHealthKitPassthroughStoreEvents: XCTestCase { private let cdStore = OCKStore( @@ -141,7 +141,7 @@ class TestHealthKitPassthroughStoreEvents: XCTestCase { func testInitialResultIsEmpty() async throws { - let noChanges: AsyncLazySequence<[SampleChange]> = [SampleChange()].async + let noChanges: AsyncSyncSequence<[SampleChange]> = [SampleChange()].async let query = OCKTaskQuery() @@ -173,7 +173,7 @@ class TestHealthKitPassthroughStoreEvents: XCTestCase { // Create a task query that does not include either of the existing tasks let query = OCKTaskQuery(id: "irrelevantTask") - let noChanges: AsyncLazySequence<[SampleChange]> = [].async + let noChanges: AsyncSyncSequence<[SampleChange]> = [].async let events = passthroughStore.events( matching: query, @@ -219,7 +219,7 @@ class TestHealthKitPassthroughStoreEvents: XCTestCase { let query = OCKTaskQuery(dateInterval: queryInterval) - let noChanges: AsyncLazySequence<[SampleChange]> = [].async + let noChanges: AsyncSyncSequence<[SampleChange]> = [].async let events = passthroughStore.events( matching: query, @@ -822,6 +822,7 @@ private struct Event: Equatable { var outcome: OCKHealthKitOutcome? } +@available(iOS 15, watchOS 8, *) private extension Event { init(_ event: OCKHealthKitPassthroughStore.Event) { diff --git a/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Outcomes.swift b/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Outcomes.swift index 35450ef98..d4c3d4b5b 100644 --- a/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Outcomes.swift +++ b/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitPassthroughStore+Outcomes.swift @@ -33,6 +33,7 @@ import HealthKit import XCTest +@available(iOS 15, watchOS 8, *) class TestHealthKitPassthroughStoreOutcomes: XCTestCase { private let cdStore = OCKStore( diff --git a/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitStore+Tasks.swift b/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitStore+Tasks.swift index 62198a5a5..c4e7116fb 100644 --- a/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitStore+Tasks.swift +++ b/CareKitStore/CareKitStoreTests/OCKHealthKitStore/TestHealthKitStore+Tasks.swift @@ -31,6 +31,7 @@ @testable import CareKitStore import XCTest +@available(iOS 15, watchOS 8, *) class TestHealthKitStoreTasks: XCTestCase { var store: OCKHealthKitPassthroughStore! let link = OCKHealthKitLinkage(quantityIdentifier: .stepCount, quantityType: .cumulative, unit: .count()) diff --git a/CareKitStore/CareKitStoreTests/OCKStoreCoordinator/TestPersistentStoreCoordinator.swift b/CareKitStore/CareKitStoreTests/OCKStoreCoordinator/TestPersistentStoreCoordinator.swift index 09035d99f..cbe01694e 100644 --- a/CareKitStore/CareKitStoreTests/OCKStoreCoordinator/TestPersistentStoreCoordinator.swift +++ b/CareKitStore/CareKitStoreTests/OCKStoreCoordinator/TestPersistentStoreCoordinator.swift @@ -41,7 +41,7 @@ class MockPatientStore: OCKPatientStore { patients = [] } - func patients(matching query: OCKPatientQuery) -> AsyncLazySequence<[[OCKPatient]]> { + func patients(matching query: OCKPatientQuery) -> AsyncSyncSequence<[[OCKPatient]]> { return [patients].async } @@ -166,6 +166,7 @@ class TestPersistentStoreCoordinator: XCTestCase { XCTAssert(store2.patients.isEmpty) } + @available(iOS 15, watchOS 8, *) func testFetchCanResultInAnArrayPopulatedWithDifferentTypes() throws { let coordinator = OCKStoreCoordinator() let schedule = OCKSchedule.mealTimesEachDay(start: Date(), end: nil) @@ -199,6 +200,8 @@ class TestPersistentStoreCoordinator: XCTestCase { XCTAssertThrowsError(try coordinator.addAnyTaskAndWait(task)) } +#if !os(watchOS) + @available(iOS 15, watchOS 8, *) func testStoreCoordinatorDoesNotSendNormalOutcomesToHealthKit() { let coordinator = OCKStoreCoordinator() let store = OCKStore(name: UUID().uuidString, type: .inMemory) @@ -215,7 +218,9 @@ class TestPersistentStoreCoordinator: XCTestCase { let willHandle = coordinator.outcomeStore(store, shouldHandleWritingOutcome: outcome) XCTAssertFalse(willHandle) } - +#endif + + @available(iOS 15, watchOS 8, *) func testCanAssociateHealthKitTaskWithCarePlan() throws { let store = OCKStore(name: UUID().uuidString, type: .inMemory) let passthrough = OCKHealthKitPassthroughStore(store: store) @@ -237,6 +242,7 @@ class TestPersistentStoreCoordinator: XCTestCase { } } +@available(iOS 15, watchOS 8, *) private struct SeededTaskStore { let store: OCKStoreCoordinator diff --git a/CareKitStore/CareKitStoreTests/Streaming/TestCoreDataQueryMonitor.swift b/CareKitStore/CareKitStoreTests/Streaming/TestCoreDataQueryMonitor.swift index 1e2410497..511bc5ae9 100644 --- a/CareKitStore/CareKitStoreTests/Streaming/TestCoreDataQueryMonitor.swift +++ b/CareKitStore/CareKitStoreTests/Streaming/TestCoreDataQueryMonitor.swift @@ -214,6 +214,11 @@ class TestCoreDataQueryMonitor: XCTestCase { XCTAssertEqual(expectedTitles, observedTitles) } + /* + TODO: Remove in the future when macOS 13 image release for GitHub actions. + GitHub actions currently only supports macOS 12 and Xcode 14.2. + */ + #if compiler(>=5.8.0) func testIrrelevantChangeDoesNotProduceResult() async throws { // Add tasks to the store @@ -264,11 +269,12 @@ class TestCoreDataQueryMonitor: XCTestCase { monitor.startQuery() - wait(for: [didProduceResult, didDeleteTasks], timeout: 2) + await fulfillment(of: [didProduceResult, didDeleteTasks], timeout: 2) monitor.stopQuery() } - + #endif + func testCancelledStreamDoesNotProduceResult() throws { // Add tasks to the store diff --git a/CareKitStore/CareKitStoreTests/Streaming/TestCoreDataSource.swift b/CareKitStore/CareKitStoreTests/Streaming/TestCoreDataSource.swift deleted file mode 100644 index 9929eb8cd..000000000 --- a/CareKitStore/CareKitStoreTests/Streaming/TestCoreDataSource.swift +++ /dev/null @@ -1,368 +0,0 @@ -/* - Copyright (c) 2022, Apple Inc. All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - - 3. Neither the name of the copyright holder(s) nor the names of any contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. No license is granted to the trademarks of - the copyright holders even if such marks are included in this software. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -import Combine -import Foundation -import XCTest - -@testable import CareKitStore - -class TestCoreDataQueryPublisher: XCTestCase { - - private let store = OCKStore( - name: "CoreDataExecutorTests.Store", - type: .inMemory - ) - - override func setUpWithError() throws { - try super.setUpWithError() - try store.reset() - } - - func testInitialResultIsForwardedAndSorted() throws { - - // Add tasks to the store - - let expectedTasks = [ - makeSampleTask(idAndTitle: "taskA"), - makeSampleTask(idAndTitle: "taskB") - ] - - try store.addTasksAndWait(expectedTasks) - - // Validate the initial published result - - let didReceiveResult = XCTestExpectation(description: "Received result") - didReceiveResult.assertForOverFulfill = true - - let coreDataSource = CoreDataSource( - OCKCDTask.self, - predicate: NSPredicate(value: true), - sortDescriptors: [NSSortDescriptor(keyPath: \OCKCDTask.title, ascending: true)], - context: store.context - ) - - let cancellable = QueryPublisher(dataSource: coreDataSource) - // Should never fail - .catch { error -> Empty<[OCKCDTask], Never> in - XCTFail(error.localizedDescription) - return Empty() - } - .sink { observedTasks in - - let expectedTitles = expectedTasks.map(\.title) - let observedTitles = observedTasks.map(\.title) - XCTAssertEqual(expectedTitles, observedTitles) - - didReceiveResult.fulfill() - } - - wait(for: [didReceiveResult], timeout: 2) - cancellable.cancel() - } - - func testResultIsForwardedWhenAddOccurs() throws { - - let expectedTasks = [ - makeSampleTask(idAndTitle: "taskA"), - makeSampleTask(idAndTitle: "taskB") - ] - - var didAddTasks = false - - let didReceiveResult = XCTestExpectation(description: "Result received") - didReceiveResult.assertForOverFulfill = true - didReceiveResult.expectedFulfillmentCount = 2 - - let coreDataSource = CoreDataSource( - OCKCDTask.self, - predicate: NSPredicate(value: true), - sortDescriptors: [NSSortDescriptor(keyPath: \OCKCDTask.title, ascending: true)], - context: store.context - ) - - let cancellable = QueryPublisher(dataSource: coreDataSource) - // Should never fail - .catch { error -> Empty<[OCKCDTask], Never> in - XCTFail(error.localizedDescription) - return Empty() - } - .sink { observedTasks in - - // Add the tasks if they have not yet been added - if !didAddTasks { - - XCTAssertEqual(observedTasks.count, 0) - - try! self.store.addTasksAndWait(expectedTasks) - didAddTasks = true - - // Validate the newly added tasks - } else { - - let expectedTitles = expectedTasks.map(\.title) - let observedTitles = observedTasks.map(\.title) - XCTAssertEqual(expectedTitles, observedTitles) - } - didReceiveResult.fulfill() - } - - wait(for: [didReceiveResult], timeout: 2) - cancellable.cancel() - } - - func testResultIsForwardedWhenDeleteOccurs() throws { - - // Add tasks to the store - - let expectedTasks = [ - makeSampleTask(idAndTitle: "taskA"), - makeSampleTask(idAndTitle: "taskB") - ] - - try store.addTasksAndWait(expectedTasks) - - // Stream tasks from the store - - var didDeleteTasks = false - - let didReceiveResult = XCTestExpectation(description: "Result received") - didReceiveResult.assertForOverFulfill = true - didReceiveResult.expectedFulfillmentCount = 2 - - let coreDataSource = CoreDataSource( - OCKCDTask.self, - predicate: NSPredicate(value: true), - sortDescriptors: [NSSortDescriptor(keyPath: \OCKCDTask.title, ascending: true)], - context: store.context - ) - - let cancellable = QueryPublisher(dataSource: coreDataSource) - // Should never fail - .catch { error -> Empty<[OCKCDTask], Never> in - XCTFail(error.localizedDescription) - return Empty() - } - .sink { observedTasks in - - // Add the tasks if they have not yet been added - if !didDeleteTasks { - - XCTAssertEqual(observedTasks.count, expectedTasks.count) - - try! self.store.reset() - didDeleteTasks = true - - // Validate the newly deleted tasks - } else { - - XCTAssertEqual(observedTasks.count, 0) - } - didReceiveResult.fulfill() - } - - wait(for: [didReceiveResult], timeout: 2) - cancellable.cancel() - } - - func testResultIsForwardedWhenUpdateOccurs() throws { - - // Add tasks to the store - - let originalTasks = [ - makeSampleTask(idAndTitle: "taskA"), - makeSampleTask(idAndTitle: "taskB") - ] - - let updatedTitles = ["taskC", "taskD"] - - try store.addTasksAndWait(originalTasks) - - // Stream tasks from the store - - var didUpdateTasks = false - - let didReceiveResult = XCTestExpectation(description: "Result received") - didReceiveResult.assertForOverFulfill = true - didReceiveResult.expectedFulfillmentCount = 2 - - let coreDataSource = CoreDataSource( - OCKCDTask.self, - predicate: NSPredicate(value: true), - sortDescriptors: [NSSortDescriptor(keyPath: \OCKCDTask.title, ascending: true)], - context: store.context - ) - - let cancellable = QueryPublisher(dataSource: coreDataSource) - // Should never fail - .catch { error -> Empty<[OCKCDTask], Never> in - XCTFail(error.localizedDescription) - return Empty() - } - .sink { observedTasks in - - // Update the tasks in the store - if !didUpdateTasks { - - XCTAssertEqual(observedTasks.count, originalTasks.count) - - let updatedTasks = observedTasks - .map { $0.makeTask() } - .enumerated() - .map { index, task -> OCKTask in - var updatedTask = task - updatedTask.title = updatedTitles[index] - updatedTask.effectiveDate = Date() - return updatedTask - } - - try! self.store.updateTasksAndWait(updatedTasks) - - didUpdateTasks = true - - // Validate the newly updated tasks - } else { - - let expectedTitles = - originalTasks.map(\.title) + - updatedTitles - - let observedTitles = observedTasks.map(\.title) - - XCTAssertEqual(expectedTitles, observedTitles) - } - - didReceiveResult.fulfill() - } - - wait(for: [didReceiveResult], timeout: 2) - cancellable.cancel() - } - - func testIrrelevantChangeDoesNotTriggerResult() throws { - - // Add tasks to the store - - let tasks = [ - makeSampleTask(idAndTitle: "taskA"), - makeSampleTask(idAndTitle: "taskB") - ] - - try store.addTasksAndWait(tasks) - - // Stream tasks from the store - - let didReceiveResult = XCTestExpectation(description: "Result received") - didReceiveResult.assertForOverFulfill = true - - let coreDataSource = CoreDataSource( - OCKCDTask.self, - predicate: NSPredicate(value: false), - sortDescriptors: [], - context: store.context - ) - - let cancellable = QueryPublisher(dataSource: coreDataSource) - // Should never fail - .catch { error -> Empty<[OCKCDTask], Never> in - XCTFail(error.localizedDescription) - return Empty() - } - .sink { _ in - - try! self.store.reset() - - didReceiveResult.fulfill() - } - - wait(for: [didReceiveResult], timeout: 2) - cancellable.cancel() - } - - func testCancelledStreamDoesNotTriggerResult() throws { - - // Add tasks to the store - - let tasks = [ - makeSampleTask(idAndTitle: "taskA"), - makeSampleTask(idAndTitle: "taskB") - ] - - try store.addTasksAndWait(tasks) - - // Stream tasks from the store - - let didReceiveResult = XCTestExpectation(description: "Result received") - didReceiveResult.assertForOverFulfill = true - - let coreDataSource = CoreDataSource( - OCKCDTask.self, - predicate: NSPredicate(value: true), - sortDescriptors: [], - context: store.context - ) - - let cancellable = QueryPublisher(dataSource: coreDataSource) - // Should never fail - .catch { error -> Empty<[OCKCDTask], Never> in - XCTFail(error.localizedDescription) - return Empty() - } - .sink { _ in - didReceiveResult.fulfill() - } - - wait(for: [didReceiveResult], timeout: 2) - cancellable.cancel() - - // Trigger a change to the observed tasks. SInk block - // should not get called. - try store.reset() - } - - // MARK: Utilities - - private func makeSampleTask(idAndTitle: String) -> OCKTask { - - let startOfDay = Calendar.current.startOfDay(for: Date()) - - let schedule = OCKSchedule - .dailyAtTime(hour: 7, minutes: 0, start: startOfDay, end: nil, text: nil) - - let task = OCKTask( - id: idAndTitle, - title: idAndTitle, - carePlanUUID: nil, - schedule: schedule - ) - - return task - } -} diff --git a/CareKitStore/CareKitStoreTests/Structs/TestKnowledgeVector.swift b/CareKitStore/CareKitStoreTests/Structs/TestKnowledgeVector.swift index f5c457887..f09205d6f 100644 --- a/CareKitStore/CareKitStoreTests/Structs/TestKnowledgeVector.swift +++ b/CareKitStore/CareKitStoreTests/Structs/TestKnowledgeVector.swift @@ -35,7 +35,7 @@ import XCTest class TestKnowledgeVector: XCTestCase { func testEncoding() throws { - let id = UIDevice.current.identifierForVendor! + let id = UUID() let vector = OCKRevisionRecord.KnowledgeVector([id: 0]) let json = try JSONEncoder().encode(vector) let string = String(data: json, encoding: .utf8)! @@ -44,7 +44,7 @@ class TestKnowledgeVector: XCTestCase { } func testDecoding() throws { - let id = UIDevice.current.identifierForVendor! + let id = UUID() let json = "{\"processes\":[{\"id\":\"\(id)\",\"clock\":0}]}" let data = json.data(using: .utf8)! let vector = try JSONDecoder().decode(OCKRevisionRecord.KnowledgeVector.self, from: data) @@ -53,7 +53,7 @@ class TestKnowledgeVector: XCTestCase { func testInitialLogicalTimeForOwnProcess() throws { let vect = OCKRevisionRecord.KnowledgeVector() - let uuid = UIDevice.current.identifierForVendor! + let uuid = UUID() let time = vect.clock(for: uuid) XCTAssert(time == 0) } @@ -68,7 +68,7 @@ class TestKnowledgeVector: XCTestCase { } func testMergeWithOtherVector() throws { - let uuid1 = UIDevice.current.identifierForVendor! + let uuid1 = UUID() let uuid2 = UUID() let uuid3 = UUID() diff --git a/CareKitUI/CareKitUI.xcodeproj/project.pbxproj b/CareKitUI/CareKitUI.xcodeproj/project.pbxproj index 93aab4e73..9f4cf4e8c 100644 --- a/CareKitUI/CareKitUI.xcodeproj/project.pbxproj +++ b/CareKitUI/CareKitUI.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ @@ -107,6 +107,7 @@ 64E1BD4E2309FCF200DFFE52 /* OCKResponsiveLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64E1BD4D2309FCF200DFFE52 /* OCKResponsiveLayout.swift */; }; 64EEC2382318253B00B1012F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 64EEC2362318253B00B1012F /* Localizable.strings */; }; 64EEC23B231825DD00B1012F /* OCKLocalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EEC23A231825DD00B1012F /* OCKLocalization.swift */; }; + 70FC4F3229F18489007DF34F /* TestColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511A854723E0CAA2002A2AFB /* TestColorExtension.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -663,8 +664,9 @@ 51742252224185290054E97C /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1100; - LastUpgradeCheck = 1420; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = Apple; TargetAttributes = { 512B012D22C2F82900ABCB1D = { @@ -725,6 +727,7 @@ 51052549244639B3004483D0 /* TestLinkView.swift in Sources */, 51746F2B2448B90B00B647E1 /* TestNumericProgressTaskView.swift in Sources */, 51AB06C222FE53E300B73FC2 /* TestStylableView.swift in Sources */, + 70FC4F3229F18489007DF34F /* TestColorExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -859,10 +862,11 @@ 512B013622C2F82900ABCB1D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; INFOPLIST_FILE = CareKitUITests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -870,17 +874,21 @@ ); PRODUCT_BUNDLE_IDENTIFIER = Apple.CareKitUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; }; name = Debug; }; 512B013722C2F82900ABCB1D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = CareKitUITests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -888,8 +896,11 @@ ); PRODUCT_BUNDLE_IDENTIFIER = Apple.CareKitUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,4"; }; name = Release; }; @@ -897,6 +908,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51266314291B123B00C1D7DE /* Project-Shared.xcconfig */; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ADDRESS_SANITIZER_CONTAINER_OVERFLOW = YES; CLANG_ANALYZER_NONNULL = YES; @@ -962,19 +974,22 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = "$(VERSION_NUMBER)"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; RUN_CLANG_STATIC_ANALYZER = YES; - SDKROOT = iphoneos; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos"; + SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -982,6 +997,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51266314291B123B00C1D7DE /* Project-Shared.xcconfig */; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ADDRESS_SANITIZER_CONTAINER_OVERFLOW = YES; CLANG_ANALYZER_NONNULL = YES; @@ -1041,12 +1057,14 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = "$(VERSION_NUMBER)"; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; RUN_CLANG_STATIC_ANALYZER = YES; - SDKROOT = iphoneos; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "watchsimulator watchos iphonesimulator iphoneos"; + SUPPORTS_MACCATALYST = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; @@ -1054,6 +1072,7 @@ VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -1070,15 +1089,18 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = "$(SRCROOT)/CareKitUI/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = org.carekit.CareKitUI; PRODUCT_NAME = "$(PROJECT_NAME)"; RUN_DOCUMENTATION_COMPILER = YES; @@ -1090,7 +1112,7 @@ SUPPORTS_UIKITFORMAC = NO; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; TARGETED_DEVICE_FAMILY = "1,2,4"; - WATCHOS_DEPLOYMENT_TARGET = 6.0; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -1107,15 +1129,18 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = "$(SRCROOT)/CareKitUI/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = org.carekit.CareKitUI; PRODUCT_NAME = "$(PROJECT_NAME)"; RUN_DOCUMENTATION_COMPILER = YES; @@ -1127,7 +1152,7 @@ SUPPORTS_UIKITFORMAC = NO; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; TARGETED_DEVICE_FAMILY = "1,2,4"; - WATCHOS_DEPLOYMENT_TARGET = 6.0; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; diff --git a/CareKitUI/CareKitUI.xcodeproj/xcshareddata/xcschemes/CareKitUI.xcscheme b/CareKitUI/CareKitUI.xcodeproj/xcshareddata/xcschemes/CareKitUI.xcscheme index 265b8e325..ff4ea51f3 100644 --- a/CareKitUI/CareKitUI.xcodeproj/xcshareddata/xcschemes/CareKitUI.xcscheme +++ b/CareKitUI/CareKitUI.xcodeproj/xcshareddata/xcschemes/CareKitUI.xcscheme @@ -1,6 +1,6 @@ | /// +-------------------------------------------------+ /// ``` -@available(iOS 14, *) struct LinkButton: View { @State private var isInAppContentPresented = false @@ -98,7 +97,6 @@ struct LinkButton: View { } } -@available(iOS 14, *) extension LinkButton where Label == LinkLabel { /// Create an instance. diff --git a/CareKitUI/CareKitUI/iOS/Link/LinkView.swift b/CareKitUI/CareKitUI/iOS/Link/LinkView.swift index 89267cc37..0541e8f71 100644 --- a/CareKitUI/CareKitUI/iOS/Link/LinkView.swift +++ b/CareKitUI/CareKitUI/iOS/Link/LinkView.swift @@ -58,7 +58,6 @@ import SwiftUI /// | | /// +-------------------------------------------------------+ /// ``` -@available(iOS 14, *) public struct LinkView: View { @Environment(\.careKitStyle) @@ -122,7 +121,6 @@ public struct LinkView: View { } } -@available(iOS 14, *) public extension LinkView where Header == _LinkViewHeader { /// Create an instance. @@ -148,7 +146,6 @@ public extension LinkView where Header == _LinkViewHeader { } /// Default header used by a `LinkView`. -@available(iOS 14, *) public struct _LinkViewHeader: View { @Environment(\.careKitStyle) @@ -172,7 +169,6 @@ public struct _LinkViewHeader: View { } #if DEBUG -@available(iOS 14, *) struct LinkViewPreview: PreviewProvider { static var links: [LinkItem] = [ diff --git a/CareKitUI/CareKitUITests/Link/TestLinkType.swift b/CareKitUI/CareKitUITests/Link/TestLinkType.swift index d6a66c7c3..7a693a98c 100644 --- a/CareKitUI/CareKitUITests/Link/TestLinkType.swift +++ b/CareKitUI/CareKitUITests/Link/TestLinkType.swift @@ -28,6 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if !os(watchOS) import Foundation @testable import CareKitUI @@ -87,3 +88,4 @@ class TestLinkType: XCTestCase { XCTAssertNil(observed) } } +#endif diff --git a/CareKitUI/CareKitUITests/Link/TestLinkView.swift b/CareKitUI/CareKitUITests/Link/TestLinkView.swift index dfe9a4c52..d8069812a 100644 --- a/CareKitUI/CareKitUITests/Link/TestLinkView.swift +++ b/CareKitUI/CareKitUITests/Link/TestLinkView.swift @@ -28,11 +28,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if !os(watchOS) import CareKitUI import SwiftUI import XCTest -@available(iOS 14, *) class TestLinkView: XCTestCase { private let text = Text("Hello World") @@ -51,3 +51,4 @@ class TestLinkView: XCTestCase { _ = LinkView(links: links, header: { }) } } +#endif diff --git a/CareKitUI/CareKitUITests/OCKResponsiveLayoutTests.swift b/CareKitUI/CareKitUITests/OCKResponsiveLayoutTests.swift index 4c6d9d482..6a8f0ee4d 100644 --- a/CareKitUI/CareKitUITests/OCKResponsiveLayoutTests.swift +++ b/CareKitUI/CareKitUITests/OCKResponsiveLayoutTests.swift @@ -28,6 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if !os(watchOS) @testable import CareKitUI import XCTest @@ -291,3 +292,4 @@ class OCKResponsiveLayoutTests: XCTestCase { } } } +#endif diff --git a/CareKitUI/CareKitUITests/Task/TestGridTaskView.swift b/CareKitUI/CareKitUITests/Task/TestGridTaskView.swift index 3b98c9823..9b22e8c68 100644 --- a/CareKitUI/CareKitUITests/Task/TestGridTaskView.swift +++ b/CareKitUI/CareKitUITests/Task/TestGridTaskView.swift @@ -28,6 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if !os(watchOS) @testable import CareKitUI import Foundation import XCTest @@ -64,3 +65,4 @@ public class TestGridTaskView: XCTestCase { XCTAssertEqual(observed, 100) } } +#endif diff --git a/CareKitUI/CareKitUITests/Task/TestNumericProgressTaskView.swift b/CareKitUI/CareKitUITests/Task/TestNumericProgressTaskView.swift index ee1f1d469..6ee2e2ce1 100644 --- a/CareKitUI/CareKitUITests/Task/TestNumericProgressTaskView.swift +++ b/CareKitUI/CareKitUITests/Task/TestNumericProgressTaskView.swift @@ -28,6 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if !os(watchOS) import CareKitUI import SwiftUI import XCTest @@ -46,3 +47,4 @@ class TestNumericProgressTaskView: XCTestCase { _ = NumericProgressTaskView(progress: text, goal: text, isComplete: true, header: { }) } } +#endif diff --git a/CareKitUI/CareKitUITests/TestColorExtension.swift b/CareKitUI/CareKitUITests/TestColorExtension.swift index 45dbc8424..45040bb87 100644 --- a/CareKitUI/CareKitUITests/TestColorExtension.swift +++ b/CareKitUI/CareKitUITests/TestColorExtension.swift @@ -56,7 +56,7 @@ class TestColorExtension: XCTestCase { func testClamping() { let start = UIColor(red: 0, green: 0, blue: 0, alpha: 1) - let lightened = start.lightened(10) + let lightened = start.lightened(1) XCTAssertEqual(lightened, UIColor(red: 1, green: 1, blue: 1, alpha: 1)) } } diff --git a/CareKitUI/CareKitUITests/TestStylableView.swift b/CareKitUI/CareKitUITests/TestStylableView.swift index 60ba15b95..8ca757907 100644 --- a/CareKitUI/CareKitUITests/TestStylableView.swift +++ b/CareKitUI/CareKitUITests/TestStylableView.swift @@ -28,6 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if !os(watchOS) @testable import CareKitUI import XCTest @@ -200,3 +201,4 @@ class TestStylableView: XCTestCase { XCTAssertEqual(innerView.layer.cornerRadius, MockOverridingView.cornerRadius) } } +#endif diff --git a/Package.resolved b/Package.resolved index 0d0e064ef..ed6e24e42 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,34 +1,32 @@ { - "object": { - "pins": [ - { - "package": "FHIRModels", - "repositoryURL": "https://github.com/apple/FHIRModels.git", - "state": { - "branch": null, - "revision": "e115442fb3c5d44ffb1dc9b4e039b77fd143ad96", - "version": "0.4.0" - } - }, - { - "package": "AsyncAlgorithms", - "repositoryURL": "https://github.com/apple/swift-async-algorithms", - "state": { - "branch": null, - "revision": "aed5422380244498344a036b8d94e27f370d9a22", - "version": "0.0.4" - } - }, - { - "package": "swift-collections", - "repositoryURL": "https://github.com/apple/swift-collections.git", - "state": { - "branch": null, - "revision": "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version": "1.0.4" - } + "pins" : [ + { + "identity" : "fhirmodels", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/FHIRModels.git", + "state" : { + "revision" : "e115442fb3c5d44ffb1dc9b4e039b77fd143ad96", + "version" : "0.4.0" } - ] - }, - "version": 1 + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms", + "state" : { + "revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a", + "version" : "0.1.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", + "version" : "1.0.4" + } + } + ], + "version" : 2 } diff --git a/Package.swift b/Package.swift index 762cafbd1..b388c446d 100644 --- a/Package.swift +++ b/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "CareKit", defaultLocalization: "en", - platforms: [.iOS(.v13), .macOS(.v10_15), .watchOS(.v6)], + platforms: [.iOS(.v14), .macOS(.v11), .watchOS(.v7)], products: [ .library( name: "CareKit", @@ -29,7 +29,7 @@ let package = Package( ), .package( url: "https://github.com/apple/swift-async-algorithms", - exact: Version(0, 0, 4) + exact: Version(0, 1, 0) ) ], targets: [ @@ -74,6 +74,12 @@ let package = Package( .process("CoreDataSchema/Migrations") ]), + .testTarget( + name: "CareKitUITests", + dependencies: ["CareKitUI"], + path: "CareKitUI/CareKitUITests", + exclude: ["Info.plist", "CareKitUI.xctestplan"]), + .testTarget( name: "CareKitFHIRTests", dependencies: ["CareKitFHIR"], diff --git a/README.md b/README.md index 3a54f5457..a5d0ff2bb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # CareKit -[![License](https://img.shields.io/badge/license-BSD-green.svg?style=flat)](https://github.com/carekit-apple/CareKit#license) ![Swift](https://img.shields.io/badge/swift-5.0-brightgreen.svg) ![Xcode 11.0+](https://img.shields.io/badge/Xcode-11.0%2B-blue.svg) ![iOS 13.0+](https://img.shields.io/badge/iOS-13.0%2B-blue.svg) [![SPM](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) +[![License](https://img.shields.io/badge/license-BSD-green.svg?style=flat)](https://github.com/carekit-apple/CareKit#license) [![Swift Versions](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcarekit-apple%2FCareKit%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/carekit-apple/CareKit) [![OS's](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcarekit-apple%2FCareKit%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/carekit-apple/CareKit) ![Xcode 14.0+](https://img.shields.io/badge/Xcode-14.0%2B-blue.svg) [![SPM](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) CareKit™ is an open source software framework for creating apps that help people better understand and manage their health. The framework provides modules that you can use out of the box, or extended and customized for more targeted use cases. It's composed of three SPM packages which can each be imported separately.