Added a proper set of Unit Tests for each sub-project
All checks were successful
OpenClimb Docker Deploy / build-and-push (push) Successful in 2m28s
All checks were successful
OpenClimb Docker Deploy / build-and-push (push) Successful in 2m28s
This commit is contained in:
@@ -554,20 +554,20 @@ class ClimbingDataManager: ObservableObject {
|
||||
|
||||
// Collect referenced image paths
|
||||
let referencedImagePaths = collectReferencedImagePaths()
|
||||
print("🎯 Starting export with \(referencedImagePaths.count) images")
|
||||
print("Starting export with \(referencedImagePaths.count) images")
|
||||
|
||||
let zipData = try ZipUtils.createExportZip(
|
||||
exportData: exportData,
|
||||
referencedImagePaths: referencedImagePaths
|
||||
)
|
||||
|
||||
print("✅ Export completed successfully")
|
||||
print("Export completed successfully")
|
||||
successMessage = "Export completed with \(referencedImagePaths.count) images"
|
||||
clearMessageAfterDelay()
|
||||
return zipData
|
||||
} catch {
|
||||
let errorMessage = "Export failed: \(error.localizedDescription)"
|
||||
print("❌ \(errorMessage)")
|
||||
print("ERROR: \(errorMessage)")
|
||||
setError(errorMessage)
|
||||
return nil
|
||||
}
|
||||
@@ -662,13 +662,13 @@ class ClimbingDataManager: ObservableObject {
|
||||
extension ClimbingDataManager {
|
||||
private func collectReferencedImagePaths() -> Set<String> {
|
||||
var imagePaths = Set<String>()
|
||||
print("🖼️ Starting image path collection...")
|
||||
print("📊 Total problems: \(problems.count)")
|
||||
print("Starting image path collection...")
|
||||
print("Total problems: \(problems.count)")
|
||||
|
||||
for problem in problems {
|
||||
if !problem.imagePaths.isEmpty {
|
||||
print(
|
||||
"📸 Problem '\(problem.name ?? "Unnamed")' has \(problem.imagePaths.count) images"
|
||||
"Problem '\(problem.name ?? "Unnamed")' has \(problem.imagePaths.count) images"
|
||||
)
|
||||
for imagePath in problem.imagePaths {
|
||||
print(" - Relative path: \(imagePath)")
|
||||
@@ -677,10 +677,10 @@ extension ClimbingDataManager {
|
||||
|
||||
// Check if file exists
|
||||
if FileManager.default.fileExists(atPath: fullPath) {
|
||||
print(" ✅ File exists")
|
||||
print(" File exists")
|
||||
imagePaths.insert(fullPath)
|
||||
} else {
|
||||
print(" ❌ File does NOT exist")
|
||||
print(" File does NOT exist")
|
||||
// Still add it to let ZipUtils handle the error logging
|
||||
imagePaths.insert(fullPath)
|
||||
}
|
||||
@@ -688,7 +688,7 @@ extension ClimbingDataManager {
|
||||
}
|
||||
}
|
||||
|
||||
print("🖼️ Collected \(imagePaths.count) total image paths for export")
|
||||
print("Collected \(imagePaths.count) total image paths for export")
|
||||
return imagePaths
|
||||
}
|
||||
|
||||
@@ -748,7 +748,7 @@ extension ClimbingDataManager {
|
||||
// Log storage information for debugging
|
||||
let info = await ImageManager.shared.getStorageInfo()
|
||||
print(
|
||||
"📊 Image Storage: \(info.primaryCount) primary, \(info.backupCount) backup, \(info.totalSize / 1024)KB total"
|
||||
"Image Storage: \(info.primaryCount) primary, \(info.backupCount) backup, \(info.totalSize / 1024)KB total"
|
||||
)
|
||||
}.value
|
||||
}
|
||||
@@ -786,7 +786,7 @@ extension ClimbingDataManager {
|
||||
}
|
||||
|
||||
if !orphanedFiles.isEmpty {
|
||||
print("🗑️ Cleaned up \(orphanedFiles.count) orphaned image files")
|
||||
print("Cleaned up \(orphanedFiles.count) orphaned image files")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -803,7 +803,7 @@ extension ClimbingDataManager {
|
||||
}
|
||||
|
||||
func forceImageRecovery() {
|
||||
print("🚨 User initiated force image recovery")
|
||||
print("User initiated force image recovery")
|
||||
ImageManager.shared.forceRecoveryMigration()
|
||||
|
||||
// Refresh the UI after recovery
|
||||
@@ -811,7 +811,7 @@ extension ClimbingDataManager {
|
||||
}
|
||||
|
||||
func emergencyImageRestore() {
|
||||
print("🆘 User initiated emergency image restore")
|
||||
print("User initiated emergency image restore")
|
||||
ImageManager.shared.emergencyImageRestore()
|
||||
|
||||
// Refresh the UI after restore
|
||||
@@ -827,7 +827,7 @@ extension ClimbingDataManager {
|
||||
let info = ImageManager.shared.getStorageInfo()
|
||||
|
||||
return """
|
||||
Image Storage Health: \(isValid ? "✅ Good" : "❌ Needs Recovery")
|
||||
Image Storage Health: \(isValid ? "Good" : "Needs Recovery")
|
||||
Primary Files: \(info.primaryCount)
|
||||
Backup Files: \(info.backupCount)
|
||||
Total Size: \(formatBytes(info.totalSize))
|
||||
@@ -845,7 +845,7 @@ extension ClimbingDataManager {
|
||||
|
||||
// Test with dummy data if we have a gym
|
||||
guard let testGym = gyms.first else {
|
||||
print("❌ No gyms available for testing")
|
||||
print("ERROR: No gyms available for testing")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -877,14 +877,14 @@ extension ClimbingDataManager {
|
||||
// Only restart if session is actually active
|
||||
guard activeSession.status == .active else {
|
||||
print(
|
||||
"⚠️ Session exists but is not active (status: \(activeSession.status)), ending Live Activity"
|
||||
"WARNING: Session exists but is not active (status: \(activeSession.status)), ending Live Activity"
|
||||
)
|
||||
await LiveActivityManager.shared.endLiveActivity()
|
||||
return
|
||||
}
|
||||
|
||||
if let gym = gym(withId: activeSession.gymId) {
|
||||
print("🔍 Checking Live Activity for active session at \(gym.name)")
|
||||
print("Checking Live Activity for active session at \(gym.name)")
|
||||
|
||||
// First cleanup any dismissed activities
|
||||
await LiveActivityManager.shared.cleanupDismissedActivities()
|
||||
@@ -894,15 +894,12 @@ extension ClimbingDataManager {
|
||||
activeSession: activeSession,
|
||||
gymName: gym.name
|
||||
)
|
||||
|
||||
// Update with current session data
|
||||
await updateLiveActivityData()
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this when app becomes active to check for Live Activity restart
|
||||
func onAppBecomeActive() {
|
||||
print("📱 App became active - checking Live Activity status")
|
||||
print("App became active - checking Live Activity status")
|
||||
Task {
|
||||
await checkAndRestartLiveActivity()
|
||||
}
|
||||
@@ -910,7 +907,7 @@ extension ClimbingDataManager {
|
||||
|
||||
/// Call this when app enters background to update Live Activity
|
||||
func onAppEnterBackground() {
|
||||
print("📱 App entering background - updating Live Activity if needed")
|
||||
print("App entering background - updating Live Activity if needed")
|
||||
Task {
|
||||
await updateLiveActivityData()
|
||||
}
|
||||
@@ -939,7 +936,7 @@ extension ClimbingDataManager {
|
||||
return
|
||||
}
|
||||
|
||||
print("🔄 Attempting to restart dismissed Live Activity for \(gym.name)")
|
||||
print("Attempting to restart dismissed Live Activity for \(gym.name)")
|
||||
|
||||
// Wait a bit before restarting to avoid frequency limits
|
||||
try? await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
|
||||
@@ -979,7 +976,7 @@ extension ClimbingDataManager {
|
||||
activeSession.status == .active,
|
||||
let gym = gym(withId: activeSession.gymId)
|
||||
else {
|
||||
print("⚠️ Live Activity update skipped - no active session or gym")
|
||||
print("WARNING: Live Activity update skipped - no active session or gym")
|
||||
if let session = activeSession {
|
||||
print(" Session ID: \(session.id)")
|
||||
print(" Session Status: \(session.status)")
|
||||
@@ -1003,7 +1000,7 @@ extension ClimbingDataManager {
|
||||
elapsedInterval = 0
|
||||
}
|
||||
|
||||
print("🔄 Live Activity Update Debug:")
|
||||
print("Live Activity Update Debug:")
|
||||
print(" Session ID: \(activeSession.id)")
|
||||
print(" Gym: \(gym.name)")
|
||||
print(" Total attempts in session: \(totalAttempts)")
|
||||
|
||||
@@ -34,11 +34,11 @@ final class LiveActivityManager {
|
||||
let isStillActive = activities.contains { $0.id == currentActivity.id }
|
||||
|
||||
if isStillActive {
|
||||
print("ℹ️ Live Activity still running: \(currentActivity.id)")
|
||||
print("Live Activity still running: \(currentActivity.id)")
|
||||
return
|
||||
} else {
|
||||
print(
|
||||
"⚠️ Tracked Live Activity \(currentActivity.id) was dismissed, clearing reference"
|
||||
"WARNING: Tracked Live Activity \(currentActivity.id) was dismissed, clearing reference"
|
||||
)
|
||||
self.currentActivity = nil
|
||||
}
|
||||
@@ -47,18 +47,18 @@ final class LiveActivityManager {
|
||||
// Check if there are ANY active Live Activities for this session
|
||||
let existingActivities = Activity<SessionActivityAttributes>.activities
|
||||
if let existingActivity = existingActivities.first {
|
||||
print("ℹ️ Found existing Live Activity: \(existingActivity.id), using it")
|
||||
print("Found existing Live Activity: \(existingActivity.id), using it")
|
||||
self.currentActivity = existingActivity
|
||||
return
|
||||
}
|
||||
|
||||
print("🔄 No Live Activity found, restarting for existing session")
|
||||
print("No Live Activity found, restarting for existing session")
|
||||
await startLiveActivity(for: activeSession, gymName: gymName)
|
||||
}
|
||||
|
||||
/// Call this when a ClimbSession starts to begin a Live Activity
|
||||
func startLiveActivity(for session: ClimbSession, gymName: String) async {
|
||||
print("🔴 Starting Live Activity for gym: \(gymName)")
|
||||
print("Starting Live Activity for gym: \(gymName)")
|
||||
|
||||
await endLiveActivity()
|
||||
|
||||
@@ -84,9 +84,9 @@ final class LiveActivityManager {
|
||||
pushType: nil
|
||||
)
|
||||
self.currentActivity = activity
|
||||
print("✅ Live Activity started successfully: \(activity.id)")
|
||||
print("Live Activity started successfully: \(activity.id)")
|
||||
} catch {
|
||||
print("❌ Failed to start live activity: \(error)")
|
||||
print("ERROR: Failed to start live activity: \(error)")
|
||||
print("Error details: \(error.localizedDescription)")
|
||||
|
||||
// Check specific error types
|
||||
@@ -104,7 +104,7 @@ final class LiveActivityManager {
|
||||
func updateLiveActivity(elapsed: TimeInterval, totalAttempts: Int, completedProblems: Int) async
|
||||
{
|
||||
guard let currentActivity = currentActivity else {
|
||||
print("⚠️ No current activity to update")
|
||||
print("WARNING: No current activity to update")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -114,14 +114,14 @@ final class LiveActivityManager {
|
||||
|
||||
if !isStillActive {
|
||||
print(
|
||||
"⚠️ Tracked Live Activity \(currentActivity.id) is no longer active, clearing reference"
|
||||
"WARNING: Tracked Live Activity \(currentActivity.id) is no longer active, clearing reference"
|
||||
)
|
||||
self.currentActivity = nil
|
||||
return
|
||||
}
|
||||
|
||||
print(
|
||||
"🔄 Updating Live Activity - Attempts: \(totalAttempts), Completed: \(completedProblems)"
|
||||
"Updating Live Activity - Attempts: \(totalAttempts), Completed: \(completedProblems)"
|
||||
)
|
||||
|
||||
let updatedContentState = SessionActivityAttributes.ContentState(
|
||||
@@ -131,7 +131,7 @@ final class LiveActivityManager {
|
||||
)
|
||||
|
||||
await currentActivity.update(.init(state: updatedContentState, staleDate: nil))
|
||||
print("✅ Live Activity updated successfully")
|
||||
print("Live Activity updated successfully")
|
||||
}
|
||||
|
||||
/// Call this when a ClimbSession ends to end the Live Activity
|
||||
@@ -141,25 +141,25 @@ final class LiveActivityManager {
|
||||
|
||||
// First end the tracked activity if it exists
|
||||
if let currentActivity {
|
||||
print("🔴 Ending tracked Live Activity: \(currentActivity.id)")
|
||||
print("Ending tracked Live Activity: \(currentActivity.id)")
|
||||
await currentActivity.end(nil, dismissalPolicy: .immediate)
|
||||
self.currentActivity = nil
|
||||
print("✅ Tracked Live Activity ended successfully")
|
||||
print("Tracked Live Activity ended successfully")
|
||||
}
|
||||
|
||||
// Force end ALL active activities of our type to ensure cleanup
|
||||
print("🔍 Checking for any remaining active activities...")
|
||||
print("Checking for any remaining active activities...")
|
||||
let activities = Activity<SessionActivityAttributes>.activities
|
||||
|
||||
if activities.isEmpty {
|
||||
print("ℹ️ No additional activities found")
|
||||
print("No additional activities found")
|
||||
} else {
|
||||
print("🔴 Found \(activities.count) additional active activities, ending them...")
|
||||
print("Found \(activities.count) additional active activities, ending them...")
|
||||
for activity in activities {
|
||||
print("🔴 Force ending activity: \(activity.id)")
|
||||
print("Force ending activity: \(activity.id)")
|
||||
await activity.end(nil, dismissalPolicy: .immediate)
|
||||
}
|
||||
print("✅ All Live Activities ended successfully")
|
||||
print("All Live Activities ended successfully")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ final class LiveActivityManager {
|
||||
if let currentActivity = currentActivity {
|
||||
let isStillActive = activities.contains { $0.id == currentActivity.id }
|
||||
if !isStillActive {
|
||||
print("🧹 Cleaning up dismissed Live Activity: \(currentActivity.id)")
|
||||
print("Cleaning up dismissed Live Activity: \(currentActivity.id)")
|
||||
self.currentActivity = nil
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,7 @@ final class LiveActivityManager {
|
||||
func stopHealthChecks() {
|
||||
healthCheckTimer?.invalidate()
|
||||
healthCheckTimer = nil
|
||||
print("🛑 Stopped Live Activity health checks")
|
||||
print("Stopped Live Activity health checks")
|
||||
}
|
||||
|
||||
/// Perform a health check on the current Live Activity
|
||||
@@ -231,7 +231,7 @@ final class LiveActivityManager {
|
||||
let isStillActive = activities.contains { $0.id == currentActivity.id }
|
||||
|
||||
if !isStillActive {
|
||||
print("💔 Health check failed - Live Activity was dismissed")
|
||||
print("Health check failed - Live Activity was dismissed")
|
||||
self.currentActivity = nil
|
||||
|
||||
// Notify that we need to restart
|
||||
@@ -240,7 +240,7 @@ final class LiveActivityManager {
|
||||
object: nil
|
||||
)
|
||||
} else {
|
||||
print("✅ Live Activity health check passed")
|
||||
print("Live Activity health check passed")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user