Proper 1.0 release for iOS. Pending App Store submission.
This commit is contained in:
146
ios/OpenClimb/ViewModels/LiveActivityManager.swift
Normal file
146
ios/OpenClimb/ViewModels/LiveActivityManager.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user