// // TrackingActivityAttributes.swift // Haru_Danim // // Live Activity 상태 정의. 앱 타깃과 위젯 확장 타깃 양쪽에 포함된다. // import Foundation import ActivityKit import SwiftUI nonisolated struct TrackingActivityAttributes: ActivityAttributes { nonisolated struct ContentState: Codable, Hashable { /// 대표로 표시할 행동 (설정: 가장 먼저/나중에 시작한 행동) var actionName: String var symbolName: String var colorHex: String var startedAt: Date /// 동시에 추적 중인 추가 행동 개수 (+1, +2 표시용) var extraCount: Int /// 대표 행동의 Action.uuid — 잠금화면 종료 버튼(RunActionIntent)이 사용. /// optional인 이유: 앱 업데이트 전에 만들어진 인플라이트 액티비티(키 없음)도 /// 디코딩되게 하기 위함 (WatchSnapshot.runningActionID와 동일 패턴) var actionID: String? = nil } } extension TrackingActivityAttributes.ContentState { var tintColor: Color { let cleaned = colorHex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var value: UInt64 = 0 Scanner(string: cleaned).scanHexInt64(&value) return Color( red: Double((value >> 16) & 0xFF) / 255, green: Double((value >> 8) & 0xFF) / 255, blue: Double(value & 0xFF) / 255 ) } /// 타이머 표시용 구간. ClosedRange가 유한해야 해서 상한을 두되, /// 30일이던 것을 1년으로 늘려 상한 도달로 타이머가 멈춰 보이는 일이 없게 한다 /// (실사용에선 장시간 측정 알림이 훨씬 먼저 개입한다) var timerRange: ClosedRange { startedAt...startedAt.addingTimeInterval(60 * 60 * 24 * 365) } }