|
@@ -62,6 +62,10 @@ struct MainChartView: View {
|
|
|
@State private var suspensionsPath = 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 fpuDots: [DotInfo] = []
|
|
|
|
|
+ @State private var fpuPath = Path()
|
|
|
|
|
+
|
|
|
@State private var glucoseYGange: GlucoseYRange = (0, 0, 0, 0)
|
|
@State private var glucoseYGange: GlucoseYRange = (0, 0, 0, 0)
|
|
|
@State private var offset: CGFloat = 0
|
|
@State private var offset: CGFloat = 0
|
|
|
@State private var cachedMaxBasalRate: Decimal?
|
|
@State private var cachedMaxBasalRate: Decimal?
|
|
@@ -93,7 +97,16 @@ struct MainChartView: View {
|
|
|
private var carbsFormatter: NumberFormatter {
|
|
private var carbsFormatter: NumberFormatter {
|
|
|
let formatter = NumberFormatter()
|
|
let formatter = NumberFormatter()
|
|
|
formatter.numberStyle = .decimal
|
|
formatter.numberStyle = .decimal
|
|
|
|
|
+ formatter.maximumFractionDigits = 0
|
|
|
|
|
+ return formatter
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private var fpuFormatter: NumberFormatter {
|
|
|
|
|
+ let formatter = NumberFormatter()
|
|
|
|
|
+ formatter.numberStyle = .decimal
|
|
|
formatter.maximumFractionDigits = 1
|
|
formatter.maximumFractionDigits = 1
|
|
|
|
|
+ formatter.decimalSeparator = "."
|
|
|
|
|
+ formatter.minimumIntegerDigits = 0
|
|
|
return formatter
|
|
return formatter
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -236,6 +249,7 @@ struct MainChartView: View {
|
|
|
ZStack {
|
|
ZStack {
|
|
|
xGridView(fullSize: fullSize)
|
|
xGridView(fullSize: fullSize)
|
|
|
carbsView(fullSize: fullSize)
|
|
carbsView(fullSize: fullSize)
|
|
|
|
|
+ fpuView(fullSize: fullSize)
|
|
|
bolusView(fullSize: fullSize)
|
|
bolusView(fullSize: fullSize)
|
|
|
glucoseView(fullSize: fullSize)
|
|
glucoseView(fullSize: fullSize)
|
|
|
predictionsView(fullSize: fullSize)
|
|
predictionsView(fullSize: fullSize)
|
|
@@ -352,6 +366,28 @@ struct MainChartView: View {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private func fpuView(fullSize: CGSize) -> some View {
|
|
|
|
|
+ ZStack {
|
|
|
|
|
+ fpuPath
|
|
|
|
|
+ .fill(Color.red)
|
|
|
|
|
+ fpuPath
|
|
|
|
|
+ .stroke(Color.primary, lineWidth: 0.5)
|
|
|
|
|
+
|
|
|
|
|
+ ForEach(fpuDots, id: \.rect.minX) { info -> AnyView in
|
|
|
|
|
+ let position = CGPoint(x: info.rect.midX, y: info.rect.minY - 8)
|
|
|
|
|
+ return Text(fpuFormatter.string(from: info.value as NSNumber)!).font(.caption2)
|
|
|
|
|
+ .position(position)
|
|
|
|
|
+ .asAny()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .onChange(of: carbs) { _ in
|
|
|
|
|
+ calculateFPUsDots(fullSize: fullSize)
|
|
|
|
|
+ }
|
|
|
|
|
+ .onChange(of: didAppearTrigger) { _ in
|
|
|
|
|
+ calculateFPUsDots(fullSize: fullSize)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private func tempTargetsView(fullSize: CGSize) -> some View {
|
|
private func tempTargetsView(fullSize: CGSize) -> some View {
|
|
|
ZStack {
|
|
ZStack {
|
|
|
tempTargetsPath
|
|
tempTargetsPath
|
|
@@ -413,6 +449,7 @@ extension MainChartView {
|
|
|
calculateGlucoseDots(fullSize: fullSize)
|
|
calculateGlucoseDots(fullSize: fullSize)
|
|
|
calculateBolusDots(fullSize: fullSize)
|
|
calculateBolusDots(fullSize: fullSize)
|
|
|
calculateCarbsDots(fullSize: fullSize)
|
|
calculateCarbsDots(fullSize: fullSize)
|
|
|
|
|
+ calculateFPUsDots(fullSize: fullSize)
|
|
|
calculateTempTargetsRects(fullSize: fullSize)
|
|
calculateTempTargetsRects(fullSize: fullSize)
|
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
calculateBasalPoints(fullSize: fullSize)
|
|
|
calculateSuspensions(fullSize: fullSize)
|
|
calculateSuspensions(fullSize: fullSize)
|
|
@@ -458,7 +495,8 @@ extension MainChartView {
|
|
|
|
|
|
|
|
private func calculateCarbsDots(fullSize: CGSize) {
|
|
private func calculateCarbsDots(fullSize: CGSize) {
|
|
|
calculationQueue.async {
|
|
calculationQueue.async {
|
|
|
- let dots = carbs.map { value -> DotInfo in
|
|
|
|
|
|
|
+ let realCarbs = carbs.filter { !($0.isFPU ?? false) }
|
|
|
|
|
+ let dots = realCarbs.map { value -> DotInfo in
|
|
|
let center = timeToInterpolatedPoint(value.createdAt.timeIntervalSince1970, fullSize: fullSize)
|
|
let center = timeToInterpolatedPoint(value.createdAt.timeIntervalSince1970, fullSize: fullSize)
|
|
|
let size = Config.carbsSize + CGFloat(value.carbs) * Config.carbsScale
|
|
let size = Config.carbsSize + CGFloat(value.carbs) * Config.carbsScale
|
|
|
let rect = CGRect(x: center.x - size / 2, y: center.y - size / 2, width: size, height: size)
|
|
let rect = CGRect(x: center.x - size / 2, y: center.y - size / 2, width: size, height: size)
|
|
@@ -478,6 +516,29 @@ extension MainChartView {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private func calculateFPUsDots(fullSize: CGSize) {
|
|
|
|
|
+ calculationQueue.async {
|
|
|
|
|
+ let fpus = carbs.filter { $0.isFPU ?? false }
|
|
|
|
|
+ let dots = fpus.map { value -> DotInfo in
|
|
|
|
|
+ let center = timeToInterpolatedPoint(value.createdAt.timeIntervalSince1970, fullSize: fullSize)
|
|
|
|
|
+ let size = Config.carbsSize + CGFloat(value.carbs) * Config.carbsScale
|
|
|
|
|
+ let rect = CGRect(x: center.x - size / 2, y: center.y - size / 2, width: size, height: size)
|
|
|
|
|
+ return DotInfo(rect: rect, value: value.carbs)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let path = Path { path in
|
|
|
|
|
+ for dot in dots {
|
|
|
|
|
+ path.addEllipse(in: dot.rect)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ DispatchQueue.main.async {
|
|
|
|
|
+ fpuDots = dots
|
|
|
|
|
+ fpuPath = path
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private func calculatePredictionDots(fullSize: CGSize, type: PredictionType) {
|
|
private func calculatePredictionDots(fullSize: CGSize, type: PredictionType) {
|
|
|
calculationQueue.async {
|
|
calculationQueue.async {
|
|
|
let values: [Int] = { () -> [Int] in
|
|
let values: [Int] = { () -> [Int] in
|