Skip to content

Commit

Permalink
Iterate
Browse files Browse the repository at this point in the history
  • Loading branch information
Supereg committed Sep 3, 2024
1 parent 1ca335c commit 102dd7d
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ extension ILSchedule.Duration: Codable {
let container = try decoder.container(keyedBy: CodingKeys.self)

let allDay = try container.decodeIfPresent(Bool.self, forKey: .allDay)
if let allDay {
if allDay != nil {
self = .allDay
} else {
let duration = try container.decode(Swift.Duration.self, forKey: .duration)
Expand All @@ -64,7 +64,7 @@ extension ILSchedule.Duration: Codable {
}


extension ILSchedule.Duration { // TODO: also support Double?
extension ILSchedule.Duration {
/// Determine if a duration is all day.
public var isAllDay: Bool {
self == .allDay
Expand Down Expand Up @@ -92,6 +92,18 @@ extension ILSchedule.Duration { // TODO: also support Double?
.seconds(minutes * 60)
}

/// A duration given a number of minutes.
///
/// Creates a new duration given a number of minutes by converting into the closest second scale value.
///
/// ```swift
/// let duration: Duration = .minutes(27.5)
/// ```
/// - Returns: A `Duration` representing a given number of minutes.
public static func minutes(_ minutes: Double) -> ILSchedule.Duration {
.duration(.seconds(minutes * 60))
}

/// A duration given a number of hours.
///
/// ```swift
Expand All @@ -102,4 +114,16 @@ extension ILSchedule.Duration { // TODO: also support Double?
public static func hours(_ hours: some BinaryInteger) -> ILSchedule.Duration {
.minutes(hours * 60)
}

/// A duration given a number of hours.
///
/// Creates a new duration given a number of hours by converting into the closest second scale value.
///
/// ```swift
/// let duration: Duration = .hours(4)
/// ```
/// - Returns: A `Duration` representing a given number of hours.
public static func hours(_ hours: Double) -> ILSchedule.Duration {
.minutes(hours * 60)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ import Foundation
/// A schedule represents the composition of multiple ``ScheduleComponent``s.
public struct ILSchedule {
// TODO: allow to specify "text" LocalizedStringResource (e.g., Breakfast, Lunch, etc), otherwise we use the time (and date?)?
// => how to store localized values in the database

/// The start date (inclusive).
private var _start: Date
/// The duration of a single occurrence.
public var duration: Duration = .seconds(2)

private var recurrenceRule: Data?
// TODO: @Transient private var _recurrence: Calendar.RecurrenceRule?
// TODO: we can't event store the calendar even though it is not being encoded???
// TODO: we could do our own wrapper that leaves out the Calendar to store at least most properties!
// => we could do our own wrapper that leaves out the Calendar to store at least most properties!

/// The recurrence of the schedule.
public var recurrence: Calendar.RecurrenceRule? {
Expand Down
20 changes: 17 additions & 3 deletions Sources/SpeziScheduler/InfinityLoop/Task/ILEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,25 @@ public struct ILEvent {
self.outcome = outcome
}

/// Complete the event with an outcome.
/// Complete the event.
public mutating func complete() {
self.complete { _ in }
}

/// Complete the event with additional information.
///
/// ```swift
/// var event: ILEvent
///
/// event.complete {
/// event.myCustomData = "..."
/// }
/// ```
///
/// - Parameter outcome: The outcome that completes the event.
public mutating func complete() { // TODO: add ability to supply a value?
/// - Parameter closure: A closure that allows setting properties of the outcome.
public mutating func complete(with closure: (Outcome) -> Void) {
let outcome = Outcome(task: task, occurrence: occurrence)
closure(outcome)
self.outcome = outcome
task.addOutcome(outcome) // TODO: is this necessary? Would this duplicate the entry?
}
Expand Down
8 changes: 3 additions & 5 deletions Sources/SpeziScheduler/InfinityLoop/Task/ILTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ import SwiftData

// TODO: there are two concepts (ending a task vs. deleting a task (with all of its previous versions)?)

public enum TaskAnchor: RepositoryAnchor {}


public protocol TaskStorageKey: UserInfoKey where Anchor == TaskAnchor {}


class StoredAsData<Value: Codable> {
private var decodedValue: Value?
Expand Down Expand Up @@ -62,7 +57,9 @@ class StoredAsData<Value: Codable> {
public final class ILTask {
#Unique<ILTask>([\.id, \.effectiveFrom, \.nextVersion])

/// The LocalizedStringResource encoded, as we cannot store Locale with SwiftData.
private var titleResource: Data
/// The LocalizedStringResource encoded, as we cannot store Locale with SwiftData.
private var instructionsResource: Data

@Transient private var titleStorage = StoredAsData<LocalizedStringResource>()
Expand Down Expand Up @@ -152,6 +149,7 @@ public final class ILTask {
self.effectiveFrom = effectiveFrom
}

// TODO: we should not allow mutation?
public subscript<Source: UserInfoKey<TaskAnchor>>(_ source: Source.Type) -> Source.Value? {
get {
userInfo.get(source)
Expand Down
7 changes: 0 additions & 7 deletions Sources/SpeziScheduler/InfinityLoop/Task/Outcome.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ import SpeziFoundation
import SwiftData


/// The storage anchor for additional user info storage entries for an `Outcome`.
public enum OutcomeAnchor: RepositoryAnchor {}


public protocol OutcomeStorageKey: UserInfoKey where Anchor == OutcomeAnchor {} // TODO: are these necessary?


/// The outcome of an event.
///
/// Describes a outcomes of an ``Event`` of a ``Task``.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziFoundation


/// The storage anchor for additional user info storage entries for an `Outcome`.
public enum OutcomeAnchor: RepositoryAnchor {}


// TODO: have a simple entry macro for these?
public protocol OutcomeStorageKey: UserInfoKey where Anchor == OutcomeAnchor {} // TODO: docs
16 changes: 16 additions & 0 deletions Sources/SpeziScheduler/InfinityLoop/UserInfo/TaskStorageKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziFoundation


/// Storage anchor for the additional storage of a task.
public enum TaskAnchor: RepositoryAnchor {}


public protocol TaskStorageKey: UserInfoKey where Anchor == TaskAnchor {} // TODO: Docs
14 changes: 14 additions & 0 deletions Sources/SpeziScheduler/InfinityLoop/UserInfo/UserInfoKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziFoundation


public protocol UserInfoKey<Anchor>: KnowledgeSource where Value: Codable {
static var identifier: String { get }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ import Foundation
import SpeziFoundation


public protocol UserInfoKey<Anchor>: KnowledgeSource where Value: Codable {
static var identifier: String { get }
}


struct UserInfoStorage<Anchor: RepositoryAnchor> {
private var userInfo: [String: Data] = [:]
private var repository: ValueRepository<Anchor>
Expand All @@ -30,7 +25,7 @@ struct UserInfoStorage<Anchor: RepositoryAnchor> {
}


extension UserInfoStorage { // TODO: Sendable?
extension UserInfoStorage {
mutating func get<Source: UserInfoKey<Anchor>>(_ source: Source.Type) -> Source.Value? {
if let value = repository.get(source) {
return value
Expand Down Expand Up @@ -62,7 +57,6 @@ extension UserInfoStorage { // TODO: Sendable?

extension UserInfoStorage: Codable {
init(from decoder: any Decoder) throws {
// TODO: does this work with SwiftData?
self.userInfo = try [String: Data](from: decoder)
self.repository = ValueRepository()
}
Expand Down

0 comments on commit 102dd7d

Please sign in to comment.