The waterfall showed mirrored/upside-down garbage because the FFT
never produced a valid spectrum:
1. g3.c.f() (high-precision sin) had its quadrant-0 case mangled by
jadx into a nested-if that returned NaN for small angles - the
twiddle factor table ended up with 329/1024 NaN entries.
Restored the smali switch: case0->g(), case1->c(), case2->-g(),
case3->-c().
2. i3.d.k() routed the runtime FFT (a5==0, single-thread path) into
the else of if(a5!=1) instead of if(a5!=0), so the FFT never ran
and the output stayed in the time domain (peak at bin 357 for a
669Hz tone instead of bin 86).
Verified with a JVM harness (static-block tables + pure-tone inputs):
200Hz->bin26, 400Hz->bin51, 669Hz->bin86, 1000Hz->bin128, all exact.
Twiddle table NaN count: 329 -> 0.
Decode page showed stats but empty waterfall and no decoded text:
the ported i3/d.k() FFT dispatch was broken by a jadx structure
misplacement - the runtime path (k=1 -> a5=0 -> cond_22 single-thread
FFT) was replaced by a hallucinated `throw null` else-branch while the
real cond_22 code sat in a dead else. Verified against smali
(7030-7263): j3.c.q forward FFT + post-processing loop + tail + small-
array branch now live in the a5==0 branch.
Also:
- UiSettingsCard now lists CwDecode (toggle + drag-reorder) between
Roaming and Map
- unknown screenIds in persisted screenOrder fall back to
defaultScreenOrder position (CwDecode lands between Roaming and Map
for existing users instead of trailing after Settings)
Verified: :feature:cw + :feature:settings + :app compileDebugKotlin
BUILD SUCCESSFUL.