Add WatchConnectivity for bidirectional iOS-Watch sync

Implement real-time sync between iOS and Apple Watch apps using
WatchConnectivity framework. This replaces reliance on CloudKit
which doesn't work reliably in simulators.

- Add WatchConnectivityManager to both iOS and Watch targets
- Sync workouts, splits, exercises, and logs between devices
- Update iOS views to trigger sync on data changes
- Add onChange observer to ExerciseView for live progress updates
- Configure App Groups for shared container storage
- Add Watch app views: WorkoutLogsView, WorkoutLogListView, ExerciseProgressView
This commit is contained in:
2026-01-19 19:15:38 -05:00
parent 8b6250e4d6
commit 9a881e841b
21 changed files with 1581 additions and 67 deletions

View File

@@ -125,6 +125,14 @@ struct ExerciseView: View {
.onAppear {
progress = Int(workoutLog.currentStateIndex)
}
.onChange(of: workoutLog.currentStateIndex) { _, newValue in
// Update local state when CoreData changes (e.g., from Watch sync)
if progress != Int(newValue) {
withAnimation(.easeInOut(duration: 0.2)) {
progress = Int(newValue)
}
}
}
}
private func updateLogStatus() {
@@ -162,6 +170,7 @@ struct ExerciseView: View {
private func saveChanges() {
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
}
}

View File

@@ -48,5 +48,6 @@ struct NotesEditView: View {
private func saveChanges() {
workoutLog.notes = notesText
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
}
}

View File

@@ -163,5 +163,6 @@ struct PlanEditView: View {
}
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
}
}

View File

@@ -133,12 +133,14 @@ struct WorkoutLogListView: View {
}
updateWorkoutStatus()
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
}
private func completeLog(_ log: WorkoutLog) {
log.status = .completed
updateWorkoutStatus()
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
}
private func updateWorkoutStatus() {
@@ -164,6 +166,7 @@ struct WorkoutLogListView: View {
log.order = Int32(index)
}
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
}
private func addExerciseFromSplit(_ exercise: Exercise) {
@@ -188,6 +191,7 @@ struct WorkoutLogListView: View {
log.workout = workout
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
// Navigate to the new exercise view
newlyAddedLog = log

View File

@@ -88,6 +88,7 @@ struct WorkoutLogsView: View {
withAnimation {
viewContext.delete(item)
try? viewContext.save()
WatchConnectivityManager.shared.syncAllData()
itemToDelete = nil
}
}
@@ -167,11 +168,17 @@ struct SplitPickerSheet: View {
workoutLog.sets = exercise.sets
workoutLog.reps = exercise.reps
workoutLog.weight = exercise.weight
workoutLog.loadType = exercise.loadType
workoutLog.duration = exercise.duration
workoutLog.status = .notStarted
workoutLog.workout = workout
}
try? viewContext.save()
// Sync to Watch
WatchConnectivityManager.shared.syncAllData()
dismiss()
}
}