feat: initial project scaffold with Watch companion app

This commit is contained in:
2026-08-04 17:28:06 +02:00
parent adbb4f01c5
commit 43b6467efb
65 changed files with 6361 additions and 166 deletions
@@ -0,0 +1,70 @@
import Foundation
import WatchConnectivity
class PhoneConnector: NSObject, ObservableObject, WCSessionDelegate {
static let shared = PhoneConnector()
private var workoutManager: WorkoutManager?
private override init() {
super.init()
}
func setup(workoutManager: WorkoutManager) {
self.workoutManager = workoutManager
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}
// Send completed workout data to phone
static func sendCompletedWorkout(_ laps: [[String: Any]], duration: TimeInterval, workoutId: String) {
let message: [String: Any] = [
"type": "workoutCompleted",
"workoutId": workoutId,
"laps": laps,
"duration": duration,
]
if WCSession.default.isReachable {
WCSession.default.sendMessage(message, replyHandler: nil) { error in
print("Failed to send: \(error)")
}
} else {
WCSession.default.transferUserInfo(message)
}
}
// MARK: - WCSessionDelegate
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print("WatchConnectivity activated: \(activationState.rawValue)")
}
func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
DispatchQueue.main.async { [weak self] in
self?.handleMessage(message)
}
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
DispatchQueue.main.async { [weak self] in
self?.handleMessage(userInfo)
}
}
private func handleMessage(_ message: [String: Any]) {
guard let type = message["type"] as? String else { return }
switch type {
case "workoutPlan":
if let data = try? JSONSerialization.data(withJSONObject: message),
let workout = try? JSONDecoder().decode(StoredWorkout.self, from: data) {
workoutManager?.addWorkoutFromPhone(workout)
}
default:
break
}
}
}