Преглед изворни кода

UI
* introduce bolus progress bar (cherry picked from dnzxy)
- add shadow for coherence in Home view
* increase font size of sf symbols in header
* (re)add legend panel for main chart
* increase height of Rectangle for main chart and adapt charts to new size
* fix vertical offset of basal- and main-chart-rulemarks
* reduce size of glucose bobble a little bit

polscm32 пре 2 година
родитељ
комит
5a63c1dc4a

+ 2 - 2
FreeAPS.xcodeproj/project.pbxproj

@@ -3297,7 +3297,7 @@
 					"$(PROJECT_DIR)/Dependencies/ios-armv7_arm64",
 				);
 				INFOPLIST_FILE = FreeAPS/Resources/Info.plist;
-				IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 16.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -3339,7 +3339,7 @@
 					"$(PROJECT_DIR)/Dependencies/ios-armv7_arm64",
 				);
 				INFOPLIST_FILE = FreeAPS/Resources/Info.plist;
-				IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 16.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",

+ 51 - 57
FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift

@@ -115,23 +115,23 @@ struct MainChartView: View {
         VStack {
             ScrollViewReader { scroller in
                 ScrollView(.horizontal, showsIndicators: false) {
-                    VStack {
+                    VStack(spacing: -0.5) {
                         BasalChart()
 
                         MainChart()
 
-                    }.onChange(of: screenHours) {
+                    }.onChange(of: screenHours) { _ in
                         updateStartEndMarkers()
                         scroller.scrollTo("MainChart", anchor: .trailing)
-                    }.onChange(of: glucose) {
+                    }.onChange(of: glucose) { _ in
                         updateStartEndMarkers()
                         scroller.scrollTo("MainChart", anchor: .trailing)
                     }
-                    .onChange(of: suggestion) {
+                    .onChange(of: suggestion) { _ in
                         updateStartEndMarkers()
                         scroller.scrollTo("MainChart", anchor: .trailing)
                     }
-                    .onChange(of: tempBasals) {
+                    .onChange(of: tempBasals) { _ in
                         updateStartEndMarkers()
                         scroller.scrollTo("MainChart", anchor: .trailing)
                     }
@@ -142,6 +142,7 @@ struct MainChartView: View {
                 }
             }
             //            Legend().padding(.vertical, 4)
+            legendPanel.padding(.top, 8)
         }
     }
 }
@@ -283,25 +284,25 @@ extension MainChartView {
                     }
                 }
             }.id("MainChart")
-                .onChange(of: glucose) {
+                .onChange(of: glucose) { _ in
                     calculatePredictions()
                     calculateFpus()
                     counter()
                 }
-                .onChange(of: carbs) {
+                .onChange(of: carbs) { _ in
                     calculateCarbs()
                     calculateFpus()
                 }
-                .onChange(of: boluses) {
+                .onChange(of: boluses) { _ in
                     calculateBoluses()
                 }
-                .onChange(of: tempTargets) {
+                .onChange(of: tempTargets) { _ in
                     calculateTTs()
                 }
-                .onChange(of: didAppearTrigger) {
+                .onChange(of: didAppearTrigger) { _ in
                     calculatePredictions()
                     calculateTTs()
-                }.onChange(of: suggestion) {
+                }.onChange(of: suggestion) { _ in
                     calculatePredictions()
                 }
                 .onReceive(
@@ -382,27 +383,27 @@ extension MainChartView {
                         series: .value("profile", "profile")
                     ).lineStyle(.init(lineWidth: 2.5, dash: [2, 3]))
                 }
-            }.onChange(of: tempBasals) {
+            }.onChange(of: tempBasals) { _ in
                 calculateBasals()
                 calculateTempBasals()
             }
-            .onChange(of: maxBasal) {
+            .onChange(of: maxBasal) { _ in
                 calculateBasals()
                 calculateTempBasals()
             }
-            .onChange(of: autotunedBasalProfile) {
+            .onChange(of: autotunedBasalProfile) { _ in
                 calculateBasals()
                 calculateTempBasals()
             }
-            .onChange(of: didAppearTrigger) {
+            .onChange(of: didAppearTrigger) { _ in
                 calculateBasals()
                 calculateTempBasals()
-            }.onChange(of: basalProfile) {
+            }.onChange(of: basalProfile) { _ in
                 calculateTempBasals()
             }
             .frame(
                 width: max(0, screenSize.width - 20, fullWidth(viewWidth: screenSize.width)),
-                height: UIScreen.main.bounds.height / 10.5
+                height: UIScreen.main.bounds.height / 10
             )
             .rotationEffect(.degrees(180))
             .scaleEffect(x: -1, y: 1)
@@ -421,50 +422,43 @@ extension MainChartView {
         }
     }
 
-    private func Legend() -> some View {
+    var legendPanel: some View {
         ZStack {
-            Capsule(style: .circular).foregroundStyle(.gray.opacity(0.1)).padding(.horizontal, 30).frame(maxHeight: 15)
-
-            HStack {
-                Image(systemName: "line.diagonal")
-                    .fontWeight(.bold)
-                    .rotationEffect(Angle(degrees: 45))
-                    .foregroundColor(.green)
-                Text("BG")
-                    .foregroundColor(.secondary)
+            HStack(alignment: .center) {
                 Spacer()
-                Image(systemName: "line.diagonal")
-                    .fontWeight(.bold)
-                    .rotationEffect(Angle(degrees: 45))
-                    .foregroundColor(.insulin)
-                Text("IOB")
-                    .foregroundColor(.secondary)
-                Spacer()
-                Image(systemName: "line.diagonal")
-                    .fontWeight(.bold)
-                    .rotationEffect(Angle(degrees: 45))
-                    .foregroundColor(.purple)
-                Text("ZT")
-                    .foregroundColor(.secondary)
-                Spacer()
-                Image(systemName: "line.diagonal")
-                    .fontWeight(.bold)
-                    .frame(height: 10)
-                    .rotationEffect(Angle(degrees: 45))
-                    .foregroundColor(.loopYellow)
-                Text("COB")
-                    .foregroundColor(.secondary)
+
+                Group {
+                    Circle().fill(Color.loopGreen).frame(width: 8, height: 8)
+                    Text("BG")
+                        .font(.system(size: 10, weight: .bold)).foregroundColor(.loopGreen)
+                }
+                Group {
+                    Circle().fill(Color.insulin).frame(width: 8, height: 8)
+                        .padding(.leading, 8)
+                    Text("IOB")
+                        .font(.system(size: 10, weight: .bold)).foregroundColor(.insulin)
+                }
+                Group {
+                    Circle().fill(Color.zt).frame(width: 8, height: 8)
+                        .padding(.leading, 8)
+                    Text("ZT")
+                        .font(.system(size: 10, weight: .bold)).foregroundColor(.zt)
+                }
+                Group {
+                    Circle().fill(Color.loopYellow).frame(width: 8, height: 8).padding(.leading, 8)
+                    Text("COB")
+                        .font(.system(size: 10, weight: .bold)).foregroundColor(.loopYellow)
+                }
+                Group {
+                    Circle().fill(Color.uam).frame(width: 8, height: 8)
+                        .padding(.leading, 8)
+                    Text("UAM")
+                        .font(.system(size: 10, weight: .bold)).foregroundColor(.uam)
+                }
                 Spacer()
-                Image(systemName: "line.diagonal")
-                    .fontWeight(.bold)
-                    .rotationEffect(Angle(degrees: 45))
-                    .foregroundColor(.orange)
-                Text("UAM")
-                    .foregroundColor(.secondary)
             }
-            .font(.caption2)
-            .padding(.horizontal, 40)
-            .padding(.vertical, 1)
+            .padding(.horizontal, 10)
+            .frame(maxWidth: .infinity)
         }
     }
 }

+ 6 - 6
FreeAPS/Sources/Modules/Home/View/Header/PumpView.swift

@@ -41,7 +41,7 @@ struct PumpView: View {
     var body: some View {
         HStack {
             Image(systemName: "syringe.fill")
-                .font(.system(size: 15))
+                .font(.system(size: 16))
                 .foregroundColor(Color.insulin)
             Text(
                 (numberFormatter.string(from: (state.suggestion?.iob ?? 0) as NSNumber) ?? "0") +
@@ -52,7 +52,7 @@ struct PumpView: View {
             Spacer()
 
             Image(systemName: "fork.knife")
-                .font(.system(size: 15))
+                .font(.system(size: 16))
                 .foregroundColor(.loopYellow)
             Text(
                 (numberFormatter.string(from: (state.suggestion?.cob ?? 0) as NSNumber) ?? "0") +
@@ -65,7 +65,7 @@ struct PumpView: View {
             if let reservoir = reservoir {
                 HStack {
                     Image(systemName: "drop.fill")
-                        .font(.system(size: 15))
+                        .font(.system(size: 16))
                         .foregroundColor(reservoirColor)
                     if reservoir == 0xDEAD_BEEF {
                         Text("50+ " + NSLocalizedString("U", comment: "Insulin unit")).font(.callout).fontWeight(.bold)
@@ -80,7 +80,7 @@ struct PumpView: View {
 
                 if let timeZone = timeZone, timeZone.secondsFromGMT() != TimeZone.current.secondsFromGMT() {
                     Image(systemName: "clock.badge.exclamationmark.fill")
-                        .font(.system(size: 15))
+                        .font(.system(size: 16))
                         .symbolRenderingMode(.palette)
                         .foregroundStyle(.red, Color(.warning))
                 }
@@ -91,7 +91,7 @@ struct PumpView: View {
             if let battery = battery, battery.display ?? false, expiresAtDate == nil {
                 HStack {
                     Image(systemName: "battery.100")
-                        .font(.system(size: 15))
+                        .font(.system(size: 16))
                         .foregroundColor(batteryColor)
                     Text("\(Int(battery.percent ?? 100)) %").font(.callout)
                         .fontWeight(.bold)
@@ -101,7 +101,7 @@ struct PumpView: View {
             if let date = expiresAtDate {
                 HStack {
                     Image(systemName: "stopwatch.fill")
-                        .font(.system(size: 15))
+                        .font(.system(size: 16))
                         .foregroundColor(timerColor)
 
                     Text(remainingTimeString(time: date.timeIntervalSince(timerDate))).font(.callout).fontWeight(.bold)

+ 98 - 78
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -158,23 +158,23 @@ extension Home {
                 alarm: $state.alarm,
                 lowGlucose: $state.lowGlucose,
                 highGlucose: $state.highGlucose
-            )
-            .onTapGesture {
-                if state.alarm == nil {
-                    state.openCGM()
-                } else {
-                    state.showModal(for: .snooze)
+            ).scaleEffect(0.9)
+                .onTapGesture {
+                    if state.alarm == nil {
+                        state.openCGM()
+                    } else {
+                        state.showModal(for: .snooze)
+                    }
                 }
-            }
-            .onLongPressGesture {
-                let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
-                impactHeavy.impactOccurred()
-                if state.alarm == nil {
-                    state.showModal(for: .snooze)
-                } else {
-                    state.openCGM()
+                .onLongPressGesture {
+                    let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
+                    impactHeavy.impactOccurred()
+                    if state.alarm == nil {
+                        state.showModal(for: .snooze)
+                    } else {
+                        state.openCGM()
+                    }
                 }
-            }
         }
 
         var pumpView: some View {
@@ -350,19 +350,6 @@ extension Home {
                 if state.closedLoop, state.settingsManager.preferences.maxIOB == 0 {
                     Text("Max IOB: 0").font(.callout).foregroundColor(.orange).padding(.trailing, 20)
                 }
-
-                if let progress = state.bolusProgress {
-                    HStack {
-                        Text("Bolusing")
-                            .font(.system(size: 12, weight: .bold)).foregroundColor(.insulin)
-                        ProgressView(value: Double(progress))
-                            .progressViewStyle(BolusProgressViewStyle())
-                            .padding(.trailing, 8)
-                    }
-                    .onTapGesture {
-                        state.cancelBolus()
-                    }
-                }
             }
             .frame(maxWidth: .infinity, maxHeight: 30)
         }
@@ -395,54 +382,6 @@ extension Home {
             .font(buttonFont)
         }
 
-        var legendPanel: some View {
-            ZStack {
-                HStack(alignment: .center) {
-                    Spacer()
-
-                    Group {
-                        Circle().fill(Color.loopGreen).frame(width: 8, height: 8)
-                        Text("BG")
-                            .font(.system(size: 12, weight: .bold)).foregroundColor(.loopGreen)
-                    }
-                    Group {
-                        Circle().fill(Color.insulin).frame(width: 8, height: 8)
-                            .padding(.leading, 8)
-                        Text("IOB")
-                            .font(.system(size: 12, weight: .bold)).foregroundColor(.insulin)
-                    }
-                    Group {
-                        Circle().fill(Color.zt).frame(width: 8, height: 8)
-                            .padding(.leading, 8)
-                        Text("ZT")
-                            .font(.system(size: 12, weight: .bold)).foregroundColor(.zt)
-                    }
-                    Group {
-                        Circle().fill(Color.loopYellow).frame(width: 8, height: 8)
-                        Text("COB")
-                            .font(.system(size: 12, weight: .bold)).foregroundColor(.loopYellow)
-                    }
-                    Group {
-                        Circle().fill(Color.uam).frame(width: 8, height: 8)
-                            .padding(.leading, 8)
-                        Text("UAM")
-                            .font(.system(size: 12, weight: .bold)).foregroundColor(.uam)
-                    }
-
-                    if let eventualBG = state.eventualBG {
-                        Text(
-                            "⇢ " + numberFormatter.string(
-                                from: (state.units == .mmolL ? eventualBG.asMmolL : Decimal(eventualBG)) as NSNumber
-                            )!
-                        )
-                        .font(.system(size: 12, weight: .bold)).foregroundColor(.secondary)
-                    }
-                    Spacer()
-                }
-                .frame(maxWidth: .infinity)
-            }
-        }
-
         var mainChart: some View {
             ZStack {
                 if state.animatedBackground {
@@ -641,6 +580,81 @@ extension Home {
             }
         }
 
+        @ViewBuilder func bolusProgressBar(_ progress: Decimal) -> some View {
+            GeometryReader { geo in
+                Rectangle()
+                    .frame(height: 6)
+                    .foregroundColor(.clear)
+                    .background(
+                        LinearGradient(colors: [
+                            Color(red: 0.7215686275, green: 0.3411764706, blue: 1),
+                            Color(red: 0.6235294118, green: 0.4235294118, blue: 0.9803921569),
+                            Color(red: 0.4862745098, green: 0.5450980392, blue: 0.9529411765),
+                            Color(red: 0.3411764706, green: 0.6666666667, blue: 0.9254901961),
+                            Color(red: 0.262745098, green: 0.7333333333, blue: 0.9137254902)
+                        ], startPoint: .leading, endPoint: .trailing)
+                            .mask(alignment: .leading) {
+                                Rectangle()
+                                    .frame(width: geo.size.width * CGFloat(progress))
+                            }
+                    )
+            }
+        }
+
+        @ViewBuilder func bolusProgressView(_: GeometryProxy, _ progress: Decimal) -> some View {
+            let colorRectangle: Color = colorScheme == .dark ? Color(
+                red: 0.05490196078,
+                green: 0.05490196078,
+                blue: 0.05490196078
+            ) : Color.white
+
+            let colorIcon = (colorScheme == .dark ? Color.white : Color.black).opacity(0.9)
+
+            let bolusTotal = state.boluses.last?.amount ?? 0
+            let bolusFraction = progress * bolusTotal
+
+            let bolusString =
+                (numberFormatter.string(from: bolusFraction as NSNumber) ?? "0")
+                    + " of " +
+                    (numberFormatter.string(from: bolusTotal as NSNumber) ?? "0")
+                    + NSLocalizedString(" U", comment: "Insulin unit")
+
+            ZStack(alignment: .bottom) {
+                HStack {
+                    Button {
+                        state.cancelBolus()
+
+                    } label: {
+                        HStack(alignment: .center) {
+                            Text("Bolusing")
+                                .font(.subheadline)
+                                .fontWeight(.bold)
+                            Text(bolusString)
+                                .font(.subheadline)
+
+                            Spacer()
+
+                            Image(systemName: "xmark.app")
+                                .font(.system(size: 30))
+                                .padding(1)
+                        }
+                    }.foregroundColor(colorIcon)
+                }.padding()
+
+                bolusProgressBar(progress).offset(y: 56)
+            }
+            .background(colorRectangle)
+            .clipShape(RoundedRectangle(cornerRadius: 8))
+            .shadow(
+                color: colorScheme == .dark ? Color(red: 0.02745098039, green: 0.1098039216, blue: 0.1411764706) :
+                    Color.black.opacity(0.33),
+                radius: 3
+            )
+            .frame(height: 62, alignment: .center)
+            .padding(.horizontal, 10)
+            .offset(y: -90)
+        }
+
         var body: some View {
             let colorBackground = colorScheme == .dark ? LinearGradient(
                 gradient: Gradient(colors: [
@@ -724,7 +738,7 @@ extension Home {
                             radius: 3
                         )
                         .padding(.horizontal, 10)
-                        .frame(maxHeight: UIScreen.main.bounds.height / 2.2)
+                        .frame(maxHeight: UIScreen.main.bounds.height / 2.1)
 
                     Spacer()
 
@@ -732,7 +746,13 @@ extension Home {
 
                     Spacer()
 
-                    bottomPanel(geo)
+                    ZStack(alignment: .bottom) {
+                        bottomPanel(geo)
+
+                        if let progress = state.bolusProgress {
+                            bolusProgressView(geo, progress)
+                        }
+                    }
                 }
                 .background(colorBackground)
                 .edgesIgnoringSafeArea(.all)