Proper 1.0 release for iOS. Pending App Store submission.

This commit is contained in:
2025-09-15 21:01:02 -06:00
parent 127c25f506
commit 363fbd676a
24 changed files with 1848 additions and 2 deletions

View File

@@ -0,0 +1,146 @@
import ActivityKit
import Foundation
@MainActor
final class LiveActivityManager {
static let shared = LiveActivityManager()
private init() {}
private var currentActivity: Activity<SessionActivityAttributes>?
/// Check if there's an active session and restart Live Activity if needed
func restartLiveActivityIfNeeded(activeSession: ClimbSession?, gymName: String?) async {
// If we have an active session but no Live Activity, restart it
guard let activeSession = activeSession,
let gymName = gymName,
activeSession.status == .active
else {
return
}
// Check if we already have a running Live Activity
if currentActivity != nil {
print(" Live Activity already running")
return
}
print("🔄 Restarting Live Activity 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)")
await endLiveActivity()
let attributes = SessionActivityAttributes(
gymName: gymName, startTime: session.startTime ?? session.date)
let initialContentState = SessionActivityAttributes.ContentState(
elapsed: 0,
totalAttempts: 0,
completedProblems: 0
)
do {
let activity = try Activity<SessionActivityAttributes>.request(
attributes: attributes,
contentState: initialContentState,
pushType: nil
)
self.currentActivity = activity
print("✅ Live Activity started successfully: \(activity.id)")
} catch {
print("❌ Failed to start live activity: \(error)")
print("Error details: \(error.localizedDescription)")
// Check specific error types
if error.localizedDescription.contains("authorization") {
print("Authorization error - check Live Activity permissions in Settings")
} else if error.localizedDescription.contains("content") {
print("Content error - check ActivityAttributes structure")
}
}
}
/// Call this to update the Live Activity with new session progress
func updateLiveActivity(elapsed: TimeInterval, totalAttempts: Int, completedProblems: Int) async
{
guard let currentActivity else {
print("⚠️ No current activity to update")
return
}
print(
"🔄 Updating Live Activity - Attempts: \(totalAttempts), Completed: \(completedProblems)"
)
let updatedContentState = SessionActivityAttributes.ContentState(
elapsed: elapsed,
totalAttempts: totalAttempts,
completedProblems: completedProblems
)
do {
await currentActivity.update(using: updatedContentState, alertConfiguration: nil)
print("✅ Live Activity updated successfully")
} catch {
print("❌ Failed to update live activity: \(error)")
}
}
/// Call this when a ClimbSession ends to end the Live Activity
func endLiveActivity() async {
guard let currentActivity else {
print(" No current activity to end")
return
}
print("🔴 Ending Live Activity: \(currentActivity.id)")
do {
await currentActivity.end(using: nil, dismissalPolicy: .immediate)
self.currentActivity = nil
print("✅ Live Activity ended successfully")
} catch {
print("❌ Failed to end live activity: \(error)")
self.currentActivity = nil
}
}
/// Check if Live Activities are available and authorized
func checkLiveActivityAvailability() -> String {
let authorizationInfo = ActivityAuthorizationInfo()
let status = authorizationInfo.areActivitiesEnabled
let message = """
Live Activity Status:
• Enabled: \(status)
• Authorization: \(authorizationInfo.areActivitiesEnabled ? "Granted" : "Denied/Unknown")
• Current Activity: \(currentActivity?.id.description ?? "None")
"""
print(message)
return message
}
/// Start periodic updates for Live Activity
func startPeriodicUpdates(for session: ClimbSession, totalAttempts: Int, completedProblems: Int)
{
guard currentActivity != nil else { return }
Task {
while currentActivity != nil {
let elapsed = Date().timeIntervalSince(session.startTime ?? session.date)
await updateLiveActivity(
elapsed: elapsed,
totalAttempts: totalAttempts,
completedProblems: completedProblems
)
// Wait 30 seconds before next update
try? await Task.sleep(nanoseconds: 30_000_000_000)
}
}
}
}