fix(ui): smooth expand/collapse animation for time input rows
- 시각 입력 값 행의 펼침/접힘이 "확" 스냅된다는 실기기 피드백 → 조건부 삽입(if) 대신 높이 0↔216pt 프레임 보간(.smooth 0.3s, 바운스 없음)으로 변경 — List/Form 행 높이가 매 프레임 따라와 부드럽게 열리고 닫힘. 공용 CollapsibleTimeWheel 한 곳 수정으로 6곳(기록 편집 4시트·마감 시각·하루 시작 시간) 전부 적용 - 휠은 Color.clear의 overlay(top 고정)로 띄움 — UIDatePicker의 고유 높이(216)가 레이아웃에 개입해 접힘 상태에 빈 공간이 남던 문제(1차 구현에서 발견) 방지. 접힘 시 clipped+터치 차단+보이스오버 숨김 - 값 반영 경로·검증(종료<시작 경고 등) 불변, 새 문자열 없음(카탈로그 클린) - 검증: 세션 수정 접힘(빈 공간 없음)·설정 펼침 시뮬 스크린샷, Debug/Store 빌드 성공. CLAUDE.md §6.5에 보간 구조 유지 규칙 기재 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014CkLDi8Lr21vGqo4SjZaTp
This commit is contained in:
parent
7baa7a424c
commit
459c85700f
@ -201,7 +201,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분으로 표시되는 어긋남 방지. **앱의 모든 시각 입력은 `CollapsibleTimeWheel`**(RecordEditors.swift) — 평소엔 값 행(라벨+현재 값+셰브론), 탭하면 인라인 휠(RecordTimeWheel) 펼침. 상시 노출 휠이 어수선하다는 실기기 피드백으로 기록 편집 4시트·다짐 '마감 시각'·설정 '하루 시작 시간' 전부 통일(기본 접힘). 팝오버 금지 이유(감속 중 닫힘 시 정착값 유실)와 범위 제약 금지·분 절사 규칙은 그대로
|
||||
- 목록: 시간 기록(시작~종료·총 시간·메모)·횟수 기록(시각·+n·메모), 탭하면 수정 시트. **수정·추가 시트의 시각 입력은 상시 노출 휠 다이얼**(`RecordEditors.swift` RecordTimeWheel) — 컴팩트 팝오버는 다이얼 감속 중 닫히면 정착값이 유실되는 실기기 보고가 있어 폐기. `in:` 범위 제약도 하한 근처 선택을 소리 없이 되감아 금지(검증은 종료<시작 경고 문구+저장 비활성). 편집 상태는 분 단위 절사(flooredToMinute) — 실측정 기록의 초 찌꺼기(14:32:47)가 남으면 다이얼로 맞춘 1시간이 59분으로 표시되는 어긋남 방지. **앱의 모든 시각 입력은 `CollapsibleTimeWheel`**(RecordEditors.swift) — 평소엔 값 행(라벨+현재 값+셰브론), 탭하면 인라인 휠(RecordTimeWheel) 펼침. 상시 노출 휠이 어수선하다는 실기기 피드백으로 기록 편집 4시트·다짐 '마감 시각'·설정 '하루 시작 시간' 전부 통일(기본 접힘). **펼침/접힘은 조건부 삽입(if)이 아니라 높이 0↔216 프레임 보간**(.smooth 0.3s) — 삽입 방식은 List 행 높이가 스냅되어 '확' 열리는 느낌(실기기 피드백). 휠은 Color.clear의 overlay로 띄워 UIDatePicker 고유 높이가 레이아웃에 개입하지 않게 한다(접힘 상태 빈 공간 버그 방지 — 이 구조를 유지할 것). 팝오버 금지 이유(감속 중 닫힘 시 정착값 유실)와 범위 제약 금지·분 절사 규칙은 그대로
|
||||
- 타임테이블: 24시간 축(하루 시작 시간 기준), 하루/일주일 전환(주간 보기에서 화살표는 7일씩 점프). 시간=색 블록, 횟수=색 점. 블록/점 탭=수정
|
||||
- 필터: `RecordFilterSheet`(공용) — 꼬리표 아래 행동이 그룹된 트리, **"제외한 행동 ID" 집합**으로 관리해 기본이 전체 선택. 활성 시 초록 칩 표시
|
||||
- 내보내기: 현재 날짜/모드/필터 그대로 `ExportBuilder.history` 스냅숏 → 이미지 시트
|
||||
|
||||
@ -54,10 +54,16 @@ struct CollapsibleTimeWheel: View {
|
||||
self._isExpanded = State(initialValue: initiallyExpanded)
|
||||
}
|
||||
|
||||
/// UIDatePicker 휠의 고유 높이 (역사적으로 고정 216pt) — 펼침/접힘을
|
||||
/// 조건부 삽입(if) 대신 0↔이 높이의 프레임 보간으로 애니메이션하기 위한 상수.
|
||||
/// List/Form 행에서 조건부 삽입은 행 높이가 스냅되어 "확" 열리고 닫히는
|
||||
/// 느낌이 나는데(실기기 피드백), 높이 보간은 행 높이가 매 프레임 따라와 부드럽다.
|
||||
private static let wheelHeight: CGFloat = 216
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Button {
|
||||
withAnimation(.snappy(duration: 0.25)) {
|
||||
withAnimation(.smooth(duration: 0.3)) {
|
||||
isExpanded.toggle()
|
||||
}
|
||||
} label: {
|
||||
@ -77,9 +83,17 @@ struct CollapsibleTimeWheel: View {
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel(Text(label))
|
||||
.accessibilityValue(Text(selection, format: valueFormat))
|
||||
if isExpanded {
|
||||
// 높이는 Color.clear가 결정(0↔휠 높이 보간)하고 휠 자체는 overlay로 띄운다 —
|
||||
// UIDatePicker의 고유 높이가 레이아웃에 개입해 접힘 상태에 빈 공간이 남는 것 방지
|
||||
Color.clear
|
||||
.frame(height: isExpanded ? Self.wheelHeight : 0)
|
||||
.overlay(alignment: .top) {
|
||||
RecordTimeWheel(label: label, selection: $selection, components: components)
|
||||
}
|
||||
.clipped()
|
||||
.opacity(isExpanded ? 1 : 0)
|
||||
.allowsHitTesting(isExpanded)
|
||||
.accessibilityHidden(!isExpanded)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user