diff --git a/.spi.yml b/.spi.yml
index 427018ec..d8699369 100644
--- a/.spi.yml
+++ b/.spi.yml
@@ -1,5 +1,5 @@
version: 1
builder:
configs:
- - documentation_targets: [CareKitUtilities]
- swift_version: 5.9
+ - documentation_targets: [CareKitEssentials]
+ swift_version: 6.0
diff --git a/CareKitEssentials.xcodeproj/project.pbxproj b/CareKitEssentials.xcodeproj/project.pbxproj
index ecd7a1f6..e744e3f9 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 */,
@@ -489,7 +489,7 @@
ENABLE_NS_ASSERTIONS = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
@@ -547,7 +547,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = s;
GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/README.md b/README.md
index 2678b760..2a7afa5e 100644
--- a/README.md
+++ b/README.md
@@ -7,4 +7,20 @@
![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)
-A description of this package.
+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
+
+
+
+### 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
+
+
diff --git a/Sources/CareKitEssentials/Cards/Shared/CardViewModel.swift b/Sources/CareKitEssentials/Cards/Shared/CardViewModel.swift
index 21761f08..600600d9 100644
--- a/Sources/CareKitEssentials/Cards/Shared/CardViewModel.swift
+++ b/Sources/CareKitEssentials/Cards/Shared/CardViewModel.swift
@@ -64,7 +64,7 @@ open class CardViewModel: ObservableObject {
public private(set) var detailsInformation: String?
var initialValue: OCKOutcomeValue
- var action: ((OCKOutcomeValue?) async -> Void)? = nil
+ var action: ((OCKOutcomeValue?) async -> Void)?
/// Create an instance with specified content for an event. The view will update when changes
/// occur in the store.
diff --git a/Sources/CareKitEssentials/Cards/Shared/CareKitEssentialView.swift b/Sources/CareKitEssentials/Cards/Shared/CareKitEssentialView.swift
index bbae9c93..8bec1d52 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 = try createOutcomeWithValues(
+ 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,35 +108,42 @@ 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
}
// If the event has already been completed
guard var currentOutcome = event.outcome else {
// Create a new outcome with the new values.
- let outcome = try createOutcomeWithValues(
+ 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.
+ /// - Parameters:
+ /// - event: The event the outcome is made for.
+ func createOutcomeForEvent(
+ _ event: OCKAnyEvent
+ ) -> OCKAnyOutcome {
+ OCKOutcome(
+ taskUUID: event.task.uuid,
+ taskOccurrenceIndex: event.scheduleEvent.occurrence,
+ values: []
+ )
}
static func eventQuery(
@@ -170,19 +161,13 @@ extension CareKitEssentialView {
/// Create an outcome for an event with the given outcome values.
/// - Parameters:
/// - values: The outcome values to attach to the outcome.
+ /// - event: The event the outcome is made for.
func createOutcomeWithValues(
_ values: [OCKOutcomeValue],
- event: OCKAnyEvent,
- store: OCKAnyStoreProtocol
- ) throws -> OCKAnyOutcome {
- 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: values
- )
+ event: OCKAnyEvent
+ ) -> OCKAnyOutcome {
+ var outcome = createOutcomeForEvent(event)
+ outcome.values = values
return outcome
}
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