Просмотр исходного кода

Cleanup and Additions
* Add confirmation dialog to home view for double cancel (OR and TT running)
* Add hint and sheet help (similar to settings) to Add TT Form to explain advanced config… what settings do users need for this to work
* Refactor and cleanup advanced TT view in home screen…

Deniz Cengiz 1 год назад
Родитель
Сommit
f59aef6522

+ 141 - 107
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -12,6 +12,7 @@ extension Home {
         @State var isStatusPopupPresented = false
         @State var showCancelAlert = false
         @State var showTempTargetCancelAlert = false
+        @State var showCancelConfirmDialog = false
         @State var isMenuPresented = false
         @State var showTreatments = false
         @State var selectedTab: Int = 0
@@ -501,149 +502,182 @@ extension Home {
             }.padding(.horizontal, 10)
         }
 
-        @ViewBuilder func profileView(geo: GeometryProxy) -> some View {
+        @ViewBuilder func adjustmentsOverrideView(_ overrideString: String) -> some View {
+            Group {
+                Image(systemName: "person.fill")
+                    .font(.system(size: 24))
+                    .foregroundColor(Color(
+                        red: 0.6235294118,
+                        green: 0.4235294118,
+                        blue: 0.9803921569
+                    ))
+                VStack(alignment: .leading) {
+                    Text(latestOverride.first?.name ?? "Custom Override")
+                        .font(.subheadline)
+                        .frame(alignment: .leading)
+
+                    Text(overrideString)
+                        .font(.caption)
+                }
+            }
+        }
+
+        @ViewBuilder func adjustmentsTempTargetView(_ tempTargetString: String) -> some View {
+            Group {
+                /// TempTarget section
+                Image(systemName: "target")
+                    .font(.system(size: 24))
+                    .foregroundColor(.loopGreen)
+                VStack(alignment: .leading) {
+                    Text(latestTempTarget.first?.name ?? "Temp Target")
+                        .font(.subheadline)
+                    Text(tempTargetString)
+                        .font(.caption)
+                }
+            }
+        }
+
+        @ViewBuilder func adjustmentsCancelView(_ cancelAction: @escaping () -> Void) -> some View {
+            Image(systemName: "xmark.app")
+                .font(.system(size: 24))
+                .onTapGesture {
+                    cancelAction()
+                }
+        }
+
+        @ViewBuilder func adjustmentView(geo: GeometryProxy) -> some View {
             ZStack {
-                // Background rectangle
+                /// rectangle as background
                 RoundedRectangle(cornerRadius: 15)
                     .fill(
-                        colorScheme == .dark
-                            ? Color(red: 0.039, green: 0.133, blue: 0.216)
-                            : Color.insulin.opacity(0.1)
+                        colorScheme == .dark ? Color(red: 0.03921568627, green: 0.133333333, blue: 0.2156862745) : Color
+                            .insulin
+                            .opacity(0.1)
                     )
+                    .clipShape(RoundedRectangle(cornerRadius: 15))
                     .frame(height: geo.size.height * 0.08)
                     .shadow(
-                        color: colorScheme == .dark
-                            ? Color(red: 0.027, green: 0.11, blue: 0.141)
-                            : Color.black.opacity(0.33),
+                        color: colorScheme == .dark ? Color(red: 0.02745098039, green: 0.1098039216, blue: 0.1411764706) :
+                            Color.black.opacity(0.33),
                         radius: 3
                     )
                 HStack {
                     if let overrideString = overrideString, let tempTargetString = tempTargetString {
                         HStack {
-                            /// override section
-                            Image(systemName: "person.fill")
-                                .font(.system(size: 24))
-                                .foregroundStyle(Color.purple)
-                            VStack(alignment: .leading) {
-                                Text(latestOverride.first?.name ?? "Custom Override")
-                                    .font(.subheadline)
-                                    .frame(alignment: .leading)
-
-                                Text(overrideString)
-                                    .font(.caption)
-                            }
+                            adjustmentsOverrideView(overrideString)
+
                             Spacer()
+
                             Divider()
                                 .frame(height: geo.size.height * 0.05)
                                 .padding(.horizontal, 2)
-                            /// TempTarget section
-                            Image(systemName: "target")
-                                .font(.system(size: 24))
-                                .foregroundColor(.loopGreen)
-                            VStack(alignment: .leading) {
-                                Text(latestTempTarget.first?.name ?? "Temp Target")
-                                    .font(.subheadline)
-                                Text(tempTargetString)
-                                    .font(.caption)
-                            }
-                            Spacer()
-                        }
-                    } else
-                    if let overrideString = overrideString {
-                        // Only override is active
-                        HStack {
-                            Image(systemName: "person.fill")
-                                .font(.system(size: 24))
-                                .foregroundStyle(Color.purple)
-                            VStack(alignment: .leading) {
-                                Text(latestOverride.first?.name ?? "Custom Override")
-                                    .font(.subheadline)
-                                Text(overrideString)
-                                    .font(.caption)
-                            }
+
+                            adjustmentsTempTargetView(tempTargetString)
+
                             Spacer()
-                            Image(systemName: "xmark")
-                                .font(.system(size: 25))
-                                .onTapGesture {
-                                    if !latestOverride.isEmpty {
-                                        showCancelAlert = true
-                                    }
+
+                            adjustmentsCancelView({
+                                if !latestTempTarget.isEmpty, !latestOverride.isEmpty {
+                                    showCancelConfirmDialog = true
+                                } else if !latestOverride.isEmpty {
+                                    showCancelAlert = true
+                                } else if !latestTempTarget.isEmpty {
+                                    showTempTargetCancelAlert = true
                                 }
+                            })
                         }
-                    } else
-                    if let tempTargetString = tempTargetString {
-                        // Only temp target is active
-                        HStack {
-                            Image(systemName: "target")
-                                .font(.system(size: 24))
-                                .foregroundColor(.loopGreen)
-                            VStack(alignment: .leading) {
-                                Text(latestTempTarget.first?.name ?? "Temp Target")
-                                    .font(.subheadline)
-                                Text(tempTargetString)
-                                    .font(.caption)
+                    } else if let overrideString = overrideString {
+                        adjustmentsOverrideView(overrideString)
+
+                        Spacer()
+
+                        adjustmentsCancelView({
+                            if !latestOverride.isEmpty {
+                                showCancelAlert = true
                             }
+                        })
+                    } else if let tempTargetString = tempTargetString {
+                        HStack {
+                            adjustmentsTempTargetView(tempTargetString)
+
                             Spacer()
-                            Image(systemName: "xmark")
-                                .font(.system(size: 25))
-                                .onTapGesture {
-                                    if !latestTempTarget.isEmpty {
-                                        showTempTargetCancelAlert = true
-                                    }
+
+                            adjustmentsCancelView({
+                                if !latestTempTarget.isEmpty {
+                                    showTempTargetCancelAlert = true
                                 }
+                            })
                         }
                     } else {
-                        // Normal profile view
-                        VStack(alignment: .leading) {
-                            Text("Normal Profile")
+                        VStack {
+                            Text("No Active Adjustment")
                                 .font(.subheadline)
-                            Text("100 %")
+                                .frame(maxWidth: .infinity, alignment: .leading)
+                            Text("Profile at 100 %")
                                 .font(.caption)
-                        }
+                                .frame(maxWidth: .infinity, alignment: .leading)
+                        }.padding(.leading, 10)
+
                         Spacer()
-                        // Placeholder xmark to keep layout consistent
-                        Image(systemName: "xmark")
+
+                        /// to ensure the same position....
+                        Image(systemName: "xmark.app")
                             .font(.system(size: 25))
-                            .foregroundColor(.clear)
+                            // clear color for the icon
+                            .foregroundStyle(Color.clear)
                     }
-                }
-                .padding(5)
-            }
-            .padding(.horizontal, 10)
-            .padding(.bottom, UIDevice.adjustPadding(min: nil, max: 10))
-            .alert(
-                "Return to Normal?",
-                isPresented: $showCancelAlert,
-                actions: {
-                    Button("No", role: .cancel) {}
-                    Button("Yes", role: .destructive) {
-                        Task {
-                            if !latestOverride.isEmpty {
+                }.padding(.horizontal, 10)
+                    .alert(
+                        "Cancel Override?",
+                        isPresented: $showCancelAlert,
+                        actions: {
+                            Button("No", role: .cancel) {}
+                            Button("Yes", role: .destructive) {
+                                Task {
+                                    if !latestOverride.isEmpty {
+                                        guard let objectID = latestOverride.first?.objectID else { return }
+                                        await state.cancelOverride(withID: objectID)
+                                    }
+                                }
+                            }
+                        },
+                        message: { Text("This will change settings back to your normal profile.")
+                        }
+                    )
+                    .alert(
+                        "Cancel Temp Target?",
+                        isPresented: $showTempTargetCancelAlert,
+                        actions: {
+                            Button("No", role: .cancel) {}
+                            Button("Yes", role: .destructive) {
+                                Task {
+                                    if !latestTempTarget.isEmpty {
+                                        guard let objectID = latestTempTarget.first?.objectID else { return }
+                                        await state.cancelTempTarget(withID: objectID)
+                                    }
+                                }
+                            }
+                        },
+                        message: { Text("This will change settings back to your regular target.") }
+                    )
+                    .confirmationDialog("Adjustment to Cancel", isPresented: $showCancelConfirmDialog) {
+                        Button("Cancel Override") {
+                            Task {
                                 guard let objectID = latestOverride.first?.objectID else { return }
                                 await state.cancelOverride(withID: objectID)
                             }
                         }
-                    }
-                },
-                message: { Text("This will change settings back to your normal profile.")
-                }
-            )
-            .alert(
-                "Cancel TempTarget?",
-                isPresented: $showTempTargetCancelAlert,
-                actions: {
-                    Button("No", role: .cancel) {}
-                    Button("Yes", role: .destructive) {
-                        Task {
-                            if !latestTempTarget.isEmpty {
+                        Button("Cancel Temp Target") {
+                            Task {
                                 guard let objectID = latestTempTarget.first?.objectID else { return }
                                 await state.cancelTempTarget(withID: objectID)
                             }
                         }
+                    } message: {
+                        Text("Select Adjustment to Cancel")
                     }
-                },
-                message: { Text("This will change settings back to your regular target.") }
-            )
+
+            }.padding(.horizontal, 10).padding(.bottom, UIDevice.adjustPadding(min: nil, max: 10))
         }
 
         @ViewBuilder func bolusProgressBar(_ progress: Decimal) -> some View {
@@ -761,7 +795,7 @@ extension Home {
                     if let progress = state.bolusProgress {
                         bolusView(geo: geo, progress).padding(.bottom, UIDevice.adjustPadding(min: nil, max: 40))
                     } else {
-                        profileView(geo: geo).padding(.bottom, UIDevice.adjustPadding(min: nil, max: 40))
+                        adjustmentView(geo: geo).padding(.bottom, UIDevice.adjustPadding(min: nil, max: 40))
                     }
                 }
                 .background(color)

+ 2 - 1
FreeAPS/Sources/Modules/OverrideConfig/View/AddOverrideForm.swift

@@ -58,7 +58,8 @@ struct AddOverrideForm: View {
                 addOverride()
             }.scrollContentBackground(.hidden).background(color)
                 .navigationTitle("Add Override")
-                .navigationBarItems(trailing: Button("Cancel") {
+                .navigationBarTitleDisplayMode(.inline)
+                .navigationBarItems(leading: Button("Cancel") {
                     presentationMode.wrappedValue.dismiss()
                 })
         }

+ 82 - 35
FreeAPS/Sources/Modules/OverrideConfig/View/AddTempTargetForm.swift

@@ -14,6 +14,11 @@ struct AddTempTargetForm: View {
     @State private var didPressSave =
         false // only used for fixing the Disclaimer showing up after pressing save (after the state was resetted), maybe refactor this...
 
+    @State private var shouldDisplayHint: Bool = false
+    @State var hintDetent = PresentationDetent.large
+    @State var selectedVerboseHint: String?
+    @State var hintLabel: String?
+
     var color: LinearGradient {
         colorScheme == .dark ? LinearGradient(
             gradient: Gradient(colors: [
@@ -55,7 +60,8 @@ struct AddTempTargetForm: View {
                 addTempTarget()
             }.scrollContentBackground(.hidden).background(color)
                 .navigationTitle("Add Temp Target")
-                .navigationBarItems(trailing: Button("Cancel") {
+                .navigationBarTitleDisplayMode(.inline)
+                .navigationBarItems(leading: Button("Close") {
                     presentationMode.wrappedValue.dismiss()
                 })
                 .alert(
@@ -78,25 +84,36 @@ struct AddTempTargetForm: View {
                         Text(alertString)
                     }
                 )
+                .sheet(isPresented: $shouldDisplayHint) {
+                    SettingInputHintView(
+                        hintDetent: $hintDetent,
+                        shouldDisplayHint: $shouldDisplayHint,
+                        hintLabel: hintLabel ?? "",
+                        hintText: selectedVerboseHint ?? "",
+                        sheetTitle: "Help"
+                    )
+                }
         }
     }
 
     @ViewBuilder private func addTempTarget() -> some View {
-        Section {
-            VStack {
-                TextField("Name", text: $state.tempTargetName)
+        Section(
+            header: Text("Configure Temp Target"),
+            content: {
+            HStack {
+                Text("Name")
+                Spacer()
+                TextField("Enter Name (optional)", text: $state.tempTargetName)
+                    .multilineTextAlignment(.trailing)
             }
-        } header: {
-            Text("Name")
-        }.listRowBackground(Color.chart)
 
-        Section {
             HStack {
                 Text("Target")
                 Spacer()
                 TextFieldWithToolBar(text: $state.tempTargetTarget, placeholder: "0", numberFormatter: glucoseFormatter)
                 Text(state.units.rawValue).foregroundColor(.secondary)
             }
+
             HStack {
                 Text("Duration")
                 Spacer()
@@ -104,35 +121,65 @@ struct AddTempTargetForm: View {
                 Text("minutes").foregroundColor(.secondary)
             }
             DatePicker("Date", selection: $state.date)
-            HStack {
-                Button {
-                    showAlert.toggle()
-                }
-                label: { Text("Enact") }
-                    .disabled(state.tempTargetDuration == 0)
-                    .buttonStyle(BorderlessButtonStyle())
-                    .font(.callout)
-                    .controlSize(.mini)
-
-                Button {
-                    Task {
-                        didPressSave.toggle()
-                        await state.saveTempTargetPreset()
-                        dismiss()
-                    }
+        }
+                ).listRowBackground(Color.chart)
+
+        // TODO: with iOS 17 we can change the body content wrapper from FORM to LIST and apply the .listSpacing modifier to make this all nice and small.
+        Section {
+            Button(action: {
+                showAlert.toggle()
+            }, label: {
+                Text("Enact Temp Target")
+
+            })
+                .disabled(state.tempTargetDuration == 0)
+                .frame(maxWidth: .infinity, alignment: .center)
+                .tint(.white)
+        }.listRowBackground(state.tempTargetDuration == 0 ? Color(.systemGray4) : Color(.systemBlue))
+
+        Section {
+            Button(action: {
+                Task {
+                    didPressSave.toggle()
+                    await state.saveTempTargetPreset()
+                    dismiss()
                 }
-                label: { Text("Save as preset") }
-                    .disabled(state.tempTargetDuration == 0)
-                    .tint(.orange)
-                    .frame(maxWidth: .infinity, alignment: .trailing)
-                    .buttonStyle(BorderlessButtonStyle())
-                    .controlSize(.mini)
-            }
-        } header: {
-            Text("Add Custom Temp Target")
-        }.listRowBackground(Color.chart)
+            }, label: {
+                Text("Save as Preset")
+
+            })
+                .disabled(state.tempTargetDuration == 0)
+                .frame(maxWidth: .infinity, alignment: .center)
+                .tint(.white)
+        }.listRowBackground(state.tempTargetDuration == 0 ? Color(.systemGray4) : Color(.orange))
 
-        Toggle("Advanced Configuration", isOn: $advancedConfiguration)
+        Section {
+            VStack {
+                Toggle("Enable Advanced Configuration", isOn: $advancedConfiguration).padding(.top)
+
+                HStack(alignment: .top) {
+                    Text(
+                        "Add an explanation of the advanced configuration options here."
+                    )
+                    .font(.footnote)
+                    .foregroundColor(.secondary)
+                    .lineLimit(nil)
+                    Spacer()
+                    Button(
+                        action: {
+                            hintLabel = "Advanced Temp Target Configuration"
+                            selectedVerboseHint = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
+                            shouldDisplayHint.toggle()
+                        },
+                        label: {
+                            HStack {
+                                Image(systemName: "questionmark.circle")
+                            }
+                        }
+                    ).buttonStyle(BorderlessButtonStyle())
+                }.padding(.top)
+            }.padding(.bottom)
+        }.listRowBackground(Color.chart)
 
         if advancedConfiguration && state.tempTargetTarget != 0 {
             if sliderEnabled {

+ 45 - 45
FreeAPS/Sources/Modules/OverrideConfig/View/EditTempTargetForm.swift

@@ -114,14 +114,51 @@ struct EditTempTargetForm: View {
     }
 
     @ViewBuilder private func editTempTarget() -> some View {
-        Section {
-            VStack {
-                TextField("Name", text: $name)
-                    .onChange(of: name) { _ in hasChanges = true }
-            }
-        } header: {
+        Section(
+            header: Text("Configure Temp Target"),
+        content: {
+        HStack {
             Text("Name")
-        }.listRowBackground(Color.chart)
+            Spacer()
+            TextField("Enter Name (optional)", text: $name)
+                .multilineTextAlignment(.trailing)
+        }
+            HStack {
+                Text("Target")
+                Spacer()
+                TextFieldWithToolBar(
+                    text: Binding(
+                        get: { target },
+                        set: {
+                            target = $0
+                            hasChanges = true
+                        }
+                    ),
+                    placeholder: "0",
+                    numberFormatter: glucoseFormatter
+                )
+                Text(state.units.rawValue).foregroundColor(.secondary)
+            }
+            HStack {
+                Text("Duration")
+                Spacer()
+                TextFieldWithToolBar(
+                    text: Binding(
+                        get: { duration },
+                        set: {
+                            duration = $0
+                            hasChanges = true
+                        }
+                    ),
+                    placeholder: "0",
+                    numberFormatter: formatter
+                )
+                Text("minutes").foregroundColor(.secondary)
+            }
+            DatePicker("Date", selection: $date)
+                .onChange(of: date) { _ in hasChanges = true }
+        }
+                ).listRowBackground(Color.chart)
 
         if state.computeSliderLow() != state.computeSliderHigh() {
             Section {
@@ -183,43 +220,6 @@ struct EditTempTargetForm: View {
                 Text("The Slider values are limited to your Autosens Min and Max Settings!")
             }.listRowBackground(Color.chart)
         }
-
-        Section {
-            HStack {
-                Text("Target")
-                Spacer()
-                TextFieldWithToolBar(
-                    text: Binding(
-                        get: { target },
-                        set: {
-                            target = $0
-                            hasChanges = true
-                        }
-                    ),
-                    placeholder: "0",
-                    numberFormatter: glucoseFormatter
-                )
-                Text(state.units.rawValue).foregroundColor(.secondary)
-            }
-            HStack {
-                Text("Duration")
-                Spacer()
-                TextFieldWithToolBar(
-                    text: Binding(
-                        get: { duration },
-                        set: {
-                            duration = $0
-                            hasChanges = true
-                        }
-                    ),
-                    placeholder: "0",
-                    numberFormatter: formatter
-                )
-                Text("minutes").foregroundColor(.secondary)
-            }
-            DatePicker("Date", selection: $date)
-                .onChange(of: date) { _ in hasChanges = true }
-        }.listRowBackground(Color.chart)
     }
 
     private var saveButton: some View {
@@ -249,7 +249,7 @@ struct EditTempTargetForm: View {
                         hasChanges = false
                         presentationMode.wrappedValue.dismiss()
                     } catch {
-                        debugPrint("Failed to edit Temp Target")
+                        debugPrint("Failed to Edit Temp Target")
                     }
                 }
             }, label: {

+ 1 - 1
FreeAPS/Sources/Modules/OverrideConfig/View/OverrideRootView.swift

@@ -67,7 +67,7 @@ extension OverrideConfig {
                         Spacer()
                         Image(systemName: "person.fill")
                             .font(.system(size: 18))
-                            .foregroundColor(Color.purple)
+                            .foregroundColor(Color(red: 0.6235294118, green: 0.4235294118, blue: 0.9803921569))
                         Text(OverrideConfig.Tab.overrides.name)
                             .font(.subheadline)
                         Spacer()