Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #387

Closed
wants to merge 37 commits into from
Closed

Dev #387

Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
93111d5
Open the app when the user taps on the widget
Dec 23, 2016
bdb02ab
Use MAIN_APP_BUNDLE_IDENTIFIER instead of hardcoding "Loop" as the UR…
Dec 23, 2016
82dc3da
Improve string concatenation style
Dec 23, 2016
67f0c3d
Merge pull request #334 from bharat/tap-opens-app
ps2 Dec 25, 2016
21ace16
Fix widget battery level for x22 pumps
wkcwells Dec 27, 2016
378b525
Fix broken build.
Dec 29, 2016
51b09c1
Merge pull request #346 from bharat/fix-build
ps2 Dec 30, 2016
2058195
Merge pull request #342 from wkcwells/fix-battery-in-widget
ps2 Dec 30, 2016
0b7afad
Merge pull request #340 from LoopKit/update-rl-frameworks
ps2 Dec 30, 2016
a3558d4
Refactor HUD views into LoopUI framework (#284) (#330)
Jan 1, 2017
d540cce
Monitor changes and update the widget in real time. (#335)
Jan 2, 2017
311ba44
Use a clear fill color for the circle. (#355)
Jan 2, 2017
9566eac
Refactor files with membership in multiple targets into a Common hier…
Jan 2, 2017
9d3cfad
Disable animation on first render, since we'd be animating from a (#354)
Jan 2, 2017
9d9890b
Enforce a fixed number of fractional digits per unit type. (#356)
Jan 5, 2017
7e221ee
Add an info.plist entry to widget info.plist to make tapping on widge…
wkcwells Jan 5, 2017
aac86be
Only allow one active glucose data source (#364)
Feb 11, 2017
f1e4342
Upgrade project to 0820 (#376)
Feb 13, 2017
c262b64
Merge complications changes back into dev (they were accidentally mer…
ps2 Feb 16, 2017
a0b425b
Merge branch 'master' into dev
ps2 Feb 16, 2017
bb7cb32
Merge branch 'master' into dev
ps2 Feb 16, 2017
1775f42
Tmecklem x22 enlite cgm (#378)
ps2 Feb 19, 2017
3ba50da
remove +ve momentum from bolus calculation (#372)
thebookins Feb 19, 2017
08591de
Minimum bg guard (#365)
ps2 Feb 20, 2017
841a366
Update LoopKit and Rileylink frameworks
ps2 Feb 20, 2017
3ae1077
Merge pull request #380 from LoopKit/update-frameworks
ps2 Feb 20, 2017
93da3d4
Bump version
ps2 Feb 20, 2017
59ce749
Merge pull request #381 from LoopKit/bump-version
ps2 Feb 20, 2017
27017e6
Show bg values in warning messages in bolus ui
ps2 Feb 24, 2017
cb394ca
Do not show last loop errors in bolus view; only recommendation alerts
ps2 Feb 24, 2017
2b6e739
Show last loop error on clicking loop status
ps2 Feb 24, 2017
32764bc
Use tap gesture recognizer instead of delegate
ps2 Feb 25, 2017
6ccc578
remove extraneous line
ps2 Feb 25, 2017
ef9f943
Add recovery text for configuration alerts, and single out minimum bg…
ps2 Feb 25, 2017
1a47658
Merge pull request #384 from LoopKit/last-loop-error
ps2 Feb 25, 2017
c92e780
Merge pull request #382 from LoopKit/bolus-ui-updates
ps2 Feb 25, 2017
e8b207e
Add mmol watchapp units support. Add modularLarge complication. Chang…
walker0 Mar 2, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Loop/Managers/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ final class DeviceDataManager: CarbStoreDelegate, CarbStoreSyncDelegate, DoseSto
*/
private func readPumpData(_ completion: @escaping (RileyLinkKit.Either<(status: RileyLinkKit.PumpStatus, date: Date), Error>) -> Void) {
guard let device = rileyLinkManager.firstConnectedDevice, let ops = device.ops else {
completion(.failure(LoopError.configurationError))
completion(.failure(LoopError.connectionError))
return
}

Expand All @@ -366,8 +366,9 @@ final class DeviceDataManager: CarbStoreDelegate, CarbStoreSyncDelegate, DoseSto
clock.timeZone = ops.pumpState.timeZone

guard let date = clock.date else {
self.logger.addError("Could not interpret pump clock: \(clock)", fromSource: "RileyLink")
completion(.failure(LoopError.configurationError))
let errorStr = "Could not interpret pump clock: \(clock)"
self.logger.addError(errorStr, fromSource: "RileyLink")
completion(.failure(LoopError.invalidData(details: errorStr)))
return
}
completion(.success(status: status, date: date))
Expand Down Expand Up @@ -435,7 +436,7 @@ final class DeviceDataManager: CarbStoreDelegate, CarbStoreSyncDelegate, DoseSto
}

guard let ops = device.ops else {
completion(LoopError.configurationError)
completion(LoopError.configurationError("PumpOps"))
return
}

Expand Down
42 changes: 24 additions & 18 deletions Loop/Managers/LoopDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ final class LoopDataManager {
private func getPendingInsulin() throws -> Double {

guard let basalRates = deviceDataManager.basalRateSchedule else {
throw LoopError.configurationError
throw LoopError.configurationError("Basal Rate Schedule")
}

let pendingTempBasalInsulin: Double
Expand All @@ -301,7 +301,7 @@ final class LoopDataManager {
guard let
glucose = self.deviceDataManager.glucoseStore?.latestGlucose
else {
resultsHandler(nil, LoopError.missingDataError("Cannot predict glucose due to missing input data"))
resultsHandler(nil, LoopError.missingDataError(details: "Cannot predict glucose due to missing input data", recovery: "Check your CGM data source"))
return
}

Expand Down Expand Up @@ -433,7 +433,7 @@ final class LoopDataManager {

private func updateCarbEffect(_ completionHandler: @escaping (_ effects: [GlucoseEffect]?, _ error: Error?) -> Void) {
guard let effectStartDate = effectStartDate else {
completionHandler(nil, LoopError.missingDataError("Glucose data not available"))
completionHandler(nil, LoopError.missingDataError(details: "Glucose data not available", recovery: "Check your CGM data source"))
return
}

Expand All @@ -446,7 +446,7 @@ final class LoopDataManager {
completionHandler(effects, error)
}
} else {
completionHandler(nil, LoopError.missingDataError("CarbStore not available"))
completionHandler(nil, LoopError.missingDataError(details: "CarbStore not available", recovery: nil))
}
}

Expand All @@ -462,7 +462,7 @@ final class LoopDataManager {

private func updateGlucoseMomentumEffect(_ completionHandler: @escaping (_ effects: [GlucoseEffect]?, _ error: Error?) -> Void) {
guard let glucoseStore = deviceDataManager.glucoseStore else {
completionHandler(nil, LoopError.missingDataError("GlucoseStore not available"))
completionHandler(nil, LoopError.missingDataError(details: "GlucoseStore not available", recovery: nil))
return
}
glucoseStore.getRecentMomentumEffect { (effects, error) -> Void in
Expand All @@ -485,7 +485,7 @@ final class LoopDataManager {
let insulinEffect = self.insulinEffect
else {
self.retrospectivePredictedGlucose = nil
throw LoopError.missingDataError("Cannot retrospect glucose due to missing input data")
throw LoopError.missingDataError(details: "Cannot retrospect glucose due to missing input data", recovery: nil)
}

guard let change = glucoseChange else {
Expand Down Expand Up @@ -525,14 +525,14 @@ final class LoopDataManager {
glucose = self.deviceDataManager.glucoseStore?.latestGlucose
else {
self.predictedGlucose = nil
throw LoopError.missingDataError("Glucose")
throw LoopError.missingDataError(details: "Glucose", recovery: "Check your CGM data source")
}

guard let
pumpStatusDate = self.deviceDataManager.doseStore.lastReservoirValue?.startDate
else {
self.predictedGlucose = nil
throw LoopError.missingDataError("Reservoir")
throw LoopError.missingDataError(details: "Reservoir", recovery: "Check that your pump is in range")
}

let startDate = Date()
Expand All @@ -556,7 +556,7 @@ final class LoopDataManager {
let insulinEffect = self.insulinEffect else
{
self.predictedGlucose = nil
throw LoopError.missingDataError("Glucose effects")
throw LoopError.missingDataError(details: "Glucose effects", recovery: nil)
}

var error: Error?
Expand Down Expand Up @@ -604,14 +604,17 @@ final class LoopDataManager {
self.predictedGlucose = retrospectiveCorrectionEnabled ? predictionWithRetrospectiveEffect : prediction
self.predictedGlucoseWithoutMomentum = predictionWithoutMomentum

guard let minimumBGGuard = self.deviceDataManager.minimumBGGuard else {
throw LoopError.configurationError("Minimum BG Guard")
}

guard let
maxBasal = deviceDataManager.maximumBasalRatePerHour,
let glucoseTargetRange = deviceDataManager.glucoseTargetRangeSchedule,
let insulinSensitivity = deviceDataManager.insulinSensitivitySchedule,
let basalRates = deviceDataManager.basalRateSchedule,
let minimumBGGuard = deviceDataManager.minimumBGGuard
let basalRates = deviceDataManager.basalRateSchedule
else {
error = LoopError.configurationError
error = LoopError.configurationError("Check settings")
throw error!
}

Expand Down Expand Up @@ -655,27 +658,30 @@ final class LoopDataManager {
}
}
} else {
resultsHandler(nil, LoopError.configurationError)
resultsHandler(nil, LoopError.configurationError("Carb Store"))
}
}

private func recommendBolus() throws -> BolusRecommendation {
guard let minimumBGGuard = self.deviceDataManager.minimumBGGuard else {
throw LoopError.configurationError("Minimum BG Guard")
}

guard let
glucose = self.predictedGlucose,
let glucoseWithoutMomentum = self.predictedGlucoseWithoutMomentum,
let maxBolus = self.deviceDataManager.maximumBolus,
let glucoseTargetRange = self.deviceDataManager.glucoseTargetRangeSchedule,
let insulinSensitivity = self.deviceDataManager.insulinSensitivitySchedule,
let basalRates = self.deviceDataManager.basalRateSchedule,
let minimumBGGuard = self.deviceDataManager.minimumBGGuard
let basalRates = self.deviceDataManager.basalRateSchedule
else {
throw LoopError.configurationError
throw LoopError.configurationError("Check Settings")
}

let recencyInterval = TimeInterval(minutes: 15)

guard let glucoseDate = glucose.first?.startDate else {
throw LoopError.missingDataError("No glucose data found")
throw LoopError.missingDataError(details: "No glucose data found", recovery: "Check your CGM source")
}

guard abs(glucoseDate.timeIntervalSinceNow) <= recencyInterval else {
Expand Down Expand Up @@ -737,7 +743,7 @@ final class LoopDataManager {
}

guard let ops = device.ops else {
resultsHandler(false, LoopError.configurationError)
resultsHandler(false, LoopError.configurationError("PumpOps"))
return
}

Expand Down
27 changes: 21 additions & 6 deletions Loop/Models/LoopError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ enum LoopError: Error {
case communicationError

// Missing or unexpected configuration values
case configurationError
case configurationError(String)

// No connected devices, or failure during device connection
case connectionError

// Missing required data to perform an action
case missingDataError(String)
// Missing data required to perform an action
case missingDataError(details: String, recovery: String?)

// Glucose data is too old to perform action
case glucoseTooOld(date: Date)
Expand All @@ -29,10 +29,22 @@ enum LoopError: Error {

// Recommendation Expired
case recommendationExpired(date: Date)

// Invalid Data
case invalidData(details: String)
}

extension LoopError: LocalizedError {

public var recoverySuggestion: String? {
switch self {
case .missingDataError(_, let recovery):
return recovery;
default:
return nil;
}
}

public var errorDescription: String? {

let formatter = DateComponentsFormatter()
Expand All @@ -42,11 +54,11 @@ extension LoopError: LocalizedError {
switch self {
case .communicationError:
return NSLocalizedString("Communication Error", comment: "The error message displayed after a communication error.")
case .configurationError:
return NSLocalizedString("Configuration Error", comment: "The error message displayed for configuration errors.")
case .configurationError(let details):
return String(format: NSLocalizedString("Configuration Error: %1$@", comment: "The error message displayed for configuration errors. (1: configuration error details)"), details)
case .connectionError:
return NSLocalizedString("No connected devices, or failure during device connection", comment: "The error message displayed for device connection errors.")
case .missingDataError(let details):
case .missingDataError(let details, _):
return String(format: NSLocalizedString("Missing data: %1$@", comment: "The error message for missing data. (1: missing data details)"), details)
case .glucoseTooOld(let date):
let minutes = formatter.string(from: -date.timeIntervalSinceNow) ?? ""
Expand All @@ -57,6 +69,9 @@ extension LoopError: LocalizedError {
case .recommendationExpired(let date):
let minutes = formatter.string(from: -date.timeIntervalSinceNow) ?? ""
return String(format: NSLocalizedString("Recommendation expired: %1$@ old", comment: "The error message when a recommendation has expired. (1: age of recommendation in minutes)"), minutes)
case .invalidData(let details):
return String(format: NSLocalizedString("Invalid data: %1$@", comment: "The error message when invalid data was encountered. (1: details of invalid data)"), details)

}
}
}
Expand Down
15 changes: 13 additions & 2 deletions Loop/View Controllers/StatusTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -771,12 +771,15 @@ final class StatusTableViewController: UITableViewController, UIGestureRecognize

@IBOutlet weak var hudView: HUDView! {
didSet {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openCGMApp(_:)))
glucoseHUD.addGestureRecognizer(tapGestureRecognizer)
let glucoseTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openCGMApp(_:)))
glucoseHUD.addGestureRecognizer(glucoseTapGestureRecognizer)

if cgmAppURL != nil {
glucoseHUD.accessibilityHint = NSLocalizedString("Launches CGM app", comment: "Glucose HUD accessibility hint")
}
let statusTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showLastError(_:)))
loopCompletionHUD.addGestureRecognizer(statusTapGestureRecognizer)
loopCompletionHUD.accessibilityHint = NSLocalizedString("Show last loop error", comment: "Loop Completion HUD accessibility hint")
}
}

Expand All @@ -802,6 +805,14 @@ final class StatusTableViewController: UITableViewController, UIGestureRecognize
}
}

@objc private func showLastError(_: Any) {
self.dataManager.loopManager.getLoopStatus { (_, _, _, _, _, _, _, error) -> Void in
if let error = error {
self.presentAlertController(with: error)
}
}
}

@objc private func openCGMApp(_: Any) {
if let url = cgmAppURL {
UIApplication.shared.open(url)
Expand Down