diff --git a/OCKSample.xcodeproj/project.pbxproj b/OCKSample.xcodeproj/project.pbxproj index 4571fe4..5ed1d97 100644 --- a/OCKSample.xcodeproj/project.pbxproj +++ b/OCKSample.xcodeproj/project.pbxproj @@ -937,17 +937,22 @@ ); GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = "$(SRCROOT)/OCKSample/Supporting Files/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = edu.uky.netrecon.ParseCarekitSample; + MACOSX_DEPLOYMENT_TARGET = 15.0; + PRODUCT_BUNDLE_IDENTIFIER = edu.usc.netrecon.ParseCarekitSample; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; TARGETED_DEVICE_FAMILY = "1,2,7"; + XROS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; @@ -957,7 +962,7 @@ CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; INFOPLIST_FILE = OCKSampleUITests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1017,7 +1022,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = OCKSampleUITests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1054,14 +1059,14 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = edu.uky.netrecon.ParseCarekitSample.watchkitapp; + PRODUCT_BUNDLE_IDENTIFIER = edu.usc.netrecon.ParseCarekitSample.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 11.0; }; name = Debug; }; @@ -1081,13 +1086,13 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = edu.uky.netrecon.ParseCarekitSample.watchkitapp; + PRODUCT_BUNDLE_IDENTIFIER = edu.usc.netrecon.ParseCarekitSample.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 11.0; }; name = Release; }; @@ -1174,17 +1179,22 @@ ); GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = "$(SRCROOT)/OCKSample/Supporting Files/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = edu.uky.netrecon.ParseCarekitSample; + MACOSX_DEPLOYMENT_TARGET = 15.0; + PRODUCT_BUNDLE_IDENTIFIER = edu.usc.netrecon.ParseCarekitSample; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_TREAT_WARNINGS_AS_ERRORS = NO; TARGETED_DEVICE_FAMILY = "1,2,7"; + XROS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; @@ -1235,7 +1245,7 @@ repositoryURL = "https://github.com/netreconlab/CareKitEssentials"; requirement = { kind = upToNextMajorVersion; - minimumVersion = "1.0.0-alpha.31"; + minimumVersion = "1.0.0-alpha.34"; }; }; 70202EBF2807333900CF73FB /* XCRemoteSwiftPackageReference "CareKit" */ = { diff --git a/OCKSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/OCKSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3686c49..a617c09 100644 --- a/OCKSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/OCKSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/netreconlab/CareKitEssentials", "state" : { - "revision" : "8df6c52a65d7881611acb23178b39d08c44ebd21", - "version" : "1.0.0-alpha.32" + "revision" : "5c1535887bb9d567a5a084820e6d3c7a87864acd", + "version" : "1.0.0-alpha.34" } }, { diff --git a/OCKSample/Extensions/AppDelegate+ParseRemoteDelegate.swift b/OCKSample/Extensions/AppDelegate+ParseRemoteDelegate.swift index 5f8c72e..02fb14c 100644 --- a/OCKSample/Extensions/AppDelegate+ParseRemoteDelegate.swift +++ b/OCKSample/Extensions/AppDelegate+ParseRemoteDelegate.swift @@ -17,7 +17,6 @@ extension AppDelegate: ParseRemoteDelegate { NotificationCenter.default.post(.init(name: Notification.Name(rawValue: Constants.requestSync))) } - @MainActor func successfullyPushedToRemote() { if isFirstTimeLogin { // BAKER: @MainActor not working (shows purple warning), leave async. @@ -29,9 +28,11 @@ extension AppDelegate: ParseRemoteDelegate { // watchOS 9 needs to be sent messages for updates on real devices if isSendingPushUpdatesToWatch { let message = Utility.prepareSyncMessageForWatch() - WCSession.default.sendMessage(message, - replyHandler: nil, - errorHandler: nil) + WCSession.default.sendMessage( + message, + replyHandler: nil, + errorHandler: nil + ) } #endif } diff --git a/OCKSample/Extensions/OCKStore.swift b/OCKSample/Extensions/OCKStore.swift index ec18f31..777cdd7 100644 --- a/OCKSample/Extensions/OCKStore.swift +++ b/OCKSample/Extensions/OCKStore.swift @@ -160,7 +160,14 @@ extension OCKStore { stretch.impactsAdherence = true stretch.asset = "figure.walk" - try await addTasksIfNotPresent([nausea, doxylamine, kegels, stretch]) + try await addTasksIfNotPresent( + [ + nausea, + doxylamine, + kegels, + stretch + ] + ) var contact1 = OCKContact( id: "jane", @@ -168,13 +175,11 @@ extension OCKStore { familyName: "Daniels", carePlanUUID: nil ) - contact1.asset = "JaneDaniels" contact1.title = "Family Practice Doctor" contact1.role = "Dr. Daniels is a family practice doctor with 8 years of experience." contact1.emailAddresses = [OCKLabeledValue(label: CNLabelEmailiCloud, value: "janedaniels@uky.edu")] contact1.phoneNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(800) 257-2000")] contact1.messagingNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(800) 357-2040")] - contact1.address = { let address = OCKPostalAddress() address.street = "1500 San Pablo St" @@ -184,9 +189,12 @@ extension OCKStore { return address }() - var contact2 = OCKContact(id: "matthew", givenName: "Matthew", - familyName: "Reiff", carePlanUUID: nil) - contact2.asset = "MatthewReiff" + var contact2 = OCKContact( + id: "matthew", + givenName: "Matthew", + familyName: "Reiff", + carePlanUUID: nil + ) contact2.title = "OBGYN" contact2.role = "Dr. Reiff is an OBGYN with 13 years of experience." contact2.phoneNumbers = [OCKLabeledValue(label: CNLabelWork, value: "(800) 257-1000")] @@ -200,6 +208,11 @@ extension OCKStore { return address }() - try await addContactsIfNotPresent([contact1, contact2]) + try await addContactsIfNotPresent( + [ + contact1, + contact2 + ] + ) } } diff --git a/OCKSample/Main/Care/CareView.swift b/OCKSample/Main/Care/CareView.swift index 6f3d2d9..f22f9d7 100644 --- a/OCKSample/Main/Care/CareView.swift +++ b/OCKSample/Main/Care/CareView.swift @@ -5,12 +5,12 @@ // Created by Corey Baker on 11/24/20. // Copyright © 2020 Network Reconnaissance Lab. All rights reserved. // -// swiftlint:disable:next line_length -// This file embeds a UIKit View Controller inside of a SwiftUI view. I used this tutorial to figure this out https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit +// This file embeds a UIKit View Controller inside of a SwiftUI view. +// Look at this tutorial for reference: +// https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit import CareKit import CareKitStore -import os.log import SwiftUI import UIKit @@ -19,10 +19,16 @@ struct CareView: UIViewControllerRepresentable { @Environment(\.appDelegate) private var appDelegate @Environment(\.careStore) private var careStore - func makeUIViewController(context: Context) -> some UIViewController { + func makeUIViewController( + context: Context + ) -> some UIViewController { let viewController = createViewController() - let navigationController = UINavigationController(rootViewController: viewController) - navigationController.navigationBar.backgroundColor = UIColor { $0.userInterfaceStyle == .light ? #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1): #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) } + let navigationController = UINavigationController( + rootViewController: viewController + ) + navigationController.navigationBar.backgroundColor = UIColor { + $0.userInterfaceStyle == .light ? #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1): #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) + } return navigationController } @@ -32,8 +38,7 @@ struct CareView: UIViewControllerRepresentable { ) { guard let navigationController = uiViewController as? UINavigationController, let careViewController = navigationController.viewControllers.first as? CareViewController else { - Logger.feed.error("CareView should have been a UINavigationController") - return + fatalError("CareView should have been a UINavigationController") } guard careViewController.store !== careStore || appDelegate?.isFirstTimeLogin == true else { diff --git a/OCKSample/Main/Care/CareViewController.swift b/OCKSample/Main/Care/CareViewController.swift index 1306923..3afc518 100644 --- a/OCKSample/Main/Care/CareViewController.swift +++ b/OCKSample/Main/Care/CareViewController.swift @@ -52,27 +52,42 @@ class CareViewController: OCKDailyPageViewController { override func viewDidLoad() { super.viewDidLoad() - navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .refresh, - target: self, - action: #selector(synchronizeWithRemote)) - NotificationCenter.default.addObserver(self, selector: #selector(synchronizeWithRemote), - name: Notification.Name(rawValue: Constants.requestSync), - object: nil) - NotificationCenter.default.addObserver(self, - selector: #selector(updateSynchronizationProgress(_:)), - name: Notification.Name(rawValue: Constants.progressUpdate), - object: nil) - NotificationCenter.default.addObserver(self, - selector: #selector(reloadView(_:)), - name: Notification.Name(rawValue: Constants.finishedAskingForPermission), - object: nil) - NotificationCenter.default.addObserver(self, - selector: #selector(reloadView(_:)), - name: Notification.Name(rawValue: Constants.shouldRefreshView), - object: nil) + navigationItem.rightBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .refresh, + target: self, + action: #selector(synchronizeWithRemote) + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(synchronizeWithRemote), + name: Notification.Name( + rawValue: Constants.requestSync + ), + object: nil + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(updateSynchronizationProgress(_:)), + name: Notification.Name(rawValue: Constants.progressUpdate), + object: nil + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(reloadView(_:)), + name: Notification.Name(rawValue: Constants.finishedAskingForPermission), + object: nil + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(reloadView(_:)), + name: Notification.Name(rawValue: Constants.shouldRefreshView), + object: nil + ) } - @objc private func updateSynchronizationProgress(_ notification: Notification) { + @objc private func updateSynchronizationProgress( + _ notification: Notification + ) { guard let receivedInfo = notification.userInfo as? [String: Any], let progress = receivedInfo[Constants.progressUpdate] as? Int else { return @@ -191,6 +206,21 @@ class CareViewController: OCKDailyPageViewController { } } + private func fetchTasks(on date: Date) async -> [OCKAnyTask] { + var query = OCKTaskQuery(for: date) + query.excludesTasksWithNoEvents = true + do { + let tasks = try await store.fetchAnyTasks(query: query) + let orderedTasks = TaskID.ordered.compactMap { orderedTaskID in + tasks.first(where: { $0.id == orderedTaskID }) + } + return orderedTasks + } catch { + Logger.feed.error("Could not fetch tasks: \(error, privacy: .public)") + return [] + } + } + private func taskViewControllers( _ task: OCKAnyTask, on date: Date @@ -340,21 +370,6 @@ class CareViewController: OCKDailyPageViewController { self.isLoading = false } } - - private func fetchTasks(on date: Date) async -> [OCKAnyTask] { - var query = OCKTaskQuery(for: date) - query.excludesTasksWithNoEvents = true - do { - let tasks = try await store.fetchAnyTasks(query: query) - let orderedTasks = TaskID.ordered.compactMap { orderedTaskID in - tasks.first(where: { $0.id == orderedTaskID }) - } - return orderedTasks - } catch { - Logger.feed.error("Could not fetch tasks: \(error, privacy: .public)") - return [] - } - } } private extension View { diff --git a/OCKSample/Main/Care/CustomCards/TipView.swift b/OCKSample/Main/Care/CustomCards/TipView.swift index 809bc64..8d94f70 100644 --- a/OCKSample/Main/Care/CustomCards/TipView.swift +++ b/OCKSample/Main/Care/CustomCards/TipView.swift @@ -28,8 +28,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if os(iOS) - import UIKit import CareKit import CareKitUI @@ -97,19 +95,23 @@ class TipView: OCKView, OCKCardable { imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), imageHeightConstraint ]) + + registerForTraitChanges( + [UITraitPreferredContentSizeCategory.self], + handler: { (self: Self, previousTraitCollection: UITraitCollection) in + let traitCollection = self.traitCollection + // swiftlint:disable:next line_length + if previousTraitCollection.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory { + self.imageHeightConstraint.constant = self.scaledImageHeight(compatibleWith: traitCollection) + } + } + ) } func scaledImageHeight(compatibleWith traitCollection: UITraitCollection) -> CGFloat { return UIFontMetrics.default.scaledValue(for: 200, compatibleWith: traitCollection) } - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory { - imageHeightConstraint.constant = scaledImageHeight(compatibleWith: traitCollection) - } - } - override func styleDidChange() { super.styleDidChange() let cachedStyle = style() @@ -117,5 +119,3 @@ class TipView: OCKView, OCKCardable { directionalLayoutMargins = cachedStyle.dimension.directionalInsets1 } } - -#endif diff --git a/OCKSample/Supporting Files/Info.plist b/OCKSample/Supporting Files/Info.plist index 3bed1d0..7cdb4c0 100644 --- a/OCKSample/Supporting Files/Info.plist +++ b/OCKSample/Supporting Files/Info.plist @@ -30,10 +30,10 @@ localhost - NSExceptionRequiresForwardSecrecy - NSExceptionAllowsInsecureHTTPLoads + NSExceptionRequiresForwardSecrecy + NSIncludesSubdomains diff --git a/OCKWatchSample Extension/Info.plist b/OCKWatchSample Extension/Info.plist index cf5caa6..bbb7c9f 100644 --- a/OCKWatchSample Extension/Info.plist +++ b/OCKWatchSample Extension/Info.plist @@ -20,29 +20,29 @@ 1.0 CFBundleVersion 1.0 - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSExceptionDomains - - localhost - - NSIncludesSubdomains - - NSExceptionAllowsInsecureHTTPLoads - - NSExceptionRequiresForwardSecrecy - - - - + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + localhost + + NSIncludesSubdomains + + NSExceptionAllowsInsecureHTTPLoads + + NSExceptionRequiresForwardSecrecy + + + + NSExtension NSExtensionAttributes WKAppBundleIdentifier - edu.uky.netrecon.ParseCarekitSample.watchkitapp + edu.usc.netrecon.ParseCarekitSample.watchkitapp NSExtensionPointIdentifier com.apple.watchkit diff --git a/OCKWatchSample/Info.plist b/OCKWatchSample/Info.plist index ba13148..a6f5559 100644 --- a/OCKWatchSample/Info.plist +++ b/OCKWatchSample/Info.plist @@ -28,12 +28,12 @@ localhost - NSIncludesSubdomains - NSExceptionAllowsInsecureHTTPLoads NSExceptionRequiresForwardSecrecy + NSIncludesSubdomains + @@ -45,6 +45,6 @@ WKApplication WKCompanionAppBundleIdentifier - edu.uky.netrecon.ParseCarekitSample + edu.usc.netrecon.ParseCarekitSample diff --git a/README.md b/README.md index 60df3ca..111a275 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # CareKitSample+ParseCareKit -![Swift](https://img.shields.io/badge/swift-5.7-brightgreen.svg) ![Xcode 14.0+](https://img.shields.io/badge/xcode-14.0%2B-blue.svg) ![iOS 16.0+](https://img.shields.io/badge/iOS-16.0%2B-blue.svg) ![watchOS 9.0+](https://img.shields.io/badge/watchOS-9.0%2B-blue.svg) ![CareKit 3.0+](https://img.shields.io/badge/CareKit-3.0%2B-red.svg) ![ci](https://github.com/netreconlab/CareKitSample-ParseCareKit/workflows/ci/badge.svg?branch=main) +![Swift](https://img.shields.io/badge/swift-5.10-brightgreen.svg) ![Xcode 16.0+](https://img.shields.io/badge/xcode-16.0%2B-blue.svg) ![iOS 18.0+](https://img.shields.io/badge/iOS-16.0%2B-blue.svg) ![watchOS 11.0+](https://img.shields.io/badge/watchOS-9.0%2B-blue.svg) ![CareKit 3.0+](https://img.shields.io/badge/CareKit-3.0%2B-red.svg) ![ci](https://github.com/netreconlab/CareKitSample-ParseCareKit/workflows/ci/badge.svg?branch=main) An example application of [CareKit](https://github.com/carekit-apple/CareKit)'s OCKSample synchronizing CareKit data to the Cloud via [ParseCareKit](https://github.com/netreconlab/ParseCareKit).