feat(engine): ManualSyncRequestEvent + Sync Now button in settings

- Added ManualSyncRequestEvent to events.rs (exported from lib.rs).
- SyncPlugin now handles ManualSyncRequestEvent: if no pull is in
  flight, spawns a new AsyncComputeTaskPool task and sets status to
  Syncing. Ignores duplicate requests while a pull is active.
- Settings panel "Sync" section now shows the status text alongside a
  "Sync Now" button that fires ManualSyncRequestEvent.
- Cleaned up stale doc comment in input_plugin.rs (Esc pause note).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-04-27 00:03:24 +00:00
parent f7f14efe07
commit 20db4b312a
5 changed files with 77 additions and 11 deletions
+26 -1
View File
@@ -25,6 +25,7 @@ use solitaire_data::{
use solitaire_sync::{merge, SyncPayload};
use crate::achievement_plugin::{AchievementsResource, AchievementsStoragePath};
use crate::events::ManualSyncRequestEvent;
use crate::progress_plugin::{ProgressResource, ProgressStoragePath};
use crate::resources::{SyncStatus, SyncStatusResource};
use crate::stats_plugin::{StatsResource, StatsStoragePath};
@@ -92,8 +93,9 @@ impl Plugin for SyncPlugin {
.init_resource::<SyncStatusResource>()
.init_resource::<PullTaskResult>()
.init_resource::<PullTask>()
.add_event::<ManualSyncRequestEvent>()
.add_systems(Startup, start_pull)
.add_systems(Update, poll_pull_result)
.add_systems(Update, (poll_pull_result, handle_manual_sync_request))
.add_systems(Last, push_on_exit);
}
}
@@ -116,6 +118,29 @@ fn start_pull(
status.0 = SyncStatus::Syncing;
}
/// Update system: starts a new pull task when `ManualSyncRequestEvent` is
/// received, but only if no pull is already in flight.
fn handle_manual_sync_request(
mut events: EventReader<ManualSyncRequestEvent>,
provider: Res<SyncProviderResource>,
mut task_res: ResMut<PullTask>,
mut status: ResMut<SyncStatusResource>,
) {
if events.is_empty() {
return;
}
events.clear();
if task_res.0.is_some() {
return; // Already pulling — ignore.
}
let provider = provider.0.clone();
let task = AsyncComputeTaskPool::get().spawn(async move {
provider.pull().await.map_err(|e| e.to_string())
});
task_res.0 = Some(task);
status.0 = SyncStatus::Syncing;
}
/// Update system: polls the pull task without blocking.
///
/// When the task resolves successfully: