From 89a21c05871a4720fcf2c67236a8694ece9e5117 Mon Sep 17 00:00:00 2001 From: funman300 Date: Sun, 10 May 2026 20:45:41 -0700 Subject: [PATCH] fix(android): wrap HUD column and action button row on narrow viewport The v0.22.3 hardware screenshot showed the 6-button action row (~510 px when laid out) overflowing into a 360 dp viewport from the right anchor, with Menu and Undo clipped off-screen left and Pause/Help/Modes/New_Game overlapping the left HUD column's Score / Moves / Timer text. Cap both clusters at `max_width: 50 %` so on mobile each takes half the viewport (~180 px) and on desktop the cap is wider than either cluster's natural width so the existing single-line layout is preserved. - Action button row: adds `flex_wrap: Wrap`, `row_gap`, and `justify_content: FlexEnd` so the row breaks to multiple right-aligned lines instead of clipping. 6 buttons become 2-3 lines of 2-3 buttons. - HUD column tier rows: add `flex_wrap: Wrap` and `row_gap` to the shared `row_node` helper so a long Mode/Challenge/Draw-cycle combo soft-wraps onto two lines instead of pushing into the action button column. Closes P0 #2 of docs/android/PLAYABILITY_TODO.md. All 854 engine tests pass; clippy clean. Co-Authored-By: Claude Sonnet 4.6 --- docs/android/PLAYABILITY_TODO.md | 11 +++++++--- solitaire_engine/src/hud_plugin.rs | 32 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/docs/android/PLAYABILITY_TODO.md b/docs/android/PLAYABILITY_TODO.md index 2b8a22c..ecab1b9 100644 --- a/docs/android/PLAYABILITY_TODO.md +++ b/docs/android/PLAYABILITY_TODO.md @@ -36,9 +36,14 @@ rewrites required. change-detection fix-up system re-applies `base_top + insets.top` whenever the resource updates. Bottom inset is captured but not yet consumed (waits for bottom-anchored UI). -- [ ] **Mobile HUD layout.** Wrap to two rows, drop redundant text, or - move secondary actions (Help, Modes) into a hamburger / drawer. - Current single-row layout requires desktop width. +- [x] **Mobile HUD layout.** *Closed 2026-05-10.* Both the left HUD + column and the right action button row are now capped at + `max_width: 50 %` and the button row + tier-row child Nodes carry + `flex_wrap: Wrap`. On a 360 dp viewport the 6-button row breaks + to multiple lines (right-justified) and the tier rows wrap + individually instead of overflowing into the action column. On + desktop (≥ 1280 px) the 50 % cap is wider than any natural row + width so the existing single-line layout is unchanged. - [x] **Card-back asset not rendering.** *Closed 2026-05-10 by `fcc7337`.* `AssetPlugin::file_path = "../assets"` was set unconditionally to fix the desktop `cargo run -p solitaire_app` diff --git a/solitaire_engine/src/hud_plugin.rs b/solitaire_engine/src/hud_plugin.rs index dfcdf43..cbb9916 100644 --- a/solitaire_engine/src/hud_plugin.rs +++ b/solitaire_engine/src/hud_plugin.rs @@ -444,6 +444,16 @@ fn spawn_hud( let row_node = || Node { flex_direction: FlexDirection::Row, column_gap: VAL_SPACE_3, + // On a narrow viewport the four tier rows (Score/Moves/Timer, + // Mode/Challenge/Draw-cycle/Won-previously, Undos/Recycles/ + // Auto-complete, selection chip) can collectively be wider than + // the available space and overflow into the action-button column + // on the right. `flex_wrap: Wrap` lets each tier soft-wrap onto + // a second line; on a desktop window the rows stay single-line + // because the parent column has no width cap and the row never + // exceeds the natural line width. + flex_wrap: FlexWrap::Wrap, + row_gap: VAL_SPACE_1, align_items: AlignItems::Baseline, ..default() }; @@ -455,6 +465,14 @@ fn spawn_hud( left: VAL_SPACE_3, top: Val::Px(SPACE_2 + top_inset), flex_direction: FlexDirection::Column, + // Cap the column at 50% of viewport so on narrow + // (mobile) widths the inner tier rows have a bounded + // width to wrap against, and the column can't bleed + // into the right-anchored action button row (also + // capped at 50%). On desktop 50% of 1920 = 960 px, + // wider than any tier row's natural width, so the + // visible layout is unaffected. + max_width: Val::Percent(50.0), row_gap: VAL_SPACE_1, ..default() }, @@ -603,7 +621,21 @@ fn spawn_action_buttons( right: VAL_SPACE_3, top: Val::Px(SPACE_2 + top_inset), flex_direction: FlexDirection::Row, + // 6 buttons total ~510 px wide; on a desktop window + // (typically >= 1280 px) `max_width: 50%` is >= 640 px + // and the row stays a single line. On a 360 dp phone + // 50% is 180 px and the row wraps to two-three lines — + // which keeps the buttons out of the left HUD column's + // horizontal range and prevents the off-screen-left + // clipping seen in the v0.22.3 hardware screenshot. + max_width: Val::Percent(50.0), + flex_wrap: FlexWrap::Wrap, + // When the row wraps, buttons pack to the *end* of each + // line so the row stays visually right-aligned (matches + // the `right: VAL_SPACE_3` anchor). + justify_content: JustifyContent::FlexEnd, column_gap: VAL_SPACE_2, + row_gap: VAL_SPACE_2, align_items: AlignItems::Center, ..default() },