crossmate

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

commit 95232622cc612c9f1d76d806c7f1e6008da4a6ec
parent 59dce84264011210c01ca422a659c95075cd1b79
Author: Michael Camilleri <[email protected]>
Date:   Mon,  1 Jun 2026 09:48:48 +0900

Hold the replay scrubber's height while it loads

The Success Panel's scrubber row started as EmptyView while idle, grew
to a caption row once loading began, then collapsed back to nothing when
the load resolved to no reachable history — appearing and vanishing as
it went. That could read as a hitch: the scoreboard below shifting up
and down as the row changed size.

ReplayScrubber now reserves the same row height in every state. The
idle, empty-ready and unavailable states all render a blank box of that
height rather than EmptyView, so the load can resolve without the banner
changing size. The loading caption shows only while a load is genuinely
in flight, so the no-replay path no longer flashes a spinner before
settling.

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

Diffstat:
MCrossmate/Views/SuccessPanel.swift | 11+++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/Crossmate/Views/SuccessPanel.swift b/Crossmate/Views/SuccessPanel.swift @@ -246,10 +246,13 @@ private struct ReplayScrubber: View { ProgressView().controlSize(.small) Text("Loading replay…") } - case .ready, .idle, .unavailable: - // Nothing to replay (empty log) or no reachable history: - // leave the banner as just the scoreboard. - EmptyView() + case .idle, .ready, .unavailable: + // Not started yet (`.idle`), nothing to replay (empty log), or + // no reachable history. Hold the row's height anyway so the + // banner doesn't change size as the load resolves — otherwise + // the scoreboard below hitches up and down as the scrubber + // appears then collapses. + Color.clear.frame(height: Self.rowHeight) } } .padding(.horizontal, 18)