Skip to content
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

Merged
merged 29 commits into from
Jun 29, 2020
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
04323bb
LOOP 1269 - add prescription data model
Jun 18, 2020
2d1bab6
Undo commit to add project.pbx file changes
Jun 18, 2020
9af1488
Auto stash before revert of "LOOP 1269 - add prescription data model"
Jun 18, 2020
e0740c4
LOOP-1269 Add prescription storage model
Jun 18, 2020
0cc3b76
LOOP-1269 - add UI controller + first screen
Jun 23, 2020
a2ce00e
Add draft of 2nd screen
Jun 23, 2020
4b3fe92
LOOP-1269: complete first 2 screens
Jun 24, 2020
63e84a0
Fix back button
Jun 24, 2020
21081ad
Fix scrolling issue
Jun 24, 2020
6e1f2d2
Widen text presentation area
Jun 24, 2020
a1332ff
Use mock prescription manager (for now) & make keyboard have letters
Jun 24, 2020
94136dd
Remove second design from views
Jun 24, 2020
17a07f6
Add colors to assets file
Jun 24, 2020
74cafcc
Add temporary correction ranges to prescription
Jun 24, 2020
1067f7c
Color dexcom icon & move delegates to right file
Jun 24, 2020
f34e32e
Add button to Tidepool setup controller to trigger flow
Jun 25, 2020
8cd0b68
Use device specified in prescription
Jun 25, 2020
0aecd3d
Enforce a prescription code length
Jun 25, 2020
0f9faaa
Change copyright -> Tidepool Project
Jun 25, 2020
30b176f
Fix keyboard obstructing text field
Jun 25, 2020
98b5110
Fix keyboard swiping
Jun 25, 2020
19a4734
Fix animation issue and use return to dismiss
Jun 25, 2020
1fec6b3
Remove onboardingNeeded
Jun 25, 2020
5bd3617
Remove commented out code
Jun 25, 2020
d2b7de9
PR-feedback changes
Jun 26, 2020
423e36f
Remove purple from assets
Jun 26, 2020
2d6d53b
Feedback from Darin's review
Jun 26, 2020
d1faedd
Set width size
Jun 29, 2020
ba933c5
Add todo
Jun 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions TidepoolService.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@
A9DAAD6A22E7E81E00E76C9F /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9DAAD6922E7E81E00E76C9F /* LoopKitUI.framework */; };
A9DAAD6D22E7EA8F00E76C9F /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DAAD6C22E7EA8F00E76C9F /* IdentifiableClass.swift */; };
A9DAAD6F22E7EA9700E76C9F /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DAAD6E22E7EA9700E76C9F /* NibLoadable.swift */; };
E93BA05E24A14CBA00C5D7E6 /* PrescriptionCodeEntryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93BA05D24A14CBA00C5D7E6 /* PrescriptionCodeEntryViewModel.swift */; };
E93BA06024A15FA800C5D7E6 /* PrescriptionDeviceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93BA05F24A15FA800C5D7E6 /* PrescriptionDeviceView.swift */; };
E93BA06224A29C9C00C5D7E6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E93BA06124A29C9C00C5D7E6 /* Assets.xcassets */; };
E9692172249BC73600D9BE3B /* MockPrescriptionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9692171249BC73600D9BE3B /* MockPrescriptionManager.swift */; };
E9692174249BF2A100D9BE3B /* MockPrescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9692173249BF2A100D9BE3B /* MockPrescription.swift */; };
E9692176249C1AE700D9BE3B /* PrescriptionReviewUICoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9692175249C1AE700D9BE3B /* PrescriptionReviewUICoordinator.swift */; };
E96AEB98249C2FF1003797B4 /* PrescriptionCodeEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96AEB97249C2FF1003797B4 /* PrescriptionCodeEntryView.swift */; };
E991F1B724A548580059281B /* AdaptiveKeyboardPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = E991F1B624A548580059281B /* AdaptiveKeyboardPadding.swift */; };
E991F1BB24A654CC0059281B /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = E991F1BA24A654CC0059281B /* TimeInterval.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -168,6 +177,15 @@
A9DAAD6922E7E81E00E76C9F /* LoopKitUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKitUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A9DAAD6C22E7EA8F00E76C9F /* IdentifiableClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentifiableClass.swift; sourceTree = "<group>"; };
A9DAAD6E22E7EA9700E76C9F /* NibLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NibLoadable.swift; sourceTree = "<group>"; };
E93BA05D24A14CBA00C5D7E6 /* PrescriptionCodeEntryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrescriptionCodeEntryViewModel.swift; sourceTree = "<group>"; };
E93BA05F24A15FA800C5D7E6 /* PrescriptionDeviceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrescriptionDeviceView.swift; sourceTree = "<group>"; };
E93BA06124A29C9C00C5D7E6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
E9692171249BC73600D9BE3B /* MockPrescriptionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrescriptionManager.swift; sourceTree = "<group>"; };
E9692173249BF2A100D9BE3B /* MockPrescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrescription.swift; sourceTree = "<group>"; };
E9692175249C1AE700D9BE3B /* PrescriptionReviewUICoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrescriptionReviewUICoordinator.swift; sourceTree = "<group>"; };
E96AEB97249C2FF1003797B4 /* PrescriptionCodeEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrescriptionCodeEntryView.swift; sourceTree = "<group>"; };
E991F1B624A548580059281B /* AdaptiveKeyboardPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveKeyboardPadding.swift; sourceTree = "<group>"; };
E991F1BA24A654CC0059281B /* TimeInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeInterval.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -235,6 +253,7 @@
A9309CAE2436C52900E02268 /* StoredGlucoseSample.swift */,
A97A60FA243818C900AD69A5 /* TDatum.swift */,
A9309CA2243563CD00E02268 /* TOrigin.swift */,
E991F1BA24A654CC0059281B /* TimeInterval.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -303,6 +322,7 @@
A9DAAD0022E7987800E76C9F /* TidepoolServiceKit */ = {
isa = PBXGroup;
children = (
E9692170249BC69B00D9BE3B /* Mocks */,
A9DAAD0122E7987800E76C9F /* TidepoolServiceKit.h */,
A9DAAD0222E7987800E76C9F /* Info.plist */,
A9DAAD3522E7CAC100E76C9F /* TidepoolService.swift */,
Expand All @@ -323,7 +343,10 @@
A9DAAD1C22E7988900E76C9F /* TidepoolServiceKitUI */ = {
isa = PBXGroup;
children = (
E93BA05C24A126E000C5D7E6 /* View Models */,
E9692179249C1B9400D9BE3B /* Views */,
A9DAAD1D22E7988900E76C9F /* TidepoolServiceKitUI.h */,
E9692177249C1B0F00D9BE3B /* View Controllers */,
A9DAAD1E22E7988900E76C9F /* Info.plist */,
A9DAAD6C22E7EA8F00E76C9F /* IdentifiableClass.swift */,
A9DAAD6E22E7EA9700E76C9F /* NibLoadable.swift */,
Expand All @@ -332,6 +355,7 @@
A92E770022E9181500591027 /* TidepoolServiceSetupViewController.swift */,
A94AE4F6235A907C005CA320 /* Extensions */,
A9DAAD4F22E7DFD400E76C9F /* Localizable.strings */,
E93BA06124A29C9C00C5D7E6 /* Assets.xcassets */,
);
path = TidepoolServiceKitUI;
sourceTree = "<group>";
Expand Down Expand Up @@ -359,6 +383,41 @@
name = Frameworks;
sourceTree = "<group>";
};
E93BA05C24A126E000C5D7E6 /* View Models */ = {
isa = PBXGroup;
children = (
E93BA05D24A14CBA00C5D7E6 /* PrescriptionCodeEntryViewModel.swift */,
);
path = "View Models";
sourceTree = "<group>";
};
E9692170249BC69B00D9BE3B /* Mocks */ = {
isa = PBXGroup;
children = (
E9692173249BF2A100D9BE3B /* MockPrescription.swift */,
E9692171249BC73600D9BE3B /* MockPrescriptionManager.swift */,
);
path = Mocks;
sourceTree = "<group>";
};
E9692177249C1B0F00D9BE3B /* View Controllers */ = {
isa = PBXGroup;
children = (
E9692175249C1AE700D9BE3B /* PrescriptionReviewUICoordinator.swift */,
);
path = "View Controllers";
sourceTree = "<group>";
};
E9692179249C1B9400D9BE3B /* Views */ = {
isa = PBXGroup;
children = (
E96AEB97249C2FF1003797B4 /* PrescriptionCodeEntryView.swift */,
E93BA05F24A15FA800C5D7E6 /* PrescriptionDeviceView.swift */,
E991F1B624A548580059281B /* AdaptiveKeyboardPadding.swift */,
);
path = Views;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -578,6 +637,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E93BA06224A29C9C00C5D7E6 /* Assets.xcassets in Resources */,
A9DAAD4D22E7DFD400E76C9F /* Localizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -693,11 +753,14 @@
A9309CA52435986300E02268 /* DeletedCarbEntry.swift in Sources */,
A9309CAF2436C52900E02268 /* StoredGlucoseSample.swift in Sources */,
A9D1107C242289720091C620 /* HKUnit.swift in Sources */,
E9692174249BF2A100D9BE3B /* MockPrescription.swift in Sources */,
A9309CA72435987000E02268 /* StoredCarbEntry.swift in Sources */,
A97A60FB243818C900AD69A5 /* TDatum.swift in Sources */,
A9DAAD3322E7CA1A00E76C9F /* LocalizedString.swift in Sources */,
A913B37D24200C97000805C4 /* Bundle.swift in Sources */,
E991F1BB24A654CC0059281B /* TimeInterval.swift in Sources */,
A9309CA3243563CD00E02268 /* TOrigin.swift in Sources */,
E9692172249BC73600D9BE3B /* MockPrescriptionManager.swift in Sources */,
A97651752421AA10002EB5D4 /* OSLog.swift in Sources */,
A9DAAD3622E7CAC100E76C9F /* TidepoolService.swift in Sources */,
);
Expand All @@ -716,10 +779,15 @@
files = (
A9DAAD6D22E7EA8F00E76C9F /* IdentifiableClass.swift in Sources */,
A94AE4F8235A909A005CA320 /* UIColor.swift in Sources */,
E991F1B724A548580059281B /* AdaptiveKeyboardPadding.swift in Sources */,
E96AEB98249C2FF1003797B4 /* PrescriptionCodeEntryView.swift in Sources */,
A97651762421AA11002EB5D4 /* OSLog.swift in Sources */,
E93BA06024A15FA800C5D7E6 /* PrescriptionDeviceView.swift in Sources */,
E9692176249C1AE700D9BE3B /* PrescriptionReviewUICoordinator.swift in Sources */,
A9DAAD3422E7CA1A00E76C9F /* LocalizedString.swift in Sources */,
A9DAAD3922E7DEE000E76C9F /* TidepoolService+UI.swift in Sources */,
A9DAAD6F22E7EA9700E76C9F /* NibLoadable.swift in Sources */,
E93BA05E24A14CBA00C5D7E6 /* PrescriptionCodeEntryViewModel.swift in Sources */,
A92E770122E9181500591027 /* TidepoolServiceSetupViewController.swift in Sources */,
A9DAAD3B22E7DEF100E76C9F /* TidepoolServiceSettingsViewController.swift in Sources */,
);
Expand Down Expand Up @@ -1188,6 +1256,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = TidepoolServiceKitUI/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
Expand All @@ -1214,6 +1283,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = TidepoolServiceKitUI/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
Expand Down
19 changes: 19 additions & 0 deletions TidepoolServiceKit/Extensions/TimeInterval.swift
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 {
Copy link
Contributor

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?

Copy link
Contributor

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?".

Copy link
Contributor

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.

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 */)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] Consider copy/paste this implementation from LoopKit:

    static func minutes(_ minutes: Double) -> TimeInterval {
        return self.init(minutes: minutes)
    }

    static func hours(_ hours: Double) -> TimeInterval {
        return self.init(hours: hours)
    }

    init(minutes: Double) {
        self.init(minutes * 60)
    }

    init(hours: Double) {
        self.init(minutes: hours * 60)
    }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@darinkrauss doesn't TidepoolService have LoopKit as a dependency? Just curious...should she just make those LoopKit functions public and then use them?

157 changes: 157 additions & 0 deletions TidepoolServiceKit/Mocks/MockPrescription.swift
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)
Copy link
Contributor

Choose a reason for hiding this comment

The 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 HKUnit and just use another enum. This would allow you to drop the custom Codable implementation below. The enum could have a func/var that converts it into an HKUnit if you'd like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
}
}
Loading