mycode/myApp/HaruDanim/IOS/Views/WhatsNewView.swift
songyc macbook 8b1bc44f67 fix+feat(1.5-p7): 소킹 실측 2건 수정 + 추가 2건 — 빌드 5
- fix: 더보기 탭 일기 달력 날짜 탭 무반응 — morePath [AppTab]→NavigationPath(Date 푸시 가능), 회귀 인자 -morePushDiaryToday(착지 실측)
- fix: 수면 블록이 수면 단계별로 칸칸이 갈라짐 — 10분 이하 깸 병합(sleepDisplayMergeGap, 표시 전용·값 무영향)
- feat: 기록 탭 타임테이블(하루·주간)에 수면·운동 블록 — 단일 공급 지점·숨김 토글 공유, 내보내기 injectingHealthBlocks(forDayKeys:)+trim 확장
- feat: 타임테이블 표시 색 설정(설정→건강 데이터 — 기본 인디고·주황, 전 타임테이블·내보내기 공통), -healthColorPreview
- QA: 주간 6일 블록 렌더·커스텀 색 픽셀 검증(#FF2D55→(255,221,228))·색 설정 화면·Date 푸시 착지, l10n 0/0, Debug/Store 그린

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WtZwRRjbtM9pZJDM4FkTq6
2026-08-22 23:24:13 +09:00

144 lines
7.0 KiB
Swift

//
// WhatsNewView.swift
// Haru_Danim
//
// (1.5 Docs/plan-1.5.md §11)
// - 1.
// ( ). .
// - " " ( plan §10 R16)
// - contentVersion
//
import SwiftData
import SwiftUI
struct WhatsNewView: View {
@Environment(\.dismiss) private var dismiss
/// (standard defaults )
static let lastShownKey = "whatsnew.lastShownVersion"
///
static let contentVersion = "1.5"
static var appVersion: String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
}
/// ( )
@MainActor
static func markSeededIfFreshInstall(context: ModelContext) {
guard UserDefaults.standard.string(forKey: lastShownKey) == nil else { return }
let isFresh = !UserDefaults.standard.bool(forKey: OnboardingView.doneKey)
&& ((try? context.fetchCount(FetchDescriptor<Action>())) ?? 0) == 0
if isFresh {
UserDefaults.standard.set(appVersion, forKey: lastShownKey)
}
}
/// : +
static var shouldShow: Bool {
appVersion == contentVersion
&& UserDefaults.standard.string(forKey: lastShownKey) != appVersion
}
static func markShown() {
UserDefaults.standard.set(appVersion, forKey: lastShownKey)
}
var body: some View {
VStack(spacing: 0) {
ScrollView {
VStack(alignment: .leading, spacing: 22) {
VStack(alignment: .leading, spacing: 4) {
Text("새로워진 하루 다님")
.font(.title.bold())
Text("버전 1.5에서 이런 것들이 더해졌어요.")
.font(.subheadline)
.foregroundStyle(.secondary)
}
.padding(.top, 28)
feature(
symbol: "applewatch",
tint: AppTheme.green,
title: String(localized: "워치 페이스에서 행동 기록 보기"),
body: String(localized: "'행동 기록' 컴플리케이션이 새로 생겼어요. 행동 편집에서 켜면 워치 페이스에서 누적 기록을 바로 보고, 눌러서 바로 실행할 수 있어요.")
)
feature(
symbol: "heart.fill",
tint: .pink,
title: String(localized: "모음 탭에서 건강 데이터 보기"),
body: String(localized: "걸음·운동·수면 같은 애플 건강 앱의 오늘 데이터를 모음 탭 타일로 볼 수 있어요. 값은 기기 밖으로 나가지 않아요.")
)
feature(
symbol: "figure.run",
tint: .pink,
title: String(localized: "건강 데이터로 다짐 만들기"),
body: String(localized: "'매일 8,000보', '수면 8시간', '달리기 30분'처럼 건강 데이터를 목표로 삼는 다짐을 만들 수 있어요. 운동은 종목별로도 돼요. (프리미엄)")
)
feature(
symbol: "book.closed.fill",
tint: AppTheme.green,
title: String(localized: "아이폰에서도 일기 쓰기"),
body: String(localized: "일기 탭이 아이폰에도 생겼어요. 하루 정리를 확인하고, 노트에서 '그리기'를 켜면 손가락으로 쓰고 그릴 수 있어요. (프리미엄)")
)
feature(
symbol: "heart.text.square.fill",
tint: .pink,
title: String(localized: "일기에서 건강 데이터 보기"),
body: String(localized: "하루 정리에 그날의 건강 값을 담는 카드가 생기고, 일기·기록 탭 타임테이블에는 수면·운동이 실제 시간 그대로 깔려요(색은 설정에서 변경). 낮에 자는 날이 있다면 설정의 '수면 표시 구간'을 요일별로 맞춰 보세요.")
)
feature(
symbol: "questionmark.circle.fill",
tint: AppTheme.yellow,
title: String(localized: "도움말 새 단장"),
body: String(localized: "도움말 전체 문구를 더 자연스럽게 다듬고, 새 기능 사용법을 더했어요.")
)
Label {
Text("아이폰·아이패드·맥을 함께 쓰신다면 모든 기기에서 하루 다님을 업데이트해 주세요. 버전이 섞이면 새 기능이 일부 기기에서 다르게 보일 수 있어요.")
.font(.footnote)
.foregroundStyle(.secondary)
} icon: {
Image(systemName: "arrow.triangle.2.circlepath")
.foregroundStyle(AppTheme.green)
}
.padding(.top, 2)
}
.padding(.horizontal, 24)
.padding(.bottom, 16)
}
Button {
dismiss()
} label: {
Text("시작하기")
.font(.headline)
.frame(maxWidth: .infinity)
.padding(.vertical, 14)
}
.buttonStyle(.borderedProminent)
.tint(AppTheme.green)
.padding(.horizontal, 24)
.padding(.bottom, 20)
}
.background(AppTheme.background)
}
private func feature(symbol: String, tint: Color, title: String, body text: String) -> some View {
HStack(alignment: .top, spacing: 14) {
Image(systemName: symbol)
.font(.title2)
.foregroundStyle(tint)
.frame(width: 34)
VStack(alignment: .leading, spacing: 3) {
Text(title)
.font(.subheadline.weight(.semibold))
Text(text)
.font(.footnote)
.foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
}
}
}
}