crossmate

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

commit 1862bed02672e9869143441ecd5ce29066c11853
parent 6776ddfd1f165fdb636c690baef5deff18f03218
Author: Michael Camilleri <[email protected]>
Date:   Tue, 19 May 2026 20:55:42 +0900

Fan out a directed .resign when resigning from the library

Resigning from the game list called store.resignGame directly, so the Game
record synced but no directed .resign ping went out and collaborators got no
notification — the in-puzzle path already fans out via onResign.

A new \.sendResignPings environment closure mirrors
\.acceptInvite/\.blockFriend: CrossmateApp wires it to
AppServices.sendCompletionPings(resigned:), and GameListView calls it right
after store.resignGame in the Resign button. No services dependency is threaded
into the view.

Co-Authored-By: Claude Opus 4.7 <[email protected]>

Diffstat:
MCrossmate/CrossmateApp.swift | 3+++
MCrossmate/Sync/SyncEngine.swift | 3+++
MCrossmate/Views/GameListView.swift | 3+++
3 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/Crossmate/CrossmateApp.swift b/Crossmate/CrossmateApp.swift @@ -35,6 +35,9 @@ struct CrossmateApp: App { .environment(\.blockFriend, { friendAuthorID in await services.blockFriend(authorID: friendAuthorID) }) + .environment(\.sendResignPings, { gameID in + await services.sendCompletionPings(gameID: gameID, resigned: true) + }) } } } diff --git a/Crossmate/Sync/SyncEngine.swift b/Crossmate/Sync/SyncEngine.swift @@ -13,6 +13,9 @@ extension EnvironmentValues { /// `(friendAuthorID)` — blocks a collaborator: suppress future invites, /// leave their shared games, tear down the friend zone. @Entry var blockFriend: ((String) async -> Void)? = nil + /// `(gameID)` — fans out the directed `.resign` ping after a game is + /// resigned from the library (the in-puzzle path uses `onResign` directly). + @Entry var sendResignPings: ((UUID) async -> Void)? = nil } extension Notification.Name { diff --git a/Crossmate/Views/GameListView.swift b/Crossmate/Views/GameListView.swift @@ -32,6 +32,7 @@ struct GameListView: View { @Environment(\.acceptInvite) private var acceptInvite @Environment(\.blockFriend) private var blockFriend + @Environment(\.sendResignPings) private var sendResignPings @State private var inviteError: String? @State private var acceptingInviteID: NSManagedObjectID? @State private var blockTarget: InviteEntity? @@ -88,6 +89,8 @@ struct GameListView: View { Button("Resign", role: .destructive) { if let target = resignTarget { try? store.resignGame(id: target.id) + let id = target.id + Task { await sendResignPings?(id) } } } Button("Cancel", role: .cancel) {}