feat(widget): lock-screen quest dots fill by progress ratio
- 잠금화면 위젯 '다짐 점'이 달성/미달성 이진 채움이라 진행 정도를 알 수 없다는 보고 → 각 점이 진행률(ratio)만큼 아래에서부터 차오르게 변경. 표시 전용 소형 뷰 수정이라 위험 낮음 판단 후 진행 - ratio를 그대로 쓰므로 달성=완전 채움(기존과 동일), '이하 유지'는 ratio가 1/0이라 한도 안=채움/초과=빈 점 동작 불변. 작은 크기(5~6pt)에선 부채꼴보다 물높이 방식이 가독성 좋아 채택 - 위젯 미리보기 잠금 섹션에 '다짐 여러 개+주간' 항목 추가 — 부분 채움(반쯤 찬 점/빈 점/가득 점) 시뮬 스크린샷으로 circular/rectangular 모두 확인 - 새 문자열 없음(카탈로그 클린), 도움말 무변경(스타일 세부 서술 없음). CLAUDE.md §10 갱신. Debug/Store 빌드 성공 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014CkLDi8Lr21vGqo4SjZaTp
This commit is contained in:
parent
e1537b32f3
commit
ddd46a4084
@ -274,7 +274,7 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f
|
||||
| ④ 다짐 현황 `HaruGoalQuestGridWidget` | 표시 전용 링 그리드 + 목표 헤더. 소형 2×2 / 중형 4×2 / 대형: 다짐16 / 목표4 / 목표2 |
|
||||
| ⑤ 행동 통계 `HaruStatsChartWidget` | 꺾은선(행동 색). 기간: 일주일/한 달(일별, 소형 제외→주별 대체)/한 달(주별). 선 수 제한 소2/중4/대6 |
|
||||
| ⑥ 현재 진행 중 `HaruNowRunningWidget` | 측정 중인 대표 행동(설정 '대표 시간 기준' — 다이나믹 아일랜드와 같은 규칙)을 꼬리표 색 배경 + 실시간 타이머(`Text(style:.timer)`) + 종료 버튼(`RunActionIntent` 토글의 종료 방향)으로 표시. 소형/중형: 대표 1개 + "+N개 함께 추적 중". 대형: 대표 카드 + 함께 측정 중 나열(각각 종료 버튼, 4개 초과분은 "외 N개") / 단독이면 오늘 누적(실시간)·시작 시각 카드. 측정 중 아니면 빈 상태 안내, 갤러리 미리보기는 샘플 표시 |
|
||||
| 잠금화면 `HaruLockGoalWidget` | 목표 1개 달성률 — 원형 게이지/숫자만/다짐 점(달성=채움). circular/rectangular/inline |
|
||||
| 잠금화면 `HaruLockGoalWidget` | 목표 1개 달성률 — 원형 게이지/숫자만/다짐 점(**진행률만큼 아래에서부터 차오름**, 달성=완전 채움 — ratio 사용이라 이하 유지는 기존대로 한도 안=채움/초과=빈 점). circular/rectangular/inline |
|
||||
| 제어 센터 `HaruActionRunControl` | iOS 18 ControlWidget — 행동 1개 토글(시간형 시작/종료, 횟수형 +1). `ToggleActionControlIntent`(SetValueIntent+LiveActivityIntent, 앱 프로세스 실행) |
|
||||
|
||||
- 슬롯 규칙: 미선택이면 기본 대상 채움, 선택했으면 순서 존중 + 모자란 슬롯은 점선 빈 칸. '선택 안 함' 센티널 `NoneEntityID`
|
||||
|
||||
@ -86,10 +86,18 @@ struct WidgetPreviewScreen: View {
|
||||
number.style = .number
|
||||
var dots = LockGoalConfigIntent()
|
||||
dots.style = .dots
|
||||
// 다짐이 여러 개고 부분 진행이 섞인 목표 + 주간 기간 — 점의 '차오름' 확인용
|
||||
var dotsWeek = LockGoalConfigIntent()
|
||||
dotsWeek.style = .dots
|
||||
dotsWeek.span = .week
|
||||
if let manyQuests = WidgetStore.defaultGoals(8).max(by: { $0.quests.count < $1.quests.count }) {
|
||||
dotsWeek.goal = GoalEntity(manyQuests)
|
||||
}
|
||||
lockEntries = [
|
||||
("gauge", LockGoalProvider.makeEntry(gauge)),
|
||||
("number", LockGoalProvider.makeEntry(number)),
|
||||
("dots", LockGoalProvider.makeEntry(dots)),
|
||||
("dots·주간·다짐多", LockGoalProvider.makeEntry(dotsWeek)),
|
||||
]
|
||||
return
|
||||
}
|
||||
|
||||
@ -214,13 +214,26 @@ struct LockGoalWidgetView: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// 다짐 달성 여부 점 표시 (달성 = 채움)
|
||||
/// 다짐 진행률 점 표시 — 진행률만큼 아래에서부터 차오른다 (달성 = 완전히 채움).
|
||||
/// ratio를 그대로 쓰므로 '이하 유지'는 기존과 동일하게 한도 안=채움/초과=빈 점.
|
||||
/// 작은 크기에서는 부채꼴보다 바닥부터 차는 물높이 방식이 읽기 쉽다.
|
||||
private func questDots(_ goal: GoalSnapshot, size: CGFloat) -> some View {
|
||||
HStack(spacing: 3) {
|
||||
ForEach(goal.quests.prefix(6)) { quest in
|
||||
let fill = min(max(quest.ratio, 0), 1)
|
||||
Circle()
|
||||
.strokeBorder(.primary, lineWidth: 1)
|
||||
.background(Circle().fill(quest.isAchieved ? AnyShapeStyle(.primary) : AnyShapeStyle(.clear)))
|
||||
.background(
|
||||
GeometryReader { geo in
|
||||
VStack(spacing: 0) {
|
||||
Spacer(minLength: 0)
|
||||
Rectangle()
|
||||
.fill(.primary)
|
||||
.frame(height: geo.size.height * fill)
|
||||
}
|
||||
}
|
||||
.clipShape(Circle())
|
||||
)
|
||||
.frame(width: size, height: size)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user