feat(debug): full UI screenshot sweep — captures modals/dialogs/flows/states
The existing sweep only captures tabs. This adds a "Full UI sweep" (DEBUG OPTIONS) that also drives every normally-hidden surface into view and captures it under every skin, so all the UI a normal sweep misses can be reviewed at once. - The capture unit becomes a "surface" (SweepTarget: a base tab, optionally with a setup()/teardown() that forces a modal / multi-step flow / state overlay on top). Tabs are surfaces with a null setup. The existing tab sweep is folded into the same state machine (one code path). All sweep logic + the catalog + demo data move into a new src/app_sweep.cpp. - Runs OFFLINE against injected demo data (installDemoWalletData snapshots then restores the real state_ — WalletState isn't copy-assignable, so a targeted field snapshot is used) and fires NO live op: capture_mode_ guards the seed-backup RPC, auto-lock, and the migration pumps; the async-firing dialogs are neutralized by pre-setting their state (fetch_started_ + demo phrase; seed_migration_step_ set directly). Verified: 0 RPC/secret/send calls. - Catalog (v1): tabs + the bool-flag modals (import/export key, backup, seed-backup, about, settings) + the 6 migrate-to-seed steps + 4 wizard steps + lock/warmup/not-ready overlays + the send-confirm popup (via a new ui::SweepShowSendConfirm debug hook, since its state is send_tab-static). - Overlay/blur surfaces settle 8 frames (blur backdrop freeze); setup re-runs each frame (OpenPopup popups must re-fire). updateScreenshotSweep now runs before the first-run-wizard early-return in render() so the sweep advances while a wizard step is shown. main.cpp drops vsync during a sweep so it isn't throttled to the compositor's unfocused rate. Output: <config>/screenshots-full/<surface>/<skin>.png + index.md. - DRAGONX_FULL_SWEEP=1 runs the sweep headlessly then quits (CI / verification). Verified end-to-end under WSLg: 288 PNGs (9 skins x 32 surfaces), all 1200x720, [Sweep] done, clean quit, no daemon. Byte-identity across runs holds only for static skins on data-free surfaces — the rest vary by animated theme effects / live price / relative timestamps (expected for a review tool, not a bug). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
47
src/app.h
47
src/app.h
@@ -343,6 +343,12 @@ public:
|
||||
// wantsScreenshotThisFrame() after drawing the frame, saves screenshotSweepPath(), then calls
|
||||
// onScreenshotCaptured() to advance. Transient — restores the original skin/page when done.
|
||||
void startScreenshotSweep();
|
||||
// Full UI sweep: like the tab sweep, but also drives every modal / dialog / multi-step flow /
|
||||
// state overlay into view (with injected demo data, offline, firing no live ops) and captures
|
||||
// each under every skin. Output: <config>/screenshots-full/<surface>/<skin>.png + an index.
|
||||
void startFullUiSweep();
|
||||
std::string screenshotFullDir() const;
|
||||
bool isScreenshotSweeping() const { return screenshot_sweep_active_; }
|
||||
bool wantsScreenshotThisFrame() const { return sweep_capture_this_frame_; }
|
||||
const std::string& screenshotSweepPath() const { return sweep_current_path_; }
|
||||
void onScreenshotCaptured();
|
||||
@@ -756,16 +762,49 @@ private:
|
||||
bool screenshot_sweep_active_ = false;
|
||||
bool sweep_capture_this_frame_ = false;
|
||||
int sweep_skin_idx_ = 0;
|
||||
int sweep_page_idx_ = 0;
|
||||
int sweep_settle_frames_ = 0; // frames to let a new skin/page settle before capturing
|
||||
int sweep_settle_frames_ = 0; // frames to let a new skin/surface settle before capture
|
||||
std::vector<std::string> sweep_skins_; // skin ids to cycle
|
||||
std::vector<ui::NavPage> sweep_pages_; // enabled pages to cycle
|
||||
std::string sweep_dir_; // output folder for this sweep
|
||||
std::string sweep_current_path_; // PNG path for the frame about to be captured
|
||||
std::string sweep_saved_skin_; // restore on completion
|
||||
ui::NavPage sweep_saved_page_ = ui::NavPage::Overview;
|
||||
void updateScreenshotSweep(); // called at the top of render() while active
|
||||
void applySweepTarget(); // apply current (skin,page), compute path, arm settle
|
||||
void applySweepTarget(); // apply current (skin,page/surface), path, arm settle
|
||||
|
||||
// --- Full UI sweep: the capture unit is a "surface" (a tab, optionally with a modal / step /
|
||||
// state forced on top). A tab is a surface with a null setup. ---
|
||||
struct SweepTarget {
|
||||
std::string name; // fs-safe id, e.g. "modal-seed-backup" / "overview"
|
||||
ui::NavPage page = ui::NavPage::Overview; // base tab under the surface
|
||||
std::function<void(App&)> setup; // reveal the surface (null = plain tab)
|
||||
std::function<void(App&)> teardown; // clear it (null = nothing to undo)
|
||||
int settle = 4;// blur overlays override to 8
|
||||
};
|
||||
std::vector<SweepTarget> sweep_targets_;
|
||||
int sweep_target_idx_ = 0;
|
||||
bool sweep_full_ = false; // full-UI sweep (drives surfaces) vs the legacy tab-only sweep
|
||||
// capture_mode_: set only during a full sweep. CONTRACT: while true, NO live op may fire — no
|
||||
// RPC, no auto-lock, no async pump. New async paths that could run mid-sweep must guard on it.
|
||||
bool capture_mode_ = false;
|
||||
void startSweepImpl(bool full);
|
||||
void buildSweepCatalog();
|
||||
void installDemoWalletData();
|
||||
void clearDemoWalletData();
|
||||
void applyHealthyDemoState(); // reset the connection/encryption flags to the healthy demo values
|
||||
void writeSweepManifest() const;
|
||||
// Snapshot of the state_ fields the demo installer mutates, restored at sweep end. Kept as a
|
||||
// plain struct because WalletState has reference-alias members and isn't copy-assignable.
|
||||
struct SweepStateSnapshot {
|
||||
bool valid = false;
|
||||
bool connected=false, warming_up=false, daemon_initializing=false;
|
||||
bool encrypted=false, locked=false, encryption_state_known=false;
|
||||
std::string warmup_status, warmup_description;
|
||||
SyncInfo sync;
|
||||
double privateBalance=0, transparentBalance=0, totalBalance=0, unconfirmedBalance=0;
|
||||
std::vector<AddressInfo> addresses, z_addresses, t_addresses;
|
||||
std::vector<TransactionInfo> transactions;
|
||||
double market_price_usd=0;
|
||||
} sweep_state_snapshot_;
|
||||
bool sidebar_user_toggled_ = false; // user manually toggled — suppress auto-collapse
|
||||
float sidebar_width_anim_ = 0.0f; // animated width (0 = uninitialized)
|
||||
float prev_dpi_scale_ = 0.0f; // detect DPI changes to snap sidebar width
|
||||
|
||||
Reference in New Issue
Block a user