Skip to content

Commit

Permalink
delta calculation/representation re-write for mmol/L
Browse files Browse the repository at this point in the history
Related to #JohanDegraeve#544

although the previous commits fixed the issue of erroneous (0 or close to 0) delta changes in mg/dL (the calculation was originally ported from an early xDrip+ many years ago), the mmol/L calculation has never been sufficiently accurate due to the conversion/rounding of mmol/L meaning that sometimes a +0.2mmol/L delta was actually calculated to +0.1mmol/L.

This changes fixes that and also updates the calculation and string representation methods for all instances in the app, Watch, Widgets etc

Also renamed a bunch of stuff to keep things constant over the whole project
  • Loading branch information
paulplant committed Oct 7, 2024
1 parent b871635 commit b3dfbe8
Show file tree
Hide file tree
Showing 51 changed files with 333 additions and 305 deletions.
14 changes: 5 additions & 9 deletions xDrip Notification Context Extension/NotificationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct NotificationView: View {
var bgReadingDates: [Date]?
var isMgDl: Bool?
var slopeOrdinal: Int?
var deltaChangeInMgDl: Double?
var deltaValueInUserUnit: Double?
var urgentLowLimitInMgDl: Double?
var lowLimitInMgDl: Double?
var highLimitInMgDl: Double?
Expand Down Expand Up @@ -104,17 +104,13 @@ struct NotificationView: View {
/// convert the optional delta change int (in mg/dL) to a formatted change value in the user chosen unit making sure all zero values are shown as a positive change to follow Nightscout convention
/// - Returns: a string holding the formatted delta change value (i.e. +0.4 or -6)
func deltaChangeStringInUserChosenUnit() -> String {
if let deltaChangeInMgDl = deltaChangeInMgDl, let isMgDl = isMgDl {
let deltaSign: String = deltaChangeInMgDl > 0 ? "+" : ""
let valueAsString = deltaChangeInMgDl.mgdlToMmolAndToString(mgdl: isMgDl)
if let deltaValueInUserUnit = deltaValueInUserUnit, let isMgDl = isMgDl {
let deltaSign: String = deltaValueInUserUnit > 0 ? "+" : ""
let deltaValueAsString = isMgDl ? deltaValueInUserUnit.mgDlToMmolAndToString(mgDl: isMgDl) : deltaValueInUserUnit.mmolToString()

// quickly check "value" and prevent "-0mg/dl" or "-0.0mmol/l" being displayed
// show unitized zero deltas as +0 or +0.0 as per Nightscout format
if isMgDl {
return (deltaChangeInMgDl > -1 && deltaChangeInMgDl < 1) ? "+0" : (deltaSign + valueAsString)
} else {
return (deltaChangeInMgDl > -0.1 && deltaChangeInMgDl < 0.1) ? "+0.0" : (deltaSign + valueAsString)
}
return deltaValueInUserUnit == 0.0 ? (isMgDl ? "+0" : "+0.0") : (deltaSign + deltaValueAsString)
} else {
return (isMgDl ?? true) ? "-" : "-.-"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
var bgReadingDates: [Date]?
var isMgDl: Bool?
var slopeOrdinal: Int?
var deltaChangeInMgDl: Double?
var deltaValueInUserUnit: Double?
var urgentLowLimitInMgDl: Double?
var lowLimitInMgDl: Double?
var highLimitInMgDl: Double?
Expand Down Expand Up @@ -50,7 +50,7 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
bgReadingValues = userInfo["bgReadingValues"] as? [Double] ?? [0]
isMgDl = userInfo["isMgDl"] as? Bool ?? true
slopeOrdinal = userInfo["slopeOrdinal"] as? Int ?? 0
deltaChangeInMgDl = userInfo["deltaChangeInMgDl"] as? Double ?? 0
deltaValueInUserUnit = userInfo["deltaValueInUserUnit"] as? Double ?? 0
urgentLowLimitInMgDl = userInfo["urgentLowLimitInMgDl"] as? Double ?? 0
lowLimitInMgDl = userInfo["lowLimitInMgDl"] as? Double ?? 0
highLimitInMgDl = userInfo["highLimitInMgDl"] as? Double ?? 0
Expand All @@ -65,15 +65,15 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
bgValueInMgDl = (bgReadingValues?.count ?? 0) > 0 ? bgReadingValues?[0] : nil
bgReadingDate = (bgReadingDates?.count ?? 0) > 0 ? bgReadingDates?[0] : nil

bgValueStringInUserChosenUnit = (bgReadingValues?.count ?? 0) > 0 ? bgReadingValues?[0].mgdlToMmolAndToString(mgdl: isMgDl ?? true) ?? "" : ""
bgValueStringInUserChosenUnit = (bgReadingValues?.count ?? 0) > 0 ? bgReadingValues?[0].mgDlToMmolAndToString(mgDl: isMgDl ?? true) ?? "" : ""

let vc = UIHostingController(rootView: NotificationView(
alertTitle: alertTitle,
bgReadingValues: bgReadingValues,
bgReadingDates: bgReadingDates,
isMgDl: isMgDl,
slopeOrdinal: slopeOrdinal,
deltaChangeInMgDl: deltaChangeInMgDl,
deltaValueInUserUnit: deltaValueInUserUnit,
urgentLowLimitInMgDl: urgentLowLimitInMgDl,
lowLimitInMgDl: lowLimitInMgDl,
highLimitInMgDl: highLimitInMgDl,
Expand Down
8 changes: 4 additions & 4 deletions xDrip Watch App/DataModels/NotificationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class NotificationController: WKUserNotificationHostingController<NotificationVi
var bgReadingDates: [Date]?
var isMgDl: Bool?
var slopeOrdinal: Int?
var deltaChangeInMgDl: Double?
var deltaValueInUserUnit: Double?
var urgentLowLimitInMgDl: Double?
var lowLimitInMgDl: Double?
var highLimitInMgDl: Double?
Expand All @@ -35,7 +35,7 @@ class NotificationController: WKUserNotificationHostingController<NotificationVi
bgReadingDates: bgReadingDates,
isMgDl: isMgDl,
slopeOrdinal: slopeOrdinal,
deltaChangeInMgDl: deltaChangeInMgDl,
deltaValueInUserUnit: deltaValueInUserUnit,
urgentLowLimitInMgDl: urgentLowLimitInMgDl,
lowLimitInMgDl: lowLimitInMgDl,
highLimitInMgDl: highLimitInMgDl,
Expand All @@ -61,7 +61,7 @@ class NotificationController: WKUserNotificationHostingController<NotificationVi
bgReadingValues = userInfo["bgReadingValues"] as? [Double] ?? [0]
isMgDl = userInfo["isMgDl"] as? Bool ?? true
slopeOrdinal = userInfo["slopeOrdinal"] as? Int ?? 0
deltaChangeInMgDl = userInfo["deltaChangeInMgDl"] as? Double ?? 0
deltaValueInUserUnit = userInfo["deltaValueInUserUnit"] as? Double ?? 0
urgentLowLimitInMgDl = userInfo["urgentLowLimitInMgDl"] as? Double ?? 0
lowLimitInMgDl = userInfo["lowLimitInMgDl"] as? Double ?? 0
highLimitInMgDl = userInfo["highLimitInMgDl"] as? Double ?? 0
Expand All @@ -76,7 +76,7 @@ class NotificationController: WKUserNotificationHostingController<NotificationVi
bgValueInMgDl = (bgReadingValues?.count ?? 0) > 0 ? bgReadingValues?[0] : nil
bgReadingDate = (bgReadingDates?.count ?? 0) > 0 ? bgReadingDates?[0] : nil

bgValueStringInUserChosenUnit = (bgReadingValues?.count ?? 0) > 0 ? bgReadingValues?[0].mgdlToMmolAndToString(mgdl: isMgDl ?? true) ?? "" : ""
bgValueStringInUserChosenUnit = (bgReadingValues?.count ?? 0) > 0 ? bgReadingValues?[0].mgDlToMmolAndToString(mgDl: isMgDl ?? true) ?? "" : ""

}
}
29 changes: 10 additions & 19 deletions xDrip Watch App/DataModels/WatchStateModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class WatchStateModel: NSObject, ObservableObject {

@Published var isMgDl: Bool = true
@Published var slopeOrdinal: Int = 2
@Published var deltaChangeInMgDl: Double = 0
@Published var deltaValueInUserUnit: Double = 0
@Published var urgentLowLimitInMgDl: Double = 60
@Published var lowLimitInMgDl: Double = 80
@Published var highLimitInMgDl: Double = 170
Expand Down Expand Up @@ -85,7 +85,7 @@ final class WatchStateModel: NSObject, ObservableObject {
/// - Returns: a string with bgValueInMgDl() converted into the user unit
func bgValueStringInUserChosenUnit() -> String {
if let bgReadingDate = bgReadingDate(), let bgValueInMgDl = bgValueInMgDl(), bgReadingDate > Date().addingTimeInterval(-60 * 20) {
return bgReadingValues.isEmpty ? (isMgDl ? "---" : "-.-") : bgValueInMgDl.mgdlToMmolAndToString(mgdl: isMgDl)
return bgReadingValues.isEmpty ? (isMgDl ? "---" : "-.-") : bgValueInMgDl.mgDlToMmolAndToString(mgDl: isMgDl)
} else {
return isMgDl ? "---" : "-.-"
}
Expand Down Expand Up @@ -181,26 +181,17 @@ final class WatchStateModel: NSObject, ObservableObject {
/// - Returns: a string holding the formatted delta change value (i.e. +0.4 or -6)
func deltaChangeStringInUserChosenUnit() -> String {
if let bgReadingDate = bgReadingDate(), bgReadingDate > Date().addingTimeInterval(-60 * 20) {
let valueAsString = deltaChangeInMgDl.mgdlToMmolAndToString(mgdl: isMgDl)
let deltaValueAsString = isMgDl ? deltaValueInUserUnit.mgDlToMmolAndToString(mgDl: isMgDl) : deltaValueInUserUnit.mmolToString()

var deltaSign: String = ""
if (deltaChangeInMgDl > 0) { deltaSign = "+"; }

if deltaValueInUserUnit > 0 {
deltaSign = "+"
}

// quickly check "value" and prevent "-0mg/dl" or "-0.0mmol/l" being displayed
// show unitized zero deltas as +0 or +0.0 as per Nightscout format
if (isMgDl) {
if (deltaChangeInMgDl > -1) && (deltaChangeInMgDl < 1) {
return "+0"
} else {
return deltaSign + valueAsString
}
} else {
if (deltaChangeInMgDl > -0.1) && (deltaChangeInMgDl < 0.1) {
return "+0.0"
} else {
return deltaSign + valueAsString
}
}
return deltaValueInUserUnit == 0.0 ? (isMgDl ? "+0" : "+0.0") : (deltaSign + deltaValueAsString)
} else {
return "-"
}
Expand Down Expand Up @@ -353,7 +344,7 @@ final class WatchStateModel: NSObject, ObservableObject {

isMgDl = dictionary["isMgDl"] as? Bool ?? true
slopeOrdinal = dictionary["slopeOrdinal"] as? Int ?? 0
deltaChangeInMgDl = dictionary["deltaChangeInMgDl"] as? Double ?? 0
deltaValueInUserUnit = dictionary["deltaValueInUserUnit"] as? Double ?? 0
urgentLowLimitInMgDl = dictionary["urgentLowLimitInMgDl"] as? Double ?? 60
lowLimitInMgDl = dictionary["lowLimitInMgDl"] as? Double ?? 70
highLimitInMgDl = dictionary["highLimitInMgDl"] as? Double ?? 180
Expand Down Expand Up @@ -399,7 +390,7 @@ final class WatchStateModel: NSObject, ObservableObject {
date.timeIntervalSince1970
}

let complicationSharedUserDefaultsModel = ComplicationSharedUserDefaultsModel(bgReadingValues: bgReadingValues, bgReadingDatesAsDouble: bgReadingDatesAsDouble, isMgDl: isMgDl, slopeOrdinal: slopeOrdinal, deltaChangeInMgDl: deltaChangeInMgDl, urgentLowLimitInMgDl: urgentLowLimitInMgDl, lowLimitInMgDl: lowLimitInMgDl, highLimitInMgDl: highLimitInMgDl, urgentHighLimitInMgDl: urgentHighLimitInMgDl, keepAliveIsDisabled: keepAliveIsDisabled, liveDataIsEnabled: liveDataIsEnabled)
let complicationSharedUserDefaultsModel = ComplicationSharedUserDefaultsModel(bgReadingValues: bgReadingValues, bgReadingDatesAsDouble: bgReadingDatesAsDouble, isMgDl: isMgDl, slopeOrdinal: slopeOrdinal, deltaValueInUserUnit: deltaValueInUserUnit, urgentLowLimitInMgDl: urgentLowLimitInMgDl, lowLimitInMgDl: lowLimitInMgDl, highLimitInMgDl: highLimitInMgDl, urgentHighLimitInMgDl: urgentHighLimitInMgDl, keepAliveIsDisabled: keepAliveIsDisabled, liveDataIsEnabled: liveDataIsEnabled)

// store the model in the shared user defaults using a name that is uniquely specific to this copy of the app as installed on
// the user's device - this allows several copies of the app to be installed without cross-contamination of widget/complication data
Expand Down
2 changes: 1 addition & 1 deletion xDrip Watch App/Views/BigNumberView/BigNumberView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ struct BigNumberView_Previews: PreviewProvider {
watchState.bgReadingDates = bgDateArray()
watchState.isMgDl = true
watchState.slopeOrdinal = 5
watchState.deltaChangeInMgDl = -2
watchState.deltaValueInUserUnit = -2
watchState.urgentLowLimitInMgDl = 60
watchState.lowLimitInMgDl = 80
watchState.highLimitInMgDl = 180
Expand Down
2 changes: 1 addition & 1 deletion xDrip Watch App/Views/MainView/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ struct ContentView_Previews: PreviewProvider {
watchState.bgReadingDates = bgDateArray()
watchState.isMgDl = false
watchState.slopeOrdinal = 3
watchState.deltaChangeInMgDl = 2
watchState.deltaValueInUserUnit = 2
watchState.urgentLowLimitInMgDl = 60
watchState.lowLimitInMgDl = 80
watchState.highLimitInMgDl = 140
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ struct MainViewDataSourceView_Previews: PreviewProvider {
watchState.bgReadingDates = bgDateArray()
watchState.isMgDl = true
watchState.slopeOrdinal = 5
watchState.deltaChangeInMgDl = -2
watchState.deltaValueInUserUnit = -2
watchState.urgentLowLimitInMgDl = 60
watchState.lowLimitInMgDl = 80
watchState.highLimitInMgDl = 140
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ struct MainViewHeaderView_Previews: PreviewProvider {
watchState.bgReadingDates = bgDateArray()
watchState.isMgDl = true
watchState.slopeOrdinal = 5
watchState.deltaChangeInMgDl = -2
watchState.deltaValueInUserUnit = -2
watchState.urgentLowLimitInMgDl = 60
watchState.lowLimitInMgDl = 80
watchState.highLimitInMgDl = 140
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ struct MainViewInfoView_Previews: PreviewProvider {
watchState.bgReadingDates = bgDateArray()
watchState.isMgDl = true
watchState.slopeOrdinal = 5
watchState.deltaChangeInMgDl = -2
watchState.deltaValueInUserUnit = -2
watchState.urgentLowLimitInMgDl = 60
watchState.lowLimitInMgDl = 80
watchState.highLimitInMgDl = 140
Expand Down
14 changes: 5 additions & 9 deletions xDrip Watch App/Views/NotificationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct NotificationView: View {
var bgReadingDates: [Date]?
var isMgDl: Bool?
var slopeOrdinal: Int?
var deltaChangeInMgDl: Double?
var deltaValueInUserUnit: Double?
var urgentLowLimitInMgDl: Double?
var lowLimitInMgDl: Double?
var highLimitInMgDl: Double?
Expand Down Expand Up @@ -110,17 +110,13 @@ struct NotificationView: View {
/// convert the optional delta change int (in mg/dL) to a formatted change value in the user chosen unit making sure all zero values are shown as a positive change to follow Nightscout convention
/// - Returns: a string holding the formatted delta change value (i.e. +0.4 or -6)
func deltaChangeStringInUserChosenUnit() -> String {
if let deltaChangeInMgDl = deltaChangeInMgDl, let isMgDl = isMgDl {
let deltaSign: String = deltaChangeInMgDl > 0 ? "+" : ""
let valueAsString = deltaChangeInMgDl.mgdlToMmolAndToString(mgdl: isMgDl)
if let deltaValueInUserUnit = deltaValueInUserUnit, let isMgDl = isMgDl {
let deltaSign: String = deltaValueInUserUnit > 0 ? "+" : ""
let deltaValueAsString = isMgDl ? deltaValueInUserUnit.mgDlToMmolAndToString(mgDl: isMgDl) : deltaValueInUserUnit.mmolToString()

// quickly check "value" and prevent "-0mg/dl" or "-0.0mmol/l" being displayed
// show unitized zero deltas as +0 or +0.0 as per Nightscout format
if isMgDl {
return (deltaChangeInMgDl > -1 && deltaChangeInMgDl < 1) ? "+0" : (deltaSign + valueAsString)
} else {
return (deltaChangeInMgDl > -0.1 && deltaChangeInMgDl < 0.1) ? "+0.0" : (deltaSign + valueAsString)
}
return deltaValueInUserUnit == 0.0 ? (isMgDl ? "+0" : "+0.0") : (deltaSign + deltaValueAsString)
} else {
return (isMgDl ?? true) ? "-" : "-.-"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct ComplicationSharedUserDefaultsModel: Codable {
var bgReadingDatesAsDouble: [Double]
var isMgDl: Bool
var slopeOrdinal: Int
var deltaChangeInMgDl: Double
var deltaValueInUserUnit: Double
var urgentLowLimitInMgDl: Double
var lowLimitInMgDl: Double
var highLimitInMgDl: Double
Expand Down
4 changes: 2 additions & 2 deletions xDrip Watch Complication/Views/AccessoryCircularView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ extension XDripWatchComplication.EntryView {
.minimumScaleFactor(0.2)
.lineLimit(1)
} minimumValueLabel: {
Text(entry.widgetState.gaugeModel().minValue.mgdlToMmolAndToString(mgdl: entry.widgetState.isMgDl))
Text(entry.widgetState.gaugeModel().minValue.mgDlToMmolAndToString(mgDl: entry.widgetState.isMgDl))
.font(.system(size: 8))
.foregroundStyle(.colorPrimary)
.minimumScaleFactor(0.2)
} maximumValueLabel: {
Text(entry.widgetState.gaugeModel().maxValue.mgdlToMmolAndToString(mgdl: entry.widgetState.isMgDl))
Text(entry.widgetState.gaugeModel().maxValue.mgDlToMmolAndToString(mgDl: entry.widgetState.isMgDl))
.font(.system(size: 8))
.foregroundStyle(.colorPrimary)
.minimumScaleFactor(0.2)
Expand Down
4 changes: 2 additions & 2 deletions xDrip Watch Complication/Views/AccessoryCornerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ extension XDripWatchComplication.EntryView {
} currentValueLabel: {
Text("Not shown")
} minimumValueLabel: {
Text(entry.widgetState.gaugeModel().minValue.mgdlToMmolAndToString(mgdl: entry.widgetState.isMgDl))
Text(entry.widgetState.gaugeModel().minValue.mgDlToMmolAndToString(mgDl: entry.widgetState.isMgDl))
.font(.system(size: 8))
.foregroundStyle(.colorPrimary)
.minimumScaleFactor(0.2)
} maximumValueLabel: {
Text(entry.widgetState.gaugeModel().maxValue.mgdlToMmolAndToString(mgdl: entry.widgetState.isMgDl))
Text(entry.widgetState.gaugeModel().maxValue.mgDlToMmolAndToString(mgDl: entry.widgetState.isMgDl))
.font(.system(size: 8))
.foregroundStyle(.colorPrimary)
.minimumScaleFactor(0.2)
Expand Down
Loading

0 comments on commit b3dfbe8

Please sign in to comment.