commit 64a417dffdc59be84f3cb50e00ce7adc326b88e6
parent 0b3b5073a635a57d9e456304c9b5fa4910f89375
Author: Michael Camilleri <[email protected]>
Date: Mon, 13 Apr 2026 02:09:49 +0900
Add more iCloud debugging support
Diffstat:
2 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/Crossmate/Sync/SyncEngine.swift b/Crossmate/Sync/SyncEngine.swift
@@ -531,6 +531,22 @@ actor SyncEngine {
let hasZoneToken: Bool
}
+ /// Clears the local sync bookkeeping (zone/subscription created flags and
+ /// change tokens) so the next bootstrap actually hits the network. Used by
+ /// the diagnostics screen to recover from stale flags. Does not touch the
+ /// outbox or any game data.
+ func resetSyncState() async {
+ let context = persistence.container.newBackgroundContext()
+ context.performAndWait {
+ let state = SyncStateEntity.current(in: context)
+ state.zoneCreated = false
+ state.subscriptionCreated = false
+ state.privateDatabaseToken = nil
+ state.privateZoneToken = nil
+ try? context.save()
+ }
+ }
+
func diagnosticSnapshot() async -> DiagnosticSnapshot {
let accountStatus: CKAccountStatus
do {
diff --git a/Crossmate/Views/SyncDiagnosticsView.swift b/Crossmate/Views/SyncDiagnosticsView.swift
@@ -49,6 +49,11 @@ struct SyncDiagnosticsView: View {
}
}
.disabled(isSyncing)
+
+ Button("Reset Sync State", role: .destructive) {
+ Task { await resetSyncState() }
+ }
+ .disabled(isSyncing)
}
Section("Recent Events") {
@@ -90,6 +95,13 @@ struct SyncDiagnosticsView: View {
// MARK: - Actions
+ private func resetSyncState() async {
+ await syncEngine.resetSyncState()
+ syncMonitor.note("Sync state reset (zone/subscription flags and tokens cleared)")
+ let snapshot = await syncEngine.diagnosticSnapshot()
+ syncMonitor.updateSnapshot(snapshot)
+ }
+
private func runFullSync() async {
guard !isSyncing else { return }
isSyncing = true