Skip to content

Commit

Permalink
Swipe to delete, and move add buttons
Browse files Browse the repository at this point in the history
Co-Authored-By: Deniz Cengiz <48965855+dnzxy@users.noreply.github.com>
  • Loading branch information
BrianWieder and dnzxy committed May 2, 2024
1 parent 2fe7d9e commit bf36c87
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 122 deletions.
2 changes: 0 additions & 2 deletions FreeAPS/Sources/Modules/DataTable/DataTableDataFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,6 @@ enum DataTable {

if isExternal ?? false {
bolusText += " " + NSLocalizedString("External", comment: "External Insulin")
} else if isSMB ?? false {
bolusText += " " + NSLocalizedString("SMB", comment: "SMB")
}

return numberFormatter
Expand Down
4 changes: 2 additions & 2 deletions FreeAPS/Sources/Modules/DataTable/DataTableStateModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ extension DataTable {
.store(in: &lifetime)
}

func deleteGlucose(at index: Int) {
let id = glucose[index].id
func deleteGlucose(_ glucose: Glucose) {
let id = glucose.id
provider.deleteGlucose(id: id)

let fetchRequest: NSFetchRequest<NSFetchRequestResult>
Expand Down
256 changes: 138 additions & 118 deletions FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ extension DataTable {
let resolver: Resolver
@StateObject var state = StateModel()

@State private var isRemoveCarbsAlertPresented = false
@State private var removeCarbsAlert: Alert?
@State private var isRemoveInsulinAlertPresented = false
@State private var removeInsulinAlert: Alert?
@State private var isRemoveHistoryItemAlertPresented: Bool = false
@State private var alertTitle: String = ""
@State private var alertMessage: String = ""
@State private var alertTreatmentToDelete: Treatment?
@State private var alertGlucoseToDelete: Glucose?
@State private var showManualGlucose = false
@State private var showExternalInsulin = false
@State private var isAmountUnconfirmed = true
Expand Down Expand Up @@ -64,7 +65,7 @@ extension DataTable {
.navigationBarTitleDisplayMode(.automatic)
.navigationBarItems(
leading: Button("Close", action: state.hideModal),
trailing: state.mode == .glucose ? EditButton().asAny() : EmptyView().asAny()
trailing: state.mode == .glucose ? addGlucoseButton.asAny() : addInsulinButton.asAny()
)
.sheet(isPresented: $showExternalInsulin, onDismiss: {
if isAmountUnconfirmed {
Expand All @@ -79,24 +80,35 @@ extension DataTable {
}
}

private var treatmentsList: some View {
List {
HStack {
Spacer()
Button(action: { showExternalInsulin = true
state.externalInsulinDate = Date() }, label: {
HStack {
Text("Add")
.foregroundColor(Color.secondary)
.font(.caption)

Image(systemName: "syringe")
.foregroundColor(Color.accentColor)
}.frame(maxWidth: .infinity, alignment: .trailing)
private var addInsulinButton: some View {
Button(action: { showExternalInsulin = true
state.externalInsulinDate = Date() }, label: {
Text("Add")
.foregroundColor(Color.secondary)
.font(.caption)
Image(systemName: "syringe")
.foregroundColor(Color.accentColor)
}).buttonStyle(.borderless)
}

}).buttonStyle(.borderless)
private var addGlucoseButton: some View {
Button(
action: {
showManualGlucose = true
state.manualGlucose = 0
},
label: {
Text("Add")
.foregroundColor(Color.secondary)
.font(.caption)
Image(systemName: "drop")
.foregroundColor(Color.accentColor)
}
).buttonStyle(.borderless)
}

private var treatmentsList: some View {
List {
if !state.treatments.isEmpty {
ForEach(state.treatments) { item in
treatmentView(item)
Expand All @@ -111,24 +123,10 @@ extension DataTable {

private var glucoseList: some View {
List {
HStack {
Text("Time").foregroundStyle(.secondary)
Spacer()
Text(state.units.rawValue).foregroundStyle(.secondary)
Button(
action: {
showManualGlucose = true
state.manualGlucose = 0
},
label: { Image(systemName: "plus.circle.fill").foregroundStyle(.secondary)
}
).buttonStyle(.borderless)
}
if !state.glucose.isEmpty {
ForEach(state.glucose) { item in
glucoseView(item)
}
.onDelete(perform: deleteGlucose)
} else {
HStack {
Text(NSLocalizedString("No data.", comment: "No data text when no entries in history list"))
Expand Down Expand Up @@ -181,84 +179,75 @@ extension DataTable {

@ViewBuilder private func treatmentView(_ item: Treatment) -> some View {
HStack {
Image(systemName: "circle.fill").foregroundColor(item.color)
Text(dateFormatter.string(from: item.date))
.moveDisabled(true)
Text(item.type.name)
if item.type == .bolus || item.type == .carbs {
Image(systemName: "circle.fill").foregroundColor(item.color).padding(.vertical)
} else {
Image(systemName: "circle.fill").foregroundColor(item.color)
}
Text((item.isSMB ?? false) ? "SMB" : item.type.name)
Text(item.amountText).foregroundColor(.secondary)
if let duration = item.durationText {
Text(duration).foregroundColor(.secondary)
}
Spacer()
Text(dateFormatter.string(from: item.date))
.moveDisabled(true)
}
.swipeActions {
// Only allow swipe to delete if a carb, fpu, or bolus entry.
if item.type == .carbs || item.type == .fpus || item.type == .bolus {
Button(
"Delete",
systemImage: "trash.fill",
role: .none,
action: {
alertTreatmentToDelete = item

if item.type == .carbs {
if item.note != "" {
Spacer()
Text(item.note ?? "").foregroundColor(.brown)
}
Spacer()
Image(systemName: "xmark.circle").foregroundColor(.secondary)
.contentShape(Rectangle())
.padding(.vertical)
.onTapGesture {
removeCarbsAlert = Alert(
title: Text("Delete carbs?"),
message: Text(item.amountText),
primaryButton: .destructive(
Text("Delete"),
action: { state.deleteCarbs(item) }
),
secondaryButton: .cancel()
)
isRemoveCarbsAlertPresented = true
}
.alert(isPresented: $isRemoveCarbsAlertPresented) {
removeCarbsAlert!
}
}
if item.type == .carbs {
alertTitle = "Delete Carbs?"
alertMessage = dateFormatter.string(from: item.date) + ", " + item.amountText
} else if item.type == .fpus {
alertTitle = "Delete Carb Equivalents?"
alertMessage = "All FPUs of the meal will be deleted."
} else {
// item is insulin treatment; item.type == .bolus
alertTitle = "Delete Insulin?"
alertMessage = dateFormatter.string(from: item.date) + ", " + item.amountText

if item.type == .fpus {
Spacer()
Image(systemName: "xmark.circle").foregroundColor(.secondary)
.contentShape(Rectangle())
.padding(.vertical)
.onTapGesture {
removeCarbsAlert = Alert(
title: Text("Delete carb equivalents?"),
message: Text(""), // Temporary fix. New to fix real amount of carb equivalents later
primaryButton: .destructive(
Text("Delete"),
action: { state.deleteCarbs(item) }
),
secondaryButton: .cancel()
)
isRemoveCarbsAlertPresented = true
}
.alert(isPresented: $isRemoveCarbsAlertPresented) {
removeCarbsAlert!
if item.isSMB ?? false {
// Add text snippet, so that alert message is more descriptive for SMBs
alertMessage += " SMB"
}
}

isRemoveHistoryItemAlertPresented = true
}
).tint(.red)
}
}
.disabled(
item.type == .tempBasal || item.type == .tempTarget || item.type == .resume || item
.type == .suspend
)
.alert(
Text(NSLocalizedString(alertTitle, comment: "")),
isPresented: $isRemoveHistoryItemAlertPresented
) {
Button("Cancel", role: .cancel) {}
Button("Delete", role: .destructive) {
guard let treatmentToDelete = alertTreatmentToDelete else {
debug(.default, "Cannot gracefully unwrap alertTreatmentToDelete!")
return
}

if item.type == .bolus {
Spacer()
Image(systemName: "xmark.circle").foregroundColor(.secondary)
.contentShape(Rectangle())
.padding(.vertical)
.onTapGesture {
removeInsulinAlert = Alert(
title: Text("Delete insulin?"),
message: Text(item.amountText),
primaryButton: .destructive(
Text("Delete"),
action: { state.deleteInsulin(item) }
),
secondaryButton: .cancel()
)
isRemoveInsulinAlertPresented = true
}
.alert(isPresented: $isRemoveInsulinAlertPresented) {
removeInsulinAlert!
}
if treatmentToDelete.type == .carbs || treatmentToDelete.type == .fpus {
state.deleteCarbs(treatmentToDelete)
} else {
state.deleteInsulin(treatmentToDelete)
}
}
} message: {
Text("\n" + NSLocalizedString(alertMessage, comment: ""))
}
}

Expand Down Expand Up @@ -327,24 +316,55 @@ extension DataTable {
}

@ViewBuilder private func glucoseView(_ item: Glucose) -> some View {
VStack(alignment: .leading, spacing: 4) {
HStack {
Text(dateFormatter.string(from: item.glucose.dateString))
Spacer()
Text(item.glucose.glucose.map {
glucoseFormatter.string(from: Double(
state.units == .mmolL ? $0.asMmolL : Decimal($0)
) as NSNumber)!
} ?? "--")
Text(state.units.rawValue)
Text(item.glucose.direction?.symbol ?? "--")
}
Text("ID: " + item.glucose.id).font(.caption2).foregroundColor(.secondary)
HStack {
Text(item.glucose.glucose.map {
glucoseFormatter.string(from: Double(
state.units == .mmolL ? $0.asMmolL : Decimal($0)
) as NSNumber)!
} ?? "--")
Text(item.glucose.direction?.symbol ?? "--")
Spacer()

Text(dateFormatter.string(from: item.glucose.dateString))
}
}
.swipeActions {
Button(
"Delete",
systemImage: "trash.fill",
role: .none,
action: {
alertGlucoseToDelete = item

private func deleteGlucose(at offsets: IndexSet) {
state.deleteGlucose(at: offsets[offsets.startIndex])
let valueText = glucoseFormatter.string(from: Double(
state.units == .mmolL ? Double(item.glucose.value.asMmolL) : item.glucose.value
) as NSNumber)! + " " + state.units.rawValue

alertTitle = "Delete Glucose?"
alertMessage = dateFormatter.string(from: item.glucose.dateString) + ", " + valueText

isRemoveHistoryItemAlertPresented = true
}
).tint(.red)
}
.alert(
Text(NSLocalizedString(alertTitle, comment: "")),
isPresented: $isRemoveHistoryItemAlertPresented
) {
Button("Cancel", role: .cancel) {}
Button("Delete", role: .destructive) {
// gracefully unwrap value here.
// value cannot ever really be nil because it is an existing(!) table entry
// but just to be sure.
guard let glucoseToDelete = alertGlucoseToDelete else {
print("Cannot gracefully unwrap alertTreatmentToDelete!")
return
}

state.deleteGlucose(glucoseToDelete)
}
} message: {
Text("\n" + NSLocalizedString(alertMessage, comment: ""))
}
}
}
}

0 comments on commit bf36c87

Please sign in to comment.