feat(export): add high-res image export of records and stats as report posters
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
This commit is contained in:
parent
b897db47db
commit
cde4c4001b
@ -600,6 +600,7 @@
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "하루 다님";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle";
|
||||
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "내보낸 리포트 이미지를 사진 앨범에 저장하기 위해 필요해요.";
|
||||
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
@ -639,6 +640,7 @@
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "하루 다님";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle";
|
||||
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "내보낸 리포트 이미지를 사진 앨범에 저장하기 위해 필요해요.";
|
||||
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
|
||||
1293
myApp/HaruDanim/IOS/Views/ExportImageView.swift
Normal file
1293
myApp/HaruDanim/IOS/Views/ExportImageView.swift
Normal file
File diff suppressed because it is too large
Load Diff
@ -69,11 +69,18 @@ struct HistoryView: View {
|
||||
#endif
|
||||
return .list
|
||||
}()
|
||||
@State private var timetableWeekly = false
|
||||
@State private var timetableWeekly: Bool = {
|
||||
#if DEBUG
|
||||
// 검증용: -historyWeekly YES → 타임테이블 일주일 보기로 시작
|
||||
if UserDefaults.standard.bool(forKey: "historyWeekly") { return true }
|
||||
#endif
|
||||
return false
|
||||
}()
|
||||
@State private var editingSession: TimeSession?
|
||||
@State private var editingEntry: CountEntry?
|
||||
@State private var showingCalendar = false
|
||||
@State private var showingFilter = false
|
||||
@State private var showingExport = false
|
||||
/// 필터는 "해제한 행동"만 저장 → 기본값이 전체 선택 (통계 탭과 동일한 모델)
|
||||
@State private var excludedActionIDs: Set<PersistentIdentifier> = []
|
||||
|
||||
@ -115,6 +122,13 @@ struct HistoryView: View {
|
||||
.navigationTitle("기록")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Button {
|
||||
showingExport = true
|
||||
} label: {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Button {
|
||||
showingFilter = true
|
||||
@ -139,6 +153,18 @@ struct HistoryView: View {
|
||||
excludedActionIDs: $excludedActionIDs
|
||||
)
|
||||
}
|
||||
.sheet(isPresented: $showingExport) {
|
||||
// 지금 보고 있는 날짜/보기 모드/필터 그대로 스냅숏을 만들어 이미지로 내보낸다
|
||||
ExportImageSheet(snapshot: ExportBuilder.history(
|
||||
dayKey: selectedDayKey,
|
||||
weeklyTimetable: mode == .timetable && timetableWeekly,
|
||||
sessions: sessions,
|
||||
entries: entries,
|
||||
orderedActions: allActions,
|
||||
excludedActionIDs: excludedActionIDs,
|
||||
math: math
|
||||
))
|
||||
}
|
||||
.onAppear {
|
||||
consumePendingFilter()
|
||||
#if DEBUG
|
||||
@ -152,6 +178,10 @@ struct HistoryView: View {
|
||||
if UserDefaults.standard.bool(forKey: "historyShowFilter") {
|
||||
showingFilter = true
|
||||
}
|
||||
// 검증용: -showExport YES → 내보내기 시트 표시
|
||||
if UserDefaults.standard.bool(forKey: "showExport") {
|
||||
showingExport = true
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.onChange(of: router.pendingHistoryActionID) {
|
||||
|
||||
@ -37,6 +37,7 @@ struct StatsTabView: View {
|
||||
}()
|
||||
@State private var anchorDayKey: Date = DayMath().dayKey(for: .now)
|
||||
@State private var showingFilter = false
|
||||
@State private var showingExport = false
|
||||
/// 필터는 "해제한 행동"만 저장 → 기본값이 전체 선택이고, 새로 만든 행동도 자동 포함됨.
|
||||
/// 꼬리표는 시트에서 소속 행동 일괄 토글용일 뿐, 판정은 행동 단위로만 한다.
|
||||
@State private var excludedActionIDs: Set<PersistentIdentifier> = []
|
||||
@ -101,6 +102,13 @@ struct StatsTabView: View {
|
||||
.navigationTitle("통계")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Button {
|
||||
showingExport = true
|
||||
} label: {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Button {
|
||||
showingFilter = true
|
||||
@ -119,6 +127,18 @@ struct StatsTabView: View {
|
||||
excludedActionIDs: $excludedActionIDs
|
||||
)
|
||||
}
|
||||
.sheet(isPresented: $showingExport) {
|
||||
// 지금 보고 있는 기간/필터 그대로 스냅숏을 만들어 이미지로 내보낸다
|
||||
ExportImageSheet(snapshot: ExportBuilder.stats(
|
||||
span: span,
|
||||
anchorDayKey: anchorDayKey,
|
||||
sessions: sessions,
|
||||
entries: entries,
|
||||
orderedActions: allActions,
|
||||
excludedActionIDs: excludedActionIDs,
|
||||
math: math
|
||||
))
|
||||
}
|
||||
.onAppear {
|
||||
consumePendingFilter()
|
||||
#if DEBUG
|
||||
@ -132,6 +152,10 @@ struct StatsTabView: View {
|
||||
if UserDefaults.standard.bool(forKey: "statShowFilter") {
|
||||
showingFilter = true
|
||||
}
|
||||
// 검증용: -showExport YES → 내보내기 시트 표시
|
||||
if UserDefaults.standard.bool(forKey: "showExport") {
|
||||
showingExport = true
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.onChange(of: router.pendingStatsActionID) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user