Allow cap deletion

This commit is contained in:
Christoph Hagen 2023-03-13 11:07:22 +01:00
parent 441197144f
commit 37fb3b4a88
2 changed files with 71 additions and 9 deletions

View File

@ -45,6 +45,9 @@ struct ContentView: View {
@State @State
var showUpdateCapNameAlert = false var showUpdateCapNameAlert = false
@State
var showDeleteCapAlert = false
@State @State
var updatedCapName = "" var updatedCapName = ""
@ -138,10 +141,13 @@ struct ContentView: View {
Label("Rename", systemSymbol: .pencil) Label("Rename", systemSymbol: .pencil)
} }
.tint(.purple) .tint(.purple)
Button(role: .destructive) { startDeleteCap(cap: cap) Button {
selectedCapId = cap.id
showDeleteCapAlert = true
} label: { } label: {
Label("Delete", systemSymbol: .trashCircleFill) Label("Delete", systemSymbol: .trashCircleFill)
} }
.tint(.red)
} }
.swipeActions(edge: .leading) { .swipeActions(edge: .leading) {
Button { Button {
@ -149,7 +155,7 @@ struct ContentView: View {
} label: { } label: {
Label("Images", systemSymbol: .photoStack) Label("Images", systemSymbol: .photoStack)
} }
.tint(.purple) .tint(.blue)
} }
} }
.refreshable { .refreshable {
@ -288,6 +294,14 @@ struct ContentView: View {
primaryButton: .default(Text("Download"), action: downloadClassifier), primaryButton: .default(Text("Download"), action: downloadClassifier),
secondaryButton: .cancel()) secondaryButton: .cancel())
} }
.alert(Text("Delete cap"),
isPresented: $showDeleteCapAlert,
actions: {
Button("Delete", role: .destructive, action: saveNewCapName)
Button("Cancel", role: .cancel, action: {})
}, message: {
Text("Confirm the deletion of cap \(selectedCapId ?? 0)")
})
.alert("Update name", isPresented: $showUpdateCapNameAlert, actions: { .alert("Update name", isPresented: $showUpdateCapNameAlert, actions: {
TextField("Name", text: $updatedCapName) TextField("Name", text: $updatedCapName)
Button("Update", action: saveNewCapName) Button("Update", action: saveNewCapName)
@ -405,8 +419,15 @@ struct ContentView: View {
showImageOverviewForCap = true showImageOverviewForCap = true
} }
private func startDeleteCap(cap: Cap) { private func startDeleteCap() {
// TODO: Implement guard let cap = selectedCapId else {
return
}
Task {
guard await database.delete(cap: cap) else {
return
}
}
} }
} }

View File

@ -35,7 +35,11 @@ final class Database: ObservableObject {
} }
var nextCapId: Int { var nextCapId: Int {
(caps.values.max()?.id ?? 0) + 1 var next = 1
while caps[next] != nil {
next += 1
}
return next
} }
@AppStorage("changed") @AppStorage("changed")
@ -621,15 +625,15 @@ final class Database: ObservableObject {
func delete(image: CapImage) async -> Bool { func delete(image: CapImage) async -> Bool {
guard hasServerAuthentication else { guard hasServerAuthentication else {
log("No authorization to set main image") log("No authorization to delete cap image")
return false return false
} }
guard var cap = cap(for: image.cap) else { guard let cap = cap(for: image.cap) else {
log("No cap \(image.cap) to set main image") log("No cap \(image.cap) to delete cap image")
return false return false
} }
guard image.version < cap.imageCount else { guard image.version < cap.imageCount else {
log("Invalid main image \(image.version) for \(cap.id) with only \(cap.imageCount) images") log("Invalid image \(image.version) to delete for \(cap.id) with only \(cap.imageCount) images")
return false return false
} }
@ -667,6 +671,43 @@ final class Database: ObservableObject {
} }
} }
func delete(cap: Int) async -> Bool {
guard hasServerAuthentication else {
log("No authorization to delete cap")
return false
}
guard caps[cap] != nil else {
log("No cap \(cap) to delete")
return false
}
let url = serverUrl.appendingPathComponent("delete/\(cap)")
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue(serverAuthenticationKey, forHTTPHeaderField: "key")
do {
let (_, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
log("Unexpected response deleting cap \(cap): \(response)")
return false
}
guard httpResponse.statusCode == 200 else {
log("Failed to delete cap \(cap): Response \(httpResponse.statusCode)")
return false
}
// Delete cached images
images.removeCachedImages(for: cap)
// Delete cap
caps[cap] = nil
log("Deleted cap \(cap)")
return true
} catch {
log("Failed to delete cap \(cap): \(error)")
return false
}
}
// MARK: Classification // MARK: Classification
/// The compiled recognition model on disk /// The compiled recognition model on disk