diff --git a/myApp/HaruDanim/CLAUDE.md b/myApp/HaruDanim/CLAUDE.md index 627078c..e870fd3 100644 --- a/myApp/HaruDanim/CLAUDE.md +++ b/myApp/HaruDanim/CLAUDE.md @@ -162,7 +162,7 @@ xcrun xcstringstool sync IOS/Localizable.xcstrings --stringsdata "${files[@]}" ### 6.2 행동 탭 (`ActionViews`) - 즐겨찾기 섹션(스와이프로 토글) → 꼬리표별 그룹 → 꼬리표 없음. 탭하면 상세(정보·즐겨찾기·메모 창 토글·누적 통계·삭제) -- 추가/수정: 이름, 아이콘(SF Symbols 검색+카테고리 선택기 `SymbolPickerView`/`SymbolCatalog`), 꼬리표 복수 선택(즉석 추가 가능), 추적 방식, 메모 창 여부. 무료 한도 초과 시 프리미엄 안내 얼럿 +- 추가/수정: 이름, 아이콘(SF Symbols 검색+카테고리 선택기 `SymbolPickerView`/`SymbolCatalog`), 꼬리표 복수 선택(즉석 추가 가능), 추적 방식(**생성 시에만 선택 — 수정에서는 비활성**, 기존 기록의 표시·집계가 뒤섞이는 것 방지), 메모 창 여부. 무료 한도 초과 시 프리미엄 안내 얼럿 - ⋯ 메뉴: 꼬리표 순서 변경 시트 ### 6.3 꼬리표 탭 (`TagViews`): 목록(행동 수 표시)·드래그 정렬·수정(이름/색: ColorPicker+프리셋 12색)·스와이프 삭제(행동은 유지) diff --git a/myApp/HaruDanim/IOS/Localizable.xcstrings b/myApp/HaruDanim/IOS/Localizable.xcstrings index bd46312..c2a257b 100644 --- a/myApp/HaruDanim/IOS/Localizable.xcstrings +++ b/myApp/HaruDanim/IOS/Localizable.xcstrings @@ -7898,6 +7898,22 @@ } } }, + "제어 센터·잠금화면 버튼·액션 버튼에서 행동을 바로 실행해요.": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Run actions right from Control Center, the Lock Screen buttons, or the Action button." + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "コントロールセンター・ロック画面ボタン・アクションボタンからアクションを即実行。" + } + } + } + }, "제어 센터를 편집해 '하루 다님'의 '행동 실행' 컨트롤을 추가하면, 화면을 켜자마자 행동을 실행할 수 있어요. 시간형은 시작/종료 토글, 횟수형은 탭마다 +1이에요. 잠금화면 하단 버튼이나 액션 버튼에도 배치할 수 있어요.": { "localizations": { "en": { @@ -7914,6 +7930,22 @@ } } }, + "제어 센터에서 실행": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Run from Control Center" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "コントロールセンターから実行" + } + } + } + }, "제어 센터에서 실행 (프리미엄)": { "localizations": { "en": { @@ -8682,6 +8714,22 @@ } } }, + "추적 방식은 행동을 만들 때만 선택할 수 있어요.": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "The tracking type can only be chosen when creating an action." + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "計測方式は行動を作成するときにのみ選択できます。" + } + } + } + }, "취미": { "localizations": { "en": { diff --git a/myApp/HaruDanim/IOS/Views/ActionViews.swift b/myApp/HaruDanim/IOS/Views/ActionViews.swift index 8e60844..45d664f 100644 --- a/myApp/HaruDanim/IOS/Views/ActionViews.swift +++ b/myApp/HaruDanim/IOS/Views/ActionViews.swift @@ -421,7 +421,7 @@ struct ActionEditorView: View { } footer: { Text("행동 버튼의 색은 지정한 꼬리표의 색을 따라요.") } - Section("추적 방식") { + Section { Picker("추적 방식", selection: $trackingType) { ForEach(TrackingType.allCases) { type in Label(type.label, systemImage: type.symbol).tag(type) @@ -429,6 +429,15 @@ struct ActionEditorView: View { } .pickerStyle(.inline) .labelsHidden() + // 기존 행동의 추적 방식을 바꾸면 이미 쌓인 기록이 화면·통계에서 + // 보이지 않는 것처럼 되므로 생성 시에만 선택 가능 (도움말 안내와 일치) + .disabled(action != nil) + } header: { + Text("추적 방식") + } footer: { + if action != nil { + Text("추적 방식은 행동을 만들 때만 선택할 수 있어요.") + } } Section { Toggle(isOn: $promptsForNote) { diff --git a/myApp/HaruDanim/IOS/Views/SettingsView.swift b/myApp/HaruDanim/IOS/Views/SettingsView.swift index b3456be..0780f9c 100644 --- a/myApp/HaruDanim/IOS/Views/SettingsView.swift +++ b/myApp/HaruDanim/IOS/Views/SettingsView.swift @@ -387,6 +387,7 @@ struct PremiumView: View { Section { featureRow("infinity", "개수 제한 해제", "행동·목표·다짐을 무제한으로 만들 수 있어요.") featureRow("square.grid.2x2.fill", "홈·잠금화면 위젯", "위젯에서 바로 행동을 실행하고 달성률을 확인해요.") + featureRow("switch.2", "제어 센터에서 실행", "제어 센터·잠금화면 버튼·액션 버튼에서 행동을 바로 실행해요.") featureRow("icloud.fill", "아이패드 동기화", "iCloud로 기기 간 데이터가 동기화돼요.") featureRow("applewatch", "애플워치 앱", "워치에서 추적하고 컴플리케이션으로 확인해요.") featureRow("book.closed.fill", "아이패드 일기", "하루 정리와 애플 펜슬 다이어리를 사용해요.") diff --git a/myApp/HaruDanim/IOS/Views/StatsTabView.swift b/myApp/HaruDanim/IOS/Views/StatsTabView.swift index ec0bc7f..bc1de13 100644 --- a/myApp/HaruDanim/IOS/Views/StatsTabView.swift +++ b/myApp/HaruDanim/IOS/Views/StatsTabView.swift @@ -542,7 +542,9 @@ struct StatsTabView: View { case .time: agg.seconds(for: action, in: weekRange) / 3600 case .count: Double(agg.count(for: action, in: weekRange)) } - result.append(ActionWeekPoint(weekLabel: "\(index + 1)주차", actionName: action.name, value: value)) + // String(localized:)로 감싸야 en/ja에서도 지역화됨 (내보내기 ExportBuilder와 동일 키) + result.append(ActionWeekPoint(weekLabel: String(localized: "\(index + 1)주차"), + actionName: action.name, value: value)) } } return result diff --git a/myApp/HaruDanim/Widgets/InfoPlist.xcstrings b/myApp/HaruDanim/Widgets/InfoPlist.xcstrings index 652784e..f59f69b 100644 --- a/myApp/HaruDanim/Widgets/InfoPlist.xcstrings +++ b/myApp/HaruDanim/Widgets/InfoPlist.xcstrings @@ -1,42 +1,43 @@ { - "sourceLanguage" : "ko", - "strings" : { - "CFBundleDisplayName" : { - "comment" : "위젯 익스텐션 표시 이름", - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Haru Danim" + "sourceLanguage": "ko", + "strings": { + "CFBundleDisplayName": { + "comment": "위젯 익스텐션 표시 이름", + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Haru Danim" } }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "Haru Danim" + "ja": { + "stringUnit": { + "state": "translated", + "value": "Haru Danim" } }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "하루 다님" + "ko": { + "stringUnit": { + "state": "translated", + "value": "하루 다님" } } } }, - "CFBundleName" : { - "comment" : "Bundle name", - "extractionState" : "extracted_with_value", - "localizations" : { - "ko" : { - "stringUnit" : { - "state" : "new", - "value" : "Haru_DanimWidgets" + "CFBundleName": { + "comment": "Bundle name", + "extractionState": "extracted_with_value", + "localizations": { + "ko": { + "stringUnit": { + "state": "new", + "value": "Haru_DanimWidgets" } } - } + }, + "shouldTranslate": false } }, - "version" : "1.0" + "version": "1.0" } \ No newline at end of file diff --git a/myApp/HaruDanim/Widgets/Localizable.xcstrings b/myApp/HaruDanim/Widgets/Localizable.xcstrings index e2dfac3..c6c826e 100644 --- a/myApp/HaruDanim/Widgets/Localizable.xcstrings +++ b/myApp/HaruDanim/Widgets/Localizable.xcstrings @@ -402,6 +402,22 @@ } } }, + "%lld주차": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Week %lld" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "第%lld週" + } + } + } + }, "%lld초": { "localizations": { "en": { diff --git a/myApp/HaruDanim/Widgets/StatsChartWidget.swift b/myApp/HaruDanim/Widgets/StatsChartWidget.swift index c449d0a..6ab88c0 100644 --- a/myApp/HaruDanim/Widgets/StatsChartWidget.swift +++ b/myApp/HaruDanim/Widgets/StatsChartWidget.swift @@ -130,7 +130,9 @@ struct StatsChartProvider: AppIntentTimelineProvider { let week = math.weekRange(containing: cursor) let clipped = max(week.lowerBound, month.lowerBound)..