iOS Build 23
This commit is contained in:
@@ -80,6 +80,10 @@ struct DataManagementSection: View {
|
||||
@Binding var activeSheet: SheetType?
|
||||
@State private var showingResetAlert = false
|
||||
@State private var isExporting = false
|
||||
@State private var isMigrating = false
|
||||
@State private var showingMigrationAlert = false
|
||||
@State private var isDeletingImages = false
|
||||
@State private var showingDeleteImagesAlert = false
|
||||
|
||||
var body: some View {
|
||||
Section("Data Management") {
|
||||
@@ -117,6 +121,48 @@ struct DataManagementSection: View {
|
||||
}
|
||||
.foregroundColor(.primary)
|
||||
|
||||
// Migrate Image Names
|
||||
Button(action: {
|
||||
showingMigrationAlert = true
|
||||
}) {
|
||||
HStack {
|
||||
if isMigrating {
|
||||
ProgressView()
|
||||
.scaleEffect(0.8)
|
||||
Text("Migrating Images...")
|
||||
.foregroundColor(.secondary)
|
||||
} else {
|
||||
Image(systemName: "photo.badge.arrow.down")
|
||||
.foregroundColor(.orange)
|
||||
Text("Fix Image Names")
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.disabled(isMigrating)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
// Delete All Images
|
||||
Button(action: {
|
||||
showingDeleteImagesAlert = true
|
||||
}) {
|
||||
HStack {
|
||||
if isDeletingImages {
|
||||
ProgressView()
|
||||
.scaleEffect(0.8)
|
||||
Text("Deleting Images...")
|
||||
.foregroundColor(.secondary)
|
||||
} else {
|
||||
Image(systemName: "trash")
|
||||
.foregroundColor(.red)
|
||||
Text("Delete All Images")
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.disabled(isDeletingImages)
|
||||
.foregroundColor(.red)
|
||||
|
||||
// Reset All Data
|
||||
Button(action: {
|
||||
showingResetAlert = true
|
||||
@@ -140,6 +186,26 @@ struct DataManagementSection: View {
|
||||
"Are you sure you want to reset all data? This will permanently delete:\n\n• All gyms and their information\n• All problems and their images\n• All climbing sessions\n• All attempts and progress data\n\nThis action cannot be undone. Consider exporting your data first."
|
||||
)
|
||||
}
|
||||
.alert("Fix Image Names", isPresented: $showingMigrationAlert) {
|
||||
Button("Cancel", role: .cancel) {}
|
||||
Button("Fix Names") {
|
||||
migrateImageNames()
|
||||
}
|
||||
} message: {
|
||||
Text(
|
||||
"This will rename all existing image files to use a consistent naming system across devices.\n\nThis improves sync reliability between iOS and Android. Your images will not be lost, only renamed.\n\nThis is safe to run multiple times."
|
||||
)
|
||||
}
|
||||
.alert("Delete All Images", isPresented: $showingDeleteImagesAlert) {
|
||||
Button("Cancel", role: .cancel) {}
|
||||
Button("Delete", role: .destructive) {
|
||||
deleteAllImages()
|
||||
}
|
||||
} message: {
|
||||
Text(
|
||||
"This will permanently delete ALL image files from your device.\n\nProblems will keep their references but the actual image files will be removed. This cannot be undone.\n\nConsider exporting your data first if you want to keep your images."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func exportDataAsync() {
|
||||
@@ -152,6 +218,75 @@ struct DataManagementSection: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func migrateImageNames() {
|
||||
isMigrating = true
|
||||
Task {
|
||||
await MainActor.run {
|
||||
ImageManager.shared.migrateImageNamesToDeterministic(dataManager: dataManager)
|
||||
isMigrating = false
|
||||
dataManager.successMessage = "Image names fixed successfully!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func deleteAllImages() {
|
||||
isDeletingImages = true
|
||||
Task {
|
||||
await MainActor.run {
|
||||
deleteAllImageFiles()
|
||||
isDeletingImages = false
|
||||
dataManager.successMessage = "All images deleted successfully!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func deleteAllImageFiles() {
|
||||
let imageManager = ImageManager.shared
|
||||
let fileManager = FileManager.default
|
||||
|
||||
// Delete all images from the images directory
|
||||
let imagesDir = imageManager.imagesDirectory
|
||||
do {
|
||||
let imageFiles = try fileManager.contentsOfDirectory(
|
||||
at: imagesDir, includingPropertiesForKeys: nil)
|
||||
var deletedCount = 0
|
||||
|
||||
for imageFile in imageFiles {
|
||||
do {
|
||||
try fileManager.removeItem(at: imageFile)
|
||||
deletedCount += 1
|
||||
} catch {
|
||||
print("Failed to delete image: \(imageFile.lastPathComponent)")
|
||||
}
|
||||
}
|
||||
|
||||
print("Deleted \(deletedCount) image files")
|
||||
} catch {
|
||||
print("Failed to access images directory: \(error)")
|
||||
}
|
||||
|
||||
// Delete all images from backup directory
|
||||
let backupDir = imageManager.backupDirectory
|
||||
do {
|
||||
let backupFiles = try fileManager.contentsOfDirectory(
|
||||
at: backupDir, includingPropertiesForKeys: nil)
|
||||
for backupFile in backupFiles {
|
||||
try? fileManager.removeItem(at: backupFile)
|
||||
}
|
||||
} catch {
|
||||
print("Failed to access backup directory: \(error)")
|
||||
}
|
||||
|
||||
// Clear image paths from all problems
|
||||
let updatedProblems = dataManager.problems.map { problem in
|
||||
problem.updated(imagePaths: [])
|
||||
}
|
||||
|
||||
for problem in updatedProblems {
|
||||
dataManager.updateProblem(problem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AppInfoSection: View {
|
||||
|
||||
Reference in New Issue
Block a user