diff --git a/Caps/Data/Database.swift b/Caps/Data/Database.swift index 3a8e1b7..030381d 100644 --- a/Caps/Data/Database.swift +++ b/Caps/Data/Database.swift @@ -551,6 +551,20 @@ final class Database: ObservableObject { Int(url.lastPathComponent.components(separatedBy: "-").first!) } + private func imageId(from url: URL) -> CapImage? { + let parts = url.deletingPathExtension().lastPathComponent.components(separatedBy: "-") + guard parts.count == 2 else { + log("File \(url.lastPathComponent) is not a cap image") + return nil + } + guard let capId = Int(parts.first!), + let version = Int(parts.last!) else { + log("File \(url.lastPathComponent) is not a cap image") + return nil + } + return .init(cap: capId, version: version) + } + private func uploadAllImages() async { guard hasServerAuthentication else { log("No server authentication to upload to server") @@ -929,7 +943,7 @@ final class Database: ObservableObject { classifierClasses.count } - func imageCacheSize() async -> Int { + func imageCacheSize() -> Int { fm.directorySize(images.folder) } @@ -940,6 +954,37 @@ final class Database: ObservableObject { var classifierSize: Int { localClassifierUrl.fileSize } + + private var cachedImages: [URL] { + do { + return try fm.contentsOfDirectory(at: images.folder, includingPropertiesForKeys: nil) + } catch { + log("Failed to get cached images: \(error)") + return [] + } + } + + func clearImageCache() { + let allImages = cachedImages + let unnecessaryImages = allImages + .filter { + guard let id = imageId(from: $0) else { + return true + } + guard let cap = caps[id.cap] else { + return true + } + return cap.mainImage != id.version + } + log("Deleting \(unnecessaryImages.count) of \(allImages.count) cached images") + for cachedImage in unnecessaryImages { + do { + try fm.removeItem(at: cachedImage) + } catch { + log("Failed to delete cached image \(cachedImage.lastPathComponent): \(error)") + } + } + } } extension Database { diff --git a/Caps/Views/SettingsView.swift b/Caps/Views/SettingsView.swift index 76d6f80..eb43920 100644 --- a/Caps/Views/SettingsView.swift +++ b/Caps/Views/SettingsView.swift @@ -54,6 +54,12 @@ struct SettingsView: View { SettingsStatisticRow(label: "Image cache", value: byteString(imageCacheSize)) SettingsStatisticRow(label: "Database", value: byteString(database.databaseSize)) SettingsStatisticRow(label: "Classifier", value: byteString(database.classifierSize)) + HStack { + Spacer() + Button("Clear image cache", action: clearImageCache) + .padding() + Spacer() + } }.padding(.horizontal) Spacer() } @@ -64,8 +70,15 @@ struct SettingsView: View { } private func updateImageCacheSize() { + imageCacheSize = database.imageCacheSize() + } + + private func clearImageCache() { Task { - imageCacheSize = await database.imageCacheSize() + database.clearImageCache() + DispatchQueue.main.async { + updateImageCacheSize() + } } }