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>
177 lines
9.5 KiB
Swift
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
|