crossmate

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

commit 826437414d77839f2466328f8c4d55f6f21a4f7e
parent 57207100d37d1bf528b9438adf40097942e8cbc5
Author: Michael Camilleri <[email protected]>
Date:   Sun, 14 Jun 2026 06:07:03 +0900

Fix fill letters and Clue Bar colour in Dark Mode

In Dark Mode the entered letters disappeared from the grid. The entry
letter drew with the hierarchical primary/secondary label style, which
follows the system appearance and resolves to near-white in Dark Mode.
Puzzle cells are always white regardless of appearance, though, so the
ink rendered white-on-white and the fill vanished. The letter is now
always black — a lighter black for pencil — which is safe because
revealed and checkedWrong state is shown by the corner triangle, not by
recolouring the letter.

The Clue Bar had a related but milder problem. Its background is the
player's colour at the faint author-tint opacity, but unlike the
always-white grid cells the wash composites over the system background;
at 10% over a near-black Dark Mode background the player's hue read as
black rather than, say, blue. A dedicated clueBarFill raises the opacity
in Dark Mode so the colour stays perceptible, while the shared author
tint on grid cells — which only ever sits over white — is left at its
original opacity.

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

Diffstat:
MCrossmate/Models/PlayerColor.swift | 9+++++++++
MCrossmate/Views/CellView.swift | 16+++++++++-------
MCrossmate/Views/PuzzleView.swift | 5++++-
3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/Crossmate/Models/PlayerColor.swift b/Crossmate/Models/PlayerColor.swift @@ -33,6 +33,15 @@ struct PlayerColor: Sendable, Identifiable, Hashable { /// Fill for UI tied to faint author-attribution tinting. var authorTintFill: Color { tint.opacity(Self.authorTintOpacity) } + + /// Background wash for the clue bar. The clue bar composites over the + /// system background, so unlike the always-white grid cells the wash's + /// perceived colour depends on the appearance: at the 10% author-tint + /// opacity over a near-black Dark Mode background the hue reads as black. + /// Raise the opacity in Dark Mode so the player's colour stays visible. + func clueBarFill(dark: Bool) -> Color { + tint.opacity(dark ? 0.20 : Self.authorTintOpacity) + } } extension PlayerColor { diff --git a/Crossmate/Views/CellView.swift b/Crossmate/Views/CellView.swift @@ -65,17 +65,19 @@ struct CellView: View, Equatable { .contentShape(Rectangle()) } - /// Foreground style for the main entry letter. Pencil entries use the - /// hierarchical `.secondary` style so they render lighter and respect - /// dark mode; everything else — including revealed and checkedWrong - /// cells — uses the primary label colour. Reveal/wrong state is shown - /// purely via the corner triangle, not by recolouring the letter. + /// Foreground style for the main entry letter. The cell fill is always + /// white regardless of system appearance, so the letter ink is always + /// black — it must not follow Dark Mode or it would vanish against the + /// white cell. Pencil entries render as a lighter black; everything else + /// — including revealed and checkedWrong cells — uses solid black. Reveal/ + /// wrong state is shown purely via the corner triangle, not by recolouring + /// the letter. private var entryStyle: AnyShapeStyle { switch mark { case .pencil: - return AnyShapeStyle(HierarchicalShapeStyle.secondary) + return AnyShapeStyle(Color.black.opacity(0.5)) case .none, .pen, .revealed: - return AnyShapeStyle(HierarchicalShapeStyle.primary) + return AnyShapeStyle(Color.black) } } diff --git a/Crossmate/Views/PuzzleView.swift b/Crossmate/Views/PuzzleView.swift @@ -1504,10 +1504,13 @@ private struct ClueBar: View { @Bindable var session: PlayerSession let replayClueTarget: ReplayClueTarget? @Environment(PlayerPreferences.self) private var preferences + @Environment(\.colorScheme) private var colorScheme @State private var slideEdge: Edge = .trailing @State private var isShowingClueList = false - private var backgroundColor: Color { preferences.color.authorTintFill } + private var backgroundColor: Color { + preferences.color.clueBarFill(dark: colorScheme == .dark) + } var body: some View { let display = replayClueDisplay ?? liveClueDisplay