c23c74f4 - Gate Pay and Send behind a hidden insider unlock - #885
c23c74f4 - Gate Pay and Send behind a hidden insider unlock#885TaprootFreak wants to merge 10 commits into
Conversation
…r unlock Pay and Send stay hidden on the dashboard until the app is unlocked by tapping the version number in the settings seven times (the Android developer-options pattern). The unlock is confirmed with a snackbar and persisted via SharedPreferences, so it survives restarts. The OpenCryptoPay payment deeplink intentionally keeps working regardless of the unlock state. The version row keeps its exact visuals; it is wrapped in a new SettingsVersionUnlock widget that follows the page-local getIt bloc access pattern. The dashboard golden baselines change (two buttons in the locked default) and a dashboard_insider_unlocked case is added; the responsive matrix renders the unlocked superset so all four actions stay covered.
… fix analyzer findings The SettingsBloc constructor now seeds insiderFeaturesUnlocked from the repository unconditionally, so the four page/golden tests that build a real bloc on a mocked repository need the new getter stubbed. Also apply the analyzer findings on the new code: const on the settings version row and an unused import in the unlock widget test.
The coverage floor scopes lib/packages/* at 100% lines; the new insiderFeaturesUnlocked getter/setter only ran against a mocked repository so far. Exercise both against a real SharedPreferences backend like the neighbouring groups.
…rix and pin gate regressions Review findings from the first pass: the zero-balance matrix case never renders DashboardActions, so its insider stub suggested coverage that did not exist — revert it and add a positive-balance insider-unlocked matrix case that checks all four actions with expectFullyTappable across the full device/text-scale matrix. Also pin two regression modes: a locked-to-unlocked bloc emission must rebuild the mounted actions row (context.watch), and nine rapid taps on the version row must still dispatch exactly one unlock event (the == 7 comparison).
…atrix case renders The positive-balance dashboard branch also builds DashboardTransactionHistory, which resolves AppStore and friends via getIt — mirror the golden harness registrations into the matrix test and add the missing bloc_test import for whenListen.
The four-button dashboard row overflowed its fixed 110x50 boxes once Expanded call sites squeezed the width (German labels wrapped, 2px at 1.0x on narrow devices) or large text scales exceeded the height (up to 258px at 3.0x). Wrap the icon/label column in a scale-down FittedBox: cells that fit keep rendering pixel-identically, the former overflow cases shrink instead. The responsive matrix now exercises the actions row standalone across the full device/text-scale grid (the surrounding positive-balance dashboard sections have pre-existing overflows, tracked in #887), and expectFullyTappable maps both rect corners through the render transform so scaled targets measure their visual rect instead of the untransformed layout size. The locked-to-unlocked transition test double-pumps to let the stream deliver before asserting the rebuild.
|
Two full two-dimensional review passes (conformance + logic) were run on this PR, the second one covering the complete diff again after the fixes from the first. Pass 1 surfaced four points: the responsive-matrix stub for the unlocked state never actually rendered the actions row (fixed — the matrix now exercises the four-button row standalone across the full device/text-scale grid, which in turn exposed and fixed a real Pass 2 came back clean on logic; the single conformance note (the widget-test harness registers a set-up-all placeholder that each test replaces) is the deliberate mirror of the existing settings golden harness structure and was kept for pattern consistency. Pre-existing positive-balance dashboard overflows discovered by the new matrix are tracked in #887. |
…reable anchor Section 79 documents how to unlock the hidden Pay and Send actions (seven taps on the settings version number) with before/after screenshots, reachable at /de/#insider-unlock for sharing with the people who should know. The new dashboard_insider_unlocked golden joins the screenshot mapping as slot 269, and the Dockerfile comment stops hardcoding the screenshot count.
…image block The build check still insisted on 278 assembled screenshots and would have gone red with the new slot; bump the guard, the stale counts in the docs, and add slot 269 to the smoke sample. The three-image unlock block gets a wrapping flex container (the only multi-image block in the file) and the source span the other catalog heads carry.
|
Follow-up: the handbook addition (section 79, shareable /de/#insider-unlock anchor, screenshot slot 269) went through two further full review passes — four in total for this PR now. Pass 3 confirmed every factual claim of the new instructions against the code (icon, tap count, snackbar wording, button labels, persistence, deeplink behaviour) and surfaced five conformance issues, most importantly the build check still guarding for 278 assembled screenshots; pass 4 verified all of them fixed (guard and docs at 279, smoke sample extended to the new slot, the three-image block got a wrapping container and a source span) and came back clean on both dimensions. |
Summary
Soft launch for the two new phase-2 features: the Pay (OpenCryptoPay, #674) and Send (W2W transfer, #687) dashboard actions are hidden behind an invisible wall so only insiders can reach them.
insiderFeaturesUnlockedflag is set; Buy and Sell stay visible unconditionally.SettingsBloc).Deliberate deviation from the API-authority rule (reviewed, intentional)
CONTRIBUTING lists "feature visibility based on local state" as not OK and prefers an API capability flag. This gate deviates from that on purpose, as a product decision made with the API-capability alternative on the table:
Implementation notes
SettingsVersionUnlockwidget that follows the page-localgetItbloc-access pattern (its test harness deliberately mirrors the settings golden harness structure).DashboardActionsgates Pay/Send with collection-ifs oncontext.watch<SettingsBloc>().ActionButtonnow scales its icon/label column down (FittedBox) instead of overflowing its fixed 110x50 box — the new actions matrix exposed real overflows under Expanded width squeeze (German labels, 2px at 1.0x on narrow devices) and at large text scales (up to 258px at 3.0x). The tap area stays the full box (theInkWellwraps it, not the scaled content). Layouts that fit are visually unchanged; the four positive-balance dashboard goldens picked up sub-pixel antialiasing deltas (77-107 bytes each) from the new render path and were regenerated by the runner.expectFullyTappablemaps both rect corners through the render transform, so scaled targets measure their visual rect (transform-neutral for every existing call site).Handbook
Section 79 of the handbook (/de/#insider-unlock) explains the unlock step by step in German with three screenshots (settings version row, dashboard before, dashboard after) so the link can be shared directly with the people who should know. The new dashboard_insider_unlocked golden is mapped as handbook screenshot slot 269; the three updated dashboard baselines were already mapped and refresh automatically on the next handbook deploy.
Tests
DashboardActionslocked/unlocked cases incl. the existing navigation assertions, plus a locked→unlocked transition test that pins thecontext.watchrebuild behaviourdashboard_insider_unlocked(renders the same four-button dashboard the pre-PR baseline showed); existing dashboard goldens change to the 2-button locked defaultDashboardActionsstandalone (insider unlocked, all four buttons) across the full device/text-scale grid with overflow + tappability gates — scoped to the actions row this PR owns; the zero-balance page matrix is unchangedlib/packages/*)