186 lines
6.8 KiB
Swift
186 lines
6.8 KiB
Swift
//
|
||
// SettingsView.swift
|
||
// Workouts
|
||
//
|
||
// Created by rzen on 7/13/25 at 10:24 AM.
|
||
//
|
||
// Copyright 2025 Rouslan Zenetl. All Rights Reserved.
|
||
//
|
||
|
||
import SwiftUI
|
||
import SwiftData
|
||
import CloudKit
|
||
|
||
enum AppStorageKeys {
|
||
static let iCloudSyncEnabled = "iCloudSyncEnabled"
|
||
}
|
||
|
||
struct SettingsView: View {
|
||
@Environment(\.modelContext) private var modelContext
|
||
|
||
@State private var showingPopulateData = false
|
||
@State private var showingClearAllDataConfirmation = false
|
||
|
||
var splitsCount: Int? { try? modelContext.fetchCount(FetchDescriptor<Split>()) }
|
||
var musclesCount: Int? { try? modelContext.fetchCount(FetchDescriptor<Muscle>()) }
|
||
var muscleGroupsCount: Int? { try? modelContext.fetchCount(FetchDescriptor<MuscleGroup>()) }
|
||
var exerciseTypeCount: Int? { try? modelContext.fetchCount(FetchDescriptor<ExerciseType>()) }
|
||
var exercisesCount: Int? { try? modelContext.fetchCount(FetchDescriptor<Exercise>()) }
|
||
|
||
var body: some View {
|
||
NavigationStack {
|
||
Form {
|
||
Section (header: Text("Lists")) {
|
||
NavigationLink(destination: SplitsListView()) {
|
||
HStack {
|
||
Text("Splits")
|
||
Spacer()
|
||
Text("\(splitsCount ?? 0)")
|
||
.font(.caption)
|
||
.foregroundColor(.gray)
|
||
}
|
||
}
|
||
NavigationLink(destination: MuscleGroupsListView()) {
|
||
HStack {
|
||
Text("Muscle Groups")
|
||
Spacer()
|
||
Text("\(muscleGroupsCount ?? 0)")
|
||
.font(.caption)
|
||
.foregroundColor(.gray)
|
||
}
|
||
}
|
||
NavigationLink(destination: MusclesListView()) {
|
||
HStack {
|
||
Text("Muscles")
|
||
Spacer()
|
||
Text("\(musclesCount ?? 0)")
|
||
.font(.caption)
|
||
.foregroundColor(.gray)
|
||
}
|
||
}
|
||
NavigationLink(destination: ExerciseTypeListView()) {
|
||
HStack {
|
||
Text("Exercise Types")
|
||
Spacer()
|
||
Text("\(exerciseTypeCount ?? 0)")
|
||
.font(.caption)
|
||
.foregroundColor(.gray)
|
||
}
|
||
}
|
||
NavigationLink(destination: ExercisesListView()) {
|
||
HStack {
|
||
Text("Exercises")
|
||
Spacer()
|
||
Text("\(exercisesCount ?? 0)")
|
||
.font(.caption)
|
||
.foregroundColor(.gray)
|
||
}
|
||
}
|
||
}
|
||
|
||
Section(header: Text("Developer")) {
|
||
|
||
Button(action: {
|
||
showingPopulateData = true
|
||
}) {
|
||
HStack {
|
||
Label("Populate Data", systemImage: "plus")
|
||
Spacer()
|
||
}
|
||
}
|
||
.confirmationDialog(
|
||
"Populate Data?",
|
||
isPresented: $showingPopulateData,
|
||
titleVisibility: .hidden
|
||
) {
|
||
Button("Populate Data") {
|
||
DataLoader.create(modelContext: modelContext)
|
||
}
|
||
Button("Cancel", role: .cancel) {}
|
||
// } message: {
|
||
// Text("This action cannot be undone. All data will be permanently deleted.")
|
||
}
|
||
|
||
Button(action: {
|
||
showingClearAllDataConfirmation = true
|
||
}) {
|
||
HStack {
|
||
Label("Clear All Data", systemImage: "trash")
|
||
Spacer()
|
||
}
|
||
}
|
||
.foregroundColor(.red)
|
||
.confirmationDialog(
|
||
"Clear All Data?",
|
||
isPresented: $showingClearAllDataConfirmation,
|
||
titleVisibility: .visible
|
||
) {
|
||
Button("Clear All Data", role: .destructive) {
|
||
clearAllData()
|
||
}
|
||
Button("Cancel", role: .cancel) {}
|
||
} message: {
|
||
Text("This action cannot be undone. All data will be permanently deleted.")
|
||
}
|
||
}
|
||
}
|
||
.navigationTitle("Settings")
|
||
}
|
||
}
|
||
|
||
func deleteAllObjects<T: PersistentModel>(ofType type: T.Type, from context: ModelContext) throws {
|
||
let descriptor = FetchDescriptor<T>()
|
||
let allObjects = try context.fetch(descriptor)
|
||
for object in allObjects {
|
||
context.delete(object)
|
||
}
|
||
try context.save()
|
||
}
|
||
|
||
private func clearAllData () {
|
||
do {
|
||
try deleteAllObjects(ofType: ExerciseType.self, from: modelContext)
|
||
try deleteAllObjects(ofType: Exercise.self, from: modelContext)
|
||
try deleteAllObjects(ofType: Muscle.self, from: modelContext)
|
||
try deleteAllObjects(ofType: MuscleGroup.self, from: modelContext)
|
||
try deleteAllObjects(ofType: Split.self, from: modelContext)
|
||
try deleteAllObjects(ofType: SplitExerciseAssignment.self, from: modelContext)
|
||
try deleteAllObjects(ofType: Workout.self, from: modelContext)
|
||
try deleteAllObjects(ofType: WorkoutLog.self, from: modelContext)
|
||
try modelContext.save()
|
||
} catch {
|
||
print("Failed to clear all data: \(error)")
|
||
}
|
||
}
|
||
}
|
||
|
||
struct ExercisesListView: View {
|
||
var body: some View {
|
||
EntityListView<Exercise>(sort: [SortDescriptor(\Exercise.name)])
|
||
}
|
||
}
|
||
|
||
struct ExerciseTypeListView: View {
|
||
var body: some View {
|
||
EntityListView<ExerciseType>(sort: [SortDescriptor(\ExerciseType.name)])
|
||
}
|
||
}
|
||
|
||
struct MuscleGroupsListView: View {
|
||
var body: some View {
|
||
EntityListView<MuscleGroup>(sort: [SortDescriptor(\MuscleGroup.name)])
|
||
}
|
||
}
|
||
|
||
struct MusclesListView: View {
|
||
var body: some View {
|
||
EntityListView<Muscle>(sort: [SortDescriptor(\Muscle.name)])
|
||
}
|
||
}
|
||
|
||
struct SplitsListView: View {
|
||
var body: some View {
|
||
EntityListView<Split>(sort: [SortDescriptor(\Split.name)])
|
||
}
|
||
}
|