|
@@ -37,8 +37,10 @@ struct MainChartView: View {
|
|
|
@Binding var suggestion: Suggestion?
|
|
@Binding var suggestion: Suggestion?
|
|
|
@Binding var tempBasals: [PumpHistoryEvent]
|
|
@Binding var tempBasals: [PumpHistoryEvent]
|
|
|
@Binding var boluses: [PumpHistoryEvent]
|
|
@Binding var boluses: [PumpHistoryEvent]
|
|
|
|
|
+ @Binding var suspensions: [PumpHistoryEvent]
|
|
|
@Binding var hours: Int
|
|
@Binding var hours: Int
|
|
|
@Binding var maxBasal: Decimal
|
|
@Binding var maxBasal: Decimal
|
|
|
|
|
+ @Binding var autotunedBasalProfile: [BasalProfileEntry]
|
|
|
@Binding var basalProfile: [BasalProfileEntry]
|
|
@Binding var basalProfile: [BasalProfileEntry]
|
|
|
@Binding var tempTargets: [TempTarget]
|
|
@Binding var tempTargets: [TempTarget]
|
|
|
@Binding var carbs: [CarbsEntry]
|
|
@Binding var carbs: [CarbsEntry]
|
|
@@ -53,6 +55,7 @@ struct MainChartView: View {
|
|
|
@State private var tempBasalPath = Path()
|
|
@State private var tempBasalPath = Path()
|
|
|
@State private var regularBasalPath = Path()
|
|
@State private var regularBasalPath = Path()
|
|
|
@State private var tempTargetsPath = Path()
|
|
@State private var tempTargetsPath = Path()
|
|
|
|
|
+ @State private var suspensionsPath = Path()
|
|
|
@State private var carbsDots: [DotInfo] = []
|
|
@State private var carbsDots: [DotInfo] = []
|
|
|
@State private var carbsPath = Path()
|
|
@State private var carbsPath = Path()
|
|
|
@State private var glucoseYGange: GlucoseYRange = (0, 0, 0, 0)
|
|
@State private var glucoseYGange: GlucoseYRange = (0, 0, 0, 0)
|
|
@@ -162,6 +165,7 @@ struct MainChartView: View {
|
|
|
ZStack {
|
|
ZStack {
|
|
|
tempBasalPath.fill(Color.tempBasal)
|
|
tempBasalPath.fill(Color.tempBasal)
|
|
|
tempBasalPath.stroke(Color.tempBasal, lineWidth: 1)
|
|
tempBasalPath.stroke(Color.tempBasal, lineWidth: 1)
|
|
|
|
|
+ suspensionsPath.fill(Color.loopGray)
|
|
|
regularBasalPath.stroke(Color.basal, lineWidth: 1)
|
|
regularBasalPath.stroke(Color.basal, lineWidth: 1)
|
|
|
}
|
|
}
|
|
|
.frame(width: fullGlucoseWidth(viewWidth: fullSize.width) + additionalWidth(viewWidth: fullSize.width))
|
|
.frame(width: fullGlucoseWidth(viewWidth: fullSize.width) + additionalWidth(viewWidth: fullSize.width))
|
|
@@ -170,10 +174,13 @@ struct MainChartView: View {
|
|
|
.onChange(of: tempBasals) { _ in
|
|
.onChange(of: tempBasals) { _ in
|
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
|
}
|
|
}
|
|
|
|
|
+ .onChange(of: suspensions) { _ in
|
|
|
|
|
+ calculateSuspensions(fullSize: fullSize)
|
|
|
|
|
+ }
|
|
|
.onChange(of: maxBasal) { _ in
|
|
.onChange(of: maxBasal) { _ in
|
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
|
}
|
|
}
|
|
|
- .onChange(of: basalProfile) { _ in
|
|
|
|
|
|
|
+ .onChange(of: autotunedBasalProfile) { _ in
|
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
|
}
|
|
}
|
|
|
.onChange(of: didAppearTrigger) { _ in
|
|
.onChange(of: didAppearTrigger) { _ in
|
|
@@ -360,6 +367,7 @@ extension MainChartView {
|
|
|
calculateTempTargetsRects(fullSize: fullSize)
|
|
calculateTempTargetsRects(fullSize: fullSize)
|
|
|
calculateTempTargetsRects(fullSize: fullSize)
|
|
calculateTempTargetsRects(fullSize: fullSize)
|
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
|
|
|
+ calculateSuspensions(fullSize: fullSize)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func calculateGlucoseDots(fullSize: CGSize) {
|
|
private func calculateGlucoseDots(fullSize: CGSize) {
|
|
@@ -458,7 +466,8 @@ extension MainChartView {
|
|
|
let firstRegularBasalPoints = findRegularBasalPoints(
|
|
let firstRegularBasalPoints = findRegularBasalPoints(
|
|
|
timeBegin: dayAgoTime,
|
|
timeBegin: dayAgoTime,
|
|
|
timeEnd: firstTempTime,
|
|
timeEnd: firstTempTime,
|
|
|
- fullSize: fullSize
|
|
|
|
|
|
|
+ fullSize: fullSize,
|
|
|
|
|
+ autotuned: false
|
|
|
)
|
|
)
|
|
|
let tempBasalPoints = firstRegularBasalPoints + tempBasals.chunks(ofCount: 2).map { chunk -> [CGPoint] in
|
|
let tempBasalPoints = firstRegularBasalPoints + tempBasals.chunks(ofCount: 2).map { chunk -> [CGPoint] in
|
|
|
let chunk = Array(chunk)
|
|
let chunk = Array(chunk)
|
|
@@ -468,7 +477,12 @@ extension MainChartView {
|
|
|
let rateCost = Config.basalHeight / CGFloat(maxBasalRate())
|
|
let rateCost = Config.basalHeight / CGFloat(maxBasalRate())
|
|
|
let x0 = timeToXCoordinate(timeBegin, fullSize: fullSize)
|
|
let x0 = timeToXCoordinate(timeBegin, fullSize: fullSize)
|
|
|
let y0 = Config.basalHeight - CGFloat(chunk[0].rate ?? 0) * rateCost
|
|
let y0 = Config.basalHeight - CGFloat(chunk[0].rate ?? 0) * rateCost
|
|
|
- let regularPoints = findRegularBasalPoints(timeBegin: lastTimeEnd, timeEnd: timeBegin, fullSize: fullSize)
|
|
|
|
|
|
|
+ let regularPoints = findRegularBasalPoints(
|
|
|
|
|
+ timeBegin: lastTimeEnd,
|
|
|
|
|
+ timeEnd: timeBegin,
|
|
|
|
|
+ fullSize: fullSize,
|
|
|
|
|
+ autotuned: false
|
|
|
|
|
+ )
|
|
|
lastTimeEnd = timeEnd
|
|
lastTimeEnd = timeEnd
|
|
|
return regularPoints + [CGPoint(x: x0, y: y0)]
|
|
return regularPoints + [CGPoint(x: x0, y: y0)]
|
|
|
}.flatMap { $0 }
|
|
}.flatMap { $0 }
|
|
@@ -488,17 +502,18 @@ extension MainChartView {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let endDateTime = dayAgoTime + 1.days.timeInterval + 6.hours.timeInterval
|
|
let endDateTime = dayAgoTime + 1.days.timeInterval + 6.hours.timeInterval
|
|
|
- let regularBasalPoints = findRegularBasalPoints(
|
|
|
|
|
|
|
+ let autotunedBasalPoints = findRegularBasalPoints(
|
|
|
timeBegin: dayAgoTime,
|
|
timeBegin: dayAgoTime,
|
|
|
timeEnd: endDateTime,
|
|
timeEnd: endDateTime,
|
|
|
- fullSize: fullSize
|
|
|
|
|
|
|
+ fullSize: fullSize,
|
|
|
|
|
+ autotuned: true
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- let regularBasalPath = Path { path in
|
|
|
|
|
|
|
+ let autotunedBasalPath = Path { path in
|
|
|
var yPoint: CGFloat = Config.basalHeight
|
|
var yPoint: CGFloat = Config.basalHeight
|
|
|
path.move(to: CGPoint(x: -50, y: yPoint))
|
|
path.move(to: CGPoint(x: -50, y: yPoint))
|
|
|
|
|
|
|
|
- for point in regularBasalPoints {
|
|
|
|
|
|
|
+ for point in autotunedBasalPoints {
|
|
|
path.addLine(to: CGPoint(x: point.x, y: yPoint))
|
|
path.addLine(to: CGPoint(x: point.x, y: yPoint))
|
|
|
path.addLine(to: point)
|
|
path.addLine(to: point)
|
|
|
yPoint = point.y
|
|
yPoint = point.y
|
|
@@ -508,7 +523,42 @@ extension MainChartView {
|
|
|
|
|
|
|
|
DispatchQueue.main.async {
|
|
DispatchQueue.main.async {
|
|
|
self.tempBasalPath = tempBasalPath
|
|
self.tempBasalPath = tempBasalPath
|
|
|
- self.regularBasalPath = regularBasalPath
|
|
|
|
|
|
|
+ self.regularBasalPath = autotunedBasalPath
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private func calculateSuspensions(fullSize: CGSize) {
|
|
|
|
|
+ calculationQueue.async {
|
|
|
|
|
+ var rects = suspensions.windows(ofCount: 2).map { window -> CGRect? in
|
|
|
|
|
+ let window = Array(window)
|
|
|
|
|
+ guard window[0].type == .pumpSuspend, window[1].type == .pumpResume else { return nil }
|
|
|
|
|
+ let x0 = self.timeToXCoordinate(window[0].timestamp.timeIntervalSince1970, fullSize: fullSize)
|
|
|
|
|
+ let x1 = self.timeToXCoordinate(window[1].timestamp.timeIntervalSince1970, fullSize: fullSize)
|
|
|
|
|
+ return CGRect(x: x0, y: 0, width: x1 - x0, height: Config.basalHeight)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let firstRec = self.suspensions.first.flatMap { event -> CGRect? in
|
|
|
|
|
+ guard event.type == .pumpResume else { return nil }
|
|
|
|
|
+ let width = self.timeToXCoordinate(event.timestamp.timeIntervalSince1970, fullSize: fullSize)
|
|
|
|
|
+ return CGRect(x: 0, y: 0, width: width, height: Config.basalHeight)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let lastRec = self.suspensions.last.flatMap { event -> CGRect? in
|
|
|
|
|
+ guard event.type == .pumpSuspend else { return nil }
|
|
|
|
|
+ let x0 = self.timeToXCoordinate(event.timestamp.timeIntervalSince1970, fullSize: fullSize)
|
|
|
|
|
+ let x1 = self.fullGlucoseWidth(viewWidth: fullSize.width) + self.additionalWidth(viewWidth: fullSize.width)
|
|
|
|
|
+ return CGRect(x: x0, y: 0, width: x1 - x0, height: Config.basalHeight)
|
|
|
|
|
+ }
|
|
|
|
|
+ rects.append(firstRec)
|
|
|
|
|
+ rects.append(lastRec)
|
|
|
|
|
+
|
|
|
|
|
+ let path = Path { path in
|
|
|
|
|
+ path.addRects(rects.compactMap { $0 })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ DispatchQueue.main.async {
|
|
|
|
|
+ suspensionsPath = path
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -560,7 +610,12 @@ extension MainChartView {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private func findRegularBasalPoints(timeBegin: TimeInterval, timeEnd: TimeInterval, fullSize: CGSize) -> [CGPoint] {
|
|
|
|
|
|
|
+ private func findRegularBasalPoints(
|
|
|
|
|
+ timeBegin: TimeInterval,
|
|
|
|
|
+ timeEnd: TimeInterval,
|
|
|
|
|
+ fullSize: CGSize,
|
|
|
|
|
+ autotuned: Bool
|
|
|
|
|
+ ) -> [CGPoint] {
|
|
|
guard timeBegin < timeEnd else {
|
|
guard timeBegin < timeEnd else {
|
|
|
return []
|
|
return []
|
|
|
}
|
|
}
|
|
@@ -568,17 +623,19 @@ extension MainChartView {
|
|
|
let calendar = Calendar.current
|
|
let calendar = Calendar.current
|
|
|
let startOfDay = calendar.startOfDay(for: beginDate)
|
|
let startOfDay = calendar.startOfDay(for: beginDate)
|
|
|
|
|
|
|
|
- let basalNormalized = basalProfile.map {
|
|
|
|
|
|
|
+ let profile = autotuned ? autotunedBasalProfile : basalProfile
|
|
|
|
|
+
|
|
|
|
|
+ let basalNormalized = profile.map {
|
|
|
(
|
|
(
|
|
|
time: startOfDay.addingTimeInterval($0.minutes.minutes.timeInterval).timeIntervalSince1970,
|
|
time: startOfDay.addingTimeInterval($0.minutes.minutes.timeInterval).timeIntervalSince1970,
|
|
|
rate: $0.rate
|
|
rate: $0.rate
|
|
|
)
|
|
)
|
|
|
- } + basalProfile.map {
|
|
|
|
|
|
|
+ } + profile.map {
|
|
|
(
|
|
(
|
|
|
time: startOfDay.addingTimeInterval($0.minutes.minutes.timeInterval + 1.days.timeInterval).timeIntervalSince1970,
|
|
time: startOfDay.addingTimeInterval($0.minutes.minutes.timeInterval + 1.days.timeInterval).timeIntervalSince1970,
|
|
|
rate: $0.rate
|
|
rate: $0.rate
|
|
|
)
|
|
)
|
|
|
- } + basalProfile.map {
|
|
|
|
|
|
|
+ } + profile.map {
|
|
|
(
|
|
(
|
|
|
time: startOfDay.addingTimeInterval($0.minutes.minutes.timeInterval + 2.days.timeInterval).timeIntervalSince1970,
|
|
time: startOfDay.addingTimeInterval($0.minutes.minutes.timeInterval + 2.days.timeInterval).timeIntervalSince1970,
|
|
|
rate: $0.rate
|
|
rate: $0.rate
|