From 1e50485537db656628d8ba3ae1ef7a14b64bebeb Mon Sep 17 00:00:00 2001 From: songyc macbook Date: Wed, 15 Jul 2026 01:42:36 +0900 Subject: [PATCH] =?UTF-8?q?fix(widget):=20quest=20ring=20tap=20dead=20zone?= =?UTF-8?q?=20=E2=80=94=20drop=20invalidatableContent=20from=20shape=20sub?= =?UTF-8?q?tree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ③ 다짐 진행률 위젯에서 링·중앙 아이콘 영역을 누르면 인텐트 대신 앱이 열리던 실기기 버그 수정. 원인은 링 ZStack(도형+아이콘)에 붙인 invalidatableContent() — invalidatable로 표시된 래스터 서브트리는 별도 레이어로 분리되며 Button(intent:)의 히트 영역에서 빠져, 셀 단위 contentShape(.rect)로도 살아나지 않는다. 정상 동작이 확인된 ① 위젯과 같은 패턴(텍스트 값에만 invalidatableContent)으로 통일하고, 탭 접수 피드백은 퍼센트·누적값 줄이 계속 담당한다. CLAUDE.md §10에 도형·아이콘 ZStack 금지 규칙 추가. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7 --- myApp/HaruDanim/CLAUDE.md | 2 +- myApp/HaruDanim/Widgets/QuestRingWidget.swift | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/myApp/HaruDanim/CLAUDE.md b/myApp/HaruDanim/CLAUDE.md index c010546..4c0bf3f 100644 --- a/myApp/HaruDanim/CLAUDE.md +++ b/myApp/HaruDanim/CLAUDE.md @@ -259,7 +259,7 @@ xcrun xcstringstool sync IOS/Localizable.xcstrings --stringsdata "${files[@]}" - 슬롯 규칙: 미선택이면 기본 대상 채움, 선택했으면 순서 존중 + 모자란 슬롯은 점선 빈 칸. '선택 안 함' 센티널 `NoneEntityID` - **타임라인 예산 전략**(`WidgetRefresh`): 주기 폴링 없음. 값 변경은 `DataChange.commit`/인텐트의 reloadAllTimelines가 담당. 측정 중일 때만 10분 간격 미래 엔트리 1시간치+.atEnd, 평상시엔 하루 경계(최대 4h) 안전망 -- **버튼 탭 즉시 피드백**: ①③의 변하는 값(누적·퍼센트·링)에 `invalidatableContent()` — 탭 즉시 '갱신 중' 표시로 바뀌어 새 타임라인 도착(1~3초, WidgetKit 구조상 단축 불가) 전에도 탭 접수를 보여 줌(중복 탭 방지) +- **버튼 탭 즉시 피드백**: ①③의 변하는 값 **텍스트**에 `invalidatableContent()` — 탭 즉시 '갱신 중' 표시로 바뀌어 새 타임라인 도착(1~3초, WidgetKit 구조상 단축 불가) 전에도 탭 접수를 보여 줌(중복 탭 방지). ⚠️ **도형·아이콘 ZStack에는 금지** — invalidatable로 표시된 래스터 서브트리는 별도 레이어로 분리돼 `Button(intent:)` 히트 영역에서 빠지고, 그 위 탭이 앱 열기로 샌다(③ 링이 그랬던 실기기 버그. contentShape(.rect)로도 못 살림 — 텍스트 값에만 붙일 것) - **버튼 히트 영역**: `Button(intent:)` 라벨 끝에 `.contentShape(.rect)` 필수 — plain 버튼은 라벨의 투명 영역(Spacer·여백·링 안쪽)을 탭 판정에서 빼는 경우가 있어, 그 지점 탭이 인텐트 대신 위젯 기본 동작(앱 열기)으로 새는 버그가 있었다. ③의 꼬리표 대상 다짐 셀은 버튼이 없어(표시 전용) 셀 전체가 앱 열기 — 의도된 동작 - 확장 프로세스는 `IntentStore.refresh()`로 작업마다 컨테이너를 새로 열어 최신 데이터 보장 (실패 시 직전 컨테이너 유지 — 크래시 방지) - `RunActionIntent`는 AppEntity 대신 **UUID 문자열 파라미터** — 버튼 탭 지연·유실 방지의 핵심 diff --git a/myApp/HaruDanim/Widgets/QuestRingWidget.swift b/myApp/HaruDanim/Widgets/QuestRingWidget.swift index 604548b..b41fba3 100644 --- a/myApp/HaruDanim/Widgets/QuestRingWidget.swift +++ b/myApp/HaruDanim/Widgets/QuestRingWidget.swift @@ -127,15 +127,16 @@ struct QuestRingActionCellView: View { .offset(x: ringSize * 0.38, y: -ringSize * 0.38) } } - // 버튼을 누르는 즉시 링·수치가 '갱신 중' 표시로 바뀌어 - // 새 타임라인 도착 전에도 탭이 접수됐음을 보여 준다 (중복 탭 방지) - .invalidatableContent() + // ⚠️ 링 ZStack에 invalidatableContent를 붙이면 안 됨 — 도형·아이콘 서브트리가 + // 별도 레이어로 분리되며 버튼 히트 영역에서 빠져, 링을 누르면 인텐트 대신 + // 앱 열기로 새는 실기기 버그가 있었다. 탭 피드백은 아래 텍스트 줄들이 담당. Text(cell.targetName) .font(.caption2.weight(.semibold)) .lineLimit(1) Text(percentText) .font(.caption2.monospacedDigit()) .foregroundStyle(.secondary) + // 탭 즉시 '갱신 중' 표시 — 새 타임라인 도착 전 접수 피드백 (중복 탭 방지) .invalidatableContent() // span 누적값 — '이하 유지'는 퍼센트가 없어 이 줄이 유일한 현재 수치 Text(cell.valueLabel)