commit 5a4d06bfa7b576d0f4e5185ad1698427ae785bdf
parent 2b69ddbe77e57913baef4ad2d2f4ed099399fa2d
Author: Michael Camilleri <[email protected]>
Date: Sat, 6 Jun 2026 12:45:13 +0900
Add cache busting value for undo/redo
Diffstat:
1 file changed, 9 insertions(+), 0 deletions(-)
diff --git a/Crossmate/Persistence/GameMutator.swift b/Crossmate/Persistence/GameMutator.swift
@@ -20,6 +20,10 @@ final class GameMutator {
private let authorIDProvider: (@MainActor () -> String?)?
private let onLocalCellEdit: (@MainActor (RealtimeCellEdit) -> Void)?
private let onLocalCellEditBatch: (@MainActor ([RealtimeCellEdit]) -> Void)?
+ /// Observation token for undo/redo availability. The journal itself is not
+ /// observable, so `canUndo`/`canRedo` read this value and journal mutations
+ /// bump it to invalidate SwiftUI menu state.
+ private var journalRevision = 0
/// While non-nil, `emitMove` parks its live broadcast here instead of
/// firing `onLocalCellEdit` per cell. A bulk gesture (check/clear/undo of a
@@ -166,11 +170,13 @@ final class GameMutator {
/// is cheap (a derivation pass over the in-memory journal) and drives the
/// enabled state of the undo/redo controls.
var canUndo: Bool {
+ _ = journalRevision
guard !isAccessRevoked, !isCompleted, let movesJournal else { return false }
return movesJournal.canUndo(gameID: gameID)
}
var canRedo: Bool {
+ _ = journalRevision
guard !isAccessRevoked, !isCompleted, let movesJournal else { return false }
return movesJournal.canRedo(gameID: gameID)
}
@@ -190,6 +196,7 @@ final class GameMutator {
while let plan = movesJournal.planUndo(gameID: gameID) {
if applyRestores(plan.restores, kind: .undo) { return cursorTarget(for: plan) }
movesJournal.markUndoConsumed(stepID: plan.stepID, gameID: gameID)
+ journalRevision += 1
}
return nil
}
@@ -201,6 +208,7 @@ final class GameMutator {
while let plan = movesJournal.planRedo(gameID: gameID) {
if applyRestores(plan.restores, kind: .redo) { return cursorTarget(for: plan) }
movesJournal.markRedoConsumed(stepID: plan.stepID, gameID: gameID)
+ journalRevision += 1
}
return nil
}
@@ -320,6 +328,7 @@ final class GameMutator {
batchID: batchID,
direction: direction
)
+ journalRevision += 1
}
guard let movesUpdater else { return }