mycode/myApp/Keging/IOS/PhoneSync.swift
songyc macbook 4d91c48844 feat(keging): 워치 연결 배지·미연결 시작 경고 + 세팅 기기별 독립(워치 좌스와이프 세팅) + 워치 진동 강화 (7차)
- 폰 첫 화면: 시작 버튼 위 워치 연결 배지(연결됨/미연결/미연동 — iOS 제약상
  '연결됨'은 워치 앱 포그라운드 기준, 설정·도움말에 안내), 미연결 시작 시 확인 창
  (기록은 동일함을 안내), 설정 > 애플워치 > '워치 미연결 경고' 토글.
  단축어·autoStart는 경고 없이 통과
- 세팅 동기화 전면 제거(기기마다 진동 질감이 달라 각자 최적화) — 동기화는 기록만.
  워치 시작 화면 왼쪽 스와이프로 전용 세팅 페이지(TabView .page): 준비/수축/이완/
  횟수 스테퍼(2줄 컴팩트 라벨), 진동 2종 피커(선택 즉시 미리 울림), 운동 유형·강도.
  요약 라인 즉시 반영(SettingsStore EnvironmentObject)
- 워치 진동 강화 재설계: 기본=.start 1방, 톡톡=.start 2방(0.35s),
  지이이잉=.retry 2방 연결(~1.3s), 완주=.retry×3+.success(~2.5s), 세대 토큰 취소
- 도움말 4건·번역(en/ja) 갱신, CLAUDE.md 현행화
- 시뮬 검증: 배지·경고 창·설정 토글, 워치 세팅 페이지(46mm·40mm)·요약 반영,
  3종 빌드 그린·경고 0·l10n 0/0/0

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UPmp29DQHY6Ahfss5SRopT
2026-09-03 03:05:28 +09:00

57 lines
1.7 KiB
Swift

//
// PhoneSync.swift
// Keging
//
// (iOS ) , .
// (2026-09-03, 7 )
// push/ .
//
import WatchConnectivity
final class PhoneSync: NSObject, WCSessionDelegate {
static let shared = PhoneSync()
private override init() { super.init() }
func activate() {
guard WCSession.isSupported() else { return }
let session = WCSession.default
session.delegate = self
session.activate()
}
private nonisolated func refreshLinkStatus() {
Task { @MainActor in WatchLinkStatus.shared.refresh() }
}
// MARK: WCSessionDelegate
nonisolated func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
refreshLinkStatus()
}
nonisolated func sessionDidBecomeInactive(_ session: WCSession) {}
nonisolated func sessionDidDeactivate(_ session: WCSession) {
session.activate()
}
nonisolated func sessionReachabilityDidChange(_ session: WCSession) {
refreshLinkStatus()
}
/// ·
nonisolated func sessionWatchStateDidChange(_ session: WCSession) {
refreshLinkStatus()
}
nonisolated func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
guard let data = userInfo["record"] as? Data,
let record = try? JSONDecoder().decode(SessionRecord.self, from: data) else { return }
Task { @MainActor in
RecordStore.shared.append(record)
}
}
}