277 lines
10 KiB
Swift
277 lines
10 KiB
Swift
//
|
|
// LiveActivityDebugView.swift
|
|
|
|
import SwiftUI
|
|
|
|
struct LiveActivityDebugView: View {
|
|
@EnvironmentObject var dataManager: ClimbingDataManager
|
|
@State private var debugOutput: String = ""
|
|
@State private var isTestRunning = false
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
VStack(alignment: .leading, spacing: 20) {
|
|
|
|
// Header
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
Text("Live Activity Debug")
|
|
.font(.title)
|
|
.fontWeight(.bold)
|
|
|
|
Text("Test and debug Live Activities for climbing sessions")
|
|
.font(.subheadline)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
|
|
// Status Section
|
|
GroupBox("Current Status") {
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
HStack {
|
|
Image(systemName: "circle.fill")
|
|
.foregroundColor(dataManager.activeSession != nil ? .green : .red)
|
|
Text(
|
|
"Active Session: \(dataManager.activeSession != nil ? "Yes" : "No")"
|
|
)
|
|
}
|
|
|
|
HStack {
|
|
Image(systemName: "building.2")
|
|
Text("Total Gyms: \(dataManager.gyms.count)")
|
|
}
|
|
|
|
if let activeSession = dataManager.activeSession,
|
|
let gym = dataManager.gym(withId: activeSession.gymId)
|
|
{
|
|
HStack {
|
|
Image(systemName: "location")
|
|
Text("Current Gym: \(gym.name)")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test Buttons
|
|
GroupBox("Live Activity Tests") {
|
|
VStack(spacing: 16) {
|
|
|
|
Button(action: checkStatus) {
|
|
HStack {
|
|
Image(systemName: "checkmark.circle")
|
|
Text("Check Live Activity Status")
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
}
|
|
.buttonStyle(.bordered)
|
|
.disabled(isTestRunning)
|
|
|
|
Button(action: testLiveActivity) {
|
|
HStack {
|
|
Image(systemName: isTestRunning ? "hourglass" : "play.circle")
|
|
Text(
|
|
isTestRunning
|
|
? "Running Test..." : "Run Full Live Activity Test")
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
.disabled(isTestRunning || dataManager.gyms.isEmpty)
|
|
|
|
Button(action: forceLiveActivityUpdate) {
|
|
HStack {
|
|
Image(systemName: "arrow.clockwise")
|
|
Text("Force Live Activity Update")
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
}
|
|
.buttonStyle(.bordered)
|
|
.disabled(dataManager.activeSession == nil)
|
|
|
|
if dataManager.gyms.isEmpty {
|
|
Text("⚠️ Add at least one gym to test Live Activities")
|
|
.font(.caption)
|
|
.foregroundColor(.orange)
|
|
}
|
|
|
|
if dataManager.activeSession != nil {
|
|
Button(action: endCurrentSession) {
|
|
HStack {
|
|
Image(systemName: "stop.circle")
|
|
Text("End Current Session")
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
}
|
|
.buttonStyle(.bordered)
|
|
.disabled(isTestRunning)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Debug Output
|
|
GroupBox("Debug Output") {
|
|
ScrollView {
|
|
ScrollViewReader { proxy in
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
if debugOutput.isEmpty {
|
|
Text("No debug output yet. Run a test to see details.")
|
|
.foregroundColor(.secondary)
|
|
.italic()
|
|
} else {
|
|
Text(debugOutput)
|
|
.font(.system(.caption, design: .monospaced))
|
|
.textSelection(.enabled)
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(8)
|
|
.id("bottom")
|
|
.onChange(of: debugOutput) {
|
|
withAnimation {
|
|
proxy.scrollTo("bottom", anchor: .bottom)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.frame(maxHeight: 200)
|
|
.background(Color(UIColor.systemGray6))
|
|
.cornerRadius(8)
|
|
}
|
|
|
|
// Clear button
|
|
HStack {
|
|
Spacer()
|
|
Button("Clear Output") {
|
|
debugOutput = ""
|
|
}
|
|
.buttonStyle(.bordered)
|
|
}
|
|
|
|
Spacer()
|
|
}
|
|
.padding()
|
|
}
|
|
.navigationTitle("Live Activity Debug")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
}
|
|
|
|
private func appendDebugOutput(_ message: String) {
|
|
let timestamp = DateFormatter.timeFormatter.string(from: Date())
|
|
let newLine = "[\(timestamp)] \(message)"
|
|
|
|
DispatchQueue.main.async {
|
|
if debugOutput.isEmpty {
|
|
debugOutput = newLine
|
|
} else {
|
|
debugOutput += "\n" + newLine
|
|
}
|
|
}
|
|
}
|
|
|
|
private func checkStatus() {
|
|
appendDebugOutput("🔍 Checking Live Activity status...")
|
|
|
|
let status = LiveActivityManager.shared.checkLiveActivityAvailability()
|
|
appendDebugOutput("Status: \(status)")
|
|
|
|
// Check iOS version
|
|
if #available(iOS 16.1, *) {
|
|
appendDebugOutput("✅ iOS version supports Live Activities")
|
|
} else {
|
|
appendDebugOutput("❌ iOS version does not support Live Activities (requires 16.1+)")
|
|
}
|
|
|
|
// Check if we're on simulator
|
|
#if targetEnvironment(simulator)
|
|
appendDebugOutput("⚠️ Running on Simulator - Live Activities have limited functionality")
|
|
#else
|
|
appendDebugOutput("✅ Running on device - Live Activities should work fully")
|
|
#endif
|
|
}
|
|
|
|
private func testLiveActivity() {
|
|
guard !dataManager.gyms.isEmpty else {
|
|
appendDebugOutput("❌ No gyms available for testing")
|
|
return
|
|
}
|
|
|
|
isTestRunning = true
|
|
appendDebugOutput("🧪 Starting Live Activity test...")
|
|
|
|
Task {
|
|
defer {
|
|
DispatchQueue.main.async {
|
|
isTestRunning = false
|
|
}
|
|
}
|
|
|
|
// Test with first gym
|
|
let testGym = dataManager.gyms[0]
|
|
appendDebugOutput("Using gym: \(testGym.name)")
|
|
|
|
// Create test session
|
|
let testSession = ClimbSession(
|
|
gymId: testGym.id, notes: "Test session for Live Activity")
|
|
appendDebugOutput("Created test session")
|
|
|
|
// Start Live Activity
|
|
await LiveActivityManager.shared.startLiveActivity(
|
|
for: testSession, gymName: testGym.name)
|
|
appendDebugOutput("Live Activity start request sent")
|
|
|
|
// Wait and update
|
|
try? await Task.sleep(nanoseconds: 3_000_000_000) // 3 seconds
|
|
appendDebugOutput("Updating Live Activity with test data...")
|
|
await LiveActivityManager.shared.updateLiveActivity(
|
|
elapsed: 180,
|
|
totalAttempts: 8,
|
|
completedProblems: 2
|
|
)
|
|
|
|
// Another update
|
|
try? await Task.sleep(nanoseconds: 3_000_000_000) // 3 seconds
|
|
appendDebugOutput("Second update...")
|
|
await LiveActivityManager.shared.updateLiveActivity(
|
|
elapsed: 360,
|
|
totalAttempts: 15,
|
|
completedProblems: 4
|
|
)
|
|
|
|
// End after delay
|
|
try? await Task.sleep(nanoseconds: 5_000_000_000) // 5 seconds
|
|
appendDebugOutput("Ending Live Activity...")
|
|
await LiveActivityManager.shared.endLiveActivity()
|
|
|
|
appendDebugOutput("🏁 Live Activity test completed!")
|
|
}
|
|
}
|
|
|
|
private func endCurrentSession() {
|
|
guard let activeSession = dataManager.activeSession else {
|
|
appendDebugOutput("❌ No active session to end")
|
|
return
|
|
}
|
|
|
|
appendDebugOutput("🛑 Ending current session: \(activeSession.id)")
|
|
dataManager.endSession(activeSession.id)
|
|
appendDebugOutput("✅ Session ended")
|
|
}
|
|
|
|
private func forceLiveActivityUpdate() {
|
|
appendDebugOutput("🔄 Forcing Live Activity update...")
|
|
dataManager.forceLiveActivityUpdate()
|
|
appendDebugOutput("✅ Live Activity update sent")
|
|
}
|
|
}
|
|
|
|
extension DateFormatter {
|
|
static let timeFormatter: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "HH:mm:ss"
|
|
return formatter
|
|
}()
|
|
}
|
|
|
|
#Preview {
|
|
LiveActivityDebugView()
|
|
.environmentObject(ClimbingDataManager.preview)
|
|
}
|