Files
SwimBuddy/targets/watch/Connectivity/PhoneConnector.swift
T

105 lines
3.8 KiB
Swift

import Foundation
import WatchConnectivity
class PhoneConnector: NSObject, ObservableObject, WCSessionDelegate {
static let shared = PhoneConnector()
var workoutManager: WorkoutManager? {
didSet {
if let pending = pendingWorkouts {
pending.forEach { workoutManager?.addWorkoutFromPhone($0) }
pendingWorkouts = nil
}
}
}
private var pendingWorkouts: [StoredWorkout]?
private override init() {
super.init()
}
// 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("[PhoneConnector] sendMessage failed, falling back to transferUserInfo: \(error)")
WCSession.default.transferUserInfo(message)
}
} else {
WCSession.default.transferUserInfo(message)
}
}
// MARK: - WCSessionDelegate
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print("[PhoneConnector] Activated: state=\(activationState.rawValue), isReachable=\(session.isReachable)")
}
func sessionReachabilityDidChange(_ session: WCSession) {
print("[PhoneConnector] Reachability changed: isReachable=\(session.isReachable)")
}
func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
print("[PhoneConnector] didReceiveMessage (no reply)")
DispatchQueue.main.async { [weak self] in
self?.handleMessage(message)
}
}
func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
print("[PhoneConnector] didReceiveMessage (with reply)")
replyHandler(["status": "received"])
DispatchQueue.main.async { [weak self] in
self?.handleMessage(message)
}
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any]) {
print("[PhoneConnector] didReceiveUserInfo")
DispatchQueue.main.async { [weak self] in
self?.handleMessage(userInfo)
}
}
private func handleMessage(_ message: [String: Any]) {
guard let type = message["type"] as? String else {
print("[PhoneConnector] No type in message: \(message.keys)")
return
}
print("[PhoneConnector] Received message type: \(type)")
switch type {
case "workoutPlan":
guard let data = try? JSONSerialization.data(withJSONObject: message) else {
print("[PhoneConnector] Failed to serialize message")
return
}
print("[PhoneConnector] JSON data: \(String(data: data, encoding: .utf8) ?? "nil")")
do {
let workout = try JSONDecoder().decode(StoredWorkout.self, from: data)
print("[PhoneConnector] Decoded workout: \(workout.name ?? "nil"), sets: \(workout.sets.count)")
if let manager = workoutManager {
manager.addWorkoutFromPhone(workout)
} else {
print("[PhoneConnector] workoutManager not set, queuing workout")
if pendingWorkouts == nil { pendingWorkouts = [] }
pendingWorkouts?.append(workout)
}
} catch {
print("[PhoneConnector] Decode error: \(error)")
}
default:
print("[PhoneConnector] Unknown type: \(type)")
}
}
}