feat(engine): add Menu dropdown for Stats/Achievements/Profile/Settings/Leaderboard
CI / Test & Lint (push) Failing after 20s
CI / Release Build (push) Has been skipped

Continues the UI-first pass. The five informational overlays were
each behind a single-key shortcut (S/A/P/O/L) with no visible UI
affordance. Add a "Menu ▾" button to the action bar that toggles a
popover with one row per overlay. Each row dispatches the same code
path the keyboard accelerator uses by writing a new
`Toggle*RequestEvent`:

- Stats        → ToggleStatsRequestEvent
- Achievements → ToggleAchievementsRequestEvent
- Profile      → ToggleProfileRequestEvent
- Settings     → ToggleSettingsRequestEvent
- Leaderboard  → ToggleLeaderboardRequestEvent

Each plugin's existing toggle handler now reads either its key or
the matching request event so the spawn / despawn / fetch logic stays
in the owning plugin (the popover never duplicates that behaviour).

Action bar order is now (left → right):
  Menu ▾   Undo   Pause   Help   Modes ▾   New Game

Menu sits on the far left because it's a navigation aggregator;
New Game stays on the far right as the most consequential action.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-04-29 23:55:43 +00:00
parent 1d9fb1884a
commit 6240156fee
8 changed files with 224 additions and 18 deletions
+9 -4
View File
@@ -14,7 +14,7 @@ use bevy::tasks::{futures_lite::future, AsyncComputeTaskPool, Task};
use solitaire_data::settings::SyncBackend;
use solitaire_sync::LeaderboardEntry;
use crate::events::InfoToastEvent;
use crate::events::{InfoToastEvent, ToggleLeaderboardRequestEvent};
use crate::settings_plugin::SettingsResource;
use crate::sync_plugin::SyncProviderResource;
@@ -73,6 +73,7 @@ impl Plugin for LeaderboardPlugin {
.init_resource::<ClosedThisFrame>()
.init_resource::<OptInTask>()
.init_resource::<OptOutTask>()
.add_message::<ToggleLeaderboardRequestEvent>()
.add_systems(
Update,
(
@@ -99,18 +100,22 @@ fn reset_closed_flag(mut flag: ResMut<ClosedThisFrame>) {
flag.0 = false;
}
/// `L` key — open or close the leaderboard panel.
/// On open, starts a new fetch if no data is cached or a fetch is not in flight.
/// `L` keyboard accelerator or `ToggleLeaderboardRequestEvent` from the
/// HUD Menu popover — open or close the leaderboard panel. On open,
/// starts a new fetch if no data is cached or a fetch is not in flight.
#[allow(clippy::too_many_arguments)]
fn toggle_leaderboard_screen(
mut commands: Commands,
keys: Res<ButtonInput<KeyCode>>,
mut requests: MessageReader<ToggleLeaderboardRequestEvent>,
screens: Query<Entity, With<LeaderboardScreen>>,
data: Res<LeaderboardResource>,
provider: Option<Res<SyncProviderResource>>,
mut task_res: ResMut<LeaderboardFetchTask>,
mut closed_flag: ResMut<ClosedThisFrame>,
) {
if !keys.just_pressed(KeyCode::KeyL) {
let button_clicked = requests.read().count() > 0;
if !keys.just_pressed(KeyCode::KeyL) && !button_clicked {
return;
}
if let Ok(entity) = screens.single() {