commit ab88c0554ac31b8a6d8606428f62c21d2b222b16
parent 6fb82447f6f854d642d3d4d409e40f2fdd125f99
Author: Michael Camilleri <[email protected]>
Date: Fri, 29 May 2026 16:42:59 +0900
Add remote-only active-puzzle debounce
Diffstat:
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/Crossmate/Services/AppServices.swift b/Crossmate/Services/AppServices.swift
@@ -139,6 +139,8 @@ final class AppServices {
/// arrived after the last successful freshen.
private let gameListFreshenCooldown: TimeInterval = 300
private var fresheningPuzzleGridKeys: Set<String> = []
+ private var lastRemotePuzzleGridFreshenAt: [String: Date] = [:]
+ private let remotePuzzleGridFreshenDebounce: TimeInterval = 5
private var isGameListVisible = false
private var latestLocalSelections: [UUID: PlayerSelection] = [:]
private var scheduledEngagementEndTasks: [UUID: Task<Void, Never>] = [:]
@@ -1363,10 +1365,23 @@ final class AppServices {
await movesUpdater.flush()
guard await ensureICloudSyncStarted() else { return }
let label = reason.diagnosticLabel
+ if reason == .remote,
+ shouldSkipRecentRemotePuzzleGridFreshen(
+ gameID: gameID,
+ scope: scope,
+ label: label
+ ) {
+ return
+ }
guard beginPuzzleGridFreshen(gameID: gameID, scope: scope, reason: label) else {
return
}
- defer { endPuzzleGridFreshen(gameID: gameID, scope: scope) }
+ defer {
+ endPuzzleGridFreshen(gameID: gameID, scope: scope)
+ if reason == .remote {
+ noteRemotePuzzleGridFreshenCompleted(gameID: gameID, scope: scope)
+ }
+ }
await syncMonitor.run("freshen puzzle grid \(label)") {
let handled = try await syncEngine.fetchGameDirect(
@@ -1400,6 +1415,25 @@ final class AppServices {
fresheningPuzzleGridKeys.remove(puzzleGridFreshenKey(gameID: gameID, scope: scope))
}
+ private func shouldSkipRecentRemotePuzzleGridFreshen(
+ gameID: UUID,
+ scope: CKDatabase.Scope,
+ label: String
+ ) -> Bool {
+ let key = puzzleGridFreshenKey(gameID: gameID, scope: scope)
+ guard let last = lastRemotePuzzleGridFreshenAt[key] else { return false }
+ let elapsed = Date().timeIntervalSince(last)
+ guard elapsed < remotePuzzleGridFreshenDebounce else { return false }
+ syncMonitor.note(
+ "freshen puzzle grid \(label): \(scopeLabel(scope)) \(gameID.uuidString.prefix(8)) skipped (recent remote refresh \(Int(elapsed.rounded()))s ago)"
+ )
+ return true
+ }
+
+ private func noteRemotePuzzleGridFreshenCompleted(gameID: UUID, scope: CKDatabase.Scope) {
+ lastRemotePuzzleGridFreshenAt[puzzleGridFreshenKey(gameID: gameID, scope: scope)] = Date()
+ }
+
private func puzzleGridFreshenKey(gameID: UUID, scope: CKDatabase.Scope) -> String {
"\(scopeLabel(scope)):\(gameID.uuidString)"
}