feat(engine): Android UX sweep — tap-to-move, safe area, HUD polish
CI / Test & Lint (push) Failing after 58s
CI / Release Build (push) Has been skipped

Single-tap auto-move (input_plugin):
- Remove 0.5 s double-tap window; any uncommitted TouchPhase::Ended on
  a face-up card now fires MoveRequestEvent immediately.

Bottom safe-area inset (layout, table_plugin):
- compute_layout gains safe_area_bottom param; height budget and bottom
  margin both respect the navigation bar reservation.

Card back contrast (card_plugin):
- CardBackFrame child sprite (gray, card_size + 3 px, local z=-0.01)
  spawned behind every face-down card so the dark back_0.png reads as
  a distinct rectangle against the dark felt.

HUD action bar compactness (hud_plugin):
- max_width 50% → 65% on the action button row; 6 buttons now wrap to
  2 rows instead of 3 on a 360 dp phone.

Dynamic tableau fan fraction (layout, card_plugin):
- Layout gains available_tableau_height field.
- update_tableau_fan_frac system (after GameMutation, before
  sync_cards_on_change) grows face-up fan from 0.25 to the window max
  as revealed column depth increases. Face-down fan is left at the
  window-adaptive value so stacks stay visible.

ModesPopover + MenuPopover light-dismiss (hud_plugin):
- Fullscreen transparent Button backdrop spawned at Z_HUD+4 behind each
  popover; tapping outside the panel despawns both panel and backdrop.

Stock badge legibility (card_plugin):
- Badge font TYPE_CAPTION (11 pt) → TYPE_BODY (14 pt); background
  sprite 28×16 → 34×20 world units.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-11 19:37:46 -07:00
parent 002d96f2c8
commit 4398403418
7 changed files with 383 additions and 174 deletions
+8 -4
View File
@@ -163,8 +163,10 @@ fn setup_table(
// Safe-area insets arrive from JNI asynchronously; they are almost always
// 0 here (populated ~frame 2-3). on_safe_area_changed fires when they
// arrive and issues a synthetic WindowResized to re-snap all game objects.
let safe_area_top = safe_area.as_deref().copied().unwrap_or_default().top / scale;
let layout = compute_layout(window_size, safe_area_top);
let insets = safe_area.as_deref().copied().unwrap_or_default();
let safe_area_top = insets.top / scale;
let safe_area_bottom = insets.bottom / scale;
let layout = compute_layout(window_size, safe_area_top, safe_area_bottom);
let selected_bg = settings.as_ref().map_or(0, |s| s.0.selected_background);
@@ -300,8 +302,10 @@ fn on_window_resized(
};
let window_size = Vec2::new(ev.width, ev.height);
let scale = windows.iter().next().map_or(1.0, |w| w.scale_factor());
let safe_area_top = safe_area.as_deref().copied().unwrap_or_default().top / scale;
let new_layout = compute_layout(window_size, safe_area_top);
let insets = safe_area.as_deref().copied().unwrap_or_default();
let safe_area_top = insets.top / scale;
let safe_area_bottom = insets.bottom / scale;
let new_layout = compute_layout(window_size, safe_area_top, safe_area_bottom);
if let Some(layout_res) = layout_res.as_deref_mut() {
layout_res.0 = new_layout.clone();