fix(settings): collapse day-start time wheel into a value row
- 설정 '하루 시작 시간'의 상시 노출 휠이 화면을 계속 차지한다는 실기기 피드백 → 평소엔 값 행(라벨 + 현재 시각 + 셰브론)만 보이고 탭하면 인라인 휠이 펼쳐지는 방식으로 변경 - 팝오버(컴팩트)로 되돌리지 않음 — 다이얼 감속 중 닫힘 시 정착값 유실 문제가 재발하므로 인라인 휠 유지가 안전. 접힘/펼침은 표시 상태일 뿐 값 반영 경로는 동일 - 접근성: 행에 라벨+현재 값 낭독. 마감 시각·기록 편집기는 일시적 시트라 상시 노출 유지 (§6.5 문서화) - 검증 인자 -settingsShowDayStartWheel 신설(펼친 상태로 시작) — 접힘·펼침 스크린샷 확인, Debug/Store 빌드 성공, 카탈로그 무변화(외부 재저장으로 오염된 워킹트리 카탈로그는 HEAD로 복원) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014CkLDi8Lr21vGqo4SjZaTp
This commit is contained in:
parent
9626e6841e
commit
dbbbfb8506
@ -199,7 +199,7 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f
|
||||
### 6.5 기록 탭 (`HistoryView`, `RecordEditors`)
|
||||
- **범위 조회**: 기록은 전량 로드하지 않고 선택 날짜가 속한 **주 범위**만 @Query로 가져온다(`HistoryRecordsView` — SwiftData 동적 쿼리 패턴: 날짜가 바뀌면 새 조건으로 재생성). 하루 경계 걸침·진행 중 세션은 "시작 < 범위끝 AND (종료 없음 OR 종료 > 범위시작)" 겹침 조건으로 포함
|
||||
- 날짜 헤더(화살표 이동, 날짜 탭=달력 팝오버, "오늘" 버튼) + 목록/타임테이블 세그먼트
|
||||
- 목록: 시간 기록(시작~종료·총 시간·메모)·횟수 기록(시각·+n·메모), 탭하면 수정 시트. **수정·추가 시트의 시각 입력은 상시 노출 휠 다이얼**(`RecordEditors.swift` RecordTimeWheel) — 컴팩트 팝오버는 다이얼 감속 중 닫히면 정착값이 유실되는 실기기 보고가 있어 폐기. `in:` 범위 제약도 하한 근처 선택을 소리 없이 되감아 금지(검증은 종료<시작 경고 문구+저장 비활성). 편집 상태는 분 단위 절사(flooredToMinute) — 실측정 기록의 초 찌꺼기(14:32:47)가 남으면 다이얼로 맞춘 1시간이 59분으로 표시되는 어긋남 방지. 다짐 '마감 시각'·설정 '하루 시작 시간'도 같은 RecordTimeWheel(components: .hourAndMinute)로 통일 — 앱의 시각 입력 다이얼은 전부 상시 노출 휠
|
||||
- 목록: 시간 기록(시작~종료·총 시간·메모)·횟수 기록(시각·+n·메모), 탭하면 수정 시트. **수정·추가 시트의 시각 입력은 상시 노출 휠 다이얼**(`RecordEditors.swift` RecordTimeWheel) — 컴팩트 팝오버는 다이얼 감속 중 닫히면 정착값이 유실되는 실기기 보고가 있어 폐기. `in:` 범위 제약도 하한 근처 선택을 소리 없이 되감아 금지(검증은 종료<시작 경고 문구+저장 비활성). 편집 상태는 분 단위 절사(flooredToMinute) — 실측정 기록의 초 찌꺼기(14:32:47)가 남으면 다이얼로 맞춘 1시간이 59분으로 표시되는 어긋남 방지. 다짐 '마감 시각'·설정 '하루 시작 시간'도 같은 RecordTimeWheel(components: .hourAndMinute)로 통일 — 앱의 시각 입력 다이얼은 전부 인라인 휠(팝오버 금지). 설정 '하루 시작 시간'은 상시 노출이 거슬린다는 실기기 피드백으로 **평소엔 값 행(라벨+현재 시각+셰브론), 탭하면 휠 펼침** — 마감 시각·기록 편집기는 일시적 시트라 상시 노출 유지
|
||||
- 타임테이블: 24시간 축(하루 시작 시간 기준), 하루/일주일 전환(주간 보기에서 화살표는 7일씩 점프). 시간=색 블록, 횟수=색 점. 블록/점 탭=수정
|
||||
- 필터: `RecordFilterSheet`(공용) — 꼬리표 아래 행동이 그룹된 트리, **"제외한 행동 ID" 집합**으로 관리해 기본이 전체 선택. 활성 시 초록 칩 표시
|
||||
- 내보내기: 현재 날짜/모드/필터 그대로 `ExportBuilder.history` 스냅숏 → 이미지 시트
|
||||
@ -332,7 +332,7 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f
|
||||
| 측정 알림 | `-settings.longSessionAlertHours <N>`(설정 주입) `-longSessionAlertTestSeconds <N>`(시간 대신 N초 발화, provisional 권한 자동) `-alertDump`(예약 상태 → Documents/session-alerts.txt) |
|
||||
| 목표 | `-goalShowEditor` `-goalShowFinished` `-goalReorder` `-goalScrollBottom` `-questShowEditor`(다짐 편집기 표시 — 마감 시각 다짐 우선, 없으면 첫 다짐) `-endGoalYesterday "제목"`(종료일을 어제로 — 실행 시점 자동 판정 검증) `-watchGoals <N>`(생성순 목표 N개를 '애플워치에서 보기'로 설정, 0=전체 해제 — 설정 후 스냅숏 즉시 푸시, 컴플리케이션 필터 검증용) `-streakDump`(모든 다짐의 연속 계산 결과 → Documents/streak-dump.txt) `-progressSelfTest`(spanProgress 수치 37건 자가 검증[환산 캡·수행일 집계·마감·atMost·custom] → Documents/progress-self-test.txt — 인메모리 컨테이너·설정 고정이라 실데이터/기기 설정 무영향) |
|
||||
| 기록/통계 | `-historyMode timetable` `-historyWeekly` `-excludeActions "이름,이름"` `-historyShowFilter` `-statShowFilter` `-statSpan <day|week|month>` `-statScrollBottom` `-showExport` `-exportDump`(Documents/export-dump.png) `-recordShowEditor <session|count>`(최신 기록 수정 시트) |
|
||||
| 설정/기타 | `-settingsScrollGoal` `-settingsScrollPremium` `-premiumPreview` `-helpPreview`(+`-helpExpandAll`: 전 주제 펼침, `-helpScrollTo <help-main 등>`: 이미지 주제로 스크롤) `-dataExportPreview`(+`-dataExportRun`이면 CSV 자동 생성 후 Documents 복사) `-widgetPreview YES|lock` `-widgetPreviewScroll <앵커>` `-widgetRenderMode accented|vibrant`(틴트/투명 홈 렌더링 분기 검증) `cloudSync`(standard bool로 강제) `-intentSmokeTest`(시리 인텐트 10개 시나리오 실행 → Documents/intent-smoke-test.txt, -seedDemo·-premium과 함께) |
|
||||
| 설정/기타 | `-settingsScrollGoal` `-settingsScrollPremium` `-settingsShowDayStartWheel`(하루 시작 시간 휠 펼침 시작) `-premiumPreview` `-helpPreview`(+`-helpExpandAll`: 전 주제 펼침, `-helpScrollTo <help-main 등>`: 이미지 주제로 스크롤) `-dataExportPreview`(+`-dataExportRun`이면 CSV 자동 생성 후 Documents 복사) `-widgetPreview YES|lock` `-widgetPreviewScroll <앵커>` `-widgetRenderMode accented|vibrant`(틴트/투명 홈 렌더링 분기 검증) `cloudSync`(standard bool로 강제) `-intentSmokeTest`(시리 인텐트 10개 시나리오 실행 → Documents/intent-smoke-test.txt, -seedDemo·-premium과 함께) |
|
||||
| 버블 | `-radialExpanded` `-radialDoubleTapTest`(2초 뒤 FAB 더블탭 재현 — `-settings.radialDoubleTapTab <탭>`과 함께) |
|
||||
| 일기 | `-diarySeed`(필기 획 2줄 포함 — 달력 화면에서 먼저 시드 후 재실행으로 열 것) `-diaryOpenToday`(**`-startTab diary` 필수**) `-diaryPage <N>` `-diaryZoomScale <배>`(2.5초 뒤 fit×N 프로그램 줌 — 획 유지·선명도 확인) `-diaryShowConfig` `-diaryShowExport`(달력 화면 onAppear — `-diaryOpenToday`와 함께 쓰면 안 뜸) `-diaryExportRun pdf|image`(결과를 Documents로 복사) `-diaryShowCalendarPicker` `-diarySeedEvents` `-diaryHideFirstAction` `-diaryShowActionFilter` `-diaryHideFirstGoal` `-diaryShowGoalFilter` `-diarySeedPhoto`(오늘=이모지+사진·어제=사진만 기분 사진 시드 — 달력 백레이어 검증) `-diarySeedTemplate`(2쪽 샘플 PDF 양식 생성) `-diaryShowTemplates`(양식 관리 시트) `-diaryShowPageChooser`(페이지 추가 선택 시트) `-diaryApplyTemplate`(첫 양식으로 페이지 추가) / 섹션 강제: `-diary.sectionOrder "timetable,hero,goals"` `-diary.hiddenSections "mood,todos,records,bars"` |
|
||||
| 워치 | `-complicationPreview` `-complicationScroll` `-complicationScrollTo <stale\|quest>` `-autoRunFirstAction` `-autoStopRunning`(측정 중 행 탭과 동일 경로로 대표 측정 종료 — 페어링 심 E2E용) |
|
||||
|
||||
@ -43,6 +43,15 @@ struct SettingsView: View {
|
||||
)
|
||||
}
|
||||
|
||||
/// 하루 시작 시간 인라인 휠 펼침 상태 (기본 접힘 — 값 행만 표시)
|
||||
@State private var showsDayStartWheel: Bool = {
|
||||
#if DEBUG
|
||||
// 검증용: -settingsShowDayStartWheel YES → 휠 펼친 상태로 시작
|
||||
if UserDefaults.standard.bool(forKey: "settingsShowDayStartWheel") { return true }
|
||||
#endif
|
||||
return false
|
||||
}()
|
||||
|
||||
/// 하루 시작 시간을 DatePicker와 연결하기 위한 변환
|
||||
private var dayStartDate: Binding<Date> {
|
||||
Binding {
|
||||
@ -146,13 +155,39 @@ struct SettingsView: View {
|
||||
Text("\(Format.weekdayShort(weekday))요일").tag(weekday)
|
||||
}
|
||||
}
|
||||
// 평소엔 현재 값만 보이는 행, 탭하면 인라인 휠 펼침 —
|
||||
// 상시 노출 휠이 설정 탭을 계속 차지한다는 실기기 피드백 반영.
|
||||
// 팝오버로 되돌리지 않는 이유: 팝오버 다이얼은 감속 중 닫히면
|
||||
// 정착값이 유실되는 문제가 있어 휠 인라인 유지가 안전 (§6.5)
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text("하루 시작 시간")
|
||||
RecordTimeWheel(
|
||||
label: String(localized: "하루 시작 시간"),
|
||||
selection: dayStartDate,
|
||||
components: .hourAndMinute
|
||||
)
|
||||
Button {
|
||||
withAnimation(.snappy(duration: 0.25)) {
|
||||
showsDayStartWheel.toggle()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Text("하루 시작 시간")
|
||||
.foregroundStyle(.primary)
|
||||
Spacer()
|
||||
Text(dayStartDate.wrappedValue, format: .dateTime.hour().minute())
|
||||
.foregroundStyle(showsDayStartWheel ? AppTheme.green : .secondary)
|
||||
Image(systemName: "chevron.down")
|
||||
.font(.caption2.weight(.semibold))
|
||||
.foregroundStyle(.tertiary)
|
||||
.rotationEffect(.degrees(showsDayStartWheel ? 180 : 0))
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(Text("하루 시작 시간"))
|
||||
.accessibilityValue(Text(dayStartDate.wrappedValue, format: .dateTime.hour().minute()))
|
||||
if showsDayStartWheel {
|
||||
RecordTimeWheel(
|
||||
label: String(localized: "하루 시작 시간"),
|
||||
selection: dayStartDate,
|
||||
components: .hourAndMinute
|
||||
)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("날짜 기준")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user