diff --git a/CareKitEssentials.xcodeproj/project.pbxproj b/CareKitEssentials.xcodeproj/project.pbxproj index ecd7a1f6..ccd8a201 100644 --- a/CareKitEssentials.xcodeproj/project.pbxproj +++ b/CareKitEssentials.xcodeproj/project.pbxproj @@ -199,10 +199,10 @@ isa = PBXGroup; children = ( OBJ_26 /* Calendar+Dates.swift */, - 700DA9062C2A66BF00435E2C /* Logger.swift */, 911BDB272A11C491004F8442 /* CGFloat.swift */, OBJ_32 /* CustomLinearCareTaskProgress.swift */, OBJ_27 /* Image.swift */, + 700DA9062C2A66BF00435E2C /* Logger.swift */, OBJ_29 /* OCKAnyEvent.swift */, OBJ_28 /* OCKAnyEvent+CustomStringConvertable.swift */, OBJ_30 /* OCKAnyOutcome.swift */, diff --git a/README.md b/README.md index a13da40e..cfa9822e 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,18 @@ ![Codecov](https://codecov.io/gh/netreconlab/CareKitEssentials/branches/main/graph/badge.svg) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/netreconlab/ParseCareKit/#license) -Provides essential cards, viewa, models, protocols, and extentions to expedite building [CareKit](https://github.com/carekit-apple/CareKit) based applications. +Provides essential cards, views, models, protocols, and extentions to expedite building [CareKit](https://github.com/carekit-apple/CareKit) based applications. + +## Entensions +A number of public extensions are available to make using CareKit easier. All of the extensions can be found in the [Extensions](https://github.com/netreconlab/CareKitEssentials/tree/main/Sources/CareKitEssentials/Extensions) folder. + +## Usage +You can create SwiftUI views that conform to [CareKitEssentialView](https://github.com/netreconlab/CareKitEssentials/blob/main/Sources/CareKitEssentials/Cards/Shared/CareKitEssentialView.swift) to obtain a number of convenience methods for saving and deleting outcomes. The following views are based on `CareKitEssentialView`: + +### iOS +[SliderLogTaskView](https://github.com/netreconlab/CareKitEssentials/blob/main/Sources/CareKitEssentials/Cards/iOS/SliderLog/SliderLogTaskView.swift) can be used to quickly create a slider view +image + +### watchOS +[DigitalCrownView](https://github.com/netreconlab/CareKitEssentials/blob/main/Sources/CareKitEssentials/Cards/watchOS/DigitalCrown/DigitalCrownView.swift) can be used to quickly create a view that responds to the crown +image \ No newline at end of file diff --git a/Sources/CareKitEssentials/Cards/Shared/CareKitEssentialView.swift b/Sources/CareKitEssentials/Cards/Shared/CareKitEssentialView.swift index 4e440257..b8e95fa7 100644 --- a/Sources/CareKitEssentials/Cards/Shared/CareKitEssentialView.swift +++ b/Sources/CareKitEssentials/Cards/Shared/CareKitEssentialView.swift @@ -27,14 +27,12 @@ public protocol CareKitEssentialView: View { with values: [OCKOutcomeValue]? ) async throws - /// Update an `OCKAnyEvent` with new a `OCKOutcome`. + /// Save a new `OCKAnyOutcome`. /// - Parameters: - /// - event: The event to update. - /// - outcome: A new `OCKOutcome`. - /// - Throws: An error if the outcome values cannot be updated. - func updateEvent( - _ event: OCKAnyEvent, - with outcome: OCKOutcome? + /// - outcome: A new `OCKAnyOutcome`. + /// - Throws: An error if the outcome cannot be updated. + func saveOutcome( + _ outcome: OCKAnyOutcome ) async throws /// Create an `OCKEventQuery` constrained to a set of `taskIDs` on a particular date. @@ -50,43 +48,31 @@ public protocol CareKitEssentialView: View { public extension CareKitEssentialView { + func deleteEventOutcome(_ event: OCKAnyEvent) async throws { + guard let outcome = event.outcome else { + throw CareKitEssentialsError.errorString("The event does not contain an outcome: \(event)") + } + _ = try await careStore.deleteAnyOutcome(outcome) + } + func updateEvent( _ event: OCKAnyEvent, with values: [OCKOutcomeValue]? ) async throws { guard let values = values else { // Attempts to delete outcome if it already exists. - _ = try await self.saveOutcomeValues( - [], - event: event, - store: careStore - ) + try await deleteEventOutcome(event) return } _ = try await self.appendOutcomeValues( values, - event: event, - store: careStore + event: event ) } - func updateEvent( - _ event: OCKAnyEvent, - with outcome: OCKOutcome? + func saveOutcome( + _ outcome: OCKAnyOutcome ) async throws { - guard let outcome = outcome else { - guard let task = event.task as? OCKAnyVersionableTask else { - throw CareKitEssentialsError.errorString("Cannot make outcome for event: \(event)") - } - let outcome = OCKOutcome( - taskUUID: task.uuid, - taskOccurrenceIndex: event.scheduleEvent.occurrence, - values: [] - ) - // Attempts to set the latest outcome values to an empty array. - _ = try await careStore.deleteAnyOutcome(outcome) - return - } _ = try await careStore.addAnyOutcome(outcome) } @@ -98,22 +84,20 @@ public extension CareKitEssentialView { /// Otherwise a new `OCKOutcome` is created with the respective outcome values. func appendOutcomeValues( _ values: [OCKOutcomeValue], - event: OCKAnyEvent, - store: OCKAnyStoreProtocol + event: OCKAnyEvent ) async throws { // Update the outcome with the new value guard var outcome = event.outcome else { let outcome = createOutcomeWithValues( values, - event: event, - store: store + event: event ) - _ = try await store.addAnyOutcome(outcome) + _ = try await careStore.addAnyOutcome(outcome) return } outcome.values.append(contentsOf: values) - _ = try await store.updateAnyOutcome(outcome) + _ = try await careStore.updateAnyOutcome(outcome) return } @@ -124,18 +108,13 @@ public extension CareKitEssentialView { /// - Note: Setting `values` to an empty array will delete the current `OCKOutcome` if it currently exists. func saveOutcomeValues( _ values: [OCKOutcomeValue], - event: OCKAnyEvent, - store: OCKAnyStoreProtocol + event: OCKAnyEvent ) async throws { // Check if outcome values need to be updated. guard !values.isEmpty else { // If the event has already been completed - guard let oldOutcome = event.outcome else { - return - } - // Delete the outcome, and create a new one. - _ = try await store.deleteAnyOutcome(oldOutcome) + try await deleteEventOutcome(event) return } @@ -144,15 +123,14 @@ public extension CareKitEssentialView { // Create a new outcome with the new values. let outcome = createOutcomeWithValues( values, - event: event, - store: store + event: event ) - _ = try await store.addAnyOutcome(outcome) + _ = try await careStore.addAnyOutcome(outcome) return } // Update the outcome with the new values. currentOutcome.values = values - _ = try await store.updateAnyOutcome(currentOutcome) + _ = try await careStore.updateAnyOutcome(currentOutcome) } /// Create an outcome for an event with the given outcome values. @@ -160,8 +138,7 @@ public extension CareKitEssentialView { /// - values: The outcome values to attach to the outcome. func createOutcomeWithValues( _ values: [OCKOutcomeValue], - event: OCKAnyEvent, - store: OCKAnyStoreProtocol + event: OCKAnyEvent ) -> OCKAnyOutcome { let outcome = OCKOutcome( taskUUID: event.task.uuid , diff --git a/Sources/CareKitEssentials/Cards/iOS/LabeledValueTaskView.swift b/Sources/CareKitEssentials/Cards/iOS/LabeledValueTaskView.swift index dad9131a..3eb14578 100644 --- a/Sources/CareKitEssentials/Cards/iOS/LabeledValueTaskView.swift +++ b/Sources/CareKitEssentials/Cards/iOS/LabeledValueTaskView.swift @@ -22,8 +22,10 @@ public extension LabeledValueTaskView where Header == InformationHeaderView { /// - Parameters: /// - event: The data that appears in the view. /// - numberFormatter: An object that formats the progress and target values. - init(event: CareStoreFetchedResult, - numberFormatter: NumberFormatter? = nil) { + init( + event: CareStoreFetchedResult, + numberFormatter: NumberFormatter? = nil + ) { let currentEvent = event.result