From fd3f12b398f244b482d2a6d585f393ba3cac4b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20M=C3=A5rtensson?= Date: Sun, 1 Dec 2024 16:44:37 +0100 Subject: [PATCH 1/4] Wrrong variable used --- FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift | 2 +- FreeAPS/Sources/Modules/Home/View/HomeRootView.swift | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift index 3c79670480..89b0c0fc77 100644 --- a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift +++ b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift @@ -66,7 +66,7 @@ extension AddCarbs { } // Summary when combining presets - if state.selection != nil { + if state.combinedPresets.isNotEmpty { let summary = state.waitersNotepad() if summary.isNotEmpty { HStack { diff --git a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift index 3ea9e1cb91..1a57e9af4a 100644 --- a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift +++ b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift @@ -833,7 +833,6 @@ extension Home { configureView() } - // .onAppear(perform: configureView) .navigationTitle("Home") .navigationBarHidden(true) .ignoresSafeArea(.keyboard) @@ -856,7 +855,6 @@ extension Home { } ) } - .onAppear(perform: configureView) } private var popup: some View { From 931ad775fd06b35605e3a4dcbb363f18ffcaabef Mon Sep 17 00:00:00 2001 From: "Jon B.M" Date: Mon, 2 Dec 2024 22:50:47 +0100 Subject: [PATCH 2/4] Edit saved food presets. Swipe right to edit. Swipe left to delete. --- .../xcshareddata/swiftpm/Package.resolved | 2 +- .../Modules/AddCarbs/AddCarbsStateModel.swift | 2 + .../AddCarbs/View/AddCarbsRootView.swift | 152 +++++++++++++----- 3 files changed, 113 insertions(+), 43 deletions(-) diff --git a/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved index c6fc96a667..37e3510a58 100644 --- a/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -39,7 +39,7 @@ }, { "package": "SwiftCharts", - "repositoryURL": "https://github.com/ivanschuetz/SwiftCharts", + "repositoryURL": "https://github.com/ivanschuetz/SwiftCharts.git", "state": { "branch": "master", "revision": "c354c1945bb35a1f01b665b22474f6db28cba4a2", diff --git a/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift b/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift index 75975763c8..c01882e84d 100644 --- a/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift +++ b/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift @@ -24,6 +24,8 @@ extension AddCarbs { @Published var skipBolus: Bool = false @Published var id: String? @Published var hypoTreatment = false + @Published var presetToEdit: Presets? + @Published var edit = false @Published var combinedPresets: [(preset: Presets?, portions: Int)] = [] diff --git a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift index 89b0c0fc77..528256b4bb 100644 --- a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift +++ b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift @@ -16,6 +16,7 @@ extension AddCarbs { @State private var showAlert = false @State private var presentPresets = false @State private var string = "" + @State private var newPreset: (dish: String, carbs: Decimal, fat: Decimal, protein: Decimal) = ("", 0, 0, 0) @FetchRequest( entity: Presets.entity(), @@ -108,9 +109,8 @@ extension AddCarbs { presetPopover } } - // Optional Hypo Treatment - if state.carbs > 0, let profile = state.id, profile != "None", let carbsReq = state.carbsRequired { + if state.carbs > 0, let profile = state.id, profile != "None", state.carbsRequired != nil { Section { Button { state.hypoTreatment = true @@ -149,9 +149,7 @@ extension AddCarbs { .navigationTitle("Add Meal") .navigationBarTitleDisplayMode(.inline) .navigationBarItems(trailing: Button("Cancel", action: state.hideModal)) - .sheet(isPresented: $presentPresets, content: { - presetView - }) + .sheet(isPresented: $presentPresets, content: { presetView }) } private var presetPopover: some View { @@ -233,13 +231,15 @@ extension AddCarbs { isPromptPresented = true } label: { - Text("Save as Preset") + HStack { + Text("Save as Preset") + Spacer() + Text("[\(state.carbs), \(state.fat), \(state.protein)]") + } }.frame(maxWidth: .infinity, alignment: .center) + .listRowBackground(Color(.systemBlue)).tint(.white) } header: { Text("Save") } - footer: { - Text("[\(state.carbs), \(state.fat), \(state.protein)]").frame(maxWidth: .infinity, alignment: .center) } - .listRowBackground(Color(.systemBlue)).tint(.white) } if carbPresets.count > 4 { @@ -257,11 +257,40 @@ extension AddCarbs { }.onDelete(perform: delete) } header: { Text("Saved Food") } } + .sheet(isPresented: $state.edit, content: { editView }) } - private func reset() { - presentPresets = false - string = "" + private var editView: some View { + Form { + Section { + HStack { + TextField("\(state.presetToEdit?.dish ?? "")", text: $newPreset.dish) + } + HStack { + Text("Carbs").foregroundStyle(.secondary) + Spacer() + DecimalTextField("\(state.presetToEdit?.carbs ?? 0)", value: $newPreset.carbs, formatter: formatter) + } + HStack { + Text("Fat").foregroundStyle(.secondary) + Spacer() + DecimalTextField("\(state.presetToEdit?.fat ?? 0)", value: $newPreset.fat, formatter: formatter) + } + HStack { + Text("Protein").foregroundStyle(.secondary) + Spacer() + DecimalTextField("\(state.presetToEdit?.protein ?? 0)", value: $newPreset.protein, formatter: formatter) + } + } header: { Text("Edit") } + + Section { + Button { save() } + label: { Text("Save") } + .frame(maxWidth: .infinity, alignment: .center) + .listRowBackground(Color(.systemBlue)) + .tint(.white) + } + } } @ViewBuilder private func proteinAndFat() -> some View { @@ -292,6 +321,43 @@ extension AddCarbs { } } + @ViewBuilder private func presetsList(for preset: Presets) -> some View { + let dish = preset.dish ?? "" + + if dish != "" { + HStack { + VStack(alignment: .leading) { + Text(dish) + HStack { + Text("Carbs") + Text("\(preset.carbs ?? 0)") + Spacer() + Text("Fat") + Text("\(preset.fat ?? 0)") + Spacer() + Text("Protein") + Text("\(preset.protein ?? 0)") + }.foregroundStyle(.secondary).font(.caption).padding(.top, 2) + } + .contentShape(Rectangle()) + .onTapGesture { + state.selection = preset + state.addU(state.selection) + reset() + } + .swipeActions(edge: .leading) { + Button { + state.edit = true + state.presetToEdit = preset + update() + } label: { + Label("Edit", systemImage: "pencil.line") + } + } + } + } + } + private var minusButton: some View { Button { state.subtract() @@ -301,20 +367,20 @@ extension AddCarbs { state.combinedPresets = [] } } - label: { Image(systemName: "minus.circle") } - .disabled(state.selection == nil) + label: { Image(systemName: "minus.circle.fill") + }.frame(maxWidth: .infinity, alignment: .leading) .buttonStyle(.borderless) - .tint(.blue) + .disabled(state.selection == nil) } private var plusButton: some View { Button { state.plus() } - label: { Image(systemName: "plus.circle") } - .disabled(state.selection == nil) + label: { Image(systemName: "plus.circle.fill") + }.frame(maxWidth: .infinity, alignment: .trailing) .buttonStyle(.borderless) - .tint(.blue) + .disabled(state.selection == nil) } private func delete(at offsets: IndexSet) { @@ -329,32 +395,34 @@ extension AddCarbs { } } - @ViewBuilder private func presetsList(for preset: Presets) -> some View { - let dish = preset.dish ?? "" - - if dish != "" { - HStack { - VStack(alignment: .leading) { - Text(dish) - HStack { - Text("Carbs") - Text("\(preset.carbs ?? 0)") - Spacer() - Text("Fat") - Text("\(preset.fat ?? 0)") - Spacer() - Text("Protein") - Text("\(preset.protein ?? 0)") - }.foregroundStyle(.secondary).font(.caption).padding(.top, 2) - } - .contentShape(Rectangle()) - .onTapGesture { - state.selection = preset - state.addU(state.selection) - reset() - } + private func save() { + if let preset = state.presetToEdit { + preset.dish = newPreset.dish + preset.carbs = newPreset.carbs as NSDecimalNumber + preset.fat = newPreset.fat as NSDecimalNumber + preset.protein = newPreset.protein as NSDecimalNumber + + if moc.hasChanges { + do { + try moc.save() + } catch { /* To do: add error */ } } } + state.edit = false + } + + private func update() { + newPreset.dish = state.presetToEdit?.dish ?? "" + newPreset.carbs = (state.presetToEdit?.carbs ?? 0) as Decimal + newPreset.fat = (state.presetToEdit?.fat ?? 0) as Decimal + newPreset.protein = (state.presetToEdit?.protein ?? 0) as Decimal + } + + private func reset() { + presentPresets = false + string = "" + state.presetToEdit = nil // Probably not needed + state.edit = false // Probably not needed } } } From f8d25efa5d4128d748161aef358378600be2d0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20M=C3=A5rtensson?= Date: Tue, 3 Dec 2024 15:20:24 +0100 Subject: [PATCH 3/4] Avoid line break And add some padding for the button --- .../Modules/AddCarbs/View/AddCarbsRootView.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift index 528256b4bb..8302793d47 100644 --- a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift +++ b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift @@ -47,7 +47,7 @@ extension AddCarbs { Section { // Saved Food presets - mealPresets + mealPresets.padding(.vertical, 9) HStack { Text("Carbs").fontWeight(.semibold) @@ -361,16 +361,15 @@ extension AddCarbs { private var minusButton: some View { Button { state.subtract() - if empty { state.selection = nil state.combinedPresets = [] } } label: { Image(systemName: "minus.circle.fill") - }.frame(maxWidth: .infinity, alignment: .leading) - .buttonStyle(.borderless) - .disabled(state.selection == nil) + } + .buttonStyle(.borderless) + .disabled(state.selection == nil) } private var plusButton: some View { @@ -378,9 +377,9 @@ extension AddCarbs { state.plus() } label: { Image(systemName: "plus.circle.fill") - }.frame(maxWidth: .infinity, alignment: .trailing) - .buttonStyle(.borderless) - .disabled(state.selection == nil) + } + .buttonStyle(.borderless) + .disabled(state.selection == nil) } private func delete(at offsets: IndexSet) { From 78a31665617a96102f3c15b08307c7b447eea8e0 Mon Sep 17 00:00:00 2001 From: "Jon B.M" Date: Tue, 3 Dec 2024 23:44:45 +0100 Subject: [PATCH 4/4] Add plus button to the meal preset list --- .../Core_Data.xcdatamodel/contents | 4 +- .../Main/en.lproj/Localizable.strings | 3 + .../AddCarbs/View/AddCarbsRootView.swift | 109 +++++++++--------- 3 files changed, 59 insertions(+), 57 deletions(-) diff --git a/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents b/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents index 6a6c521bdd..09d7e0645e 100644 --- a/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents +++ b/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -116,7 +116,7 @@ - + diff --git a/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings index 76a51a2109..cbd65f3ad7 100644 --- a/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings @@ -1581,6 +1581,9 @@ Enact a temp Basal or a temp target */ /* Search Saved Food presets */ "Search" = "Search"; +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift index 8302793d47..4349b22bec 100644 --- a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift +++ b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift @@ -17,10 +17,12 @@ extension AddCarbs { @State private var presentPresets = false @State private var string = "" @State private var newPreset: (dish: String, carbs: Decimal, fat: Decimal, protein: Decimal) = ("", 0, 0, 0) - + @FetchRequest( entity: Presets.entity(), - sortDescriptors: [NSSortDescriptor(key: "dish", ascending: true)] + sortDescriptors: [NSSortDescriptor(key: "dish", ascending: true)], predicate: NSPredicate( + format: "dish != %@", " " as String + ) ) var carbPresets: FetchedResults @Environment(\.managedObjectContext) var moc @@ -105,9 +107,6 @@ extension AddCarbs { label: { Image(systemName: "plus.circle") }.tint(.blue).buttonStyle(.borderless) } } - .popover(isPresented: $isPromptPresented) { - presetPopover - } } // Optional Hypo Treatment if state.carbs > 0, let profile = state.id, profile != "None", state.carbsRequired != nil { @@ -152,39 +151,6 @@ extension AddCarbs { .sheet(isPresented: $presentPresets, content: { presetView }) } - private var presetPopover: some View { - Form { - Section { - TextField("Name Of Dish", text: $dish) - Button { - saved = true - if dish != "", saved { - let preset = Presets(context: moc) - preset.dish = dish - preset.fat = state.fat as NSDecimalNumber - preset.protein = state.protein as NSDecimalNumber - preset.carbs = state.carbs as NSDecimalNumber - try? moc.save() - - state.selection = preset - if state.combinedPresets.isEmpty { - state.addPresetToNewMeal() - } - - saved = false - isPromptPresented = false - } - } - label: { Text("Save") } - Button { - dish = "" - saved = false - isPromptPresented = false } - label: { Text("Cancel") } - } header: { Text("Enter Meal Preset Name") } - }.dynamicTypeSize(...DynamicTypeSize.xxLarge) - } - private var empty: Bool { state.carbs <= 0 && state.fat <= 0 && state.protein <= 0 } @@ -228,7 +194,7 @@ extension AddCarbs { if !empty { Section { Button { - isPromptPresented = true + addfromCarbsView() } label: { HStack { @@ -242,20 +208,30 @@ extension AddCarbs { header: { Text("Save") } } - if carbPresets.count > 4 { + let filtered = carbPresets.filter { ($0.dish ?? "").count > 1 }.removeDublicates() + if filtered.count > 4 { Section { TextField("Search", text: $string) } header: { Text("Search") } } - let data = string.isEmpty ? carbPresets - .filter { _ in true } : carbPresets + let data = string.isEmpty ? filtered : carbPresets .filter { ($0.dish ?? "").localizedCaseInsensitiveContains(string) } Section { ForEach(data, id: \.self) { preset in presetsList(for: preset) }.onDelete(perform: delete) - } header: { Text("Saved Food") } + } header: { + HStack { + Text("Saved Food") + Button { + state.presetToEdit = Presets(context: moc) + newPreset = (NSLocalizedString("New", comment: ""), 0, 0, 0) + state.edit = true + } label: { Image(systemName: "plus").font(.system(size: 22)) } + .buttonStyle(.borderless).frame(maxWidth: .infinity, alignment: .trailing) + } + } } .sheet(isPresented: $state.edit, content: { editView }) } @@ -264,31 +240,32 @@ extension AddCarbs { Form { Section { HStack { - TextField("\(state.presetToEdit?.dish ?? "")", text: $newPreset.dish) + TextField("", text: $newPreset.dish) } HStack { Text("Carbs").foregroundStyle(.secondary) Spacer() - DecimalTextField("\(state.presetToEdit?.carbs ?? 0)", value: $newPreset.carbs, formatter: formatter) + DecimalTextField("0", value: $newPreset.carbs, formatter: formatter) } HStack { Text("Fat").foregroundStyle(.secondary) Spacer() - DecimalTextField("\(state.presetToEdit?.fat ?? 0)", value: $newPreset.fat, formatter: formatter) + DecimalTextField("0", value: $newPreset.fat, formatter: formatter) } HStack { Text("Protein").foregroundStyle(.secondary) Spacer() - DecimalTextField("\(state.presetToEdit?.protein ?? 0)", value: $newPreset.protein, formatter: formatter) + DecimalTextField("0", value: $newPreset.protein, formatter: formatter) } - } header: { Text("Edit") } + } header: { Text(!addingNew ? NSLocalizedString("Edit", comment: "") : NSLocalizedString("Add", comment: "")) } Section { Button { save() } label: { Text("Save") } .frame(maxWidth: .infinity, alignment: .center) - .listRowBackground(Color(.systemBlue)) + .listRowBackground(!disabled ? Color(.systemBlue) : Color(.systemGray4)) .tint(.white) + .disabled(disabled) } } } @@ -324,7 +301,8 @@ extension AddCarbs { @ViewBuilder private func presetsList(for preset: Presets) -> some View { let dish = preset.dish ?? "" - if dish != "" { + // Only list saved entries + if !preset.hasChanges { HStack { VStack(alignment: .leading) { Text(dish) @@ -400,13 +378,20 @@ extension AddCarbs { preset.carbs = newPreset.carbs as NSDecimalNumber preset.fat = newPreset.fat as NSDecimalNumber preset.protein = newPreset.protein as NSDecimalNumber + } else if !disabled { + let preset = Presets(context: moc) + preset.carbs = newPreset.carbs as NSDecimalNumber + preset.fat = newPreset.fat as NSDecimalNumber + preset.protein = newPreset.protein as NSDecimalNumber + preset.dish = newPreset.dish + } - if moc.hasChanges { - do { - try moc.save() - } catch { /* To do: add error */ } - } + if moc.hasChanges { + do { + try moc.save() + } catch { /* To do: add error */ } } + state.edit = false } @@ -417,12 +402,26 @@ extension AddCarbs { newPreset.protein = (state.presetToEdit?.protein ?? 0) as Decimal } + private func addfromCarbsView() { + newPreset = (NSLocalizedString("New", comment: ""), state.carbs, state.fat, state.protein) + state.edit = true + } + private func reset() { presentPresets = false string = "" state.presetToEdit = nil // Probably not needed state.edit = false // Probably not needed } + + private var disabled: Bool { + (newPreset == (NSLocalizedString("New", comment: ""), 0, 0, 0)) || (newPreset.dish == "") || + (newPreset.carbs + newPreset.fat + newPreset.protein <= 0) + } + + private var addingNew: Bool { + ((state.presetToEdit?.dish) == nil) + } } }