diff --git a/myApp/Haru_Danim/Haru_Danim.xcodeproj/project.xcworkspace/xcuserdata/ceuak.xcuserdatad/UserInterfaceState.xcuserstate b/myApp/Haru_Danim/Haru_Danim.xcodeproj/project.xcworkspace/xcuserdata/ceuak.xcuserdatad/UserInterfaceState.xcuserstate index 403280e..1aa384b 100644 Binary files a/myApp/Haru_Danim/Haru_Danim.xcodeproj/project.xcworkspace/xcuserdata/ceuak.xcuserdatad/UserInterfaceState.xcuserstate and b/myApp/Haru_Danim/Haru_Danim.xcodeproj/project.xcworkspace/xcuserdata/ceuak.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/myApp/Haru_Danim/IOS/ContentView.swift b/myApp/Haru_Danim/IOS/ContentView.swift index e6df3ca..fa954a9 100644 --- a/myApp/Haru_Danim/IOS/ContentView.swift +++ b/myApp/Haru_Danim/IOS/ContentView.swift @@ -90,17 +90,30 @@ final class AppRouter { /// 기록 탭이 열릴 때 적용할 행동 필터 (기록 탭에서 소비 후 nil로 되돌림) var pendingHistoryActionID: PersistentIdentifier? + /// 통계 탭이 열릴 때 적용할 행동 필터 (통계 탭에서 소비 후 nil로 되돌림) + var pendingStatsActionID: PersistentIdentifier? + /// 더보기 탭 내부 내비게이션 경로. 더보기에 숨은 탭으로 바로 진입할 때 라우터가 채워 넣는다. var morePath: [AppTab] = [] /// 기록 탭으로 이동하며 행동 필터를 예약. 기록 탭이 노출 탭에 없으면 더보기 안의 기록 화면까지 바로 진입. func openHistory(filtering actionID: PersistentIdentifier, visibleTabsRaw: String) { pendingHistoryActionID = actionID + open(.history, visibleTabsRaw: visibleTabsRaw) + } + + /// 통계 탭으로 이동하며 행동 필터를 예약. 통계 탭이 노출 탭에 없으면 더보기 안의 통계 화면까지 바로 진입. + func openStats(filtering actionID: PersistentIdentifier, visibleTabsRaw: String) { + pendingStatsActionID = actionID + open(.stats, visibleTabsRaw: visibleTabsRaw) + } + + private func open(_ tab: AppTab, visibleTabsRaw: String) { let visible = AppTab.visibleTabs(from: visibleTabsRaw) - if visible.contains(.history) { - tabSelection = AppTab.history.rawValue + if visible.contains(tab) { + tabSelection = tab.rawValue } else { - morePath = [.history] + morePath = [tab] tabSelection = AppTab.moreTabValue } } diff --git a/myApp/Haru_Danim/IOS/Localizable.xcstrings b/myApp/Haru_Danim/IOS/Localizable.xcstrings index b8e31d7..925f239 100644 --- a/myApp/Haru_Danim/IOS/Localizable.xcstrings +++ b/myApp/Haru_Danim/IOS/Localizable.xcstrings @@ -591,6 +591,9 @@ }, "통계" : { + }, + "통계 보기" : { + }, "특정 시각 지정" : { diff --git a/myApp/Haru_Danim/IOS/Views/MainView.swift b/myApp/Haru_Danim/IOS/Views/MainView.swift index 2383cc3..d731c4e 100644 --- a/myApp/Haru_Danim/IOS/Views/MainView.swift +++ b/myApp/Haru_Danim/IOS/Views/MainView.swift @@ -99,6 +99,23 @@ struct MainView: View { } message: { action in Text("‘\(action.name)’ 행동을 삭제할까요? 기록도 함께 삭제됩니다.") } + #if DEBUG + // 검증용: -openStatsFor "행동이름" / -openHistoryFor "행동이름" → 롱프레스 메뉴와 동일한 라우팅 실행 + .onAppear { + if let name = UserDefaults.standard.string(forKey: "openStatsFor"), + let action = actions.first(where: { $0.name == name }) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { + router.openStats(filtering: action.persistentModelID, visibleTabsRaw: visibleTabsRaw) + } + } + if let name = UserDefaults.standard.string(forKey: "openHistoryFor"), + let action = actions.first(where: { $0.name == name }) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { + router.openHistory(filtering: action.persistentModelID, visibleTabsRaw: visibleTabsRaw) + } + } + } + #endif } // MARK: 현재 진행 중 영역 @@ -189,6 +206,15 @@ struct MainView: View { } label: { Label("기록 확인", systemImage: "list.bullet.rectangle") } + Button { + // 통계 탭으로 이동해 이 행동만 필터링된 상태로 표시 + router.openStats( + filtering: action.persistentModelID, + visibleTabsRaw: visibleTabsRaw + ) + } label: { + Label("통계 보기", systemImage: "chart.xyaxis.line") + } Button { recordsAction = action } label: { diff --git a/myApp/Haru_Danim/IOS/Views/StatsTabView.swift b/myApp/Haru_Danim/IOS/Views/StatsTabView.swift index 3880d4f..1082fb4 100644 --- a/myApp/Haru_Danim/IOS/Views/StatsTabView.swift +++ b/myApp/Haru_Danim/IOS/Views/StatsTabView.swift @@ -13,6 +13,7 @@ import SwiftData import Charts struct StatsTabView: View { + @Environment(AppRouter.self) private var router @Query private var sessions: [TimeSession] @Query private var entries: [CountEntry] @Query(sort: \Tag.sortOrder) private var tags: [Tag] @@ -112,6 +113,7 @@ struct StatsTabView: View { ) } .onAppear { + consumePendingFilter() #if DEBUG // 검증용: -excludeActions "이름,이름"으로 필터 상태 주입, -statShowFilter YES로 시트 표시 if let raw = UserDefaults.standard.string(forKey: "excludeActions") { @@ -125,6 +127,18 @@ struct StatsTabView: View { } #endif } + .onChange(of: router.pendingStatsActionID) { + consumePendingFilter() + } + } + + /// 모음 탭 '통계 보기'에서 예약한 행동 필터를 적용 (오늘 기준 기간으로 이동) + private func consumePendingFilter() { + guard let id = router.pendingStatsActionID else { return } + // 해당 행동만 남기고 모두 해제 + excludedActionIDs = Set(allActions.map(\.persistentModelID)).subtracting([id]) + anchorDayKey = math.dayKey(for: .now) + router.pendingStatsActionID = nil } // MARK: 기간 이동 헤더