- 잠금화면 실시간 현황(라이브 액티비티)에 종료 수단이 없다는 보고 → 배너 오른쪽에 노란 정지 버튼 추가. 워치·⑥ 위젯과 같은 검증된 경로(NowRunningStopButton → RunActionIntent 토글) 재사용이라 위험 낮음 판단 후 진행 - ContentState에 actionID(optional) 추가 — 앱 업데이트 전 인플라이트 액티비티(키 없음)도 안전 디코딩(WatchSnapshot 선례), 없으면 버튼 없이 기존 표시 - LockScreenActivityView를 NowRunningWidget.swift로 이동 — @main 파일은 앱 타깃에서 제외라 앱 내 위젯 미리보기(-widgetPreview)에서 배너를 렌더하기 위함(동작 불변). 미리보기 최상단에 배너 박스 신설 - 다이나믹 아일랜드 스모크 확인(상태 필드 추가 회귀 없음 — 콤팩트 정상 표시). 실기기 확인 항목: 잠금화면에서 정지 버튼 탭 시 즉시 종료 - 도움말 '다이나믹 아일랜드·잠금화면' 문구에 정지 버튼 안내 추가(ko/en/ja, stale 정리), CLAUDE.md §9 갱신. Debug/Store 빌드 성공, 카탈로그 9종 클린 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014CkLDi8Lr21vGqo4SjZaTp
47 lines
1.8 KiB
Swift
47 lines
1.8 KiB
Swift
//
|
|
// 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<Date> {
|
|
startedAt...startedAt.addingTimeInterval(60 * 60 * 24 * 365)
|
|
}
|
|
}
|