-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LOOP-1479: Implement first 2 screens of prescription flow + mock manager #11
Changes from 26 commits
04323bb
2d1bab6
9af1488
e0740c4
0cc3b76
a2ce00e
4b3fe92
63e84a0
21081ad
6e1f2d2
a1332ff
94136dd
17a07f6
74cafcc
1067f7c
f34e32e
8cd0b68
0aecd3d
0f9faaa
30b176f
98b5110
19a4734
1fec6b3
5bd3617
d2b7de9
423e36f
2d6d53b
d1faedd
ba933c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// | ||
// TimeInterval.swift | ||
// TidepoolServiceKit | ||
// | ||
// Created by Anna Quinlan on 6/26/20. | ||
// Copyright © 2020 Tidepool Project. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
extension TimeInterval { | ||
public static func minutes(_ minutes: Double) -> TimeInterval { | ||
return TimeInterval(minutes * 60 /* seconds in minute */) | ||
} | ||
|
||
public static func hours(_ hours: Double) -> TimeInterval { | ||
return TimeInterval(hours * 60 /* minutes in hr */ * 60 /* seconds in minute */) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] Consider copy/paste this implementation from LoopKit:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @darinkrauss doesn't |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// | ||
// Prescription.swift | ||
// TidepoolServiceKit | ||
// | ||
// Created by Anna Quinlan on 6/18/20. | ||
// Copyright © 2020 Tidepool Project. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import HealthKit | ||
import LoopKit | ||
|
||
|
||
public enum CGMType: String, Codable { | ||
case g6 | ||
} | ||
|
||
public enum PumpType: String, Codable { | ||
case dash | ||
} | ||
|
||
public enum TrainingType: String, Codable { | ||
case inPerson // Patient must have hands-on training with clinician/CDE | ||
case inModule // Patient can train in-app | ||
|
||
} | ||
|
||
public struct MockPrescription { | ||
public let datePrescribed: Date // Date prescription was prescribed | ||
public let providerName: String // Name of clinician prescribing | ||
public let cgm: CGMType // CGM type (manufacturer & model) | ||
public let pump: PumpType // Pump type (manufacturer & model) | ||
public let bloodGlucoseUnit: HKUnit // CGM type (manufacturer & model) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this object is a mock, but something similar will end up in TidepoolKit (using many of the types already implemented in TidepoolKit). Consider dropping use of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great suggestion, thanks! |
||
public let basalRateSchedule: BasalRateSchedule | ||
public let glucoseTargetRangeSchedule: GlucoseRangeSchedule | ||
public let carbRatioSchedule: CarbRatioSchedule | ||
public let insulinSensitivitySchedule: InsulinSensitivitySchedule | ||
public let maximumBasalRatePerHour: Double | ||
public let maximumBolus: Double | ||
public let suspendThreshold: GlucoseThreshold | ||
public let insulinModel: InsulinModel | ||
public let preMealTargetRange: DoubleRange | ||
public let workoutTargetRange: DoubleRange | ||
|
||
public init(datePrescribed: Date, | ||
providerName: String, | ||
cgmType: CGMType, | ||
pumpType: PumpType, | ||
bloodGlucoseUnit: HKUnit, | ||
basalRateSchedule: BasalRateSchedule, | ||
glucoseTargetRangeSchedule: GlucoseRangeSchedule, | ||
carbRatioSchedule: CarbRatioSchedule, | ||
insulinSensitivitySchedule: InsulinSensitivitySchedule, | ||
maximumBasalRatePerHour: Double, | ||
maximumBolus: Double, | ||
suspendThreshold: GlucoseThreshold, | ||
insulinModel: InsulinModel, | ||
preMealTargetRange: DoubleRange, | ||
workoutTargetRange: DoubleRange) { | ||
self.datePrescribed = datePrescribed | ||
self.providerName = providerName | ||
self.cgm = cgmType | ||
self.pump = pumpType | ||
self.bloodGlucoseUnit = bloodGlucoseUnit | ||
self.basalRateSchedule = basalRateSchedule | ||
self.glucoseTargetRangeSchedule = glucoseTargetRangeSchedule | ||
self.carbRatioSchedule = carbRatioSchedule | ||
self.insulinSensitivitySchedule = insulinSensitivitySchedule | ||
self.maximumBasalRatePerHour = maximumBasalRatePerHour | ||
self.maximumBolus = maximumBolus | ||
self.suspendThreshold = suspendThreshold | ||
self.insulinModel = insulinModel | ||
self.preMealTargetRange = preMealTargetRange | ||
self.workoutTargetRange = workoutTargetRange | ||
} | ||
|
||
public struct InsulinModel: Codable, Equatable { | ||
public enum ModelType: String, Codable { | ||
case fiasp | ||
case rapidAdult | ||
case rapidChild | ||
case walsh | ||
} | ||
|
||
public let modelType: ModelType | ||
public let actionDuration: TimeInterval | ||
public let peakActivity: TimeInterval? | ||
|
||
public init(modelType: ModelType, actionDuration: TimeInterval, peakActivity: TimeInterval? = nil) { | ||
self.modelType = modelType | ||
self.actionDuration = actionDuration | ||
self.peakActivity = peakActivity | ||
} | ||
} | ||
} | ||
|
||
extension MockPrescription: Codable { | ||
public init(from decoder: Decoder) throws { | ||
let container = try decoder.container(keyedBy: CodingKeys.self) | ||
var bloodGlucoseUnit: HKUnit? | ||
if let bloodGlucoseUnitString = try container.decodeIfPresent(String.self, forKey: .bloodGlucoseUnit) { | ||
bloodGlucoseUnit = HKUnit(from: bloodGlucoseUnitString) | ||
} | ||
self.init(datePrescribed: try container.decode(Date.self, forKey: .datePrescribed), | ||
providerName: try container.decode(String.self, forKey: .providerName), | ||
cgmType: try container.decode(CGMType.self, forKey: .cgm), | ||
pumpType: try container.decode(PumpType.self, forKey: .pump), | ||
bloodGlucoseUnit: bloodGlucoseUnit ?? .milligramsPerDeciliter, | ||
basalRateSchedule: try container.decode(BasalRateSchedule.self, forKey: .basalRateSchedule), | ||
glucoseTargetRangeSchedule: try container.decode(GlucoseRangeSchedule.self, forKey: .glucoseTargetRangeSchedule), | ||
carbRatioSchedule: try container.decode(CarbRatioSchedule.self, forKey: .carbRatioSchedule), | ||
insulinSensitivitySchedule: try container.decode(InsulinSensitivitySchedule.self, forKey: .insulinSensitivitySchedule), | ||
maximumBasalRatePerHour: try container.decode(Double.self, forKey: .maximumBasalRatePerHour), | ||
maximumBolus: try container.decode(Double.self, forKey: .maximumBolus), | ||
suspendThreshold: try container.decode(GlucoseThreshold.self, forKey: .suspendThreshold), | ||
insulinModel: try container.decode(InsulinModel.self, forKey: .insulinModel), | ||
preMealTargetRange: try container.decode(DoubleRange.self, forKey: .preMealTargetRange), | ||
workoutTargetRange: try container.decode(DoubleRange.self, forKey: .workoutTargetRange)) | ||
} | ||
|
||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.container(keyedBy: CodingKeys.self) | ||
try container.encode(datePrescribed, forKey: .datePrescribed) | ||
try container.encode(providerName, forKey: .providerName) | ||
try container.encode(cgm, forKey: .cgm) | ||
try container.encode(pump, forKey: .pump) | ||
try container.encode(bloodGlucoseUnit.unitString, forKey: .bloodGlucoseUnit) | ||
try container.encode(basalRateSchedule, forKey: .basalRateSchedule) | ||
try container.encode(glucoseTargetRangeSchedule, forKey: .glucoseTargetRangeSchedule) | ||
try container.encode(carbRatioSchedule, forKey: .carbRatioSchedule) | ||
try container.encode(insulinSensitivitySchedule, forKey: .insulinSensitivitySchedule) | ||
try container.encode(maximumBasalRatePerHour, forKey: .maximumBasalRatePerHour) | ||
try container.encode(maximumBolus, forKey: .maximumBolus) | ||
try container.encode(suspendThreshold, forKey: .suspendThreshold) | ||
try container.encode(insulinModel, forKey: .insulinModel) | ||
try container.encode(preMealTargetRange, forKey: .preMealTargetRange) | ||
try container.encode(workoutTargetRange, forKey: .workoutTargetRange) | ||
} | ||
|
||
private enum CodingKeys: String, CodingKey { | ||
case datePrescribed | ||
case providerName | ||
case cgm | ||
case pump | ||
case bloodGlucoseUnit | ||
case basalRateSchedule | ||
case glucoseTargetRangeSchedule | ||
case carbRatioSchedule | ||
case insulinSensitivitySchedule | ||
case maximumBasalRatePerHour | ||
case maximumBolus | ||
case suspendThreshold | ||
case insulinModel | ||
case preMealTargetRange | ||
case workoutTargetRange | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@novalegra why not use the existing LoopKit functions for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rickpasetto We typically don't publicly export extensions to system types from our Frameworks. There are exceptions, but these are likely conflict sources; imagine if another framework did the same. I could easily see another framework thinking "wouldn't it be nice to implement minute/hour/day extensions for TimeInterval and export them for everyone?".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ps2 I see. @novalegra in that case, it is fine to leave these as-is.