diff --git a/.travis.yml b/.travis.yml index ae15c2a041..bd1ad9d3b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ before_script: script: # Build the app target - set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme Loop build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty + - set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme Learn build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty # Run the test target - set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme LoopTests -destination 'name=iPhone SE' test | xcpretty - set -o pipefail && xcodebuild -project Loop.xcodeproj -scheme DoseMathTests -destination 'name=iPhone SE' test | xcpretty diff --git a/Cartfile.resolved b/Cartfile.resolved index f157ff4757..ddbfd0d55e 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,7 +1,7 @@ github "LoopKit/Amplitude-iOS" "2137d5fd44bf630ed33e1e72d7af6d8f8612f270" github "LoopKit/CGMBLEKit" "ea1267791c66e884f1013fffd36faf4555cc6eaf" github "LoopKit/G4ShareSpy" "fed5a389e3e47e3a1953878dd21852aa5f44b360" -github "LoopKit/LoopKit" "797a4fffeb0b56c8ce47543ea6516b3b8c8e0857" +github "LoopKit/LoopKit" "c6e9f9200deec9a401ab1725e888451b17dee98a" github "LoopKit/dexcom-share-client-swift" "b0419edf55c7f389b36cb47dd5c376bbd3d03d69" github "i-schuetz/SwiftCharts" "0.6.2" -github "ps2/rileylink_ios" "23af71639041ca3a2a1b4120d3cd0a06c5d3fa01" +github "ps2/rileylink_ios" "8418b57c1983bdefaec7ccb456c86d5efacf40e7" diff --git a/Common/Extensions/HKUnit.swift b/Common/Extensions/HKUnit.swift index 961414a265..52b933a2c3 100644 --- a/Common/Extensions/HKUnit.swift +++ b/Common/Extensions/HKUnit.swift @@ -7,6 +7,7 @@ // import HealthKit +import LoopCore // Code in this extension is duplicated from: // https://github.com/LoopKit/LoopKit/blob/master/LoopKit/HKUnit.swift @@ -21,14 +22,6 @@ extension HKUnit { } } - static let milligramsPerDeciliter: HKUnit = { - return HKUnit.gramUnit(with: .milli).unitDivided(by: HKUnit.literUnit(with: .deci)) - }() - - static let millimolesPerLiter: HKUnit = { - return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: HKUnit.liter()) - }() - var localizedShortUnitString: String { if self == HKUnit.millimolesPerLiter { return NSLocalizedString("mmol/L", comment: "The short unit display string for millimoles of glucose per liter") diff --git a/Common/Extensions/NSTimeInterval.swift b/Common/Extensions/NSTimeInterval.swift index be19ded20d..d24b718fd8 100644 --- a/Common/Extensions/NSTimeInterval.swift +++ b/Common/Extensions/NSTimeInterval.swift @@ -22,6 +22,10 @@ extension TimeInterval { return TimeInterval(hours: hours) } + static func days(_ days: Double) -> TimeInterval { + return TimeInterval(days: days) + } + init(minutes: Double) { self.init(minutes * 60) } @@ -30,6 +34,10 @@ extension TimeInterval { self.init(minutes: hours * 60) } + init(days: Double) { + self.init(hours: days * 24) + } + var minutes: Double { return self / 60.0 } diff --git a/Common/Extensions/NewCarbEntryIntent+Loop.swift b/Common/Extensions/NewCarbEntryIntent+Loop.swift index 11d21f0297..0f2419ffa9 100644 --- a/Common/Extensions/NewCarbEntryIntent+Loop.swift +++ b/Common/Extensions/NewCarbEntryIntent+Loop.swift @@ -6,6 +6,7 @@ // import Foundation +import LoopCore @available(iOS 12.0, watchOSApplicationExtension 5.0, *) extension NewCarbEntryIntent: IdentifiableClass { } diff --git a/Loop/Views/TextFieldTableViewCell.swift b/Common/Extensions/TextFieldTableViewCell.swift similarity index 92% rename from Loop/Views/TextFieldTableViewCell.swift rename to Common/Extensions/TextFieldTableViewCell.swift index 4334e6f4ea..82c5867cc3 100644 --- a/Loop/Views/TextFieldTableViewCell.swift +++ b/Common/Extensions/TextFieldTableViewCell.swift @@ -6,6 +6,7 @@ // import LoopKitUI +import LoopUI extension TextFieldTableViewCell: NibLoadable { } diff --git a/Common/Models/Insulin/ExponentialInsulinModelPreset.swift b/Common/Models/Insulin/ExponentialInsulinModelPreset.swift deleted file mode 100644 index 66644da1b8..0000000000 --- a/Common/Models/Insulin/ExponentialInsulinModelPreset.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// ExponentialInsulinModelPreset.swift -// Loop -// -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import LoopKit - - -enum ExponentialInsulinModelPreset: String { - case humalogNovologAdult - case humalogNovologChild - case fiasp -} - - -// MARK: - Model generation -extension ExponentialInsulinModelPreset { - var actionDuration: TimeInterval { - switch self { - case .humalogNovologAdult: - return .minutes(360) - case .humalogNovologChild: - return .minutes(360) - case .fiasp: - return .minutes(360) - } - } - - var peakActivity: TimeInterval { - switch self { - case .humalogNovologAdult: - return .minutes(75) - case .humalogNovologChild: - return .minutes(65) - case .fiasp: - return .minutes(55) - } - } - - var model: InsulinModel { - return ExponentialInsulinModel(actionDuration: actionDuration, peakActivityTime: peakActivity) - } -} - - -// MARK: - Localization -extension ExponentialInsulinModelPreset { - var title: String { - switch self { - case .humalogNovologAdult: - return NSLocalizedString("Rapid-Acting – Adults", comment: "Title of insulin model preset") - case .humalogNovologChild: - return NSLocalizedString("Rapid-Acting – Children", comment: "Title of insulin model preset") - case .fiasp: - return NSLocalizedString("Fiasp", comment: "Title of insulin model preset") - } - } - - var subtitle: String? { - switch self { - case .humalogNovologAdult: - return NSLocalizedString("A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults.", comment: "Subtitle of Rapid-Acting – Adult preset") - case .humalogNovologChild: - return NSLocalizedString("An adjustment to the adult model based on empirical effects in children.", comment: "Subtitle of Rapid-Acting – Children preset") - case .fiasp: - return NSLocalizedString("A model based on the published absorption of Fiasp insulin.", comment: "Subtitle of Fiasp preset") - } - } -} - - -extension ExponentialInsulinModelPreset: InsulinModel { - var effectDuration: TimeInterval { - return model.effectDuration - } - - func percentEffectRemaining(at time: TimeInterval) -> Double { - return model.percentEffectRemaining(at: time) - } -} - - -extension ExponentialInsulinModelPreset: CustomDebugStringConvertible { - var debugDescription: String { - return "\(self.rawValue)(\(String(reflecting: model))" - } -} diff --git a/Common/Models/LoopSettingsUserInfo.swift b/Common/Models/LoopSettingsUserInfo.swift index 06efd35087..a6123825d8 100644 --- a/Common/Models/LoopSettingsUserInfo.swift +++ b/Common/Models/LoopSettingsUserInfo.swift @@ -5,6 +5,8 @@ // Copyright © 2018 LoopKit Authors. All rights reserved. // +import LoopCore + struct LoopSettingsUserInfo { let settings: LoopSettings diff --git a/DoseMathTests/DoseMathTests.swift b/DoseMathTests/DoseMathTests.swift index 7bde9f85e5..e69f5d34e5 100644 --- a/DoseMathTests/DoseMathTests.swift +++ b/DoseMathTests/DoseMathTests.swift @@ -9,6 +9,7 @@ import XCTest import HealthKit import LoopKit +import LoopCore extension XCTestCase { diff --git a/Learn/AppDelegate.swift b/Learn/AppDelegate.swift new file mode 100644 index 0000000000..7b1a7fe712 --- /dev/null +++ b/Learn/AppDelegate.swift @@ -0,0 +1,61 @@ +// +// AppDelegate.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + guard + let nav = window?.rootViewController as? UINavigationController, + let lessonsVC = nav.topViewController as? LessonsViewController + else { + return false + } + + let dataManager = DataManager() + dataManager.authorize({ + DispatchQueue.main.async { + lessonsVC.lessons = [ + TimeInRangeLesson(dataManager: dataManager) + ] + } + }) + + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Learn/Assets.xcassets/AppIcon.appiconset/Contents.json b/Learn/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..d8db8d65fd --- /dev/null +++ b/Learn/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Learn/Assets.xcassets/Contents.json b/Learn/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/Learn/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Learn/Base.lproj/LaunchScreen.storyboard b/Learn/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..bfa3612941 --- /dev/null +++ b/Learn/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Learn/Base.lproj/Main.storyboard b/Learn/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..e11dcdf980 --- /dev/null +++ b/Learn/Base.lproj/Main.storyboard @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Learn/Configuration/DateEntry.swift b/Learn/Configuration/DateEntry.swift new file mode 100644 index 0000000000..a36a9c5b98 --- /dev/null +++ b/Learn/Configuration/DateEntry.swift @@ -0,0 +1,43 @@ +// +// DateEntry.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import LoopKitUI + + +class DateEntry { + private(set) var date: Date + let title: String + let mode: UIDatePicker.Mode + + init(date: Date, title: String, mode: UIDatePicker.Mode) { + self.date = date + self.title = title + self.mode = mode + } +} + +extension DateEntry: LessonCellProviding { + func registerCell(for tableView: UITableView) { + tableView.register(DateAndDurationTableViewCell.nib(), forCellReuseIdentifier: DateAndDurationTableViewCell.className) + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: DateAndDurationTableViewCell.className, for: indexPath) as! DateAndDurationTableViewCell + cell.delegate = self + cell.titleLabel.text = title + cell.datePicker.isEnabled = true + cell.datePicker.datePickerMode = mode + cell.date = date + return cell + } +} + +extension DateEntry: DatePickerTableViewCellDelegate { + func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) { + date = cell.datePicker.date + } +} diff --git a/Learn/Configuration/NumberEntry.swift b/Learn/Configuration/NumberEntry.swift new file mode 100644 index 0000000000..50eaaa04e4 --- /dev/null +++ b/Learn/Configuration/NumberEntry.swift @@ -0,0 +1,110 @@ +// +// NumberEntry.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import Foundation +import LoopKitUI + + +class TextEntry: TextFieldTableViewCellDelegate { + + func registerCell(for tableView: UITableView) { + tableView.register(TextFieldTableViewCell.nib(), forCellReuseIdentifier: TextFieldTableViewCell.className) + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> TextFieldTableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: TextFieldTableViewCell.className, for: indexPath) as! TextFieldTableViewCell + cell.delegate = self + return cell + } + + // MARK: - TextFieldTableViewCellDelegate + + func textFieldTableViewCellDidBeginEditing(_ cell: TextFieldTableViewCell) { + + } + + func textFieldTableViewCellDidEndEditing(_ cell: TextFieldTableViewCell) { + + } +} + + +class NumberEntry: TextEntry, LessonCellProviding { + + let formatter: NumberFormatter + private(set) var number: NSNumber? + let keyboardType: UIKeyboardType + let placeholder: String? + let unitString: String? + + init(number: NSNumber?, formatter: NumberFormatter, placeholder: String?, unitString: String?, keyboardType: UIKeyboardType) { + self.number = number + self.formatter = formatter + self.placeholder = placeholder + self.unitString = unitString + self.keyboardType = keyboardType + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = super.tableView(tableView, cellForRowAt: indexPath) + cell.textField.placeholder = placeholder + cell.unitLabel?.text = unitString + cell.textField.keyboardType = keyboardType + updateText(for: cell) + return cell + } + + override func textFieldTableViewCellDidEndEditing(_ cell: TextFieldTableViewCell) { + if let text = cell.textField.text { + number = formatter.number(from: text) + } else { + number = nil + } + + updateText(for: cell) + } + + private func updateText(for cell: TextFieldTableViewCell) { + if let number = number { + cell.textField.text = formatter.string(from: number) + } else { + cell.textField.text = nil + } + } +} + + +extension NumberEntry { + class func decimalEntry(value: Double?, unitString: String?) -> NumberEntry { + let number: NSNumber? + if let value = value { + number = NSNumber(value: value) + } else { + number = nil + } + + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + + return NumberEntry(number: number, formatter: formatter, placeholder: nil, unitString: unitString, keyboardType: .decimalPad) + } + + class func integerEntry(value: Int?, unitString: String?) -> NumberEntry { + let number: NSNumber? + if let value = value { + number = NSNumber(value: value) + } else { + number = nil + } + + + let formatter = NumberFormatter() + formatter.numberStyle = .none + + return NumberEntry(number: number, formatter: formatter, placeholder: nil, unitString: unitString, keyboardType: .decimalPad) + } +} diff --git a/Learn/Configuration/NumberRangeEntry.swift b/Learn/Configuration/NumberRangeEntry.swift new file mode 100644 index 0000000000..7382d99a5b --- /dev/null +++ b/Learn/Configuration/NumberRangeEntry.swift @@ -0,0 +1,66 @@ +// +// NumberRangeEntry.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import UIKit + + +class NumberRangeEntry: LessonSectionProviding { + let headerTitle: String? + + let footerTitle: String? = nil + + var cells: [LessonCellProviding] { + return numberCells + } + + var minValue: NSNumber? { + return numberCells.compactMap({ $0.number }).min() + } + + var maxValue: NSNumber? { + return numberCells.compactMap({ $0.number }).max() + } + + var range: Range? { + guard let minValue = minValue, let maxValue = maxValue else { + return nil + } + + return minValue..? { + guard let minValue = minValue, let maxValue = maxValue else { + return nil + } + + return minValue...maxValue + } + + private var numberCells: [NumberEntry] + + init(headerTitle: String?, minValue: NSNumber?, maxValue: NSNumber?, formatter: NumberFormatter, unitString: String?, keyboardType: UIKeyboardType) { + self.headerTitle = headerTitle + + self.numberCells = [ + NumberEntry( + number: minValue, + formatter: formatter, + placeholder: NSLocalizedString("Minimum", comment: "Placeholder for lower range entry"), + unitString: unitString, + keyboardType: keyboardType + ), + NumberEntry( + number: maxValue, + formatter: formatter, + placeholder: NSLocalizedString("Maximum", comment: "Placeholder for upper range entry"), + unitString: unitString, + keyboardType: keyboardType + ), + ] + } +} diff --git a/Learn/Configuration/QuantityRangeEntry.swift b/Learn/Configuration/QuantityRangeEntry.swift new file mode 100644 index 0000000000..fd151b8b05 --- /dev/null +++ b/Learn/Configuration/QuantityRangeEntry.swift @@ -0,0 +1,77 @@ +// +// QuantityRangeEntry.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import HealthKit +import LoopKit +import UIKit + + +class QuantityRangeEntry: LessonSectionProviding { + var headerTitle: String? { + return numberRange.headerTitle + } + + var footerTitle: String? { + return numberRange.footerTitle + } + + var cells: [LessonCellProviding] { + return numberRange.cells + } + + var minValue: HKQuantity? { + if let minValue = numberRange.minValue?.doubleValue { + return HKQuantity(unit: unit, doubleValue: minValue) + } else { + return nil + } + } + + var maxValue: HKQuantity? { + if let maxValue = numberRange.maxValue?.doubleValue { + return HKQuantity(unit: unit, doubleValue: maxValue) + } else { + return nil + } + } + + var range: Range? { + guard let minValue = minValue, let maxValue = maxValue else { + return nil + } + + return minValue..? { + guard let minValue = minValue, let maxValue = maxValue else { + return nil + } + + return minValue...maxValue + } + + private let numberRange: NumberRangeEntry + + let quantityFormatter: QuantityFormatter + + let unit: HKUnit + + init(headerTitle: String?, minValue: HKQuantity?, maxValue: HKQuantity?, quantityFormatter: QuantityFormatter, unit: HKUnit, keyboardType: UIKeyboardType) { + self.quantityFormatter = quantityFormatter + self.unit = unit + + numberRange = NumberRangeEntry( + headerTitle: headerTitle, + minValue: NSNumber(value: minValue?.doubleValue(for: unit)), + maxValue: NSNumber(value: maxValue?.doubleValue(for: unit)), + formatter: quantityFormatter.numberFormatter, + unitString: quantityFormatter.string(from: unit), + keyboardType: keyboardType + ) + } +} diff --git a/Learn/Display/DatesAndNumberCell.swift b/Learn/Display/DatesAndNumberCell.swift new file mode 100644 index 0000000000..be663f716a --- /dev/null +++ b/Learn/Display/DatesAndNumberCell.swift @@ -0,0 +1,43 @@ +// +// DatesAndNumberCell.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import UIKit + + +class DatesAndNumberCell: LessonCellProviding { + static let cellIdentifier = "DatesAndNumberCell" + + let date: DateInterval + let value: NSNumber + let dateFormatter: DateIntervalFormatter + let numberFormatter: NumberFormatter + + init(date: DateInterval, value: NSNumber, dateFormatter: DateIntervalFormatter, numberFormatter: NumberFormatter) { + self.date = date + self.value = value + self.dateFormatter = dateFormatter + self.numberFormatter = numberFormatter + } + + func registerCell(for tableView: UITableView) { + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell: UITableViewCell + + if let existingCell = tableView.dequeueReusableCell(withIdentifier: DatesAndNumberCell.cellIdentifier) { + cell = existingCell + } else { + cell = UITableViewCell(style: .value1, reuseIdentifier: DatesAndNumberCell.cellIdentifier) + } + + cell.textLabel?.text = dateFormatter.string(from: date) + cell.detailTextLabel?.text = numberFormatter.string(from: value) + + return cell + } +} diff --git a/Learn/Display/TextCell.swift b/Learn/Display/TextCell.swift new file mode 100644 index 0000000000..1b96291536 --- /dev/null +++ b/Learn/Display/TextCell.swift @@ -0,0 +1,51 @@ +// +// TextCell.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import UIKit + + +class TextCell: LessonCellProviding { + static let cellIdentifier = "TextCell" + + let text: String + let detailText: String? + let textColor: UIColor? + let detailTextColor: UIColor? + + init(text: String, detailText: String? = nil, textColor: UIColor? = nil, detailTextColor: UIColor? = nil) { + self.text = text + self.detailText = detailText + self.textColor = textColor + self.detailTextColor = detailTextColor + } + + func registerCell(for tableView: UITableView) { + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell: UITableViewCell + + if let existingCell = tableView.dequeueReusableCell(withIdentifier: TextCell.cellIdentifier) { + cell = existingCell + } else { + cell = UITableViewCell(style: .value1, reuseIdentifier: TextCell.cellIdentifier) + } + + cell.textLabel?.text = text + cell.detailTextLabel?.text = detailText + + if let color = textColor { + cell.textLabel?.textColor = color + } + + if let color = detailTextColor { + cell.detailTextLabel?.textColor = color + } + + return cell + } +} diff --git a/Learn/Extensions/Date.swift b/Learn/Extensions/Date.swift new file mode 100644 index 0000000000..bd2f73b890 --- /dev/null +++ b/Learn/Extensions/Date.swift @@ -0,0 +1,21 @@ +// +// Date.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import Foundation + + +extension Date: Strideable { + public typealias Stride = TimeInterval + + public func distance(to other: Date) -> TimeInterval { + return other.timeIntervalSince(self) + } + + public func advanced(by n: TimeInterval) -> Date { + return addingTimeInterval(n) + } +} diff --git a/Learn/Extensions/DateIntervalFormatter.swift b/Learn/Extensions/DateIntervalFormatter.swift new file mode 100644 index 0000000000..33a16e4c2a --- /dev/null +++ b/Learn/Extensions/DateIntervalFormatter.swift @@ -0,0 +1,17 @@ +// +// DateIntervalFormatter.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import Foundation + + +extension DateIntervalFormatter { + convenience init(dateStyle: DateIntervalFormatter.Style, timeStyle: DateIntervalFormatter.Style) { + self.init() + self.dateStyle = dateStyle + self.timeStyle = timeStyle + } +} diff --git a/Learn/Extensions/NSNumber.swift b/Learn/Extensions/NSNumber.swift new file mode 100644 index 0000000000..913f5f8bc4 --- /dev/null +++ b/Learn/Extensions/NSNumber.swift @@ -0,0 +1,26 @@ +// +// NSNumber.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import Foundation + + +extension NSNumber: Comparable { + public static func < (lhs: NSNumber, rhs: NSNumber) -> Bool { + return lhs.compare(rhs) == .orderedAscending + } +} + + +extension NSNumber { + convenience init?(value: Double?) { + if let value = value { + self.init(value: value) + } else { + return nil + } + } +} diff --git a/Learn/Extensions/UITableViewCell.swift b/Learn/Extensions/UITableViewCell.swift new file mode 100644 index 0000000000..369855d0f6 --- /dev/null +++ b/Learn/Extensions/UITableViewCell.swift @@ -0,0 +1,16 @@ +// +// UITableViewCell.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import LoopCore +import LoopKitUI +import LoopUI + + +extension DateAndDurationTableViewCell: NibLoadable { } + + +extension TextButtonTableViewCell: IdentifiableClass { } diff --git a/Learn/Info.plist b/Learn/Info.plist new file mode 100644 index 0000000000..48ea02de2d --- /dev/null +++ b/Learn/Info.plist @@ -0,0 +1,53 @@ + + + + + MainAppBundleIdentifier + $(MAIN_APP_BUNDLE_IDENTIFIER) + AppGroupIdentifier + $(APP_GROUP_IDENTIFIER) + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.9.4 dev + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + NSHealthShareUsageDescription + Meal data from the Health database is used to determine glucose effects. Glucose data from the Health database is used for graphing and momentum calculation. + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + healthkit + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Learn/Learn.entitlements b/Learn/Learn.entitlements new file mode 100644 index 0000000000..b09682c70b --- /dev/null +++ b/Learn/Learn.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.developer.healthkit + + com.apple.developer.healthkit.access + + com.apple.security.application-groups + + $(APP_GROUP_IDENTIFIER) + + + diff --git a/Learn/Lesson.swift b/Learn/Lesson.swift new file mode 100644 index 0000000000..f9f2a0bbf7 --- /dev/null +++ b/Learn/Lesson.swift @@ -0,0 +1,53 @@ +// +// Lesson.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import Foundation +import UIKit + + +protocol Lesson { + init(dataManager: DataManager) + + var title: String { get } + + var subtitle: String { get } + + var configurationSections: [LessonSectionProviding] { get } + + func execute(completion: @escaping (_ resultSections: [LessonSectionProviding]) -> Void) +} + + +protocol LessonSectionProviding { + var headerTitle: String? { get } + + var footerTitle: String? { get } + + var cells: [LessonCellProviding] { get } +} + + +protocol LessonCellProviding { + func registerCell(for tableView: UITableView) + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell +} + + +struct LessonSection: LessonSectionProviding { + let headerTitle: String? + + let footerTitle: String? + + let cells: [LessonCellProviding] + + init(headerTitle: String? = nil, footerTitle: String? = nil, cells: [LessonCellProviding]) { + self.headerTitle = headerTitle + self.footerTitle = footerTitle + self.cells = cells + } +} diff --git a/Learn/Lessons/TimeInRangeLesson.swift b/Learn/Lessons/TimeInRangeLesson.swift new file mode 100644 index 0000000000..34d43e86e6 --- /dev/null +++ b/Learn/Lessons/TimeInRangeLesson.swift @@ -0,0 +1,265 @@ +// +// LessonPlayground.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import Foundation +import LoopCore +import LoopKit +import LoopKitUI +import LoopUI +import HealthKit +import os.log + + +final class TimeInRangeLesson: Lesson { + let title = NSLocalizedString("Time in Range", comment: "Lesson title") + + let subtitle = NSLocalizedString("Computes the percentage of glucose measurements within a specified range", comment: "Lesson subtitle") + + let configurationSections: [LessonSectionProviding] + + private let dataManager: DataManager + + private let glucoseUnit: HKUnit + + private let glucoseFormatter = QuantityFormatter() + + private let dateEntry: DateEntry + + private let weeksEntry: NumberEntry + + private let rangeEntry: QuantityRangeEntry + + init(dataManager: DataManager) { + self.dataManager = dataManager + self.glucoseUnit = dataManager.glucoseStore.preferredUnit ?? .milligramsPerDeciliter + + let twoWeeksAgo = Calendar.current.date(byAdding: DateComponents(weekOfYear: -2), to: Date())! + + glucoseFormatter.setPreferredNumberFormatter(for: glucoseUnit) + + // TODO: Add a date components picker cell, and combine into a "DateIntervalEntry" section + dateEntry = DateEntry( + date: Calendar.current.startOfDay(for: twoWeeksAgo), + title: NSLocalizedString("Start Date", comment: "Title of config entry"), + mode: .date + ) + weeksEntry = NumberEntry.integerEntry( + value: 2, + unitString: NSLocalizedString("Weeks", comment: "Unit string for a count of calendar weeks") + ) + + rangeEntry = QuantityRangeEntry.glucoseRange(quantityFormatter: glucoseFormatter, unit: glucoseUnit) + + self.configurationSections = [ + LessonSection(headerTitle: nil, footerTitle: nil, cells: [dateEntry, weeksEntry]), + rangeEntry + ] + } + + func execute(completion: @escaping ([LessonSectionProviding]) -> Void) { + guard let weeks = weeksEntry.number?.intValue, let closedRange = rangeEntry.closedRange else { + // TODO: Cleaner error presentation + completion([LessonSection(headerTitle: "Error: Please fill out all fields", footerTitle: nil, cells: [])]) + return + } + + let start = dateEntry.date + let calculator = TimeInRangeCalculator(dataManager: dataManager, start: start, duration: DateComponents(weekOfYear: weeks), range: closedRange) + + calculator.perform { result in + switch result { + case .failure(let error): + completion([ + LessonSection(cells: [TextCell(text: String(describing: error))]) + ]) + case .success(let resultsByDay): + guard resultsByDay.count > 0 else { + completion([ + LessonSection(cells: [TextCell(text: NSLocalizedString("No data available", comment: "Lesson result text for no data"))]) + ]) + return + } + + let dateFormatter = DateIntervalFormatter(dateStyle: .short, timeStyle: .none) + let numberFormatter = NumberFormatter() + numberFormatter.numberStyle = .percent + + var aggregator = TimeInRangeAggregator() + resultsByDay.forEach({ (pair) in + aggregator.add(percentInRange: pair.value, for: pair.key) + }) + + completion([ + TimesInRangeSection( + ranges: aggregator.dictionary, + dateFormatter: dateFormatter, + numberFormatter: numberFormatter + ), + TimesInRangeSection( + ranges: resultsByDay, + dateFormatter: dateFormatter, + numberFormatter: numberFormatter + ) + ]) + } + } + } +} + + +private extension QuantityRangeEntry { + class func glucoseRange(quantityFormatter: QuantityFormatter, unit: HKUnit) -> QuantityRangeEntry { + return QuantityRangeEntry( + headerTitle: NSLocalizedString("Range", comment: "Section title for glucose range"), + minValue: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 80), + maxValue: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 160), + quantityFormatter: quantityFormatter, + unit: unit, + keyboardType: unit == .milligramsPerDeciliter ? .numberPad : .decimalPad + ) + } +} + + +class TimesInRangeSection: LessonSectionProviding { + let headerTitle: String? = nil + let footerTitle: String? = nil + + let cells: [LessonCellProviding] + + init(ranges: [DateInterval: Double], dateFormatter: DateIntervalFormatter, numberFormatter: NumberFormatter) { + cells = ranges.sorted(by: { $0.0 < $1.0 }).map { pair -> LessonCellProviding in + DatesAndNumberCell(date: pair.key, value: NSNumber(value: pair.value), dateFormatter: dateFormatter, numberFormatter: numberFormatter) + } + } +} + + +struct TimeInRangeAggregator { + private var count = 0 + private var sum: Double = 0 + var allDates: DateInterval? + + var averagePercentInRange: Double? { + guard count > 0 else { + return nil + } + + return sum / Double(count) + } + + var dictionary: [DateInterval: Double] { + guard let allDates = allDates, let averagePercentInRange = averagePercentInRange else { + return [:] + } + + return [allDates: averagePercentInRange] + } + + mutating func add(percentInRange: Double, for dates: DateInterval) { + sum += percentInRange + count += 1 + + if let allDates = self.allDates { + self.allDates = DateInterval(start: min(allDates.start, dates.start), end: max(allDates.end, dates.end)) + } else { + self.allDates = dates + } + } +} + + +/// Time-in-range, e.g. "2 weeks starting on March 5" +private class TimeInRangeCalculator { + let dataManager: DataManager + let start: Date + let duration: DateComponents + let range: ClosedRange + + init(dataManager: DataManager, start: Date, duration: DateComponents, range: ClosedRange) { + self.dataManager = dataManager + self.start = start + self.duration = duration + self.range = range + + log = OSLog(subsystem: "com.loopkit.Learn", category: String(describing: type(of: self))) + } + + private let log: OSLog + + private let unit = HKUnit.milligramsPerDeciliter + + func perform(completion: @escaping (_ result: Result<[DateInterval: Double]>) -> Void) { + // Compute the end date + guard let end = Calendar.current.date(byAdding: duration, to: start) else { + fatalError("Unable to resolve duration: \(duration)") + } + + os_log(.default, "Computing Time in range from %{public}@ for %{public}@ between %{public}@", String(describing: start), String(describing: end), String(describing: range)) + + // Paginate into 24-hour blocks + let lockedResults = Locked([DateInterval: Double]()) + var anyError: Error? + + let group = DispatchGroup() + + var segmentStart = start + + Calendar.current.enumerateDates(startingAfter: start, matching: DateComponents(hour: 0), matchingPolicy: .nextTime) { (date, _, stop) in + guard let date = date else { + stop = true + return + } + + let interval = DateInterval(start: segmentStart, end: min(end, date)) + + guard interval.duration > 0 else { + stop = true + return + } + + os_log(.default, "Fetching samples in %{public}@", String(describing: interval)) + + group.enter() + dataManager.glucoseStore.getGlucoseSamples(start: interval.start, end: interval.end) { (result) in + switch result { + case .failure(let error): + os_log(.error, log: self.log, "Failed to fetch samples: %{public}@", String(describing: error)) + anyError = error + case .success(let samples): + var inRangeCount = 0 + var totalCount = 0 + + for sample in samples { + if self.range.contains(sample.quantity) { + inRangeCount += 1 + } + totalCount += 1 + } + + if totalCount > 0 { + _ = lockedResults.mutate({ (results) in + results[interval] = Double(inRangeCount) / Double(totalCount) + }) + } + } + + group.leave() + } + + segmentStart = interval.end + } + + group.notify(queue: DispatchQueue.main) { + if let error = anyError { + completion(.failure(error)) + } else { + completion(.success(lockedResults.value)) + } + } + } +} diff --git a/Learn/Managers/DataManager.swift b/Learn/Managers/DataManager.swift new file mode 100644 index 0000000000..7082b5e6ff --- /dev/null +++ b/Learn/Managers/DataManager.swift @@ -0,0 +1,133 @@ +// +// DataManager.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import Foundation +import HealthKit +import LoopKit +import LoopCore + + +final class DataManager { + let carbStore: CarbStore + + let doseStore: DoseStore + + let glucoseStore: GlucoseStore + + let settings: LoopSettings + + init( + basalRateSchedule: BasalRateSchedule? = UserDefaults.appGroup?.basalRateSchedule, + carbRatioSchedule: CarbRatioSchedule? = UserDefaults.appGroup?.carbRatioSchedule, + insulinModelSettings: InsulinModelSettings? = UserDefaults.appGroup?.insulinModelSettings, + insulinSensitivitySchedule: InsulinSensitivitySchedule? = UserDefaults.appGroup?.insulinSensitivitySchedule, + settings: LoopSettings = UserDefaults.appGroup?.loopSettings ?? LoopSettings() + ) { + self.settings = settings + + let healthStore = HKHealthStore() + let cacheStore = PersistenceController.controllerInAppGroupDirectory(isReadOnly: true) + + carbStore = CarbStore( + healthStore: healthStore, + cacheStore: cacheStore, + observationEnabled: false, + carbRatioSchedule: carbRatioSchedule, + insulinSensitivitySchedule: insulinSensitivitySchedule + ) + + doseStore = DoseStore( + healthStore: healthStore, + cacheStore: cacheStore, + observationEnabled: false, + insulinModel: insulinModelSettings?.model, + basalProfile: basalRateSchedule, + insulinSensitivitySchedule: insulinSensitivitySchedule + ) + + glucoseStore = GlucoseStore( + healthStore: healthStore, + cacheStore: cacheStore, + observationEnabled: false + ) + } +} + + +// MARK: - Thread-safe Preferences +extension DataManager { + /// The daily schedule of basal insulin rates + var basalRateSchedule: BasalRateSchedule? { + return doseStore.basalProfile + } + + /// The daily schedule of carbs-to-insulin ratios + /// This is measured in grams/Unit + var carbRatioSchedule: CarbRatioSchedule? { + return carbStore.carbRatioSchedule + } + + /// The length of time insulin has an effect on blood glucose + var insulinModelSettings: InsulinModelSettings? { + guard let model = doseStore.insulinModel else { + return nil + } + + return InsulinModelSettings(model: model) + } + + /// The daily schedule of insulin sensitivity (also known as ISF) + /// This is measured in /Unit + var insulinSensitivitySchedule: InsulinSensitivitySchedule? { + return carbStore.insulinSensitivitySchedule + } +} + + +// MARK: - HealthKit Setup +extension DataManager { + var healthStore: HKHealthStore { + return carbStore.healthStore + } + + /// All the HealthKit types to be read and shared by stores + private var sampleTypes: Set { + return Set([ + glucoseStore.sampleType, + carbStore.sampleType, + doseStore.sampleType, + ].compactMap { $0 }) + } + + /// True if any stores require HealthKit authorization + var authorizationRequired: Bool { + return glucoseStore.authorizationRequired || + carbStore.authorizationRequired || + doseStore.authorizationRequired + } + + /// True if the user has explicitly denied access to any stores' HealthKit types + private var sharingDenied: Bool { + return glucoseStore.sharingDenied || + carbStore.sharingDenied || + doseStore.sharingDenied + } + + func authorize(_ completion: @escaping () -> Void) { + // Authorize all types at once for simplicity + carbStore.healthStore.requestAuthorization(toShare: [], read: sampleTypes) { (success, error) in + if success { + // Call the individual authorization methods to trigger query creation + self.carbStore.authorize(toShare: false, { _ in }) + self.doseStore.insulinDeliveryStore.authorize(toShare: false, { _ in }) + self.glucoseStore.authorize(toShare: false, { _ in }) + } + + completion() + } + } +} diff --git a/Learn/View Controllers/LessonConfigurationViewController.swift b/Learn/View Controllers/LessonConfigurationViewController.swift new file mode 100644 index 0000000000..c6476f2119 --- /dev/null +++ b/Learn/View Controllers/LessonConfigurationViewController.swift @@ -0,0 +1,161 @@ +// +// LessonConfigurationViewController.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import UIKit +import LoopKitUI + +class LessonConfigurationViewController: UITableViewController { + + var lesson: Lesson! + + private enum State { + case editing + case executing + } + + private var state = State.editing { + didSet { + guard state != oldValue else { + return + } + + if let cell = tableView.cellForRow(at: IndexPath(row: 0, section: lesson.configurationSections.count)) as? TextButtonTableViewCell { + cell.isLoading = state == .executing + cell.isEnabled = state == .editing + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + title = lesson.title + tableView.estimatedRowHeight = 44 + tableView.rowHeight = UITableView.automaticDimension + + for section in lesson.configurationSections { + for cell in section.cells { + cell.registerCell(for: self.tableView) + } + } + + tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className) + } + + /// If a tap occurs in the table view, but not on any cells, dismiss any active edits + @IBAction private func dismissActiveEditing(gestureRecognizer: UITapGestureRecognizer) { + let tapPoint = gestureRecognizer.location(in: tableView) + guard tableView.indexPathForRow(at: tapPoint) == nil else { + return + } + + tableView.endEditing(false) + tableView.beginUpdates() + hideDatePickerCells() + tableView.endUpdates() + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + return lesson.configurationSections.count + 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == lesson.configurationSections.count { + return 1 + } else { + return lesson.configurationSections[section].cells.count + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + if indexPath.section == lesson.configurationSections.count { + let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell + cell.textLabel?.text = NSLocalizedString("Continue", comment: "Title of the button to begin lesson execution") + + switch state { + case .editing: + cell.isEnabled = true + cell.isLoading = false + case .executing: + cell.isEnabled = false + cell.isLoading = true + } + + return cell + } else { + return lesson.configurationSections[indexPath.section].cells[indexPath.item].tableView(tableView, cellForRowAt: indexPath) + } + } + + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + if section < lesson.configurationSections.count { + return lesson.configurationSections[section].headerTitle + } else { + return nil + } + } + + override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { + if section < lesson.configurationSections.count { + return lesson.configurationSections[section].footerTitle + } else { + return nil + } + } + + // MARK: - UITableViewDelegate + + override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { + return state == .editing + } + + override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { + guard case .editing = state else { + return nil + } + + tableView.endEditing(false) + tableView.beginUpdates() + hideDatePickerCells(excluding: indexPath) + return indexPath + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.endUpdates() + tableView.deselectRow(at: indexPath, animated: true) + + if indexPath.section == lesson.configurationSections.count { + state = .executing + + lesson.execute { resultSections in + dispatchPrecondition(condition: .onQueue(.main)) + + self.performSegue(withIdentifier: LessonResultsViewController.className, sender: resultSections) + + self.state = .editing + } + } + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + super.prepare(for: segue, sender: sender) + + if let results = sender as? [LessonSectionProviding], let destination = segue.destination as? LessonResultsViewController { + destination.lesson = lesson + destination.results = results + } + } +} + + +extension LessonConfigurationViewController: DatePickerTableViewCellDelegate { + func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) { + + } +} diff --git a/Learn/View Controllers/LessonResultsViewController.swift b/Learn/View Controllers/LessonResultsViewController.swift new file mode 100644 index 0000000000..e9c45b6b44 --- /dev/null +++ b/Learn/View Controllers/LessonResultsViewController.swift @@ -0,0 +1,58 @@ +// +// LessonResultsViewController.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import LoopCore +import UIKit + + +class LessonResultsViewController: UITableViewController, IdentifiableClass { + + var lesson: Lesson! + + var results: [LessonSectionProviding] = [] { + didSet { + if isViewLoaded { + tableView.reloadData() + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + title = lesson.title + + for section in results { + for cell in section.cells { + cell.registerCell(for: self.tableView) + } + } + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + return results.count + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return results[section].cells.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + return results[indexPath.section].cells[indexPath.row].tableView(tableView, cellForRowAt: indexPath) + } + + override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { + return nil + } + + override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { + return false + } + +} diff --git a/Learn/View Controllers/LessonsViewController.swift b/Learn/View Controllers/LessonsViewController.swift new file mode 100644 index 0000000000..a5c3b4ef7a --- /dev/null +++ b/Learn/View Controllers/LessonsViewController.swift @@ -0,0 +1,46 @@ +// +// LessonsViewController.swift +// Learn +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +import UIKit + +class LessonsViewController: UITableViewController { + + var lessons: [Lesson] = [] { + didSet { + if isViewLoaded { + tableView.reloadData() + } + } + } + + // MARK: - Table view data source + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return lessons.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Lesson", for: indexPath) + let lesson = lessons[indexPath.row] + + cell.textLabel?.text = lesson.title + cell.detailTextLabel?.text = lesson.subtitle + + return cell + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + super.prepare(for: segue, sender: sender) + + if let configVC = segue.destination as? LessonConfigurationViewController, + let cell = sender as? UITableViewCell, + let indexPath = tableView.indexPath(for: cell) + { + configVC.lesson = lessons[indexPath.row] + } + } +} diff --git a/Loop Status Extension/Base.lproj/Localizable.strings b/Loop Status Extension/Base.lproj/Localizable.strings index 4c9097d64c..d6bea75c74 100644 --- a/Loop Status Extension/Base.lproj/Localizable.strings +++ b/Loop Status Extension/Base.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "A model based on the published absorption of Fiasp insulin."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "An adjustment to the adult model based on empirical effects in children."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Eventually %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "g"; @@ -34,17 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Rapid-Acting – Adults"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Rapid-Acting – Children"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "The legacy model used by Loop, allowing customization of action duration."; - /* The short unit display string for international units of insulin */ "U" = "U"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; diff --git a/Loop Status Extension/StatusViewController.swift b/Loop Status Extension/StatusViewController.swift index 29176c2a2a..b8657a6310 100644 --- a/Loop Status Extension/StatusViewController.swift +++ b/Loop Status Extension/StatusViewController.swift @@ -10,6 +10,7 @@ import CoreData import HealthKit import LoopKit import LoopKitUI +import LoopCore import LoopUI import NotificationCenter import UIKit @@ -60,7 +61,7 @@ class StatusViewController: UIViewController, NCWidgetProviding { var statusExtensionContext: StatusExtensionContext? - lazy var defaults = UserDefaults(suiteName: Bundle.main.appGroupSuiteName) + lazy var defaults = UserDefaults.appGroup private var observers: [Any] = [] diff --git a/Loop Status Extension/de.lproj/Localizable.strings b/Loop Status Extension/de.lproj/Localizable.strings index e18f2cf64d..9647565cac 100644 --- a/Loop Status Extension/de.lproj/Localizable.strings +++ b/Loop Status Extension/de.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "Ein Modell basierend auf der veröffentlichten Absorption von Fiasp-Insulin."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "Ein Modell auf der Grundlage der veröffentlichten Absorption von Humalog, Novolog und Apidra Insulin bei Erwachsenen."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "Eine Anpassung an das Erwachsenenmodell basierend auf empirischen Effekten bei Kindern."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Schließlich %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "g"; @@ -34,18 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Schnell handelnd - Erwachsene"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Schnell handelnd - Kinder"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Das Legacy-Modell, das von Loop verwendet wird und die Anpassung der Aktionsdauer ermöglicht."; - /* The short unit display string for international units of insulin */ "U" = "E"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop Status Extension/es.lproj/Localizable.strings b/Loop Status Extension/es.lproj/Localizable.strings index 689064591d..28d6aca859 100644 --- a/Loop Status Extension/es.lproj/Localizable.strings +++ b/Loop Status Extension/es.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "Un modelo basado en la publicación de la absorción de insulina Fiasp."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "Un modelo basado en la publicación de la absorción de insulina Humalog, Novolog y Apidra en adultos."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "Un ajuste al modelo adulto basado en los efectos empíricos en niños."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Eventualmente %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "g"; @@ -34,18 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Acción Rápida — Adultos"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Acción Rápida — Niños"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "El model utilizado por ediciones iniciales de Loop, permite ajustar duración de acción."; - /* The short unit display string for international units of insulin */ "U" = "U"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop Status Extension/fr.lproj/Localizable.strings b/Loop Status Extension/fr.lproj/Localizable.strings index 1baaaf0570..3504d07581 100644 --- a/Loop Status Extension/fr.lproj/Localizable.strings +++ b/Loop Status Extension/fr.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "Un modèle basé sur l’absorption publiée de l’insuline FIASP."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "Un modèle basé sur l’absorption publiée de l’Hunalog, Novolog, et Apidra chez l’adulte."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "Un ajustement au modèle adulte basé sur des effets empiriques chez les enfants."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Éventuellement %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "g"; @@ -34,18 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Action rapide - Adulte"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Action rapide - Enfant"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Le modèle hérité utilisé par Loop, permettant de personnaliser la durée de l’action."; - /* The short unit display string for international units of insulin */ "U" = "U"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop Status Extension/it.lproj/Localizable.strings b/Loop Status Extension/it.lproj/Localizable.strings index 732d79d715..d50f79d31d 100644 --- a/Loop Status Extension/it.lproj/Localizable.strings +++ b/Loop Status Extension/it.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "Modello basato sull'assorbimento dell'insulina Fiasp."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "Modello basato sull'assorbimento negli adulti dell'insulina Humalog, Novolog ed Apidra."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "Un adattamento al modello adulto basato su effetti empirici nei bambini."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Probabile Glic. %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "g"; @@ -34,18 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Insulina ultrarapida – Adulti"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Insulina ultrarapida – Bambini"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "ll modello legacy utilizzato da Loop, che consente la personalizzazione della durata dell'azione."; - /* The short unit display string for international units of insulin */ "U" = "U"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop Status Extension/nb.lproj/Localizable.strings b/Loop Status Extension/nb.lproj/Localizable.strings index 766f3ff5d7..8b9c8d3ca4 100644 --- a/Loop Status Extension/nb.lproj/Localizable.strings +++ b/Loop Status Extension/nb.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "En modell basert på publiserte data for absorpsjon av Fiasp insulin."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "En modell basert på publiserte data for absorpsjon av Humalog, Novolog og Apidra insulin hos voksne."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "En justering til modellen tilpasset voksne, basert på empiriske effekter hos barn."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Omsider %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "g"; @@ -34,18 +22,6 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Hurtigvirkende – voksen"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Hurtigvirkende – barn"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Den gamle modellen brukt av Loop, tillater endring av varighet for tiltak."; - /* The short unit display string for international units of insulin */ "U" = "E"; -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop Status Extension/nl.lproj/Localizable.strings b/Loop Status Extension/nl.lproj/Localizable.strings index d245c795f3..b461d99419 100644 --- a/Loop Status Extension/nl.lproj/Localizable.strings +++ b/Loop Status Extension/nl.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "Een model gebaseerd op de gepubliceerde opname van Fiasp insuline."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "Een model gebaseerd op de gepubliceerde opname van Humalog, Novorapid, en Apidra insuline bij volwassenen."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "Een aanpassing aan het volwassen model gebaseerd om praktijk effecten bij kinderen."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Uiteindelijk %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "gr"; @@ -34,18 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Snelwerkende - volwassenen"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Snelwerkende - kinderen"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Het oude model dat door Loop wordt gebruikt, waardoor de actieduur kan worden aangepast."; - /* The short unit display string for international units of insulin */ "U" = "E"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop Status Extension/pl.lproj/Localizable.strings b/Loop Status Extension/pl.lproj/Localizable.strings index faab632afe..63067cea30 100644 --- a/Loop Status Extension/pl.lproj/Localizable.strings +++ b/Loop Status Extension/pl.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "Model oparty na opublikowanym czasie absorpcji insuliny Fiasp."; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "Model oparty na opublikowanym czasie absorpcji insulin Humalog, Novolog/Novorapid i Apidra u dorosłych."; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "Model absorpcji insuliny u dzieci oparty na empirycznym dostosowaniu czasu absorpcji u dorosłych."; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "Docelowo %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "g"; @@ -34,17 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Szybko działająca – dorośli"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Szybko działająca – dzieci"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Model umożliwiający dostosowanie czasu działania insuliny."; - /* The short unit display string for international units of insulin */ "U" = "J"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; diff --git a/Loop Status Extension/ru.lproj/Localizable.strings b/Loop Status Extension/ru.lproj/Localizable.strings index eaad302889..fad6c822b1 100644 --- a/Loop Status Extension/ru.lproj/Localizable.strings +++ b/Loop Status Extension/ru.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "модель, основанная на опубликованных данных усвоения FIASP инсулина"; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "модель, основанная на опубликованных данных усвоения Humalog, Novolog и Apidra у взрослых"; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "Поправка к модели для взрослых основанная на эмпирических данных для детей"; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "В конечном итоге %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "г"; @@ -34,18 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "Боыстродействующий - взрослые"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "Быстродействующий - дети"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Модель, используемая для цикла/контура, позволяет настройку длительности действия"; - /* The short unit display string for international units of insulin */ "U" = "ед"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop Status Extension/zh-Hans.lproj/Localizable.strings b/Loop Status Extension/zh-Hans.lproj/Localizable.strings index 79541f11d5..3fd0ae4ddc 100644 --- a/Loop Status Extension/zh-Hans.lproj/Localizable.strings +++ b/Loop Status Extension/zh-Hans.lproj/Localizable.strings @@ -1,24 +1,12 @@ /* The format string for the app name and version number. (1: bundle name)(2: bundle version) */ "%1$@ v%2$@" = "%1$@ v%2$@"; -/* Subtitle of Fiasp preset */ -"A model based on the published absorption of Fiasp insulin." = "基于公布的Fiasp胰岛素吸收的模型"; - -/* Subtitle of Rapid-Acting – Adult preset */ -"A model based on the published absorption of Humalog, Novolog, and Apidra insulin in adults." = "基于已公布的Humalog,Novolog和Apidra胰岛素在成人中吸收的模型。"; - -/* Subtitle of Rapid-Acting – Children preset */ -"An adjustment to the adult model based on empirical effects in children." = "在成人胰岛素模型基础上专为儿童修改的胰岛素代谢模型"; - /* The short unit display string for decibles */ "dB" = "dB"; /* The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description) */ "Eventually %1$@ %2$@" = "最终 %1$@ %2$@"; -/* Title of insulin model preset */ -"Fiasp" = "Fiasp"; - /* The short unit display string for grams */ "g" = "克"; @@ -34,18 +22,5 @@ /* Format string for combining localized numeric value and unit. (1: numeric value)(2: unit) */ "QUANTITY_VALUE_AND_UNIT" = "%1$@ %2$@"; -/* Title of insulin model preset */ -"Rapid-Acting – Adults" = "速效胰岛素 - 成人模型"; - -/* Title of insulin model preset */ -"Rapid-Acting – Children" = "速效胰岛素 - 儿童模型"; - -/* Subtitle description of Walsh insulin model setting */ -"The legacy model used by Loop, allowing customization of action duration." = "Loop使用的默认模型参数,您可以自行修改胰岛素代谢时间。"; - /* The short unit display string for international units of insulin */ "U" = "单位"; - -/* Title of insulin model setting */ -"Walsh" = "Walsh"; - diff --git a/Loop.xcodeproj/project.pbxproj b/Loop.xcodeproj/project.pbxproj index 4422013483..2a032d66c6 100644 --- a/Loop.xcodeproj/project.pbxproj +++ b/Loop.xcodeproj/project.pbxproj @@ -25,21 +25,19 @@ 43027F0F1DFE0EC900C51989 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F526D5E1DF2459000A04910 /* HKUnit.swift */; }; 4302F4E11D4E9C8900F0FCAF /* TextFieldTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4E01D4E9C8900F0FCAF /* TextFieldTableViewController.swift */; }; 4302F4E31D4EA54200F0FCAF /* InsulinDeliveryTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4302F4E21D4EA54200F0FCAF /* InsulinDeliveryTableViewController.swift */; }; - 430B298A2041F54A00BA9F93 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */; }; - 430B298B2041F55700BA9F93 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */; }; - 430B298E2041F56500BA9F93 /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298C2041F56500BA9F93 /* LoopSettings.swift */; }; - 430B298F2041F56500BA9F93 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; - 430B29902041F57000BA9F93 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; - 430B29912041F57200BA9F93 /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298C2041F56500BA9F93 /* LoopSettings.swift */; }; 430B29932041F5B300BA9F93 /* UserDefaults+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29922041F5B200BA9F93 /* UserDefaults+Loop.swift */; }; 430B29952041F5CB00BA9F93 /* LoopSettings+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29942041F5CB00BA9F93 /* LoopSettings+Loop.swift */; }; 430D85891F44037000AF2D4F /* HUDViewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430D85881F44037000AF2D4F /* HUDViewTableViewCell.swift */; }; - 430DA58E1D4AEC230097D1CA /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; 4311FB9B1F37FE1B00D4C0A7 /* TitleSubtitleTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4311FB9A1F37FE1B00D4C0A7 /* TitleSubtitleTextFieldTableViewCell.swift */; }; 4315D2871CA5CC3B00589052 /* CarbEntryEditTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4315D2861CA5CC3B00589052 /* CarbEntryEditTableViewController.swift */; }; 4315D28A1CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4315D2891CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift */; }; 431A8C401EC6E8AB00823B9C /* CircleMaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431A8C3F1EC6E8AB00823B9C /* CircleMaskView.swift */; }; - 431E73481FF95A900069B5F7 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431E73471FF95A900069B5F7 /* PersistenceController.swift */; }; + 431EA87021EB29120076EC1A /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */; }; + 431EA87121EB29120076EC1A /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */; }; + 431EA87221EB29150076EC1A /* InsulinModelSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */; }; + 431EA87321EB29160076EC1A /* InsulinModelSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */; }; + 431EA87421EB291A0076EC1A /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */; }; + 431EA87521EB291B0076EC1A /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */; }; 4326BA641F3A44D9007CCAD4 /* ChartLineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4326BA631F3A44D9007CCAD4 /* ChartLineModel.swift */; }; 4328E01A1CFBE1DA00E199AA /* ActionHUDController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4328E0151CFBE1DA00E199AA /* ActionHUDController.swift */; }; 4328E01B1CFBE1DA00E199AA /* BolusInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4328E0161CFBE1DA00E199AA /* BolusInterfaceController.swift */; }; @@ -64,14 +62,19 @@ 4344628F20A7ADD500C4BE6F /* UserDefaults+CGM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4344628D20A7ADD100C4BE6F /* UserDefaults+CGM.swift */; }; 4344629220A7C19800C4BE6F /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4344629120A7C19800C4BE6F /* ButtonGroup.swift */; }; 4344629820A8B2D700C4BE6F /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5EE209D84BE00D17AA8 /* OSLog.swift */; }; + 4345E3F221F0351E009E00E5 /* Locked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5F1209D897600D17AA8 /* Locked.swift */; }; + 4345E3F321F0351E009E00E5 /* Locked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5F1209D897600D17AA8 /* Locked.swift */; }; + 4345E3F421F036FC009E00E5 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D848AF1E7DCBE100DADCBC /* Result.swift */; }; + 4345E3F521F036FC009E00E5 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D848AF1E7DCBE100DADCBC /* Result.swift */; }; + 4345E3F821F03D2A009E00E5 /* DatesAndNumberCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345E3F721F03D2A009E00E5 /* DatesAndNumberCell.swift */; }; + 4345E3FA21F0473B009E00E5 /* TextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345E3F921F0473B009E00E5 /* TextCell.swift */; }; + 4345E3FB21F04911009E00E5 /* UIColor+HIG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */; }; + 4345E3FC21F04911009E00E5 /* UIColor+HIG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */; }; + 4345E3FE21F04A50009E00E5 /* DateIntervalFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345E3FD21F04A50009E00E5 /* DateIntervalFormatter.swift */; }; + 4345E3FF21F051C6009E00E5 /* LoopCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; }; + 4345E40021F051DD009E00E5 /* LoopCore.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4346D1E71C77F5FE00ABAFE3 /* ChartTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4346D1E61C77F5FE00ABAFE3 /* ChartTableViewCell.swift */; }; - 434B2886206628B3000EE07B /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431E73471FF95A900069B5F7 /* PersistenceController.swift */; }; - 434B2887206B4F07000EE07B /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */; }; - 434B2888206B4F0A000EE07B /* InsulinModelSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */; }; - 434B2889206B4F0C000EE07B /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */; }; - 434F54571D287FDB002A9274 /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434F54561D287FDB002A9274 /* NibLoadable.swift */; }; 434FB6461D68F1CD007B9C70 /* Amplitude.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 434FB6451D68F1CD007B9C70 /* Amplitude.framework */; }; - 434FF1EA1CF26C29000DB779 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FF1E91CF26C29000DB779 /* IdentifiableClass.swift */; }; 434FF1EE1CF27EEF000DB779 /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FF1ED1CF27EEF000DB779 /* UITableViewCell.swift */; }; 43523EDB1CC35083001850F1 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43523EDA1CC35083001850F1 /* RileyLinkKit.framework */; }; 435400311C9F744E00D5819C /* BolusSuggestionUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400301C9F744E00D5819C /* BolusSuggestionUserInfo.swift */; }; @@ -79,9 +82,6 @@ 435400341C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */; }; 435400351C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */; }; 435CB6231F37967800C320C7 /* InsulinModelSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6221F37967800C320C7 /* InsulinModelSettingsViewController.swift */; }; - 435CB6251F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */; }; - 435CB6271F37AE5600C320C7 /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */; }; - 435CB6291F37B01300C320C7 /* InsulinModelSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */; }; 436961911F19D11E00447E89 /* ChartPointsContextFillLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4369618F1F19C86400447E89 /* ChartPointsContextFillLayer.swift */; }; 436A0DA51D236A2A00104B24 /* LoopError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436A0DA41D236A2A00104B24 /* LoopError.swift */; }; 436D9BF81F6F4EA100CFA75F /* recommended_temp_start_low_end_just_above_range.json in Resources */ = {isa = PBXBuildFile; fileRef = 436D9BF71F6F4EA100CFA75F /* recommended_temp_start_low_end_just_above_range.json */; }; @@ -91,21 +91,12 @@ 4372E488213C862B0068E043 /* SampleValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4372E486213C86240068E043 /* SampleValue.swift */; }; 4372E48B213CB5F00068E043 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4372E48A213CB5F00068E043 /* Double.swift */; }; 4372E48C213CB6750068E043 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4372E48A213CB5F00068E043 /* Double.swift */; }; - 4372E48D213CF8A70068E043 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; - 4372E48E213CF8AD0068E043 /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298C2041F56500BA9F93 /* LoopSettings.swift */; }; 4372E490213CFCE70068E043 /* LoopSettingsUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4372E48F213CFCE70068E043 /* LoopSettingsUserInfo.swift */; }; 4372E491213D05F90068E043 /* LoopSettingsUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4372E48F213CFCE70068E043 /* LoopSettingsUserInfo.swift */; }; 4372E492213D956C0068E043 /* GlucoseRangeSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C513181E864C4E001547C7 /* GlucoseRangeSchedule.swift */; }; 4372E496213DCDD30068E043 /* GlucoseChartValueHashable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4372E495213DCDD30068E043 /* GlucoseChartValueHashable.swift */; }; - 4372E497213F79F90068E043 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */; }; - 4372E498213F7A550068E043 /* InsulinModelSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */; }; - 4372E499213F7A6D0068E043 /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */; }; - 4372E49A213F7A830068E043 /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */; }; - 4372E49B213F7B340068E043 /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; 4374B5EF209D84BF00D17AA8 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5EE209D84BE00D17AA8 /* OSLog.swift */; }; 4374B5F0209D857E00D17AA8 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5EE209D84BE00D17AA8 /* OSLog.swift */; }; - 4374B5F2209D897600D17AA8 /* Locked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5F1209D897600D17AA8 /* Locked.swift */; }; - 4374B5F4209D89A900D17AA8 /* TextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5F3209D89A900D17AA8 /* TextFieldTableViewCell.swift */; }; 43776F901B8022E90074EA36 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43776F8F1B8022E90074EA36 /* AppDelegate.swift */; }; 43776F971B8022E90074EA36 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43776F951B8022E90074EA36 /* Main.storyboard */; }; 43776F991B8022E90074EA36 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43776F981B8022E90074EA36 /* Assets.xcassets */; }; @@ -150,15 +141,35 @@ 43BFF0B71E45C20C00FF19A9 /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0B31E45C1BE00FF19A9 /* NumberFormatter.swift */; }; 43BFF0BC1E45C80600FF19A9 /* UIColor+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0BB1E45C80600FF19A9 /* UIColor+Loop.swift */; }; 43BFF0BF1E45C8EA00FF19A9 /* UIColor+Widget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0BE1E45C8EA00FF19A9 /* UIColor+Widget.swift */; }; - 43BFF0C51E465A2D00FF19A9 /* UIColor+HIG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */; }; 43BFF0C61E465A4400FF19A9 /* UIColor+HIG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */; }; - 43BFF0C71E465A4F00FF19A9 /* UIColor+HIG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */; }; 43BFF0CD1E466C8400FF19A9 /* StateColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0CC1E466C8400FF19A9 /* StateColorPalette.swift */; }; + 43C05CA821EB2B26006FB252 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431E73471FF95A900069B5F7 /* PersistenceController.swift */; }; + 43C05CA921EB2B26006FB252 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431E73471FF95A900069B5F7 /* PersistenceController.swift */; }; + 43C05CAA21EB2B49006FB252 /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; + 43C05CAB21EB2B4A006FB252 /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; + 43C05CAC21EB2B8B006FB252 /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; + 43C05CAD21EB2BBF006FB252 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */; }; + 43C05CAE21EB2BBF006FB252 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */; }; + 43C05CAF21EB2C24006FB252 /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; + 43C05CB121EBBDB9006FB252 /* TimeInRangeLesson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CB021EBBDB9006FB252 /* TimeInRangeLesson.swift */; }; + 43C05CB221EBD88A006FB252 /* LoopCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9002A21EB209400AF44BF /* LoopCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 43C05CB521EBE274006FB252 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CB421EBE274006FB252 /* Date.swift */; }; + 43C05CB621EBE321006FB252 /* NSTimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439897341CD2F7DE00223065 /* NSTimeInterval.swift */; }; + 43C05CB821EBEA54006FB252 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CB721EBEA54006FB252 /* HKUnit.swift */; }; + 43C05CB921EBEA54006FB252 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CB721EBEA54006FB252 /* HKUnit.swift */; }; + 43C05CBA21EBEAD8006FB252 /* LoopCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; }; + 43C05CBD21EBF77D006FB252 /* LessonsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CBC21EBF77D006FB252 /* LessonsViewController.swift */; }; + 43C05CC021EBFFA4006FB252 /* Lesson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CBF21EBFFA4006FB252 /* Lesson.swift */; }; + 43C05CC221EC06E4006FB252 /* LessonConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CC121EC06E4006FB252 /* LessonConfigurationViewController.swift */; }; + 43C05CC521EC29E3006FB252 /* TextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5F3209D89A900D17AA8 /* TextFieldTableViewCell.swift */; }; + 43C05CC621EC29E7006FB252 /* TextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5F3209D89A900D17AA8 /* TextFieldTableViewCell.swift */; }; + 43C05CC721EC2ABC006FB252 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FF1E91CF26C29000DB779 /* IdentifiableClass.swift */; }; + 43C05CC821EC2ABC006FB252 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FF1E91CF26C29000DB779 /* IdentifiableClass.swift */; }; + 43C05CCA21EC382B006FB252 /* NumberEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C05CC921EC382B006FB252 /* NumberEntry.swift */; }; 43C0944A1CACCC73001F6403 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C094491CACCC73001F6403 /* NotificationManager.swift */; }; 43C246A81D89990F0031F8D1 /* Crypto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43C246A71D89990F0031F8D1 /* Crypto.framework */; }; 43C2FAE11EB656A500364AFF /* GlucoseEffectVelocity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C2FAE01EB656A500364AFF /* GlucoseEffectVelocity.swift */; }; 43C3B6EC20B650A80026CAFA /* SettingsImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C3B6EB20B650A80026CAFA /* SettingsImageTableViewCell.swift */; }; - 43C3B6ED20B884500026CAFA /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; 43C513191E864C4E001547C7 /* GlucoseRangeSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C513181E864C4E001547C7 /* GlucoseRangeSchedule.swift */; }; 43CA93371CB98079000026B5 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43CA93361CB98079000026B5 /* MinimedKit.framework */; }; 43CB2B2B1D924D450079823D /* WCSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CB2B2A1D924D450079823D /* WCSession.swift */; }; @@ -166,7 +177,42 @@ 43CEE6E61E56AFD400CB9116 /* NightscoutUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CEE6E51E56AFD400CB9116 /* NightscoutUploader.swift */; }; 43D2E8231F00425400AE5CBF /* BolusViewController+LoopDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D2E8221F00425400AE5CBF /* BolusViewController+LoopDataManager.swift */; }; 43D381621EBD9759007F8C8F /* HeaderValuesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D381611EBD9759007F8C8F /* HeaderValuesTableViewCell.swift */; }; - 43D848B01E7DCBE100DADCBC /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D848AF1E7DCBE100DADCBC /* Result.swift */; }; + 43D9000B21EB0BE000AF44BF /* LoopCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; }; + 43D9001E21EB209400AF44BF /* LoopCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D9FFD121EAE05D00AF44BF /* LoopCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43D9002021EB209400AF44BF /* NSTimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439897341CD2F7DE00223065 /* NSTimeInterval.swift */; }; + 43D9002121EB209400AF44BF /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; + 43D9002221EB209400AF44BF /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298C2041F56500BA9F93 /* LoopSettings.swift */; }; + 43D9002D21EB225D00AF44BF /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9002C21EB225D00AF44BF /* HealthKit.framework */; }; + 43D9002E21EB226F00AF44BF /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4344628320A7A3BE00C4BE6F /* LoopKit.framework */; }; + 43D9002F21EB234400AF44BF /* LoopCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9002A21EB209400AF44BF /* LoopCore.framework */; }; + 43D9003321EB258C00AF44BF /* InsulinModelSettings+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9003221EB258C00AF44BF /* InsulinModelSettings+Loop.swift */; }; + 43D9F81821EC51CC000578CD /* DateEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9F81721EC51CC000578CD /* DateEntry.swift */; }; + 43D9F81A21EC593C000578CD /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9F81921EC593C000578CD /* UITableViewCell.swift */; }; + 43D9F81E21EF0609000578CD /* NumberRangeEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9F81D21EF0609000578CD /* NumberRangeEntry.swift */; }; + 43D9F82021EF0906000578CD /* NSNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9F81F21EF0906000578CD /* NSNumber.swift */; }; + 43D9F82221EF0A7A000578CD /* QuantityRangeEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9F82121EF0A7A000578CD /* QuantityRangeEntry.swift */; }; + 43D9F82421EFF1AB000578CD /* LessonResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9F82321EFF1AB000578CD /* LessonResultsViewController.swift */; }; + 43D9FFA521EA9A0C00AF44BF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9FFA421EA9A0C00AF44BF /* AppDelegate.swift */; }; + 43D9FFAA21EA9A0C00AF44BF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43D9FFA821EA9A0C00AF44BF /* Main.storyboard */; }; + 43D9FFAC21EA9A0F00AF44BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43D9FFAB21EA9A0F00AF44BF /* Assets.xcassets */; }; + 43D9FFAF21EA9A0F00AF44BF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43D9FFAD21EA9A0F00AF44BF /* LaunchScreen.storyboard */; }; + 43D9FFB421EA9AD800AF44BF /* LoopUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F75288B1DFE1DC600C322D6 /* LoopUI.framework */; }; + 43D9FFB621EA9B2F00AF44BF /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F5C2C81B929C09003EB13D /* HealthKit.framework */; }; + 43D9FFBB21EA9CC900AF44BF /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D4B1C914197002152D1 /* LoopKit.framework */; }; + 43D9FFBC21EA9CCD00AF44BF /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 437AFEE6203688CF008C4892 /* LoopKitUI.framework */; }; + 43D9FFBD21EA9CD700AF44BF /* SwiftCharts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4346D1EF1C781BEA00ABAFE3 /* SwiftCharts.framework */; }; + 43D9FFC021EAB22E00AF44BF /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D9FFBF21EAB22E00AF44BF /* DataManager.swift */; }; + 43D9FFD321EAE05D00AF44BF /* LoopCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D9FFD121EAE05D00AF44BF /* LoopCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43D9FFD621EAE05D00AF44BF /* LoopCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; }; + 43D9FFD721EAE05D00AF44BF /* LoopCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 43D9FFDE21EAE3AE00AF44BF /* LoopCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; }; + 43D9FFE021EAE3E500AF44BF /* LoopUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4F75288B1DFE1DC600C322D6 /* LoopUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 43D9FFE121EAE3E500AF44BF /* LoopCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 43D9FFF521EAF27200AF44BF /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298C2041F56500BA9F93 /* LoopSettings.swift */; }; + 43D9FFF821EAF2EF00AF44BF /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D4B1C914197002152D1 /* LoopKit.framework */; }; + 43D9FFF921EAF34800AF44BF /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; + 43D9FFFA21EAF35900AF44BF /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F5C2C81B929C09003EB13D /* HealthKit.framework */; }; + 43D9FFFB21EAF3D300AF44BF /* NSTimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439897341CD2F7DE00223065 /* NSTimeInterval.swift */; }; 43DAD00020A2736F000F8529 /* PersistedPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DACFFF20A2736F000F8529 /* PersistedPumpEvent.swift */; }; 43DBF04C1C93B8D700B3C386 /* BolusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DBF04B1C93B8D700B3C386 /* BolusViewController.swift */; }; 43DBF0531C93EC8200B3C386 /* DeviceDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DBF0521C93EC8200B3C386 /* DeviceDataManager.swift */; }; @@ -225,7 +271,6 @@ 4F2C15971E09E94E00E160D4 /* HUDAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4F2C15961E09E94E00E160D4 /* HUDAssets.xcassets */; }; 4F2C159A1E0C9E5600E160D4 /* LoopUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4F75288B1DFE1DC600C322D6 /* LoopUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4F526D611DF8D9A900A04910 /* NetBasal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F526D601DF8D9A900A04910 /* NetBasal.swift */; }; - 4F526D621DF9D95200A04910 /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; 4F6663941E905FD2009E74FC /* ChartColorPalette+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6663931E905FD2009E74FC /* ChartColorPalette+Loop.swift */; }; 4F70C1E11DE8DCA7006380B7 /* StatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F70C1E01DE8DCA7006380B7 /* StatusViewController.swift */; }; 4F70C1E41DE8DCA7006380B7 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4F70C1E21DE8DCA7006380B7 /* MainInterface.storyboard */; }; @@ -264,9 +309,7 @@ 4FC8C8011DEB93E400A1452E /* NSUserDefaults+StatusExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FC8C8001DEB93E400A1452E /* NSUserDefaults+StatusExtension.swift */; }; 4FC8C8021DEB943800A1452E /* NSUserDefaults+StatusExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FC8C8001DEB93E400A1452E /* NSUserDefaults+StatusExtension.swift */; }; 4FDDD23720DC51DF00D04B16 /* LoopDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FDDD23620DC51DF00D04B16 /* LoopDataManager.swift */; }; - 4FF0F75E20E1E5D100FC6291 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431E73471FF95A900069B5F7 /* PersistenceController.swift */; }; 4FF4D0F81E1725B000846527 /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434F54561D287FDB002A9274 /* NibLoadable.swift */; }; - 4FF4D0F91E17268800846527 /* IdentifiableClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434FF1E91CF26C29000DB779 /* IdentifiableClass.swift */; }; 4FF4D1001E18374700846527 /* WatchContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FF4D0FF1E18374700846527 /* WatchContext.swift */; }; 4FF4D1011E18375000846527 /* WatchContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FF4D0FF1E18374700846527 /* WatchContext.swift */; }; 7D23667D21250C7E0028B67D /* LocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D23667C21250C7E0028B67D /* LocalizedString.swift */; }; @@ -347,6 +390,62 @@ remoteGlobalIDString = 43A943711B926B7B0051FA24; remoteInfo = WatchApp; }; + 43D9000C21EB0BEA00AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 43D9FFCE21EAE05D00AF44BF; + remoteInfo = LoopCore; + }; + 43D9001221EB137A00AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 43D9FFCE21EAE05D00AF44BF; + remoteInfo = LoopCore; + }; + 43D9001821EB207300AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 432CF87720D8B8380066B889; + remoteInfo = Cartfile; + }; + 43D9001C21EB209400AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 432CF87720D8B8380066B889; + remoteInfo = Cartfile; + }; + 43D9003021EB236800AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 43D9001A21EB209400AF44BF; + remoteInfo = "LoopCore-watchOS"; + }; + 43D9FFB721EA9C9F00AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 432CF87720D8B8380066B889; + remoteInfo = Cartfile; + }; + 43D9FFB921EA9CA400AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4F75288A1DFE1DC600C322D6; + remoteInfo = LoopUI; + }; + 43D9FFD421EAE05D00AF44BF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 43776F841B8022E90074EA36 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 43D9FFCE21EAE05D00AF44BF; + remoteInfo = LoopCore; + }; 43E2D9101D20C581004DA55F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 43776F841B8022E90074EA36 /* Project object */; @@ -407,6 +506,7 @@ dstSubfolderSpec = 10; files = ( 4F2C159A1E0C9E5600E160D4 /* LoopUI.framework in Embed Frameworks */, + 43D9FFD721EAE05D00AF44BF /* LoopCore.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -417,6 +517,19 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 43C05CB221EBD88A006FB252 /* LoopCore.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FFDF21EAE3C600AF44BF /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 43D9FFE021EAE3E500AF44BF /* LoopUI.framework in Embed Frameworks */, + 43D9FFE121EAE3E500AF44BF /* LoopCore.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -428,6 +541,7 @@ dstSubfolderSpec = 10; files = ( 43E2D9171D2226BD004DA55F /* LoopKit.framework in CopyFiles */, + 4345E40021F051DD009E00E5 /* LoopCore.framework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -484,6 +598,9 @@ 4344628420A7A3BE00C4BE6F /* CGMBLEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CGMBLEKit.framework; path = Carthage/Build/watchOS/CGMBLEKit.framework; sourceTree = ""; }; 4344628D20A7ADD100C4BE6F /* UserDefaults+CGM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+CGM.swift"; sourceTree = ""; }; 4344629120A7C19800C4BE6F /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = ""; }; + 4345E3F721F03D2A009E00E5 /* DatesAndNumberCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatesAndNumberCell.swift; sourceTree = ""; }; + 4345E3F921F0473B009E00E5 /* TextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextCell.swift; sourceTree = ""; }; + 4345E3FD21F04A50009E00E5 /* DateIntervalFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateIntervalFormatter.swift; sourceTree = ""; }; 4346D1E61C77F5FE00ABAFE3 /* ChartTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ChartTableViewCell.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 4346D1EF1C781BEA00ABAFE3 /* SwiftCharts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCharts.framework; path = Carthage/Build/iOS/SwiftCharts.framework; sourceTree = SOURCE_ROOT; }; 434AB0B11CBB4C3300422F4A /* RileyLinkBLEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RileyLinkBLEKit.framework; path = Carthage/Build/iOS/RileyLinkBLEKit.framework; sourceTree = SOURCE_ROOT; }; @@ -565,6 +682,13 @@ 43BFF0BE1E45C8EA00FF19A9 /* UIColor+Widget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Widget.swift"; sourceTree = ""; }; 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+HIG.swift"; sourceTree = ""; }; 43BFF0CC1E466C8400FF19A9 /* StateColorPalette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateColorPalette.swift; sourceTree = ""; }; + 43C05CB021EBBDB9006FB252 /* TimeInRangeLesson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeInRangeLesson.swift; sourceTree = ""; }; + 43C05CB421EBE274006FB252 /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; + 43C05CB721EBEA54006FB252 /* HKUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; }; + 43C05CBC21EBF77D006FB252 /* LessonsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonsViewController.swift; sourceTree = ""; }; + 43C05CBF21EBFFA4006FB252 /* Lesson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lesson.swift; sourceTree = ""; }; + 43C05CC121EC06E4006FB252 /* LessonConfigurationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonConfigurationViewController.swift; sourceTree = ""; }; + 43C05CC921EC382B006FB252 /* NumberEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberEntry.swift; sourceTree = ""; }; 43C094491CACCC73001F6403 /* NotificationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = ""; }; 43C246A71D89990F0031F8D1 /* Crypto.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crypto.framework; path = Carthage/Build/iOS/Crypto.framework; sourceTree = SOURCE_ROOT; }; 43C2FAE01EB656A500364AFF /* GlucoseEffectVelocity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEffectVelocity.swift; sourceTree = ""; }; @@ -580,6 +704,26 @@ 43D381611EBD9759007F8C8F /* HeaderValuesTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderValuesTableViewCell.swift; sourceTree = ""; }; 43D533BB1CFD1DD7009E3085 /* WatchApp Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "WatchApp Extension.entitlements"; sourceTree = ""; }; 43D848AF1E7DCBE100DADCBC /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; + 43D9002A21EB209400AF44BF /* LoopCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LoopCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43D9002C21EB225D00AF44BF /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS5.1.sdk/System/Library/Frameworks/HealthKit.framework; sourceTree = DEVELOPER_DIR; }; + 43D9003221EB258C00AF44BF /* InsulinModelSettings+Loop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InsulinModelSettings+Loop.swift"; sourceTree = ""; }; + 43D9F81721EC51CC000578CD /* DateEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateEntry.swift; sourceTree = ""; }; + 43D9F81921EC593C000578CD /* UITableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = ""; }; + 43D9F81D21EF0609000578CD /* NumberRangeEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberRangeEntry.swift; sourceTree = ""; }; + 43D9F81F21EF0906000578CD /* NSNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSNumber.swift; sourceTree = ""; }; + 43D9F82121EF0A7A000578CD /* QuantityRangeEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantityRangeEntry.swift; sourceTree = ""; }; + 43D9F82321EFF1AB000578CD /* LessonResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonResultsViewController.swift; sourceTree = ""; }; + 43D9FFA221EA9A0C00AF44BF /* Learn.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Learn.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 43D9FFA421EA9A0C00AF44BF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 43D9FFA921EA9A0C00AF44BF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 43D9FFAB21EA9A0F00AF44BF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 43D9FFAE21EA9A0F00AF44BF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 43D9FFB021EA9A0F00AF44BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 43D9FFB521EA9B0100AF44BF /* Learn.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Learn.entitlements; sourceTree = ""; }; + 43D9FFBF21EAB22E00AF44BF /* DataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = ""; }; + 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LoopCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43D9FFD121EAE05D00AF44BF /* LoopCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoopCore.h; sourceTree = ""; }; + 43D9FFD221EAE05D00AF44BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43DACFFF20A2736F000F8529 /* PersistedPumpEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistedPumpEvent.swift; sourceTree = ""; }; 43DBF04B1C93B8D700B3C386 /* BolusViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BolusViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 43DBF0521C93EC8200B3C386 /* DeviceDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DeviceDataManager.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -857,6 +1001,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 43D9FFD621EAE05D00AF44BF /* LoopCore.framework in Frameworks */, 4F7528941DFE1E9500C322D6 /* LoopUI.framework in Frameworks */, 434FB6461D68F1CD007B9C70 /* Amplitude.framework in Frameworks */, 43A8EC6F210E622700A81379 /* CGMBLEKitUI.framework in Frameworks */, @@ -886,6 +1031,38 @@ 4344628020A7A37400C4BE6F /* HealthKit.framework in Frameworks */, 4344628520A7A3BE00C4BE6F /* LoopKit.framework in Frameworks */, 4344628620A7A3BE00C4BE6F /* CGMBLEKit.framework in Frameworks */, + 43D9002F21EB234400AF44BF /* LoopCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9002321EB209400AF44BF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43D9002D21EB225D00AF44BF /* HealthKit.framework in Frameworks */, + 43D9002E21EB226F00AF44BF /* LoopKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FF9F21EA9A0C00AF44BF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43D9FFDE21EAE3AE00AF44BF /* LoopCore.framework in Frameworks */, + 43D9FFBD21EA9CD700AF44BF /* SwiftCharts.framework in Frameworks */, + 43D9FFB421EA9AD800AF44BF /* LoopUI.framework in Frameworks */, + 43D9FFBB21EA9CC900AF44BF /* LoopKit.framework in Frameworks */, + 43D9FFB621EA9B2F00AF44BF /* HealthKit.framework in Frameworks */, + 43D9FFBC21EA9CCD00AF44BF /* LoopKitUI.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FFCC21EAE05D00AF44BF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43D9FFFA21EAF35900AF44BF /* HealthKit.framework in Frameworks */, + 43D9FFF821EAF2EF00AF44BF /* LoopKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -893,6 +1070,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4345E3FF21F051C6009E00E5 /* LoopCore.framework in Frameworks */, 43E2D9191D222759004DA55F /* LoopKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -910,6 +1088,7 @@ files = ( C168C40621B0D53E00ADE90E /* MinimedKit.framework in Frameworks */, C168C40821B0D53E00ADE90E /* MinimedKitUI.framework in Frameworks */, + 43D9000B21EB0BE000AF44BF /* LoopCore.framework in Frameworks */, 4F7528951DFE1E9B00C322D6 /* LoopUI.framework in Frameworks */, 437AFEE520352591008C4892 /* NotificationCenter.framework in Frameworks */, ); @@ -921,6 +1100,7 @@ files = ( 437AFEE8203689FE008C4892 /* LoopKit.framework in Frameworks */, 4FB76FB01E8C3E8000B39636 /* SwiftCharts.framework in Frameworks */, + 43C05CBA21EBEAD8006FB252 /* LoopCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -963,14 +1143,13 @@ path = Extensions; sourceTree = ""; }; - 43673E2E1F37BDA10058AC7C /* Insulin */ = { + 4345E3F621F03C2E009E00E5 /* Display */ = { isa = PBXGroup; children = ( - 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */, - 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */, - 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */, + 4345E3F721F03D2A009E00E5 /* DatesAndNumberCell.swift */, + 4345E3F921F0473B009E00E5 /* TextCell.swift */, ); - path = Insulin; + path = Display; sourceTree = ""; }; 43757D131C06F26C00910CB9 /* Models */ = { @@ -980,12 +1159,10 @@ 43DE92601C555C26001FFDE1 /* AbsorptionTimeType+CarbKit.swift */, C17824A41E1AD4D100D9D25C /* BolusRecommendation.swift */, 43C2FAE01EB656A500364AFF /* GlucoseEffectVelocity.swift */, - 4374B5F1209D897600D17AA8 /* Locked.swift */, 436A0DA41D236A2A00104B24 /* LoopError.swift */, 430B29942041F5CB00BA9F93 /* LoopSettings+Loop.swift */, 4F526D601DF8D9A900A04910 /* NetBasal.swift */, 438D42F81D7C88BC003244B0 /* PredictionInputEffect.swift */, - 43D848AF1E7DCBE100DADCBC /* Result.swift */, 43441A9B1EDB34810087958C /* StatusExtensionContext+LoopKit.swift */, 4328E0311CFC068900E199AA /* WatchContext+LoopKit.swift */, ); @@ -998,11 +1175,13 @@ 4FF4D0FA1E1834BD00846527 /* Common */, 43776F8E1B8022E90074EA36 /* Loop */, 4F70C1DF1DE8DCA7006380B7 /* Loop Status Extension */, + 43D9FFD021EAE05D00AF44BF /* LoopCore */, 4F75288C1DFE1DC600C322D6 /* LoopUI */, 43A943731B926B7B0051FA24 /* WatchApp */, 43A943821B926B7B0051FA24 /* WatchApp Extension */, 43F78D2C1C8FC58F002152D1 /* LoopTests */, 43E2D8D21D20BF42004DA55F /* DoseMathTests */, + 43D9FFA321EA9A0C00AF44BF /* Learn */, 968DCD53F724DE56FFE51920 /* Frameworks */, 43776F8D1B8022E90074EA36 /* Products */, 437D9BA11D7B5203007245E8 /* Loop.xcconfig */, @@ -1019,6 +1198,9 @@ 43E2D90B1D20C581004DA55F /* LoopTests.xctest */, 4F70C1DC1DE8DCA7006380B7 /* Loop Status Extension.appex */, 4F75288B1DFE1DC600C322D6 /* LoopUI.framework */, + 43D9FFA221EA9A0C00AF44BF /* Learn.app */, + 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */, + 43D9002A21EB209400AF44BF /* LoopCore.framework */, ); name = Products; sourceTree = ""; @@ -1079,8 +1261,8 @@ 4328E0121CFBE1B700E199AA /* Controllers */, 4328E01F1CFBE2B100E199AA /* Extensions */, 4FE3475F20D5D7FA00A86D03 /* Managers */, - 4F75F0052100146B00B5570E /* Scenes */, 898ECA5D218ABD17001E9D35 /* Models */, + 4F75F0052100146B00B5570E /* Scenes */, 43A943831B926B7B0051FA24 /* Supporting Files */, ); path = "WatchApp Extension"; @@ -1094,6 +1276,102 @@ name = "Supporting Files"; sourceTree = ""; }; + 43C05CB321EBE268006FB252 /* Extensions */ = { + isa = PBXGroup; + children = ( + 43C05CB421EBE274006FB252 /* Date.swift */, + 4345E3FD21F04A50009E00E5 /* DateIntervalFormatter.swift */, + 43D9F81F21EF0906000578CD /* NSNumber.swift */, + 43D9F81921EC593C000578CD /* UITableViewCell.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 43C05CBB21EBF743006FB252 /* View Controllers */ = { + isa = PBXGroup; + children = ( + 43C05CC121EC06E4006FB252 /* LessonConfigurationViewController.swift */, + 43D9F82321EFF1AB000578CD /* LessonResultsViewController.swift */, + 43C05CBC21EBF77D006FB252 /* LessonsViewController.swift */, + ); + path = "View Controllers"; + sourceTree = ""; + }; + 43C05CBE21EBFF66006FB252 /* Lessons */ = { + isa = PBXGroup; + children = ( + 43C05CB021EBBDB9006FB252 /* TimeInRangeLesson.swift */, + ); + path = Lessons; + sourceTree = ""; + }; + 43C05CC321EC0868006FB252 /* Configuration */ = { + isa = PBXGroup; + children = ( + 43D9F81721EC51CC000578CD /* DateEntry.swift */, + 43C05CC921EC382B006FB252 /* NumberEntry.swift */, + 43D9F81D21EF0609000578CD /* NumberRangeEntry.swift */, + 43D9F82121EF0A7A000578CD /* QuantityRangeEntry.swift */, + ); + path = Configuration; + sourceTree = ""; + }; + 43D9003A21EB281300AF44BF /* Insulin */ = { + isa = PBXGroup; + children = ( + 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */, + 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */, + 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */, + ); + path = Insulin; + sourceTree = ""; + }; + 43D9FFA321EA9A0C00AF44BF /* Learn */ = { + isa = PBXGroup; + children = ( + 43D9FFA421EA9A0C00AF44BF /* AppDelegate.swift */, + 43C05CBF21EBFFA4006FB252 /* Lesson.swift */, + 43C05CC321EC0868006FB252 /* Configuration */, + 4345E3F621F03C2E009E00E5 /* Display */, + 43C05CB321EBE268006FB252 /* Extensions */, + 43C05CBE21EBFF66006FB252 /* Lessons */, + 43D9FFBE21EAB20B00AF44BF /* Managers */, + 43C05CBB21EBF743006FB252 /* View Controllers */, + 43D9FFB521EA9B0100AF44BF /* Learn.entitlements */, + 43D9FFA821EA9A0C00AF44BF /* Main.storyboard */, + 43D9FFAB21EA9A0F00AF44BF /* Assets.xcassets */, + 43D9FFAD21EA9A0F00AF44BF /* LaunchScreen.storyboard */, + 43D9FFB021EA9A0F00AF44BF /* Info.plist */, + ); + path = Learn; + sourceTree = ""; + }; + 43D9FFBE21EAB20B00AF44BF /* Managers */ = { + isa = PBXGroup; + children = ( + 43D9FFBF21EAB22E00AF44BF /* DataManager.swift */, + ); + path = Managers; + sourceTree = ""; + }; + 43D9FFD021EAE05D00AF44BF /* LoopCore */ = { + isa = PBXGroup; + children = ( + 43D9003A21EB281300AF44BF /* Insulin */, + 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */, + 43C05CB721EBEA54006FB252 /* HKUnit.swift */, + 434FF1E91CF26C29000DB779 /* IdentifiableClass.swift */, + 4374B5F1209D897600D17AA8 /* Locked.swift */, + 430B298C2041F56500BA9F93 /* LoopSettings.swift */, + 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */, + 431E73471FF95A900069B5F7 /* PersistenceController.swift */, + 43D848AF1E7DCBE100DADCBC /* Result.swift */, + 43D9FFD121EAE05D00AF44BF /* LoopCore.h */, + 43D9FFD221EAE05D00AF44BF /* Info.plist */, + ); + path = LoopCore; + sourceTree = ""; + }; 43E2D8D21D20BF42004DA55F /* DoseMathTests */ = { isa = PBXGroup; children = ( @@ -1137,6 +1415,7 @@ 4389916A1E91B689000EEF90 /* ChartSettings+Loop.swift */, 4F08DE8E1E7BB871006741EA /* CollectionType+Loop.swift */, 43CE7CDD1CA8B63E003CC1B0 /* Data.swift */, + 43D9003221EB258C00AF44BF /* InsulinModelSettings+Loop.swift */, C15713811DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift */, 438172D81F4E9E37003C3328 /* NewPumpEvent.swift */, 43CEE6E51E56AFD400CB9116 /* NightscoutUploader.swift */, @@ -1183,7 +1462,6 @@ 430D85881F44037000AF2D4F /* HUDViewTableViewCell.swift */, 438D42FA1D7D11A4003244B0 /* PredictionInputEffectTableViewCell.swift */, 43C3B6EB20B650A80026CAFA /* SettingsImageTableViewCell.swift */, - 4374B5F3209D89A900D17AA8 /* TextFieldTableViewCell.swift */, 43F64DD81D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift */, 4311FB9A1F37FE1B00D4C0A7 /* TitleSubtitleTextFieldTableViewCell.swift */, ); @@ -1305,6 +1583,7 @@ 4F08DE801E7BB6F1006741EA /* CGPoint.swift */, 438991661E91B563000EEF90 /* ChartPoint.swift */, 43649A621C7A347F00523D7F /* CollectionType.swift */, + 434F54561D287FDB002A9274 /* NibLoadable.swift */, ); path = Extensions; sourceTree = ""; @@ -1331,12 +1610,9 @@ 4FF4D0FB1E1834C400846527 /* Models */ = { isa = PBXGroup; children = ( - 43673E2E1F37BDA10058AC7C /* Insulin */, 435400301C9F744E00D5819C /* BolusSuggestionUserInfo.swift */, 43DE92581C5479E4001FFDE1 /* CarbEntryUserInfo.swift */, 4F11D3BF20DCBEEC006E072C /* GlucoseBackfillRequestUserInfo.swift */, - 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */, - 430B298C2041F56500BA9F93 /* LoopSettings.swift */, 4372E48F213CFCE70068E043 /* LoopSettingsUserInfo.swift */, 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */, 4F70C2111DE900EA006380B7 /* StatusExtensionContext.swift */, @@ -1355,18 +1631,15 @@ 4372E48A213CB5F00068E043 /* Double.swift */, 4F526D5E1DF2459000A04910 /* HKUnit.swift */, 43C513181E864C4E001547C7 /* GlucoseRangeSchedule.swift */, - 434FF1E91CF26C29000DB779 /* IdentifiableClass.swift */, 43785E922120A01B0057DED1 /* NewCarbEntryIntent+Loop.swift */, - 434F54561D287FDB002A9274 /* NibLoadable.swift */, 430DA58D1D4AEC230097D1CA /* NSBundle.swift */, 439897341CD2F7DE00223065 /* NSTimeInterval.swift */, 439A7943211FE22F0041B75F /* NSUserActivity.swift */, - 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */, 4FC8C8001DEB93E400A1452E /* NSUserDefaults+StatusExtension.swift */, 43BFF0B31E45C1BE00FF19A9 /* NumberFormatter.swift */, 4374B5EE209D84BE00D17AA8 /* OSLog.swift */, - 431E73471FF95A900069B5F7 /* PersistenceController.swift */, 4372E486213C86240068E043 /* SampleValue.swift */, + 4374B5F3209D89A900D17AA8 /* TextFieldTableViewCell.swift */, 43BFF0B11E45C18400FF19A9 /* UIColor.swift */, 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */, 4344628D20A7ADD100C4BE6F /* UserDefaults+CGM.swift */, @@ -1404,6 +1677,7 @@ 4344628120A7A37E00C4BE6F /* CoreBluetooth.framework */, 43C246A71D89990F0031F8D1 /* Crypto.framework */, 4D3B40021D4A9DFE00BC6334 /* G4ShareSpy.framework */, + 43D9002C21EB225D00AF44BF /* HealthKit.framework */, 4344627F20A7A37400C4BE6F /* HealthKit.framework */, 43F5C2C81B929C09003EB13D /* HealthKit.framework */, 4344628320A7A3BE00C4BE6F /* LoopKit.framework */, @@ -1426,6 +1700,22 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 43D9001D21EB209400AF44BF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 43D9001E21EB209400AF44BF /* LoopCore.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FFCA21EAE05D00AF44BF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 43D9FFD321EAE05D00AF44BF /* LoopCore.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4F7528881DFE1DC600C322D6 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1456,6 +1746,7 @@ 4F7528971DFE1ED400C322D6 /* PBXTargetDependency */, 43A943931B926B7B0051FA24 /* PBXTargetDependency */, 4F70C1E71DE8DCA7006380B7 /* PBXTargetDependency */, + 43D9FFD521EAE05D00AF44BF /* PBXTargetDependency */, ); name = Loop; productName = Loop; @@ -1494,12 +1785,72 @@ ); dependencies = ( 432CF88120D8BC460066B889 /* PBXTargetDependency */, + 43D9003121EB236800AF44BF /* PBXTargetDependency */, ); name = "WatchApp Extension"; productName = "WatchApp Extension"; productReference = 43A9437E1B926B7B0051FA24 /* WatchApp Extension.appex */; productType = "com.apple.product-type.watchkit2-extension"; }; + 43D9001A21EB209400AF44BF /* LoopCore-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43D9002721EB209400AF44BF /* Build configuration list for PBXNativeTarget "LoopCore-watchOS" */; + buildPhases = ( + 43D9001D21EB209400AF44BF /* Headers */, + 43D9001F21EB209400AF44BF /* Sources */, + 43D9002321EB209400AF44BF /* Frameworks */, + 43D9002621EB209400AF44BF /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 43D9001B21EB209400AF44BF /* PBXTargetDependency */, + ); + name = "LoopCore-watchOS"; + productName = LoopCore; + productReference = 43D9002A21EB209400AF44BF /* LoopCore.framework */; + productType = "com.apple.product-type.framework"; + }; + 43D9FFA121EA9A0C00AF44BF /* Learn */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43D9FFB321EA9A0F00AF44BF /* Build configuration list for PBXNativeTarget "Learn" */; + buildPhases = ( + 43D9FF9E21EA9A0C00AF44BF /* Sources */, + 43D9FF9F21EA9A0C00AF44BF /* Frameworks */, + 43D9FFA021EA9A0C00AF44BF /* Resources */, + 43D9FFDF21EAE3C600AF44BF /* Embed Frameworks */, + 43D9FFE221EAE40600AF44BF /* Copy Frameworks with Carthage */, + ); + buildRules = ( + ); + dependencies = ( + 43D9FFB821EA9C9F00AF44BF /* PBXTargetDependency */, + 43D9FFBA21EA9CA400AF44BF /* PBXTargetDependency */, + ); + name = Learn; + productName = Learn; + productReference = 43D9FFA221EA9A0C00AF44BF /* Learn.app */; + productType = "com.apple.product-type.application"; + }; + 43D9FFCE21EAE05D00AF44BF /* LoopCore */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43D9FFD821EAE05D00AF44BF /* Build configuration list for PBXNativeTarget "LoopCore" */; + buildPhases = ( + 43D9FFCA21EAE05D00AF44BF /* Headers */, + 43D9FFCB21EAE05D00AF44BF /* Sources */, + 43D9FFCC21EAE05D00AF44BF /* Frameworks */, + 43D9FFCD21EAE05D00AF44BF /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 43D9001921EB207300AF44BF /* PBXTargetDependency */, + ); + name = LoopCore; + productName = LoopCore; + productReference = 43D9FFCF21EAE05D00AF44BF /* LoopCore.framework */; + productType = "com.apple.product-type.framework"; + }; 43E2D8D01D20BF42004DA55F /* DoseMathTests */ = { isa = PBXNativeTarget; buildConfigurationList = 43E2D8D61D20BF42004DA55F /* Build configuration list for PBXNativeTarget "DoseMathTests" */; @@ -1547,6 +1898,7 @@ buildRules = ( ); dependencies = ( + 43D9000D21EB0BEA00AF44BF /* PBXTargetDependency */, 4F7528991DFE1ED800C322D6 /* PBXTargetDependency */, ); name = "Loop Status Extension"; @@ -1567,6 +1919,7 @@ ); dependencies = ( 432CF87F20D8BC3B0066B889 /* PBXTargetDependency */, + 43D9001321EB137A00AF44BF /* PBXTargetDependency */, ); name = LoopUI; productName = LoopUI; @@ -1579,8 +1932,8 @@ 43776F841B8022E90074EA36 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0940; + LastSwiftUpdateCheck = 1010; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "LoopKit Authors"; TargetAttributes = { 432CF87720D8B8380066B889 = { @@ -1641,6 +1994,25 @@ }; }; }; + 43D9001A21EB209400AF44BF = { + ProvisioningStyle = Automatic; + }; + 43D9FFA121EA9A0C00AF44BF = { + CreatedOnToolsVersion = 10.1; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + com.apple.HealthKit = { + enabled = 1; + }; + }; + }; + 43D9FFCE21EAE05D00AF44BF = { + CreatedOnToolsVersion = 10.1; + ProvisioningStyle = Automatic; + }; 43E2D8D01D20BF42004DA55F = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 0800; @@ -1690,6 +2062,9 @@ 4F70C1DB1DE8DCA7006380B7 /* Loop Status Extension */, 43A943711B926B7B0051FA24 /* WatchApp */, 43A9437D1B926B7B0051FA24 /* WatchApp Extension */, + 43D9FFA121EA9A0C00AF44BF /* Learn */, + 43D9FFCE21EAE05D00AF44BF /* LoopCore */, + 43D9001A21EB209400AF44BF /* LoopCore-watchOS */, 4F75288A1DFE1DC600C322D6 /* LoopUI */, 43E2D8D01D20BF42004DA55F /* DoseMathTests */, 43E2D90A1D20C581004DA55F /* LoopTests */, @@ -1732,6 +2107,30 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 43D9002621EB209400AF44BF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FFA021EA9A0C00AF44BF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43D9FFAF21EA9A0F00AF44BF /* LaunchScreen.storyboard in Resources */, + 43D9FFAC21EA9A0F00AF44BF /* Assets.xcassets in Resources */, + 43D9FFAA21EA9A0C00AF44BF /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FFCD21EAE05D00AF44BF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 43E2D8CF1D20BF42004DA55F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1817,6 +2216,27 @@ shellPath = /bin/sh; shellScript = "if ! [ -x \"$(command -v brew)\" ]; then\n # Install Homebrew\n ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\"\nfi\n\nif brew ls carthage > /dev/null; then\n brew upgrade carthage || echo \"Continuing…\"\nelse\n brew install carthage\nfi\n"; }; + 43D9FFE221EAE40600AF44BF /* Copy Frameworks with Carthage */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/LoopKit.framework", + "$(SRCROOT)/Carthage/Build/iOS/LoopKitUI.framework", + "$(SRCROOT)/Carthage/Build/iOS/SwiftCharts.framework", + ); + name = "Copy Frameworks with Carthage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "carthage_frameworks_dir=${SRCROOT}/Carthage/Build/iOS\nif [ -f $PROJECT_DIR/.gitmodules && [ $ACTION != \"install\" ]; then\nfor varname in ${!SCRIPT_INPUT_FILE_*}\ndo\nexport ${varname}=${!varname/$carthage_frameworks_dir/$BUILT_PRODUCTS_DIR}\ndone\nfi\n/usr/local/bin/carthage copy-frameworks\n"; + }; 43EDDBEF1C361BCE007D89B5 /* Copy Frameworks with Carthage */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1865,7 +2285,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "carthage_frameworks_dir=${SRCROOT}/Carthage/Build/iOS\nif [ -f $PROJECT_DIR/.gitmodules ] && [ $ACTION != \"install\" ]; then\nfor varname in ${!SCRIPT_INPUT_FILE_*}\ndo\nexport ${varname}=${!varname/$carthage_frameworks_dir/$BUILT_PRODUCTS_DIR}\ndone\nfi\n/usr/local/bin/carthage copy-frameworks\n"; + shellScript = "carthage_frameworks_dir=${SRCROOT}/Carthage/Build/watchOS\nif [ -f $PROJECT_DIR/.gitmodules && [ $ACTION != \"install\" ]; then\nfor varname in ${!SCRIPT_INPUT_FILE_*}\ndo\nexport ${varname}=${!varname/$carthage_frameworks_dir/$BUILT_PRODUCTS_DIR}\ndone\nfi\n/usr/local/bin/carthage copy-frameworks\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -1876,14 +2296,12 @@ files = ( C17824A51E1AD4D100D9D25C /* BolusRecommendation.swift in Sources */, 4F70C2131DE90339006380B7 /* StatusExtensionContext.swift in Sources */, - 434F54571D287FDB002A9274 /* NibLoadable.swift in Sources */, 43441A9C1EDB34810087958C /* StatusExtensionContext+LoopKit.swift in Sources */, + 43C05CC521EC29E3006FB252 /* TextFieldTableViewCell.swift in Sources */, 4FF4D1001E18374700846527 /* WatchContext.swift in Sources */, - 430B298A2041F54A00BA9F93 /* NSUserDefaults.swift in Sources */, 4315D28A1CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift in Sources */, 4F2C15821E074FC600E160D4 /* NSTimeInterval.swift in Sources */, 4311FB9B1F37FE1B00D4C0A7 /* TitleSubtitleTextFieldTableViewCell.swift in Sources */, - 430DA58E1D4AEC230097D1CA /* NSBundle.swift in Sources */, C1FB428F217921D600FAB378 /* PumpManagerUI.swift in Sources */, 43C513191E864C4E001547C7 /* GlucoseRangeSchedule.swift in Sources */, 43A51E1F1EB6D62A000736CC /* CarbAbsorptionViewController.swift in Sources */, @@ -1895,29 +2313,26 @@ 439A7942211F631C0041B75F /* RootNavigationController.swift in Sources */, 4F11D3C020DCBEEC006E072C /* GlucoseBackfillRequestUserInfo.swift in Sources */, 43F5C2DB1B92A5E1003EB13D /* SettingsTableViewController.swift in Sources */, - 434FF1EA1CF26C29000DB779 /* IdentifiableClass.swift in Sources */, 43A567691C94880B00334FAC /* LoopDataManager.swift in Sources */, - 43D848B01E7DCBE100DADCBC /* Result.swift in Sources */, 43B260491ED248FB008CAA77 /* CarbEntryTableViewCell.swift in Sources */, 4302F4E11D4E9C8900F0FCAF /* TextFieldTableViewController.swift in Sources */, - 435CB6271F37AE5600C320C7 /* WalshInsulinModel.swift in Sources */, 43F64DD91D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift in Sources */, C15713821DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift in Sources */, 435400321C9F745500D5819C /* BolusSuggestionUserInfo.swift in Sources */, 43E3449F1B9D68E900C85C07 /* StatusTableViewController.swift in Sources */, 43DBF0531C93EC8200B3C386 /* DeviceDataManager.swift in Sources */, 43E2D8C81D208D5B004DA55F /* KeychainManager+Loop.swift in Sources */, - 430B298F2041F56500BA9F93 /* GlucoseThreshold.swift in Sources */, C17824A01E19CF9800D9D25C /* GlucoseThresholdTableViewController.swift in Sources */, - 435CB6251F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift in Sources */, 4372E487213C86240068E043 /* SampleValue.swift in Sources */, 4346D1E71C77F5FE00ABAFE3 /* ChartTableViewCell.swift in Sources */, 437CEEE41CDE5C0A003C8C80 /* UIImage.swift in Sources */, 43DBF0591C93F73800B3C386 /* CarbEntryTableViewController.swift in Sources */, 43E93FB71E469A5100EAB8DB /* HKUnit.swift in Sources */, + 43C05CAF21EB2C24006FB252 /* NSBundle.swift in Sources */, 43BFF0BC1E45C80600FF19A9 /* UIColor+Loop.swift in Sources */, 43C0944A1CACCC73001F6403 /* NotificationManager.swift in Sources */, 4F08DE9D1E81D0E9006741EA /* StatusChartsManager+LoopKit.swift in Sources */, + 43D9003321EB258C00AF44BF /* InsulinModelSettings+Loop.swift in Sources */, 434FF1EE1CF27EEF000DB779 /* UITableViewCell.swift in Sources */, 439BED2A1E76093C00B0AED5 /* CGMManager.swift in Sources */, C18C8C511D5A351900E043FB /* NightscoutDataManager.swift in Sources */, @@ -1931,11 +2346,10 @@ 4374B5EF209D84BF00D17AA8 /* OSLog.swift in Sources */, 4F6663941E905FD2009E74FC /* ChartColorPalette+Loop.swift in Sources */, 4328E0351CFC0AE100E199AA /* WatchDataManager.swift in Sources */, + 4345E3FC21F04911009E00E5 /* UIColor+HIG.swift in Sources */, 43D381621EBD9759007F8C8F /* HeaderValuesTableViewCell.swift in Sources */, - 43BFF0C51E465A2D00FF19A9 /* UIColor+HIG.swift in Sources */, 43785E982120E7060057DED1 /* Intents.intentdefinition in Sources */, 4302F4E31D4EA54200F0FCAF /* InsulinDeliveryTableViewController.swift in Sources */, - 4374B5F4209D89A900D17AA8 /* TextFieldTableViewCell.swift in Sources */, 4FC8C8011DEB93E400A1452E /* NSUserDefaults+StatusExtension.swift in Sources */, 43DAD00020A2736F000F8529 /* PersistedPumpEvent.swift in Sources */, 438849EC1D29EC34003B3F23 /* AmplitudeService.swift in Sources */, @@ -1959,13 +2373,11 @@ 436A0DA51D236A2A00104B24 /* LoopError.swift in Sources */, 4F11D3C220DD80B3006E072C /* WatchHistoricalGlucose.swift in Sources */, 435CB6231F37967800C320C7 /* InsulinModelSettingsViewController.swift in Sources */, - 431E73481FF95A900069B5F7 /* PersistenceController.swift in Sources */, 4372E490213CFCE70068E043 /* LoopSettingsUserInfo.swift in Sources */, 43F78D261C8FC000002152D1 /* DoseMath.swift in Sources */, 438D42F91D7C88BC003244B0 /* PredictionInputEffect.swift in Sources */, 4F70C2101DE8FAC5006380B7 /* StatusExtensionDataManager.swift in Sources */, 43DFB62320D4CAE7008A7BAE /* PumpManager.swift in Sources */, - 435CB6291F37B01300C320C7 /* InsulinModelSettings.swift in Sources */, 431A8C401EC6E8AB00823B9C /* CircleMaskView.swift in Sources */, 439897371CD2F80600223065 /* AnalyticsManager.swift in Sources */, 430D85891F44037000AF2D4F /* HUDViewTableViewCell.swift in Sources */, @@ -1976,9 +2388,7 @@ 432E73CB1D24B3D6009AD15D /* RemoteDataManager.swift in Sources */, 43DE92591C5479E4001FFDE1 /* CarbEntryUserInfo.swift in Sources */, 43DE92611C555C26001FFDE1 /* AbsorptionTimeType+CarbKit.swift in Sources */, - 430B298E2041F56500BA9F93 /* LoopSettings.swift in Sources */, 43C2FAE11EB656A500364AFF /* GlucoseEffectVelocity.swift in Sources */, - 4374B5F2209D897600D17AA8 /* Locked.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1990,12 +2400,10 @@ 4F2C15741E0209F500E160D4 /* NSTimeInterval.swift in Sources */, 4FF4D1011E18375000846527 /* WatchContext.swift in Sources */, 435400311C9F744E00D5819C /* BolusSuggestionUserInfo.swift in Sources */, - 4372E49A213F7A830068E043 /* WalshInsulinModel.swift in Sources */, 898ECA63218ABD21001E9D35 /* ComplicationChartManager.swift in Sources */, 43A9438A1B926B7B0051FA24 /* NotificationController.swift in Sources */, 439A7945211FE23A0041B75F /* NSUserActivity.swift in Sources */, 43A943881B926B7B0051FA24 /* ExtensionDelegate.swift in Sources */, - 4372E498213F7A550068E043 /* InsulinModelSettings.swift in Sources */, 4F75F00220FCFE8C00B5570E /* GlucoseChartScene.swift in Sources */, 4328E02F1CFBF81800E199AA /* WKInterfaceImage.swift in Sources */, 4F2C15811E0495B200E160D4 /* WatchContext+WatchApp.swift in Sources */, @@ -2012,7 +2420,6 @@ 4328E02B1CFBE2C500E199AA /* WKAlertAction.swift in Sources */, 4F7E8AC720E2AC0300AEA65E /* WatchPredictedGlucose.swift in Sources */, 4344628E20A7ADD100C4BE6F /* UserDefaults+CGM.swift in Sources */, - 4372E499213F7A6D0068E043 /* ExponentialInsulinModelPreset.swift in Sources */, 4F7E8AC520E2AB9600AEA65E /* Date.swift in Sources */, 4F11D3C420DD881A006E072C /* WatchHistoricalGlucose.swift in Sources */, 4328E0281CFBE2C500E199AA /* CLKComplicationTemplate.swift in Sources */, @@ -2025,28 +2432,88 @@ 898ECA69218ABDA9001E9D35 /* CLKTextProvider+Compound.m in Sources */, 4372E48C213CB6750068E043 /* Double.swift in Sources */, 43785E972120E4500057DED1 /* INRelevantShortcutStore+Loop.swift in Sources */, - 4372E48E213CF8AD0068E043 /* LoopSettings.swift in Sources */, 898ECA65218ABD9B001E9D35 /* CGRect.swift in Sources */, - 4372E49B213F7B340068E043 /* NSBundle.swift in Sources */, 43CB2B2B1D924D450079823D /* WCSession.swift in Sources */, - 4372E497213F79F90068E043 /* NSUserDefaults.swift in Sources */, 4372E491213D05F90068E043 /* LoopSettingsUserInfo.swift in Sources */, 43DE925A1C5479E4001FFDE1 /* CarbEntryUserInfo.swift in Sources */, - 4FF0F75E20E1E5D100FC6291 /* PersistenceController.swift in Sources */, 43BFF0B51E45C1E700FF19A9 /* NumberFormatter.swift in Sources */, 43A9438E1B926B7B0051FA24 /* ComplicationController.swift in Sources */, 4328E01A1CFBE1DA00E199AA /* ActionHUDController.swift in Sources */, 4F11D3C320DD84DB006E072C /* GlucoseBackfillRequestUserInfo.swift in Sources */, - 4372E48D213CF8A70068E043 /* GlucoseThreshold.swift in Sources */, 435400351C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + 43D9001F21EB209400AF44BF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43C05CB821EBEA54006FB252 /* HKUnit.swift in Sources */, + 4345E3F421F036FC009E00E5 /* Result.swift in Sources */, + 43D9002021EB209400AF44BF /* NSTimeInterval.swift in Sources */, + 43C05CA921EB2B26006FB252 /* PersistenceController.swift in Sources */, + 431EA87221EB29150076EC1A /* InsulinModelSettings.swift in Sources */, + 43D9002121EB209400AF44BF /* GlucoseThreshold.swift in Sources */, + 4345E3F221F0351E009E00E5 /* Locked.swift in Sources */, + 43C05CAB21EB2B4A006FB252 /* NSBundle.swift in Sources */, + 43D9002221EB209400AF44BF /* LoopSettings.swift in Sources */, + 431EA87421EB291A0076EC1A /* WalshInsulinModel.swift in Sources */, + 431EA87021EB29120076EC1A /* ExponentialInsulinModelPreset.swift in Sources */, + 43C05CC721EC2ABC006FB252 /* IdentifiableClass.swift in Sources */, + 43C05CAE21EB2BBF006FB252 /* NSUserDefaults.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FF9E21EA9A0C00AF44BF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43C05CBD21EBF77D006FB252 /* LessonsViewController.swift in Sources */, + 43C05CB621EBE321006FB252 /* NSTimeInterval.swift in Sources */, + 43C05CB521EBE274006FB252 /* Date.swift in Sources */, + 43D9F82421EFF1AB000578CD /* LessonResultsViewController.swift in Sources */, + 4345E3FA21F0473B009E00E5 /* TextCell.swift in Sources */, + 43D9F81821EC51CC000578CD /* DateEntry.swift in Sources */, + 43D9FFC021EAB22E00AF44BF /* DataManager.swift in Sources */, + 43C05CB121EBBDB9006FB252 /* TimeInRangeLesson.swift in Sources */, + 43D9F81E21EF0609000578CD /* NumberRangeEntry.swift in Sources */, + 43C05CCA21EC382B006FB252 /* NumberEntry.swift in Sources */, + 4345E3FE21F04A50009E00E5 /* DateIntervalFormatter.swift in Sources */, + 4345E3F821F03D2A009E00E5 /* DatesAndNumberCell.swift in Sources */, + 43D9F82221EF0A7A000578CD /* QuantityRangeEntry.swift in Sources */, + 43D9F81A21EC593C000578CD /* UITableViewCell.swift in Sources */, + 43D9F82021EF0906000578CD /* NSNumber.swift in Sources */, + 43C05CC221EC06E4006FB252 /* LessonConfigurationViewController.swift in Sources */, + 43C05CC621EC29E7006FB252 /* TextFieldTableViewCell.swift in Sources */, + 43C05CC021EBFFA4006FB252 /* Lesson.swift in Sources */, + 43D9FFA521EA9A0C00AF44BF /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43D9FFCB21EAE05D00AF44BF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43C05CB921EBEA54006FB252 /* HKUnit.swift in Sources */, + 4345E3F521F036FC009E00E5 /* Result.swift in Sources */, + 43D9FFFB21EAF3D300AF44BF /* NSTimeInterval.swift in Sources */, + 43C05CA821EB2B26006FB252 /* PersistenceController.swift in Sources */, + 431EA87321EB29160076EC1A /* InsulinModelSettings.swift in Sources */, + 43D9FFF921EAF34800AF44BF /* GlucoseThreshold.swift in Sources */, + 4345E3F321F0351E009E00E5 /* Locked.swift in Sources */, + 43C05CAA21EB2B49006FB252 /* NSBundle.swift in Sources */, + 43D9FFF521EAF27200AF44BF /* LoopSettings.swift in Sources */, + 431EA87521EB291B0076EC1A /* WalshInsulinModel.swift in Sources */, + 431EA87121EB29120076EC1A /* ExponentialInsulinModelPreset.swift in Sources */, + 43C05CC821EC2ABC006FB252 /* IdentifiableClass.swift in Sources */, + 43C05CAD21EB2BBF006FB252 /* NSUserDefaults.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 43E2D8CD1D20BF42004DA55F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 43C3B6ED20B884500026CAFA /* GlucoseThreshold.swift in Sources */, 43947D731F529FAA00A07D31 /* GlucoseRangeSchedule.swift in Sources */, 43E2D8DC1D20C049004DA55F /* DoseMath.swift in Sources */, 43E2D8DB1D20C03B004DA55F /* NSTimeInterval.swift in Sources */, @@ -2069,26 +2536,19 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 43C05CAC21EB2B8B006FB252 /* NSBundle.swift in Sources */, 4FAC02541E22F6B20087A773 /* NSTimeInterval.swift in Sources */, - 434B2888206B4F0A000EE07B /* InsulinModelSettings.swift in Sources */, 4FB76FBA1E8C42CE00B39636 /* UIColor.swift in Sources */, 4F2C15831E0757E600E160D4 /* HKUnit.swift in Sources */, - 430B29902041F57000BA9F93 /* GlucoseThreshold.swift in Sources */, C1FB4290217922A100FAB378 /* PumpManagerUI.swift in Sources */, - 434B2887206B4F07000EE07B /* WalshInsulinModel.swift in Sources */, C1FB428D21791D2500FAB378 /* PumpManager.swift in Sources */, 43E93FB51E4675E800EAB8DB /* NumberFormatter.swift in Sources */, + 4345E3FB21F04911009E00E5 /* UIColor+HIG.swift in Sources */, 43BFF0CD1E466C8400FF19A9 /* StateColorPalette.swift in Sources */, - 430B29912041F57200BA9F93 /* LoopSettings.swift in Sources */, - 4F526D621DF9D95200A04910 /* NSBundle.swift in Sources */, 4FC8C8021DEB943800A1452E /* NSUserDefaults+StatusExtension.swift in Sources */, - 434B2889206B4F0C000EE07B /* ExponentialInsulinModelPreset.swift in Sources */, - 434B2886206628B3000EE07B /* PersistenceController.swift in Sources */, - 43BFF0C71E465A4F00FF19A9 /* UIColor+HIG.swift in Sources */, 43BFF0BF1E45C8EA00FF19A9 /* UIColor+Widget.swift in Sources */, 4F70C2121DE900EA006380B7 /* StatusExtensionContext.swift in Sources */, 4F70C1E11DE8DCA7006380B7 /* StatusViewController.swift in Sources */, - 430B298B2041F55700BA9F93 /* NSUserDefaults.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2098,7 +2558,6 @@ files = ( 4FB76FB91E8C42B000B39636 /* CollectionType.swift in Sources */, 7D23667D21250C7E0028B67D /* LocalizedString.swift in Sources */, - 4FF4D0F91E17268800846527 /* IdentifiableClass.swift in Sources */, 436961911F19D11E00447E89 /* ChartPointsContextFillLayer.swift in Sources */, 4FF4D0F81E1725B000846527 /* NibLoadable.swift in Sources */, 4326BA641F3A44D9007CCAD4 /* ChartLineModel.swift in Sources */, @@ -2154,6 +2613,46 @@ target = 43A943711B926B7B0051FA24 /* WatchApp */; targetProxy = 43A943921B926B7B0051FA24 /* PBXContainerItemProxy */; }; + 43D9000D21EB0BEA00AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 43D9FFCE21EAE05D00AF44BF /* LoopCore */; + targetProxy = 43D9000C21EB0BEA00AF44BF /* PBXContainerItemProxy */; + }; + 43D9001321EB137A00AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 43D9FFCE21EAE05D00AF44BF /* LoopCore */; + targetProxy = 43D9001221EB137A00AF44BF /* PBXContainerItemProxy */; + }; + 43D9001921EB207300AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 432CF87720D8B8380066B889 /* Cartfile */; + targetProxy = 43D9001821EB207300AF44BF /* PBXContainerItemProxy */; + }; + 43D9001B21EB209400AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 432CF87720D8B8380066B889 /* Cartfile */; + targetProxy = 43D9001C21EB209400AF44BF /* PBXContainerItemProxy */; + }; + 43D9003121EB236800AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 43D9001A21EB209400AF44BF /* LoopCore-watchOS */; + targetProxy = 43D9003021EB236800AF44BF /* PBXContainerItemProxy */; + }; + 43D9FFB821EA9C9F00AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 432CF87720D8B8380066B889 /* Cartfile */; + targetProxy = 43D9FFB721EA9C9F00AF44BF /* PBXContainerItemProxy */; + }; + 43D9FFBA21EA9CA400AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4F75288A1DFE1DC600C322D6 /* LoopUI */; + targetProxy = 43D9FFB921EA9CA400AF44BF /* PBXContainerItemProxy */; + }; + 43D9FFD521EAE05D00AF44BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 43D9FFCE21EAE05D00AF44BF /* LoopCore */; + targetProxy = 43D9FFD421EAE05D00AF44BF /* PBXContainerItemProxy */; + }; 43E2D9111D20C581004DA55F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 43776F8B1B8022E90074EA36 /* Loop */; @@ -2240,6 +2739,22 @@ name = Interface.storyboard; sourceTree = ""; }; + 43D9FFA821EA9A0C00AF44BF /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 43D9FFA921EA9A0C00AF44BF /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 43D9FFAD21EA9A0F00AF44BF /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 43D9FFAE21EA9A0F00AF44BF /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; 4F70C1E21DE8DCA7006380B7 /* MainInterface.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -2756,6 +3271,202 @@ }; name = Release; }; + 43D9002821EB209400AF44BF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 54; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 54; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PROJECT_DIR)/Carthage/Build/watchOS", + "$(inherited)", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = LoopCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopCore; + PRODUCT_NAME = LoopCore; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 43D9002921EB209400AF44BF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 54; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 54; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PROJECT_DIR)/Carthage/Build/watchOS", + "$(inherited)", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = LoopCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopCore; + PRODUCT_NAME = LoopCore; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 43D9FFB121EA9A0F00AF44BF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = Learn/Learn.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = Learn/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "$(MAIN_APP_BUNDLE_IDENTIFIER)Learn"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 43D9FFB221EA9A0F00AF44BF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = Learn/Learn.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = Learn/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "$(MAIN_APP_BUNDLE_IDENTIFIER)Learn"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 43D9FFD921EAE05D00AF44BF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 54; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 54; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = LoopCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopCore; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 43D9FFDA21EAE05D00AF44BF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 54; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 54; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = LoopCore/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.loopkit.LoopCore; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; 43E2D8D71D20BF42004DA55F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2950,6 +3661,33 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 43D9002721EB209400AF44BF /* Build configuration list for PBXNativeTarget "LoopCore-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43D9002821EB209400AF44BF /* Debug */, + 43D9002921EB209400AF44BF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 43D9FFB321EA9A0F00AF44BF /* Build configuration list for PBXNativeTarget "Learn" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43D9FFB121EA9A0F00AF44BF /* Debug */, + 43D9FFB221EA9A0F00AF44BF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 43D9FFD821EAE05D00AF44BF /* Build configuration list for PBXNativeTarget "LoopCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43D9FFD921EAE05D00AF44BF /* Debug */, + 43D9FFDA21EAE05D00AF44BF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 43E2D8D61D20BF42004DA55F /* Build configuration list for PBXNativeTarget "DoseMathTests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Loop.xcodeproj/xcshareddata/xcschemes/Cartfile.xcscheme b/Loop.xcodeproj/xcshareddata/xcschemes/Cartfile.xcscheme new file mode 100644 index 0000000000..6b9c3c2cba --- /dev/null +++ b/Loop.xcodeproj/xcshareddata/xcschemes/Cartfile.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Loop.xcodeproj/xcshareddata/xcschemes/Complication - WatchApp.xcscheme b/Loop.xcodeproj/xcshareddata/xcschemes/Complication - WatchApp.xcscheme index 41e44bba86..e1cf09c605 100644 --- a/Loop.xcodeproj/xcshareddata/xcschemes/Complication - WatchApp.xcscheme +++ b/Loop.xcodeproj/xcshareddata/xcschemes/Complication - WatchApp.xcscheme @@ -1,6 +1,6 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Loop.xcodeproj/xcshareddata/xcschemes/Loop Status Extension.xcscheme b/Loop.xcodeproj/xcshareddata/xcschemes/Loop Status Extension.xcscheme index b9703af9df..7f086b637f 100644 --- a/Loop.xcodeproj/xcshareddata/xcschemes/Loop Status Extension.xcscheme +++ b/Loop.xcodeproj/xcshareddata/xcschemes/Loop Status Extension.xcscheme @@ -1,6 +1,6 @@ com.apple.developer.healthkit + com.apple.developer.healthkit.access + com.apple.developer.siri com.apple.security.application-groups diff --git a/Loop/Managers/AnalyticsManager.swift b/Loop/Managers/AnalyticsManager.swift index 431ed82921..dc62fde479 100644 --- a/Loop/Managers/AnalyticsManager.swift +++ b/Loop/Managers/AnalyticsManager.swift @@ -9,6 +9,7 @@ import Foundation import Amplitude import LoopKit +import LoopCore final class AnalyticsManager: IdentifiableClass { diff --git a/Loop/Managers/DeviceDataManager.swift b/Loop/Managers/DeviceDataManager.swift index 8fe8026f53..8603a0d156 100644 --- a/Loop/Managers/DeviceDataManager.swift +++ b/Loop/Managers/DeviceDataManager.swift @@ -9,6 +9,7 @@ import HealthKit import LoopKit import LoopKitUI +import LoopCore final class DeviceDataManager { @@ -29,7 +30,7 @@ final class DeviceDataManager { NotificationCenter.default.post(name: .PumpManagerChanged, object: self, userInfo: nil) - UserDefaults.appGroup.pumpManager = pumpManager + UserDefaults.appGroup?.pumpManager = pumpManager } } @@ -61,7 +62,7 @@ final class DeviceDataManager { didSet { setupCGM() - UserDefaults.appGroup.cgmManager = cgmManager + UserDefaults.appGroup?.cgmManager = cgmManager } } @@ -140,11 +141,11 @@ final class DeviceDataManager { private(set) var loopManager: LoopDataManager! init() { - pumpManager = UserDefaults.appGroup.pumpManager as? PumpManagerUI - - if let cgmManager = UserDefaults.appGroup.cgmManager { + pumpManager = UserDefaults.appGroup?.pumpManager as? PumpManagerUI + + if let cgmManager = UserDefaults.appGroup?.cgmManager { self.cgmManager = cgmManager - } else if UserDefaults.appGroup.isCGMManagerValidPumpManager { + } else if UserDefaults.appGroup?.isCGMManagerValidPumpManager == true { self.cgmManager = pumpManager as? CGMManager } @@ -228,7 +229,7 @@ extension DeviceDataManager: PumpManagerDelegate { func pumpManagerDidUpdateState(_ pumpManager: PumpManager) { log.default("PumpManager:\(type(of: pumpManager)) did update state") - UserDefaults.appGroup.pumpManager = pumpManager + UserDefaults.appGroup?.pumpManager = pumpManager } func pumpManagerBLEHeartbeatDidFire(_ pumpManager: PumpManager) { diff --git a/Loop/Managers/LoopDataManager.swift b/Loop/Managers/LoopDataManager.swift index 6ae172a1f4..7b02413af5 100644 --- a/Loop/Managers/LoopDataManager.swift +++ b/Loop/Managers/LoopDataManager.swift @@ -9,6 +9,7 @@ import Foundation import HealthKit import LoopKit +import LoopCore final class LoopDataManager { @@ -44,11 +45,11 @@ final class LoopDataManager { init( lastLoopCompleted: Date?, lastTempBasal: DoseEntry?, - basalRateSchedule: BasalRateSchedule? = UserDefaults.appGroup.basalRateSchedule, - carbRatioSchedule: CarbRatioSchedule? = UserDefaults.appGroup.carbRatioSchedule, - insulinModelSettings: InsulinModelSettings? = UserDefaults.appGroup.insulinModelSettings, - insulinSensitivitySchedule: InsulinSensitivitySchedule? = UserDefaults.appGroup.insulinSensitivitySchedule, - settings: LoopSettings = UserDefaults.appGroup.loopSettings ?? LoopSettings() + basalRateSchedule: BasalRateSchedule? = UserDefaults.appGroup?.basalRateSchedule, + carbRatioSchedule: CarbRatioSchedule? = UserDefaults.appGroup?.carbRatioSchedule, + insulinModelSettings: InsulinModelSettings? = UserDefaults.appGroup?.insulinModelSettings, + insulinSensitivitySchedule: InsulinSensitivitySchedule? = UserDefaults.appGroup?.insulinSensitivitySchedule, + settings: LoopSettings = UserDefaults.appGroup?.loopSettings ?? LoopSettings() ) { self.logger = DiagnosticLogger.shared.forCategory("LoopDataManager") self.lockedLastLoopCompleted = Locked(lastLoopCompleted) @@ -118,7 +119,7 @@ final class LoopDataManager { /// These are not thread-safe. var settings: LoopSettings { didSet { - UserDefaults.appGroup.loopSettings = settings + UserDefaults.appGroup?.loopSettings = settings notify(forChange: .preferences) AnalyticsManager.shared.didChangeLoopSettings(from: oldValue, to: settings) } @@ -246,7 +247,7 @@ extension LoopDataManager { } set { doseStore.basalProfile = newValue - UserDefaults.appGroup.basalRateSchedule = newValue + UserDefaults.appGroup?.basalRateSchedule = newValue notify(forChange: .preferences) if let newValue = newValue, let oldValue = doseStore.basalProfile, newValue.items != oldValue.items { @@ -263,7 +264,7 @@ extension LoopDataManager { } set { carbStore.carbRatioSchedule = newValue - UserDefaults.appGroup.carbRatioSchedule = newValue + UserDefaults.appGroup?.carbRatioSchedule = newValue // Invalidate cached effects based on this schedule carbEffect = nil @@ -284,7 +285,7 @@ extension LoopDataManager { } set { doseStore.insulinModel = newValue?.model - UserDefaults.appGroup.insulinModelSettings = newValue + UserDefaults.appGroup?.insulinModelSettings = newValue self.dataAccessQueue.async { // Invalidate cached effects based on this schedule @@ -307,7 +308,7 @@ extension LoopDataManager { carbStore.insulinSensitivitySchedule = newValue doseStore.insulinSensitivitySchedule = newValue - UserDefaults.appGroup.insulinSensitivitySchedule = newValue + UserDefaults.appGroup?.insulinSensitivitySchedule = newValue dataAccessQueue.async { // Invalidate cached effects based on this schedule diff --git a/Loop/Managers/WatchDataManager.swift b/Loop/Managers/WatchDataManager.swift index 6f3fc32866..e8a9300b9a 100644 --- a/Loop/Managers/WatchDataManager.swift +++ b/Loop/Managers/WatchDataManager.swift @@ -10,6 +10,8 @@ import HealthKit import UIKit import WatchConnectivity import LoopKit +import LoopCore + final class WatchDataManager: NSObject { diff --git a/Loop/Models/LoopSettings+Loop.swift b/Loop/Models/LoopSettings+Loop.swift index 32ba973f0a..eaf569fdb0 100644 --- a/Loop/Models/LoopSettings+Loop.swift +++ b/Loop/Models/LoopSettings+Loop.swift @@ -5,6 +5,7 @@ // Copyright © 2018 LoopKit Authors. All rights reserved. // +import LoopCore // MARK: - Static configuration extension LoopSettings { diff --git a/Loop/View Controllers/BolusViewController.swift b/Loop/View Controllers/BolusViewController.swift index 3a58b7f3be..2e2cf97409 100644 --- a/Loop/View Controllers/BolusViewController.swift +++ b/Loop/View Controllers/BolusViewController.swift @@ -10,6 +10,7 @@ import UIKit import LocalAuthentication import LoopKit import HealthKit +import LoopCore final class BolusViewController: UITableViewController, IdentifiableClass, UITextFieldDelegate { diff --git a/Loop/View Controllers/CarbAbsorptionViewController.swift b/Loop/View Controllers/CarbAbsorptionViewController.swift index afab2f835f..8dfc1e32fd 100644 --- a/Loop/View Controllers/CarbAbsorptionViewController.swift +++ b/Loop/View Controllers/CarbAbsorptionViewController.swift @@ -12,6 +12,7 @@ import os.log import LoopKit import LoopKitUI +import LoopCore private extension RefreshContext { diff --git a/Loop/View Controllers/CarbEntryEditTableViewController.swift b/Loop/View Controllers/CarbEntryEditTableViewController.swift index 742ca766ba..99f73c6102 100644 --- a/Loop/View Controllers/CarbEntryEditTableViewController.swift +++ b/Loop/View Controllers/CarbEntryEditTableViewController.swift @@ -7,6 +7,7 @@ // import LoopKitUI +import LoopCore extension CarbEntryEditViewController: IdentifiableClass { diff --git a/Loop/View Controllers/CarbEntryTableViewController.swift b/Loop/View Controllers/CarbEntryTableViewController.swift index d2c6698bf9..1c66be5fb3 100644 --- a/Loop/View Controllers/CarbEntryTableViewController.swift +++ b/Loop/View Controllers/CarbEntryTableViewController.swift @@ -7,6 +7,7 @@ // import LoopKitUI +import LoopCore extension CarbEntryTableViewController: IdentifiableClass { diff --git a/Loop/View Controllers/InsulinDeliveryTableViewController.swift b/Loop/View Controllers/InsulinDeliveryTableViewController.swift index 4bd534e042..723ef3a8ff 100644 --- a/Loop/View Controllers/InsulinDeliveryTableViewController.swift +++ b/Loop/View Controllers/InsulinDeliveryTableViewController.swift @@ -7,6 +7,7 @@ // import LoopKitUI +import LoopCore extension InsulinDeliveryTableViewController: IdentifiableClass { diff --git a/Loop/View Controllers/InsulinModelSettingsViewController.swift b/Loop/View Controllers/InsulinModelSettingsViewController.swift index 855d0096f5..81878ba4fc 100644 --- a/Loop/View Controllers/InsulinModelSettingsViewController.swift +++ b/Loop/View Controllers/InsulinModelSettingsViewController.swift @@ -8,6 +8,7 @@ import UIKit import HealthKit import LoopKit +import LoopCore protocol InsulinModelSettingsViewControllerDelegate: class { diff --git a/Loop/View Controllers/PredictionTableViewController.swift b/Loop/View Controllers/PredictionTableViewController.swift index 14e8375b56..2b904cecaa 100644 --- a/Loop/View Controllers/PredictionTableViewController.swift +++ b/Loop/View Controllers/PredictionTableViewController.swift @@ -10,6 +10,7 @@ import UIKit import HealthKit import LoopKit import LoopKitUI +import LoopCore private extension RefreshContext { diff --git a/Loop/View Controllers/SettingsTableViewController.swift b/Loop/View Controllers/SettingsTableViewController.swift index 1ed62dfe69..d21e2d1d48 100644 --- a/Loop/View Controllers/SettingsTableViewController.swift +++ b/Loop/View Controllers/SettingsTableViewController.swift @@ -10,6 +10,7 @@ import UIKit import HealthKit import LoopKit import LoopKitUI +import LoopCore final class SettingsTableViewController: UITableViewController { diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index ed29d842c5..320fc740cc 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -9,6 +9,7 @@ import UIKit import HealthKit import Intents +import LoopCore import LoopKit import LoopKitUI import LoopUI diff --git a/Common/Models/GlucoseThreshold.swift b/LoopCore/GlucoseThreshold.swift similarity index 75% rename from Common/Models/GlucoseThreshold.swift rename to LoopCore/GlucoseThreshold.swift index 03bc479eab..8532905624 100644 --- a/Common/Models/GlucoseThreshold.swift +++ b/LoopCore/GlucoseThreshold.swift @@ -9,11 +9,11 @@ import Foundation import HealthKit -struct GlucoseThreshold: Equatable, RawRepresentable { - typealias RawValue = [String: Any] +public struct GlucoseThreshold: Equatable, RawRepresentable { + public typealias RawValue = [String: Any] - let value: Double - let unit: HKUnit + public let value: Double + public let unit: HKUnit public var quantity: HKQuantity { return HKQuantity(unit: unit, doubleValue: value) @@ -24,7 +24,7 @@ struct GlucoseThreshold: Equatable, RawRepresentable { self.unit = unit } - init?(rawValue: RawValue) { + public init?(rawValue: RawValue) { guard let unitsStr = rawValue["units"] as? String, let value = rawValue["value"] as? Double else { return nil } @@ -32,7 +32,7 @@ struct GlucoseThreshold: Equatable, RawRepresentable { self.value = value } - var rawValue: RawValue { + public var rawValue: RawValue { return [ "value": value, "units": unit.unitString diff --git a/LoopCore/HKUnit.swift b/LoopCore/HKUnit.swift new file mode 100644 index 0000000000..da6d179e84 --- /dev/null +++ b/LoopCore/HKUnit.swift @@ -0,0 +1,20 @@ +// +// HKUnit.swift +// Naterade +// +// Created by Nathan Racklyeft on 1/17/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import HealthKit + + +extension HKUnit { + public static let milligramsPerDeciliter: HKUnit = { + return HKUnit.gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)) + }() + + public static let millimolesPerLiter: HKUnit = { + return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()) + }() +} diff --git a/Common/Extensions/IdentifiableClass.swift b/LoopCore/IdentifiableClass.swift similarity index 79% rename from Common/Extensions/IdentifiableClass.swift rename to LoopCore/IdentifiableClass.swift index a350a1fde5..3e0035edd8 100644 --- a/Common/Extensions/IdentifiableClass.swift +++ b/LoopCore/IdentifiableClass.swift @@ -9,13 +9,13 @@ import Foundation -protocol IdentifiableClass: class { +public protocol IdentifiableClass: class { static var className: String { get } } extension IdentifiableClass { - static var className: String { + public static var className: String { return NSStringFromClass(self).components(separatedBy: ".").last! } } diff --git a/LoopCore/Info.plist b/LoopCore/Info.plist new file mode 100644 index 0000000000..e239aff029 --- /dev/null +++ b/LoopCore/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.9.4 dev + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/LoopCore/Insulin/ExponentialInsulinModelPreset.swift b/LoopCore/Insulin/ExponentialInsulinModelPreset.swift new file mode 100644 index 0000000000..e2f0877ed8 --- /dev/null +++ b/LoopCore/Insulin/ExponentialInsulinModelPreset.swift @@ -0,0 +1,63 @@ +// +// ExponentialInsulinModelPreset.swift +// Loop +// +// Copyright © 2017 LoopKit Authors. All rights reserved. +// + +import LoopKit + + +public enum ExponentialInsulinModelPreset: String { + case humalogNovologAdult + case humalogNovologChild + case fiasp +} + + +// MARK: - Model generation +extension ExponentialInsulinModelPreset { + var actionDuration: TimeInterval { + switch self { + case .humalogNovologAdult: + return .minutes(360) + case .humalogNovologChild: + return .minutes(360) + case .fiasp: + return .minutes(360) + } + } + + var peakActivity: TimeInterval { + switch self { + case .humalogNovologAdult: + return .minutes(75) + case .humalogNovologChild: + return .minutes(65) + case .fiasp: + return .minutes(55) + } + } + + var model: InsulinModel { + return ExponentialInsulinModel(actionDuration: actionDuration, peakActivityTime: peakActivity) + } +} + + +extension ExponentialInsulinModelPreset: InsulinModel { + public var effectDuration: TimeInterval { + return model.effectDuration + } + + public func percentEffectRemaining(at time: TimeInterval) -> Double { + return model.percentEffectRemaining(at: time) + } +} + + +extension ExponentialInsulinModelPreset: CustomDebugStringConvertible { + public var debugDescription: String { + return "\(self.rawValue)(\(String(reflecting: model))" + } +} diff --git a/Common/Models/Insulin/InsulinModelSettings.swift b/LoopCore/Insulin/InsulinModelSettings.swift similarity index 82% rename from Common/Models/Insulin/InsulinModelSettings.swift rename to LoopCore/Insulin/InsulinModelSettings.swift index 0d6eb295c4..84b3485555 100644 --- a/Common/Models/Insulin/InsulinModelSettings.swift +++ b/LoopCore/Insulin/InsulinModelSettings.swift @@ -8,11 +8,11 @@ import LoopKit -enum InsulinModelSettings { +public enum InsulinModelSettings { case exponentialPreset(ExponentialInsulinModelPreset) case walsh(WalshInsulinModel) - var model: InsulinModel { + public var model: InsulinModel { switch self { case .exponentialPreset(let model): return model @@ -21,7 +21,7 @@ enum InsulinModelSettings { } } - init?(model: InsulinModel) { + public init?(model: InsulinModel) { switch model { case let model as ExponentialInsulinModelPreset: self = .exponentialPreset(model) @@ -35,25 +35,16 @@ enum InsulinModelSettings { extension InsulinModelSettings: CustomDebugStringConvertible { - var title: String { - switch self { - case .exponentialPreset(let model): - return model.title - case .walsh(let model): - return model.title - } - } - - var debugDescription: String { + public var debugDescription: String { return String(reflecting: model) } } extension InsulinModelSettings: RawRepresentable { - typealias RawValue = [String: Any] + public typealias RawValue = [String: Any] - init?(rawValue: RawValue) { + public init?(rawValue: RawValue) { guard let typeName = rawValue["type"] as? InsulinModelType.RawValue, let type = InsulinModelType(rawValue: typeName) else { @@ -80,7 +71,7 @@ extension InsulinModelSettings: RawRepresentable { } } - var rawValue: [String : Any] { + public var rawValue: [String : Any] { switch self { case .exponentialPreset(let model): return [ diff --git a/Common/Models/Insulin/WalshInsulinModel.swift b/LoopCore/Insulin/WalshInsulinModel.swift similarity index 58% rename from Common/Models/Insulin/WalshInsulinModel.swift rename to LoopCore/Insulin/WalshInsulinModel.swift index 50d2f70ad5..eaa6aeae55 100644 --- a/Common/Models/Insulin/WalshInsulinModel.swift +++ b/LoopCore/Insulin/WalshInsulinModel.swift @@ -23,15 +23,3 @@ extension WalshInsulinModel: RawRepresentable { return ["actionDuration": self.actionDuration] } } - - -// MARK: - Localization -extension WalshInsulinModel { - var title: String { - return NSLocalizedString("Walsh", comment: "Title of insulin model setting") - } - - var subtitle: String { - return NSLocalizedString("The legacy model used by Loop, allowing customization of action duration.", comment: "Subtitle description of Walsh insulin model setting") - } -} diff --git a/Loop/Models/Locked.swift b/LoopCore/Locked.swift similarity index 82% rename from Loop/Models/Locked.swift rename to LoopCore/Locked.swift index fd6e35b104..27dd05d96b 100644 --- a/Loop/Models/Locked.swift +++ b/LoopCore/Locked.swift @@ -8,17 +8,17 @@ import os.lock -internal class Locked { +public class Locked { private var lock = os_unfair_lock() private var _value: T - init(_ value: T) { + public init(_ value: T) { os_unfair_lock_lock(&lock) defer { os_unfair_lock_unlock(&lock) } _value = value } - var value: T { + public var value: T { get { os_unfair_lock_lock(&lock) defer { os_unfair_lock_unlock(&lock) } @@ -31,7 +31,7 @@ internal class Locked { } } - func mutate(_ changes: (_ value: inout T) -> Void) -> T { + public func mutate(_ changes: (_ value: inout T) -> Void) -> T { os_unfair_lock_lock(&lock) defer { os_unfair_lock_unlock(&lock) } changes(&_value) diff --git a/LoopCore/LoopCore.h b/LoopCore/LoopCore.h new file mode 100644 index 0000000000..619115ff00 --- /dev/null +++ b/LoopCore/LoopCore.h @@ -0,0 +1,18 @@ +// +// LoopCore.h +// LoopCore +// +// Copyright © 2019 LoopKit Authors. All rights reserved. +// + +#import + +//! Project version number for LoopCore. +FOUNDATION_EXPORT double LoopCoreVersionNumber; + +//! Project version string for LoopCore. +FOUNDATION_EXPORT const unsigned char LoopCoreVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Common/Models/LoopSettings.swift b/LoopCore/LoopSettings.swift similarity index 56% rename from Common/Models/LoopSettings.swift rename to LoopCore/LoopSettings.swift index ae1c5a33b1..4d0d4f084b 100644 --- a/Common/Models/LoopSettings.swift +++ b/LoopCore/LoopSettings.swift @@ -8,43 +8,59 @@ import LoopKit -struct LoopSettings: Equatable { - var dosingEnabled = false +public struct LoopSettings: Equatable { + public var dosingEnabled = false - let dynamicCarbAbsorptionEnabled = true + public let dynamicCarbAbsorptionEnabled = true - var glucoseTargetRangeSchedule: GlucoseRangeSchedule? + public var glucoseTargetRangeSchedule: GlucoseRangeSchedule? - var maximumBasalRatePerHour: Double? + public var maximumBasalRatePerHour: Double? - var maximumBolus: Double? + public var maximumBolus: Double? - var suspendThreshold: GlucoseThreshold? = nil + public var suspendThreshold: GlucoseThreshold? = nil - var retrospectiveCorrectionEnabled = true + public var retrospectiveCorrectionEnabled = true /// The interval over which to aggregate changes in glucose for retrospective correction - let retrospectiveCorrectionGroupingInterval = TimeInterval(minutes: 30) + public let retrospectiveCorrectionGroupingInterval = TimeInterval(minutes: 30) /// The maximum duration over which to integrate retrospective correction changes - let retrospectiveCorrectionIntegrationInterval = TimeInterval(minutes: 30) + public let retrospectiveCorrectionIntegrationInterval = TimeInterval(minutes: 30) /// The amount of time since a given date that data should be considered valid - let recencyInterval = TimeInterval(minutes: 15) + public let recencyInterval = TimeInterval(minutes: 15) // MARK - Display settings - let minimumChartWidthPerHour: CGFloat = 50 - - let statusChartMinimumHistoryDisplay: TimeInterval = .hours(1) + public let minimumChartWidthPerHour: CGFloat = 50 + + public let statusChartMinimumHistoryDisplay: TimeInterval = .hours(1) + + public init( + dosingEnabled: Bool = false, + glucoseTargetRangeSchedule: GlucoseRangeSchedule? = nil, + maximumBasalRatePerHour: Double? = nil, + maximumBolus: Double? = nil, + suspendThreshold: GlucoseThreshold? = nil, + retrospectiveCorrectionEnabled: Bool = true + ) { + self.dosingEnabled = dosingEnabled + self.glucoseTargetRangeSchedule = glucoseTargetRangeSchedule + self.maximumBasalRatePerHour = maximumBasalRatePerHour + self.maximumBolus = maximumBolus + self.suspendThreshold = suspendThreshold + self.retrospectiveCorrectionEnabled = retrospectiveCorrectionEnabled + } } extension LoopSettings: RawRepresentable { - typealias RawValue = [String: Any] + public typealias RawValue = [String: Any] private static let version = 1 - init?(rawValue: RawValue) { + public init?(rawValue: RawValue) { guard let version = rawValue["version"] as? Int, version == LoopSettings.version @@ -73,7 +89,7 @@ extension LoopSettings: RawRepresentable { } } - var rawValue: RawValue { + public var rawValue: RawValue { var raw: RawValue = [ "version": LoopSettings.version, "dosingEnabled": dosingEnabled, diff --git a/Common/Extensions/NSUserDefaults.swift b/LoopCore/NSUserDefaults.swift similarity index 92% rename from Common/Extensions/NSUserDefaults.swift rename to LoopCore/NSUserDefaults.swift index 7d5d73edde..062cb83ca6 100644 --- a/Common/Extensions/NSUserDefaults.swift +++ b/LoopCore/NSUserDefaults.swift @@ -21,7 +21,9 @@ extension UserDefaults { case insulinSensitivitySchedule = "com.loudnate.Naterade.InsulinSensitivitySchedule" } - var basalRateSchedule: BasalRateSchedule? { + public static let appGroup = UserDefaults(suiteName: Bundle.main.appGroupSuiteName) + + public var basalRateSchedule: BasalRateSchedule? { get { if let rawValue = dictionary(forKey: Key.basalRateSchedule.rawValue) { return BasalRateSchedule(rawValue: rawValue) @@ -34,7 +36,7 @@ extension UserDefaults { } } - var carbRatioSchedule: CarbRatioSchedule? { + public var carbRatioSchedule: CarbRatioSchedule? { get { if let rawValue = dictionary(forKey: Key.carbRatioSchedule.rawValue) { return CarbRatioSchedule(rawValue: rawValue) @@ -47,7 +49,7 @@ extension UserDefaults { } } - var insulinModelSettings: InsulinModelSettings? { + public var insulinModelSettings: InsulinModelSettings? { get { if let rawValue = dictionary(forKey: Key.insulinModelSettings.rawValue) { return InsulinModelSettings(rawValue: rawValue) @@ -67,7 +69,7 @@ extension UserDefaults { } } - var loopSettings: LoopSettings? { + public var loopSettings: LoopSettings? { get { if let rawValue = dictionary(forKey: Key.loopSettings.rawValue) { return LoopSettings(rawValue: rawValue) @@ -124,7 +126,7 @@ extension UserDefaults { } } - var insulinSensitivitySchedule: InsulinSensitivitySchedule? { + public var insulinSensitivitySchedule: InsulinSensitivitySchedule? { get { if let rawValue = dictionary(forKey: Key.insulinSensitivitySchedule.rawValue) { return InsulinSensitivitySchedule(rawValue: rawValue) diff --git a/Common/Extensions/PersistenceController.swift b/LoopCore/PersistenceController.swift similarity index 81% rename from Common/Extensions/PersistenceController.swift rename to LoopCore/PersistenceController.swift index a5c465bc42..4f88ffd24e 100644 --- a/Common/Extensions/PersistenceController.swift +++ b/LoopCore/PersistenceController.swift @@ -9,19 +9,19 @@ import LoopKit extension PersistenceController { - class func controllerInAppGroupDirectory() -> PersistenceController { + public class func controllerInAppGroupDirectory(isReadOnly: Bool = false) -> PersistenceController { let appGroup = Bundle.main.appGroupSuiteName guard let directoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { assertionFailure("Could not get a container directory URL. Please ensure App Groups are set up correctly in entitlements.") return self.init(directoryURL: URL(fileURLWithPath: "/")) } - let isReadOnly = Bundle.main.bundleURL.pathExtension == "appex" + let isReadOnly = isReadOnly || Bundle.main.bundleURL.pathExtension == "appex" return self.init(directoryURL: directoryURL.appendingPathComponent("com.loopkit.LoopKit", isDirectory: true), isReadOnly: isReadOnly) } - class func controllerInLocalDirectory() -> PersistenceController { + public class func controllerInLocalDirectory() -> PersistenceController { guard let directoryURL = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else { fatalError("Could not access the document directory of the current process") } diff --git a/Loop/Models/Result.swift b/LoopCore/Result.swift similarity index 85% rename from Loop/Models/Result.swift rename to LoopCore/Result.swift index b6763baf7c..580595159d 100644 --- a/Loop/Models/Result.swift +++ b/LoopCore/Result.swift @@ -6,7 +6,7 @@ // -enum Result { +public enum Result { case success(T) case failure(Error) } diff --git a/Common/Extensions/NibLoadable.swift b/LoopUI/Extensions/NibLoadable.swift similarity index 73% rename from Common/Extensions/NibLoadable.swift rename to LoopUI/Extensions/NibLoadable.swift index 4e762b2c69..00edfe2f6c 100644 --- a/Common/Extensions/NibLoadable.swift +++ b/LoopUI/Extensions/NibLoadable.swift @@ -7,15 +7,16 @@ // import UIKit +import LoopCore -protocol NibLoadable: IdentifiableClass { +public protocol NibLoadable: IdentifiableClass { static func nib() -> UINib } extension NibLoadable { - static func nib() -> UINib { + public static func nib() -> UINib { return UINib(nibName: className, bundle: Bundle(for: self)) } } diff --git a/LoopUI/Managers/StatusChartsManager.swift b/LoopUI/Managers/StatusChartsManager.swift index d605937b15..382115dfa6 100644 --- a/LoopUI/Managers/StatusChartsManager.swift +++ b/LoopUI/Managers/StatusChartsManager.swift @@ -8,6 +8,7 @@ import Foundation import HealthKit +import LoopCore import LoopKit import SwiftCharts import os.log diff --git a/WatchApp Extension/Controllers/ActionHUDController.swift b/WatchApp Extension/Controllers/ActionHUDController.swift index 71eef5a0f7..7729cb1fd0 100644 --- a/WatchApp Extension/Controllers/ActionHUDController.swift +++ b/WatchApp Extension/Controllers/ActionHUDController.swift @@ -9,6 +9,7 @@ import WatchKit import WatchConnectivity import LoopKit +import LoopCore final class ActionHUDController: HUDInterfaceController { diff --git a/WatchApp Extension/Managers/LoopDataManager.swift b/WatchApp Extension/Managers/LoopDataManager.swift index 4191ced26f..5195e950fc 100644 --- a/WatchApp Extension/Managers/LoopDataManager.swift +++ b/WatchApp Extension/Managers/LoopDataManager.swift @@ -9,6 +9,7 @@ import Foundation import HealthKit import LoopKit +import LoopCore import WatchConnectivity import os.log diff --git a/WatchApp Extension/Models/GlucoseChartData.swift b/WatchApp Extension/Models/GlucoseChartData.swift index 1be3f2d8d5..c45f24fa04 100644 --- a/WatchApp Extension/Models/GlucoseChartData.swift +++ b/WatchApp Extension/Models/GlucoseChartData.swift @@ -95,9 +95,9 @@ private extension HKUnit { var lowWatermark: Double { if self == .milligramsPerDeciliter { - return 50.0 + return 75 } else { - return 3.0 + return 3 } } }