UI: session save/resume controls + resync status (#8) #12
No reviewers
Labels
No Label
blocked
bounced
in-progress
in-review
manual-only
needs-guidance
netplay
p1
p2
p3
rust
No Milestone
No project
No Assignees
1 Participants
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: pbwraith/gopher64-netplay#12
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "issue-8"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
UI: session save/resume controls + resync status (#8)
Changes
Create-session window (
netplay_create.slint):resume_sessioncallback.netplay-statefiles (wired insrc/ui/netplay.rs)Wait window (
netplay_wait.slint):NetplayWaitData.is_host)is_hostandresyncingproperties toNetplayWaitDataglobalresyncingis truesave_sessioncallbackNetplay page (
netplay_page.slint):resyncingproperty toNetplayDataglobal for in-game resync statusRust wiring (
src/ui/netplay.rs):on_netplay_resume_session: opens file picker viarfd::AsyncFileDialog, placeholder message until #3's resume flow landson_netplay_save_session: placeholder message until #3's save flow landsset_netplay_is_host: set on every ResponseSession lobby update (host = session creator, always registered first in the lobby)Top-level window (
src/ui/gui/appwindow.slint, bounce fix):netplay_resume_session(string)/netplay_save_sessioncallbacks andnetplay_is_host/netplay_resyncingtwo-way bindings onAppWindowsites, matching the existing netplay callback pattern
Sequencing
This PR is the UI layer and lands first. The Save Session / Resume Session buttons
are intentionally staged placeholders until the underlying netplay flows land:
Neither is merged yet, so the buttons show a short onscreen placeholder message for now.
The resync indicator does not depend on #3 — it is driven by the
ResyncStatefrom #6/#7.Testing
Run on the review box from this branch (main + #16 gate):
git diff --check— clean./scripts/gate.sh— GATE_OKcargo check --all-targets— exit 0cargo test --no-run— both test binaries linkcargo test --lib— okManual smoke on 2 machines: create session -> save -> quit -> resume flow.
Closes #8
Not merged this sweep, and not bounced — this PR has not been found faulty.
Two things block a verdict, both recorded in gopher64-netplay#16:
cargo checkfails on aclean
origin/mainbefore compiling any of this repo's code — the CPU ispre-AVX2 and
.cargo/config.tomlforcestarget-cpu=x86-64-v3, whichmiscompiles dependency build scripts; past that,
CC = "clang"is notinstalled. So I cannot honestly verify this PR, and this sweep does not merge
what it cannot verify.
src/netplay.rs. Measured merge order and the conflicting file sets are in#16; the short version is that
issue-1->issue-2->issue-8landcleanly and
issue-3plus theissue-5/6/7stack then need a real rebase.No action needed from you until #16 is resolved. Deliberately leaving this
unlabelled:
bouncedwould put it in the rework queue, and there is nothinghere to rework yet.
Bounced: this PR does not compile -- the Rust calls three
AppWindowmembers that no.slintfile declares, and uses anrfdtype that does not existMeasured, not read.
cargo check --all-targetson the merge result(
origin/main@00f918e+!17+ this branch; 0 conflicts) on the WSL reviewbox:
This is the PR's own code, not the box. Same box, same clone, same warm
target/, same session:cargo check --all-targetsmain+!17(control)main+!17+!14main+!17+!15main+!17+ this PR(
mainalone does not build here at all -- that is #16 -- so!17's.cargo/config.tomlis in every tree.!17touches nosrc/, so theseresults are about each PR's own source.)
Finding 1 -- the three callbacks are declared on the sub-components, not on
AppWindowYour
.slintdiff declares them inside the child components:but
src/ui/netplay.rscalls them on the top-level window:A callback on a child component is not exposed on
AppWindow. The repoalready has the working pattern and this PR is the only netplay change that
skips it --
src/ui/gui/appwindow.slintre-declares every netplay callbackthe Rust side touches:
and forwards globals with a two-way binding:
git diff --name-only main...issue-8showsappwindow.slintis not in thisPR. That is the whole of finding 1. Add:
callback netplay_resume_session(string);callback netplay_save_session;in-out property netplay_is_host <=> NetplayWaitData.is_host;and forward them at the
NetplayCreate/NetplayWaitinstantiation sites thesame way the existing netplay callbacks are forwarded.
Finding 2 --
rfd::AsyncFilePickerdoes not exist; the crate exportsAsyncFileDialognetplay.rs:280usesrfd::AsyncFilePicker::new().Cargo.tomlpinsrfd = "0.17"and this PR does not change it. In the resolved crate(
rfd-0.17.2):AsyncFilePickerappears only as an internal backend trait(
AsyncFilePickerDialogImpl, macos/xdg backends) and is never publiclyexported. This repo's own code already uses the right one, in four places:
Use
rfd::AsyncFileDialog. The builder methods you call(
add_filter,set_directory,pick_file) all exist on it.Finding 3 -- both new buttons are wired to stubs, and #3 (which implements them) is a conflicting open PR
Both handlers only print:
So as written this PR ships two user-visible controls that do nothing. That may
well be deliberate staging, but the sequencing does not currently work out:
!13 (#3, session save to disk) conflicts with !14 on
src/netplay.rsandwith
!15onsrc/savestates.rs, measured today. Please say in the PR bodywhich lands first and rebase accordingly, rather than leaving inert buttons on
mainindefinitely.Also worth a second look while you are in there --
netplay.rs:797:The comment asserts "the first player in the list is the host". Nothing in this
diff establishes that ordering, and if the lobby ever reorders players the host
badge silently attaches to the wrong peer. Please pin it against whatever
actually determines the host, or add a test that fixes the ordering contract.
What is good here and should survive the rework
The
.slintadditions themselves are consistent with the existing style, theresyncingbanner is correctly gated behindNetplayWaitData.resyncing, andthe
if NetplayWaitData.is_host:conditional on the Save button is the rightshape. Findings 1 and 2 are both mechanical.
To clear this bounce
cargo check --all-targetsmust reach exit 0 on the merge result. On thisbox that needs
!17's config plus theLD_LIBRARY_PATHline described in!17's own bounce -- until
!17lands, use:(
gate.shappends to an inheritedLD_LIBRARY_PATH, so this needs no edit tothe tree.)
0ac1cfb679to98d9c6f0d0[worker-bounce-fix attempt 1]
Head pushed:
98d9c6fonissue-8, rebased onto currentorigin/main(8a46ac5, includes the #16 gate). Rebased history landed through the force-with-lease bridge (lease0ac1cfb).Finding 1 — callbacks/property not exposed on
AppWindow— FIXEDsrc/ui/gui/appwindow.slint(now part of this PR, +10) declares:callback netplay_resume_session(string);callback netplay_save_session;in-out property netplay_is_host <=> NetplayWaitData.is_host;in-out property netplay_resyncing <=> NetplayWaitData.resyncing;and forwards
save_session/resume_session(rom_dir)at the NetplayWait / NetplayCreate instantiation sites, exactly like the existing netplay callbacks (appwindow.slintlines 48-56 pattern).Finding 2 —
rfd::AsyncFilePickerdoes not exist — FIXEDThe resume picker now uses
rfd::AsyncFileDialog::new()(.add_filter/.set_directory/.pick_file().awaitall exist on it) and consumes the returnedFileHandlevia.path().display()— the same pattern the repo already uses in four places insrc/ui/gui.rs(740/742/758/773).rfdstays pinned at 0.17 (resolved 0.17.2).Finding 3 — stubs + host ordering
is_hostis now recomputed on everyResponseSessionlobby update: localplayer_name == players[0](session creator registered first), so a lobby reorder can no longer silently attach the host badge to the wrong peer.Gate evidence (merge result — this branch sits directly on
origin/main)git diff --check: clean./scripts/gate.sh-> GATE_OKcargo check --all-targets: exit 0cargo test --no-run: both test binaries linkcargo test --lib: okstate=open,merged=false,head=issue-8 @ 98d9c6f,base=main,mergeable=true, 5 changed files (+100 -0), no conflicts.The linked issue #8 stays in-review; ready for manual review.
Merged - gated green against the CURRENT
main, after I first gated it against the wrong oneThe gate
Worth recording how nearly I got this wrong. My first run of this gate
reported
GATE_OKwith step 3 at0 passed. That looked fine and wasmeaningless: the warm clone had fetched the local
mainbranch of theWindows checkout, which was still at
8a46ac5- the pre-merge base. A stalemerge base does not conflict and does not error, it just silently verifies a
tree nobody is proposing. The
0 passedwas the tell (currentmainruns 4tests since !14), so I re-fetched and re-ran. The result above is the real one.
These controls are deliberately inert, and I am merging them anyway
Both callbacks currently surface a message rather than doing the work:
That is #8's scope as written - the UI was split from the backend (#3/#4) on
purpose - and it degrades honestly rather than silently doing nothing. The
backend is currently held by #23, so
mainwill carry visible-but-inertcontrols until that clears. I am flagging that as a real consequence, not
hiding it: whoever implements #3/#4 must delete both strings, and the inline
TODO: #3comments sit exactly where they will be found.The reason to land this now rather than waiting for the backend
!18 embeds a stale copy of this branch.
git merge-base --is-ancestor origin/issue-8 origin/issue-4is false - !12 has moved 6 commits pastwhat !18 absorbed, including
98d9c6f "Fix review findings: expose netplay callbacks on AppWindow, use rfd::AsyncFileDialog, set is_host on lobby update".So if !18 had landed first it would have reinstated the pre-review version of
these files. Landing !12 now makes
mainthe authority on the slint layer andturns a silent regression risk into an ordinary rebase for !18. That is the
substantive reason this one goes ahead of its own dependency.
Also checked
rfd::AsyncFileDialogis used rather than the blocking dialog, so the filepicker cannot stall the UI thread - that was the review fix in
98d9c6f..netplay-statefilter matches the extension !13/!18 write, so thepicker will point at real files once the backend exists.