feat(main): add 'view statistics' to action long-press menu
- Add 'View Statistics' option to the context menu when long-pressing an action icon in the main tab - Route the user directly to the independent Statistics tab upon selection - Automatically apply the selected action as a filter when entering the Statistics tab, mirroring the 'View Records' behavior
This commit is contained in:
parent
810e4d6373
commit
ce3cb00fcc
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -591,6 +591,9 @@
|
||||
},
|
||||
"통계" : {
|
||||
|
||||
},
|
||||
"통계 보기" : {
|
||||
|
||||
},
|
||||
"특정 시각 지정" : {
|
||||
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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: 기간 이동 헤더
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user