crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit 85312f48466959b9955502f9285afbddaa2ee9f7
parent e98eaf1d440c1be0bae86cc9d9a35954ab7b6831
Author: Michael Camilleri <[email protected]>
Date:   Fri,  3 Jul 2026 08:42:25 +0900

Clean up hacky code

Diffstat:
MCrossmate/CrossmateApp.swift | 66+++++++++++++++++++++++++++++++-----------------------------------
MCrossmate/Views/Puzzle/SuccessPanel.swift | 10+++++++++-
2 files changed, 40 insertions(+), 36 deletions(-)

diff --git a/Crossmate/CrossmateApp.swift b/Crossmate/CrossmateApp.swift @@ -835,44 +835,40 @@ private struct PuzzleDisplayView: View { noteSessionPhase(scenePhase) Task { await services.badge.dismissDeliveredNotifications(for: gameID) } - while !Task.isCancelled { - do { - if let plan = NYTPuzzleUpgrader.plan(for: gameID, store: store) { - loadingMessage = "Updating puzzle..." - let fetcher = services.nytFetcher - let outcome = await NYTPuzzleUpgrader.apply(plan: plan, store: store) { date in - try await fetcher.fetchPuzzle(for: date) - } - switch outcome { - case .upgraded: - services.eventLog.note("[upgrade NYT \(gameID.uuidString.prefix(8))] applied") - case .mismatched(let reason): - services.eventLog.note("[upgrade NYT \(gameID.uuidString.prefix(8))] structural mismatch — \(reason)", level: "warn") - case .failed(let error): - services.eventLog.note("[upgrade NYT \(gameID.uuidString.prefix(8))] fetch failed: \(error)", level: "error") - } + do { + if let plan = NYTPuzzleUpgrader.plan(for: gameID, store: store) { + loadingMessage = "Updating puzzle..." + let fetcher = services.nytFetcher + let outcome = await NYTPuzzleUpgrader.apply(plan: plan, store: store) { date in + try await fetcher.fetchPuzzle(for: date) } - let (game, mutator) = try store.loadGame(id: gameID) - let newSession = PlayerSession( - game: game, - mutator: mutator, - cursorStore: services.cursorStore - ) - let newRoster = services.makePlayerRoster(for: gameID, preferences: preferences) - roster = newRoster - session = newSession - openPuzzleFollowUpTask = Task { @MainActor in - await finishOpeningPuzzle( - session: newSession, - roster: newRoster, - isShared: mutator.isShared - ) + switch outcome { + case .upgraded: + services.eventLog.note("[upgrade NYT \(gameID.uuidString.prefix(8))] applied") + case .mismatched(let reason): + services.eventLog.note("[upgrade NYT \(gameID.uuidString.prefix(8))] structural mismatch — \(reason)", level: "warn") + case .failed(let error): + services.eventLog.note("[upgrade NYT \(gameID.uuidString.prefix(8))] fetch failed: \(error)", level: "error") } - break - } catch { - loadError = String(describing: error) - break } + let (game, mutator) = try store.loadGame(id: gameID) + let newSession = PlayerSession( + game: game, + mutator: mutator, + cursorStore: services.cursorStore + ) + let newRoster = services.makePlayerRoster(for: gameID, preferences: preferences) + roster = newRoster + session = newSession + openPuzzleFollowUpTask = Task { @MainActor in + await finishOpeningPuzzle( + session: newSession, + roster: newRoster, + isShared: mutator.isShared + ) + } + } catch { + loadError = String(describing: error) } } .task(id: session?.mutator.isShared == true) { diff --git a/Crossmate/Views/Puzzle/SuccessPanel.swift b/Crossmate/Views/Puzzle/SuccessPanel.swift @@ -393,7 +393,10 @@ private struct ReplayScrubber: View { // Drive autoplay: play/pause and speed changes restart the loop with // the current interval. A paused replay yields a `nil` interval, so the // task exits and the grid rests. - .task(id: "\(replay.isPlaybackActive)-\(replay.selectedPlaybackSpeed)") { + .task(id: PlaybackTaskID( + isActive: replay.isPlaybackActive, + speed: replay.selectedPlaybackSpeed + )) { guard let interval = replay.playbackStepInterval else { return } while !Task.isCancelled { try? await Task.sleep(for: interval) @@ -403,6 +406,11 @@ private struct ReplayScrubber: View { } } + private struct PlaybackTaskID: Equatable { + let isActive: Bool + let speed: Int + } + private var historyOrSpeedControl: some View { ZStack { Image(systemName: "clock.arrow.circlepath")