Allow cap deletion
This commit is contained in:
parent
441197144f
commit
37fb3b4a88
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user