Files
Reflect/Shared/Services/SharingScreenshotExporter.swift
Trey t 0442eab1f8 Rebrand entire project from Feels to Reflect
Complete rename across all bundle IDs, App Groups, CloudKit containers,
StoreKit product IDs, data store filenames, URL schemes, logger subsystems,
Swift identifiers, user-facing strings (7 languages), file names, directory
names, Xcode project, schemes, assets, and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:47:16 -06:00

177 lines
9.5 KiB
Swift

//
// SharingScreenshotExporter.swift
// Reflect
//
// Debug utility to export sharing template screenshots.
//
#if DEBUG
import SwiftUI
import UIKit
/// Exports sharing template screenshots for App Store marketing
@MainActor
class SharingScreenshotExporter {
/// Exports all original templates + kept variations as PNGs
/// - Returns: URL to the export directory, or nil if failed
static func exportAllSharingScreenshots() async -> URL? {
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let exportPath = documentsPath.appendingPathComponent("SharingExports", isDirectory: true)
// Clean and create export directory
try? FileManager.default.removeItem(at: exportPath)
try? FileManager.default.createDirectory(at: exportPath, withIntermediateDirectories: true)
// Create subdirectories
let origDir = exportPath.appendingPathComponent("originals", isDirectory: true)
let varDir = exportPath.appendingPathComponent("variations", isDirectory: true)
try? FileManager.default.createDirectory(at: origDir, withIntermediateDirectories: true)
try? FileManager.default.createDirectory(at: varDir, withIntermediateDirectories: true)
var totalExported = 0
let distantPast = Date(timeIntervalSince1970: 0)
let now = Date()
let calendar = Calendar.current
//
// Fetch shared data once for all variations
//
// All moods data
let allEntries = DataController.shared.getData(
startDate: distantPast, endDate: now, includedDays: [1,2,3,4,5,6,7]
)
let allMetrics = Random.createTotalPerc(fromEntries: allEntries)
.sorted(by: { $0.mood.rawValue > $1.mood.rawValue })
// Current streak data (last 10 days) fetch 12 days to handle boundary, take last 10
let streakFetchStart = calendar.date(byAdding: .day, value: -12, to: now)!
let streakEntries = Array(DataController.shared.getData(
startDate: streakFetchStart, endDate: now, includedDays: [1,2,3,4,5,6,7]
).suffix(10))
// Current month data
let currentMonthEntries = DataController.shared.getData(
startDate: now.startOfMonth, endDate: now.endOfMonth, includedDays: [1,2,3,4,5,6,7]
)
let currentMonthMetrics = Random.createTotalPerc(fromEntries: currentMonthEntries)
.sorted(by: { $0.mood.rawValue > $1.mood.rawValue })
let currentMonth = calendar.component(.month, from: now)
// Last month data
let lastMonthDate = calendar.date(byAdding: .month, value: -1, to: now)!
let lastMonthStart = lastMonthDate.startOfMonth
let lastMonthEnd = lastMonthDate.endOfMonth
let lastMonthEntries = DataController.shared.getData(
startDate: lastMonthStart, endDate: lastMonthEnd, includedDays: [1,2,3,4,5,6,7]
)
let lastMonthMetrics = Random.createTotalPerc(fromEntries: lastMonthEntries)
.sorted(by: { $0.mood.rawValue > $1.mood.rawValue })
let lastMonth = calendar.component(.month, from: lastMonthDate)
// Longest streak data (find longest "great" streak)
let selectedMood: Mood = .great
let longestStreakEntries: [MoodEntryModel] = {
var splitArrays = [[MoodEntryModel]]()
var currentSplit = [MoodEntryModel]()
for entry in allEntries {
if entry.mood == selectedMood {
currentSplit.append(entry)
} else {
splitArrays.append(currentSplit)
currentSplit.removeAll()
}
}
splitArrays.append(currentSplit)
return splitArrays.sorted(by: { $0.count > $1.count }).first ?? []
}()
//
// Export originals
//
let allMoods = AllMoodsTotalTemplate(isPreview: false, startDate: distantPast, endDate: now, fakeData: false)
if saveImage(allMoods.image, to: origDir, name: "all_moods_total") { totalExported += 1 }
let currentStreak = CurrentStreakTemplate(isPreview: false, startDate: streakFetchStart, endDate: now, fakeData: false)
if saveImage(currentStreak.image, to: origDir, name: "current_streak") { totalExported += 1 }
let monthTotal = MonthTotalTemplate(isPreview: false, startDate: now.startOfMonth, endDate: now.endOfMonth, fakeData: false)
if saveImage(monthTotal.image, to: origDir, name: "month_total") { totalExported += 1 }
let longestStreak = LongestStreakTemplate(isPreview: false, startDate: distantPast, endDate: now, fakeData: false)
if saveImage(longestStreak.image, to: origDir, name: "longest_streak") { totalExported += 1 }
//
// Export All Moods variations (666x1190)
// Kept: V2, V5
//
if saveImage(AllMoodsV2(metrics: allMetrics, totalCount: allEntries.count).image,
to: varDir, name: "all_moods_v2_gradient") { totalExported += 1 }
if saveImage(AllMoodsV5(metrics: allMetrics, totalCount: allEntries.count).image,
to: varDir, name: "all_moods_v5_colorblock") { totalExported += 1 }
//
// Export Current Streak variations (666x1190)
// Kept: V2, V5
//
if saveImage(CurrentStreakV2(moodEntries: streakEntries).image,
to: varDir, name: "current_streak_v2_gradient") { totalExported += 1 }
if saveImage(CurrentStreakV5(moodEntries: streakEntries).image,
to: varDir, name: "current_streak_v5_colorblock") { totalExported += 1 }
//
// Export Month Total variations (666x1190)
// Kept: V1, V5 exported for BOTH current and last month
//
// Current month
if saveImage(MonthTotalV1(moodMetrics: currentMonthMetrics, moodEntries: currentMonthEntries, month: currentMonth).image,
to: varDir, name: "month_total_v1_clean_current") { totalExported += 1 }
if saveImage(MonthTotalV5(moodMetrics: currentMonthMetrics, moodEntries: currentMonthEntries, month: currentMonth).image,
to: varDir, name: "month_total_v5_colorblock_current") { totalExported += 1 }
// Last month
if saveImage(MonthTotalV1(moodMetrics: lastMonthMetrics, moodEntries: lastMonthEntries, month: lastMonth).image,
to: varDir, name: "month_total_v1_clean_lastmonth") { totalExported += 1 }
if saveImage(MonthTotalV5(moodMetrics: lastMonthMetrics, moodEntries: lastMonthEntries, month: lastMonth).image,
to: varDir, name: "month_total_v5_colorblock_lastmonth") { totalExported += 1 }
//
// Export Longest Streak variations (650x400)
// Kept: V2, V3
//
if saveImage(LongestStreakV2(streakEntries: longestStreakEntries, selectedMood: selectedMood).image,
to: varDir, name: "longest_streak_v2_gradient") { totalExported += 1 }
if saveImage(LongestStreakV3(streakEntries: longestStreakEntries, selectedMood: selectedMood).image,
to: varDir, name: "longest_streak_v3_dark") { totalExported += 1 }
print("📸 Total \(totalExported) sharing screenshots exported to: \(exportPath.path)")
print(" originals/ — 4 original templates")
print(" variations/ — 12 design variations (2 all moods, 2 current streak, 4 month total, 2 longest streak)")
return exportPath
}
private static func saveImage(_ image: UIImage, to folder: URL, name: String) -> Bool {
let url = folder.appendingPathComponent("\(name).png")
if let data = image.pngData() {
do {
try data.write(to: url)
return true
} catch {
print("Failed to save \(name): \(error)")
}
}
return false
}
}
#endif